ADM3a terminal emulator
[termu] / src / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <ctype.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 #include <errno.h>
7 #include <sys/wait.h>
8 #include <sys/select.h>
9 #include <X11/Xlib.h>
10 #include "miniglut.h"
11 #include "font.h"
12 #include "term.h"
13
14 static int init(void);
15 static void cleanup(void);
16
17 static void display(void);
18 static void reshape(int x, int y);
19 static void keypress(unsigned char key, int x, int y);
20 static void keyrelease(unsigned char key, int x, int y);
21 static void sighandler(int s);
22
23 int win_width, win_height;
24 int pty, pid;
25
26
27 int main(int argc, char **argv)
28 {
29         int xfd, maxfd, rdsz;
30         char *shell;
31         fd_set rdset;
32         char buf[1024];
33
34         if(!(shell = getenv("SHELL"))) {
35                 shell = "/bin/sh";
36         }
37         if((pty = open("/dev/ptmx", O_RDWR)) == -1) {
38                 fprintf(stderr, "failed to open pseudoterminal\n");
39                 return 1;
40         }
41         grantpt(pty);
42
43         if(!(pid = fork())) {
44                 setsid();
45                 unlockpt(pty);
46
47                 close(0);
48                 close(1);
49                 close(2);
50                 if(open(ptsname(pty), O_RDWR) == -1) {
51                         _exit(1);
52                 }
53                 close(pty);
54                 dup(0);
55                 dup(0);
56
57                 putenv("TERM=adm3a");
58
59                 execl(shell, shell, (void*)0);
60                 _exit(1);
61         }
62
63         glutInit(&argc, argv);
64         glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
65         glutInitWindowSize(800, 600);
66         glutCreateWindow("termu");
67
68         glutDisplayFunc(display);
69         glutReshapeFunc(reshape);
70         glutKeyboardFunc(keypress);
71         glutKeyboardUpFunc(keyrelease);
72
73         if(init() == -1) {
74                 kill(pid, SIGINT);
75                 return 1;
76         }
77         atexit(cleanup);
78
79         signal(SIGCHLD, sighandler);
80
81         xfd = miniglut_x11_socket();
82         maxfd = xfd > pty ? xfd : pty;
83
84         for(;;) {
85                 FD_ZERO(&rdset);
86                 FD_SET(pty, &rdset);
87                 FD_SET(xfd, &rdset);
88
89                 XFlush(miniglut_x11_display());
90                 while(select(maxfd + 1, &rdset, 0, 0, 0) == -1 && errno == EINTR);
91
92                 if(FD_ISSET(pty, &rdset)) {
93                         rdsz = read(pty, buf, sizeof buf);
94                         if(term_proc(buf, rdsz)) {
95                                 glutPostRedisplay();
96                         }
97                 }
98                 if(FD_ISSET(xfd, &rdset)) {
99                         glutMainLoopEvent();
100                 }
101         }
102
103         return 0;
104 }
105
106 static int init(void)
107 {
108         int width, height;
109
110         text_init();
111         term_init();
112
113         width = TERM_COLS * fontw * 2;
114         height = width / 1.333333333;
115         glutReshapeWindow(width, height);
116         glutPostRedisplay();
117
118         return 0;
119 }
120
121 static void cleanup(void)
122 {
123         text_cleanup();
124 }
125
126 static void display(void)
127 {
128         int i, j;
129         unsigned char *scrptr = scrbuf;
130
131         glClearColor(0.1, 0.1, 0.1, 1);
132         glClear(GL_COLOR_BUFFER_BIT);
133
134         glMatrixMode(GL_PROJECTION);
135         glLoadIdentity();
136         glOrtho(0, TERM_COLS, 0, TERM_ROWS, -1, 1);
137
138         glMatrixMode(GL_MODELVIEW);
139         glLoadIdentity();
140
141         text_begin();
142         for(i=0; i<TERM_ROWS; i++) {
143                 for(j=0; j<TERM_COLS; j++) {
144                         if(*scrptr && *scrptr != ' ') {
145                                 draw_glyph(j, i, *scrptr);
146                         }
147                         scrptr++;
148                 }
149         }
150         text_end();
151
152         glutSwapBuffers();
153 }
154
155 static void reshape(int x, int y)
156 {
157         printf("RESHAPE\n");
158         win_width = x;
159         win_height = y;
160
161         glViewport(0, 0, x, y);
162 }
163
164 static unsigned char shifted[] = {
165         "\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017"
166         "\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
167         "\040\041\042\043\044\045\046\047\050\051\052\053<_>?"
168         ")!@#$%^&*(;:<+>?"
169         "@ABCDEFGHIJKLMNO"
170         "PQRSTUVWXYZ{|}^_"
171         "~ABCDEFGHIJKLMNO"
172         "PQRSTUVWXYZ{|}~\077"
173 };
174
175 static void keypress(unsigned char key, int x, int y)
176 {
177         unsigned int mod = glutGetModifiers();
178
179         switch(key) {
180         case 'q':
181                 if(mod & GLUT_ACTIVE_CTRL) {
182                         exit(0);
183                 }
184                 break;
185
186         default:
187                 break;
188         }
189
190         if(mod & GLUT_ACTIVE_SHIFT) {
191                 if(key < 0x80) {
192                         key = shifted[key];
193                 }
194         }
195
196         write(pty, &key, 1);
197 }
198
199 static void keyrelease(unsigned char key, int x, int y)
200 {
201 }
202
203 static void sighandler(int s)
204 {
205         switch(s) {
206         case SIGCHLD:
207                 printf("shell exited, closing terminal\n");
208                 wait(0);
209                 exit(0);
210         }
211 }