xkill.c revision b66d1acb
14fb28925Smrg/* $Xorg: xkill.c,v 1.5 2001/02/09 02:05:54 xorgcvs Exp $ */ 24fb28925Smrg/* 34fb28925Smrg 44fb28925SmrgCopyright 1988, 1998 The Open Group 54fb28925Smrg 64fb28925SmrgPermission to use, copy, modify, distribute, and sell this software and its 74fb28925Smrgdocumentation for any purpose is hereby granted without fee, provided that 84fb28925Smrgthe above copyright notice appear in all copies and that both that 94fb28925Smrgcopyright notice and this permission notice appear in supporting 104fb28925Smrgdocumentation. 114fb28925Smrg 124fb28925SmrgThe above copyright notice and this permission notice shall be included 134fb28925Smrgin all copies or substantial portions of the Software. 144fb28925Smrg 154fb28925SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 164fb28925SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 174fb28925SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 184fb28925SmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 194fb28925SmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 204fb28925SmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 214fb28925SmrgOTHER DEALINGS IN THE SOFTWARE. 224fb28925Smrg 234fb28925SmrgExcept as contained in this notice, the name of The Open Group shall 244fb28925Smrgnot be used in advertising or otherwise to promote the sale, use or 254fb28925Smrgother dealings in this Software without prior written authorization 264fb28925Smrgfrom The Open Group. 274fb28925Smrg 284fb28925Smrg*/ 294fb28925Smrg/* $XFree86: xc/programs/xkill/xkill.c,v 1.5 2001/04/01 14:00:22 tsi Exp $ */ 304fb28925Smrg 314fb28925Smrg/* 324fb28925Smrg * xkill - simple program for destroying unwanted clients 334fb28925Smrg * Author: Jim Fulton, MIT X Consortium; Dana Chee, Bellcore 344fb28925Smrg */ 354fb28925Smrg 364fb28925Smrg/* 374fb28925Smrg * Warning, this is a very dangerous client.... 384fb28925Smrg */ 394fb28925Smrg 404fb28925Smrg#include <stdio.h> 414fb28925Smrg#include <stdlib.h> 424fb28925Smrg#include <ctype.h> 434fb28925Smrg 444fb28925Smrg#include <X11/Xos.h> 454fb28925Smrg#include <X11/Xlib.h> 464fb28925Smrg#include <X11/cursorfont.h> 474fb28925Smrg#include <X11/Xproto.h> 484fb28925Smrg 494fb28925Smrg#include <X11/Xmu/WinUtil.h> 504fb28925Smrg 51b66d1acbSmrgstatic Display *dpy = NULL; 52b66d1acbSmrgstatic char *ProgramName; 534fb28925Smrg 544fb28925Smrg#define SelectButtonAny (-1) 554fb28925Smrg#define SelectButtonFirst (-2) 564fb28925Smrg 574fb28925Smrgstatic int parse_button ( char *s, int *buttonp ); 584fb28925Smrgstatic XID parse_id ( char *s ); 594fb28925Smrgstatic XID get_window_id ( Display *dpy, int screen, int button, char *msg ); 604fb28925Smrgstatic int catch_window_errors ( Display *dpy, XErrorEvent *ev ); 614fb28925Smrgstatic int kill_all_windows ( Display *dpy, int screenno, Bool top ); 624fb28925Smrgstatic int verify_okay_to_kill ( Display *dpy, int screenno ); 634fb28925Smrgstatic Bool wm_state_set ( Display *dpy, Window win ); 644fb28925Smrgstatic Bool wm_running ( Display *dpy, int screenno ); 654fb28925Smrg 664fb28925Smrgstatic void 674fb28925SmrgExit(int code) 684fb28925Smrg{ 694fb28925Smrg if (dpy) { 704fb28925Smrg XCloseDisplay (dpy); 714fb28925Smrg } 724fb28925Smrg exit (code); 734fb28925Smrg} 744fb28925Smrg 754fb28925Smrgstatic void 764fb28925Smrgusage(void) 774fb28925Smrg{ 784fb28925Smrg static char *options[] = { 794fb28925Smrg"where options include:", 804fb28925Smrg" -display displayname X server to contact", 814fb28925Smrg" -id resource resource whose client is to be killed", 824fb28925Smrg" -frame don't ignore window manager frames", 834fb28925Smrg" -button number specific button to be pressed to select window", 844fb28925Smrg" -all kill all clients with top level windows", 854fb28925Smrg"", 864fb28925SmrgNULL}; 874fb28925Smrg char **cpp; 884fb28925Smrg 894fb28925Smrg fprintf (stderr, "usage: %s [-option ...]\n", 904fb28925Smrg ProgramName); 914fb28925Smrg for (cpp = options; *cpp; cpp++) { 924fb28925Smrg fprintf (stderr, "%s\n", *cpp); 934fb28925Smrg } 944fb28925Smrg Exit (1); 954fb28925Smrg} 964fb28925Smrg 974fb28925Smrgint 984fb28925Smrgmain(int argc, char *argv[]) 994fb28925Smrg{ 1004fb28925Smrg int i; /* iterator, temp variable */ 1014fb28925Smrg char *displayname = NULL; /* name of server to contact */ 1024fb28925Smrg int screenno; /* screen number of dpy */ 1034fb28925Smrg XID id = None; /* resource to kill */ 1044fb28925Smrg char *button_name = NULL; /* name of button for window select */ 1054fb28925Smrg int button; /* button number or negative for all */ 1064fb28925Smrg Bool kill_all = False; 1074fb28925Smrg Bool top = False; 1084fb28925Smrg 1094fb28925Smrg ProgramName = argv[0]; 110b66d1acbSmrg button = SelectButtonFirst; 1114fb28925Smrg 1124fb28925Smrg for (i = 1; i < argc; i++) { 1134fb28925Smrg char *arg = argv[i]; 1144fb28925Smrg 1154fb28925Smrg if (arg[0] == '-') { 1164fb28925Smrg switch (arg[1]) { 1174fb28925Smrg case 'd': /* -display displayname */ 1184fb28925Smrg if (++i >= argc) usage (); 1194fb28925Smrg displayname = argv[i]; 1204fb28925Smrg continue; 1214fb28925Smrg case 'i': /* -id resourceid */ 1224fb28925Smrg if (++i >= argc) usage (); 1234fb28925Smrg id = parse_id (argv[i]); 1244fb28925Smrg continue; 1254fb28925Smrg case 'b': /* -button number */ 1264fb28925Smrg if (++i >= argc) usage (); 1274fb28925Smrg button_name = argv[i]; 1284fb28925Smrg continue; 1294fb28925Smrg case 'f': /* -frame */ 1304fb28925Smrg top = True; 1314fb28925Smrg continue; 1324fb28925Smrg case 'a': /* -all */ 1334fb28925Smrg kill_all = True; 1344fb28925Smrg continue; 1354fb28925Smrg default: 1364fb28925Smrg usage (); 1374fb28925Smrg } 1384fb28925Smrg } else { 1394fb28925Smrg usage (); 1404fb28925Smrg } 1414fb28925Smrg } /* end for */ 1424fb28925Smrg 1434fb28925Smrg dpy = XOpenDisplay (displayname); 1444fb28925Smrg if (!dpy) { 1454fb28925Smrg fprintf (stderr, "%s: unable to open display \"%s\"\n", 1464fb28925Smrg ProgramName, XDisplayName (displayname)); 1474fb28925Smrg Exit (1); 1484fb28925Smrg } 1494fb28925Smrg screenno = DefaultScreen (dpy); 1504fb28925Smrg 1514fb28925Smrg if (kill_all) { 1524fb28925Smrg if (verify_okay_to_kill (dpy, screenno)) 1534fb28925Smrg kill_all_windows (dpy, screenno, top); 1544fb28925Smrg Exit (0); 1554fb28925Smrg } 1564fb28925Smrg 1574fb28925Smrg /* 1584fb28925Smrg * if no id was given, we need to choose a window 1594fb28925Smrg */ 1604fb28925Smrg 1614fb28925Smrg if (id == None) { 1624fb28925Smrg if (!button_name) 1634fb28925Smrg button_name = XGetDefault (dpy, ProgramName, "Button"); 1644fb28925Smrg 165b66d1acbSmrg if (button_name && !parse_button (button_name, &button)) { 1664fb28925Smrg fprintf (stderr, "%s: invalid button specification \"%s\"\n", 1674fb28925Smrg ProgramName, button_name); 1684fb28925Smrg Exit (1); 1694fb28925Smrg } 1704fb28925Smrg 1714fb28925Smrg if (button >= 0 || button == SelectButtonFirst) { 1724fb28925Smrg unsigned char pointer_map[256]; /* 8 bits of pointer num */ 1734fb28925Smrg int count, j; 1744fb28925Smrg unsigned int ub = (unsigned int) button; 1754fb28925Smrg 1764fb28925Smrg 1774fb28925Smrg count = XGetPointerMapping (dpy, pointer_map, 256); 1784fb28925Smrg if (count <= 0) { 1794fb28925Smrg fprintf (stderr, 1804fb28925Smrg "%s: no pointer mapping, can't select window\n", 1814fb28925Smrg ProgramName); 1824fb28925Smrg Exit (1); 1834fb28925Smrg } 1844fb28925Smrg 1854fb28925Smrg if (button >= 0) { /* check button */ 1864fb28925Smrg for (j = 0; j < count; j++) { 1874fb28925Smrg if (ub == (unsigned int) pointer_map[j]) break; 1884fb28925Smrg } 1894fb28925Smrg if (j == count) { 1904fb28925Smrg fprintf (stderr, 1914fb28925Smrg "%s: no button number %u in pointer map, can't select window\n", 1924fb28925Smrg ProgramName, ub); 1934fb28925Smrg Exit (1); 1944fb28925Smrg } 1954fb28925Smrg } else { /* get first entry */ 1964fb28925Smrg button = (int) ((unsigned int) pointer_map[0]); 1974fb28925Smrg } 1984fb28925Smrg } 1994fb28925Smrg if ((id = get_window_id (dpy, screenno, button, 2004fb28925Smrg "the window whose client you wish to kill"))) { 2014fb28925Smrg if (id == RootWindow(dpy,screenno)) id = None; 2024fb28925Smrg else if (!top) { 2034fb28925Smrg XID indicated = id; 2044fb28925Smrg if ((id = XmuClientWindow(dpy, indicated)) == indicated) { 2054fb28925Smrg 2064fb28925Smrg /* Try not to kill the window manager when the user 2074fb28925Smrg * indicates an icon to xkill. 2084fb28925Smrg */ 2094fb28925Smrg 2104fb28925Smrg if (! wm_state_set(dpy, id) && wm_running(dpy, screenno)) 2114fb28925Smrg id = None; 2124fb28925Smrg 2134fb28925Smrg } 2144fb28925Smrg } 2154fb28925Smrg } 2164fb28925Smrg } 2174fb28925Smrg 2184fb28925Smrg if (id != None) { 2194fb28925Smrg printf ("%s: killing creator of resource 0x%lx\n", ProgramName, id); 2204fb28925Smrg XSync (dpy, 0); /* give xterm a chance */ 2214fb28925Smrg XKillClient (dpy, id); 2224fb28925Smrg XSync (dpy, 0); 2234fb28925Smrg } 2244fb28925Smrg 2254fb28925Smrg Exit (0); 2264fb28925Smrg /*NOTREACHED*/ 2274fb28925Smrg return 0; 2284fb28925Smrg} 2294fb28925Smrg 2304fb28925Smrgstatic int 2314fb28925Smrgparse_button(char *s, int *buttonp) 2324fb28925Smrg{ 2334fb28925Smrg register char *cp; 2344fb28925Smrg 2354fb28925Smrg /* lower case name */ 2364fb28925Smrg for (cp = s; *cp; cp++) { 2374fb28925Smrg if (isascii (*cp) && isupper (*cp)) { 2384fb28925Smrg#ifdef _tolower 2394fb28925Smrg *cp = _tolower (*cp); 2404fb28925Smrg#else 2414fb28925Smrg *cp = tolower (*cp); 2424fb28925Smrg#endif /* _tolower */ 2434fb28925Smrg } 2444fb28925Smrg } 2454fb28925Smrg 2464fb28925Smrg if (strcmp (s, "any") == 0) { 2474fb28925Smrg *buttonp = SelectButtonAny; 2484fb28925Smrg return (1); 2494fb28925Smrg } 2504fb28925Smrg 2514fb28925Smrg /* check for non-numeric input */ 2524fb28925Smrg for (cp = s; *cp; cp++) { 2534fb28925Smrg if (!(isascii (*cp) && isdigit (*cp))) return (0); /* bogus name */ 2544fb28925Smrg } 2554fb28925Smrg 2564fb28925Smrg *buttonp = atoi (s); 2574fb28925Smrg return (1); 2584fb28925Smrg} 2594fb28925Smrg 2604fb28925Smrg 2614fb28925Smrgstatic XID 2624fb28925Smrgparse_id(char *s) 2634fb28925Smrg{ 2644fb28925Smrg XID retval = None; 2654fb28925Smrg char *fmt = "%ld"; /* since XID is long */ 2664fb28925Smrg 2674fb28925Smrg if (s) { 2684fb28925Smrg if (*s == '0') s++, fmt = "%lo"; 2694fb28925Smrg if (*s == 'x' || *s == 'X') s++, fmt = "%lx"; 2704fb28925Smrg sscanf (s, fmt, &retval); 2714fb28925Smrg } 2724fb28925Smrg return (retval); 2734fb28925Smrg} 2744fb28925Smrg 2754fb28925Smrgstatic XID 2764fb28925Smrgget_window_id(Display *dpy, int screen, int button, char *msg) 2774fb28925Smrg{ 2784fb28925Smrg Cursor cursor; /* cursor to use when selecting */ 2794fb28925Smrg Window root; /* the current root */ 2804fb28925Smrg Window retwin = None; /* the window that got selected */ 2814fb28925Smrg int retbutton = -1; /* button used to select window */ 2824fb28925Smrg int pressed = 0; /* count of number of buttons pressed */ 2834fb28925Smrg 2844fb28925Smrg#define MASK (ButtonPressMask | ButtonReleaseMask) 2854fb28925Smrg 2864fb28925Smrg root = RootWindow (dpy, screen); 2874fb28925Smrg cursor = XCreateFontCursor (dpy, XC_pirate); 2884fb28925Smrg if (cursor == None) { 2894fb28925Smrg fprintf (stderr, "%s: unable to create selection cursor\n", 2904fb28925Smrg ProgramName); 2914fb28925Smrg Exit (1); 2924fb28925Smrg } 2934fb28925Smrg 2944fb28925Smrg printf ("Select %s with ", msg); 2954fb28925Smrg if (button == -1) 2964fb28925Smrg printf ("any button"); 2974fb28925Smrg else 2984fb28925Smrg printf ("button %d", button); 2994fb28925Smrg printf ("....\n"); 3004fb28925Smrg XSync (dpy, 0); /* give xterm a chance */ 3014fb28925Smrg 3024fb28925Smrg if (XGrabPointer (dpy, root, False, MASK, GrabModeSync, GrabModeAsync, 3034fb28925Smrg None, cursor, CurrentTime) != GrabSuccess) { 3044fb28925Smrg fprintf (stderr, "%s: unable to grab cursor\n", ProgramName); 3054fb28925Smrg Exit (1); 3064fb28925Smrg } 3074fb28925Smrg 3084fb28925Smrg /* from dsimple.c in xwininfo */ 3094fb28925Smrg while (retwin == None || pressed != 0) { 3104fb28925Smrg XEvent event; 3114fb28925Smrg 3124fb28925Smrg XAllowEvents (dpy, SyncPointer, CurrentTime); 3134fb28925Smrg XWindowEvent (dpy, root, MASK, &event); 3144fb28925Smrg switch (event.type) { 3154fb28925Smrg case ButtonPress: 3164fb28925Smrg if (retwin == None) { 3174fb28925Smrg retbutton = event.xbutton.button; 3184fb28925Smrg retwin = ((event.xbutton.subwindow != None) ? 3194fb28925Smrg event.xbutton.subwindow : root); 3204fb28925Smrg } 3214fb28925Smrg pressed++; 3224fb28925Smrg continue; 3234fb28925Smrg case ButtonRelease: 3244fb28925Smrg if (pressed > 0) pressed--; 3254fb28925Smrg continue; 3264fb28925Smrg } /* end switch */ 3274fb28925Smrg } /* end for */ 3284fb28925Smrg 3294fb28925Smrg XUngrabPointer (dpy, CurrentTime); 3304fb28925Smrg XFreeCursor (dpy, cursor); 3314fb28925Smrg XSync (dpy, 0); 3324fb28925Smrg 3334fb28925Smrg return ((button == -1 || retbutton == button) ? retwin : None); 3344fb28925Smrg} 3354fb28925Smrg 3364fb28925Smrg 3374fb28925Smrgstatic int 3384fb28925Smrgcatch_window_errors(Display *dpy, XErrorEvent *ev) 3394fb28925Smrg{ 3404fb28925Smrg return 0; 3414fb28925Smrg} 3424fb28925Smrg 3434fb28925Smrgstatic int 3444fb28925Smrgkill_all_windows(Display *dpy, int screenno, Bool top) 3454fb28925Smrg{ 3464fb28925Smrg Window root = RootWindow (dpy, screenno); 3474fb28925Smrg Window dummywindow; 3484fb28925Smrg Window *children; 3494fb28925Smrg unsigned int nchildren; 3504fb28925Smrg unsigned int i; 3514fb28925Smrg XWindowAttributes attr; 3524fb28925Smrg 3534fb28925Smrg XSync (dpy, 0); 3544fb28925Smrg XSetErrorHandler (catch_window_errors); 3554fb28925Smrg 3564fb28925Smrg nchildren = 0; 3574fb28925Smrg XQueryTree (dpy, root, &dummywindow, &dummywindow, &children, &nchildren); 3584fb28925Smrg if (!top) { 3594fb28925Smrg for (i = 0; i < nchildren; i++) { 3604fb28925Smrg if (XGetWindowAttributes(dpy, children[i], &attr) && 3614fb28925Smrg (attr.map_state == IsViewable)) 3624fb28925Smrg children[i] = XmuClientWindow(dpy, children[i]); 3634fb28925Smrg else 3644fb28925Smrg children[i] = 0; 3654fb28925Smrg } 3664fb28925Smrg } 3674fb28925Smrg for (i = 0; i < nchildren; i++) { 3684fb28925Smrg if (children[i]) 3694fb28925Smrg XKillClient (dpy, children[i]); 3704fb28925Smrg } 3714fb28925Smrg XFree ((char *)children); 3724fb28925Smrg 3734fb28925Smrg XSync (dpy, 0); 3744fb28925Smrg XSetErrorHandler (NULL); /* pretty stupid way to do things... */ 3754fb28925Smrg 3764fb28925Smrg return 0; 3774fb28925Smrg} 3784fb28925Smrg 3794fb28925Smrg/* 3804fb28925Smrg * ask the user to press in the root with each button in succession 3814fb28925Smrg */ 3824fb28925Smrgstatic int 3834fb28925Smrgverify_okay_to_kill(Display *dpy, int screenno) 3844fb28925Smrg{ 3854fb28925Smrg unsigned char pointer_map[256]; 3864fb28925Smrg int count = XGetPointerMapping (dpy, pointer_map, 256); 3874fb28925Smrg int i; 3884fb28925Smrg int button; 3894fb28925Smrg static char *msg = "the root window"; 3904fb28925Smrg Window root = RootWindow (dpy, screenno); 3914fb28925Smrg int okay = 0; 3924fb28925Smrg 3934fb28925Smrg for (i = 0; i < count; i++) { 3944fb28925Smrg button = (int) pointer_map[i]; 3954fb28925Smrg if (button == 0) continue; /* disabled */ 3964fb28925Smrg if (get_window_id (dpy, screenno, button, msg) != root) { 3974fb28925Smrg okay = 0; 3984fb28925Smrg break; 3994fb28925Smrg } 4004fb28925Smrg okay++; /* must have at least one button */ 4014fb28925Smrg } 4024fb28925Smrg if (okay) { 4034fb28925Smrg return 1; 4044fb28925Smrg } else { 4054fb28925Smrg printf ("Aborting.\n"); 4064fb28925Smrg return 0; 4074fb28925Smrg } 4084fb28925Smrg} 4094fb28925Smrg 4104fb28925Smrg/* Return True if the property WM_STATE is set on the window, otherwise 4114fb28925Smrg * return False. 4124fb28925Smrg */ 4134fb28925Smrgstatic Bool 4144fb28925Smrgwm_state_set(Display *dpy, Window win) 4154fb28925Smrg{ 4164fb28925Smrg Atom wm_state; 4174fb28925Smrg Atom actual_type; 4184fb28925Smrg int success; 4194fb28925Smrg int actual_format; 4204fb28925Smrg unsigned long nitems, remaining; 4214fb28925Smrg unsigned char* prop = NULL; 4224fb28925Smrg 4234fb28925Smrg wm_state = XInternAtom(dpy, "WM_STATE", True); 4244fb28925Smrg if (wm_state == None) return False; 4254fb28925Smrg success = XGetWindowProperty(dpy, win, wm_state, 0L, 0L, False, 4264fb28925Smrg AnyPropertyType, &actual_type, &actual_format, 4274fb28925Smrg &nitems, &remaining, &prop); 4284fb28925Smrg if (prop) XFree((char *) prop); 4294fb28925Smrg return (success == Success && actual_type != None && actual_format); 4304fb28925Smrg} 4314fb28925Smrg 4324fb28925Smrg/* Using a heuristic method, return True if a window manager is running, 4334fb28925Smrg * otherwise, return False. 4344fb28925Smrg */ 4354fb28925Smrg 4364fb28925Smrgstatic Bool 4374fb28925Smrgwm_running(Display *dpy, int screenno) 4384fb28925Smrg{ 4394fb28925Smrg XWindowAttributes xwa; 4404fb28925Smrg Status status; 4414fb28925Smrg 4424fb28925Smrg status = XGetWindowAttributes(dpy, RootWindow(dpy, screenno), &xwa); 4434fb28925Smrg return (status && 4444fb28925Smrg ((xwa.all_event_masks & SubstructureRedirectMask) || 4454fb28925Smrg (xwa.all_event_masks & SubstructureNotifyMask))); 4464fb28925Smrg} 447