Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  * propwatch.c -- (c) 1997-2003 Gerd Knorr <kraxel@bytesex.org>
  3  *
  4  * A tool to monitor window properties of root and application windows.
  5  * Nice for debugging property-based IPC of X11 programs.
  6  *
  7  * see also:
  8  *   xhost(1), xauth(1), xprop(1), xwd(1)
  9  *
 10  */
 11 
 12 #include <stdio.h>
 13 #include <stdlib.h>
 14 #include <unistd.h>
 15 #include <string.h>
 16 #include <sys/time.h>
 17 #include <sys/types.h>
 18 
 19 #include <X11/Xlib.h>
 20 #include <X11/Xatom.h>
 21 #include <X11/Intrinsic.h>
 22 #include <X11/StringDefs.h>
 23 #include <X11/Shell.h>
 24 #include <X11/cursorfont.h>
 25 #include <X11/Xaw/XawInit.h>
 26 #include <X11/Xaw/Label.h>
 27 #include <X11/Xaw/List.h>
 28 #include <X11/Xaw/Viewport.h>
 29 
 30 #ifndef TRUE
 31 #define TRUE   1
 32 #define FALSE  0
 33 #endif
 34 
 35 /*-------------------------------------------------------------------------*/
 36 
 37 struct WATCHLIST {
 38     Window                 win;
 39     int                    watch;
 40     struct WATCHLIST       *next;
 41     char                   *text;
 42 };
 43 
 44 /* WM */
 45 static Atom wm_del_win;
 46 static Atom wm_class;
 47 
 48 /*-------------------------------------------------------------------------*/
 49 
 50 static Widget              bl,vp;
 51 static struct WATCHLIST    *watchlist = NULL;
 52 static char                **watch_name;
 53 static Atom                *watch_atom;
 54 static int                 watch_count;
 55 
 56 static char *watch_default[] = {
 57     "WM_COMMAND",
 58 };
 59 
 60 static String   *str_list;
 61 static int      str_count;
 62 
 63 static void AddWatch(Display *dpy, Window win, int i);
 64 static void DeleteWatch(Window win);
 65 static void CheckWindow(Display *dpy, Window win);
 66 static void Update(Display *dpy, Window win, Atom prop);
 67 
 68 /*-------------------------------------------------------------------------*/
 69 
 70 struct ARGS {
 71     char  *watch;
 72     int   verbose;
 73     int   proplog;
 74     int   kbdlog;
 75 } args;
 76 
 77 XtResource args_desc[] = {
 78     /* name, class, type, size, offset, default_type, default_addr */
 79     {
 80         /* ----- Strings ----- */
 81         "watch",
 82         XtCString, XtRString, sizeof(char*),
 83         XtOffset(struct ARGS*,watch),
 84         XtRString, NULL,
 85     },{
 86         /* ----- Integer ----- */
 87         "verbose",
 88         XtCValue, XtRInt, sizeof(int),
 89         XtOffset(struct ARGS*,verbose),
 90         XtRString, ""
 91     },{
 92         "proplog",
 93         XtCValue, XtRInt, sizeof(int),
 94         XtOffset(struct ARGS*,proplog),
 95         XtRString, ""
 96     },{
 97         "kbdlog",
 98         XtCValue, XtRInt, sizeof(int),
 99         XtOffset(struct ARGS*,kbdlog),
100         XtRString, ""
101     }
102 };
103 const int args_count = XtNumber(args_desc);
104 
105 XrmOptionDescRec opt_desc[] = {
106     { "-watch",      "watch",       XrmoptionSepArg, NULL },
107     { "-verbose",    "verbose",     XrmoptionNoArg,  "1" },
108     { "-proplog",    "proplog",     XrmoptionNoArg,  "1" },
109     { "-kbdlog",     "kbdlog",      XrmoptionNoArg,  "1" },
110 };
111 const int opt_count = (sizeof(opt_desc)/sizeof(XrmOptionDescRec));
112 
113 /*-------------------------------------------------------------------------*/
114 
115 XtAppContext      app_context;
116 Widget            app_shell;
117 Cursor            left_ptr;
118 Cursor            menu_ptr;
119 
120 static void QuitAction(Widget, XEvent*, String*, Cardinal*);
121 static void HookAction(Widget, XEvent*, String*, Cardinal*);
122 
123 static void ProcessPropertyChange(Display*,XEvent*);
124 static void ProcessKeyPress(Display*,XEvent*);
125 static void ProcessClientMessage(Display*,XEvent*);
126 static void ProcessCreateWindow(Display*,XEvent*);
127 static void ProcessEvent(Display *dpy, XEvent *event);
128 
129 /* Actions */
130 static XtActionsRec actionTable[] = {
131     { "Quit", QuitAction },
132     { "Hook", HookAction },
133 };
134 
135 /*-------------------------------------------------------------------------*/
136 
137 static int
138 x11_error_dev_null(Display * dpy, XErrorEvent * event)
139 {
140     if (args.verbose)
141         printf("x11 error -- ignored (likely just a race as X11 is async)\n");
142     return 0;
143 }
144 
145 static void
146 spy_input(XtPointer client_data, int *src, XtInputId *id)
147 {
148     Display *spy_dpy = client_data;
149     XEvent   event;
150 
151     while (True == XCheckMaskEvent(spy_dpy, 0xffffffff, &event))
152         ProcessEvent(spy_dpy,&event);
153 }
154 
155 static void
156 add_window(Display *dpy, Window win)
157 {
158     Window rroot,parent,*children = NULL;
159     int i, n;
160 
161     if (NULL == args.watch && XtWindow(app_shell) == win)
162         /* don't f*ck up ourself */
163         return;
164 
165     XSelectInput(dpy, win,
166                  (args.kbdlog ? KeyPressMask | KeyReleaseMask : 0) |
167                  PropertyChangeMask |
168                  SubstructureNotifyMask);
169 
170     if (0 != XQueryTree(dpy, win, &rroot, &parent, &children, &n)) {
171         for (i = 0; i < n; i++)
172             add_window(dpy,children[i]);
173         if (children)
174             XFree(children);
175     }
176 
177     /* look for properties to show */
178     CheckWindow(dpy, win);
179 }
180 
181 int
182 main(int argc, char *argv[])
183 {
184     Screen *scr;
185     XColor white,red,dummy;
186     int i;
187     Window root;
188     Display *dpy, *spy_dpy;
189     char title[1024];
190     XEvent  event;
191 
192     /* init X11 */
193     app_shell = XtAppInitialize(&app_context, "Propwatch",
194                                 opt_desc, opt_count,
195                                 &argc, argv,
196                                 NULL,
197                                 NULL, 0);
198     XtGetApplicationResources(app_shell,&args,
199                               args_desc,args_count,
200                               NULL,0);
201 
202     XtAppAddActions(app_context,actionTable,
203                     sizeof(actionTable)/sizeof(XtActionsRec));
204     XtOverrideTranslations
205         (app_shell,XtParseTranslationTable("<Message>WM_PROTOCOLS: Quit()\n"));
206     dpy = XtDisplay(app_shell);
207     if (NULL != args.watch) {
208         if (NULL == (spy_dpy = XOpenDisplay(args.watch))) {
209             fprintf(stderr,"can't open display: %s\n",args.watch);
210             exit(1);
211         }
212         sprintf(title,"watch on %s - ",args.watch);
213     } else {
214         spy_dpy = dpy;
215         sprintf(title,"watch - ");
216     }
217     root = DefaultRootWindow(spy_dpy);
218     
219     XSetErrorHandler(x11_error_dev_null);
220 
221     /* args */
222     if (argc > 1) {
223         watch_count = argc-1;
224         watch_name  = argv+1;
225     } else {
226         watch_count = sizeof(watch_default)/sizeof(char*);
227         watch_name  = watch_default;
228     }
229     watch_atom  = malloc(sizeof(Atom)*watch_count);
230 
231     /* Atoms */
232     wm_del_win   = XInternAtom(dpy,"WM_DELETE_WINDOW", FALSE);
233     wm_class     = XInternAtom(dpy,"WM_CLASS",         FALSE);
234     for (i = 0; i < watch_count; i++) {
235         watch_atom[i] = XInternAtom(spy_dpy,watch_name[i],FALSE);
236         strcat(title,watch_name[i]);
237         if (i < watch_count-1)
238             strcat(title,", ");
239     }
240     XtVaSetValues(app_shell,XtNtitle,title,NULL);
241 
242     /* nice Cursors */
243     left_ptr = XCreateFontCursor(dpy,XC_left_ptr);
244     menu_ptr = XCreateFontCursor(dpy,XC_right_ptr);
245     scr = DefaultScreenOfDisplay(dpy);
246     if (DefaultDepthOfScreen(scr) > 1) {
247         if (XAllocNamedColor(dpy,DefaultColormapOfScreen(scr),
248                              "white",&white,&dummy) &&
249             XAllocNamedColor(dpy,DefaultColormapOfScreen(scr),
250                              "red",&red,&dummy)) {
251             XRecolorCursor(dpy,left_ptr,&red,&white);
252             XRecolorCursor(dpy,menu_ptr,&red,&white);
253         } 
254     }
255 
256     /* widgets*/
257     vp = XtVaCreateManagedWidget("vp",viewportWidgetClass,app_shell,
258                                  XtNallowHoriz, False,
259                                  XtNallowVert,  True,
260                                  XtNwidth,      600,
261                                  XtNheight,     400,
262                                  NULL);
263     bl = XtVaCreateManagedWidget("box",listWidgetClass,vp,
264                                  XtNdefaultColumns,1,
265                                  XtNforceColumns,True,
266                                  NULL);
267     XtOverrideTranslations(bl,XtParseTranslationTable
268                            ("<Key>Q: Quit()\n"
269                             "<Key>P: Hook(xprop)\n"));
270 
271     /* display main window */
272     XtRealizeWidget(app_shell);
273     XDefineCursor(dpy,XtWindow(app_shell),left_ptr);
274     XSetWMProtocols(dpy,XtWindow(app_shell),&wm_del_win,1);
275 
276     add_window(spy_dpy,root);
277 
278     /* enter main loop */
279     if (spy_dpy != dpy) {
280         XtAppAddInput(app_context,ConnectionNumber(spy_dpy),
281                       (XtPointer)XtInputReadMask,
282                       spy_input,spy_dpy);
283     }
284     while (TRUE) {
285         XtAppNextEvent(app_context,&event);
286         if (XtDispatchEvent(&event))
287             continue;
288         ProcessEvent(spy_dpy,&event);
289     }
290     
291     /* keep compiler happy */
292     return 0;
293 }
294 
295 /*-------------------------------------------------------------------------*/
296 
297 static int
298 cmp(const void *a, const void *b)
299 {
300     char **aa = (char**)a;
301     char **bb = (char**)b;
302     return strcmp(*aa,*bb);
303 }
304 
305 static void
306 RebuildList(void)
307 {
308     static char *empty = "empty";
309     int i;
310     struct WATCHLIST *this;
311 
312     if (str_list)
313         free(str_list);
314     str_list = malloc(str_count*sizeof(String));
315     for (i=0, this=watchlist; this!=NULL; i++, this=this->next)
316         str_list[i] = this->text;
317     qsort(str_list,str_count,sizeof(char*),cmp);
318     XawListChange(bl,str_count ? str_list : &empty,
319                   str_count ? str_count : 1,1000,1);
320 }
321 
322 void
323 AddWatch(Display *dpy, Window win, int i)
324 {
325     struct WATCHLIST   *this;
326 
327     this = malloc(sizeof(struct WATCHLIST));
328     memset(this,0,sizeof(struct WATCHLIST));
329     if (watchlist)
330         this->next = watchlist;
331     watchlist = this;
332 
333     this->win   = win;
334     this->watch = i;
335     str_count++;
336     Update(dpy,win,watch_atom[i]);
337     RebuildList();
338 }
339 
340 void
341 DeleteWatch(Window win)
342 {
343     struct WATCHLIST *this,*prev = NULL;
344 
345     for (this = watchlist; this != NULL;) {
346         if (this->win == win) {
347             if (prev)
348                 prev->next = this->next;
349             else
350                 watchlist = this->next;
351             this = this->next;
352             str_count--;
353         } else {
354             prev = this;
355             this = this->next;
356         }
357     }
358     RebuildList();
359 }
360 
361 void
362 CheckWindow(Display *dpy, Window win)
363 {
364     Atom               type;
365     int                format,i;
366     unsigned long      nitems,rest;
367     unsigned char      *data;
368 
369     for (i = 0; i < watch_count; i++) {
370         if (Success != XGetWindowProperty
371             (dpy,win,watch_atom[i],
372              0,64,False,AnyPropertyType,
373              &type,&format,&nitems,&rest,&data))
374             continue;
375         if (None != type) {
376             AddWatch(dpy,win,i);
377             XFree(data);
378         }
379     }
380 }
381 
382 /*-------------------------------------------------------------------------*/
383 
384 static char* str_append(char *dest, char *sep, char *quot, char *str)
385 {
386     int size, pos;
387 
388     pos   = dest ? strlen(dest)   : 0;
389     size  = str  ? strlen(str)    : 0;
390     size += sep  ? strlen(sep)    : 0;
391     size += quot ? strlen(quot)*2 : 0;
392     dest  = realloc(dest,pos+size+1);
393     sprintf(dest+pos,"%s%s%s%s",
394             sep  ? sep  : "",
395             quot ? quot : "",
396             str  ? str  : "",
397             quot ? quot : "");
398     return dest;
399 }
400 
401 static char*
402 PropertyToString(Display *dpy, Window win, Atom prop)
403 {
404     Atom               type;
405     int                format;
406     unsigned int       i;
407     unsigned long      nitems,rest;
408     unsigned char      *cdata;
409     unsigned long      *ldata;
410     char               window[12],*name;
411     char               *buf = NULL;
412     char               *sep = NULL;
413 
414     if (Success != XGetWindowProperty
415         (dpy,win,prop,0,64,False,AnyPropertyType,
416          &type,&format,&nitems,&rest,&cdata))
417         return NULL;
418     ldata = (unsigned long*)cdata;
419     switch (type) {
420     case XA_STRING:
421         for (i = 0; i < nitems; i += strlen(cdata+i)+1) {
422             buf = str_append(buf,sep,"\"",cdata+i);
423             sep = ", ";
424         }
425         break;
426     case XA_ATOM:
427         for (i = 0; i < nitems; i++) {
428             name = XGetAtomName(dpy,ldata[i]);
429             buf = str_append(buf,sep,NULL,name);
430             sep = ", ";
431             if (name)
432                 XFree(name);
433         }
434         break;
435     default:
436         if (32 == format) {
437             for (i = 0; i < nitems; i++) {
438                 sprintf(window,"0x%x",(unsigned int)ldata[i]);
439                 buf = str_append(buf,sep,NULL,window);
440                 sep = ", ";
441             }
442         } else {
443             name = XGetAtomName(dpy,type);
444             buf = malloc(40 + (name ? strlen(name) : 4));
445             sprintf(buf,"can't handle: format=%d type=%s",
446                     format, name ? name : "NULL");
447             if (name)
448                 XFree(name);
449         }
450         break;
451     }
452     XFree(cdata);
453     return buf;
454 }
455 
456 void
457 Update(Display *dpy, Window win, Atom prop)
458 {
459     struct WATCHLIST   *this;
460     char               *str;
461 
462     for (this = watchlist; this != NULL; this = this->next)
463         if (this->win == win && watch_atom[this->watch] == prop)
464             break;
465     if (this) {
466         if (this->text)
467             free(this->text);
468         str = PropertyToString(dpy,win,prop);
469         this->text = malloc((str ? strlen(str) : 4) +
470                             strlen(watch_name[this->watch]) + 20);
471         sprintf(this->text,"0x%08lx: %s: %s",
472                 this->win, watch_name[this->watch], str ? str : "NULL");
473         if (str)
474             free(str);
475     }
476 }
477 
478 void
479 ProcessPropertyChange(Display *dpy, XEvent* event)
480 {
481     int                i;
482     struct WATCHLIST   *this;
483     char               *name = NULL;
484     char               *prop = NULL;
485 
486     name = XGetAtomName(dpy,event->xproperty.atom);
487     for (i = 0; i < watch_count; i++) {
488         if (watch_atom[i] == event->xproperty.atom) {
489             for (this = watchlist; this != NULL; this = this->next)
490                 if (this->win == event->xproperty.window &&
491                     watch_atom[this->watch] == event->xproperty.atom)
492                     break;
493             if (!this)
494                 AddWatch(dpy,event->xproperty.window, i);
495             else {
496                 Update(dpy,event->xproperty.window,event->xproperty.atom);
497                 XawListChange(bl,str_list,str_count,1000,1);
498             }
499         }
500     }
501 
502     if (args.proplog) {
503         prop = PropertyToString(dpy, event->xproperty.window,
504                                 event->xproperty.atom);
505         printf("0x%-8lx: PropertyChange: %s: %s\n",
506                event->xproperty.window,
507                name ? name : "NULL",
508                prop ? prop : "NULL");
509         if (prop)
510             free(prop);
511     }
512     if (name)
513         XFree(name);
514 }
515 
516 void
517 ProcessClientMessage(Display *dpy, XEvent* event)
518 {
519     fprintf(stderr,"0x%-8lx: ClientMessage\n",
520             event->xclient.window);
521 }
522 
523 void
524 ProcessKeyPress(Display *dpy, XEvent* event)
525 {
526     fprintf(stderr,"0x%-8lx: %s: code=%d sym=%s\n",
527             event->xkey.window,
528             event->type == KeyPress ? "KeyPress" : "KeyRelease",
529             event->xkey.keycode,
530             XKeysymToString(XKeycodeToKeysym(dpy,event->xkey.keycode,0)));
531 }
532 
533 void
534 ProcessCreateWindow(Display *dpy, XEvent* event)
535 {
536     add_window(dpy,event->xcreatewindow.window);
537 }
538 
539 void
540 ProcessEvent(Display *dpy, XEvent *event)
541 {
542     if (event->type == PropertyNotify) {
543         ProcessPropertyChange(dpy,event);
544 
545     } else if (event->type == CreateNotify) {
546         ProcessCreateWindow(dpy,event);
547 
548     } else if (event->type == KeyPress ||
549                event->type == KeyRelease) {
550         ProcessKeyPress(dpy,event);
551 
552     } else if (event->type == ClientMessage) {
553         ProcessClientMessage(dpy,event);
554 
555     } else if (event->type == DestroyNotify) {
556         DeleteWatch(event->xdestroywindow.window);
557     }
558 }
559 
560 /*-------------------------------------------------------------------------*/
561 
562 void
563 QuitAction(Widget widget, XEvent* event, String* arg, Cardinal* arg_count)
564 {
565     exit(0);
566 }
567 
568 void
569 HookAction(Widget widget, XEvent* event, String* arg, Cardinal* arg_count)
570 {
571     XawListReturnStruct *ret;
572     struct WATCHLIST *this;
573     char *dname;
574     char cmd[256];
575     int i;
576 
577     /* find window */
578     if (0 != strcmp(XtName(widget),"box"))
579         return;
580     ret = XawListShowCurrent(widget);
581     for (i = 0, this = watchlist; this != NULL; i++, this=this->next)
582         if (0 == strcmp(ret->string,this->text))
583             break;
584     if (NULL == this)
585         return;
586     if (0 == arg_count)
587         return;
588     dname = DisplayString(XtDisplay(widget));
589 
590     if (0 == strcmp(arg[0],"xprop")) {
591         /* dump window properties */
592         sprintf(cmd,"xprop -display %s -id 0x%lx",
593                 args.watch ? args.watch : dname,
594                 this->win);
595         printf("### %s\n",cmd);
596         system(cmd);
597         printf("### done\n");
598     }
599 }
600 
  This page was automatically generated by the LXR engine.