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