From 0903416a020ef8fe5ada9799a2c532433df3b520 Mon Sep 17 00:00:00 2001 From: khonkhortisan <khonkhorti...@gmail.com> Date: Sun, 30 Nov 2014 20:57:47 -0800 Subject: [PATCH xkill] Use secondary mouse pointers
--- configure.ac | 2 +- man/xkill.man | 8 +++- xkill.c | 130 +++++++++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 110 insertions(+), 30 deletions(-) diff --git a/configure.ac b/configure.ac index 6af4b04..32b68c0 100644 --- a/configure.ac +++ b/configure.ac @@ -38,7 +38,7 @@ XORG_MACROS_VERSION(1.8) XORG_DEFAULT_OPTIONS # Checks for pkg-config packages -PKG_CHECK_MODULES(XKILL, [x11 xmuu xproto >= 7.0.22]) +PKG_CHECK_MODULES(XKILL, [xi x11 xmuu xproto >= 7.0.22]) AC_CONFIG_FILES([ Makefile diff --git a/man/xkill.man b/man/xkill.man index 6cddc0a..23a2c4c 100644 --- a/man/xkill.man +++ b/man/xkill.man @@ -27,7 +27,7 @@ xkill - kill a client by its X resource .SH SYNOPSIS .B "xkill" -[\-display \fIdisplayname\fP] [\-id \fIresource\fP] [\-button number] [\-frame] [\-all] [\-version] +[\-display \fIdisplayname\fP] [\-id \fIresource\fP] [\-pointer id] [\-button number] [\-frame] [\-all] [\-version] .SH DESCRIPTION .PP .I Xkill @@ -48,6 +48,12 @@ 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 \-pointer \fIid\fP +This option specifies the id of a mouse pointer that may be used in +selecting a window to kill. This id must match the number given by xinput(1). +If the pointer is specified, any other pointers are ignored. +By default, every pointer is used. +.TP 8 .B \-button \fInumber\fP This option specifies the number of pointer button that should be used in selecting a window to kill. diff --git a/xkill.c b/xkill.c index 32cb0cc..1e6a26c 100644 --- a/xkill.c +++ b/xkill.c @@ -45,6 +45,7 @@ from The Open Group. #include <X11/Xos.h> #include <X11/Xlib.h> +#include <X11/extensions/XInput2.h> #include <X11/cursorfont.h> #include <X11/Xproto.h> @@ -52,11 +53,12 @@ from The Open Group. static char *ProgramName; +#define SelectPointerAny (-1) #define SelectButtonAny (-1) #define SelectButtonFirst (-2) static int parse_button ( char *s, int *buttonp ); -static XID get_window_id ( Display *dpy, int screen, int button, const char *msg ); +static XID get_window_id ( Display *dpy, int screen, int pointer_id, int button, const char *msg ); static int catch_window_errors ( Display *dpy, XErrorEvent *ev ); static int kill_all_windows ( Display *dpy, int screenno, Bool top ); static int verify_okay_to_kill ( Display *dpy, int screenno ); @@ -80,6 +82,7 @@ usage(const char *errmsg) " -display displayname X server to contact\n" " -id resource resource whose client is to be killed\n" " -frame don't ignore window manager frames\n" +" -pointer id specific mouse pointer to use for killing a window\n" " -button number specific button to be pressed to select window\n" " -all kill all clients with top level windows\n" " -version print version and exit\n" @@ -101,12 +104,14 @@ main(int argc, char *argv[]) char *displayname = NULL; /* name of server to contact */ int screenno; /* screen number of dpy */ XID id = None; /* resource to kill */ + int pointer_id; /* number of mouse pointer to grab */ 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]; + pointer_id = SelectPointerAny; button = SelectButtonFirst; for (i = 1; i < argc; i++) { @@ -127,6 +132,10 @@ main(int argc, char *argv[]) Exit (1, dpy); } continue; + case 'p': + if (++i >= argc) usage ("-pointer requires an argument"); + pointer_id = strtoul (argv[i], NULL, 0); + continue; case 'b': /* -button number */ if (++i >= argc) usage ("-button requires an argument"); button_name = argv[i]; @@ -208,7 +217,7 @@ main(int argc, char *argv[]) button = (int) ((unsigned int) pointer_map[0]); } } - if ((id = get_window_id (dpy, screenno, button, + if ((id = get_window_id (dpy, screenno, pointer_id, button, "the window whose client you wish to kill"))) { if (id == RootWindow(dpy,screenno)) id = None; else if (!top) { @@ -270,15 +279,18 @@ parse_button(char *s, int *buttonp) } static XID -get_window_id(Display *dpy, int screen, int button, const char *msg) +get_window_id(Display *dpy, int screen, int pointer_id, int button, const 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) + int xi_opcode, xi_event, xi_error, major, minor, rc; + XIEventMask eventmask; /* event filter */ + unsigned char mask[1]; /* the actual mask */ + XIDeviceInfo *devices, *device; + int i, ndevices; root = RootWindow (dpy, screen); cursor = XCreateFontCursor (dpy, XC_pirate); @@ -288,6 +300,64 @@ get_window_id(Display *dpy, int screen, int button, const char *msg) Exit (1, dpy); } + /* initialize XI2 */ + if (!XQueryExtension(dpy, "XInputExtension", &xi_opcode, &xi_event, &xi_error)) { + fprintf(stderr, "X Input extension not available.\n"); + Exit (1, dpy); + } + + /* We support XI 2.0 */ + major = 2; + minor = 0; + + rc = XIQueryVersion(dpy, &major, &minor); + if (rc == BadRequest) { + fprintf(stderr, "No XI2 support. Server supports version %d.%d only.\n", major, minor); + Exit (1, dpy); + } + else if (rc != Success) { + fprintf(stderr, "Internal Error! This is a bug in Xlib.\n"); + } + + printf("XI2 supported. Server provides version %d.%d.\n", major, minor); + + /* Filter events */ + mask[0] = 0; + + eventmask.deviceid = 2; + eventmask.mask_len = sizeof(mask); /* always in bytes */ + eventmask.mask = mask; + /* now set the mask */ + XISetMask(mask, XI_ButtonPress); + XISetMask(mask, XI_ButtonRelease); + + /* select on the window */ + XISelectEvents(dpy, root, &eventmask, 1); + + /* grab mouse pointer(s) */ + devices = XIQueryDevice(dpy, + (pointer_id == SelectPointerAny) ? XIAllMasterDevices : pointer_id, + &ndevices); + + for (i = 0; i < ndevices; i++) { + device = &devices[i]; + if (device->use == XIMasterPointer) { + if ((rc = XIGrabDevice (dpy, device->deviceid, root, CurrentTime, cursor, GrabModeAsync, GrabModeAsync, False, &eventmask)) != GrabSuccess) { + fprintf(stderr, "%s: Grabbing pointer (id=%i) failed with %d\n", ProgramName, device->deviceid, rc); + Exit (1, dpy); + } + else { + printf("Grabbed pointer (id=%i)\n", device->deviceid); + } + XFlush(dpy); + } + else if (pointer_id != SelectPointerAny) { + fprintf(stderr, "%s: Not a master pointer device (id=%i)\n", ProgramName, pointer_id); + Exit (1, dpy); + } + } + XIFreeDeviceInfo(devices); + printf ("Select %s with ", msg); if (button == -1) printf ("any button"); @@ -296,34 +366,38 @@ get_window_id(Display *dpy, int screen, int button, const char *msg) 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, dpy); - } - /* from dsimple.c in xwininfo */ while (retwin == None || pressed != 0) { XEvent event; + XGenericEventCookie *cookie = &event.xcookie; - 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--; + XNextEvent(dpy, &event); + + if (cookie->type != GenericEvent || + cookie->extension != xi_opcode) continue; - } /* end switch */ - } /* end for */ - XUngrabPointer (dpy, CurrentTime); + if (XGetEventData(dpy, cookie)) + { + XIDeviceEvent *devev = cookie->data; + switch (devev->evtype) + { + case XI_ButtonPress: + if (retwin == None) { + retbutton = devev->detail; + retwin = ((devev->child != None) ? + devev->child : root); + } + pressed++; + continue; + case XI_ButtonRelease: + if (pressed > 0) pressed--; + continue; + } /* end switch */ + XFreeEventData(dpy, &event.xcookie); + } + } /* end while */ + XFreeCursor (dpy, cursor); XSync (dpy, 0); @@ -390,7 +464,7 @@ verify_okay_to_kill(Display *dpy, int screenno) 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) { + if (get_window_id (dpy, screenno, SelectPointerAny, button, msg) != root) { okay = 0; break; } -- 2.1.3
_______________________________________________ xorg-devel@lists.x.org: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel