[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