1/*
2
3Copyright (c) 1988  X Consortium
4
5Permission is hereby granted, free of charge, to any person obtaining
6a copy of this software and associated documentation files (the
7"Software"), to deal in the Software without restriction, including
8without limitation the rights to use, copy, modify, merge, publish,
9distribute, sublicense, and/or sell copies of the Software, and to
10permit persons to whom the Software is furnished to do so, subject to
11the following conditions:
12
13The above copyright notice and this permission notice shall be included
14in all copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
20OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22OTHER DEALINGS IN THE SOFTWARE.
23
24Except as contained in this notice, the name of the X Consortium shall
25not be used in advertising or otherwise to promote the sale, use or
26other dealings in this Software without prior written authorization
27from the X Consortium.
28
29*/
30
31/*
32 * Author:  Jim Fulton, MIT X Consortium
33 */
34
35#ifdef HAVE_CONFIG_H
36# include "config.h"
37#endif
38#include <stdarg.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <ctype.h>
42#include <X11/Xlocale.h>
43#include <X11/Xos.h>
44#include <X11/Xlib.h>
45#include <X11/Xutil.h>
46#include <X11/Xproto.h>
47#include <X11/extensions/Xrandr.h>
48
49#define INNER_WINDOW_WIDTH 50
50#define INNER_WINDOW_HEIGHT 50
51#define INNER_WINDOW_BORDER 4
52#define INNER_WINDOW_X 10
53#define INNER_WINDOW_Y 10
54#define OUTER_WINDOW_MIN_WIDTH (INNER_WINDOW_WIDTH + \
55				2 * (INNER_WINDOW_BORDER + INNER_WINDOW_X))
56#define OUTER_WINDOW_MIN_HEIGHT (INNER_WINDOW_HEIGHT + \
57				2 * (INNER_WINDOW_BORDER + INNER_WINDOW_Y))
58#define OUTER_WINDOW_DEF_WIDTH (OUTER_WINDOW_MIN_WIDTH + 100)
59#define OUTER_WINDOW_DEF_HEIGHT (OUTER_WINDOW_MIN_HEIGHT + 100)
60#define OUTER_WINDOW_DEF_X 100
61#define OUTER_WINDOW_DEF_Y 100
62
63
64typedef unsigned long Pixel;
65
66static const char *Yes = "YES";
67static const char *No = "NO";
68static const char *Unknown = "unknown";
69
70static const char *ProgramName;
71static Display *dpy;
72static int screen;
73
74static XIC xic = NULL;
75
76static Atom wm_delete_window;
77static Atom wm_protocols;
78
79static Bool have_rr;
80static int rr_event_base, rr_error_base;
81
82static Bool single_line = False;
83
84enum EventMaskIndex {
85    EVENT_MASK_INDEX_CORE,
86    EVENT_MASK_INDEX_RANDR,
87    NUM_EVENT_MASKS
88};
89
90enum OutputFlags {
91    InitialNewLine = 1,
92    Indent         = 2,
93    NewLine        = 4,
94};
95
96static void usage(const char *errmsg) _X_NORETURN;
97
98static void
99output_new_line(void)
100{
101    if (!single_line) {
102        printf("\n");
103    }
104}
105
106static void
107_X_ATTRIBUTE_PRINTF(2, 3)
108output(enum OutputFlags flags, const char* format, ...)
109{
110    va_list args;
111
112    if (flags & InitialNewLine) {
113        output_new_line();
114    }
115    if (flags & Indent) {
116        printf(single_line ? " " : "    ");
117    }
118
119    va_start(args, format);
120    vprintf(format, args);
121    va_end(args);
122
123    if (flags & NewLine) {
124        output_new_line();
125    }
126}
127
128static void _X_NORETURN
129graceful_exit(int status)
130{
131    if (single_line) {
132        printf("\n");
133    }
134    fflush(stdout);
135    exit(status);
136}
137
138static void
139prologue(XEvent *eventp, const char *event_name)
140{
141    XAnyEvent *e = (XAnyEvent *) eventp;
142
143    output(InitialNewLine | NewLine,
144           "%s event, serial %ld, synthetic %s, window 0x%lx,",
145           event_name, e->serial, e->send_event ? Yes : No, e->window);
146}
147
148static void
149dump(char *str, int len)
150{
151    output(0, "(");
152    len--;
153    while (len-- > 0)
154        output(0, "%02x ", (unsigned char) *str++);
155    output(0, "%02x)", (unsigned char) *str++);
156}
157
158static void
159do_KeyPress(XEvent *eventp)
160{
161    XKeyEvent *e = (XKeyEvent *) eventp;
162    KeySym ks;
163    KeyCode kc = 0;
164    Bool kc_set = False;
165    const char *ksname;
166    int nbytes, nmbbytes = 0;
167    char str[256 + 1];
168    static char *buf = NULL;
169    static int bsize = 8;
170    Status status;
171
172    if (buf == NULL)
173        buf = malloc(bsize);
174
175    nbytes = XLookupString(e, str, 256, &ks, NULL);
176
177    /* not supposed to call XmbLookupString on a key release event */
178    if (e->type == KeyPress && xic) {
179        do {
180            nmbbytes = XmbLookupString(xic, e, buf, bsize - 1, &ks, &status);
181
182            if (status == XBufferOverflow) {
183                bsize = nmbbytes + 1;
184                buf = realloc(buf, bsize);
185            }
186        } while (status == XBufferOverflow);
187        buf[nmbbytes] = '\0';
188    }
189
190    if (ks == NoSymbol)
191        ksname = "NoSymbol";
192    else {
193        if (!(ksname = XKeysymToString(ks)))
194            ksname = "(no name)";
195        kc = XKeysymToKeycode(dpy, ks);
196        kc_set = True;
197    }
198
199    output(Indent | NewLine,
200           "root 0x%lx, subw 0x%lx, time %lu, (%d,%d), root:(%d,%d),",
201           e->root, e->subwindow, e->time, e->x, e->y, e->x_root, e->y_root);
202    output(Indent | NewLine,
203           "state 0x%x, keycode %u (keysym 0x%lx, %s), same_screen %s,",
204           e->state, e->keycode, (unsigned long) ks, ksname,
205           e->same_screen ? Yes : No);
206    if (kc_set && e->keycode != kc)
207        output(Indent | NewLine, "XKeysymToKeycode returns keycode: %u", kc);
208    if (nbytes < 0)
209        nbytes = 0;
210    if (nbytes > 256)
211        nbytes = 256;
212    str[nbytes] = '\0';
213    output(Indent, "XLookupString gives %d bytes: ", nbytes);
214    if (nbytes > 0) {
215        dump(str, nbytes);
216        output(NewLine, " \"%s\"", str);
217    }
218    else {
219        output_new_line();
220    }
221
222    /* not supposed to call XmbLookupString on a key release event */
223    if (e->type == KeyPress && xic) {
224        output(Indent, "XmbLookupString gives %d bytes: ", nmbbytes);
225        if (nmbbytes > 0) {
226            dump(buf, nmbbytes);
227            output(NewLine, " \"%s\"", buf);
228        }
229        else {
230            output_new_line();
231        }
232    }
233
234    output(Indent | NewLine, "XFilterEvent returns: %s",
235           XFilterEvent(eventp, e->window) ? "True" : "False");
236}
237
238static void
239do_KeyRelease(XEvent *eventp)
240{
241    do_KeyPress(eventp);        /* since it has the same info */
242}
243
244static void
245do_ButtonPress(XEvent *eventp)
246{
247    XButtonEvent *e = (XButtonEvent *) eventp;
248
249    output(Indent | NewLine,
250           "root 0x%lx, subw 0x%lx, time %lu, (%d,%d), root:(%d,%d),",
251           e->root, e->subwindow, e->time, e->x, e->y, e->x_root, e->y_root);
252    output(Indent | NewLine, "state 0x%x, button %u, same_screen %s",
253           e->state, e->button, e->same_screen ? Yes : No);
254}
255
256static void
257do_ButtonRelease(XEvent *eventp)
258{
259    do_ButtonPress(eventp);     /* since it has the same info */
260}
261
262static void
263do_MotionNotify(XEvent *eventp)
264{
265    XMotionEvent *e = (XMotionEvent *) eventp;
266
267    output(Indent | NewLine,
268           "root 0x%lx, subw 0x%lx, time %lu, (%d,%d), root:(%d,%d),",
269           e->root, e->subwindow, e->time, e->x, e->y, e->x_root, e->y_root);
270    output(Indent | NewLine, "state 0x%x, is_hint %u, same_screen %s",
271           e->state, e->is_hint, e->same_screen ? Yes : No);
272}
273
274static void
275do_EnterNotify(XEvent *eventp)
276{
277    XCrossingEvent *e = (XCrossingEvent *) eventp;
278    const char *mode, *detail;
279    char dmode[10], ddetail[10];
280
281    switch (e->mode) {
282    case NotifyNormal:
283        mode = "NotifyNormal";
284        break;
285    case NotifyGrab:
286        mode = "NotifyGrab";
287        break;
288    case NotifyUngrab:
289        mode = "NotifyUngrab";
290        break;
291    case NotifyWhileGrabbed:
292        mode = "NotifyWhileGrabbed";
293        break;
294    default:
295        mode = dmode;
296        snprintf(dmode, sizeof(dmode), "%u", e->mode);
297        break;
298    }
299
300    switch (e->detail) {
301    case NotifyAncestor:
302        detail = "NotifyAncestor";
303        break;
304    case NotifyVirtual:
305        detail = "NotifyVirtual";
306        break;
307    case NotifyInferior:
308        detail = "NotifyInferior";
309        break;
310    case NotifyNonlinear:
311        detail = "NotifyNonlinear";
312        break;
313    case NotifyNonlinearVirtual:
314        detail = "NotifyNonlinearVirtual";
315        break;
316    case NotifyPointer:
317        detail = "NotifyPointer";
318        break;
319    case NotifyPointerRoot:
320        detail = "NotifyPointerRoot";
321        break;
322    case NotifyDetailNone:
323        detail = "NotifyDetailNone";
324        break;
325    default:
326        detail = ddetail;
327        snprintf(ddetail, sizeof(ddetail), "%u", e->detail);
328        break;
329    }
330
331    output(Indent | NewLine,
332           "root 0x%lx, subw 0x%lx, time %lu, (%d,%d), root:(%d,%d),",
333           e->root, e->subwindow, e->time, e->x, e->y, e->x_root, e->y_root);
334    output(Indent | NewLine, "mode %s, detail %s, same_screen %s,",
335           mode, detail, e->same_screen ? Yes : No);
336    output(Indent | NewLine, "focus %s, state %u",
337           e->focus ? Yes : No, e->state);
338}
339
340static void
341do_LeaveNotify(XEvent *eventp)
342{
343    do_EnterNotify(eventp);     /* since it has same information */
344}
345
346static void
347do_FocusIn(XEvent *eventp)
348{
349    XFocusChangeEvent *e = (XFocusChangeEvent *) eventp;
350    const char *mode, *detail;
351    char dmode[10], ddetail[10];
352
353    switch (e->mode) {
354    case NotifyNormal:
355        mode = "NotifyNormal";
356        break;
357    case NotifyGrab:
358        mode = "NotifyGrab";
359        break;
360    case NotifyUngrab:
361        mode = "NotifyUngrab";
362        break;
363    case NotifyWhileGrabbed:
364        mode = "NotifyWhileGrabbed";
365        break;
366    default:
367        mode = dmode;
368        snprintf(dmode, sizeof(dmode), "%u", e->mode);
369        break;
370    }
371
372    switch (e->detail) {
373    case NotifyAncestor:
374        detail = "NotifyAncestor";
375        break;
376    case NotifyVirtual:
377        detail = "NotifyVirtual";
378        break;
379    case NotifyInferior:
380        detail = "NotifyInferior";
381        break;
382    case NotifyNonlinear:
383        detail = "NotifyNonlinear";
384        break;
385    case NotifyNonlinearVirtual:
386        detail = "NotifyNonlinearVirtual";
387        break;
388    case NotifyPointer:
389        detail = "NotifyPointer";
390        break;
391    case NotifyPointerRoot:
392        detail = "NotifyPointerRoot";
393        break;
394    case NotifyDetailNone:
395        detail = "NotifyDetailNone";
396        break;
397    default:
398        detail = ddetail;
399        snprintf(ddetail, sizeof(ddetail), "%u", e->detail);
400        break;
401    }
402
403    output(Indent | NewLine, "mode %s, detail %s", mode, detail);
404}
405
406static void
407do_FocusOut(XEvent *eventp)
408{
409    do_FocusIn(eventp);         /* since it has same information */
410}
411
412static void
413do_KeymapNotify(XEvent *eventp)
414{
415    XKeymapEvent *e = (XKeymapEvent *) eventp;
416    int i;
417
418    output(Indent, "keys:  ");
419    for (i = 0; i < 32; i++) {
420        if (i == 16 && !single_line) {
421            output(InitialNewLine | Indent, "       ");
422        }
423        output(0, "%-3u ", (unsigned char) e->key_vector[i]);
424    }
425    output_new_line();
426}
427
428static void
429do_Expose(XEvent *eventp)
430{
431    XExposeEvent *e = (XExposeEvent *) eventp;
432
433    output(Indent | NewLine, "(%d,%d), width %d, height %d, count %d",
434           e->x, e->y, e->width, e->height, e->count);
435}
436
437static void
438do_GraphicsExpose(XEvent *eventp)
439{
440    XGraphicsExposeEvent *e = (XGraphicsExposeEvent *) eventp;
441    const char *m;
442    char mdummy[10];
443
444    switch (e->major_code) {
445    case X_CopyArea:
446        m = "CopyArea";
447        break;
448    case X_CopyPlane:
449        m = "CopyPlane";
450        break;
451    default:
452        m = mdummy;
453        snprintf(mdummy, sizeof(mdummy), "%d", e->major_code);
454        break;
455    }
456
457    output(Indent | NewLine, "(%d,%d), width %d, height %d, count %d,",
458           e->x, e->y, e->width, e->height, e->count);
459    output(Indent | NewLine, "major %s, minor %d", m, e->minor_code);
460}
461
462static void
463do_NoExpose(XEvent *eventp)
464{
465    XNoExposeEvent *e = (XNoExposeEvent *) eventp;
466    const char *m;
467    char mdummy[10];
468
469    switch (e->major_code) {
470    case X_CopyArea:
471        m = "CopyArea";
472        break;
473    case X_CopyPlane:
474        m = "CopyPlane";
475        break;
476    default:
477        m = mdummy;
478        snprintf(mdummy, sizeof(mdummy), "%d", e->major_code);
479        break;
480    }
481
482    output(Indent | NewLine, "major %s, minor %d", m, e->minor_code);
483    return;
484}
485
486static void
487do_VisibilityNotify(XEvent *eventp)
488{
489    XVisibilityEvent *e = (XVisibilityEvent *) eventp;
490    const char *v;
491    char vdummy[10];
492
493    switch (e->state) {
494    case VisibilityUnobscured:
495        v = "VisibilityUnobscured";
496        break;
497    case VisibilityPartiallyObscured:
498        v = "VisibilityPartiallyObscured";
499        break;
500    case VisibilityFullyObscured:
501        v = "VisibilityFullyObscured";
502        break;
503    default:
504        v = vdummy;
505        snprintf(vdummy, sizeof(vdummy), "%d", e->state);
506        break;
507    }
508
509    output(Indent | NewLine, "state %s", v);
510}
511
512static void
513do_CreateNotify(XEvent *eventp)
514{
515    XCreateWindowEvent *e = (XCreateWindowEvent *) eventp;
516
517    output(Indent | NewLine,
518           "parent 0x%lx, window 0x%lx, (%d,%d), width %d, height %d",
519           e->parent, e->window, e->x, e->y, e->width, e->height);
520    output(NewLine, "border_width %d, override %s",
521           e->border_width, e->override_redirect ? Yes : No);
522}
523
524static void
525do_DestroyNotify(XEvent *eventp)
526{
527    XDestroyWindowEvent *e = (XDestroyWindowEvent *) eventp;
528
529    output(Indent | NewLine, "event 0x%lx, window 0x%lx", e->event, e->window);
530}
531
532static void
533do_UnmapNotify(XEvent *eventp)
534{
535    XUnmapEvent *e = (XUnmapEvent *) eventp;
536
537    output(Indent | NewLine, "event 0x%lx, window 0x%lx, from_configure %s",
538           e->event, e->window, e->from_configure ? Yes : No);
539}
540
541static void
542do_MapNotify(XEvent *eventp)
543{
544    XMapEvent *e = (XMapEvent *) eventp;
545
546    output(Indent | NewLine, "event 0x%lx, window 0x%lx, override %s",
547           e->event, e->window, e->override_redirect ? Yes : No);
548}
549
550static void
551do_MapRequest(XEvent *eventp)
552{
553    XMapRequestEvent *e = (XMapRequestEvent *) eventp;
554
555    output(Indent | NewLine, "parent 0x%lx, window 0x%lx",
556           e->parent, e->window);
557}
558
559static void
560do_ReparentNotify(XEvent *eventp)
561{
562    XReparentEvent *e = (XReparentEvent *) eventp;
563
564    output(Indent | NewLine, "event 0x%lx, window 0x%lx, parent 0x%lx,",
565           e->event, e->window, e->parent);
566    output(Indent | NewLine, "(%d,%d), override %s", e->x, e->y,
567           e->override_redirect ? Yes : No);
568}
569
570static void
571do_ConfigureNotify(XEvent *eventp)
572{
573    XConfigureEvent *e = (XConfigureEvent *) eventp;
574
575    output(Indent | NewLine,
576           "event 0x%lx, window 0x%lx, (%d,%d), width %d, height %d,",
577           e->event, e->window, e->x, e->y, e->width, e->height);
578    output(Indent | NewLine, "border_width %d, above 0x%lx, override %s",
579           e->border_width, e->above, e->override_redirect ? Yes : No);
580}
581
582static void
583do_ConfigureRequest(XEvent *eventp)
584{
585    XConfigureRequestEvent *e = (XConfigureRequestEvent *) eventp;
586    const char *detail;
587    char ddummy[10];
588
589    switch (e->detail) {
590    case Above:
591        detail = "Above";
592        break;
593    case Below:
594        detail = "Below";
595        break;
596    case TopIf:
597        detail = "TopIf";
598        break;
599    case BottomIf:
600        detail = "BottomIf";
601        break;
602    case Opposite:
603        detail = "Opposite";
604        break;
605    default:
606        detail = ddummy;
607        snprintf(ddummy, sizeof(ddummy), "%d", e->detail);
608        break;
609    }
610
611    output(Indent | NewLine,
612           "parent 0x%lx, window 0x%lx, (%d,%d), width %d, height %d,",
613           e->parent, e->window, e->x, e->y, e->width, e->height);
614    output(Indent | NewLine,
615           "border_width %d, above 0x%lx, detail %s, value 0x%lx",
616           e->border_width, e->above, detail, e->value_mask);
617}
618
619static void
620do_GravityNotify(XEvent *eventp)
621{
622    XGravityEvent *e = (XGravityEvent *) eventp;
623
624    output(Indent | NewLine, "event 0x%lx, window 0x%lx, (%d,%d)",
625           e->event, e->window, e->x, e->y);
626}
627
628static void
629do_ResizeRequest(XEvent *eventp)
630{
631    XResizeRequestEvent *e = (XResizeRequestEvent *) eventp;
632
633    output(Indent | NewLine, "width %d, height %d", e->width, e->height);
634}
635
636static void
637do_CirculateNotify(XEvent *eventp)
638{
639    XCirculateEvent *e = (XCirculateEvent *) eventp;
640    const char *p;
641    char pdummy[10];
642
643    switch (e->place) {
644    case PlaceOnTop:
645        p = "PlaceOnTop";
646        break;
647    case PlaceOnBottom:
648        p = "PlaceOnBottom";
649        break;
650    default:
651        p = pdummy;
652        snprintf(pdummy, sizeof(pdummy), "%d", e->place);
653        break;
654    }
655
656    output(Indent | NewLine, "event 0x%lx, window 0x%lx, place %s",
657           e->event, e->window, p);
658}
659
660static void
661do_CirculateRequest(XEvent *eventp)
662{
663    XCirculateRequestEvent *e = (XCirculateRequestEvent *) eventp;
664    const char *p;
665    char pdummy[10];
666
667    switch (e->place) {
668    case PlaceOnTop:
669        p = "PlaceOnTop";
670        break;
671    case PlaceOnBottom:
672        p = "PlaceOnBottom";
673        break;
674    default:
675        p = pdummy;
676        snprintf(pdummy, sizeof(pdummy), "%d", e->place);
677        break;
678    }
679
680    output(Indent | NewLine, "parent 0x%lx, window 0x%lx, place %s",
681           e->parent, e->window, p);
682}
683
684static void
685do_PropertyNotify(XEvent *eventp)
686{
687    XPropertyEvent *e = (XPropertyEvent *) eventp;
688    char *aname = XGetAtomName(dpy, e->atom);
689    const char *s;
690    char sdummy[10];
691
692    switch (e->state) {
693    case PropertyNewValue:
694        s = "PropertyNewValue";
695        break;
696    case PropertyDelete:
697        s = "PropertyDelete";
698        break;
699    default:
700        s = sdummy;
701        snprintf(sdummy, sizeof(sdummy), "%d", e->state);
702        break;
703    }
704
705    output(Indent | NewLine, "atom 0x%lx (%s), time %lu, state %s",
706           e->atom, aname ? aname : Unknown, e->time, s);
707
708    XFree(aname);
709}
710
711static void
712do_SelectionClear(XEvent *eventp)
713{
714    XSelectionClearEvent *e = (XSelectionClearEvent *) eventp;
715    char *sname = XGetAtomName(dpy, e->selection);
716
717    output(Indent | NewLine, "selection 0x%lx (%s), time %lu",
718           e->selection, sname ? sname : Unknown, e->time);
719
720    XFree(sname);
721}
722
723static void
724do_SelectionRequest(XEvent *eventp)
725{
726    XSelectionRequestEvent *e = (XSelectionRequestEvent *) eventp;
727    char *sname = XGetAtomName(dpy, e->selection);
728    char *tname = XGetAtomName(dpy, e->target);
729    char *pname = XGetAtomName(dpy, e->property);
730
731    output(Indent | NewLine,
732           "owner 0x%lx, requestor 0x%lx, selection 0x%lx (%s),",
733           e->owner, e->requestor, e->selection, sname ? sname : Unknown);
734    output(Indent | NewLine,
735           "target 0x%lx (%s), property 0x%lx (%s), time %lu",
736           e->target, tname ? tname : Unknown, e->property,
737           pname ? pname : Unknown, e->time);
738
739    XFree(sname);
740    XFree(tname);
741    XFree(pname);
742}
743
744static void
745do_SelectionNotify(XEvent *eventp)
746{
747    XSelectionEvent *e = (XSelectionEvent *) eventp;
748    char *sname = XGetAtomName(dpy, e->selection);
749    char *tname = XGetAtomName(dpy, e->target);
750    char *pname = XGetAtomName(dpy, e->property);
751
752    output(Indent | NewLine, "selection 0x%lx (%s), target 0x%lx (%s),",
753           e->selection, sname ? sname : Unknown, e->target,
754           tname ? tname : Unknown);
755    output(Indent | NewLine, "property 0x%lx (%s), time %lu",
756           e->property, pname ? pname : Unknown, e->time);
757
758    XFree(sname);
759    XFree(tname);
760    XFree(pname);
761}
762
763static void
764do_ColormapNotify(XEvent *eventp)
765{
766    XColormapEvent *e = (XColormapEvent *) eventp;
767    const char *s;
768    char sdummy[10];
769
770    switch (e->state) {
771    case ColormapInstalled:
772        s = "ColormapInstalled";
773        break;
774    case ColormapUninstalled:
775        s = "ColormapUninstalled";
776        break;
777    default:
778        s = sdummy;
779        snprintf(sdummy, sizeof(sdummy), "%d", e->state);
780        break;
781    }
782
783    output(Indent | NewLine, "colormap 0x%lx, new %s, state %s",
784           e->colormap, e->new ? Yes : No, s);
785}
786
787static void
788do_ClientMessage(XEvent *eventp)
789{
790    XClientMessageEvent *e = (XClientMessageEvent *) eventp;
791
792    char *mname = XGetAtomName(dpy, e->message_type);
793
794    if (e->message_type == wm_protocols) {
795        char *message = XGetAtomName(dpy, e->data.l[0]);
796
797        output(Indent | NewLine,
798               "message_type 0x%lx (%s), format %d, message 0x%lx (%s)",
799               e->message_type, mname ? mname : Unknown, e->format,
800               e->data.l[0], message);
801        XFree(message);
802    }
803    else {
804        output(Indent | NewLine, "message_type 0x%lx (%s), format %d",
805               e->message_type, mname ? mname : Unknown, e->format);
806    }
807
808    XFree(mname);
809
810    if (e->format == 32
811        && e->message_type == wm_protocols
812        && (Atom) e->data.l[0] == wm_delete_window
813    ) {
814        graceful_exit(0);
815    }
816}
817
818static void
819do_MappingNotify(XEvent *eventp)
820{
821    XMappingEvent *e = (XMappingEvent *) eventp;
822    const char *r;
823    char rdummy[10];
824
825    switch (e->request) {
826    case MappingModifier:
827        r = "MappingModifier";
828        break;
829    case MappingKeyboard:
830        r = "MappingKeyboard";
831        break;
832    case MappingPointer:
833        r = "MappingPointer";
834        break;
835    default:
836        r = rdummy;
837        snprintf(rdummy, sizeof(rdummy), "%d", e->request);
838        break;
839    }
840
841    output(Indent | NewLine, "request %s, first_keycode %d, count %d",
842           r, e->first_keycode, e->count);
843    XRefreshKeyboardMapping(e);
844}
845
846static void
847print_SubPixelOrder(SubpixelOrder subpixel_order)
848{
849    switch (subpixel_order) {
850    case SubPixelUnknown:
851        output(0, "SubPixelUnknown");
852        return;
853    case SubPixelHorizontalRGB:
854        output(0, "SubPixelHorizontalRGB");
855        return;
856    case SubPixelHorizontalBGR:
857        output(0, "SubPixelHorizontalBGR");
858        return;
859    case SubPixelVerticalRGB:
860        output(0, "SubPixelVerticalRGB");
861        return;
862    case SubPixelVerticalBGR:
863        output(0, "SubPixelVerticalBGR");
864        return;
865    case SubPixelNone:
866        output(0, "SubPixelNone");
867        return;
868    default:
869        output(0, "%d", subpixel_order);
870    }
871}
872
873static void
874print_Rotation(Rotation rotation)
875{
876    if (rotation & RR_Rotate_0)
877        output(0, "RR_Rotate_0");
878    else if (rotation & RR_Rotate_90)
879        output(0, "RR_Rotate_90");
880    else if (rotation & RR_Rotate_180)
881        output(0, "RR_Rotate_180");
882    else if (rotation & RR_Rotate_270)
883        output(0, "RR_Rotate_270");
884    else {
885        output(0, "%d", rotation);
886        return;
887    }
888    if (rotation & RR_Reflect_X)
889        output(0, ", RR_Reflect_X");
890    if (rotation & RR_Reflect_Y)
891        output(0, ", RR_Reflect_Y");
892}
893
894static void
895print_Connection(Connection connection)
896{
897    switch (connection) {
898    case RR_Connected:
899        output(0, "RR_Connected");
900        return;
901    case RR_Disconnected:
902        output(0, "RR_Disconnected");
903        return;
904    case RR_UnknownConnection:
905        output(0, "RR_UnknownConnection");
906        return;
907    default:
908        output(0, "%d", connection);
909    }
910}
911
912static void
913do_RRScreenChangeNotify(XEvent *eventp)
914{
915    XRRScreenChangeNotifyEvent *e = (XRRScreenChangeNotifyEvent *) eventp;
916
917    XRRUpdateConfiguration(eventp);
918    output(Indent | NewLine, "root 0x%lx, timestamp %lu, config_timestamp %lu",
919           e->root, e->timestamp, e->config_timestamp);
920    output(Indent, "size_index %hu", e->size_index);
921    output(0, ", subpixel_order ");
922    print_SubPixelOrder(e->subpixel_order);
923    output(InitialNewLine | Indent, "rotation ");
924    print_Rotation(e->rotation);
925    output(InitialNewLine | Indent | NewLine,
926           "width %d, height %d, mwidth %d, mheight %d",
927           e->width, e->height, e->mwidth, e->mheight);
928}
929
930static void
931do_RRNotify_OutputChange(XEvent *eventp, XRRScreenResources *screen_resources)
932{
933    XRROutputChangeNotifyEvent *e = (XRROutputChangeNotifyEvent *) eventp;
934    XRROutputInfo *output_info = NULL;
935    XRRModeInfo *mode_info = NULL;
936
937    if (screen_resources) {
938        int i;
939
940        output_info = XRRGetOutputInfo(dpy, screen_resources, e->output);
941        for (i = 0; i < screen_resources->nmode; i++)
942            if (screen_resources->modes[i].id == e->mode) {
943                mode_info = &screen_resources->modes[i];
944                break;
945            }
946    }
947    output(Indent | NewLine, "subtype XRROutputChangeNotifyEvent");
948    if (output_info)
949        output(Indent, "output %s, ", output_info->name);
950    else
951        output(Indent, "output %lu, ", e->output);
952    if (e->crtc)
953        output(0, "crtc %lu, ", e->crtc);
954    else
955        output(0, "crtc None, ");
956    if (mode_info)
957        output(NewLine, "mode %s (%dx%d)", mode_info->name, mode_info->width,
958               mode_info->height);
959    else if (e->mode)
960        output(NewLine, "mode %lu", e->mode);
961    else
962        output(NewLine, "mode None");
963    output(Indent, "rotation ");
964    print_Rotation(e->rotation);
965    output(InitialNewLine | Indent, "connection ");
966    print_Connection(e->connection);
967    output(0, ", subpixel_order ");
968    print_SubPixelOrder(e->subpixel_order);
969    output_new_line();
970    XRRFreeOutputInfo(output_info);
971}
972
973static void
974do_RRNotify_CrtcChange(XEvent *eventp, XRRScreenResources *screen_resources)
975{
976    XRRCrtcChangeNotifyEvent *e = (XRRCrtcChangeNotifyEvent *) eventp;
977    XRRModeInfo *mode_info = NULL;
978
979    if (screen_resources) {
980        int i;
981
982        for (i = 0; i < screen_resources->nmode; i++)
983            if (screen_resources->modes[i].id == e->mode) {
984                mode_info = &screen_resources->modes[i];
985                break;
986            }
987    }
988    output(Indent | NewLine, "subtype XRRCrtcChangeNotifyEvent");
989    if (e->crtc)
990        output(Indent, "crtc %lu, ", e->crtc);
991    else
992        output(Indent, "crtc None, ");
993    if (mode_info)
994        output(0, "mode %s, ", mode_info->name);
995    else if (e->mode)
996        output(0, "mode %lu, ", e->mode);
997    else
998        output(0, "mode None, ");
999    output(0, "rotation ");
1000    print_Rotation(e->rotation);
1001    output(InitialNewLine | Indent | NewLine, "x %d, y %d, width %d, height %d",
1002           e->x, e->y, e->width, e->height);
1003}
1004
1005static void
1006do_RRNotify_OutputProperty(XEvent *eventp,
1007                           XRRScreenResources *screen_resources)
1008{
1009    XRROutputPropertyNotifyEvent *e = (XRROutputPropertyNotifyEvent *) eventp;
1010    XRROutputInfo *output_info = NULL;
1011    char *property = XGetAtomName(dpy, e->property);
1012
1013    if (screen_resources)
1014        output_info = XRRGetOutputInfo(dpy, screen_resources, e->output);
1015    output(Indent | NewLine, "subtype XRROutputPropertyChangeNotifyEvent");
1016    if (output_info)
1017        output(Indent, "output %s, ", output_info->name);
1018    else
1019        output(Indent, "output %lu, ", e->output);
1020    output(0, "property %s, timestamp %lu, state ", property, e->timestamp);
1021    if (e->state == PropertyNewValue)
1022        output(NewLine, "NewValue");
1023    else if (e->state == PropertyDelete)
1024        output(NewLine, "Delete");
1025    else
1026        output(NewLine, "%d", e->state);
1027    XRRFreeOutputInfo(output_info);
1028    XFree(property);
1029}
1030
1031static void
1032do_RRNotify(XEvent *eventp)
1033{
1034    XRRNotifyEvent *e = (XRRNotifyEvent *) eventp;
1035    XRRScreenResources *screen_resources;
1036
1037    XRRUpdateConfiguration(eventp);
1038    screen_resources = XRRGetScreenResources(dpy, e->window);
1039    prologue(eventp, "RRNotify");
1040    switch (e->subtype) {
1041    case RRNotify_OutputChange:
1042        do_RRNotify_OutputChange(eventp, screen_resources);
1043        break;
1044    case RRNotify_CrtcChange:
1045        do_RRNotify_CrtcChange(eventp, screen_resources);
1046        break;
1047    case RRNotify_OutputProperty:
1048        do_RRNotify_OutputProperty(eventp, screen_resources);
1049        break;
1050    default:
1051        output(Indent | NewLine, "subtype %d", e->subtype);
1052    }
1053    XRRFreeScreenResources(screen_resources);
1054}
1055
1056static void
1057set_sizehints(XSizeHints *hintp, int min_width, int min_height,
1058              int defwidth, int defheight, int defx, int defy, char *geom)
1059{
1060    int geom_result;
1061
1062    /* set the size hints, algorithm from xlib xbiff */
1063
1064    hintp->width = hintp->min_width = min_width;
1065    hintp->height = hintp->min_height = min_height;
1066    hintp->flags = PMinSize;
1067    hintp->x = hintp->y = 0;
1068    geom_result = NoValue;
1069    if (geom != NULL) {
1070        geom_result = XParseGeometry(geom, &hintp->x, &hintp->y,
1071                                     (unsigned int *) &hintp->width,
1072                                     (unsigned int *) &hintp->height);
1073        if ((geom_result & WidthValue) && (geom_result & HeightValue)) {
1074#ifndef max
1075#define max(a,b) ((a) > (b) ? (a) : (b))
1076#endif
1077            hintp->width = max(hintp->width, hintp->min_width);
1078            hintp->height = max(hintp->height, hintp->min_height);
1079            hintp->flags |= USSize;
1080        }
1081        if ((geom_result & XValue) && (geom_result & YValue)) {
1082            hintp->flags += USPosition;
1083        }
1084    }
1085    if (!(hintp->flags & USSize)) {
1086        hintp->width = defwidth;
1087        hintp->height = defheight;
1088        hintp->flags |= PSize;
1089    }
1090/*
1091    if (!(hintp->flags & USPosition)) {
1092	hintp->x = defx;
1093	hintp->y = defy;
1094	hintp->flags |= PPosition;
1095    }
1096 */
1097    if (geom_result & XNegative) {
1098        hintp->x = DisplayWidth(dpy, DefaultScreen(dpy)) + hintp->x -
1099            hintp->width;
1100    }
1101    if (geom_result & YNegative) {
1102        hintp->y = DisplayHeight(dpy, DefaultScreen(dpy)) + hintp->y -
1103            hintp->height;
1104    }
1105}
1106
1107static void
1108usage(const char *errmsg)
1109{
1110    const char *msg =
1111"    -display displayname                X server to contact\n"
1112"    -geometry geom                      size and location of window\n"
1113"    -bw pixels                          border width in pixels\n"
1114"    -bs {NotUseful,WhenMapped,Always}   backingstore attribute\n"
1115"    -id windowid                        use existing window\n"
1116"    -root                               use root window\n"
1117"    -s                                  set save-unders attribute\n"
1118"    -name string                        window name\n"
1119"    -rv                                 reverse video\n"
1120"    -event event_mask                   select 'event_mask' events\n"
1121"           Supported event masks: keyboard mouse expose visibility structure\n"
1122"                                  substructure focus property colormap\n"
1123"                                  owner_grab_button randr button\n"
1124"           This option can be specified multiple times to select multiple\n"
1125"           event masks.\n"
1126"    -1                                  display only a single line per event\n"
1127"    -version                            print version and exit\n"
1128"\n";
1129
1130    if (errmsg != NULL)
1131        fprintf(stderr, "%s: %s\n", ProgramName, errmsg);
1132
1133    fprintf(stderr, "usage:  %s [-options ...]\n", ProgramName);
1134    fprintf(stderr, "where options include:\n");
1135    fputs(msg, stderr);
1136
1137    exit(1);
1138}
1139
1140static int
1141parse_backing_store(const char *s)
1142{
1143    size_t len = strlen(s);
1144
1145    if (strncasecmp(s, "NotUseful", len) == 0)
1146        return (NotUseful);
1147    if (strncasecmp(s, "WhenMapped", len) == 0)
1148        return (WhenMapped);
1149    if (strncasecmp(s, "Always", len) == 0)
1150        return (Always);
1151
1152    fprintf(stderr, "%s: unrecognized argument '%s' for -bs\n", ProgramName, s);
1153    usage(NULL);
1154}
1155
1156static Bool
1157parse_event_mask(const char *s, long event_masks[])
1158{
1159    const struct {
1160        const char *name;
1161        enum EventMaskIndex mask_index;
1162        long mask;
1163    } events[] = {
1164        { "keyboard",
1165          EVENT_MASK_INDEX_CORE,
1166          KeyPressMask | KeyReleaseMask | KeymapStateMask },
1167        { "mouse",
1168          EVENT_MASK_INDEX_CORE,
1169          ButtonPressMask | ButtonReleaseMask | EnterWindowMask |
1170          LeaveWindowMask | PointerMotionMask | Button1MotionMask |
1171          Button2MotionMask | Button3MotionMask | Button4MotionMask |
1172          Button5MotionMask | ButtonMotionMask },
1173        { "button",
1174          EVENT_MASK_INDEX_CORE,
1175          ButtonPressMask | ButtonReleaseMask },
1176        { "expose",
1177          EVENT_MASK_INDEX_CORE,
1178          ExposureMask },
1179        { "visibility",
1180          EVENT_MASK_INDEX_CORE,
1181          VisibilityChangeMask },
1182        { "structure",
1183          EVENT_MASK_INDEX_CORE,
1184          StructureNotifyMask },
1185        { "substructure",
1186          EVENT_MASK_INDEX_CORE,
1187          SubstructureNotifyMask | SubstructureRedirectMask },
1188        { "focus",
1189          EVENT_MASK_INDEX_CORE,
1190          FocusChangeMask },
1191        { "property",
1192          EVENT_MASK_INDEX_CORE,
1193          PropertyChangeMask },
1194        { "colormap",
1195          EVENT_MASK_INDEX_CORE,
1196          ColormapChangeMask },
1197        { "owner_grab_button",
1198          EVENT_MASK_INDEX_CORE,
1199          OwnerGrabButtonMask },
1200        { "randr",
1201          EVENT_MASK_INDEX_RANDR,
1202          RRScreenChangeNotifyMask | RRCrtcChangeNotifyMask |
1203          RROutputChangeNotifyMask | RROutputPropertyNotifyMask },
1204        { NULL, 0, 0 }
1205    };
1206    int i;
1207
1208    for (i = 0; events[i].name; i++) {
1209        if (!s || !strcmp(s, events[i].name)) {
1210            event_masks[events[i].mask_index] |= events[i].mask;
1211            if (s)
1212                return True;
1213        }
1214    }
1215
1216    if (s != NULL)
1217        fprintf(stderr, "%s: unrecognized event mask '%s'\n", ProgramName, s);
1218
1219    return False;
1220}
1221
1222int
1223main(int argc, char **argv)
1224{
1225    char *displayname = NULL;
1226    char *geom = NULL;
1227    int i;
1228    XSizeHints hints;
1229    int borderwidth = 2;
1230    Window w, subw;
1231    XSetWindowAttributes attr;
1232    XWindowAttributes wattr;
1233    unsigned long mask = 0L;
1234    int done;
1235    const char *name = "Event Tester";
1236    Bool reverse = False;
1237    Bool use_root = False;
1238    unsigned long back, fore;
1239    XIM xim;
1240    XIMStyles *xim_styles;
1241    XIMStyle xim_style = 0;
1242    char *modifiers;
1243    char *imvalret;
1244    long event_masks[NUM_EVENT_MASKS];
1245    Bool event_mask_specified = False;
1246
1247    ProgramName = argv[0];
1248
1249    if (setlocale(LC_ALL, "") == NULL) {
1250        fprintf(stderr, "%s: warning: could not set default locale\n",
1251                ProgramName);
1252    }
1253
1254    memset(event_masks, 0, sizeof(event_masks));
1255
1256    w = 0;
1257    for (i = 1; i < argc; i++) {
1258        char *arg = argv[i];
1259
1260        if (arg[0] == '-') {
1261            switch (arg[1]) {
1262            case 'd':          /* -display host:dpy */
1263                if (++i >= argc)
1264                    usage("-display requires an argument");
1265                displayname = argv[i];
1266                continue;
1267            case 'g':          /* -geometry geom */
1268                if (++i >= argc)
1269                    usage("-geometry requires an argument");
1270                geom = argv[i];
1271                continue;
1272            case 'b':
1273                switch (arg[2]) {
1274                case 'w':      /* -bw pixels */
1275                    if (++i >= argc)
1276                        usage("-bw requires an argument");
1277                    borderwidth = atoi(argv[i]);
1278                    continue;
1279                case 's':      /* -bs type */
1280                    if (++i >= argc)
1281                        usage("-bs requires an argument");
1282                    attr.backing_store = parse_backing_store(argv[i]);
1283                    mask |= CWBackingStore;
1284                    continue;
1285                default:
1286                    goto unrecognized;
1287                }
1288            case 'i':          /* -id */
1289                if (++i >= argc)
1290                    usage("-id requires an argument");
1291                sscanf(argv[i], "0x%lx", &w);
1292                if (!w)
1293                    sscanf(argv[i], "%lu", &w);
1294                if (!w) {
1295                    fprintf(stderr,
1296                            "%s: unable to parse argument '%s' for -id\n",
1297                            ProgramName, argv[i]);
1298                    usage(NULL);
1299                }
1300                continue;
1301            case 'n':          /* -name */
1302                if (++i >= argc)
1303                    usage("-name requires an argument");
1304                name = argv[i];
1305                continue;
1306            case 'r':
1307                switch (arg[2]) {
1308                case 'o':      /* -root */
1309                    use_root = True;
1310                    continue;
1311                case 'v':      /* -rv */
1312                    reverse = True;
1313                    continue;
1314                default:
1315                    goto unrecognized;
1316                }
1317                continue;
1318            case 's':          /* -s */
1319                attr.save_under = True;
1320                mask |= CWSaveUnder;
1321                continue;
1322            case 'e':          /* -event */
1323                if (++i >= argc)
1324                    usage("-event requires an argument");
1325                if (!parse_event_mask(argv[i], event_masks))
1326                    usage(NULL);
1327                event_mask_specified = True;
1328                continue;
1329            case '1':
1330                single_line = True;
1331                continue;
1332            case 'v':
1333                puts(PACKAGE_STRING);
1334                exit(0);
1335            default:
1336                goto unrecognized;
1337            }                   /* end switch on - */
1338        }
1339        else {
1340 unrecognized:
1341            fprintf(stderr, "%s: unrecognized argument '%s'\n",
1342                    ProgramName, arg);
1343            usage(NULL);
1344        }
1345    }                           /* end for over argc */
1346
1347    /* if no -event options were specified, pretend all of them were */
1348    if (!event_mask_specified)
1349        parse_event_mask(NULL, event_masks);
1350
1351    dpy = XOpenDisplay(displayname);
1352    if (!dpy) {
1353        fprintf(stderr, "%s:  unable to open display '%s'\n",
1354                ProgramName, XDisplayName(displayname));
1355        exit(1);
1356    }
1357
1358    /* we're testing the default input method */
1359    modifiers = XSetLocaleModifiers("@im=none");
1360    if (modifiers == NULL) {
1361        fprintf(stderr, "%s:  XSetLocaleModifiers failed\n", ProgramName);
1362    }
1363
1364    xim = XOpenIM(dpy, NULL, NULL, NULL);
1365    if (xim == NULL) {
1366        fprintf(stderr, "%s:  XOpenIM failed\n", ProgramName);
1367    }
1368
1369    if (xim) {
1370        imvalret = XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL);
1371        if (imvalret != NULL || xim_styles == NULL) {
1372            fprintf(stderr, "%s:  input method doesn't support any styles\n",
1373                    ProgramName);
1374        }
1375
1376        if (xim_styles) {
1377            xim_style = 0;
1378            for (i = 0; i < xim_styles->count_styles; i++) {
1379                if (xim_styles->supported_styles[i] ==
1380                    (XIMPreeditNothing | XIMStatusNothing)) {
1381                    xim_style = xim_styles->supported_styles[i];
1382                    break;
1383                }
1384            }
1385
1386            if (xim_style == 0) {
1387                fprintf(stderr,
1388                        "%s: input method doesn't support the style we support\n",
1389                        ProgramName);
1390            }
1391            XFree(xim_styles);
1392        }
1393    }
1394
1395    screen = DefaultScreen(dpy);
1396
1397    attr.event_mask = event_masks[EVENT_MASK_INDEX_CORE];
1398
1399    if (use_root)
1400        w = RootWindow(dpy, screen);
1401
1402    if (w) {
1403        XGetWindowAttributes(dpy, w, &wattr);
1404        if (wattr.all_event_masks & ButtonPressMask)
1405            attr.event_mask &= ~ButtonPressMask;
1406        attr.event_mask &= ~SubstructureRedirectMask;
1407        XSelectInput(dpy, w, attr.event_mask);
1408    }
1409    else {
1410        set_sizehints(&hints, OUTER_WINDOW_MIN_WIDTH, OUTER_WINDOW_MIN_HEIGHT,
1411                      OUTER_WINDOW_DEF_WIDTH, OUTER_WINDOW_DEF_HEIGHT,
1412                      OUTER_WINDOW_DEF_X, OUTER_WINDOW_DEF_Y, geom);
1413
1414        if (reverse) {
1415            back = BlackPixel(dpy, screen);
1416            fore = WhitePixel(dpy, screen);
1417        }
1418        else {
1419            back = WhitePixel(dpy, screen);
1420            fore = BlackPixel(dpy, screen);
1421        }
1422
1423        attr.background_pixel = back;
1424        attr.border_pixel = fore;
1425        mask |= (CWBackPixel | CWBorderPixel | CWEventMask);
1426
1427        w = XCreateWindow(dpy, RootWindow(dpy, screen), hints.x, hints.y,
1428                          hints.width, hints.height, borderwidth, 0,
1429                          InputOutput, (Visual *) CopyFromParent, mask, &attr);
1430
1431        XSetStandardProperties(dpy, w, name, NULL, (Pixmap) 0,
1432                               argv, argc, &hints);
1433
1434        subw = XCreateSimpleWindow(dpy, w, INNER_WINDOW_X, INNER_WINDOW_Y,
1435                                   INNER_WINDOW_WIDTH, INNER_WINDOW_HEIGHT,
1436                                   INNER_WINDOW_BORDER,
1437                                   attr.border_pixel, attr.background_pixel);
1438
1439        wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False);
1440        wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
1441        XSetWMProtocols(dpy, w, &wm_delete_window, 1);
1442
1443        XMapWindow(dpy, subw);  /* map before w so that it appears */
1444        XMapWindow(dpy, w);
1445
1446        printf("Outer window is 0x%lx, inner window is 0x%lx\n", w, subw);
1447    }
1448
1449    if (xim && xim_style) {
1450        xic = XCreateIC(xim,
1451                        XNInputStyle, xim_style,
1452                        XNClientWindow, w, XNFocusWindow, w, NULL);
1453
1454        if (xic == NULL) {
1455            fprintf(stderr, "XCreateIC failed\n");
1456        }
1457    }
1458
1459    have_rr = XRRQueryExtension(dpy, &rr_event_base, &rr_error_base);
1460    if (have_rr) {
1461        int rr_major, rr_minor;
1462
1463        if (XRRQueryVersion(dpy, &rr_major, &rr_minor)) {
1464            int rr_mask = event_masks[EVENT_MASK_INDEX_RANDR];
1465
1466            if (rr_major == 1 && rr_minor <= 1) {
1467                rr_mask &= ~(RRCrtcChangeNotifyMask |
1468                             RROutputChangeNotifyMask |
1469                             RROutputPropertyNotifyMask);
1470            }
1471
1472            XRRSelectInput(dpy, w, rr_mask);
1473        }
1474    }
1475
1476    for (done = 0; !done;) {
1477        XEvent event;
1478
1479        XNextEvent(dpy, &event);
1480
1481        switch (event.type) {
1482        case KeyPress:
1483            prologue(&event, "KeyPress");
1484            do_KeyPress(&event);
1485            break;
1486        case KeyRelease:
1487            prologue(&event, "KeyRelease");
1488            do_KeyRelease(&event);
1489            break;
1490        case ButtonPress:
1491            prologue(&event, "ButtonPress");
1492            do_ButtonPress(&event);
1493            break;
1494        case ButtonRelease:
1495            prologue(&event, "ButtonRelease");
1496            do_ButtonRelease(&event);
1497            break;
1498        case MotionNotify:
1499            prologue(&event, "MotionNotify");
1500            do_MotionNotify(&event);
1501            break;
1502        case EnterNotify:
1503            prologue(&event, "EnterNotify");
1504            do_EnterNotify(&event);
1505            break;
1506        case LeaveNotify:
1507            prologue(&event, "LeaveNotify");
1508            do_LeaveNotify(&event);
1509            break;
1510        case FocusIn:
1511            prologue(&event, "FocusIn");
1512            do_FocusIn(&event);
1513            break;
1514        case FocusOut:
1515            prologue(&event, "FocusOut");
1516            do_FocusOut(&event);
1517            break;
1518        case KeymapNotify:
1519            prologue(&event, "KeymapNotify");
1520            do_KeymapNotify(&event);
1521            break;
1522        case Expose:
1523            prologue(&event, "Expose");
1524            do_Expose(&event);
1525            break;
1526        case GraphicsExpose:
1527            prologue(&event, "GraphicsExpose");
1528            do_GraphicsExpose(&event);
1529            break;
1530        case NoExpose:
1531            prologue(&event, "NoExpose");
1532            do_NoExpose(&event);
1533            break;
1534        case VisibilityNotify:
1535            prologue(&event, "VisibilityNotify");
1536            do_VisibilityNotify(&event);
1537            break;
1538        case CreateNotify:
1539            prologue(&event, "CreateNotify");
1540            do_CreateNotify(&event);
1541            break;
1542        case DestroyNotify:
1543            prologue(&event, "DestroyNotify");
1544            do_DestroyNotify(&event);
1545            break;
1546        case UnmapNotify:
1547            prologue(&event, "UnmapNotify");
1548            do_UnmapNotify(&event);
1549            break;
1550        case MapNotify:
1551            prologue(&event, "MapNotify");
1552            do_MapNotify(&event);
1553            break;
1554        case MapRequest:
1555            prologue(&event, "MapRequest");
1556            do_MapRequest(&event);
1557            break;
1558        case ReparentNotify:
1559            prologue(&event, "ReparentNotify");
1560            do_ReparentNotify(&event);
1561            break;
1562        case ConfigureNotify:
1563            prologue(&event, "ConfigureNotify");
1564            do_ConfigureNotify(&event);
1565            break;
1566        case ConfigureRequest:
1567            prologue(&event, "ConfigureRequest");
1568            do_ConfigureRequest(&event);
1569            break;
1570        case GravityNotify:
1571            prologue(&event, "GravityNotify");
1572            do_GravityNotify(&event);
1573            break;
1574        case ResizeRequest:
1575            prologue(&event, "ResizeRequest");
1576            do_ResizeRequest(&event);
1577            break;
1578        case CirculateNotify:
1579            prologue(&event, "CirculateNotify");
1580            do_CirculateNotify(&event);
1581            break;
1582        case CirculateRequest:
1583            prologue(&event, "CirculateRequest");
1584            do_CirculateRequest(&event);
1585            break;
1586        case PropertyNotify:
1587            prologue(&event, "PropertyNotify");
1588            do_PropertyNotify(&event);
1589            break;
1590        case SelectionClear:
1591            prologue(&event, "SelectionClear");
1592            do_SelectionClear(&event);
1593            break;
1594        case SelectionRequest:
1595            prologue(&event, "SelectionRequest");
1596            do_SelectionRequest(&event);
1597            break;
1598        case SelectionNotify:
1599            prologue(&event, "SelectionNotify");
1600            do_SelectionNotify(&event);
1601            break;
1602        case ColormapNotify:
1603            prologue(&event, "ColormapNotify");
1604            do_ColormapNotify(&event);
1605            break;
1606        case ClientMessage:
1607            prologue(&event, "ClientMessage");
1608            do_ClientMessage(&event);
1609            break;
1610        case MappingNotify:
1611            prologue(&event, "MappingNotify");
1612            do_MappingNotify(&event);
1613            break;
1614        default:
1615            if (have_rr) {
1616                if (event.type == rr_event_base + RRScreenChangeNotify) {
1617                    prologue(&event, "RRScreenChangeNotify");
1618                    do_RRScreenChangeNotify(&event);
1619                    break;
1620                }
1621                if (event.type == rr_event_base + RRNotify) {
1622                    do_RRNotify(&event);
1623                    break;
1624                }
1625            }
1626            output(NewLine, "Unknown event type %d", event.type);
1627            break;
1628        }
1629        if (single_line) {
1630            printf("\n");
1631        }
1632        fflush(stdout);
1633    }
1634
1635    XCloseDisplay(dpy);
1636    return 0;
1637}
1638