1 /*
2 * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3 * Copyright (C) 2004-2021 Kim Woelders
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies of the Software, its documentation and marketing & publicity
14 * materials, and acknowledgment shall be given in the documentation, materials
15 * and software packages that this Software was used.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24 #include "config.h"
25
26 #if USE_EVHAN_POLL
27 #include <poll.h>
28 #elif USE_EVHAN_SELECT
29 #include <sys/select.h>
30 #endif
31 #include <sys/time.h>
32 #include <X11/Xlib.h>
33 #include <X11/Xutil.h>
34 #include <X11/extensions/shape.h>
35 #if USE_XSYNC
36 #include <X11/extensions/sync.h>
37 #endif
38 #if USE_XSCREENSAVER
39 #include <X11/extensions/scrnsaver.h>
40 #endif
41 #if USE_XRANDR
42 #include <X11/extensions/Xrandr.h>
43 #endif
44 #if USE_XINERAMA
45 #include <X11/extensions/Xinerama.h>
46 #endif
47 #if USE_COMPOSITE
48 #include <X11/extensions/Xcomposite.h>
49 #include <X11/extensions/Xdamage.h>
50 #include <X11/extensions/Xfixes.h>
51 #include <X11/extensions/Xrender.h>
52 #endif
53 #if USE_XPRESENT
54 #include <X11/extensions/Xpresent.h>
55 #define USE_GENERIC 1
56 #endif
57 #if USE_GLX
58 #include <GL/glx.h>
59 #endif
60 #if USE_XI2
61 #include <X11/extensions/XInput2.h>
62 #define USE_GENERIC 1
63 #endif
64
65 #include "E.h"
66 #include "aclass.h"
67 #include "ecompmgr.h"
68 #include "emodule.h"
69 #include "events.h"
70 #include "timers.h"
71 #include "tooltips.h"
72 #include "xwin.h"
73
74 #if ENABLE_DEBUG_EVENTS
75 static const char *EventName(unsigned int type);
76 #endif
77
78 /*
79 * Server extension handling
80 */
81
82 typedef struct {
83 int version;
84 int major_op, event_base, error_base;
85 } EServerExtData;
86
87 typedef struct {
88 const char *name;
89 unsigned int ix;
90 int (*query_ver)(Display * dpy, int *major, int *minor);
91 void (*init)(int avaliable);
92 } EServerExt;
93
94 static EServerExtData ExtData[12];
95
96 #define event_base_shape ExtData[XEXT_SHAPE].event_base
97 #define event_base_randr ExtData[XEXT_RANDR].event_base
98 #define event_base_damage ExtData[XEXT_DAMAGE].event_base
99 #define event_base_saver ExtData[XEXT_SCRSAVER].event_base
100 #define event_base_glx ExtData[XEXT_GLX].event_base
101
102 static void
ExtInitShape(int available)103 ExtInitShape(int available)
104 {
105 if (available)
106 return;
107
108 AlertX(_("X server setup error"), _("OK"), NULL, NULL,
109 _("FATAL ERROR:\n" "\n"
110 "This Xserver does not support the Shape extension.\n"
111 "This is required for Enlightenment to run.\n" "\n"
112 "Your Xserver probably is too old or mis-configured.\n" "\n"
113 "Exiting.\n"));
114 EExit(1);
115 }
116
117 #if USE_XSYNC
118 static void
ExtInitSync(int available)119 ExtInitSync(int available)
120 {
121 int i, num;
122 XSyncSystemCounter *xssc;
123
124 if (!available)
125 return;
126
127 xssc = XSyncListSystemCounters(disp, &num);
128 for (i = 0; i < num; i++)
129 {
130 if (!strcmp(xssc[i].name, "SERVERTIME"))
131 Mode.display.server_time = xssc[i].counter;
132 if (EDebug(EDBUG_TYPE_VERBOSE))
133 Eprintf(" Sync counter %2d: %10s %#lx %#x:%#x\n", i,
134 xssc[i].name, xssc[i].counter,
135 XSyncValueHigh32(xssc[i].resolution),
136 XSyncValueLow32(xssc[i].resolution));
137 }
138 XSyncFreeSystemCounterList(xssc);
139
140 if (Mode.display.server_time == NoXID)
141 Conf.movres.enable_sync_request = 0;
142 }
143 #endif
144
145 #if USE_XSCREENSAVER
146 static void
ExtInitSS(int available)147 ExtInitSS(int available)
148 {
149 if (!available)
150 return;
151
152 if (EDebug(EDBUG_TYPE_VERBOSE))
153 {
154 XScreenSaverInfo *xssi = XScreenSaverAllocInfo();
155
156 XScreenSaverQueryInfo(disp, WinGetXwin(VROOT), xssi);
157 Eprintf(" Screen saver window=%#lx\n", xssi->window);
158 XFree(xssi);
159 }
160 XScreenSaverSelectInput(disp, WinGetXwin(VROOT),
161 ScreenSaverNotifyMask | ScreenSaverCycleMask);
162 }
163 #endif
164
165 #if USE_XRANDR
166 static void
EventsRRUpdateInfo(void)167 EventsRRUpdateInfo(void)
168 {
169 XRRScreenConfiguration *sc;
170 int fps;
171
172 sc = XRRGetScreenInfo(disp, WinGetXwin(VROOT));
173 fps = XRRConfigCurrentRate(sc);
174 XRRFreeScreenConfigInfo(sc);
175
176 /* We may get e.g. fps = 0 (Xephyr) */
177 if (fps > 0 && fps < 240)
178 Mode.screen.fps = fps;
179
180 if (EDebug(EDBUG_TYPE_VERBOSE))
181 Eprintf("Screen refresh rate = %d(%d) Hz\n", Mode.screen.fps, fps);
182 }
183
184 static void
ExtInitRR(int available)185 ExtInitRR(int available)
186 {
187 Rotation rot;
188
189 if (!available)
190 return;
191
192 /* Listen for RandR events */
193 XRRSelectInput(disp, WinGetXwin(VROOT), RRScreenChangeNotifyMask);
194
195 XRRRotations(disp, Dpy.screen, &rot);
196 Mode.screen.rotation = rot;
197
198 EventsRRUpdateInfo();
199 }
200
201 void
EventsRandrScreenChange(XEvent * ev)202 EventsRandrScreenChange(XEvent * ev)
203 {
204 const XRRScreenChangeNotifyEvent *rrev = (XRRScreenChangeNotifyEvent *) ev;
205
206 XRRUpdateConfiguration(ev);
207
208 Mode.screen.rotation = rrev->rotation;
209
210 EventsRRUpdateInfo();
211 }
212 #endif /* USE_XRANDR */
213
214 #if USE_XI2
215 static Status
EInputQueryVersion(Display * dpy,int * major_version_return,int * minor_version_return)216 EInputQueryVersion(Display * dpy,
217 int *major_version_return, int *minor_version_return)
218 {
219 *major_version_return = XI_2_Major;
220 *minor_version_return = XI_2_Minor;
221
222 return XIQueryVersion(dpy, major_version_return, minor_version_return);
223 }
224
225 #include <X11/extensions/XInput.h>
226
227 static void
ExtInitInput(int available)228 ExtInitInput(int available)
229 {
230 int i, j, nd;
231 XIDeviceInfo *dvi, *dvis;
232
233 if (!available)
234 return;
235
236 dvis = XIQueryDevice(disp, XIAllDevices, &nd);
237 for (i = 0; i < nd; i++)
238 {
239 dvi = dvis + i;
240
241 if (dvi->use == XIMasterPointer && Mode.events.xi2_ptr == 0)
242 Mode.events.xi2_ptr = dvi->deviceid;
243 else if (dvi->use == XIMasterKeyboard && Mode.events.xi2_kbd == 0)
244 Mode.events.xi2_kbd = dvi->deviceid;
245
246 if (!EDebug(EDBUG_TYPE_VERBOSE))
247 continue;
248
249 if (i == 0)
250 Eprintf("Dev id use att ena name\n");
251 Eprintf(" %2d %2d %3d %3d %3d %-32s %2d", i,
252 dvi->deviceid, dvi->use, dvi->attachment, dvi->enabled,
253 dvi->name, dvi->num_classes);
254 for (j = 0; j < dvi->num_classes; j++)
255 {
256 printf(" %2d/%2d", dvi->classes[j]->type,
257 dvi->classes[j]->sourceid);
258 }
259 printf("\n");
260 }
261 XIFreeDeviceInfo(dvis);
262 }
263 #endif
264
265 #if USE_XPRESENT
266 static void
ExtInitPresent(int available)267 ExtInitPresent(int available)
268 {
269 if (!available)
270 return;
271
272 if (EDebug(EDBUG_TYPE_VERBOSE))
273 {
274 Eprintf(" Capabilities: %#x\n",
275 XPresentQueryCapabilities(disp, WinGetXwin(VROOT)));
276 }
277 }
278 #endif
279
280 static const EServerExt Extensions[] = {
281 {"SHAPE", XEXT_SHAPE, XShapeQueryVersion, ExtInitShape},
282 #if USE_XSYNC
283 {"SYNC", XEXT_SYNC, XSyncInitialize, ExtInitSync},
284 #endif
285 #if USE_XSCREENSAVER
286 {"MIT-SCREEN-SAVER", XEXT_SCRSAVER, XScreenSaverQueryVersion, ExtInitSS},
287 #endif
288 #if USE_XRANDR
289 {"RANDR", XEXT_RANDR, XRRQueryVersion, ExtInitRR},
290 #endif
291 #if USE_XINERAMA
292 {"XINERAMA", XEXT_XINERAMA, XineramaQueryVersion, NULL},
293 #endif
294 #if USE_COMPOSITE
295 {"Composite", XEXT_COMPOSITE, XCompositeQueryVersion, NULL},
296 {"DAMAGE", XEXT_DAMAGE, XDamageQueryVersion, NULL},
297 {"XFIXES", XEXT_FIXES, XFixesQueryVersion, NULL},
298 {"RENDER", XEXT_RENDER, XRenderQueryVersion, NULL},
299 #endif
300 #if USE_GLX
301 {"GLX", XEXT_GLX, glXQueryVersion, NULL},
302 #endif
303 #if USE_XI2
304 {"XInputExtension", XEXT_XI, EInputQueryVersion, ExtInitInput},
305 #endif
306 #if USE_XPRESENT
307 {"Present", XEXT_PRESENT, XPresentQueryVersion, ExtInitPresent},
308 #endif
309 };
310
311 static void
ExtQuery(const EServerExt * ext)312 ExtQuery(const EServerExt * ext)
313 {
314 int available, major, minor;
315 EServerExtData *exd = ExtData + ext->ix;
316
317 available = XQueryExtension(disp, ext->name, &(exd->major_op),
318 &(exd->event_base), &(exd->error_base));
319
320 if (available)
321 {
322 Mode.server.extensions |= 1 << ext->ix;
323
324 ext->query_ver(disp, &major, &minor);
325 exd->version = VERS(major, minor);
326
327 if (EDebug(EDBUG_TYPE_VERBOSE))
328 Eprintf("Extension %-15s version %d.%d -"
329 " req/evt/err base = %3d/%3d/%3d\n", ext->name,
330 major, minor,
331 exd->major_op, exd->event_base, exd->error_base);
332 }
333
334 if (ext->init)
335 ext->init(available);
336 }
337
338 int
ExtVersion(int ext_ix)339 ExtVersion(int ext_ix)
340 {
341 EServerExtData *exd = ExtData + ext_ix;
342
343 return exd->version;
344 }
345
346 /*
347 * File descriptor handling
348 */
349
350 typedef struct {
351 #if 0 /* Unused */
352 const char *name;
353 #endif
354 #if USE_EVHAN_SELECT
355 int fd;
356 #endif
357 void (*handler)(void);
358 } EventFdDesc;
359
360 static int nfds = 0;
361 #if USE_EVHAN_POLL
362 static struct pollfd *pfdl = NULL;
363 #endif
364 static EventFdDesc *pfds = NULL;
365
366 int
EventFdRegister(int fd,EventFdHandler * handler)367 EventFdRegister(int fd, EventFdHandler * handler)
368 {
369 int efd;
370
371 efd = nfds++;
372 pfds = EREALLOC(EventFdDesc, pfds, nfds);
373
374 #if USE_EVHAN_POLL
375 pfdl = EREALLOC(struct pollfd, pfdl, nfds);
376 pfdl[efd].fd = fd;
377 #elif USE_EVHAN_SELECT
378 pfds[efd].fd = fd;
379 #endif
380
381 pfds[efd].handler = handler;
382
383 return efd;
384 }
385
386 void
EventFdUnregister(int efd)387 EventFdUnregister(int efd)
388 {
389 #if USE_EVHAN_POLL
390 if (pfdl[efd].fd > 0)
391 pfdl[efd].fd = -pfdl[efd].fd;
392 #elif USE_EVHAN_SELECT
393 pfds[efd].fd = -1;
394 #endif
395 }
396
397 /*
398 * Event handling
399 */
400
401 #define DOUBLE_CLICK_TIME 250 /* Milliseconds */
402
403 void
EventsInit(void)404 EventsInit(void)
405 {
406 unsigned int i;
407
408 memset(ExtData, 0, sizeof(ExtData));
409
410 Mode.screen.fps = 60; /* If not randr or weirdness */
411
412 for (i = 0; i < E_ARRAY_SIZE(Extensions); i++)
413 ExtQuery(Extensions + i);
414
415 #if USE_COMPOSITE
416 #define XEXT_MASK_CM_ALL ((1 << XEXT_COMPOSITE) | (1 << XEXT_DAMAGE) | \
417 (1 << XEXT_FIXES) | (1 << XEXT_RENDER))
418 if (((Mode.server.extensions & XEXT_MASK_CM_ALL) == XEXT_MASK_CM_ALL) &&
419 (ExtData[XEXT_COMPOSITE].version >= VERS(0, 2)))
420 Mode.server.extensions |= 1 << XEXT_CM_ALL;
421 #endif
422
423 EventFdRegister(ConnectionNumber(disp), NULL);
424 }
425
426 static const char *
EventsGetExtensionName(int req)427 EventsGetExtensionName(int req)
428 {
429 unsigned int i;
430 EServerExtData *exd;
431
432 for (i = 0; i < E_ARRAY_SIZE(Extensions); i++)
433 {
434 exd = ExtData + Extensions[i].ix;
435 if (req == exd->major_op)
436 return Extensions[i].name;
437 }
438
439 return "?";
440 }
441
442 void
EventShowError(const XEvent * evp)443 EventShowError(const XEvent * evp)
444 {
445 const XErrorEvent *ev = &evp->xerror;
446 char buf[64], buf1[64];
447
448 if (ev->request_code < 128)
449 Esnprintf(buf, sizeof(buf), "%d", ev->request_code);
450 else
451 Esnprintf(buf, sizeof(buf), "%s.%d",
452 EventsGetExtensionName(ev->request_code), ev->minor_code);
453 XGetErrorDatabaseText(disp, "XRequest", buf, "", buf1, sizeof(buf1));
454 XGetErrorText(disp, ev->error_code, buf, sizeof(buf));
455 Eprintf("*** ERROR: xid=%#lx req=%i/%i err=%i: %s: %s\n",
456 ev->resourceid, ev->request_code, ev->minor_code,
457 ev->error_code, buf1, buf);
458 }
459
460 int
EventsUpdateXY(int * px,int * py)461 EventsUpdateXY(int *px, int *py)
462 {
463 int ss;
464
465 ss = EQueryPointer(NULL, &Mode.events.cx, &Mode.events.cy, NULL, NULL);
466 if (px)
467 *px = Mode.events.cx;
468 if (py)
469 *py = Mode.events.cy;
470
471 return ss;
472 }
473
474 void
EventsBlock(int mode)475 EventsBlock(int mode)
476 {
477 Mode.events.block = mode;
478 if (EDebug(EDBUG_TYPE_EVENTS))
479 Eprintf("%s: mode=%d\n", __func__, Mode.events.block);
480 }
481
482 static void
ModeGetXY(int rx,int ry)483 ModeGetXY(int rx, int ry)
484 {
485 /* Mode.wm.win_x/y should always be 0 if not in window mode */
486 Mode.events.cx = rx - Mode.wm.win_x;
487 Mode.events.cy = ry - Mode.wm.win_y;
488 if (Mode.wm.window)
489 {
490 if (rx < Mode.wm.win_x || rx >= Mode.wm.win_x + Mode.wm.win_w ||
491 ry < Mode.wm.win_y || ry >= Mode.wm.win_y + Mode.wm.win_h)
492 Mode.events.on_screen = 0;
493 }
494 }
495
496 static void
HandleEvent(XEvent * ev)497 HandleEvent(XEvent * ev)
498 {
499 Win win;
500
501 #if ENABLE_DEBUG_EVENTS
502 if (EDebug(ev->type))
503 EventShow(ev);
504 #endif
505
506 win = ELookupXwin(ev->xany.window);
507
508 switch (ev->type)
509 {
510 case KeyPress:
511 Mode.events.last_keycode = ev->xkey.keycode;
512 Mode.events.last_keystate = ev->xkey.state;
513 /* FALLTHROUGH */
514 case KeyRelease:
515 Mode.events.time = ev->xkey.time;
516 ModeGetXY(ev->xkey.x_root, ev->xkey.y_root);
517 #if 0 /* FIXME - Why? */
518 if (ev->xkey.root != WinGetXwin(VROOT))
519 {
520 XSetInputFocus(disp, ev->xkey.root, RevertToPointerRoot,
521 CurrentTime);
522 ESync();
523 ev->xkey.time = CurrentTime;
524 EXSendEvent(ev->xkey.root, 0, ev);
525 return;
526 }
527 #endif
528 Mode.events.on_screen = ev->xkey.same_screen;
529 goto do_stuff;
530
531 case ButtonPress:
532 case ButtonRelease:
533 Mode.events.time = ev->xbutton.time;
534 ModeGetXY(ev->xbutton.x_root, ev->xbutton.y_root);
535 Mode.events.on_screen = ev->xbutton.same_screen;
536 TooltipsHide();
537 goto do_stuff;
538
539 case MotionNotify:
540 Mode.events.time = ev->xmotion.time;
541 Mode.events.px = Mode.events.mx;
542 Mode.events.py = Mode.events.my;
543 ModeGetXY(ev->xmotion.x_root, ev->xmotion.y_root);
544 Mode.events.mx = Mode.events.cx;
545 Mode.events.my = Mode.events.cy;
546 Mode.events.on_screen = ev->xmotion.same_screen;
547 break;
548
549 case EnterNotify:
550 Mode.context_win = win;
551 Mode.events.time = ev->xcrossing.time;
552 Mode.events.on_screen = ev->xcrossing.same_screen;
553 if (ev->xcrossing.mode == NotifyGrab &&
554 ev->xcrossing.detail == NotifyInferior)
555 {
556 Mode.grabs.pointer_grab_window = ev->xany.window;
557 if (!Mode.grabs.pointer_grab_active)
558 Mode.grabs.pointer_grab_active = 2;
559 }
560 ModeGetXY(ev->xcrossing.x_root, ev->xcrossing.y_root);
561 TooltipsHide();
562 goto do_stuff;
563
564 case LeaveNotify:
565 Mode.events.time = ev->xcrossing.time;
566 Mode.events.on_screen = ev->xcrossing.same_screen;
567 if (ev->xcrossing.mode == NotifyGrab &&
568 ev->xcrossing.detail == NotifyInferior)
569 {
570 Mode.grabs.pointer_grab_window = NoXID;
571 Mode.grabs.pointer_grab_active = 0;
572 }
573 ModeGetXY(ev->xcrossing.x_root, ev->xcrossing.y_root);
574 TooltipsHide();
575 goto do_stuff;
576
577 case PropertyNotify:
578 Mode.events.time = ev->xproperty.time;
579 break;
580
581 do_stuff:
582 if (ev->xany.window == WinGetXwin(VROOT))
583 ActionclassesGlobalEvent(ev);
584 break;
585 }
586
587 switch (ev->type)
588 {
589 case KeyPress: /* 2 */
590 case KeyRelease: /* 3 */
591 /* Unfreeze keyboard in case we got here by keygrab */
592 XAllowEvents(disp, AsyncKeyboard, CurrentTime);
593 break;
594
595 case ButtonPress: /* 4 */
596 SoundPlay(SOUND_BUTTON_CLICK);
597
598 Mode.events.double_click =
599 ((ev->xbutton.time - Mode.events.last_btime < DOUBLE_CLICK_TIME) &&
600 ev->xbutton.button == Mode.events.last_button &&
601 ev->xbutton.window == Mode.events.last_bpress2);
602
603 Mode.events.last_bpress = ev->xbutton.window;
604 Mode.events.last_bpress2 = ev->xbutton.window;
605 Mode.events.last_btime = ev->xbutton.time;
606 Mode.events.last_button = ev->xbutton.button;
607 break;
608 case ButtonRelease: /* 5 */
609 SoundPlay(SOUND_BUTTON_RAISE);
610 break;
611 }
612
613 /* The new event dispatcher */
614 EventCallbacksProcess(win, ev);
615
616 /* Post-event stuff TBD */
617 switch (ev->type)
618 {
619 case ButtonRelease: /* 5 */
620 Mode.events.last_bpress = 0;
621 break;
622
623 #if 1 /* Do this here? */
624 case DestroyNotify:
625 EUnregisterXwin(ev->xdestroywindow.window);
626 break;
627 #endif
628
629 case MappingNotify:
630 XRefreshKeyboardMapping(&ev->xmapping);
631 if (Conf.testing.bindings_reload)
632 ActionclassesReload();
633 break;
634 }
635 }
636
637 static void
EventsCompress(XEvent * evq,int count)638 EventsCompress(XEvent * evq, int count)
639 {
640 XEvent *ev, *ev2;
641 int i, j, n;
642 int xa, ya, xb, yb;
643 int type;
644
645 #if ENABLE_DEBUG_EVENTS
646 /* Debug - should be taken out */
647 if (EDebug(EDBUG_TYPE_COMPRESSION))
648 for (i = 0; i < count; i++)
649 if (evq[i].type)
650 Eprintf("%s-1 %3d %s w=%#lx\n", __func__, i,
651 EventName(evq[i].type), evq[i].xany.window);
652 #endif
653
654 /* Loop through event list, starting with latest */
655 for (i = count - 1; i >= 0; i--)
656 {
657 ev = evq + i;
658
659 type = ev->type;
660 switch (type)
661 {
662 case 0:
663 /* Already thrown away */
664 default:
665 break;
666
667 case MotionNotify:
668 /* Discard all but last motion event */
669 j = i - 1;
670 n = 0;
671 for (; j >= 0; j--)
672 {
673 ev2 = evq + j;
674 if (ev2->type == type)
675 {
676 n++;
677 ev2->type = 0;
678 }
679 }
680 #if ENABLE_DEBUG_EVENTS
681 if (n && EDebug(EDBUG_TYPE_COMPRESSION))
682 Eprintf("%s: n=%4d %s %#lx x,y = %d,%d\n", __func__,
683 n, EventName(type), ev->xmotion.window,
684 ev->xmotion.x, ev->xmotion.y);
685 #endif
686 break;
687
688 case LeaveNotify:
689 for (j = i - 1; j >= 0; j--)
690 {
691 ev2 = evq + j;
692 if (ev2->type == EnterNotify)
693 {
694 if (ev2->xcrossing.window == ev->xcrossing.window)
695 goto do_enter_leave_nuked;
696 }
697 }
698 break;
699 do_enter_leave_nuked:
700 ev2->type = ev->type = 0;
701 for (n = i - 1; n > j; n--)
702 {
703 ev2 = evq + n;
704 if (ev2->type == MotionNotify)
705 {
706 if (ev2->xmotion.window != ev->xmotion.window)
707 continue;
708 ev2->type = 0;
709 }
710 }
711 #if ENABLE_DEBUG_EVENTS
712 if (EDebug(EDBUG_TYPE_COMPRESSION))
713 Eprintf("%s: n=%4d %s %#lx\n", __func__,
714 1, EventName(type), ev->xcrossing.window);
715 #endif
716 break;
717
718 case DestroyNotify:
719 for (j = i - 1; j >= 0; j--)
720 {
721 ev2 = evq + j;
722 switch (ev2->type)
723 {
724 case CreateNotify:
725 if (ev2->xcreatewindow.window !=
726 ev->xdestroywindow.window)
727 continue;
728 ev2->type = EX_EVENT_CREATE_GONE;
729 goto loop_quit_DestroyNotify;
730 case DestroyNotify:
731 break;
732 case UnmapNotify:
733 if (ev2->xunmap.window != ev->xdestroywindow.window)
734 continue;
735 ev2->type = EX_EVENT_UNMAP_GONE;
736 break;
737 case MapNotify:
738 if (ev2->xmap.window != ev->xdestroywindow.window)
739 continue;
740 ev2->type = EX_EVENT_MAP_GONE;
741 break;
742 case MapRequest:
743 if (ev2->xmaprequest.window != ev->xdestroywindow.window)
744 continue;
745 ev2->type = EX_EVENT_MAPREQUEST_GONE;
746 break;
747 case ReparentNotify:
748 if (ev2->xreparent.window != ev->xdestroywindow.window)
749 continue;
750 ev2->type = EX_EVENT_REPARENT_GONE;
751 break;
752 case ConfigureRequest:
753 if (ev2->xconfigurerequest.window !=
754 ev->xdestroywindow.window)
755 continue;
756 ev2->type = 0;
757 break;
758 default:
759 /* Nuke all other events on a destroyed window */
760 if (ev2->xany.window != ev->xdestroywindow.window)
761 continue;
762 ev2->type = 0;
763 break;
764 }
765 }
766 loop_quit_DestroyNotify:
767 break;
768
769 case Expose:
770 n = 0;
771 xa = ev->xexpose.x;
772 xb = xa + ev->xexpose.width;
773 ya = ev->xexpose.y;
774 yb = ya + ev->xexpose.height;
775 for (j = i - 1; j >= 0; j--)
776 {
777 ev2 = evq + j;
778 if (ev2->type == type &&
779 ev2->xexpose.window == ev->xexpose.window)
780 {
781 n++;
782 ev2->type = 0;
783 if (xa > ev2->xexpose.x)
784 xa = ev2->xexpose.x;
785 if (xb < ev2->xexpose.x + ev2->xexpose.width)
786 xb = ev2->xexpose.x + ev2->xexpose.width;
787 if (ya > ev2->xexpose.y)
788 ya = ev2->xexpose.y;
789 if (yb < ev2->xexpose.y + ev2->xexpose.height)
790 yb = ev2->xexpose.y + ev2->xexpose.height;
791 }
792 }
793 if (n)
794 {
795 ev->xexpose.x = xa;
796 ev->xexpose.width = xb - xa;
797 ev->xexpose.y = ya;
798 ev->xexpose.height = yb - ya;
799 }
800 #if ENABLE_DEBUG_EVENTS
801 if (EDebug(EDBUG_TYPE_COMPRESSION))
802 Eprintf("%s: n=%4d %s %#lx x=%4d-%4d y=%4d-%4d\n", __func__,
803 n, EventName(type), ev->xexpose.window, xa, xb, ya, yb);
804 #endif
805 break;
806
807 case EX_EVENT_SHAPE_NOTIFY:
808 n = 0;
809 for (j = i - 1; j >= 0; j--)
810 {
811 ev2 = evq + j;
812 if (ev2->type == type && ev2->xany.window == ev->xany.window)
813 {
814 n++;
815 ev2->type = 0;
816 }
817 }
818 #if ENABLE_DEBUG_EVENTS
819 if (n && EDebug(EDBUG_TYPE_COMPRESSION))
820 Eprintf("%s: n=%4d %s %#lx\n", __func__,
821 n, EventName(type), ev->xmotion.window);
822 #endif
823 break;
824
825 case GraphicsExpose:
826 case NoExpose:
827 /* Not using these */
828 ev->type = 0;
829 break;
830 }
831 }
832
833 #if ENABLE_DEBUG_EVENTS
834 /* Debug - should be taken out */
835 if (EDebug(EDBUG_TYPE_COMPRESSION))
836 for (i = 0; i < count; i++)
837 if (evq[i].type)
838 Eprintf("%s-2 %3d %s w=%#lx\n", __func__, i,
839 EventName(evq[i].type), evq[i].xany.window);
840 #endif
841 }
842
843 #if USE_GENERIC
844
845 #if USE_XI2
846 typedef union {
847 XIEvent gen; /* Generic XI2 */
848 XIDeviceEvent dev; /* Device events */
849 XIEnterEvent elf; /* Enter/leave, focus in/out */
850 } xie_t;
851
852 static void
_EventFetchXI2(XEvent * ev)853 _EventFetchXI2(XEvent * ev)
854 {
855 xie_t *xie = (xie_t *) ev->xcookie.data;
856
857 if (EDebug(EDBUG_TYPE_XI2))
858 Eprintf("%s: %#lx: type=%d devid=%d srcid=%d\n",
859 __func__, xie->dev.event, xie->gen.evtype,
860 xie->dev.deviceid, xie->dev.sourceid);
861
862 switch (xie->gen.evtype)
863 {
864 default:
865 break;
866 case XI_KeyPress:
867 case XI_KeyRelease:
868 case XI_ButtonPress:
869 case XI_ButtonRelease:
870 case XI_Motion:
871 ev->type = xie->gen.evtype; /* Same as core */
872 #if 0
873 /* Keep those. At least serial seems to be bad in xie. */
874 ev->xany.serial = xie->gen.serial;
875 ev->xany.send_event = xie->gen.send_event;
876 ev->xany.display = xie->gen.display;
877 #endif
878 ev->xkey.window = xie->dev.event;
879 ev->xkey.root = xie->dev.root;
880 ev->xkey.subwindow = xie->dev.child;
881 ev->xkey.time = xie->gen.time;
882 ev->xkey.x = (int)xie->dev.event_x;
883 ev->xkey.y = (int)xie->dev.event_y;
884 ev->xkey.x_root = (int)xie->dev.root_x;
885 ev->xkey.y_root = (int)xie->dev.root_y;
886 ev->xkey.state = xie->dev.mods.effective;
887 ev->xkey.keycode = xie->dev.detail;
888 #if 0
889 /* These are the only differences between the key/button/motion
890 * structs. The Xlib struct layout should ensure that things land
891 * appropriately (xmotion.is_hint is not used) */
892 ev->xbutton.button = xie->dev.detail;
893 ev->xmotion.is_hint = xie->dev.detail; /* ??? */
894 #endif
895 ev->xkey.same_screen = xie->dev.deviceid; /* FIXME */
896 break;
897 case XI_Enter:
898 case XI_Leave:
899 ev->type = xie->gen.evtype; /* Same as core */
900 #if 0
901 /* Keep those. At least serial seems to be bad in xie. */
902 ev->xany.serial = xie->gen.serial;
903 ev->xany.send_event = xie->gen.send_event;
904 ev->xany.display = xie->gen.display;
905 #endif
906 ev->xcrossing.window = xie->elf.event;
907 ev->xcrossing.root = xie->elf.root;
908 ev->xcrossing.subwindow = xie->elf.child;
909 ev->xcrossing.time = xie->gen.time;
910 ev->xcrossing.x = (int)xie->elf.event_x;
911 ev->xcrossing.y = (int)xie->elf.event_y;
912 ev->xcrossing.x_root = (int)xie->elf.root_x;
913 ev->xcrossing.y_root = (int)xie->elf.root_y;
914 /* mode and detail values are the same in core/XI2.
915 * XI2 has a few extra modes. */
916 ev->xcrossing.mode = xie->elf.mode;
917 ev->xcrossing.detail = xie->elf.detail;
918 ev->xcrossing.same_screen = xie->elf.deviceid; /* FIXME */
919 ev->xcrossing.focus = xie->elf.focus;
920 ev->xcrossing.state = xie->elf.mods.effective;
921 break;
922 case XI_FocusIn:
923 case XI_FocusOut:
924 ev->type = xie->gen.evtype; /* Same as core */
925 #if 0
926 /* Keep those. At least serial seems to be bad in xie. */
927 ev->xany.serial = xie->gen.serial;
928 ev->xany.send_event = xie->gen.send_event;
929 ev->xany.display = xie->gen.display;
930 #endif
931 ev->xfocus.window = xie->elf.event;
932 /* mode and detail values are the same in core/XI2.
933 * XI2 has a few extra modes. */
934 ev->xfocus.mode = xie->elf.mode;
935 ev->xfocus.detail = xie->elf.detail;
936 break;
937 }
938 }
939 #endif /* USE_XI2 */
940
941 #if USE_XPRESENT
942 typedef union {
943 XPresentEvent xpe;
944 XPresentConfigureNotifyEvent conf;
945 XPresentCompleteNotifyEvent cmpl;
946 XPresentIdleNotifyEvent idle;
947 } xpe_t;
948
949 static void
_EventFetchPresent(XEvent * ev)950 _EventFetchPresent(XEvent * ev)
951 {
952 xpe_t *xpe = (xpe_t *) ev->xcookie.data;
953
954 if (EDebug(EDBUG_TYPE_PRESENT))
955 Eprintf("%s: %#lx: type=%d\n",
956 __func__, xpe->idle.window, xpe->xpe.evtype);
957 }
958 #endif /* USE_XPRESENT */
959
960 static void
_EventFetchGeneric(XEvent * ev)961 _EventFetchGeneric(XEvent * ev)
962 {
963 XGenericEventCookie gec;
964
965 if (!XGetEventData(disp, &ev->xcookie))
966 return;
967
968 gec = ev->xcookie; /* Save copy for XFreeEventData() */
969
970 #if USE_XI2
971 if (ev->xcookie.extension == ExtData[XEXT_XI].major_op)
972 {
973 _EventFetchXI2(ev);
974 goto done;
975 }
976 #endif
977 #if USE_XPRESENT
978 if (ev->xcookie.extension == ExtData[XEXT_PRESENT].major_op)
979 {
980 _EventFetchPresent(ev);
981 goto done;
982 }
983 #endif
984 /* We should never go here */
985 Eprintf("*** %s: ext=%d type=%d\n", __func__,
986 ev->xcookie.extension, ev->xcookie.evtype);
987
988 done:
989 XFreeEventData(disp, &gec);
990 }
991
992 #endif /* USE_GENERIC */
993
994 static int
EventsFetch(XEvent ** evq_p,int * evq_n)995 EventsFetch(XEvent ** evq_p, int *evq_n)
996 {
997 int i, n, count;
998 XEvent *evq = *evq_p, *ev;
999 int qsz = *evq_n;
1000
1001 /* Fetch the entire event queue */
1002 for (i = count = 0; (n = XPending(disp)) > 0;)
1003 {
1004 count += n;
1005 if (count > qsz)
1006 {
1007 qsz = count;
1008 evq = EREALLOC(XEvent, evq, qsz);
1009 }
1010 ev = evq + i;
1011 for (; i < count; i++, ev++)
1012 {
1013 XNextEvent(disp, ev);
1014 #if USE_GENERIC
1015 if (ev->type == GenericEvent)
1016 {
1017 _EventFetchGeneric(ev);
1018 continue;
1019 }
1020 #endif
1021
1022 /* Map some event types to E internals */
1023 if (ev->type == event_base_shape + ShapeNotify)
1024 ev->type = EX_EVENT_SHAPE_NOTIFY;
1025 #if USE_XRANDR
1026 else if (ev->type == event_base_randr + RRScreenChangeNotify)
1027 ev->type = EX_EVENT_SCREEN_CHANGE_NOTIFY;
1028 #endif
1029 #if USE_COMPOSITE
1030 else if (ev->type == event_base_damage + XDamageNotify)
1031 ev->type = EX_EVENT_DAMAGE_NOTIFY;
1032 #endif
1033 #if USE_XSCREENSAVER
1034 else if (ev->type == event_base_saver + ScreenSaverNotify)
1035 ev->type = EX_EVENT_SAVER_NOTIFY;
1036 #endif
1037 #if USE_GLX
1038 else if (ev->type == event_base_glx + GLX_BufferSwapComplete)
1039 ev->type = EX_EVENT_GLX_FLIP;
1040 #endif
1041 }
1042 }
1043
1044 EventsCompress(evq, count);
1045
1046 *evq_p = evq;
1047 *evq_n = qsz;
1048
1049 return count;
1050 }
1051
1052 static int
EventsProcess(XEvent ** evq_p,int * evq_n,int * evq_f)1053 EventsProcess(XEvent ** evq_p, int *evq_n, int *evq_f)
1054 {
1055 int i, n, count;
1056 XEvent *evq;
1057
1058 /* Fetch the entire event queue */
1059 n = EventsFetch(evq_p, evq_n);
1060 evq = *evq_p;
1061
1062 if (EDebug(EDBUG_TYPE_EVENTS) > 1)
1063 Eprintf("%s-B %d\n", __func__, n);
1064
1065 for (i = count = 0; i < n; i++)
1066 {
1067 if (evq[i].type == 0)
1068 continue;
1069
1070 if (EDebug(EDBUG_TYPE_EVENTS) > 2)
1071 EventShow(evq + i);
1072
1073 count++;
1074 HandleEvent(evq + i);
1075 evq[i].type = 0;
1076 }
1077
1078 if (EDebug(EDBUG_TYPE_EVENTS) > 1)
1079 Eprintf("%s-E %d/%d\n", __func__, count, n);
1080
1081 if (n > *evq_f)
1082 *evq_f = n;
1083
1084 return count;
1085 }
1086
1087 /*
1088 * This is the primary event loop. Everything that is going to happen in the
1089 * window manager has to start here at some point. This is where all the
1090 * events from the X server are interpreted, timer events are inserted, etc
1091 */
1092 void
EventsMain(void)1093 EventsMain(void)
1094 {
1095 static int evq_alloc = 0;
1096 static int evq_fetch = 0;
1097 static XEvent *evq_ptr = NULL;
1098 #if USE_EVHAN_SELECT
1099 fd_set fdset;
1100 int fdsize, fd;
1101 struct timeval tval;
1102 #endif
1103 unsigned int time1, time2;
1104 int dtl, dt;
1105 int count, pfetch;
1106 int i;
1107
1108 time1 = GetTimeMs();
1109
1110 for (;;)
1111 {
1112 pfetch = 0;
1113 if (!Mode.events.block)
1114 count = EventsProcess(&evq_ptr, &evq_alloc, &pfetch);
1115
1116 if (pfetch)
1117 {
1118 evq_fetch =
1119 (pfetch > evq_fetch) ? pfetch : (3 * evq_fetch + pfetch) / 4;
1120 if (EDebug(EDBUG_TYPE_EVENTS) > 1)
1121 Eprintf("%s - Alloc/fetch/pfetch/peak=%d/%d/%d/%d)\n",
1122 __func__, evq_alloc, evq_fetch, pfetch, count);
1123 if ((evq_ptr) && ((evq_alloc - evq_fetch) > 64))
1124 {
1125 evq_alloc = 0;
1126 EFREE_NULL(evq_ptr);
1127 }
1128 }
1129
1130 /* time2 = current time */
1131 time2 = GetTimeMs();
1132 dtl = time2 - time1;
1133 Mode.events.time_ms = time1 = time2;
1134 Mode.events.seqn++;
1135 /* dtl = time spent since we last were here */
1136
1137 /* Run all expired timers */
1138 TimersRun(time2);
1139
1140 /* Run idlers */
1141 IdlersRun();
1142
1143 /* Get time to first non-expired (0 means none) */
1144 dt = TimersRunNextIn(time2);
1145
1146 /* Do composite rendering */
1147 dt = ECompMgrRender(dt);
1148
1149 if (Mode.wm.exit_mode)
1150 break;
1151
1152 if (Mode.events.block)
1153 XFlush(disp);
1154 else if (XPending(disp))
1155 continue;
1156
1157 #if USE_EVHAN_POLL
1158 for (i = 0; i < nfds; i++)
1159 pfdl[i].events = (i == 0 && Mode.events.block) ? 0 : POLLIN;
1160
1161 if (dt < 0.)
1162 dt = 0.;
1163 count = poll(pfdl, nfds, (int)dt);
1164
1165 if (EDebug(EDBUG_TYPE_EVENTS))
1166 Eprintf("%s: count=%d xfd=%d:%d dtl=%.6lf dt=%.6lf\n", __func__,
1167 count, pfdl[0].fd, pfdl[0].revents, dtl * 1e-3, dt * 1e-3);
1168
1169 if (count <= 0)
1170 continue; /* Timeout (or error) */
1171
1172 /* Excluding X fd */
1173 for (i = 1; i < nfds; i++)
1174 {
1175 if (pfdl[i].fd >= 0 && pfdl[i].revents & POLLIN)
1176 {
1177 if (EDebug(EDBUG_TYPE_EVENTS) > 1)
1178 Eprintf("Event fd %d\n", i);
1179 pfds[i].handler();
1180 }
1181 }
1182 #elif USE_EVHAN_SELECT
1183 FD_ZERO(&fdset);
1184 fdsize = -1;
1185 for (i = 0; i < nfds; i++)
1186 {
1187 if (Mode.events.block && i == 0)
1188 continue;
1189 fd = pfds[i].fd;
1190 if (fd < 0)
1191 continue;
1192 if (fdsize < fd)
1193 fdsize = fd;
1194 FD_SET(fd, &fdset);
1195 }
1196 fdsize++;
1197
1198 if (dt > 0.)
1199 {
1200 tval.tv_sec = (long)dt / 1000;
1201 tval.tv_usec = ((long)dt - tval.tv_sec * 1000) * 1000;
1202 count = select(fdsize, &fdset, NULL, NULL, &tval);
1203 }
1204 else
1205 {
1206 count = select(fdsize, &fdset, NULL, NULL, NULL);
1207 }
1208
1209 if (EDebug(EDBUG_TYPE_EVENTS))
1210 Eprintf("%s: count=%d xfd=%d:%d dtl=%.6lf dt=%.6lf\n", __func__,
1211 count, pfds[0].fd, FD_ISSET(pfds[0].fd, &fdset),
1212 dtl * 1e-3, dt * 1e-3);
1213
1214 if (count <= 0)
1215 continue; /* Timeout (or error) */
1216
1217 /* Excluding X fd */
1218 for (i = 1; i < nfds; i++)
1219 {
1220 fd = pfds[i].fd;
1221 if ((fd >= 0) && (FD_ISSET(fd, &fdset)))
1222 {
1223 if (EDebug(EDBUG_TYPE_EVENTS) > 1)
1224 Eprintf("Event fd %d\n", i);
1225 pfds[i].handler();
1226 }
1227 }
1228 #endif
1229 }
1230 }
1231
1232 #if ENABLE_DEBUG_EVENTS
1233 /*
1234 * Event debug stuff
1235 */
1236
1237 static const char *const TxtEventNames[] = {
1238 "Error", "Reply", "KeyPress", "KeyRelease", "ButtonPress",
1239 "ButtonRelease", "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn",
1240 "FocusOut", "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose",
1241 "VisibilityNotify", "CreateNotify", "DestroyNotify", "UnmapNotify",
1242 "MapNotify",
1243 "MapRequest", "ReparentNotify", "ConfigureNotify", "ConfigureRequest",
1244 "GravityNotify",
1245 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
1246 "SelectionClear",
1247 "SelectionRequest", "SelectionNotify", "ColormapNotify", "ClientMessage",
1248 "MappingNotify"
1249 };
1250
1251 static const char *
EventName(unsigned int type)1252 EventName(unsigned int type)
1253 {
1254 static char buf[16];
1255
1256 if (type < E_ARRAY_SIZE(TxtEventNames))
1257 return TxtEventNames[type];
1258
1259 switch (type)
1260 {
1261 case EX_EVENT_CREATE_GONE:
1262 return "Create-Gone";
1263 case EX_EVENT_UNMAP_GONE:
1264 return "Unmap-Gone";
1265 case EX_EVENT_MAP_GONE:
1266 return "Map-Gone";
1267 case EX_EVENT_MAPREQUEST_GONE:
1268 return "MapRequest-Gone";
1269 case EX_EVENT_REPARENT_GONE:
1270 return "Reparent-Gone";
1271 case EX_EVENT_SHAPE_NOTIFY:
1272 return "ShapeNotify";
1273 #if USE_XSCREENSAVER
1274 case EX_EVENT_SAVER_NOTIFY:
1275 return "ScreenSaverNotify";
1276 #endif
1277 #if USE_XRANDR
1278 case EX_EVENT_SCREEN_CHANGE_NOTIFY:
1279 return "ScreenChangeNotify";
1280 #endif
1281 #if USE_COMPOSITE
1282 case EX_EVENT_DAMAGE_NOTIFY:
1283 return "DamageNotify";
1284 #endif
1285 }
1286
1287 sprintf(buf, "%d", type);
1288 return buf;
1289 }
1290
1291 static const char *const TxtEventNotifyModeNames[] = {
1292 "NotifyNormal", "NotifyGrab", "NotifyUngrab", "NotifyWhileGrabbed"
1293 };
1294
1295 static const char *
EventNotifyModeName(unsigned int mode)1296 EventNotifyModeName(unsigned int mode)
1297 {
1298 if (mode < E_ARRAY_SIZE(TxtEventNotifyModeNames))
1299 return TxtEventNotifyModeNames[mode];
1300
1301 return "Unknown";
1302 }
1303
1304 static const char *const TxtEventNotifyDetailNames[] = {
1305 "NotifyAncestor", "NotifyVirtual", "NotifyInferior", "NotifyNonlinear",
1306 "NotifyNonlinearVirtual", "NotifyPointer", "NotifyPointerRoot",
1307 "NotifyDetailNone"
1308 };
1309
1310 static const char *
EventNotifyDetailName(unsigned int detail)1311 EventNotifyDetailName(unsigned int detail)
1312 {
1313 if (detail < E_ARRAY_SIZE(TxtEventNotifyDetailNames))
1314 return TxtEventNotifyDetailNames[detail];
1315
1316 return "Unknown";
1317 }
1318
1319 void
EventShow(const XEvent * ev)1320 EventShow(const XEvent * ev)
1321 {
1322 char *txt, buf[64];
1323
1324 Esnprintf(buf, sizeof(buf), "%#08lx %cEV-%s ev=%#lx",
1325 ev->xany.serial, (ev->xany.send_event) ? '*' : ' ',
1326 EventName(ev->type), ev->xany.window);
1327
1328 switch (ev->type)
1329 {
1330 case KeyPress:
1331 case KeyRelease:
1332 Eprintf("%s sub=%#lx x,y=%d,%d state=%#x keycode=%#x ss=%d\n", buf,
1333 ev->xkey.subwindow, ev->xkey.x, ev->xkey.y,
1334 ev->xkey.state, ev->xkey.keycode, ev->xkey.same_screen);
1335 break;
1336 case ButtonPress:
1337 case ButtonRelease:
1338 Eprintf("%s sub=%#lx x,y=%d,%d state=%#x button=%#x ss=%d\n", buf,
1339 ev->xbutton.subwindow, ev->xbutton.x, ev->xbutton.y,
1340 ev->xbutton.state, ev->xbutton.button, ev->xbutton.same_screen);
1341 break;
1342 case MotionNotify:
1343 Eprintf("%s sub=%#lx x,y=%d,%d rx,ry=%d,%d ss=%d\n", buf,
1344 ev->xmotion.subwindow, ev->xmotion.x, ev->xmotion.y,
1345 ev->xmotion.x_root, ev->xmotion.y_root,
1346 ev->xmotion.same_screen);
1347 break;
1348 case EnterNotify:
1349 case LeaveNotify:
1350 Eprintf("%s sub=%#lx x,y=%d,%d m=%s d=%s ss=%d focus=%d\n", buf,
1351 ev->xcrossing.subwindow, ev->xcrossing.x, ev->xcrossing.y,
1352 EventNotifyModeName(ev->xcrossing.mode),
1353 EventNotifyDetailName(ev->xcrossing.detail),
1354 ev->xcrossing.same_screen, ev->xcrossing.focus);
1355 break;
1356 case FocusIn:
1357 case FocusOut:
1358 Eprintf("%s m=%s d=%s\n", buf, EventNotifyModeName(ev->xfocus.mode),
1359 EventNotifyDetailName(ev->xfocus.detail));
1360 break;
1361 case KeymapNotify:
1362 case Expose:
1363 case GraphicsExpose:
1364 Eprintf("%sx %d+%d %dx%d\n", buf,
1365 ev->xexpose.x, ev->xexpose.y,
1366 ev->xexpose.width, ev->xexpose.height);
1367 break;
1368 case VisibilityNotify:
1369 Eprintf("%s state=%d\n", buf, ev->xvisibility.state);
1370 break;
1371 case CreateNotify:
1372 case DestroyNotify:
1373 case UnmapNotify:
1374 case MapRequest:
1375 case EX_EVENT_CREATE_GONE:
1376 case EX_EVENT_UNMAP_GONE:
1377 case EX_EVENT_MAPREQUEST_GONE:
1378 Eprintf("%s win=%#lx\n", buf, ev->xcreatewindow.window);
1379 break;
1380 case MapNotify:
1381 case EX_EVENT_MAP_GONE:
1382 Eprintf("%s win=%#lx or=%d\n", buf, ev->xmap.window,
1383 ev->xmap.override_redirect);
1384 break;
1385 case ReparentNotify:
1386 case EX_EVENT_REPARENT_GONE:
1387 Eprintf("%s win=%#lx parent=%#lx %d+%d\n", buf,
1388 ev->xreparent.window, ev->xreparent.parent,
1389 ev->xreparent.x, ev->xreparent.y);
1390 break;
1391 case ConfigureNotify:
1392 Eprintf("%s win=%#lx %d+%d %dx%d bw=%d above=%#lx\n", buf,
1393 ev->xconfigure.window, ev->xconfigure.x,
1394 ev->xconfigure.y, ev->xconfigure.width, ev->xconfigure.height,
1395 ev->xconfigure.border_width, ev->xconfigure.above);
1396 break;
1397 case ConfigureRequest:
1398 Eprintf("%s win=%#lx m=%#lx %d+%d %dx%d bw=%d above=%#lx stk=%d\n",
1399 buf, ev->xconfigurerequest.window,
1400 ev->xconfigurerequest.value_mask, ev->xconfigurerequest.x,
1401 ev->xconfigurerequest.y, ev->xconfigurerequest.width,
1402 ev->xconfigurerequest.height,
1403 ev->xconfigurerequest.border_width, ev->xconfigurerequest.above,
1404 ev->xconfigurerequest.detail);
1405 break;
1406 case GravityNotify:
1407 goto case_common;
1408 case ResizeRequest:
1409 Eprintf("%s %dx%d\n", buf,
1410 ev->xresizerequest.width, ev->xresizerequest.height);
1411 break;
1412 case CirculateNotify:
1413 case CirculateRequest:
1414 goto case_common;
1415 case PropertyNotify:
1416 txt = XGetAtomName(disp, ev->xproperty.atom);
1417 Eprintf("%s Atom=%s(%ld)\n", buf, txt, ev->xproperty.atom);
1418 XFree(txt);
1419 break;
1420 case SelectionClear:
1421 case SelectionRequest:
1422 case SelectionNotify:
1423 case ColormapNotify:
1424 goto case_common;
1425 case ClientMessage:
1426 txt = XGetAtomName(disp, ev->xclient.message_type);
1427 Eprintf("%s ev_type=%s(%ld) data: %08lx %08lx %08lx %08lx %08lx\n",
1428 buf, txt, ev->xclient.message_type,
1429 ev->xclient.data.l[0], ev->xclient.data.l[1],
1430 ev->xclient.data.l[2], ev->xclient.data.l[3],
1431 ev->xclient.data.l[4]);
1432 XFree(txt);
1433 break;
1434 case MappingNotify:
1435 Eprintf("%s req=%d first=%d count=%d\n",
1436 buf, ev->xmapping.request,
1437 ev->xmapping.first_keycode, ev->xmapping.count);
1438 break;
1439
1440 case EX_EVENT_SHAPE_NOTIFY:
1441 #define se ((XShapeEvent *)ev)
1442 Eprintf("%s kind=%d shaped=%d %d,%d %dx%d\n", buf,
1443 se->kind, se->shaped, se->x, se->y, se->width, se->height);
1444 #undef se
1445 break;
1446 #if USE_XSCREENSAVER
1447 case EX_EVENT_SAVER_NOTIFY:
1448 #define se ((XScreenSaverNotifyEvent *)ev)
1449 Eprintf("%s state=%d kind=%d\n", buf, se->state, se->kind);
1450 #undef se
1451 break;
1452 #endif
1453 #if USE_XRANDR
1454 case EX_EVENT_SCREEN_CHANGE_NOTIFY:
1455 Eprintf("%s\n", buf);
1456 break;
1457 #endif
1458 #if USE_COMPOSITE
1459 #define de ((XDamageNotifyEvent *)ev)
1460 case EX_EVENT_DAMAGE_NOTIFY:
1461 Eprintf("%s level=%d more=%x %d+%d %dx%d\n", buf,
1462 de->level, de->more,
1463 de->area.x, de->area.y, de->area.width, de->area.height);
1464 break;
1465 #undef de
1466 #endif
1467 default:
1468 case_common:
1469 Eprintf("%s\n", buf);
1470 break;
1471 }
1472 }
1473 #endif /* ENABLE_DEBUG_EVENTS */
1474