summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaleb Keithley <kaleb@freedesktop.org>2003-11-14 15:54:54 +0000
committerKaleb Keithley <kaleb@freedesktop.org>2003-11-14 15:54:54 +0000
commit856b88d175fe3399a0fd34a4531931061eb8a309 (patch)
tree9e3fbe953456acd473e4b6e674d771139a793524
R6.6 is the Xorg base-lineXORG-MAINXORG-STABLE
-rw-r--r--xkill.c447
-rw-r--r--xkill.man80
2 files changed, 527 insertions, 0 deletions
diff --git a/xkill.c b/xkill.c
new file mode 100644
index 0000000..816f3e8
--- /dev/null
+++ b/xkill.c
@@ -0,0 +1,447 @@
+/* $Xorg: xkill.c,v 1.5 2001/02/09 02:05:54 xorgcvs Exp $ */
+/*
+
+Copyright 1988, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+*/
+
+/*
+ * xkill - simple program for destroying unwanted clients
+ * Author: Jim Fulton, MIT X Consortium; Dana Chee, Bellcore
+ */
+
+/*
+ * Warning, this is a very dangerous client....
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include <X11/Xos.h>
+#include <X11/Xlib.h>
+#include <X11/cursorfont.h>
+#include <X11/Xproto.h>
+
+#include <X11/Xmu/WinUtil.h>
+
+Display *dpy = NULL;
+char *ProgramName;
+
+#define SelectButtonAny (-1)
+#define SelectButtonFirst (-2)
+
+XID parse_id(), get_window_id();
+int parse_button(), verify_okay_to_kill();
+
+Exit (code)
+ int code;
+{
+ if (dpy) {
+ XCloseDisplay (dpy);
+ }
+ exit (code);
+}
+
+usage ()
+{
+ static char *options[] = {
+"where options include:",
+" -display displayname X server to contact",
+" -id resource resource whose client is to be killed",
+" -frame don't ignore window manager frames",
+" -button number specific button to be pressed to select window",
+" -all kill all clients with top level windows",
+"",
+NULL};
+ char **cpp;
+
+ fprintf (stderr, "usage: %s [-option ...]\n",
+ ProgramName);
+ for (cpp = options; *cpp; cpp++) {
+ fprintf (stderr, "%s\n", *cpp);
+ }
+ Exit (1);
+}
+
+main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ int i; /* iterator, temp variable */
+ char *displayname = NULL; /* name of server to contact */
+ int screenno; /* screen number of dpy */
+ XID id = None; /* resource to kill */
+ char *button_name = NULL; /* name of button for window select */
+ int button; /* button number or negative for all */
+ Bool kill_all = False;
+ Bool top = False;
+
+ ProgramName = argv[0];
+
+ for (i = 1; i < argc; i++) {
+ char *arg = argv[i];
+
+ if (arg[0] == '-') {
+ switch (arg[1]) {
+ case 'd': /* -display displayname */
+ if (++i >= argc) usage ();
+ displayname = argv[i];
+ continue;
+ case 'i': /* -id resourceid */
+ if (++i >= argc) usage ();
+ id = parse_id (argv[i]);
+ continue;
+ case 'b': /* -button number */
+ if (++i >= argc) usage ();
+ button_name = argv[i];
+ continue;
+ case 'f': /* -frame */
+ top = True;
+ continue;
+ case 'a': /* -all */
+ kill_all = True;
+ continue;
+ default:
+ usage ();
+ }
+ } else {
+ usage ();
+ }
+ } /* end for */
+
+ dpy = XOpenDisplay (displayname);
+ if (!dpy) {
+ fprintf (stderr, "%s: unable to open display \"%s\"\n",
+ ProgramName, XDisplayName (displayname));
+ Exit (1);
+ }
+ screenno = DefaultScreen (dpy);
+
+ if (kill_all) {
+ if (verify_okay_to_kill (dpy, screenno))
+ kill_all_windows (dpy, screenno, top);
+ Exit (0);
+ }
+
+ /*
+ * if no id was given, we need to choose a window
+ */
+
+ if (id == None) {
+ if (!button_name)
+ button_name = XGetDefault (dpy, ProgramName, "Button");
+
+ if (!button_name)
+ button = SelectButtonFirst;
+ else if (!parse_button (button_name, &button)) {
+ fprintf (stderr, "%s: invalid button specification \"%s\"\n",
+ ProgramName, button_name);
+ Exit (1);
+ }
+
+ if (button >= 0 || button == SelectButtonFirst) {
+ unsigned char pointer_map[256]; /* 8 bits of pointer num */
+ int count, j;
+ unsigned int ub = (unsigned int) button;
+
+
+ count = XGetPointerMapping (dpy, pointer_map, 256);
+ if (count <= 0) {
+ fprintf (stderr,
+ "%s: no pointer mapping, can't select window\n",
+ ProgramName);
+ Exit (1);
+ }
+
+ if (button >= 0) { /* check button */
+ for (j = 0; j < count; j++) {
+ if (ub == (unsigned int) pointer_map[j]) break;
+ }
+ if (j == count) {
+ fprintf (stderr,
+ "%s: no button number %u in pointer map, can't select window\n",
+ ProgramName, ub);
+ Exit (1);
+ }
+ } else { /* get first entry */
+ button = (int) ((unsigned int) pointer_map[0]);
+ }
+ }
+ if ((id = get_window_id (dpy, screenno, button,
+ "the window whose client you wish to kill"))) {
+ if (id == RootWindow(dpy,screenno)) id = None;
+ else if (!top) {
+ XID indicated = id;
+ if ((id = XmuClientWindow(dpy, indicated)) == indicated) {
+
+ /* Try not to kill the window manager when the user
+ * indicates an icon to xkill.
+ */
+
+ if (! wm_state_set(dpy, id) && wm_running(dpy, screenno))
+ id = None;
+
+ }
+ }
+ }
+ }
+
+ if (id != None) {
+ printf ("%s: killing creator of resource 0x%lx\n", ProgramName, id);
+ XSync (dpy, 0); /* give xterm a chance */
+ XKillClient (dpy, id);
+ XSync (dpy, 0);
+ }
+
+ Exit (0);
+}
+
+int parse_button (s, buttonp)
+ register char *s;
+ int *buttonp;
+{
+ register char *cp;
+
+ /* lower case name */
+ for (cp = s; *cp; cp++) {
+ if (isascii (*cp) && isupper (*cp)) {
+#ifdef _tolower
+ *cp = _tolower (*cp);
+#else
+ *cp = tolower (*cp);
+#endif /* _tolower */
+ }
+ }
+
+ if (strcmp (s, "any") == 0) {
+ *buttonp = SelectButtonAny;
+ return (1);
+ }
+
+ /* check for non-numeric input */
+ for (cp = s; *cp; cp++) {
+ if (!(isascii (*cp) && isdigit (*cp))) return (0); /* bogus name */
+ }
+
+ *buttonp = atoi (s);
+ return (1);
+}
+
+
+XID parse_id (s)
+ char *s;
+{
+ XID retval = None;
+ char *fmt = "%ld"; /* since XID is long */
+
+ if (s) {
+ if (*s == '0') s++, fmt = "%lo";
+ if (*s == 'x' || *s == 'X') s++, fmt = "%lx";
+ sscanf (s, fmt, &retval);
+ }
+ return (retval);
+}
+
+XID get_window_id (dpy, screen, button, msg)
+ Display *dpy;
+ int screen;
+ int button;
+ char *msg;
+{
+ Cursor cursor; /* cursor to use when selecting */
+ Window root; /* the current root */
+ Window retwin = None; /* the window that got selected */
+ int retbutton = -1; /* button used to select window */
+ int pressed = 0; /* count of number of buttons pressed */
+
+#define MASK (ButtonPressMask | ButtonReleaseMask)
+
+ root = RootWindow (dpy, screen);
+ cursor = XCreateFontCursor (dpy, XC_draped_box);
+ if (cursor == None) {
+ fprintf (stderr, "%s: unable to create selection cursor\n",
+ ProgramName);
+ Exit (1);
+ }
+
+ printf ("Select %s with ", msg);
+ if (button == -1)
+ printf ("any button");
+ else
+ printf ("button %d", button);
+ printf ("....\n");
+ XSync (dpy, 0); /* give xterm a chance */
+
+ if (XGrabPointer (dpy, root, False, MASK, GrabModeSync, GrabModeAsync,
+ None, cursor, CurrentTime) != GrabSuccess) {
+ fprintf (stderr, "%s: unable to grab cursor\n", ProgramName);
+ Exit (1);
+ }
+
+ /* from dsimple.c in xwininfo */
+ while (retwin == None || pressed != 0) {
+ XEvent event;
+
+ XAllowEvents (dpy, SyncPointer, CurrentTime);
+ XWindowEvent (dpy, root, MASK, &event);
+ switch (event.type) {
+ case ButtonPress:
+ if (retwin == None) {
+ retbutton = event.xbutton.button;
+ retwin = ((event.xbutton.subwindow != None) ?
+ event.xbutton.subwindow : root);
+ }
+ pressed++;
+ continue;
+ case ButtonRelease:
+ if (pressed > 0) pressed--;
+ continue;
+ } /* end switch */
+ } /* end for */
+
+ XUngrabPointer (dpy, CurrentTime);
+ XFreeCursor (dpy, cursor);
+ XSync (dpy, 0);
+
+ return ((button == -1 || retbutton == button) ? retwin : None);
+}
+
+
+int catch_window_errors (dpy, ev)
+ Display *dpy;
+ XErrorEvent *ev;
+{
+ return 0;
+}
+
+int kill_all_windows (dpy, screenno, top)
+ Display *dpy;
+ int screenno;
+ Bool top;
+{
+ Window root = RootWindow (dpy, screenno);
+ Window dummywindow;
+ Window *children;
+ unsigned int nchildren;
+ unsigned int i;
+ XWindowAttributes attr;
+
+ XSync (dpy, 0);
+ XSetErrorHandler (catch_window_errors);
+
+ nchildren = 0;
+ XQueryTree (dpy, root, &dummywindow, &dummywindow, &children, &nchildren);
+ if (!top) {
+ for (i = 0; i < nchildren; i++) {
+ if (XGetWindowAttributes(dpy, children[i], &attr) &&
+ (attr.map_state == IsViewable))
+ children[i] = XmuClientWindow(dpy, children[i]);
+ else
+ children[i] = 0;
+ }
+ }
+ for (i = 0; i < nchildren; i++) {
+ if (children[i])
+ XKillClient (dpy, children[i]);
+ }
+ XFree ((char *)children);
+
+ XSync (dpy, 0);
+ XSetErrorHandler (NULL); /* pretty stupid way to do things... */
+
+ return 0;
+}
+
+/*
+ * ask the user to press in the root with each button in succession
+ */
+int verify_okay_to_kill (dpy, screenno)
+ Display *dpy;
+ int screenno;
+{
+ unsigned char pointer_map[256];
+ int count = XGetPointerMapping (dpy, pointer_map, 256);
+ int i;
+ int button;
+ static char *msg = "the root window";
+ Window root = RootWindow (dpy, screenno);
+ int okay = 0;
+
+ for (i = 0; i < count; i++) {
+ button = (int) pointer_map[i];
+ if (button == 0) continue; /* disabled */
+ if (get_window_id (dpy, screenno, button, msg) != root) {
+ okay = 0;
+ break;
+ }
+ okay++; /* must have at least one button */
+ }
+ if (okay) {
+ return 1;
+ } else {
+ printf ("Aborting.\n");
+ return 0;
+ }
+}
+
+/* Return True if the property WM_STATE is set on the window, otherwise
+ * return False.
+ */
+Bool wm_state_set(dpy, win)
+Display *dpy;
+Window win;
+{
+ Atom wm_state;
+ Atom actual_type;
+ int success;
+ int actual_format;
+ unsigned long nitems, remaining;
+ unsigned char* prop = NULL;
+
+ wm_state = XInternAtom(dpy, "WM_STATE", True);
+ if (wm_state == None) return False;
+ success = XGetWindowProperty(dpy, win, wm_state, 0L, 0L, False,
+ AnyPropertyType, &actual_type, &actual_format,
+ &nitems, &remaining, &prop);
+ if (prop) XFree((char *) prop);
+ return (success == Success && actual_type != None && actual_format);
+}
+
+/* Using a heuristic method, return True if a window manager is running,
+ * otherwise, return False.
+ */
+
+Bool wm_running(dpy, screenno)
+Display *dpy;
+int screenno;
+{
+ XWindowAttributes xwa;
+ Status status;
+
+ status = XGetWindowAttributes(dpy, RootWindow(dpy, screenno), &xwa);
+ return (status &&
+ ((xwa.all_event_masks & SubstructureRedirectMask) ||
+ (xwa.all_event_masks & SubstructureNotifyMask)));
+}
diff --git a/xkill.man b/xkill.man
new file mode 100644
index 0000000..015eb7d
--- /dev/null
+++ b/xkill.man
@@ -0,0 +1,80 @@
+.\" $Xorg: xkill.man,v 1.4 2001/02/09 02:05:54 xorgcvs Exp $
+.\" Copyright 1988, 1998 The Open Group
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and its
+.\" documentation for any purpose is hereby granted without fee, provided that
+.\" the above copyright notice appear in all copies and that both that
+.\" copyright notice and this permission notice appear in supporting
+.\" documentation.
+.\"
+.\" The above copyright notice and this permission notice shall be included
+.\" in all copies or substantial portions of the Software.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+.\" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+.\" IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+.\" OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+.\" ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+.\" OTHER DEALINGS IN THE SOFTWARE.
+.\"
+.\" Except as contained in this notice, the name of The Open Group shall
+.\" not be used in advertising or otherwise to promote the sale, use or
+.\" other dealings in this Software without prior written authorization
+.\" from The Open Group.
+.TH XKILL 1 "Release 6.4" "X Version 11"
+.SH NAME
+xkill - kill a client by its X resource
+.SH SYNOPSIS
+.B "xkill"
+[\-display \fIdisplayname\fP] [\-id \fIresource\fP] [\-button number] [\-frame] [\-all]
+.SH DESCRIPTION
+.PP
+.I Xkill
+is a utility for forcing the X server to close connections to clients. This
+program is very dangerous, but is useful for aborting programs that have
+displayed undesired windows on a user's screen. If no resource identifier
+is given with \fI-id\fP, \fIxkill\fP will display a special cursor
+as a prompt for the user to select a window to be killed. If a pointer button
+is pressed over a non-root window, the server will close its connection to
+the client that created the window.
+.SH OPTIONS
+.TP 8
+.B \-display \fIdisplayname\fP
+This option specifies the name of the X server to contact.
+.TP 8
+.B \-id \fIresource\fP
+This option specifies the X identifier for the resource whose creator is
+to be aborted. If no resource is specified, \fIxkill\fP will display a
+special cursor with which you should select a window to be kill.
+.TP 8
+.B \-button \fInumber\fP
+This option specifies the number of pointer button
+that should be used in selecting a window to kill.
+If the word "any" is specified, any button on the pointer may be used. By
+default, the first button in the pointer map (which is usually the leftmost
+button) is used.
+.TP 8
+.B \-all
+This option indicates that all clients with top-level windows on the screen
+should be killed. \fIXkill\fP will ask you to select the root window with
+each of the currently defined buttons to give you several chances to abort.
+Use of this option is highly discouraged.
+.TP 8
+.B \-frame
+This option indicates that xkill should ignore the standard conventions for
+finding top-level client windows (which are typically nested inside a window
+manager window), and simply believe that you want to kill direct children of
+the root.
+.SH XDEFAULTS
+.TP 8
+.B Button
+Specifies a specific pointer button number or the word "any" to use when
+selecting windows.
+.SH "SEE ALSO"
+X(1), xwininfo(1), XKillClient and XGetPointerMapping in the Xlib Programmers
+Manual, KillClient in the X Protocol Specification
+.SH AUTHOR
+Jim Fulton, MIT X Consortium
+.br
+Dana Chee, Bellcore