xev.c revision 625f88be
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#include <stdio.h>
36#include <stdlib.h>
37#include <ctype.h>
38#include <X11/Xlocale.h>
39#include <X11/Xos.h>
40#include <X11/Xlib.h>
41#include <X11/Xutil.h>
42#include <X11/Xproto.h>
43
44#define INNER_WINDOW_WIDTH 50
45#define INNER_WINDOW_HEIGHT 50
46#define INNER_WINDOW_BORDER 4
47#define INNER_WINDOW_X 10
48#define INNER_WINDOW_Y 10
49#define OUTER_WINDOW_MIN_WIDTH (INNER_WINDOW_WIDTH + \
50				2 * (INNER_WINDOW_BORDER + INNER_WINDOW_X))
51#define OUTER_WINDOW_MIN_HEIGHT (INNER_WINDOW_HEIGHT + \
52				2 * (INNER_WINDOW_BORDER + INNER_WINDOW_Y))
53#define OUTER_WINDOW_DEF_WIDTH (OUTER_WINDOW_MIN_WIDTH + 100)
54#define OUTER_WINDOW_DEF_HEIGHT (OUTER_WINDOW_MIN_HEIGHT + 100)
55#define OUTER_WINDOW_DEF_X 100
56#define OUTER_WINDOW_DEF_Y 100
57
58
59typedef unsigned long Pixel;
60
61const char *Yes = "YES";
62const char *No = "NO";
63const char *Unknown = "unknown";
64
65const char *ProgramName;
66Display *dpy;
67int screen;
68
69XIC xic = NULL;
70
71Atom wm_delete_window;
72Atom wm_protocols;
73
74static void
75prologue (XEvent *eventp, char *event_name)
76{
77    XAnyEvent *e = (XAnyEvent *) eventp;
78
79    printf ("\n%s event, serial %ld, synthetic %s, window 0x%lx,\n",
80	    event_name, e->serial, e->send_event ? Yes : No, e->window);
81}
82
83static void
84dump (char *str, int len)
85{
86    printf("(");
87    len--;
88    while (len-- > 0)
89        printf("%02x ", (unsigned char) *str++);
90    printf("%02x)", (unsigned char) *str++);
91}
92
93static void
94do_KeyPress (XEvent *eventp)
95{
96    XKeyEvent *e = (XKeyEvent *) eventp;
97    KeySym ks;
98    KeyCode kc = 0;
99    Bool kc_set = False;
100    char *ksname;
101    int nbytes, nmbbytes = 0;
102    char str[256+1];
103    static char *buf = NULL;
104    static int bsize = 8;
105    Status status;
106
107    if (buf == NULL)
108      buf = malloc (bsize);
109
110    nbytes = XLookupString (e, str, 256, &ks, NULL);
111
112    /* not supposed to call XmbLookupString on a key release event */
113    if (e->type == KeyPress && xic) {
114        do {
115            nmbbytes = XmbLookupString (xic, e, buf, bsize - 1, &ks, &status);
116            buf[nmbbytes] = '\0';
117
118            if (status == XBufferOverflow) {
119                bsize = nmbbytes + 1;
120                buf = realloc (buf, bsize);
121            }
122        } while (status == XBufferOverflow);
123    }
124
125    if (ks == NoSymbol)
126	ksname = "NoSymbol";
127    else {
128	if (!(ksname = XKeysymToString (ks)))
129	    ksname = "(no name)";
130	kc = XKeysymToKeycode(dpy, ks);
131	kc_set = True;
132    }
133
134    printf ("    root 0x%lx, subw 0x%lx, time %lu, (%d,%d), root:(%d,%d),\n",
135	    e->root, e->subwindow, e->time, e->x, e->y, e->x_root, e->y_root);
136    printf ("    state 0x%x, keycode %u (keysym 0x%lx, %s), same_screen %s,\n",
137	    e->state, e->keycode, (unsigned long) ks, ksname,
138	    e->same_screen ? Yes : No);
139    if (kc_set && e->keycode != kc)
140	printf ("    XKeysymToKeycode returns keycode: %u\n",kc);
141    if (nbytes < 0) nbytes = 0;
142    if (nbytes > 256) nbytes = 256;
143    str[nbytes] = '\0';
144    printf ("    XLookupString gives %d bytes: ", nbytes);
145    if (nbytes > 0) {
146        dump (str, nbytes);
147        printf (" \"%s\"\n", str);
148    } else {
149    	printf ("\n");
150    }
151
152    /* not supposed to call XmbLookupString on a key release event */
153    if (e->type == KeyPress && xic) {
154        printf ("    XmbLookupString gives %d bytes: ", nmbbytes);
155        if (nmbbytes > 0) {
156           dump (buf, nmbbytes);
157           printf (" \"%s\"\n", buf);
158        } else {
159    	   printf ("\n");
160        }
161    }
162
163    printf ("    XFilterEvent returns: %s\n",
164	    XFilterEvent (eventp, e->window) ? "True" : "False");
165}
166
167static void
168do_KeyRelease (XEvent *eventp)
169{
170    do_KeyPress (eventp);		/* since it has the same info */
171}
172
173static void
174do_ButtonPress (XEvent *eventp)
175{
176    XButtonEvent *e = (XButtonEvent *) eventp;
177
178    printf ("    root 0x%lx, subw 0x%lx, time %lu, (%d,%d), root:(%d,%d),\n",
179	    e->root, e->subwindow, e->time, e->x, e->y, e->x_root, e->y_root);
180    printf ("    state 0x%x, button %u, same_screen %s\n",
181	    e->state, e->button, e->same_screen ? Yes : No);
182}
183
184static void
185do_ButtonRelease (XEvent *eventp)
186{
187    do_ButtonPress (eventp);		/* since it has the same info */
188}
189
190static void
191do_MotionNotify (XEvent *eventp)
192{
193    XMotionEvent *e = (XMotionEvent *) eventp;
194
195    printf ("    root 0x%lx, subw 0x%lx, time %lu, (%d,%d), root:(%d,%d),\n",
196	    e->root, e->subwindow, e->time, e->x, e->y, e->x_root, e->y_root);
197    printf ("    state 0x%x, is_hint %u, same_screen %s\n",
198	    e->state, e->is_hint, e->same_screen ? Yes : No);
199}
200
201static void
202do_EnterNotify (XEvent *eventp)
203{
204    XCrossingEvent *e = (XCrossingEvent *) eventp;
205    char *mode, *detail;
206    char dmode[10], ddetail[10];
207
208    switch (e->mode) {
209      case NotifyNormal:  mode = "NotifyNormal"; break;
210      case NotifyGrab:  mode = "NotifyGrab"; break;
211      case NotifyUngrab:  mode = "NotifyUngrab"; break;
212      case NotifyWhileGrabbed:  mode = "NotifyWhileGrabbed"; break;
213      default:  mode = dmode, sprintf (dmode, "%u", e->mode); break;
214    }
215
216    switch (e->detail) {
217      case NotifyAncestor:  detail = "NotifyAncestor"; break;
218      case NotifyVirtual:  detail = "NotifyVirtual"; break;
219      case NotifyInferior:  detail = "NotifyInferior"; break;
220      case NotifyNonlinear:  detail = "NotifyNonlinear"; break;
221      case NotifyNonlinearVirtual:  detail = "NotifyNonlinearVirtual"; break;
222      case NotifyPointer:  detail = "NotifyPointer"; break;
223      case NotifyPointerRoot:  detail = "NotifyPointerRoot"; break;
224      case NotifyDetailNone:  detail = "NotifyDetailNone"; break;
225      default:  detail = ddetail; sprintf (ddetail, "%u", e->detail); break;
226    }
227
228    printf ("    root 0x%lx, subw 0x%lx, time %lu, (%d,%d), root:(%d,%d),\n",
229	    e->root, e->subwindow, e->time, e->x, e->y, e->x_root, e->y_root);
230    printf ("    mode %s, detail %s, same_screen %s,\n",
231	    mode, detail, e->same_screen ? Yes : No);
232    printf ("    focus %s, state %u\n", e->focus ? Yes : No, e->state);
233}
234
235static void
236do_LeaveNotify (XEvent *eventp)
237{
238    do_EnterNotify (eventp);		/* since it has same information */
239}
240
241static void
242do_FocusIn (XEvent *eventp)
243{
244    XFocusChangeEvent *e = (XFocusChangeEvent *) eventp;
245    char *mode, *detail;
246    char dmode[10], ddetail[10];
247
248    switch (e->mode) {
249      case NotifyNormal:  mode = "NotifyNormal"; break;
250      case NotifyGrab:  mode = "NotifyGrab"; break;
251      case NotifyUngrab:  mode = "NotifyUngrab"; break;
252      case NotifyWhileGrabbed:  mode = "NotifyWhileGrabbed"; break;
253      default:  mode = dmode, sprintf (dmode, "%u", e->mode); break;
254    }
255
256    switch (e->detail) {
257      case NotifyAncestor:  detail = "NotifyAncestor"; break;
258      case NotifyVirtual:  detail = "NotifyVirtual"; break;
259      case NotifyInferior:  detail = "NotifyInferior"; break;
260      case NotifyNonlinear:  detail = "NotifyNonlinear"; break;
261      case NotifyNonlinearVirtual:  detail = "NotifyNonlinearVirtual"; break;
262      case NotifyPointer:  detail = "NotifyPointer"; break;
263      case NotifyPointerRoot:  detail = "NotifyPointerRoot"; break;
264      case NotifyDetailNone:  detail = "NotifyDetailNone"; break;
265      default:  detail = ddetail; sprintf (ddetail, "%u", e->detail); break;
266    }
267
268    printf ("    mode %s, detail %s\n", mode, detail);
269}
270
271static void
272do_FocusOut (XEvent *eventp)
273{
274    do_FocusIn (eventp);		/* since it has same information */
275}
276
277static void
278do_KeymapNotify (XEvent *eventp)
279{
280    XKeymapEvent *e = (XKeymapEvent *) eventp;
281    int i;
282
283    printf ("    keys:  ");
284    for (i = 0; i < 32; i++) {
285	if (i == 16) printf ("\n           ");
286	printf ("%-3u ", (unsigned int) e->key_vector[i]);
287    }
288    printf ("\n");
289}
290
291static void
292do_Expose (XEvent *eventp)
293{
294    XExposeEvent *e = (XExposeEvent *) eventp;
295
296    printf ("    (%d,%d), width %d, height %d, count %d\n",
297	    e->x, e->y, e->width, e->height, e->count);
298}
299
300static void
301do_GraphicsExpose (XEvent *eventp)
302{
303    XGraphicsExposeEvent *e = (XGraphicsExposeEvent *) eventp;
304    char *m;
305    char mdummy[10];
306
307    switch (e->major_code) {
308      case X_CopyArea:  m = "CopyArea";  break;
309      case X_CopyPlane:  m = "CopyPlane";  break;
310      default:  m = mdummy; sprintf (mdummy, "%d", e->major_code); break;
311    }
312
313    printf ("    (%d,%d), width %d, height %d, count %d,\n",
314	    e->x, e->y, e->width, e->height, e->count);
315    printf ("    major %s, minor %d\n", m, e->minor_code);
316}
317
318static void
319do_NoExpose (XEvent *eventp)
320{
321    XNoExposeEvent *e = (XNoExposeEvent *) eventp;
322    char *m;
323    char mdummy[10];
324
325    switch (e->major_code) {
326      case X_CopyArea:  m = "CopyArea";  break;
327      case X_CopyPlane:  m = "CopyPlane";  break;
328      default:  m = mdummy; sprintf (mdummy, "%d", e->major_code); break;
329    }
330
331    printf ("    major %s, minor %d\n", m, e->minor_code);
332    return;
333}
334
335static void
336do_VisibilityNotify (XEvent *eventp)
337{
338    XVisibilityEvent *e = (XVisibilityEvent *) eventp;
339    char *v;
340    char vdummy[10];
341
342    switch (e->state) {
343      case VisibilityUnobscured:  v = "VisibilityUnobscured"; break;
344      case VisibilityPartiallyObscured:  v = "VisibilityPartiallyObscured"; break;
345      case VisibilityFullyObscured:  v = "VisibilityFullyObscured"; break;
346      default:  v = vdummy; sprintf (vdummy, "%d", e->state); break;
347    }
348
349    printf ("    state %s\n", v);
350}
351
352static void
353do_CreateNotify (XEvent *eventp)
354{
355    XCreateWindowEvent *e = (XCreateWindowEvent *) eventp;
356
357    printf ("    parent 0x%lx, window 0x%lx, (%d,%d), width %d, height %d\n",
358	    e->parent, e->window, e->x, e->y, e->width, e->height);
359    printf ("border_width %d, override %s\n",
360	    e->border_width, e->override_redirect ? Yes : No);
361}
362
363static void
364do_DestroyNotify (XEvent *eventp)
365{
366    XDestroyWindowEvent *e = (XDestroyWindowEvent *) eventp;
367
368    printf ("    event 0x%lx, window 0x%lx\n", e->event, e->window);
369}
370
371static void
372do_UnmapNotify (XEvent *eventp)
373{
374    XUnmapEvent *e = (XUnmapEvent *) eventp;
375
376    printf ("    event 0x%lx, window 0x%lx, from_configure %s\n",
377	    e->event, e->window, e->from_configure ? Yes : No);
378}
379
380static void
381do_MapNotify (XEvent *eventp)
382{
383    XMapEvent *e = (XMapEvent *) eventp;
384
385    printf ("    event 0x%lx, window 0x%lx, override %s\n",
386	    e->event, e->window, e->override_redirect ? Yes : No);
387}
388
389static void
390do_MapRequest (XEvent *eventp)
391{
392    XMapRequestEvent *e = (XMapRequestEvent *) eventp;
393
394    printf ("    parent 0x%lx, window 0x%lx\n", e->parent, e->window);
395}
396
397static void
398do_ReparentNotify (XEvent *eventp)
399{
400    XReparentEvent *e = (XReparentEvent *) eventp;
401
402    printf ("    event 0x%lx, window 0x%lx, parent 0x%lx,\n",
403	    e->event, e->window, e->parent);
404    printf ("    (%d,%d), override %s\n", e->x, e->y,
405	    e->override_redirect ? Yes : No);
406}
407
408static void
409do_ConfigureNotify (XEvent *eventp)
410{
411    XConfigureEvent *e = (XConfigureEvent *) eventp;
412
413    printf ("    event 0x%lx, window 0x%lx, (%d,%d), width %d, height %d,\n",
414	    e->event, e->window, e->x, e->y, e->width, e->height);
415    printf ("    border_width %d, above 0x%lx, override %s\n",
416	    e->border_width, e->above, e->override_redirect ? Yes : No);
417}
418
419static void
420do_ConfigureRequest (XEvent *eventp)
421{
422    XConfigureRequestEvent *e = (XConfigureRequestEvent *) eventp;
423    char *detail;
424    char ddummy[10];
425
426    switch (e->detail) {
427      case Above:  detail = "Above";  break;
428      case Below:  detail = "Below";  break;
429      case TopIf:  detail = "TopIf";  break;
430      case BottomIf:  detail = "BottomIf"; break;
431      case Opposite:  detail = "Opposite"; break;
432      default:  detail = ddummy; sprintf (ddummy, "%d", e->detail); break;
433    }
434
435    printf ("    parent 0x%lx, window 0x%lx, (%d,%d), width %d, height %d,\n",
436	    e->parent, e->window, e->x, e->y, e->width, e->height);
437    printf ("    border_width %d, above 0x%lx, detail %s, value 0x%lx\n",
438	    e->border_width, e->above, detail, e->value_mask);
439}
440
441static void
442do_GravityNotify (XEvent *eventp)
443{
444    XGravityEvent *e = (XGravityEvent *) eventp;
445
446    printf ("    event 0x%lx, window 0x%lx, (%d,%d)\n",
447	    e->event, e->window, e->x, e->y);
448}
449
450static void
451do_ResizeRequest (XEvent *eventp)
452{
453    XResizeRequestEvent *e = (XResizeRequestEvent *) eventp;
454
455    printf ("    width %d, height %d\n", e->width, e->height);
456}
457
458static void
459do_CirculateNotify (XEvent *eventp)
460{
461    XCirculateEvent *e = (XCirculateEvent *) eventp;
462    char *p;
463    char pdummy[10];
464
465    switch (e->place) {
466      case PlaceOnTop:  p = "PlaceOnTop"; break;
467      case PlaceOnBottom:  p = "PlaceOnBottom"; break;
468      default:  p = pdummy; sprintf (pdummy, "%d", e->place); break;
469    }
470
471    printf ("    event 0x%lx, window 0x%lx, place %s\n",
472	    e->event, e->window, p);
473}
474
475static void
476do_CirculateRequest (XEvent *eventp)
477{
478    XCirculateRequestEvent *e = (XCirculateRequestEvent *) eventp;
479    char *p;
480    char pdummy[10];
481
482    switch (e->place) {
483      case PlaceOnTop:  p = "PlaceOnTop"; break;
484      case PlaceOnBottom:  p = "PlaceOnBottom"; break;
485      default:  p = pdummy; sprintf (pdummy, "%d", e->place); break;
486    }
487
488    printf ("    parent 0x%lx, window 0x%lx, place %s\n",
489	    e->parent, e->window, p);
490}
491
492static void
493do_PropertyNotify (XEvent *eventp)
494{
495    XPropertyEvent *e = (XPropertyEvent *) eventp;
496    char *aname = XGetAtomName (dpy, e->atom);
497    char *s;
498    char sdummy[10];
499
500    switch (e->state) {
501      case PropertyNewValue:  s = "PropertyNewValue"; break;
502      case PropertyDelete:  s = "PropertyDelete"; break;
503      default:  s = sdummy; sprintf (sdummy, "%d", e->state); break;
504    }
505
506    printf ("    atom 0x%lx (%s), time %lu, state %s\n",
507	   e->atom, aname ? aname : Unknown, e->time,  s);
508
509    if (aname) XFree (aname);
510}
511
512static void
513do_SelectionClear (XEvent *eventp)
514{
515    XSelectionClearEvent *e = (XSelectionClearEvent *) eventp;
516    char *sname = XGetAtomName (dpy, e->selection);
517
518    printf ("    selection 0x%lx (%s), time %lu\n",
519	    e->selection, sname ? sname : Unknown, e->time);
520
521    if (sname) XFree (sname);
522}
523
524static void
525do_SelectionRequest (XEvent *eventp)
526{
527    XSelectionRequestEvent *e = (XSelectionRequestEvent *) eventp;
528    char *sname = XGetAtomName (dpy, e->selection);
529    char *tname = XGetAtomName (dpy, e->target);
530    char *pname = XGetAtomName (dpy, e->property);
531
532    printf ("    owner 0x%lx, requestor 0x%lx, selection 0x%lx (%s),\n",
533	    e->owner, e->requestor, e->selection, sname ? sname : Unknown);
534    printf ("    target 0x%lx (%s), property 0x%lx (%s), time %lu\n",
535	    e->target, tname ? tname : Unknown, e->property,
536	    pname ? pname : Unknown, e->time);
537
538    if (sname) XFree (sname);
539    if (tname) XFree (tname);
540    if (pname) XFree (pname);
541}
542
543static void
544do_SelectionNotify (XEvent *eventp)
545{
546    XSelectionEvent *e = (XSelectionEvent *) eventp;
547    char *sname = XGetAtomName (dpy, e->selection);
548    char *tname = XGetAtomName (dpy, e->target);
549    char *pname = XGetAtomName (dpy, e->property);
550
551    printf ("    selection 0x%lx (%s), target 0x%lx (%s),\n",
552	    e->selection, sname ? sname : Unknown, e->target,
553	    tname ? tname : Unknown);
554    printf ("    property 0x%lx (%s), time %lu\n",
555	    e->property, pname ? pname : Unknown, e->time);
556
557    if (sname) XFree (sname);
558    if (tname) XFree (tname);
559    if (pname) XFree (pname);
560}
561
562static void
563do_ColormapNotify (XEvent *eventp)
564{
565    XColormapEvent *e = (XColormapEvent *) eventp;
566    char *s;
567    char sdummy[10];
568
569    switch (e->state) {
570      case ColormapInstalled:  s = "ColormapInstalled"; break;
571      case ColormapUninstalled:  s = "ColormapUninstalled"; break;
572      default:  s = sdummy; sprintf (sdummy, "%d", e->state); break;
573    }
574
575    printf ("    colormap 0x%lx, new %s, state %s\n",
576	    e->colormap, e->new ? Yes : No, s);
577}
578
579static void
580do_ClientMessage (XEvent *eventp)
581{
582    XClientMessageEvent *e = (XClientMessageEvent *) eventp;
583    char *mname = XGetAtomName (dpy, e->message_type);
584
585    if (e->message_type == wm_protocols) {
586        char *message = XGetAtomName (dpy, e->data.l[0]);
587        printf ("    message_type 0x%lx (%s), format %d, message 0x%lx (%s)\n",
588                e->message_type, mname ? mname : Unknown, e->format, e->data.l[0], message);
589        if (message) XFree (message);
590    }
591    else {
592        printf ("    message_type 0x%lx (%s), format %d\n",
593                e->message_type, mname ? mname : Unknown, e->format);
594    }
595
596    if (mname) XFree (mname);
597
598    if (e->format == 32
599        && e->message_type == wm_protocols
600        && (Atom) e->data.l[0] == wm_delete_window)
601        exit (0);
602}
603
604static void
605do_MappingNotify (XEvent *eventp)
606{
607    XMappingEvent *e = (XMappingEvent *) eventp;
608    char *r;
609    char rdummy[10];
610
611    switch (e->request) {
612      case MappingModifier:  r = "MappingModifier"; break;
613      case MappingKeyboard:  r = "MappingKeyboard"; break;
614      case MappingPointer:  r = "MappingPointer"; break;
615      default:  r = rdummy; sprintf (rdummy, "%d", e->request); break;
616    }
617
618    printf ("    request %s, first_keycode %d, count %d\n",
619	    r, e->first_keycode, e->count);
620    XRefreshKeyboardMapping(e);
621}
622
623
624
625static void
626set_sizehints (XSizeHints *hintp, int min_width, int min_height,
627	       int defwidth, int defheight, int defx, int defy,
628	       char *geom)
629{
630    int geom_result;
631
632    /* set the size hints, algorithm from xlib xbiff */
633
634    hintp->width = hintp->min_width = min_width;
635    hintp->height = hintp->min_height = min_height;
636    hintp->flags = PMinSize;
637    hintp->x = hintp->y = 0;
638    geom_result = NoValue;
639    if (geom != NULL) {
640        geom_result = XParseGeometry (geom, &hintp->x, &hintp->y,
641				      (unsigned int *)&hintp->width,
642				      (unsigned int *)&hintp->height);
643	if ((geom_result & WidthValue) && (geom_result & HeightValue)) {
644#ifndef max
645#define max(a,b) ((a) > (b) ? (a) : (b))
646#endif
647	    hintp->width = max (hintp->width, hintp->min_width);
648	    hintp->height = max (hintp->height, hintp->min_height);
649	    hintp->flags |= USSize;
650	}
651	if ((geom_result & XValue) && (geom_result & YValue)) {
652	    hintp->flags += USPosition;
653	}
654    }
655    if (!(hintp->flags & USSize)) {
656	hintp->width = defwidth;
657	hintp->height = defheight;
658	hintp->flags |= PSize;
659    }
660/*
661    if (!(hintp->flags & USPosition)) {
662	hintp->x = defx;
663	hintp->y = defy;
664	hintp->flags |= PPosition;
665    }
666 */
667    if (geom_result & XNegative) {
668	hintp->x = DisplayWidth (dpy, DefaultScreen (dpy)) + hintp->x -
669		    hintp->width;
670    }
671    if (geom_result & YNegative) {
672	hintp->y = DisplayHeight (dpy, DefaultScreen (dpy)) + hintp->y -
673		    hintp->height;
674    }
675}
676
677
678#if defined(__GNUC__) && \
679    ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 7)))
680static void usage (void) __attribute__((__noreturn__));
681#endif
682static void
683usage (void)
684{
685    static const char *msg[] = {
686"    -display displayname                X server to contact",
687"    -geometry geom                      size and location of window",
688"    -bw pixels                          border width in pixels",
689"    -bs {NotUseful,WhenMapped,Always}   backingstore attribute",
690"    -id windowid                        use existing window",
691"    -root                               use root window",
692"    -s                                  set save-unders attribute",
693"    -name string                        window name",
694"    -rv                                 reverse video",
695"",
696NULL};
697    const char **cpp;
698
699    fprintf (stderr, "usage:  %s [-options ...]\n", ProgramName);
700    fprintf (stderr, "where options include:\n");
701
702    for (cpp = msg; *cpp; cpp++)
703	fprintf (stderr, "%s\n", *cpp);
704
705    exit (1);
706}
707
708static int
709parse_backing_store (char *s)
710{
711    int len = strlen (s);
712    char *cp;
713
714    for (cp = s; *cp; cp++) {
715	if (isascii (*cp) && isupper (*cp))
716	    *cp = tolower (*cp);
717    }
718
719    if (strncmp (s, "notuseful", len) == 0) return (NotUseful);
720    if (strncmp (s, "whenmapped", len) == 0) return (WhenMapped);
721    if (strncmp (s, "always", len) == 0) return (Always);
722
723    usage ();
724}
725
726int
727main (int argc, char **argv)
728{
729    char *displayname = NULL;
730    char *geom = NULL;
731    int i;
732    XSizeHints hints;
733    int borderwidth = 2;
734    Window w, subw;
735    XSetWindowAttributes attr;
736    XWindowAttributes wattr;
737    unsigned long mask = 0L;
738    int done;
739    char *name = "Event Tester";
740    Bool reverse = False;
741    Bool use_root = False;
742    unsigned long back, fore;
743    XIM xim;
744    XIMStyles *xim_styles;
745    XIMStyle xim_style = 0;
746    char *modifiers;
747    char *imvalret;
748
749    ProgramName = argv[0];
750
751    if (setlocale(LC_ALL,"") == NULL) {
752	fprintf(stderr, "%s: warning: could not set default locale\n",
753		ProgramName);
754    }
755
756    w = 0;
757    for (i = 1; i < argc; i++) {
758	char *arg = argv[i];
759
760	if (arg[0] == '-') {
761	    switch (arg[1]) {
762	      case 'd':			/* -display host:dpy */
763		if (++i >= argc) usage ();
764		displayname = argv[i];
765		continue;
766	      case 'g':			/* -geometry geom */
767		if (++i >= argc) usage ();
768		geom = argv[i];
769		continue;
770	      case 'b':
771		switch (arg[2]) {
772		  case 'w':		/* -bw pixels */
773		    if (++i >= argc) usage ();
774		    borderwidth = atoi (argv[i]);
775		    continue;
776		  case 's':		/* -bs type */
777		    if (++i >= argc) usage ();
778		    attr.backing_store = parse_backing_store (argv[i]);
779		    mask |= CWBackingStore;
780		    continue;
781		  default:
782		    usage ();
783		}
784	      case 'i':			/* -id */
785		if (++i >= argc) usage ();
786		sscanf(argv[i], "0x%lx", &w);
787		if (!w)
788		    sscanf(argv[i], "%lu", &w);
789		if (!w)
790		    usage ();
791		continue;
792	      case 'n':			/* -name */
793		if (++i >= argc) usage ();
794		name = argv[i];
795		continue;
796	      case 'r':
797		switch (arg[2]) {
798		  case 'o':		/* -root */
799		    use_root = True;
800		    continue;
801		  case 'v':		/* -rv */
802		    reverse = True;
803		    continue;
804		  default:
805		    usage ();
806		}
807		continue;
808	      case 's':			/* -s */
809		attr.save_under = True;
810		mask |= CWSaveUnder;
811		continue;
812	      default:
813		usage ();
814	    }				/* end switch on - */
815	} else
816	  usage ();
817    }					/* end for over argc */
818
819    dpy = XOpenDisplay (displayname);
820    if (!dpy) {
821	fprintf (stderr, "%s:  unable to open display '%s'\n",
822		 ProgramName, XDisplayName (displayname));
823	exit (1);
824    }
825
826    /* we're testing the default input method */
827    modifiers = XSetLocaleModifiers ("@im=none");
828    if (modifiers == NULL) {
829        fprintf (stderr, "%s:  XSetLocaleModifiers failed\n", ProgramName);
830    }
831
832    xim = XOpenIM (dpy, NULL, NULL, NULL);
833    if (xim == NULL) {
834        fprintf (stderr, "%s:  XOpenIM failed\n", ProgramName);
835    }
836
837    if (xim) {
838        imvalret = XGetIMValues (xim, XNQueryInputStyle, &xim_styles, NULL);
839        if (imvalret != NULL || xim_styles == NULL) {
840            fprintf (stderr, "%s:  input method doesn't support any styles\n", ProgramName);
841        }
842
843        if (xim_styles) {
844            xim_style = 0;
845            for (i = 0;  i < xim_styles->count_styles;  i++) {
846                if (xim_styles->supported_styles[i] ==
847                    (XIMPreeditNothing | XIMStatusNothing)) {
848                    xim_style = xim_styles->supported_styles[i];
849                    break;
850                }
851            }
852
853            if (xim_style == 0) {
854                fprintf (stderr, "%s: input method doesn't support the style we support\n",
855                         ProgramName);
856            }
857            XFree (xim_styles);
858        }
859    }
860
861    screen = DefaultScreen (dpy);
862
863    /* select for all events */
864    attr.event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask |
865			   ButtonReleaseMask | EnterWindowMask |
866			   LeaveWindowMask | PointerMotionMask |
867			   Button1MotionMask |
868			   Button2MotionMask | Button3MotionMask |
869			   Button4MotionMask | Button5MotionMask |
870			   ButtonMotionMask | KeymapStateMask |
871			   ExposureMask | VisibilityChangeMask |
872			   StructureNotifyMask | /* ResizeRedirectMask | */
873			   SubstructureNotifyMask | SubstructureRedirectMask |
874			   FocusChangeMask | PropertyChangeMask |
875			   ColormapChangeMask | OwnerGrabButtonMask;
876
877    if (use_root)
878	w = RootWindow(dpy, screen);
879
880    if (w) {
881	XGetWindowAttributes(dpy, w, &wattr);
882	if (wattr.all_event_masks & ButtonPressMask)
883	    attr.event_mask &= ~ButtonPressMask;
884	attr.event_mask &= ~SubstructureRedirectMask;
885	XSelectInput(dpy, w, attr.event_mask);
886    } else {
887	set_sizehints (&hints, OUTER_WINDOW_MIN_WIDTH, OUTER_WINDOW_MIN_HEIGHT,
888		       OUTER_WINDOW_DEF_WIDTH, OUTER_WINDOW_DEF_HEIGHT,
889		       OUTER_WINDOW_DEF_X, OUTER_WINDOW_DEF_Y, geom);
890
891	if (reverse) {
892	    back = BlackPixel(dpy,screen);
893	    fore = WhitePixel(dpy,screen);
894	} else {
895	    back = WhitePixel(dpy,screen);
896	    fore = BlackPixel(dpy,screen);
897	}
898
899	attr.background_pixel = back;
900	attr.border_pixel = fore;
901	mask |= (CWBackPixel | CWBorderPixel | CWEventMask);
902
903	w = XCreateWindow (dpy, RootWindow (dpy, screen), hints.x, hints.y,
904			   hints.width, hints.height, borderwidth, 0,
905			   InputOutput, (Visual *)CopyFromParent,
906			   mask, &attr);
907
908	XSetStandardProperties (dpy, w, name, NULL, (Pixmap) 0,
909				argv, argc, &hints);
910
911	subw = XCreateSimpleWindow (dpy, w, INNER_WINDOW_X, INNER_WINDOW_Y,
912				    INNER_WINDOW_WIDTH, INNER_WINDOW_HEIGHT,
913				    INNER_WINDOW_BORDER,
914				    attr.border_pixel, attr.background_pixel);
915
916        wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False);
917        wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
918        XSetWMProtocols(dpy, w, &wm_delete_window, 1);
919
920	XMapWindow (dpy, subw);		/* map before w so that it appears */
921	XMapWindow (dpy, w);
922
923	printf ("Outer window is 0x%lx, inner window is 0x%lx\n", w, subw);
924    }
925
926    if (xim && xim_style) {
927        xic = XCreateIC (xim,
928                         XNInputStyle, xim_style,
929                         XNClientWindow, w,
930                         XNFocusWindow, w,
931                         NULL);
932
933        if (xic == NULL) {
934            fprintf (stderr, "XCreateIC failed\n");
935        }
936    }
937
938    for (done = 0; !done; ) {
939	XEvent event;
940
941	XNextEvent (dpy, &event);
942
943	switch (event.type) {
944	  case KeyPress:
945	    prologue (&event, "KeyPress");
946	    do_KeyPress (&event);
947	    break;
948	  case KeyRelease:
949	    prologue (&event, "KeyRelease");
950	    do_KeyRelease (&event);
951	    break;
952	  case ButtonPress:
953	    prologue (&event, "ButtonPress");
954	    do_ButtonPress (&event);
955	    break;
956	  case ButtonRelease:
957	    prologue (&event, "ButtonRelease");
958	    do_ButtonRelease (&event);
959	    break;
960	  case MotionNotify:
961	    prologue (&event, "MotionNotify");
962	    do_MotionNotify (&event);
963	    break;
964	  case EnterNotify:
965	    prologue (&event, "EnterNotify");
966	    do_EnterNotify (&event);
967	    break;
968	  case LeaveNotify:
969	    prologue (&event, "LeaveNotify");
970	    do_LeaveNotify (&event);
971	    break;
972	  case FocusIn:
973	    prologue (&event, "FocusIn");
974	    do_FocusIn (&event);
975	    break;
976	  case FocusOut:
977	    prologue (&event, "FocusOut");
978	    do_FocusOut (&event);
979	    break;
980	  case KeymapNotify:
981	    prologue (&event, "KeymapNotify");
982	    do_KeymapNotify (&event);
983	    break;
984	  case Expose:
985	    prologue (&event, "Expose");
986	    do_Expose (&event);
987	    break;
988	  case GraphicsExpose:
989	    prologue (&event, "GraphicsExpose");
990	    do_GraphicsExpose (&event);
991	    break;
992	  case NoExpose:
993	    prologue (&event, "NoExpose");
994	    do_NoExpose (&event);
995	    break;
996	  case VisibilityNotify:
997	    prologue (&event, "VisibilityNotify");
998	    do_VisibilityNotify (&event);
999	    break;
1000	  case CreateNotify:
1001	    prologue (&event, "CreateNotify");
1002	    do_CreateNotify (&event);
1003	    break;
1004	  case DestroyNotify:
1005	    prologue (&event, "DestroyNotify");
1006	    do_DestroyNotify (&event);
1007	    break;
1008	  case UnmapNotify:
1009	    prologue (&event, "UnmapNotify");
1010	    do_UnmapNotify (&event);
1011	    break;
1012	  case MapNotify:
1013	    prologue (&event, "MapNotify");
1014	    do_MapNotify (&event);
1015	    break;
1016	  case MapRequest:
1017	    prologue (&event, "MapRequest");
1018	    do_MapRequest (&event);
1019	    break;
1020	  case ReparentNotify:
1021	    prologue (&event, "ReparentNotify");
1022	    do_ReparentNotify (&event);
1023	    break;
1024	  case ConfigureNotify:
1025	    prologue (&event, "ConfigureNotify");
1026	    do_ConfigureNotify (&event);
1027	    break;
1028	  case ConfigureRequest:
1029	    prologue (&event, "ConfigureRequest");
1030	    do_ConfigureRequest (&event);
1031	    break;
1032	  case GravityNotify:
1033	    prologue (&event, "GravityNotify");
1034	    do_GravityNotify (&event);
1035	    break;
1036	  case ResizeRequest:
1037	    prologue (&event, "ResizeRequest");
1038	    do_ResizeRequest (&event);
1039	    break;
1040	  case CirculateNotify:
1041	    prologue (&event, "CirculateNotify");
1042	    do_CirculateNotify (&event);
1043	    break;
1044	  case CirculateRequest:
1045	    prologue (&event, "CirculateRequest");
1046	    do_CirculateRequest (&event);
1047	    break;
1048	  case PropertyNotify:
1049	    prologue (&event, "PropertyNotify");
1050	    do_PropertyNotify (&event);
1051	    break;
1052	  case SelectionClear:
1053	    prologue (&event, "SelectionClear");
1054	    do_SelectionClear (&event);
1055	    break;
1056	  case SelectionRequest:
1057	    prologue (&event, "SelectionRequest");
1058	    do_SelectionRequest (&event);
1059	    break;
1060	  case SelectionNotify:
1061	    prologue (&event, "SelectionNotify");
1062	    do_SelectionNotify (&event);
1063	    break;
1064	  case ColormapNotify:
1065	    prologue (&event, "ColormapNotify");
1066	    do_ColormapNotify (&event);
1067	    break;
1068	  case ClientMessage:
1069	    prologue (&event, "ClientMessage");
1070	    do_ClientMessage (&event);
1071	    break;
1072	  case MappingNotify:
1073	    prologue (&event, "MappingNotify");
1074	    do_MappingNotify (&event);
1075	    break;
1076	  default:
1077	    printf ("Unknown event type %d\n", event.type);
1078	    break;
1079	}
1080	fflush(stdout);
1081    }
1082
1083    XCloseDisplay (dpy);
1084    return 0;
1085}
1086