wmii

git clone git://oldgit.suckless.org/wmii/
Log | Files | Refs | README | LICENSE

printevent.c (21469B)


      1 /*
      2  * Original code posted to comp.sources.x
      3  * Modifications by Russ Cox <rsc@swtch.com>.
      4  * Further modifications by Kris Maglione <maglione.k at Gmail>
      5  */
      6 
      7 /*
      8  * Path: uunet!wyse!mikew From: mikew@wyse.wyse.com (Mike Wexler) Newsgroups:
      9  * comp.sources.x Subject: v02i056:  subroutine to print events in human
     10  * readable form, Part01/01 Message-ID: <1935@wyse.wyse.com> Date: 22 Dec 88
     11  * 19:28:25 GMT Organization: Wyse Technology, San Jose Lines: 1093 Approved:
     12  * mikew@wyse.com
     13  *
     14  * Submitted-by: richsun!darkstar!ken Posting-number: Volume 2, Issue 56
     15  * Archive-name: showevent/part01
     16  *
     17  *
     18  * There are times during debugging when it would be real useful to be able to
     19  * print the fields of an event in a human readable form.  Too many times I
     20  * found myself scrounging around in section 8 of the Xlib manual looking for
     21  * the valid fields for the events I wanted to see, then adding printf's to
     22  * display the numeric values of the fields, and then scanning through X.h
     23  * trying to decode the cryptic detail and state fields.  After playing with
     24  * xev, I decided to write a couple of standard functions that I could keep
     25  * in a library and call on whenever I needed a little debugging verbosity.
     26  * The first function, GetType(), is useful for returning the string
     27  * representation of the type of an event.  The second function, ShowEvent(),
     28  * is used to display all the fields of an event in a readable format.  The
     29  * functions are not complicated, in fact, they are mind-numbingly boring -
     30  * but that's just the point nobody wants to spend the time writing functions
     31  * like this, they just want to have them when they need them.
     32  *
     33  * A simple, sample program is included which does little else but to
     34  * demonstrate the use of these two functions.  These functions have saved me
     35  * many an hour during debugging and I hope you find some benefit to these.
     36  * If you have any comments, suggestions, improvements, or if you find any
     37  * blithering errors you can get it touch with me at the following location:
     38  *
     39  * ken@richsun.UUCP
     40  */
     41 
     42 #include <stdarg.h>
     43 #include <bio.h>
     44 #include <stuff/x.h>
     45 #include <stuff/util.h>
     46 #include "printevent.h"
     47 #define Window XWindow
     48 #define unmask _unmask
     49 
     50 #define nil ((void*)0)
     51 
     52 typedef struct Pair Pair;
     53 
     54 struct Pair {
     55 	int key;
     56 	char *val;
     57 };
     58 
     59 static char* sep = " ";
     60 
     61 static char *
     62 search(Pair *lst, int key, char *(*def)(int)) {
     63 	for(; lst->val; lst++)
     64 		if(lst->key == key)
     65 			return lst->val;
     66 	return def(key);
     67 }
     68 
     69 static char*
     70 unmask(Pair *list, uint val)
     71 {
     72 	Pair  *p;
     73 	char *s, *end;
     74 	int n;
     75 
     76 	buffer[0] = '\0';
     77 	end = buffer + sizeof buffer;
     78 	s = buffer;
     79 
     80 	n = 0;
     81 	s = utfecpy(s, end, "(");
     82 	for (p = list; p->val; p++)
     83 		if (val & p->key) {
     84 			if(n++)
     85 				s = utfecpy(s, end, "|");
     86 			s = utfecpy(s, end, p->val);
     87 		}
     88 	utfecpy(s, end, ")");
     89 
     90 	return buffer;
     91 }
     92 
     93 static char *
     94 strhex(int key) {
     95 	sprint(buffer, "0x%x", key);
     96 	return buffer;
     97 }
     98 
     99 static char *
    100 strdec(int key) {
    101 	sprint(buffer, "%d", key);
    102 	return buffer;
    103 }
    104 
    105 static char *
    106 strign(int key) {
    107 	USED(key);
    108 
    109 	return "?";
    110 }
    111 
    112 /******************************************************************************/
    113 /**** Miscellaneous routines to convert values to their string equivalents ****/
    114 /******************************************************************************/
    115 
    116 static void
    117 TInt(Fmt *b, va_list *ap) {
    118 	fmtprint(b, "%d", va_arg(*ap, int));
    119 }
    120 
    121 static void
    122 TWindow(Fmt *b, va_list *ap) {
    123 	Window w;
    124 
    125 	w = va_arg(*ap, Window);
    126 	fmtprint(b, "0x%ux", (uint)w);
    127 }
    128 
    129 static void
    130 TData(Fmt *b, va_list *ap) {
    131 	long *l;
    132 	int i;
    133 
    134 	l = va_arg(*ap, long*);
    135 	fmtprint(b, "{");
    136 	for (i = 0; i < 5; i++) {
    137 		if(i > 0)
    138 			fmtprint(b, ", ");
    139 		fmtprint(b, "0x%08lx", l[i]);
    140 	}
    141 	fmtprint(b, "}");
    142 }
    143 
    144 /* Returns the string equivalent of a timestamp */
    145 static void
    146 TTime(Fmt *b, va_list *ap) {
    147 	ldiv_t	d;
    148 	ulong   msec;
    149 	ulong   sec;
    150 	ulong   min;
    151 	ulong   hr;
    152 	ulong   day;
    153 	Time time;
    154 
    155 	time = va_arg(*ap, Time);
    156 
    157 	msec = time/1000;
    158 	d = ldiv(msec, 60);
    159 	msec = time-msec*1000;
    160 
    161 	sec = d.rem;
    162 	d = ldiv(d.quot, 60);
    163 	min = d.rem;
    164 	d = ldiv(d.quot, 24);
    165 	hr = d.rem;
    166 	day = d.quot;
    167 
    168 #ifdef notdef
    169 	sprintf(buffer, "%lu day%s %02lu:%02lu:%02lu.%03lu",
    170 		day, day == 1 ? "" : "(s)", hr, min, sec, msec);
    171 #endif
    172 
    173 	fmtprint(b, "%ludd_%ludh_%ludm_%lud.%03luds", day, hr, min, sec, msec);
    174 }
    175 
    176 /* Returns the string equivalent of a boolean parameter */
    177 static void
    178 TBool(Fmt *b, va_list *ap) {
    179 	static Pair list[] = {
    180 		{True, "True"},
    181 		{False, "False"},
    182 		{0, nil},
    183 	};
    184 	Bool key;
    185 
    186 	key = va_arg(*ap, Bool);
    187 	fmtprint(b, "%s", search(list, key, strign));
    188 }
    189 
    190 /* Returns the string equivalent of a property notify state */
    191 static void
    192 TPropState(Fmt *b, va_list *ap) {
    193 	static Pair list[] = {
    194 		{PropertyNewValue, "PropertyNewValue"},
    195 		{PropertyDelete, "PropertyDelete"},
    196 		{0, nil},
    197 	};
    198 	uint key;
    199 
    200 	key = va_arg(*ap, uint);
    201 	fmtprint(b, "%s", search(list, key, strign));
    202 }
    203 
    204 /* Returns the string equivalent of a visibility notify state */
    205 static void
    206 TVis(Fmt *b, va_list *ap) {
    207 	static Pair list[] = {
    208 		{VisibilityUnobscured, "VisibilityUnobscured"},
    209 		{VisibilityPartiallyObscured, "VisibilityPartiallyObscured"},
    210 		{VisibilityFullyObscured, "VisibilityFullyObscured"},
    211 		{0, nil},
    212 	};
    213 	int key;
    214 
    215 	key = va_arg(*ap, int);
    216 	fmtprint(b, "%s", search(list, key, strign));
    217 }
    218 
    219 /* Returns the string equivalent of a mask of buttons and/or modifier keys */
    220 static void
    221 TModState(Fmt *b, va_list *ap) {
    222 	static Pair list[] = {
    223 		{Button1Mask, "Button1Mask"},
    224 		{Button2Mask, "Button2Mask"},
    225 		{Button3Mask, "Button3Mask"},
    226 		{Button4Mask, "Button4Mask"},
    227 		{Button5Mask, "Button5Mask"},
    228 		{ShiftMask, "ShiftMask"},
    229 		{LockMask, "LockMask"},
    230 		{ControlMask, "ControlMask"},
    231 		{Mod1Mask, "Mod1Mask"},
    232 		{Mod2Mask, "Mod2Mask"},
    233 		{Mod3Mask, "Mod3Mask"},
    234 		{Mod4Mask, "Mod4Mask"},
    235 		{Mod5Mask, "Mod5Mask"},
    236 		{0, nil},
    237 	};
    238 	uint state;
    239 
    240 	state = va_arg(*ap, uint);
    241 	fmtprint(b, "%s", unmask(list, state));
    242 }
    243 
    244 /* Returns the string equivalent of a mask of configure window values */
    245 static void
    246 TConfMask(Fmt *b, va_list *ap) {
    247 	static Pair list[] = {
    248 		{CWX, "CWX"},
    249 		{CWY, "CWY"},
    250 		{CWWidth, "CWWidth"},
    251 		{CWHeight, "CWHeight"},
    252 		{CWBorderWidth, "CWBorderWidth"},
    253 		{CWSibling, "CWSibling"},
    254 		{CWStackMode, "CWStackMode"},
    255 		{0, nil},
    256 	};
    257 	uint valuemask;
    258 
    259 	valuemask = va_arg(*ap, uint);
    260 	fmtprint(b, "%s", unmask(list, valuemask));
    261 }
    262 
    263 /* Returns the string equivalent of a motion hint */
    264 #if 0
    265 static void
    266 IsHint(Fmt *b, va_list *ap) {
    267 	static Pair list[] = {
    268 		{NotifyNormal, "NotifyNormal"},
    269 		{NotifyHint, "NotifyHint"},
    270 		{0, nil},
    271 	};
    272 	char key;
    273 
    274 	key = va_arg(*ap, char);
    275 	fmtprint(b, "%s", search(list, key, strign));
    276 }
    277 #endif
    278 
    279 /* Returns the string equivalent of an id or the value "None" */
    280 static void
    281 TIntNone(Fmt *b, va_list *ap) {
    282 	static Pair list[] = {
    283 		{None, "None"},
    284 		{0, nil},
    285 	};
    286 	int key;
    287 
    288 	key = va_arg(*ap, int);
    289 	fmtprint(b, "%s", search(list, key, strhex));
    290 }
    291 
    292 /* Returns the string equivalent of a colormap state */
    293 static void
    294 TColMap(Fmt *b, va_list *ap) {
    295 	static Pair list[] = {
    296 		{ColormapInstalled, "ColormapInstalled"},
    297 		{ColormapUninstalled, "ColormapUninstalled"},
    298 		{0, nil},
    299 	};
    300 	int key;
    301 
    302 	key = va_arg(*ap, int);
    303 	fmtprint(b, "%s", search(list, key, strign));
    304 }
    305 
    306 /* Returns the string equivalent of a crossing detail */
    307 static void
    308 TXing(Fmt *b, va_list *ap) {
    309 	static Pair list[] = {
    310 		{NotifyAncestor, "NotifyAncestor"},
    311 		{NotifyInferior, "NotifyInferior"},
    312 		{NotifyVirtual, "NotifyVirtual"},
    313 		{NotifyNonlinear, "NotifyNonlinear"},
    314 		{NotifyNonlinearVirtual, "NotifyNonlinearVirtual"},
    315 		{0, nil},
    316 	};
    317 	int key;
    318 
    319 	key = va_arg(*ap, int);
    320 	fmtprint(b, "%s", search(list, key, strign));
    321 }
    322 
    323 /* Returns the string equivalent of a focus change detail */
    324 static void
    325 TFocus(Fmt *b, va_list *ap) {
    326 	static Pair list[] = {
    327 		{NotifyAncestor, "NotifyAncestor"},
    328 		{NotifyInferior, "NotifyInferior"},
    329 		{NotifyVirtual, "NotifyVirtual"},
    330 		{NotifyNonlinear, "NotifyNonlinear"},
    331 		{NotifyNonlinearVirtual, "NotifyNonlinearVirtual"},
    332 		{NotifyPointer, "NotifyPointer"},
    333 		{NotifyPointerRoot, "NotifyPointerRoot"},
    334 		{NotifyDetailNone, "NotifyDetailNone"},
    335 		{0, nil},
    336 	};
    337 	int key;
    338 
    339 	key = va_arg(*ap, int);
    340 	fmtprint(b, "%s", search(list, key, strign));
    341 }
    342 
    343 /* Returns the string equivalent of a configure detail */
    344 static void
    345 TConfDetail(Fmt *b, va_list *ap) {
    346 	static Pair list[] = {
    347 		{Above, "Above"},
    348 		{Below, "Below"},
    349 		{TopIf, "TopIf"},
    350 		{BottomIf, "BottomIf"},
    351 		{Opposite, "Opposite"},
    352 		{0, nil},
    353 	};
    354 	int key;
    355 
    356 	key = va_arg(*ap, int);
    357 	fmtprint(b, "%s", search(list, key, strign));
    358 }
    359 
    360 /* Returns the string equivalent of a grab mode */
    361 static void
    362 TGrabMode(Fmt *b, va_list *ap) {
    363 	static Pair list[] = {
    364 		{NotifyNormal, "NotifyNormal"},
    365 		{NotifyGrab, "NotifyGrab"},
    366 		{NotifyUngrab, "NotifyUngrab"},
    367 		{NotifyWhileGrabbed, "NotifyWhileGrabbed"},
    368 		{0, nil},
    369 	};
    370 	int key;
    371 
    372 	key = va_arg(*ap, int);
    373 	fmtprint(b, "%s", search(list, key, strign));
    374 }
    375 
    376 /* Returns the string equivalent of a mapping request */
    377 static void
    378 TMapping(Fmt *b, va_list *ap) {
    379 	static Pair list[] = {
    380 		{MappingModifier, "MappingModifier"},
    381 		{MappingKeyboard, "MappingKeyboard"},
    382 		{MappingPointer, "MappingPointer"},
    383 		{0, nil},
    384 	};
    385 	int key;
    386 
    387 	key = va_arg(*ap, int);
    388 	fmtprint(b, "%s", search(list, key, strign));
    389 }
    390 
    391 /* Returns the string equivalent of a stacking order place */
    392 static void
    393 TPlace(Fmt *b, va_list *ap) {
    394 	static Pair list[] = {
    395 		{PlaceOnTop, "PlaceOnTop"},
    396 		{PlaceOnBottom, "PlaceOnBottom"},
    397 		{0, nil},
    398 	};
    399 	int key;
    400 
    401 	key = va_arg(*ap, int);
    402 	fmtprint(b, "%s", search(list, key, strign));
    403 }
    404 
    405 /* Returns the string equivalent of a major code */
    406 static void
    407 TMajor(Fmt *b, va_list *ap) {
    408 	static char *list[] = { XMajors };
    409 	char *s;
    410 	uint key;
    411 
    412 	key = va_arg(*ap, uint);
    413 	s = "<nil>";
    414 	if(key < nelem(list))
    415 		s = list[key];
    416 	fmtprint(b, "%s", s);
    417 }
    418 
    419 static char*
    420 eventtype(int key) {
    421 	static Pair list[] = {
    422 		{ButtonPress, "ButtonPress"},
    423 		{ButtonRelease, "ButtonRelease"},
    424 		{CirculateNotify, "CirculateNotify"},
    425 		{CirculateRequest, "CirculateRequest"},
    426 		{ClientMessage, "ClientMessage"},
    427 		{ColormapNotify, "ColormapNotify"},
    428 		{ConfigureNotify, "ConfigureNotify"},
    429 		{ConfigureRequest, "ConfigureRequest"},
    430 		{CreateNotify, "CreateNotify"},
    431 		{DestroyNotify, "DestroyNotify"},
    432 		{EnterNotify, "EnterNotify"},
    433 		{Expose, "Expose"},
    434 		{FocusIn, "FocusIn"},
    435 		{FocusOut, "FocusOut"},
    436 		{GraphicsExpose, "GraphicsExpose"},
    437 		{GravityNotify, "GravityNotify"},
    438 		{KeyPress, "KeyPress"},
    439 		{KeyRelease, "KeyRelease"},
    440 		{KeymapNotify, "KeymapNotify"},
    441 		{LeaveNotify, "LeaveNotify"},
    442 		{MapNotify, "MapNotify"},
    443 		{MapRequest, "MapRequest"},
    444 		{MappingNotify, "MappingNotify"},
    445 		{MotionNotify, "MotionNotify"},
    446 		{NoExpose, "NoExpose"},
    447 		{PropertyNotify, "PropertyNotify"},
    448 		{ReparentNotify, "ReparentNotify"},
    449 		{ResizeRequest, "ResizeRequest"},
    450 		{SelectionClear, "SelectionClear"},
    451 		{SelectionNotify, "SelectionNotify"},
    452 		{SelectionRequest, "SelectionRequest"},
    453 		{UnmapNotify, "UnmapNotify"},
    454 		{VisibilityNotify, "VisibilityNotify"},
    455 		{0, nil},
    456 	};
    457 	return search(list, key, strdec);
    458 }
    459 /* Returns the string equivalent the keycode contained in the key event */
    460 static void
    461 TKeycode(Fmt *b, va_list *ap) {
    462 	KeySym keysym_str;
    463 	XKeyEvent *ev;
    464 	char *keysym_name;
    465 
    466 	ev = va_arg(*ap, XKeyEvent*);
    467 
    468 	XLookupString(ev, buffer, sizeof buffer, &keysym_str, nil);
    469 
    470 	if (keysym_str == NoSymbol)
    471 		keysym_name = "NoSymbol";
    472 	else
    473 		keysym_name = XKeysymToString(keysym_str);
    474 	if(keysym_name == nil)
    475 		keysym_name = "(no name)";
    476 
    477 	fmtprint(b, "%ud (keysym 0x%x \"%s\")", (int)ev->keycode,
    478 			(int)keysym_str, keysym_name);
    479 }
    480 
    481 /* Returns the string equivalent of an atom or "None" */
    482 static void
    483 TAtom(Fmt *b, va_list *ap) {
    484 
    485 	fmtstrcpy(b, atomname(va_arg(*ap, Atom)));
    486 }
    487 
    488 #define _(m) #m, ev->m
    489 #define TEnd nil
    490 typedef void (*Tfn)(Fmt*, va_list*);
    491 
    492 static int
    493 pevent(Fmt *fmt, void *e, ...) {
    494 	va_list ap;
    495 	Tfn fn;
    496 	XAnyEvent *ev;
    497 	char *key;
    498 	int n;
    499 
    500 	ev = e;
    501 	fmtprint(fmt, "%3ld %-20s ", ev->serial, eventtype(ev->type));
    502 	if(ev->send_event)
    503 		fmtstrcpy(fmt, "(sendevent) ");
    504 
    505 	n = 0;
    506 	va_start(ap, e);
    507 	for(;;) {
    508 		fn = va_arg(ap, Tfn);
    509 		if(fn == TEnd)
    510 			break;
    511 
    512 		if(n++ != 0)
    513 			fmtprint(fmt, "%s", sep);
    514 
    515 		key = va_arg(ap, char*);
    516 		fmtprint(fmt, "%s=", key);
    517 		fn(fmt, &ap);
    518 	}
    519 	va_end(ap);
    520 	return 0;
    521 }
    522 
    523 /*****************************************************************************/
    524 /*** Routines to print out readable values for the field of various events ***/
    525 /*****************************************************************************/
    526 
    527 static int
    528 VerbMotion(Fmt *fmt, XEvent *e) {
    529 	XMotionEvent *ev = &e->xmotion;
    530 
    531 	return 	pevent(fmt, ev,
    532 		TWindow, _(window),
    533 		TWindow, _(root),
    534 		TWindow, _(subwindow),
    535 		TTime, _(time),
    536 		TInt, _(x), TInt, _(y),
    537 		TInt, _(x_root), TInt, _(y_root),
    538 		TModState, _(state),
    539 		TBool, _(same_screen),
    540 		TEnd
    541 	);
    542     //fprintf(stderr, "is_hint=%s%s", IsHint(ev->is_hint), sep);
    543 }
    544 
    545 static int
    546 VerbButton(Fmt *fmt, XEvent *e) {
    547 	XButtonEvent *ev = &e->xbutton;
    548 
    549 	return 	pevent(fmt, ev,
    550 		TWindow, _(window),
    551 		TWindow, _(root),
    552 		TWindow, _(subwindow),
    553 		TTime, _(time),
    554 		TInt, _(x), TInt, _(y),
    555 		TInt, _(x_root), TInt, _(y_root),
    556 		TModState, _(state),
    557 		TInt, _(button),
    558 		TBool, _(same_screen),
    559 		TEnd
    560 	);
    561 }
    562 
    563 static int
    564 VerbColormap(Fmt *fmt, XEvent *e) {
    565 	XColormapEvent *ev = &e->xcolormap;
    566 
    567 	return 	pevent(fmt, ev,
    568 		TWindow, _(window),
    569 		TIntNone, _(colormap),
    570 		TBool, _(new),
    571 		TColMap, _(state),
    572 		TEnd
    573 	);
    574 }
    575 
    576 static int
    577 VerbCrossing(Fmt *fmt, XEvent *e) {
    578 	XCrossingEvent *ev = &e->xcrossing;
    579 
    580 	return 	pevent(fmt, ev,
    581 		TWindow, _(window),
    582 		TWindow, _(root),
    583 		TWindow, _(subwindow),
    584 		TTime, _(time),
    585 		TInt, _(x), TInt, _(y),
    586 		TInt, _(x_root), TInt, _(y_root),
    587 		TGrabMode, _(mode),
    588 		TXing, _(detail),
    589 		TBool, _(same_screen),
    590 		TBool, _(focus),
    591 		TModState, _(state),
    592 		TEnd
    593 	);
    594 }
    595 
    596 static int
    597 VerbExpose(Fmt *fmt, XEvent *e) {
    598 	XExposeEvent *ev = &e->xexpose;
    599 
    600 	return 	pevent(fmt, ev,
    601 		TWindow, _(window),
    602 		TInt, _(x), TInt, _(y),
    603 		TInt, _(width), TInt, _(height),
    604 		TInt, _(count),
    605 		TEnd
    606 	);
    607 }
    608 
    609 static int
    610 VerbGraphicsExpose(Fmt *fmt, XEvent *e) {
    611 	XGraphicsExposeEvent *ev = &e->xgraphicsexpose;
    612 
    613 	return 	pevent(fmt, ev,
    614 		TWindow, _(drawable),
    615 		TInt, _(x), TInt, _(y),
    616 		TInt, _(width), TInt, _(height),
    617 		TMajor, _(major_code),
    618 		TInt, _(minor_code),
    619 		TEnd
    620 	);
    621 }
    622 
    623 static int
    624 VerbNoExpose(Fmt *fmt, XEvent *e) {
    625 	XNoExposeEvent *ev = &e->xnoexpose;
    626 
    627 	return 	pevent(fmt, ev,
    628 		TWindow, _(drawable),
    629 		TMajor, _(major_code),
    630 		TInt, _(minor_code),
    631 		TEnd
    632 	);
    633 }
    634 
    635 static int
    636 VerbFocus(Fmt *fmt, XEvent *e) {
    637 	XFocusChangeEvent *ev = &e->xfocus;
    638 
    639 	return 	pevent(fmt, ev,
    640 		TWindow, _(window),
    641 		TGrabMode, _(mode),
    642 		TFocus, _(detail),
    643 		TEnd
    644 	);
    645 }
    646 
    647 static int
    648 VerbKeymap(Fmt *fmt, XEvent *e) {
    649 	XKeymapEvent *ev = &e->xkeymap;
    650 	int i;
    651 
    652 	fmtprint(fmt, "window=0x%x%s", (int)ev->window, sep);
    653 	fmtprint(fmt, "key_vector=");
    654 	for (i = 0; i < 32; i++)
    655 		fmtprint(fmt, "%02x", ev->key_vector[i]);
    656 	fmtprint(fmt, "\n");
    657 	return 0;
    658 }
    659 
    660 static int
    661 VerbKey(Fmt *fmt, XEvent *e) {
    662 	XKeyEvent *ev = &e->xkey;
    663 
    664 	return 	pevent(fmt, ev,
    665 		TWindow, _(window),
    666 		TWindow, _(root),
    667 		TWindow, _(subwindow),
    668 		TTime, _(time),
    669 		TInt, _(x), TInt, _(y),
    670 		TInt, _(x_root), TInt, _(y_root),
    671 		TModState, _(state),
    672 		TKeycode, "keycode", ev,
    673 		TBool, _(same_screen),
    674 		TEnd
    675 	);
    676 }
    677 
    678 static int
    679 VerbProperty(Fmt *fmt, XEvent *e) {
    680 	XPropertyEvent *ev = &e->xproperty;
    681 
    682 	return 	pevent(fmt, ev,
    683 		TWindow, _(window),
    684 		TAtom, _(atom),
    685 		TTime, _(time),
    686 		TPropState, _(state),
    687 		TEnd
    688 	);
    689 }
    690 
    691 static int
    692 VerbResizeRequest(Fmt *fmt, XEvent *e) {
    693 	XResizeRequestEvent *ev = &e->xresizerequest;
    694 
    695 	return 	pevent(fmt, ev,
    696 		TWindow, _(window),
    697 		TInt, _(width), TInt, _(height),
    698 		TEnd
    699 	);
    700 }
    701 
    702 static int
    703 VerbCirculate(Fmt *fmt, XEvent *e) {
    704 	XCirculateEvent *ev = &e->xcirculate;
    705 
    706 	return 	pevent(fmt, ev,
    707 		TWindow, _(event),
    708 		TWindow, _(window),
    709 		TPlace, _(place),
    710 		TEnd
    711 	);
    712 }
    713 
    714 static int
    715 VerbConfigure(Fmt *fmt, XEvent *e) {
    716 	XConfigureEvent *ev = &e->xconfigure;
    717 
    718 	return 	pevent(fmt, ev,
    719 		TWindow, _(event),
    720 		TWindow, _(window),
    721 		TInt, _(x), TInt, _(y),
    722 		TInt, _(width), TInt, _(height),
    723 		TInt, _(border_width),
    724 		TIntNone, _(above),
    725 		TBool, _(override_redirect),
    726 		TEnd
    727 	);
    728 }
    729 
    730 static int
    731 VerbCreateWindow(Fmt *fmt, XEvent *e) {
    732 	XCreateWindowEvent *ev = &e->xcreatewindow;
    733 
    734 	return 	pevent(fmt, ev,
    735 		TWindow, _(parent),
    736 		TWindow, _(window),
    737 		TInt, _(x), TInt, _(y),
    738 		TInt, _(width), TInt, _(height),
    739 		TInt, _(border_width),
    740 		TBool, _(override_redirect),
    741 		TEnd
    742 	);
    743 }
    744 
    745 static int
    746 VerbDestroyWindow(Fmt *fmt, XEvent *e) {
    747 	XDestroyWindowEvent *ev = &e->xdestroywindow;
    748 
    749 	return 	pevent(fmt, ev,
    750 		TWindow, _(event),
    751 		TWindow, _(window),
    752 		TEnd
    753 	);
    754 }
    755 
    756 static int
    757 VerbGravity(Fmt *fmt, XEvent *e) {
    758 	XGravityEvent *ev = &e->xgravity;
    759 
    760 	return 	pevent(fmt, ev,
    761 		TWindow, _(event),
    762 		TWindow, _(window),
    763 		TInt, _(x), TInt, _(y),
    764 		TEnd
    765 	);
    766 }
    767 
    768 static int
    769 VerbMap(Fmt *fmt, XEvent *e) {
    770 	XMapEvent *ev = &e->xmap;
    771 
    772 	return 	pevent(fmt, ev,
    773 		TWindow, _(event),
    774 		TWindow, _(window),
    775 		TBool, _(override_redirect),
    776 		TEnd
    777 	);
    778 }
    779 
    780 static int
    781 VerbReparent(Fmt *fmt, XEvent *e) {
    782 	XReparentEvent *ev = &e->xreparent;
    783 
    784 	return 	pevent(fmt, ev,
    785 		TWindow, _(event),
    786 		TWindow, _(window),
    787 		TWindow, _(parent),
    788 		TInt, _(x), TInt, _(y),
    789 		TBool, _(override_redirect),
    790 		TEnd
    791 	);
    792 }
    793 
    794 static int
    795 VerbUnmap(Fmt *fmt, XEvent *e) {
    796 	XUnmapEvent *ev = &e->xunmap;
    797 
    798 	return 	pevent(fmt, ev,
    799 		TWindow, _(event),
    800 		TWindow, _(window),
    801 		TBool, _(from_configure),
    802 		TEnd
    803 	);
    804 }
    805 
    806 static int
    807 VerbCirculateRequest(Fmt *fmt, XEvent *e) {
    808 	XCirculateRequestEvent *ev = &e->xcirculaterequest;
    809 
    810 	return 	pevent(fmt, ev,
    811 		TWindow, _(parent),
    812 		TWindow, _(window),
    813 		TPlace, _(place),
    814 		TEnd
    815 	);
    816 }
    817 
    818 static int
    819 VerbConfigureRequest(Fmt *fmt, XEvent *e) {
    820 	XConfigureRequestEvent *ev = &e->xconfigurerequest;
    821 
    822 	return 	pevent(fmt, ev,
    823 		TWindow, _(parent),
    824 		TWindow, _(window),
    825 		TInt, _(x), TInt, _(y),
    826 		TInt, _(width), TInt, _(height),
    827 		TInt, _(border_width),
    828 		TIntNone, _(above),
    829 		TConfDetail, _(detail),
    830 		TConfMask, _(value_mask),
    831 		TEnd
    832 	);
    833 }
    834 
    835 static int
    836 VerbMapRequest(Fmt *fmt, XEvent *e) {
    837 	XMapRequestEvent *ev = &e->xmaprequest;
    838 
    839 	return 	pevent(fmt, ev,
    840 		TWindow, _(parent),
    841 		TWindow, _(window),
    842 		TEnd
    843 	);
    844 }
    845 
    846 static int
    847 VerbClient(Fmt *fmt, XEvent *e) {
    848 	XClientMessageEvent *ev = &e->xclient;
    849 
    850 	return 	pevent(fmt, ev,
    851 		TWindow, _(window),
    852 		TAtom, _(message_type),
    853 		TInt, _(format),
    854 		TData, "data (as longs)", &ev->data,
    855 		TEnd
    856 	);
    857 }
    858 
    859 static int
    860 VerbMapping(Fmt *fmt, XEvent *e) {
    861 	XMappingEvent *ev = &e->xmapping;
    862 
    863 	return 	pevent(fmt, ev,
    864 		TWindow, _(window),
    865 		TMapping, _(request),
    866 		TWindow, _(first_keycode),
    867 		TWindow, _(count),
    868 		TEnd
    869 	);
    870 }
    871 
    872 static int
    873 VerbSelectionClear(Fmt *fmt, XEvent *e) {
    874 	XSelectionClearEvent *ev = &e->xselectionclear;
    875 
    876 	return 	pevent(fmt, ev,
    877 		TWindow, _(window),
    878 		TAtom, _(selection),
    879 		TTime, _(time),
    880 		TEnd
    881 	);
    882 }
    883 
    884 static int
    885 VerbSelection(Fmt *fmt, XEvent *e) {
    886 	XSelectionEvent *ev = &e->xselection;
    887 
    888 	return 	pevent(fmt, ev,
    889 		TWindow, _(requestor),
    890 		TAtom, _(selection),
    891 		TAtom, _(target),
    892 		TAtom, _(property),
    893 		TTime, _(time),
    894 		TEnd
    895 	);
    896 }
    897 
    898 static int
    899 VerbSelectionRequest(Fmt *fmt, XEvent *e) {
    900 	XSelectionRequestEvent *ev = &e->xselectionrequest;
    901 
    902 	return 	pevent(fmt, ev,
    903 		TWindow, _(owner),
    904 		TWindow, _(requestor),
    905 		TAtom, _(selection),
    906 		TAtom, _(target),
    907 		TAtom, _(property),
    908 		TTime, _(time),
    909 		TEnd
    910 	);
    911 }
    912 
    913 static int
    914 VerbVisibility(Fmt *fmt, XEvent *e) {
    915 	XVisibilityEvent *ev = &e->xvisibility;
    916 
    917 	return 	pevent(fmt, ev,
    918 		TWindow, _(window),
    919 		TVis, _(state),
    920 		TEnd
    921 	);
    922 }
    923 
    924 /******************************************************************************/
    925 /**************** Print the values of all fields for any event ****************/
    926 /******************************************************************************/
    927 
    928 typedef struct Handler Handler;
    929 struct Handler {
    930 	int key;
    931 	int (*fn)(Fmt*, XEvent*);
    932 };
    933 
    934 int
    935 fmtevent(Fmt *fmt) {
    936 	XEvent *e;
    937 	XAnyEvent *ev;
    938 	/*
    939 		fprintf(stderr, "type=%s%s", eventtype(e->xany.type), sep);
    940 		fprintf(stderr, "serial=%lu%s", ev->serial, sep);
    941 		fprintf(stderr, "send_event=%s%s", TorF(ev->send_event), sep);
    942 		fprintf(stderr, "display=0x%p%s", ev->display, sep);
    943 	*/
    944 	static Handler fns[] = {
    945 		{MotionNotify, VerbMotion},
    946 		{ButtonPress, VerbButton},
    947 		{ButtonRelease, VerbButton},
    948 		{ColormapNotify, VerbColormap},
    949 		{EnterNotify, VerbCrossing},
    950 		{LeaveNotify, VerbCrossing},
    951 		{Expose, VerbExpose},
    952 		{GraphicsExpose, VerbGraphicsExpose},
    953 		{NoExpose, VerbNoExpose},
    954 		{FocusIn, VerbFocus},
    955 		{FocusOut, VerbFocus},
    956 		{KeymapNotify, VerbKeymap},
    957 		{KeyPress, VerbKey},
    958 		{KeyRelease, VerbKey},
    959 		{PropertyNotify, VerbProperty},
    960 		{ResizeRequest, VerbResizeRequest},
    961 		{CirculateNotify, VerbCirculate},
    962 		{ConfigureNotify, VerbConfigure},
    963 		{CreateNotify, VerbCreateWindow},
    964 		{DestroyNotify, VerbDestroyWindow},
    965 		{GravityNotify, VerbGravity},
    966 		{MapNotify, VerbMap},
    967 		{ReparentNotify, VerbReparent},
    968 		{UnmapNotify, VerbUnmap},
    969 		{CirculateRequest, VerbCirculateRequest},
    970 		{ConfigureRequest, VerbConfigureRequest},
    971 		{MapRequest, VerbMapRequest},
    972 		{ClientMessage, VerbClient},
    973 		{MappingNotify, VerbMapping},
    974 		{SelectionClear, VerbSelectionClear},
    975 		{SelectionNotify, VerbSelection},
    976 		{SelectionRequest, VerbSelectionRequest},
    977 		{VisibilityNotify, VerbVisibility},
    978 		{0, nil},
    979 	};
    980 	Handler *p;
    981 
    982 	e = va_arg(fmt->args, XEvent*);
    983 	ev = &e->xany;
    984 
    985 	for (p = fns; p->fn; p++)
    986 		if (p->key == ev->type)
    987 			return p->fn(fmt, e);
    988 	return 1;
    989 }
    990