[PATCH xkill] Use secondary mouse pointers
Peter Hutterer
peter.hutterer at who-t.net
Wed Dec 3 23:12:23 PST 2014
On Wed, Dec 03, 2014 at 07:56:43PM -0800, Kyle Mills wrote:
> From 0903416a020ef8fe5ada9799a2c532433df3b520 Mon Sep 17 00:00:00 2001
> From: khonkhortisan <khonkhortisan at gmail.com>
> Date: Sun, 30 Nov 2014 20:57:47 -0800
> Subject: [PATCH xkill] Use secondary mouse pointers
I am honestly wondering: why?
Cheers,
Peter
> ---
> 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 at lists.x.org: X.Org development
> Archives: http://lists.x.org/archives/xorg-devel
> Info: http://lists.x.org/mailman/listinfo/xorg-devel
More information about the xorg-devel
mailing list