rev |
line source |
nuclear@0
|
1 #include <stdio.h>
|
nuclear@0
|
2 #include <stdlib.h>
|
nuclear@0
|
3 #include <assert.h>
|
nuclear@0
|
4 #include <errno.h>
|
nuclear@0
|
5 #include <unistd.h>
|
nuclear@0
|
6 #include <sys/select.h>
|
nuclear@0
|
7 #include <GL/glew.h>
|
nuclear@0
|
8 #include <X11/Xlib.h>
|
nuclear@0
|
9 #include <GL/glx.h>
|
nuclear@1
|
10 #include "dev.h"
|
nuclear@0
|
11
|
nuclear@0
|
12 static bool init();
|
nuclear@0
|
13 static void cleanup();
|
nuclear@0
|
14 static void display();
|
nuclear@0
|
15 static void keyb(int key, bool pressed);
|
nuclear@0
|
16 static void mouse(int bn, bool pressed, int x, int y);
|
nuclear@0
|
17 static void motion(int x, int y);
|
nuclear@0
|
18
|
nuclear@0
|
19 static Window create_window(const char *title, int xsz, int ysz);
|
nuclear@0
|
20 static void process_events();
|
nuclear@0
|
21 static int translate_keysym(KeySym sym);
|
nuclear@0
|
22
|
nuclear@2
|
23 static int proc_args(int argc, char **argv);
|
nuclear@2
|
24
|
nuclear@0
|
25 static Display *dpy;
|
nuclear@0
|
26 static Window win;
|
nuclear@0
|
27 static GLXContext ctx;
|
nuclear@0
|
28 static Atom xa_wm_prot, xa_wm_del_win;
|
nuclear@0
|
29
|
nuclear@0
|
30 static int win_width, win_height;
|
nuclear@0
|
31
|
nuclear@0
|
32 static bool redisplay_pending;
|
nuclear@0
|
33 static bool win_mapped;
|
nuclear@0
|
34
|
nuclear@2
|
35 static int fakefd = -1;
|
nuclear@2
|
36 static char *fake_devpath;
|
nuclear@2
|
37
|
nuclear@2
|
38 int main(int argc, char **argv)
|
nuclear@0
|
39 {
|
nuclear@2
|
40 if(proc_args(argc, argv) == -1) {
|
nuclear@2
|
41 return 1;
|
nuclear@2
|
42 }
|
nuclear@0
|
43 if(!init()) {
|
nuclear@0
|
44 return 1;
|
nuclear@0
|
45 }
|
nuclear@0
|
46 atexit(cleanup);
|
nuclear@0
|
47
|
nuclear@0
|
48 int xfd = ConnectionNumber(dpy);
|
nuclear@0
|
49
|
nuclear@0
|
50 for(;;) {
|
nuclear@0
|
51 fd_set rd;
|
nuclear@0
|
52 FD_ZERO(&rd);
|
nuclear@0
|
53
|
nuclear@0
|
54 FD_SET(xfd, &rd);
|
nuclear@2
|
55 FD_SET(fakefd, &rd);
|
nuclear@0
|
56
|
nuclear@2
|
57 int maxfd = xfd > fakefd ? xfd : fakefd;
|
nuclear@2
|
58
|
nuclear@2
|
59 while(select(maxfd + 1, &rd, 0, 0, 0) == -1 && errno == EINTR);
|
nuclear@0
|
60
|
nuclear@0
|
61 if(FD_ISSET(xfd, &rd)) {
|
nuclear@0
|
62 process_events();
|
nuclear@0
|
63 }
|
nuclear@2
|
64 if(FD_ISSET(fakefd, &rd)) {
|
nuclear@2
|
65 proc_dev_input();
|
nuclear@2
|
66 }
|
nuclear@0
|
67
|
nuclear@0
|
68 if(redisplay_pending) {
|
nuclear@0
|
69 display();
|
nuclear@0
|
70 redisplay_pending = false;
|
nuclear@0
|
71 }
|
nuclear@0
|
72 }
|
nuclear@0
|
73 return 0;
|
nuclear@0
|
74 }
|
nuclear@0
|
75
|
nuclear@0
|
76 static bool init()
|
nuclear@0
|
77 {
|
nuclear@2
|
78 if(fake_devpath) {
|
nuclear@2
|
79 if((fakefd = start_dev(fake_devpath)) == -1) {
|
nuclear@2
|
80 return false;
|
nuclear@2
|
81 }
|
nuclear@2
|
82 }
|
nuclear@1
|
83
|
nuclear@0
|
84 if(!(dpy = XOpenDisplay(0))) {
|
nuclear@0
|
85 fprintf(stderr, "failed to connect to the X server!\n");
|
nuclear@0
|
86 return false;
|
nuclear@0
|
87 }
|
nuclear@0
|
88
|
nuclear@0
|
89 if(!(win = create_window("dummy equeue device", 800, 600))) {
|
nuclear@0
|
90 return false;
|
nuclear@0
|
91 }
|
nuclear@0
|
92
|
nuclear@0
|
93 return true;
|
nuclear@0
|
94 }
|
nuclear@0
|
95
|
nuclear@0
|
96 static void cleanup()
|
nuclear@0
|
97 {
|
nuclear@1
|
98 stop_dev();
|
nuclear@1
|
99
|
nuclear@0
|
100 if(!dpy) return;
|
nuclear@0
|
101
|
nuclear@0
|
102 if(win) {
|
nuclear@0
|
103 XDestroyWindow(dpy, win);
|
nuclear@0
|
104 }
|
nuclear@0
|
105 XCloseDisplay(dpy);
|
nuclear@0
|
106 }
|
nuclear@0
|
107
|
nuclear@0
|
108 static void display()
|
nuclear@0
|
109 {
|
nuclear@0
|
110 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
nuclear@0
|
111
|
nuclear@0
|
112 glMatrixMode(GL_MODELVIEW);
|
nuclear@0
|
113 glLoadIdentity();
|
nuclear@0
|
114
|
nuclear@0
|
115 glXSwapBuffers(dpy, win);
|
nuclear@0
|
116 assert(glGetError() == GL_NO_ERROR);
|
nuclear@0
|
117 }
|
nuclear@0
|
118
|
nuclear@0
|
119 static void reshape(int x, int y)
|
nuclear@0
|
120 {
|
nuclear@0
|
121 glViewport(0, 0, x, y);
|
nuclear@0
|
122
|
nuclear@0
|
123 glMatrixMode(GL_PROJECTION);
|
nuclear@0
|
124 glLoadIdentity();
|
nuclear@0
|
125 gluPerspective(50.0, (float)x / (float)y, 0.5, 500.0);
|
nuclear@0
|
126 }
|
nuclear@0
|
127
|
nuclear@0
|
128 static void keyb(int key, bool pressed)
|
nuclear@0
|
129 {
|
nuclear@0
|
130 if(pressed) {
|
nuclear@0
|
131 switch(key) {
|
nuclear@0
|
132 case 27:
|
nuclear@0
|
133 exit(0);
|
nuclear@0
|
134 }
|
nuclear@0
|
135 }
|
nuclear@0
|
136 }
|
nuclear@0
|
137
|
nuclear@0
|
138 static void mouse(int bn, bool pressed, int x, int y)
|
nuclear@0
|
139 {
|
nuclear@0
|
140 }
|
nuclear@0
|
141
|
nuclear@0
|
142 static void motion(int x, int y)
|
nuclear@0
|
143 {
|
nuclear@0
|
144 }
|
nuclear@0
|
145
|
nuclear@0
|
146 static Window create_window(const char *title, int xsz, int ysz)
|
nuclear@0
|
147 {
|
nuclear@0
|
148 int scr = DefaultScreen(dpy);
|
nuclear@0
|
149 Window root = RootWindow(dpy, scr);
|
nuclear@0
|
150
|
nuclear@0
|
151 int glxattr[] = {
|
nuclear@0
|
152 GLX_RGBA,
|
nuclear@0
|
153 GLX_RED_SIZE, 8,
|
nuclear@0
|
154 GLX_GREEN_SIZE, 8,
|
nuclear@0
|
155 GLX_BLUE_SIZE, 8,
|
nuclear@0
|
156 GLX_DEPTH_SIZE, 24,
|
nuclear@0
|
157 GLX_DOUBLEBUFFER,
|
nuclear@0
|
158 #if defined(GLX_VERSION_1_4) || defined(GLX_ARB_multisample)
|
nuclear@0
|
159 GLX_SAMPLE_BUFFERS_ARB, 1,
|
nuclear@0
|
160 GLX_SAMPLES_ARB, 1,
|
nuclear@0
|
161 #endif
|
nuclear@0
|
162 None
|
nuclear@0
|
163 };
|
nuclear@0
|
164
|
nuclear@0
|
165 XVisualInfo *vis = glXChooseVisual(dpy, scr, glxattr);
|
nuclear@0
|
166 if(!vis) {
|
nuclear@0
|
167 fprintf(stderr, "failed to find a suitable visual\n");
|
nuclear@0
|
168 return 0;
|
nuclear@0
|
169 }
|
nuclear@0
|
170
|
nuclear@0
|
171 if(!(ctx = glXCreateContext(dpy, vis, 0, True))) {
|
nuclear@0
|
172 fprintf(stderr, "failed to create OpenGL context\n");
|
nuclear@0
|
173 XFree(vis);
|
nuclear@0
|
174 return -1;
|
nuclear@0
|
175 }
|
nuclear@0
|
176
|
nuclear@0
|
177 XSetWindowAttributes xattr;
|
nuclear@0
|
178 xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, scr);
|
nuclear@0
|
179 xattr.colormap = XCreateColormap(dpy, root, vis->visual, AllocNone);
|
nuclear@0
|
180 unsigned int xattr_mask = CWColormap | CWBackPixel | CWBorderPixel;
|
nuclear@0
|
181
|
nuclear@0
|
182 Window win = XCreateWindow(dpy, root, 0, 0, xsz, ysz, 0, vis->depth, InputOutput,
|
nuclear@0
|
183 vis->visual, xattr_mask, &xattr);
|
nuclear@0
|
184 if(!win) {
|
nuclear@0
|
185 fprintf(stderr, "failed to create window\n");
|
nuclear@0
|
186 glXDestroyContext(dpy, ctx);
|
nuclear@0
|
187 XFree(vis);
|
nuclear@0
|
188 return -1;
|
nuclear@0
|
189 }
|
nuclear@0
|
190 XFree(vis);
|
nuclear@0
|
191
|
nuclear@0
|
192 unsigned int evmask = StructureNotifyMask | VisibilityChangeMask | ExposureMask |
|
nuclear@0
|
193 KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
|
nuclear@0
|
194 ButtonMotionMask | PointerMotionMask;
|
nuclear@0
|
195 XSelectInput(dpy, win, evmask);
|
nuclear@0
|
196
|
nuclear@0
|
197 xa_wm_prot = XInternAtom(dpy, "WM_PROTOCOLS", False);
|
nuclear@0
|
198 xa_wm_del_win = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
|
nuclear@0
|
199 XSetWMProtocols(dpy, win, &xa_wm_del_win, 1);
|
nuclear@0
|
200
|
nuclear@0
|
201 XClassHint hint;
|
nuclear@0
|
202 hint.res_name = hint.res_class = (char*)"equeue_win";
|
nuclear@0
|
203 XSetClassHint(dpy, win, &hint);
|
nuclear@0
|
204
|
nuclear@0
|
205 XTextProperty wm_name;
|
nuclear@0
|
206 XStringListToTextProperty((char**)&title, 1, &wm_name);
|
nuclear@0
|
207 XSetWMName(dpy, win, &wm_name);
|
nuclear@0
|
208 XSetWMIconName(dpy, win, &wm_name);
|
nuclear@0
|
209 XFree(wm_name.value);
|
nuclear@0
|
210
|
nuclear@0
|
211 XMapWindow(dpy, win);
|
nuclear@0
|
212 glXMakeCurrent(dpy, win, ctx);
|
nuclear@0
|
213
|
nuclear@0
|
214 return win;
|
nuclear@0
|
215 }
|
nuclear@0
|
216
|
nuclear@0
|
217 static void process_events()
|
nuclear@0
|
218 {
|
nuclear@0
|
219 XEvent ev;
|
nuclear@0
|
220
|
nuclear@0
|
221 while(XPending(dpy)) {
|
nuclear@0
|
222 XNextEvent(dpy, &ev);
|
nuclear@0
|
223 switch(ev.type) {
|
nuclear@0
|
224 case MapNotify:
|
nuclear@0
|
225 win_mapped = true;
|
nuclear@0
|
226 break;
|
nuclear@0
|
227
|
nuclear@0
|
228 case UnmapNotify:
|
nuclear@0
|
229 win_mapped = false;
|
nuclear@0
|
230 break;
|
nuclear@0
|
231
|
nuclear@0
|
232 case Expose:
|
nuclear@0
|
233 if(win_mapped && ev.xexpose.count == 0) {
|
nuclear@0
|
234 redisplay_pending = 1;
|
nuclear@0
|
235 }
|
nuclear@0
|
236 break;
|
nuclear@0
|
237
|
nuclear@0
|
238 case MotionNotify:
|
nuclear@0
|
239 motion(ev.xmotion.x, ev.xmotion.y);
|
nuclear@0
|
240 break;
|
nuclear@0
|
241
|
nuclear@0
|
242 case ButtonPress:
|
nuclear@0
|
243 mouse(ev.xbutton.button - 1, true, ev.xbutton.x, ev.xbutton.y);
|
nuclear@0
|
244 break;
|
nuclear@0
|
245
|
nuclear@0
|
246 case ButtonRelease:
|
nuclear@0
|
247 mouse(ev.xbutton.button - 1, false, ev.xbutton.x, ev.xbutton.y);
|
nuclear@0
|
248 break;
|
nuclear@0
|
249
|
nuclear@0
|
250 case KeyPress:
|
nuclear@0
|
251 {
|
nuclear@0
|
252 KeySym sym = XLookupKeysym(&ev.xkey, 0);
|
nuclear@0
|
253 keyb(translate_keysym(sym), true);
|
nuclear@0
|
254 }
|
nuclear@0
|
255 break;
|
nuclear@0
|
256
|
nuclear@0
|
257 case KeyRelease:
|
nuclear@0
|
258 {
|
nuclear@0
|
259 KeySym sym = XLookupKeysym(&ev.xkey, 0);
|
nuclear@0
|
260 keyb(translate_keysym(sym), false);
|
nuclear@0
|
261 }
|
nuclear@0
|
262 break;
|
nuclear@0
|
263
|
nuclear@0
|
264 case ConfigureNotify:
|
nuclear@0
|
265 {
|
nuclear@0
|
266 int xsz = ev.xconfigure.width;
|
nuclear@0
|
267 int ysz = ev.xconfigure.height;
|
nuclear@0
|
268
|
nuclear@0
|
269 if(xsz != win_width || ysz != win_height) {
|
nuclear@0
|
270 win_width = xsz;
|
nuclear@0
|
271 win_height = ysz;
|
nuclear@0
|
272 reshape(xsz, ysz);
|
nuclear@0
|
273 }
|
nuclear@0
|
274 }
|
nuclear@0
|
275 break;
|
nuclear@0
|
276
|
nuclear@0
|
277 case ClientMessage:
|
nuclear@0
|
278 if(ev.xclient.message_type == xa_wm_prot) {
|
nuclear@0
|
279 if((Atom)ev.xclient.data.l[0] == xa_wm_del_win) {
|
nuclear@0
|
280 exit(0);
|
nuclear@0
|
281 }
|
nuclear@0
|
282 }
|
nuclear@0
|
283 break;
|
nuclear@0
|
284
|
nuclear@0
|
285 default:
|
nuclear@0
|
286 break;
|
nuclear@0
|
287 }
|
nuclear@0
|
288
|
nuclear@0
|
289 }
|
nuclear@0
|
290 }
|
nuclear@0
|
291
|
nuclear@0
|
292 static int translate_keysym(KeySym sym)
|
nuclear@0
|
293 {
|
nuclear@0
|
294 switch(sym) {
|
nuclear@0
|
295 case XK_BackSpace:
|
nuclear@0
|
296 return '\b';
|
nuclear@0
|
297 case XK_Tab:
|
nuclear@0
|
298 return '\t';
|
nuclear@0
|
299 case XK_Linefeed:
|
nuclear@0
|
300 return '\r';
|
nuclear@0
|
301 case XK_Return:
|
nuclear@0
|
302 return '\n';
|
nuclear@0
|
303 case XK_Escape:
|
nuclear@0
|
304 return 27;
|
nuclear@0
|
305 default:
|
nuclear@0
|
306 break;
|
nuclear@0
|
307 }
|
nuclear@0
|
308 return (int)sym;
|
nuclear@0
|
309 }
|
nuclear@2
|
310
|
nuclear@2
|
311 static int proc_args(int argc, char **argv)
|
nuclear@2
|
312 {
|
nuclear@2
|
313 for(int i=1; i<argc; i++) {
|
nuclear@2
|
314 if(argv[i][0] == '-') {
|
nuclear@2
|
315 fprintf(stderr, "unexpected option: %s\n", argv[i]);
|
nuclear@2
|
316 return -1;
|
nuclear@2
|
317
|
nuclear@2
|
318 } else {
|
nuclear@2
|
319 if(fake_devpath) {
|
nuclear@2
|
320 fprintf(stderr, "unexpected argument: %s\n", argv[i]);
|
nuclear@2
|
321 return -1;
|
nuclear@2
|
322 }
|
nuclear@2
|
323 fake_devpath = argv[i];
|
nuclear@2
|
324 }
|
nuclear@2
|
325 }
|
nuclear@2
|
326 if(!fake_devpath) {
|
nuclear@2
|
327 fprintf(stderr, "no device path specified, running standalone\n");
|
nuclear@2
|
328 }
|
nuclear@2
|
329 return 0;
|
nuclear@2
|
330 }
|