On Wed, Dec 03, 2014 at 07:56:43PM -0800, Kyle Mills wrote:
> From 0903416a020ef8fe5ada9799a2c532433df3b520 Mon Sep 17 00:00:00 2001
> From: khonkhortisan <[email protected]>
> 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
> 

> _______________________________________________
> [email protected]: X.Org development
> Archives: http://lists.x.org/archives/xorg-devel
> Info: http://lists.x.org/mailman/listinfo/xorg-devel

_______________________________________________
[email protected]: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: http://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to