home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / clients / xkill / xkill.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-03-20  |  10.4 KB  |  434 lines

  1. /*
  2.  * xkill - simple program for destroying unwanted clients
  3.  *
  4.  * $XConsortium: xkill.c,v 1.18 91/03/20 19:44:15 converse Exp $
  5.  *
  6.  * Copyright 1988 Massachusetts Institute of Technology
  7.  *
  8.  * Permission to use, copy, modify, and distribute this software and its
  9.  * documentation for any purpose and without fee is hereby granted, provided
  10.  * that the above copyright notice appear in all copies and that both that
  11.  * copyright notice and this permission notice appear in supporting
  12.  * documentation, and that the name of M.I.T. not be used in advertising or
  13.  * publicity pertaining to distribution of the software without specific,
  14.  * written prior permission.  M.I.T. makes no representations about the
  15.  * suitability of this software for any purpose.  It is provided "as is"
  16.  * without express or implied warranty.
  17.  *
  18.  * Author:  Jim Fulton, MIT X Consortium; Dana Chee, Bellcore
  19.  */
  20.  
  21. /*
  22.  * Warning, this is a very dangerous client....
  23.  */
  24.  
  25. #include <stdio.h>
  26. #include <ctype.h>
  27.  
  28. #include <X11/Xos.h>
  29. #include <X11/Xlib.h>
  30. #include <X11/cursorfont.h>
  31. #include <X11/Xproto.h>
  32.  
  33. #include <X11/Xmu/WinUtil.h>
  34.  
  35. Display *dpy = NULL;
  36. char *ProgramName;
  37.  
  38. #define SelectButtonAny (-1)
  39. #define SelectButtonFirst (-2)
  40.  
  41. XID parse_id(), get_window_id();
  42. int parse_button(), verify_okay_to_kill();
  43.  
  44. Exit (code)
  45.     int code;
  46. {
  47.     if (dpy) {
  48.     XCloseDisplay (dpy);
  49.     }
  50.     exit (code);
  51. }
  52.  
  53. usage ()
  54. {
  55.     static char *options[] = {
  56. "where options include:",
  57. "    -display displayname    X server to contact",
  58. "    -id resource            resource whose client is to be killed",
  59. "    -frame                  don't ignore window manager frames",
  60. "    -button number          specific button to be pressed to select window",
  61. "    -all                    kill all clients with top level windows",
  62. "",
  63. NULL};
  64.     char **cpp;
  65.  
  66.     fprintf (stderr, "usage:  %s [-option ...]\n",
  67.          ProgramName);
  68.     for (cpp = options; *cpp; cpp++) {
  69.     fprintf (stderr, "%s\n", *cpp);
  70.     }
  71.     Exit (1);
  72. }
  73.  
  74. main (argc, argv)
  75.     int argc;
  76.     char *argv[];
  77. {
  78.     int i;                /* iterator, temp variable */
  79.     char *displayname = NULL;        /* name of server to contact */
  80.     int screenno;            /* screen number of dpy */
  81.     XID id = None;            /* resource to kill */
  82.     char *button_name = NULL;        /* name of button for window select */
  83.     int button;                /* button number or negative for all */
  84.     Bool kill_all = False;
  85.     Bool top = False;
  86.  
  87.     ProgramName = argv[0];
  88.  
  89.     for (i = 1; i < argc; i++) {
  90.     char *arg = argv[i];
  91.  
  92.     if (arg[0] == '-') {
  93.         switch (arg[1]) {
  94.           case 'd':            /* -display displayname */
  95.         if (++i >= argc) usage ();
  96.         displayname = argv[i];
  97.         continue;
  98.           case 'i':            /* -id resourceid */
  99.         if (++i >= argc) usage ();
  100.         id = parse_id (argv[i]);
  101.         continue;
  102.           case 'b':            /* -button number */
  103.         if (++i >= argc) usage ();
  104.         button_name = argv[i];
  105.         continue;
  106.           case 'f':            /* -frame */
  107.         top = True;
  108.         continue;
  109.           case 'a':            /* -all */
  110.         kill_all = True;
  111.         continue;
  112.           default:
  113.         usage ();
  114.         }
  115.     } else {
  116.         usage ();
  117.     }
  118.     }                    /* end for */
  119.  
  120.     dpy = XOpenDisplay (displayname);
  121.     if (!dpy) {
  122.     fprintf (stderr, "%s:  unable to open display \"%s\"\n",
  123.          ProgramName, XDisplayName (displayname));
  124.     Exit (1);
  125.     }
  126.     screenno = DefaultScreen (dpy);
  127.  
  128.     if (kill_all) {
  129.     if (verify_okay_to_kill (dpy, screenno)) 
  130.       kill_all_windows (dpy, screenno, top);
  131.     Exit (0);
  132.     }
  133.  
  134.     /*
  135.      * if no id was given, we need to choose a window
  136.      */
  137.  
  138.     if (id == None) {
  139.     if (!button_name)
  140.         button_name = XGetDefault (dpy, ProgramName, "Button");
  141.  
  142.     if (!button_name)
  143.         button = SelectButtonFirst;
  144.     else if (!parse_button (button_name, &button)) {
  145.         fprintf (stderr, "%s:  invalid button specification \"%s\"\n",
  146.              ProgramName, button_name);
  147.         Exit (1);
  148.     }
  149.  
  150.     if (button >= 0 || button == SelectButtonFirst) {
  151.         unsigned char pointer_map[256];     /* 8 bits of pointer num */
  152.         int count, j;
  153.         unsigned int ub = (unsigned int) button;
  154.  
  155.  
  156.         count = XGetPointerMapping (dpy, pointer_map, 256);
  157.         if (count <= 0) {
  158.         fprintf (stderr, 
  159.              "%s:  no pointer mapping, can't select window\n",
  160.              ProgramName);
  161.         Exit (1);
  162.         }
  163.  
  164.         if (button >= 0) {            /* check button */
  165.         for (j = 0; j < count; j++) {
  166.             if (ub == (unsigned int) pointer_map[j]) break;
  167.         }
  168.         if (j == count) {
  169.             fprintf (stderr,
  170.      "%s:  no button number %u in pointer map, can't select window\n",
  171.                  ProgramName, ub);
  172.             Exit (1);
  173.             }
  174.         } else {                /* get first entry */
  175.         button = (int) ((unsigned int) pointer_map[0]);
  176.         }
  177.     }
  178.     if (id = get_window_id (dpy, screenno, button,
  179.                 "the window whose client you wish to kill")) {
  180.         if (id == RootWindow(dpy,screenno)) id = None;
  181.         else if (!top) {
  182.         XID indicated = id;
  183.         if ((id = XmuClientWindow(dpy, indicated)) == indicated) {
  184.             
  185.             /* Try not to kill the window manager when the user
  186.              * indicates an icon to xkill.
  187.              */
  188.  
  189.             if (! wm_state_set(dpy, id) && wm_running(dpy, screenno))
  190.             id = None;
  191.  
  192.         } 
  193.         }
  194.     }
  195.     }
  196.  
  197.     if (id != None) {
  198.     printf ("%s:  killing creator of resource 0x%lx\n", ProgramName, id);
  199.     XSync (dpy, 0);            /* give xterm a chance */
  200.     XKillClient (dpy, id);
  201.     XSync (dpy, 0);
  202.     }
  203.  
  204.     Exit (0);
  205. }
  206.  
  207. int parse_button (s, buttonp)
  208.     register char *s;
  209.     int *buttonp;
  210. {
  211.     register char *cp;
  212.  
  213.     /* lower case name */
  214.     for (cp = s; *cp; cp++) {
  215.     if (isascii (*cp) && isupper (*cp)) {
  216. #ifdef _tolower
  217.         *cp = _tolower (*cp);
  218. #else
  219.         *cp = tolower (*cp);
  220. #endif /* _tolower */
  221.     }
  222.     }
  223.  
  224.     if (strcmp (s, "any") == 0) {
  225.     *buttonp = SelectButtonAny;
  226.     return (1);
  227.     }
  228.  
  229.     /* check for non-numeric input */
  230.     for (cp = s; *cp; cp++) {
  231.     if (!(isascii (*cp) && isdigit (*cp))) return (0);  /* bogus name */
  232.     }
  233.  
  234.     *buttonp = atoi (s);
  235.     return (1);
  236. }
  237.  
  238.  
  239. XID parse_id (s)
  240.     char *s;
  241. {
  242.     XID retval = None;
  243.     char *fmt = "%ld";            /* since XID is long */
  244.  
  245.     if (s) {
  246.     if (*s == '0') s++, fmt = "%lo";
  247.     if (*s == 'x' || *s == 'X') s++, fmt = "%lx";
  248.     sscanf (s, fmt, &retval);
  249.     }
  250.     return (retval);
  251. }
  252.  
  253. XID get_window_id (dpy, screen, button, msg)
  254.     Display *dpy;
  255.     int screen;
  256.     int button;
  257.     char *msg;
  258. {
  259.     Cursor cursor;        /* cursor to use when selecting */
  260.     Window root;        /* the current root */
  261.     Window retwin = None;    /* the window that got selected */
  262.     int retbutton = -1;        /* button used to select window */
  263.     int pressed = 0;        /* count of number of buttons pressed */
  264.  
  265. #define MASK (ButtonPressMask | ButtonReleaseMask)
  266.  
  267.     root = RootWindow (dpy, screen);
  268.     cursor = XCreateFontCursor (dpy, XC_draped_box);
  269.     if (cursor == None) {
  270.     fprintf (stderr, "%s:  unable to create selection cursor\n",
  271.          ProgramName);
  272.     Exit (1);
  273.     }
  274.  
  275.     printf ("Select %s with ", msg);
  276.     if (button == -1)
  277.       printf ("any button");
  278.     else
  279.       printf ("button %d", button);
  280.     printf ("....\n");
  281.     XSync (dpy, 0);            /* give xterm a chance */
  282.  
  283.     if (XGrabPointer (dpy, root, False, MASK, GrabModeSync, GrabModeAsync, 
  284.                   None, cursor, CurrentTime) != GrabSuccess) {
  285.     fprintf (stderr, "%s:  unable to grab cursor\n", ProgramName);
  286.     Exit (1);
  287.     }
  288.  
  289.     /* from dsimple.c in xwininfo */
  290.     while (retwin == None || pressed != 0) {
  291.     XEvent event;
  292.  
  293.     XAllowEvents (dpy, SyncPointer, CurrentTime);
  294.     XWindowEvent (dpy, root, MASK, &event);
  295.     switch (event.type) {
  296.       case ButtonPress:
  297.         if (retwin == None) {
  298.         retbutton = event.xbutton.button;
  299.         retwin = ((event.xbutton.subwindow != None) ?
  300.               event.xbutton.subwindow : root);
  301.         }
  302.         pressed++;
  303.         continue;
  304.       case ButtonRelease:
  305.         if (pressed > 0) pressed--;
  306.         continue;
  307.     }                    /* end switch */
  308.     }                        /* end for */
  309.  
  310.     XUngrabPointer (dpy, CurrentTime);
  311.     XFreeCursor (dpy, cursor);
  312.     XSync (dpy, 0);
  313.  
  314.     return ((button == -1 || retbutton == button) ? retwin : None);
  315. }
  316.  
  317.  
  318. int catch_window_errors (dpy, ev)
  319.     Display *dpy;
  320.     XErrorEvent *ev;
  321. {
  322.     return 0;
  323. }
  324.  
  325. int kill_all_windows (dpy, screenno, top)
  326.     Display *dpy;
  327.     int screenno;
  328.     Bool top;
  329. {
  330.     Window root = RootWindow (dpy, screenno);
  331.     Window dummywindow;
  332.     Window *children;
  333.     unsigned int nchildren;
  334.     unsigned int i;
  335.     XWindowAttributes attr;
  336.  
  337.     XSync (dpy, 0);
  338.     XSetErrorHandler (catch_window_errors);
  339.  
  340.     nchildren = 0;
  341.     XQueryTree (dpy, root, &dummywindow, &dummywindow, &children, &nchildren);
  342.     if (!top) {
  343.     for (i = 0; i < nchildren; i++) {
  344.         if (XGetWindowAttributes(dpy, children[i], &attr) &&
  345.         (attr.map_state == IsViewable))
  346.         children[i] = XmuClientWindow(dpy, children[i]);
  347.         else
  348.         children[i] = 0;
  349.     }
  350.     }
  351.     for (i = 0; i < nchildren; i++) {
  352.     if (children[i])
  353.         XKillClient (dpy, children[i]);
  354.     }
  355.     XFree ((char *)children);
  356.  
  357.     XSync (dpy, 0);
  358.     XSetErrorHandler (NULL);        /* pretty stupid way to do things... */
  359.  
  360.     return 0;
  361. }
  362.  
  363. /*
  364.  * ask the user to press in the root with each button in succession
  365.  */
  366. int verify_okay_to_kill (dpy, screenno)
  367.     Display *dpy;
  368.     int screenno;
  369. {
  370.     unsigned char pointer_map[256];
  371.     int count = XGetPointerMapping (dpy, pointer_map, 256);
  372.     int i;
  373.     int button;
  374.     static char *msg = "the root window";
  375.     Window root = RootWindow (dpy, screenno);
  376.     int okay = 0;
  377.  
  378.     for (i = 0; i < count; i++) {
  379.     button = (int) pointer_map[i];
  380.     if (button == 0) continue;    /* disabled */
  381.     if (get_window_id (dpy, screenno, button, msg) != root) {
  382.         okay = 0;
  383.         break;
  384.     }
  385.     okay++;                /* must have at least one button */
  386.     }
  387.     if (okay) {
  388.     return 1;
  389.     } else {
  390.     printf ("Aborting.\n");
  391.     return 0;
  392.     }
  393. }
  394.  
  395. /* Return True if the property WM_STATE is set on the window, otherwise
  396.  * return False.
  397.  */
  398. Bool wm_state_set(dpy, win) 
  399. Display    *dpy;
  400. Window    win;
  401. {
  402.     Atom wm_state;
  403.     Atom actual_type;
  404.     int success;
  405.     int actual_format;
  406.     unsigned long nitems, remaining;
  407.     unsigned char* prop = NULL;
  408.  
  409.     wm_state = XInternAtom(dpy, "WM_STATE", True);
  410.     if (wm_state == None) return False;
  411.     success = XGetWindowProperty(dpy, win, wm_state, 0L, 0L, False, 
  412.                  AnyPropertyType, &actual_type, &actual_format,
  413.                  &nitems, &remaining, &prop);
  414.     if (prop) XFree((char *) prop);
  415.     return (success == Success && actual_type != None && actual_format);
  416. }
  417.  
  418. /* Using a heuristic method, return True if a window manager is running,
  419.  * otherwise, return False.
  420.  */
  421.  
  422. Bool wm_running(dpy, screenno)
  423. Display *dpy;
  424. int    screenno;
  425. {
  426.     XWindowAttributes    xwa;
  427.     Status        status;
  428.  
  429.     status = XGetWindowAttributes(dpy, RootWindow(dpy, screenno), &xwa);
  430.     return (status &&
  431.         ((xwa.all_event_masks & SubstructureRedirectMask) ||
  432.          (xwa.all_event_masks & SubstructureNotifyMask)));
  433. }
  434.