rev |
line source |
nuclear@7
|
1 /* SimplyGL window system module for X11/GLX */
|
nuclear@9
|
2 /* link-with: -lX11 */
|
nuclear@7
|
3
|
nuclear@7
|
4 #include "config.h"
|
nuclear@7
|
5
|
nuclear@7
|
6 #ifdef USE_WSYS_MODULE_X11
|
nuclear@7
|
7
|
nuclear@4
|
8 #include <stdlib.h>
|
nuclear@7
|
9 #include <ctype.h>
|
nuclear@3
|
10 #include <X11/Xlib.h>
|
nuclear@3
|
11 #include <GL/glx.h>
|
nuclear@4
|
12 #include "sgl.h"
|
nuclear@3
|
13 #include "wsys.h"
|
nuclear@4
|
14 #include "log.h"
|
nuclear@3
|
15
|
nuclear@5
|
16
|
nuclear@3
|
17 struct window {
|
nuclear@3
|
18 Window win;
|
nuclear@3
|
19 GLXContext ctx;
|
nuclear@5
|
20 int width, height;
|
nuclear@5
|
21 int mapped;
|
nuclear@4
|
22 long evmask;
|
nuclear@5
|
23 int redisp_pending;
|
nuclear@3
|
24 struct window *next;
|
nuclear@3
|
25 };
|
nuclear@3
|
26
|
nuclear@3
|
27 static int init(void);
|
nuclear@3
|
28 static void shutdown(void);
|
nuclear@4
|
29
|
nuclear@4
|
30 /* video mode switching */
|
nuclear@4
|
31 static int set_vidmode(int xsz, int ysz);
|
nuclear@4
|
32 static int get_vidmode(int *xsz, int *ysz);
|
nuclear@4
|
33
|
nuclear@4
|
34 /* create/destroy windows */
|
nuclear@3
|
35 static int create_window(int xsz, int ysz, unsigned int flags);
|
nuclear@4
|
36 static void fill_attr(int *attr, unsigned int flags);
|
nuclear@4
|
37 static void print_visual_info(XVisualInfo *vis);
|
nuclear@3
|
38 static void close_window(int id);
|
nuclear@3
|
39
|
nuclear@4
|
40 /* window management */
|
nuclear@4
|
41 static int set_active(int id);
|
nuclear@5
|
42 static struct window *find_window(int id);
|
nuclear@5
|
43 static int activate_window(struct window *win);
|
nuclear@4
|
44 static int set_title(const char *str);
|
nuclear@4
|
45 static void redisplay(void);
|
nuclear@4
|
46 static void swap_buffers(void);
|
nuclear@4
|
47
|
nuclear@7
|
48 static int get_modifiers(void);
|
nuclear@7
|
49
|
nuclear@4
|
50 /* event handling and friends */
|
nuclear@4
|
51 static void set_bits(long *mask, long bits);
|
nuclear@4
|
52 static void clear_bits(long *mask, long bits);
|
nuclear@4
|
53 static void set_event(int idx, int enable);
|
nuclear@4
|
54 static int process_events(void);
|
nuclear@5
|
55 static int handle_event(XEvent *xev);
|
nuclear@7
|
56 static void process_key(KeySym sym, int state);
|
nuclear@5
|
57 static int translate_keysym(KeySym sym);
|
nuclear@4
|
58
|
nuclear@3
|
59 static struct wsys_module ws = {
|
nuclear@3
|
60 "x11-glx", 0,
|
nuclear@3
|
61 init,
|
nuclear@3
|
62 shutdown,
|
nuclear@3
|
63 set_vidmode,
|
nuclear@3
|
64 get_vidmode,
|
nuclear@3
|
65 create_window,
|
nuclear@3
|
66 close_window,
|
nuclear@4
|
67 set_active,
|
nuclear@4
|
68 set_title,
|
nuclear@4
|
69 redisplay,
|
nuclear@4
|
70 swap_buffers,
|
nuclear@7
|
71 get_modifiers,
|
nuclear@4
|
72 set_event,
|
nuclear@4
|
73 process_events,
|
nuclear@3
|
74 0
|
nuclear@3
|
75 };
|
nuclear@3
|
76
|
nuclear@3
|
77 static Display *dpy;
|
nuclear@4
|
78 static Window root;
|
nuclear@3
|
79 static int scr;
|
nuclear@4
|
80 static Atom xa_wm_prot, xa_wm_del_win;
|
nuclear@3
|
81 static struct window *winlist;
|
nuclear@5
|
82 static struct window *active_win, *prev_active;
|
nuclear@7
|
83 static int modkeys;
|
nuclear@3
|
84
|
nuclear@4
|
85 /* this is the only exported function, everything else should be static */
|
nuclear@3
|
86 void sgl_register_x11(void)
|
nuclear@3
|
87 {
|
nuclear@3
|
88 sgl_register_module(&ws);
|
nuclear@3
|
89 }
|
nuclear@3
|
90
|
nuclear@3
|
91 static int init(void)
|
nuclear@3
|
92 {
|
nuclear@5
|
93 if(dpy) {
|
nuclear@5
|
94 sgl_log("warning: double init\n");
|
nuclear@5
|
95 return 0;
|
nuclear@5
|
96 }
|
nuclear@5
|
97
|
nuclear@3
|
98 winlist = 0;
|
nuclear@5
|
99 active_win = prev_active = 0;
|
nuclear@3
|
100
|
nuclear@3
|
101 if(!(dpy = XOpenDisplay(0))) {
|
nuclear@4
|
102 sgl_log("failed to open X display: %s\n", XDisplayName(0));
|
nuclear@3
|
103 return -1;
|
nuclear@3
|
104 }
|
nuclear@3
|
105 scr = DefaultScreen(dpy);
|
nuclear@4
|
106 root = RootWindow(dpy, scr);
|
nuclear@4
|
107
|
nuclear@4
|
108 xa_wm_prot = XInternAtom(dpy, "WM_PROTOCOLS", False);
|
nuclear@4
|
109 xa_wm_del_win = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
|
nuclear@3
|
110
|
nuclear@3
|
111 return 0;
|
nuclear@3
|
112 }
|
nuclear@3
|
113
|
nuclear@3
|
114 static void shutdown(void)
|
nuclear@3
|
115 {
|
nuclear@5
|
116 if(!dpy) {
|
nuclear@5
|
117 return;
|
nuclear@5
|
118 }
|
nuclear@5
|
119
|
nuclear@3
|
120 while(winlist) {
|
nuclear@3
|
121 struct window *win = winlist;
|
nuclear@3
|
122 winlist = winlist->next;
|
nuclear@3
|
123
|
nuclear@3
|
124 glXDestroyContext(dpy, win->ctx);
|
nuclear@4
|
125 XDestroyWindow(dpy, win->win);
|
nuclear@3
|
126 free(win);
|
nuclear@3
|
127 }
|
nuclear@3
|
128 XCloseDisplay(dpy);
|
nuclear@3
|
129 dpy = 0;
|
nuclear@3
|
130 }
|
nuclear@3
|
131
|
nuclear@4
|
132 static int set_vidmode(int xsz, int ysz)
|
nuclear@3
|
133 {
|
nuclear@3
|
134 /* TODO */
|
nuclear@4
|
135 return 0;
|
nuclear@3
|
136 }
|
nuclear@3
|
137
|
nuclear@4
|
138 static int get_vidmode(int *xsz, int *ysz)
|
nuclear@3
|
139 {
|
nuclear@3
|
140 /* TODO */
|
nuclear@4
|
141 return 0;
|
nuclear@3
|
142 }
|
nuclear@3
|
143
|
nuclear@3
|
144 static int create_window(int xsz, int ysz, unsigned int flags)
|
nuclear@3
|
145 {
|
nuclear@4
|
146 int attr[32];
|
nuclear@4
|
147 Window win;
|
nuclear@4
|
148 GLXContext ctx;
|
nuclear@4
|
149 XVisualInfo *vis;
|
nuclear@4
|
150 XClassHint chint;
|
nuclear@4
|
151 XSetWindowAttributes xattr;
|
nuclear@4
|
152 unsigned int attr_valid;
|
nuclear@4
|
153 long evmask;
|
nuclear@4
|
154 struct window *wnode;
|
nuclear@6
|
155 void (*func)();
|
nuclear@4
|
156
|
nuclear@4
|
157 if(!(wnode = malloc(sizeof *wnode))) {
|
nuclear@4
|
158 return -1;
|
nuclear@4
|
159 }
|
nuclear@4
|
160
|
nuclear@4
|
161 fill_attr(attr, flags);
|
nuclear@4
|
162
|
nuclear@4
|
163 if(!(vis = glXChooseVisual(dpy, scr, attr))) {
|
nuclear@4
|
164 sgl_log("failed to find a suitable visual\n");
|
nuclear@4
|
165 free(wnode);
|
nuclear@4
|
166 return -1;
|
nuclear@4
|
167 }
|
nuclear@4
|
168 print_visual_info(vis);
|
nuclear@4
|
169
|
nuclear@4
|
170 if(!(ctx = glXCreateContext(dpy, vis, 0, True))) {
|
nuclear@4
|
171 sgl_log("failed to create OpenGL context\n");
|
nuclear@4
|
172 XFree(vis);
|
nuclear@4
|
173 free(wnode);
|
nuclear@4
|
174 return -1;
|
nuclear@4
|
175 }
|
nuclear@4
|
176
|
nuclear@4
|
177 xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, scr);
|
nuclear@4
|
178 xattr.colormap = XCreateColormap(dpy, root, vis->visual, AllocNone);
|
nuclear@4
|
179 attr_valid = CWColormap | CWBackPixel | CWBorderPixel;
|
nuclear@4
|
180
|
nuclear@4
|
181 if(!(win = XCreateWindow(dpy, root, 0, 0, xsz, ysz, 0, vis->depth, InputOutput,
|
nuclear@4
|
182 vis->visual, attr_valid, &xattr))) {
|
nuclear@4
|
183 sgl_log("failed to create window\n");
|
nuclear@4
|
184 glXDestroyContext(dpy, ctx);
|
nuclear@4
|
185 XFree(vis);
|
nuclear@4
|
186 free(wnode);
|
nuclear@4
|
187 return -1;
|
nuclear@4
|
188 }
|
nuclear@4
|
189 XFree(vis);
|
nuclear@4
|
190
|
nuclear@4
|
191 evmask = StructureNotifyMask | VisibilityChangeMask;
|
nuclear@4
|
192 XSelectInput(dpy, win, evmask);
|
nuclear@4
|
193
|
nuclear@4
|
194 XSetWMProtocols(dpy, win, &xa_wm_del_win, 1);
|
nuclear@4
|
195
|
nuclear@4
|
196 set_title("OpenGL/X11");
|
nuclear@4
|
197
|
nuclear@4
|
198 chint.res_name = chint.res_class = "simplygl";
|
nuclear@4
|
199 XSetClassHint(dpy, win, &chint);
|
nuclear@4
|
200
|
nuclear@4
|
201 XMapWindow(dpy, win);
|
nuclear@4
|
202
|
nuclear@4
|
203 wnode->win = win;
|
nuclear@4
|
204 wnode->ctx = ctx;
|
nuclear@5
|
205 wnode->width = xsz;
|
nuclear@5
|
206 wnode->height = ysz;
|
nuclear@5
|
207 wnode->mapped = 0;
|
nuclear@4
|
208 wnode->evmask = evmask;
|
nuclear@5
|
209 wnode->redisp_pending = 1;
|
nuclear@4
|
210 wnode->next = winlist;
|
nuclear@5
|
211 winlist = wnode;
|
nuclear@4
|
212
|
nuclear@4
|
213 if(!active_win) {
|
nuclear@4
|
214 set_active(win);
|
nuclear@6
|
215 } else {
|
nuclear@6
|
216 activate_window(wnode);
|
nuclear@4
|
217 }
|
nuclear@6
|
218
|
nuclear@6
|
219 if((func = sgl_get_callback(SGL_CREATE))) {
|
nuclear@6
|
220 func(win);
|
nuclear@6
|
221 }
|
nuclear@6
|
222 if((func = sgl_get_callback(SGL_RESHAPE))) {
|
nuclear@6
|
223 func(xsz, ysz);
|
nuclear@6
|
224 }
|
nuclear@6
|
225 activate_window(prev_active);
|
nuclear@4
|
226 return win;
|
nuclear@4
|
227 }
|
nuclear@4
|
228
|
nuclear@4
|
229 static void fill_attr(int *attr, unsigned int flags)
|
nuclear@4
|
230 {
|
nuclear@4
|
231 int i = 0;
|
nuclear@4
|
232
|
nuclear@4
|
233 attr[i++] = GLX_RGBA;
|
nuclear@4
|
234 attr[i++] = GLX_RED_SIZE; attr[i++] = 1;
|
nuclear@4
|
235 attr[i++] = GLX_GREEN_SIZE; attr[i++] = 1;
|
nuclear@4
|
236 attr[i++] = GLX_BLUE_SIZE; attr[i++] = 1;
|
nuclear@4
|
237
|
nuclear@4
|
238 if(flags & SGL_DOUBLE) {
|
nuclear@4
|
239 attr[i++] = GLX_DOUBLEBUFFER;
|
nuclear@4
|
240 }
|
nuclear@4
|
241 if(flags & SGL_DEPTH) {
|
nuclear@4
|
242 attr[i++] = GLX_DEPTH_SIZE;
|
nuclear@4
|
243 attr[i++] = 1;
|
nuclear@4
|
244 }
|
nuclear@4
|
245 if(flags & SGL_STENCIL) {
|
nuclear@4
|
246 attr[i++] = GLX_STENCIL_SIZE;
|
nuclear@4
|
247 attr[i++] = 1;
|
nuclear@4
|
248 }
|
nuclear@4
|
249 if(flags & SGL_STEREO) {
|
nuclear@4
|
250 attr[i++] = GLX_STEREO;
|
nuclear@4
|
251 }
|
nuclear@4
|
252 #if defined(GLX_VERSION_1_4) || defined(GLX_ARB_multisample)
|
nuclear@4
|
253 if(flags & SGL_MULTISAMPLE) {
|
nuclear@4
|
254 attr[i++] = GLX_SAMPLE_BUFFERS_ARB;
|
nuclear@4
|
255 attr[i++] = 1;
|
nuclear@4
|
256 attr[i++] = GLX_SAMPLES_ARB;
|
nuclear@4
|
257 attr[i++] = 1;
|
nuclear@4
|
258 }
|
nuclear@4
|
259 #endif /* defined GLX_VERSION_1_4 || GLX_ARB_multisample */
|
nuclear@4
|
260 attr[i] = None;
|
nuclear@4
|
261 }
|
nuclear@4
|
262
|
nuclear@4
|
263 static void print_visual_info(XVisualInfo *vis)
|
nuclear@4
|
264 {
|
nuclear@4
|
265 int rbits, gbits, bbits, zbits, sbits, stereo, aa, samples;
|
nuclear@4
|
266
|
nuclear@4
|
267 glXGetConfig(dpy, vis, GLX_RED_SIZE, &rbits);
|
nuclear@4
|
268 glXGetConfig(dpy, vis, GLX_GREEN_SIZE, &gbits);
|
nuclear@4
|
269 glXGetConfig(dpy, vis, GLX_BLUE_SIZE, &bbits);
|
nuclear@4
|
270 glXGetConfig(dpy, vis, GLX_DEPTH_SIZE, &zbits);
|
nuclear@4
|
271 glXGetConfig(dpy, vis, GLX_STENCIL_SIZE, &sbits);
|
nuclear@4
|
272 glXGetConfig(dpy, vis, GLX_STEREO, &stereo);
|
nuclear@4
|
273 #if defined(GLX_VERSION_1_4) || defined(GLX_ARB_multisample)
|
nuclear@4
|
274 glXGetConfig(dpy, vis, GLX_SAMPLE_BUFFERS_ARB, &aa);
|
nuclear@4
|
275 if(aa) {
|
nuclear@4
|
276 glXGetConfig(dpy, vis, GLX_SAMPLES_ARB, &samples);
|
nuclear@4
|
277 } else {
|
nuclear@4
|
278 samples = 1;
|
nuclear@4
|
279 }
|
nuclear@4
|
280 #endif /* defined GLX_VERSION_1_4 || GLX_ARB_multisample */
|
nuclear@4
|
281
|
nuclear@4
|
282 sgl_log("got visual: %d%d%d d:%d s:%d", rbits, gbits, bbits, zbits, sbits);
|
nuclear@4
|
283 sgl_log(" %s", stereo ? "stereo" : "mono");
|
nuclear@4
|
284 sgl_log(" samples/pixel: %d\n", samples);
|
nuclear@3
|
285 }
|
nuclear@3
|
286
|
nuclear@3
|
287 static void close_window(int id)
|
nuclear@3
|
288 {
|
nuclear@3
|
289 struct window dummy, *win, *prev;
|
nuclear@6
|
290 sgl_close_callback_t close_func;
|
nuclear@6
|
291
|
nuclear@3
|
292 dummy.next = winlist;
|
nuclear@3
|
293
|
nuclear@3
|
294 prev = &dummy;
|
nuclear@3
|
295 win = prev->next;
|
nuclear@3
|
296
|
nuclear@3
|
297 while(win) {
|
nuclear@3
|
298 if(win->win == id) {
|
nuclear@6
|
299 if(!(close_func = sgl_get_callback(SGL_CLOSE))) {
|
nuclear@6
|
300 close_func(id);
|
nuclear@6
|
301 }
|
nuclear@3
|
302 glXDestroyContext(dpy, win->ctx);
|
nuclear@4
|
303 XDestroyWindow(dpy, win->win);
|
nuclear@3
|
304 prev->next = win->next;
|
nuclear@3
|
305 free(win);
|
nuclear@3
|
306 return;
|
nuclear@3
|
307 }
|
nuclear@13
|
308 prev = win;
|
nuclear@3
|
309 win = win->next;
|
nuclear@3
|
310 }
|
nuclear@3
|
311 }
|
nuclear@4
|
312
|
nuclear@4
|
313 static int set_active(int id)
|
nuclear@4
|
314 {
|
nuclear@5
|
315 struct window *win = find_window(id);
|
nuclear@5
|
316 if(!win) {
|
nuclear@5
|
317 sgl_log("no such window: %d\n", id);
|
nuclear@5
|
318 return -1;
|
nuclear@5
|
319 }
|
nuclear@5
|
320 /* only the user calls this, so don't revert this selection */
|
nuclear@5
|
321 prev_active = win;
|
nuclear@5
|
322 return activate_window(win);
|
nuclear@5
|
323 }
|
nuclear@5
|
324
|
nuclear@5
|
325 static struct window *find_window(int id)
|
nuclear@5
|
326 {
|
nuclear@4
|
327 struct window *win = winlist;
|
nuclear@4
|
328
|
nuclear@4
|
329 while(win) {
|
nuclear@4
|
330 if(win->win == id) {
|
nuclear@5
|
331 return win;
|
nuclear@4
|
332 }
|
nuclear@4
|
333 win = win->next;
|
nuclear@4
|
334 }
|
nuclear@5
|
335 return 0;
|
nuclear@5
|
336 }
|
nuclear@4
|
337
|
nuclear@5
|
338 static int activate_window(struct window *win)
|
nuclear@5
|
339 {
|
nuclear@5
|
340 if(glXMakeCurrent(dpy, win->win, win->ctx) == False) {
|
nuclear@5
|
341 sgl_log("failed to activate window %d\n", (int)win->win);
|
nuclear@5
|
342 return -1;
|
nuclear@5
|
343 }
|
nuclear@5
|
344 active_win = win;
|
nuclear@5
|
345 return 0;
|
nuclear@4
|
346 }
|
nuclear@4
|
347
|
nuclear@4
|
348 static int set_title(const char *str)
|
nuclear@4
|
349 {
|
nuclear@4
|
350 XTextProperty wm_name;
|
nuclear@4
|
351
|
nuclear@4
|
352 if(!str || !active_win) {
|
nuclear@4
|
353 return -1;
|
nuclear@4
|
354 }
|
nuclear@4
|
355 XStringListToTextProperty((char**)&str, 1, &wm_name);
|
nuclear@4
|
356 XSetWMName(dpy, active_win->win, &wm_name);
|
nuclear@4
|
357 XSetWMIconName(dpy, active_win->win, &wm_name);
|
nuclear@4
|
358 XFree(wm_name.value);
|
nuclear@4
|
359 return 0;
|
nuclear@4
|
360 }
|
nuclear@4
|
361
|
nuclear@4
|
362 static void redisplay(void)
|
nuclear@4
|
363 {
|
nuclear@4
|
364 active_win->redisp_pending = 1;
|
nuclear@4
|
365 }
|
nuclear@4
|
366
|
nuclear@4
|
367 static void swap_buffers(void)
|
nuclear@4
|
368 {
|
nuclear@5
|
369 glXSwapBuffers(dpy, active_win->win);
|
nuclear@4
|
370 }
|
nuclear@4
|
371
|
nuclear@7
|
372 static int get_modifiers(void)
|
nuclear@7
|
373 {
|
nuclear@7
|
374 return modkeys;
|
nuclear@7
|
375 }
|
nuclear@7
|
376
|
nuclear@4
|
377 static void set_bits(long *mask, long bits)
|
nuclear@4
|
378 {
|
nuclear@4
|
379 *mask |= bits;
|
nuclear@4
|
380 }
|
nuclear@4
|
381
|
nuclear@4
|
382 static void clear_bits(long *mask, long bits)
|
nuclear@4
|
383 {
|
nuclear@4
|
384 *mask &= ~bits;
|
nuclear@4
|
385 }
|
nuclear@4
|
386
|
nuclear@4
|
387 static void set_event(int idx, int enable)
|
nuclear@4
|
388 {
|
nuclear@4
|
389 void (*op)(long*, long);
|
nuclear@4
|
390 op = enable ? set_bits : clear_bits;
|
nuclear@4
|
391
|
nuclear@4
|
392 switch(idx) {
|
nuclear@4
|
393 case SGL_DISPLAY:
|
nuclear@4
|
394 op(&active_win->evmask, ExposureMask);
|
nuclear@4
|
395 break;
|
nuclear@4
|
396
|
nuclear@4
|
397 case SGL_KEYBOARD:
|
nuclear@4
|
398 op(&active_win->evmask, KeyPressMask | KeyReleaseMask);
|
nuclear@4
|
399 break;
|
nuclear@4
|
400
|
nuclear@4
|
401 case SGL_MOUSE:
|
nuclear@4
|
402 op(&active_win->evmask, ButtonPressMask | ButtonReleaseMask);
|
nuclear@4
|
403 break;
|
nuclear@4
|
404
|
nuclear@4
|
405 case SGL_MOTION:
|
nuclear@4
|
406 op(&active_win->evmask, ButtonMotionMask);
|
nuclear@4
|
407 break;
|
nuclear@4
|
408
|
nuclear@4
|
409 case SGL_PASSIVE:
|
nuclear@4
|
410 op(&active_win->evmask, PointerMotionMask);
|
nuclear@4
|
411 break;
|
nuclear@4
|
412
|
nuclear@4
|
413 default:
|
nuclear@4
|
414 return;
|
nuclear@4
|
415 }
|
nuclear@4
|
416
|
nuclear@4
|
417 XSelectInput(dpy, active_win->win, active_win->evmask);
|
nuclear@4
|
418 }
|
nuclear@4
|
419
|
nuclear@4
|
420 static int process_events(void)
|
nuclear@4
|
421 {
|
nuclear@4
|
422 XEvent xev;
|
nuclear@4
|
423 void (*func)();
|
nuclear@5
|
424 struct window *win;
|
nuclear@4
|
425
|
nuclear@5
|
426 prev_active = active_win;
|
nuclear@5
|
427
|
nuclear@5
|
428 win = winlist;
|
nuclear@5
|
429 while(win) {
|
nuclear@5
|
430 if(win->redisp_pending && (func = sgl_get_callback(SGL_DISPLAY))) {
|
nuclear@5
|
431 activate_window(win);
|
nuclear@5
|
432 func();
|
nuclear@5
|
433 win->redisp_pending = 0;
|
nuclear@5
|
434 }
|
nuclear@5
|
435 win = win->next;
|
nuclear@5
|
436 }
|
nuclear@5
|
437
|
nuclear@5
|
438 func = sgl_get_callback(SGL_IDLE);
|
nuclear@5
|
439 if(!func) {
|
nuclear@5
|
440 XNextEvent(dpy, &xev);
|
nuclear@5
|
441 XPutBackEvent(dpy, &xev);
|
nuclear@5
|
442 }
|
nuclear@5
|
443
|
nuclear@5
|
444 /* process all pending events... */
|
nuclear@4
|
445 while(XPending(dpy)) {
|
nuclear@4
|
446 XNextEvent(dpy, &xev);
|
nuclear@5
|
447 if(handle_event(&xev) == -1) {
|
nuclear@5
|
448 return -1;
|
nuclear@5
|
449 }
|
nuclear@4
|
450
|
nuclear@5
|
451 if(!dpy) {
|
nuclear@5
|
452 return -1;
|
nuclear@5
|
453 }
|
nuclear@5
|
454 }
|
nuclear@5
|
455
|
nuclear@5
|
456 if(func) {
|
nuclear@5
|
457 /* ... and then call the idle function */
|
nuclear@5
|
458 func();
|
nuclear@5
|
459 }
|
nuclear@5
|
460
|
nuclear@5
|
461 activate_window(prev_active);
|
nuclear@5
|
462 return 0;
|
nuclear@5
|
463 }
|
nuclear@5
|
464
|
nuclear@5
|
465 /* returns 0, or -1 when the last window gets closed */
|
nuclear@5
|
466 static int handle_event(XEvent *xev)
|
nuclear@5
|
467 {
|
nuclear@5
|
468 int state;
|
nuclear@5
|
469 struct window *win;
|
nuclear@5
|
470 void (*func)();
|
nuclear@7
|
471 KeySym sym;
|
nuclear@5
|
472
|
nuclear@5
|
473 if((win = find_window(xev->xany.window))) {
|
nuclear@5
|
474 activate_window(win);
|
nuclear@5
|
475 } else {
|
nuclear@5
|
476 return 0;
|
nuclear@5
|
477 }
|
nuclear@5
|
478
|
nuclear@5
|
479 switch(xev->type) {
|
nuclear@5
|
480 case MapNotify:
|
nuclear@5
|
481 active_win->mapped = 1;
|
nuclear@5
|
482 break;
|
nuclear@5
|
483
|
nuclear@5
|
484 case UnmapNotify:
|
nuclear@5
|
485 active_win->mapped = 0;
|
nuclear@5
|
486 break;
|
nuclear@5
|
487
|
nuclear@5
|
488 case Expose:
|
nuclear@5
|
489 if(active_win->mapped && xev->xexpose.count == 0) {
|
nuclear@5
|
490 if((func = sgl_get_callback(SGL_DISPLAY))) {
|
nuclear@5
|
491 func();
|
nuclear@5
|
492 active_win->redisp_pending = 0;
|
nuclear@5
|
493 }
|
nuclear@5
|
494 }
|
nuclear@5
|
495 break;
|
nuclear@5
|
496
|
nuclear@5
|
497 case MotionNotify:
|
nuclear@5
|
498 if(xev->xmotion.state) {
|
nuclear@5
|
499 func = sgl_get_callback(SGL_MOTION);
|
nuclear@5
|
500 } else {
|
nuclear@5
|
501 func = sgl_get_callback(SGL_PASSIVE);
|
nuclear@5
|
502 }
|
nuclear@5
|
503 if(func) {
|
nuclear@6
|
504 func(0, xev->xmotion.x, xev->xmotion.y);
|
nuclear@5
|
505 }
|
nuclear@5
|
506 break;
|
nuclear@5
|
507
|
nuclear@5
|
508 case ButtonPress:
|
nuclear@5
|
509 if(1) {
|
nuclear@5
|
510 state = 1;
|
nuclear@5
|
511 } else {
|
nuclear@5
|
512 case ButtonRelease:
|
nuclear@5
|
513 state = 0;
|
nuclear@5
|
514 }
|
nuclear@5
|
515 if((func = sgl_get_callback(SGL_MOUSE))) {
|
nuclear@5
|
516 int bn = xev->xbutton.button - 1;
|
nuclear@6
|
517 func(0, bn, state, xev->xbutton.x, xev->xbutton.y);
|
nuclear@5
|
518 }
|
nuclear@5
|
519 break;
|
nuclear@5
|
520
|
nuclear@5
|
521 case KeyPress:
|
nuclear@5
|
522 if(1) {
|
nuclear@5
|
523 state = 1;
|
nuclear@5
|
524 } else {
|
nuclear@5
|
525 case KeyRelease:
|
nuclear@5
|
526 state = 0;
|
nuclear@5
|
527 }
|
nuclear@7
|
528 sym = XLookupKeysym(&xev->xkey, 0);
|
nuclear@7
|
529 process_key(sym, state);
|
nuclear@7
|
530
|
nuclear@5
|
531 if((func = sgl_get_callback(SGL_KEYBOARD))) {
|
nuclear@5
|
532 func(translate_keysym(sym), state);
|
nuclear@5
|
533 }
|
nuclear@5
|
534 break;
|
nuclear@5
|
535
|
nuclear@5
|
536 case ConfigureNotify:
|
nuclear@5
|
537 if((func = sgl_get_callback(SGL_RESHAPE))) {
|
nuclear@5
|
538 if(xev->xconfigure.width != active_win->width || xev->xconfigure.height != active_win->height) {
|
nuclear@5
|
539 active_win->width = xev->xconfigure.width;
|
nuclear@5
|
540 active_win->height = xev->xconfigure.height;
|
nuclear@5
|
541
|
nuclear@5
|
542 func(xev->xconfigure.width, xev->xconfigure.height);
|
nuclear@5
|
543 }
|
nuclear@5
|
544 }
|
nuclear@5
|
545 break;
|
nuclear@5
|
546
|
nuclear@5
|
547 case ClientMessage:
|
nuclear@5
|
548 if(xev->xclient.message_type == xa_wm_prot) {
|
nuclear@5
|
549 if(xev->xclient.data.l[0] == xa_wm_del_win) {
|
nuclear@5
|
550 close_window(active_win->win);
|
nuclear@5
|
551 if(!active_win) {
|
nuclear@5
|
552 return -1;
|
nuclear@4
|
553 }
|
nuclear@4
|
554 }
|
nuclear@5
|
555 }
|
nuclear@5
|
556 break;
|
nuclear@4
|
557
|
nuclear@5
|
558 default:
|
nuclear@5
|
559 break;
|
nuclear@5
|
560 }
|
nuclear@4
|
561
|
nuclear@4
|
562 return 0;
|
nuclear@4
|
563 }
|
nuclear@5
|
564
|
nuclear@7
|
565 static void process_key(KeySym sym, int state)
|
nuclear@7
|
566 {
|
nuclear@7
|
567 switch(sym) {
|
nuclear@7
|
568 case XK_Shift_L:
|
nuclear@7
|
569 case XK_Shift_R:
|
nuclear@7
|
570 modkeys = state ? (modkeys | SGL_MOD_SHIFT) : (modkeys & ~SGL_MOD_SHIFT);
|
nuclear@7
|
571 break;
|
nuclear@7
|
572
|
nuclear@7
|
573 case XK_Control_L:
|
nuclear@7
|
574 case XK_Control_R:
|
nuclear@7
|
575 modkeys = state ? (modkeys | SGL_MOD_CONTROL) : (modkeys & ~SGL_MOD_CONTROL);
|
nuclear@7
|
576 break;
|
nuclear@7
|
577
|
nuclear@7
|
578 case XK_Alt_L:
|
nuclear@7
|
579 case XK_Alt_R:
|
nuclear@7
|
580 modkeys = state ? (modkeys | SGL_MOD_ALT) : (modkeys & ~SGL_MOD_ALT);
|
nuclear@7
|
581 break;
|
nuclear@7
|
582
|
nuclear@7
|
583 default:
|
nuclear@7
|
584 break;
|
nuclear@7
|
585 }
|
nuclear@7
|
586 }
|
nuclear@7
|
587
|
nuclear@5
|
588 static int translate_keysym(KeySym sym)
|
nuclear@5
|
589 {
|
nuclear@5
|
590 if(sym < 256) {
|
nuclear@7
|
591 if(isalpha(sym) && (modkeys & SGL_MOD_SHIFT)) {
|
nuclear@7
|
592 sym = toupper(sym);
|
nuclear@7
|
593 }
|
nuclear@5
|
594 return sym;
|
nuclear@5
|
595 }
|
nuclear@5
|
596
|
nuclear@5
|
597 switch(sym) {
|
nuclear@5
|
598 case XK_BackSpace:
|
nuclear@5
|
599 return '\b';
|
nuclear@5
|
600 case XK_Tab:
|
nuclear@5
|
601 return '\t';
|
nuclear@5
|
602 case XK_Linefeed:
|
nuclear@5
|
603 return '\r';
|
nuclear@5
|
604 case XK_Return:
|
nuclear@5
|
605 return '\n';
|
nuclear@5
|
606 case XK_Escape:
|
nuclear@5
|
607 return 27;
|
nuclear@5
|
608 default:
|
nuclear@5
|
609 break;
|
nuclear@5
|
610 }
|
nuclear@5
|
611 return (int)sym;
|
nuclear@5
|
612 }
|
nuclear@7
|
613
|
nuclear@8
|
614 #else
|
nuclear@8
|
615 int sgl_wsys_x11_silence_the_fucking_empty_file_warnings;
|
nuclear@7
|
616 #endif /* USE_WSYS_MODULE_X11 */
|