1 #include "config.h"
2 #include "base.h"
3 #include <string.h>
4 #include <stdio.h>
5 #include <X11/Xlib.h>
6 #ifdef CONFIG_SHAPE
7 #include <X11/extensions/shape.h>
8 #endif
9 #ifdef CONFIG_XRANDR
10 #include <X11/extensions/Xrandr.h>
11 #endif
12 #include "logevent.h"
13
14 bool loggingEvents;
15 bool loggedEventsInited;
16
emptyAtom(Atom atom)17 static const char* emptyAtom(Atom atom) { return ""; }
18 static AtomNameFunc atomName = emptyAtom;
setAtomName(AtomNameFunc func)19 void setAtomName(AtomNameFunc func) { atomName = func; }
getAtomName(unsigned long atom)20 const char* getAtomName(unsigned long atom) {
21 return atomName ? atomName(atom) : "";
22 }
23
24 #if LOGEVENTS
25
26 bool loggedEvents[LASTEvent];
27
28 static const char eventNames[][17] = {
29 "KeyPress", // 2
30 "KeyRelease", // 3
31 "ButtonPress", // 4
32 "ButtonRelease", // 5
33 "MotionNotify", // 6
34 "EnterNotify", // 7
35 "LeaveNotify", // 8
36 "FocusIn", // 9
37 "FocusOut", // 10
38 "KeymapNotify", // 11
39 "Expose", // 12
40 "GraphicsExpose", // 13
41 "NoExpose", // 14
42 "VisibilityNotify", // 15
43 "CreateNotify", // 16
44 "DestroyNotify", // 17
45 "UnmapNotify", // 18
46 "MapNotify", // 19
47 "MapRequest", // 20
48 "ReparentNotify", // 21
49 "ConfigureNotify", // 22
50 "ConfigureRequest", // 23
51 "GravityNotify", // 24
52 "ResizeRequest", // 25
53 "CirculateNotify", // 26
54 "CirculateRequest", // 27
55 "PropertyNotify", // 28
56 "SelectionClear", // 29
57 "SelectionRequest", // 30
58 "SelectionNotify", // 31
59 "ColormapNotify", // 32
60 "ClientMessage", // 33
61 "MappingNotify", // 34
62 "GenericEvent", // 35
63 };
eventName(int eventType)64 const char* eventName(int eventType) {
65 if (inrange(eventType, KeyPress, GenericEvent))
66 return eventNames[eventType - KeyPress];
67 return "UnknownEvent!";
68 }
69
setLogEvent(int evtype,bool enable)70 void setLogEvent(int evtype, bool enable) {
71 if (size_t(evtype) < sizeof loggedEvents)
72 loggedEvents[evtype] = enable;
73 else if (evtype == -1)
74 memset(loggedEvents, enable, sizeof loggedEvents);
75 }
76
boolStr(Bool aBool)77 inline const char* boolStr(Bool aBool) {
78 return aBool ? "True" : "False";
79 }
80
logAny(const XAnyEvent & xev)81 void logAny(const XAnyEvent& xev) {
82 tlog("window=0x%lX: %s type=%d, send=%s, #%lu",
83 xev.window, eventName(xev.type), xev.type,
84 boolStr(xev.send_event), (unsigned long) xev.serial);
85 }
86
logButton(const XButtonEvent & xev)87 void logButton(const XButtonEvent& xev) {
88 tlog("window=0x%lX: %s root=0x%lX, subwindow=0x%lX, time=%ld, "
89 "(%d:%d %d:%d) state=0x%X button=%d same_screen=%s",
90 xev.window,
91 eventName(xev.type),
92 xev.root,
93 xev.subwindow,
94 xev.time,
95 xev.x, xev.y,
96 xev.x_root, xev.y_root,
97 xev.state,
98 xev.button,
99 boolStr(xev.same_screen));
100 }
101
logColormap(const XColormapEvent & xev)102 void logColormap(const XColormapEvent& xev) {
103 tlog("window=0x%lX: colormapNotify colormap=%ld new=%s state=%d",
104 xev.window,
105 xev.colormap,
106 boolStr(xev.c_new),
107 xev.state);
108 }
109
logConfigureNotify(const XConfigureEvent & xev)110 void logConfigureNotify(const XConfigureEvent& xev) {
111 const int size = 256;
112 char buf[size];
113 int len = snprintf(buf, size, "window=0x%lX: configureNotify serial=%lu event=0x%lX, (%+d%+d %dx%d) border=%d",
114 xev.window,
115 (unsigned long) xev.serial,
116 xev.event,
117 xev.x, xev.y,
118 xev.width, xev.height,
119 xev.border_width);
120 if (xev.above)
121 len += snprintf(buf + len, size - len, " above=0x%lX", xev.above);
122 if (xev.override_redirect)
123 len += snprintf(buf + len, size - len, " override=%s", boolStr(xev.override_redirect));
124 if (xev.send_event)
125 len += snprintf(buf + len, size - len, " send=%s", boolStr(xev.send_event));
126 tlog("%s", (0 < len && len < size) ? buf : "lcnbug");
127 }
128
logConfigureRequest(const XConfigureRequestEvent & xev)129 void logConfigureRequest(const XConfigureRequestEvent& xev) {
130 const int size = 256;
131 char buf[size];
132 int len = snprintf(buf, size, "window=0x%lX: %s configureRequest",
133 xev.window, xev.send_event ? "synth" : "real");
134 len += snprintf(buf + len, size - len, " serial=%lu parent=0x%lX",
135 (unsigned long) xev.serial, xev.parent);
136 if ((xev.value_mask & CWX) && 0 < len && len < size)
137 len += snprintf(buf + len, size - len, " X=%d", xev.x);
138 if ((xev.value_mask & CWY) && 0 < len && len < size)
139 len += snprintf(buf + len, size - len, " Y=%d", xev.y);
140 if ((xev.value_mask & CWWidth) && 0 < len && len < size)
141 len += snprintf(buf + len, size - len, " Width=%d", xev.width);
142 if ((xev.value_mask & CWHeight) && 0 < len && len < size)
143 len += snprintf(buf + len, size - len, " Height=%d", xev.height);
144 if ((xev.value_mask & CWBorderWidth) && 0 < len && len < size)
145 len += snprintf(buf + len, size - len, " Border=%d", xev.border_width);
146 if ((xev.value_mask & CWSibling) && 0 < len && len < size)
147 len += snprintf(buf + len, size - len, " Sibling=0x%lX", xev.above);
148 if ((xev.value_mask & CWStackMode) && 0 < len && len < size)
149 len += snprintf(buf + len, size - len, " StackMode=%s",
150 xev.detail == Above ? "Above" :
151 xev.detail == Below ? "Below" :
152 xev.detail == TopIf ? "TopIf" :
153 xev.detail == BottomIf ? "BottomIf" :
154 xev.detail == Opposite ? "Opposite" : "Invalid");
155 tlog("%s", (0 < len && len < size) ? buf : "lcrbug");
156 }
157
logCreate(const XCreateWindowEvent & xev)158 void logCreate(const XCreateWindowEvent& xev) {
159 tlog("window=0x%lX: create serial=%lu parent=0x%lX, (%+d%+d %dx%d) border=%d, override=%s",
160 xev.window,
161 (unsigned long) xev.serial,
162 xev.parent,
163 xev.x, xev.y,
164 xev.width, xev.height,
165 xev.border_width,
166 boolStr(xev.override_redirect));
167 }
168
logCrossing(const XCrossingEvent & xev)169 void logCrossing(const XCrossingEvent& xev) {
170 tlog("window=0x%06lX: %s serial=%lu root=0x%lX, subwindow=0x%lX, time=%ld, "
171 "(%d:%d %d:%d) mode=%s detail=%s same_screen=%s, focus=%s state=0x%X",
172 xev.window,
173 eventName(xev.type),
174 (unsigned long) xev.serial,
175 xev.root,
176 xev.subwindow,
177 xev.time,
178 xev.x, xev.y,
179 xev.x_root, xev.y_root,
180 xev.mode == NotifyNormal ? "Normal" :
181 xev.mode == NotifyGrab ? "Grab" :
182 xev.mode == NotifyUngrab ? "Ungrab" :
183 xev.mode == NotifyWhileGrabbed ? "Grabbed" : "Unknown",
184 xev.detail == NotifyAncestor ? "Ancestor" :
185 xev.detail == NotifyVirtual ? "Virtual" :
186 xev.detail == NotifyInferior ? "Inferior" :
187 xev.detail == NotifyNonlinear ? "Nonlinear" :
188 xev.detail == NotifyNonlinearVirtual ? "NonlinearVirtual" :
189 xev.detail == NotifyPointer ? "Pointer" :
190 xev.detail == NotifyPointerRoot ? "PointerRoot" :
191 xev.detail == NotifyDetailNone ? "DetailNone" : "Unknown",
192 boolStr(xev.same_screen),
193 boolStr(xev.focus),
194 xev.state);
195 }
196
logDestroy(const XDestroyWindowEvent & xev)197 void logDestroy(const XDestroyWindowEvent& xev) {
198 tlog("window=0x%lX: destroy serial=%lu event=0x%lX",
199 xev.window,
200 (unsigned long) xev.serial,
201 xev.event);
202 }
203
logExpose(const XExposeEvent & xev)204 void logExpose(const XExposeEvent& xev) {
205 tlog("window=0x%lX: expose (%+d%+d %dx%d) count=%d",
206 xev.window,
207 xev.x, xev.y, xev.width, xev.height,
208 xev.count);
209 }
210
logFocus(const XFocusChangeEvent & xev)211 void logFocus(const XFocusChangeEvent& xev) {
212 tlog("window=0x%lX: %s mode=%s, detail=%s",
213 xev.window,
214 eventName(xev.type),
215 xev.mode == NotifyNormal ? "NotifyNormal" :
216 xev.mode == NotifyWhileGrabbed ? "NotifyWhileGrabbed" :
217 xev.mode == NotifyGrab ? "NotifyGrab" :
218 xev.mode == NotifyUngrab ? "NotifyUngrab" : "???",
219 xev.detail == NotifyAncestor ? "NotifyAncestor" :
220 xev.detail == NotifyVirtual ? "NotifyVirtual" :
221 xev.detail == NotifyInferior ? "NotifyInferior" :
222 xev.detail == NotifyNonlinear ? "NotifyNonlinear" :
223 xev.detail == NotifyNonlinearVirtual ? "NotifyNonlinearVirtual" :
224 xev.detail == NotifyPointer ? "NotifyPointer" :
225 xev.detail == NotifyPointerRoot ? "NotifyPointerRoot" :
226 xev.detail == NotifyDetailNone ? "NotifyDetailNone" : "???");
227 }
228
logGravity(const XGravityEvent & xev)229 void logGravity(const XGravityEvent& xev) {
230 tlog("window=0x%lX: gravityNotify serial=%lu, x=%+d, y=%+d",
231 xev.window,
232 (unsigned long) xev.serial,
233 xev.x, xev.y);
234 }
235
logKey(const XKeyEvent & xev)236 void logKey(const XKeyEvent& xev) {
237 tlog("window=0x%lX: %s root=0x%lX, subwindow=0x%lX, time=%ld, (%d:%d %d:%d) state=0x%X keycode=0x%x same_screen=%s",
238 xev.window,
239 eventName(xev.type),
240 xev.root,
241 xev.subwindow,
242 xev.time,
243 xev.x, xev.y,
244 xev.x_root, xev.y_root,
245 xev.state,
246 xev.keycode,
247 boolStr(xev.same_screen));
248 }
249
logMapping(const XMappingEvent & xev)250 void logMapping(const XMappingEvent& xev) {
251 tlog("window=0x%lX: mapping request=%s, keycode=%d, n=%d, serial=%lu, send=%s",
252 xev.window,
253 xev.request == MappingModifier ? "MappingModifier" :
254 xev.request == MappingKeyboard ? "MappingKeyboard" :
255 xev.request == MappingPointer ? "MappingPointer" : "?",
256 xev.first_keycode, xev.count,
257 (unsigned long) xev.serial,
258 boolStr(xev.send_event));
259 }
260
logMapRequest(const XMapRequestEvent & xev)261 void logMapRequest(const XMapRequestEvent& xev) {
262 tlog("window=0x%lX: mapRequest serial=%lu parent=0x%lX",
263 xev.window,
264 (unsigned long) xev.serial,
265 xev.parent);
266 }
267
logMapNotify(const XMapEvent & xev)268 void logMapNotify(const XMapEvent& xev) {
269 tlog("window=0x%lX: mapNotify serial=%lu event=0x%lX, override=%s send=%s",
270 xev.window,
271 (unsigned long) xev.serial,
272 xev.event,
273 boolStr(xev.override_redirect),
274 boolStr(xev.send_event));
275 }
276
logUnmap(const XUnmapEvent & xev)277 void logUnmap(const XUnmapEvent& xev) {
278 tlog("window=0x%lX: unmapNotify serial=%lu event=0x%lX, from_configure=%s send=%s",
279 xev.window,
280 (unsigned long) xev.serial,
281 xev.event,
282 boolStr(xev.from_configure),
283 boolStr(xev.send_event));
284 }
285
logMotion(const XMotionEvent & xev)286 void logMotion(const XMotionEvent& xev) {
287 tlog("window=0x%lX: %s root=0x%lX, subwindow=0x%lX, time=%ld, "
288 "(%d:%d %d:%d) state=0x%X is_hint=%s same_screen=%s",
289 xev.window,
290 eventName(xev.type),
291 xev.root,
292 xev.subwindow,
293 xev.time,
294 xev.x, xev.y,
295 xev.x_root, xev.y_root,
296 xev.state,
297 xev.is_hint == NotifyHint ? "NotifyHint" : "",
298 boolStr(xev.same_screen));
299 }
300
logProperty(const XPropertyEvent & xev)301 void logProperty(const XPropertyEvent& xev) {
302 tlog("window=0x%lX: propertyNotify %s time=%ld state=%s",
303 xev.window,
304 atomName(xev.atom),
305 xev.time,
306 xev.state == PropertyNewValue ? "NewValue" :
307 xev.state == PropertyDelete ? "Delete" : "?");
308 }
309
logReparent(const XReparentEvent & xev)310 void logReparent(const XReparentEvent& xev) {
311 tlog("window=0x%lX: reparentNotify serial=%lu event=0x%lX, parent=0x%lX, (%d:%d), override=%s",
312 xev.window,
313 (unsigned long) xev.serial,
314 xev.event,
315 xev.parent,
316 xev.x, xev.y,
317 boolStr(xev.override_redirect));
318 }
319
logVisibility(const XVisibilityEvent & xev)320 void logVisibility(const XVisibilityEvent& xev) {
321 tlog("window=0x%lX: visibilityNotify state=%s",
322 xev.window,
323 xev.state == VisibilityPartiallyObscured ? "partial" :
324 xev.state == VisibilityFullyObscured ? "obscured" :
325 xev.state == VisibilityUnobscured ? "unobscured" : "bogus"
326 );
327 }
328
329 #ifdef CONFIG_SHAPE
logShape(const XEvent & xev)330 void logShape(const XEvent& xev) {
331 const XShapeEvent &shp = (const XShapeEvent &)xev;
332 tlog("window=0x%lX: %s kind=%s %d:%d=%dx%d shaped=%s time=%ld",
333 shp.window, "ShapeEvent",
334 shp.kind == ShapeBounding ? "ShapeBounding" :
335 shp.kind == ShapeClip ? "ShapeClip" : "unknown_shape_kind",
336 shp.x, shp.y, shp.width, shp.height, boolstr(shp.shaped), shp.time);
337 }
338 #endif
339
340 #ifdef CONFIG_XRANDR
logRandrScreen(const XEvent & xev)341 void logRandrScreen(const XEvent& xev) {
342 const XRRScreenChangeNotifyEvent& evt =
343 (const XRRScreenChangeNotifyEvent &)xev;
344 tlog("window=0x%lX: %s index=%u order=%u "
345 "rotation=%u width=%dpx(%dmm) height=%dpx(%dmm)",
346 evt.window, "XRRScreenChangeNotifyEvent",
347 evt.size_index, evt.subpixel_order, (evt.rotation & 15) * 45,
348 evt.width, evt.mwidth, evt.height, evt.mheight
349 );
350 }
351 #endif
352
353 #ifdef CONFIG_XRANDR
logRandrNotify(const XEvent & xev)354 void logRandrNotify(const XEvent& xev) {
355 const XRRNotifyEvent& nev = (const XRRNotifyEvent &)xev;
356 if (nev.subtype == RRNotify_CrtcChange) {
357 const XRRCrtcChangeNotifyEvent& e =
358 (const XRRCrtcChangeNotifyEvent &) xev;
359 tlog("window=0x%lX: %s crtc=%lu mode=%lu rotation=%u %ux%u+%d+%d",
360 e.window, "XRRCrtcChangeNotifyEvent",
361 e.crtc, e.mode, (e.rotation & 15) * 45, e.width, e.height, e.x, e.y
362 );
363 }
364 else if (nev.subtype == RRNotify_OutputChange) {
365 const XRROutputChangeNotifyEvent& e =
366 (const XRROutputChangeNotifyEvent &) xev;
367 tlog("window=0x%lX: %s output=%lu crtc=%lu mode=%lu "
368 "rotation=%u connection=%s subpixel=%u",
369 e.window, "XRROutputChangeNotifyEvent",
370 e.output, e.crtc, e.mode, (e.rotation & 15) * 45,
371 e.connection == RR_Connected ? "RR_Connected" :
372 e.connection == RR_Disconnected ? "RR_Disconnected" :
373 e.connection == RR_UnknownConnection ? "RR_UnknownConnection" :
374 "unknown", e.subpixel_order
375 );
376 }
377 else if (nev.subtype == RRNotify_OutputProperty) {
378 const XRROutputPropertyNotifyEvent& e =
379 (const XRROutputPropertyNotifyEvent &) xev;
380 tlog("window=0x%lX: %s output=%lu property=%lu state=%s",
381 e.window, "XRROutputPropertyNotifyEvent",
382 e.output, e.property,
383 e.state == PropertyNewValue ? "NewValue" :
384 e.state == PropertyDelete ? "Deleted" :
385 "unknown"
386 );
387 }
388 #ifdef RRNotify_ProviderChange
389 else if (nev.subtype == RRNotify_ProviderChange) {
390 const XRRProviderChangeNotifyEvent& e =
391 (const XRRProviderChangeNotifyEvent &) xev;
392 tlog("window=0x%lX: %s provider=%lu current_role=%u",
393 e.window, "XRRProviderChangeNotifyEvent",
394 e.provider, e.current_role
395 );
396 }
397 #endif
398 #ifdef RRNotify_ProviderProperty
399 else if (nev.subtype == RRNotify_ProviderProperty) {
400 const XRRProviderPropertyNotifyEvent& e =
401 (const XRRProviderPropertyNotifyEvent &) xev;
402 tlog("window=0x%lX: %s provider=%lu property=%lu state=%s",
403 e.window, "XRRProviderPropertyNotifyEvent",
404 e.provider, e.property,
405 e.state == PropertyNewValue ? "NewValue" :
406 e.state == PropertyDelete ? "Deleted" :
407 "unknown"
408 );
409 }
410 #endif
411 #ifdef RRNotify_ResourceChange
412 else if (nev.subtype == RRNotify_ResourceChange) {
413 const XRRResourceChangeNotifyEvent& e =
414 (const XRRResourceChangeNotifyEvent &) xev;
415 tlog("window=0x%lX: %s",
416 e.window, "XRRResourceChangeNotifyEvent"
417 );
418 }
419 #endif
420 }
421 #endif
422
423 #else
eventName(int eventType)424 const char* eventName(int eventType) {
425 static char name[3];
426 name[0] = eventType / 10 % 10 + '0';
427 name[1] = eventType % 10 + '0';
428 name[2] = '\0';
429 return name;
430 }
431 #endif
432
433 #if LOGEVENTS
434 #pragma GCC diagnostic push
435 #pragma GCC diagnostic ignored "-Wpragmas"
436 #pragma GCC diagnostic ignored "-Wunknown-pragmas"
437 #pragma GCC diagnostic ignored "-Wunknown-warning-option"
438 #pragma GCC diagnostic ignored "-Wcast-function-type"
439 #endif
440
logEvent(const XEvent & xev)441 void logEvent(const XEvent& xev) {
442 #if LOGEVENTS
443 typedef void (*fun)(const XEvent&);
444 static void (*const loggers[])(const XEvent&) = {
445 (fun) logAny, // 0 reserved
446 (fun) logAny, // 1 reserved
447 (fun) logKey, // 2 KeyPress
448 (fun) logKey, // 3 KeyRelease
449 (fun) logButton, // 4 ButtonPress
450 (fun) logButton, // 5 ButtonRelease
451 (fun) logMotion, // 6 MotionNotify
452 (fun) logCrossing, // 7 EnterNotify
453 (fun) logCrossing, // 8 LeaveNotify
454 (fun) logFocus, // 9 FocusIn
455 (fun) logFocus, // 10 FocusOut
456 (fun) logAny, // 11 KeymapNotify
457 (fun) logExpose, // 12 Expose
458 (fun) logAny, // 13 GraphicsExpose
459 (fun) logAny, // 14 NoExpose
460 (fun) logVisibility, // 15 VisibilityNotify
461 (fun) logCreate, // 16 CreateNotify
462 (fun) logDestroy, // 17 DestroyNotify
463 (fun) logUnmap, // 18 UnmapNotify
464 (fun) logMapNotify, // 19 MapNotify
465 (fun) logMapRequest, // 20 MapRequest
466 (fun) logReparent, // 21 ReparentNotify
467 (fun) logConfigureNotify, // 22 ConfigureNotify
468 (fun) logConfigureRequest, // 23 ConfigureRequest
469 (fun) logGravity, // 24 GravityNotify
470 (fun) logAny, // 25 ResizeRequest
471 (fun) logAny, // 26 CirculateNotify
472 (fun) logAny, // 27 CirculateRequest
473 (fun) logProperty, // 28 PropertyNotify
474 (fun) logAny, // 29 SelectionClear
475 (fun) logAny, // 30 SelectionRequest
476 (fun) logAny, // 31 SelectionNotify
477 (fun) logColormap, // 32 ColormapNotify
478 (fun) logClientMessage, // 33 ClientMessage
479 (fun) logMapping, // 34 MappingNotify
480 (fun) logAny, // 35 GenericEvent
481 };
482 if (loggingEvents && size_t(xev.type) < sizeof loggedEvents &&
483 (loggedEventsInited || initLogEvents()) && loggedEvents[xev.type])
484 {
485 loggers[xev.type](xev);
486 }
487 #endif
488 }
489
490 #if LOGEVENTS
491 #pragma GCC diagnostic pop
492 #endif
493
initLogEvents()494 bool initLogEvents() {
495 #if LOGEVENTS
496 if (loggedEventsInited == false) {
497 memset(loggedEvents, false, sizeof loggedEvents);
498
499 // setLogEvent(KeyPress, true);
500 // setLogEvent(KeyRelease, true);
501 setLogEvent(ButtonPress, true);
502 setLogEvent(ButtonRelease, true);
503 // setLogEvent(MotionNotify, true);
504 setLogEvent(EnterNotify, true);
505 setLogEvent(LeaveNotify, true);
506 setLogEvent(FocusIn, true);
507 setLogEvent(FocusOut, true);
508 // setLogEvent(KeymapNotify, true);
509 // setLogEvent(Expose, true);
510 // setLogEvent(GraphicsExpose, true);
511 // setLogEvent(NoExpose, true);
512 // setLogEvent(VisibilityNotify, true);
513 setLogEvent(CreateNotify, true);
514 setLogEvent(DestroyNotify, true);
515 setLogEvent(UnmapNotify, true);
516 setLogEvent(MapNotify, true);
517 setLogEvent(MapRequest, true);
518 setLogEvent(ReparentNotify, true);
519 setLogEvent(ConfigureNotify, true);
520 setLogEvent(ConfigureRequest, true);
521 // setLogEvent(GravityNotify, true);
522 setLogEvent(ResizeRequest, true);
523 // setLogEvent(CirculateNotify, true);
524 // setLogEvent(CirculateRequest, true);
525 // setLogEvent(PropertyNotify, true);
526 // setLogEvent(SelectionClear, true);
527 // setLogEvent(SelectionRequest, true);
528 // setLogEvent(SelectionNotify, true);
529 // setLogEvent(ColormapNotify, true);
530 setLogEvent(ClientMessage, true);
531 setLogEvent(MappingNotify, true);
532 // setLogEvent(GenericEvent, true);
533
534 loggedEventsInited = true;
535 }
536 #endif
537 return loggedEventsInited;
538 }
539
toggleLogEvents()540 bool toggleLogEvents() {
541 #if LOGEVENTS
542 loggingEvents = !loggingEvents && initLogEvents();
543 #endif
544 return loggingEvents;
545 }
546
logClientMessage(const XClientMessageEvent & event)547 void logClientMessage(const XClientMessageEvent& event) {
548 const char* name = atomName(event.message_type);
549 const long* data = event.data.l;
550 char head[64];
551 snprintf(head, sizeof head, "window=0x%lX: ", event.window);
552 if (strcmp(name, "_NET_WM_STATE") == 0) {
553 const char* op =
554 data[0] == 0 ? "REMOVE" :
555 data[0] == 1 ? "ADD" :
556 data[0] == 2 ? "TOGGLE" : "?";
557 const char* p1 = data[1] ? atomName(data[1]) : "";
558 const char* p2 = data[2] ? atomName(data[2]) : "";
559 tlog("%sClientMessage %s %d data=%s,%s,%s\n",
560 head, name, event.format, op, p1, p2);
561 }
562 else if (strcmp(name, "WM_CHANGE_STATE") == 0) {
563 const char* op =
564 data[0] == 0 ? "WithdrawnState" :
565 data[0] == 1 ? "NormalState" :
566 data[0] == 3 ? "IconicState" : "?";
567 tlog("%sClientMessage %s %s\n", head, name, op);
568 }
569 else {
570 tlog("%sClientMessage %s fmt=%d data=%ld,0x%lX,0x%lX",
571 head, name, event.format, data[0], data[1], data[2]);
572 }
573 }
574
575