When redirect actions are used with Gtk3, Gtk3 complained about
events not holding a GdkDevice.  This was caused by device IDs
not being set for redirect actions.

More seriously, Gtk3 did not receive state changes redirect
actions might specify.  This was because event_set_state in
dix/inpututils.c accesses the prev_state field, but the changes
for the redirect action were only put into the state field.

Signed-off-by: Andreas Wettstein <wettstein...@solnet.ch>
---
 xkb/xkbActions.c |   28 +++++++++++++++++++++++-----
 1 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/xkb/xkbActions.c b/xkb/xkbActions.c
index da0bdea..891179b 100644
--- a/xkb/xkbActions.c
+++ b/xkb/xkbActions.c
@@ -795,7 +795,7 @@ _XkbFilterRedirectKey(      XkbSrvInfoPtr   xkbi,
 {
 DeviceEvent    ev;
 int            x,y;
-XkbStateRec    old;
+XkbStateRec    old, old_prev;
 unsigned       mods,mask;
 xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(xkbi->device);
 ProcessInputProc backupproc;
@@ -803,6 +803,7 @@ ProcessInputProc backupproc;
     /* never actually used uninitialised, but gcc isn't smart enough
      * to work that out. */
     memset(&old, 0, sizeof(old));
+    memset(&old_prev, 0, sizeof(old_prev));
     memset(&ev, 0, sizeof(ev));
 
     if ((filter->keycode!=0)&&(filter->keycode!=keycode))
@@ -814,6 +815,11 @@ ProcessInputProc backupproc;
     ev.time = GetTimeInMillis();
     ev.root_x = x;
     ev.root_y = y;
+    /* redirect actions do not work across devices, therefore the following is
+     * correct: */
+    ev.deviceid = xkbi->device->id;
+    /* filter->priv must be set up by the caller for the initial press. */
+    ev.sourceid = filter->priv;
 
     if (filter->keycode==0) {          /* initial press */
        if ((pAction->redirect.new_key<xkbi->desc->min_key_code)||
@@ -823,7 +829,6 @@ ProcessInputProc backupproc;
        filter->keycode = keycode;
        filter->active = 1;
        filter->filterOthers = 0;
-       filter->priv = 0;
        filter->filter = _XkbFilterRedirectKey;
        filter->upAction = *pAction;
 
@@ -839,6 +844,7 @@ ProcessInputProc backupproc;
 
        if ( mask || mods ) {
            old= xkbi->state;
+           old_prev= xkbi->prev_state;
            xkbi->state.base_mods&= ~mask;
            xkbi->state.base_mods|= (mods&mask);
            xkbi->state.latched_mods&= ~mask;
@@ -846,15 +852,18 @@ ProcessInputProc backupproc;
            xkbi->state.locked_mods&= ~mask;
            xkbi->state.locked_mods|= (mods&mask);
            XkbComputeDerivedState(xkbi);
+           xkbi->prev_state= xkbi->state;
        }
 
        UNWRAP_PROCESS_INPUT_PROC(xkbi->device,xkbPrivPtr, backupproc);
        xkbi->device->public.processInputProc((InternalEvent*)&ev, 
xkbi->device);
        COND_WRAP_PROCESS_INPUT_PROC(xkbi->device, xkbPrivPtr,
                                     backupproc,xkbUnwrapProc);
-       
-       if ( mask || mods )
+
+       if ( mask || mods ) {
            xkbi->state= old;
+           xkbi->prev_state= old_prev;
+       }
     }
     else if (filter->keycode==keycode) {
 
@@ -870,6 +879,7 @@ ProcessInputProc backupproc;
 
        if ( mask || mods ) {
            old= xkbi->state;
+           old_prev= xkbi->prev_state;
            xkbi->state.base_mods&= ~mask;
            xkbi->state.base_mods|= (mods&mask);
            xkbi->state.latched_mods&= ~mask;
@@ -877,6 +887,7 @@ ProcessInputProc backupproc;
            xkbi->state.locked_mods&= ~mask;
            xkbi->state.locked_mods|= (mods&mask);
            XkbComputeDerivedState(xkbi);
+           xkbi->prev_state= xkbi->state;
        }
 
        UNWRAP_PROCESS_INPUT_PROC(xkbi->device,xkbPrivPtr, backupproc);
@@ -884,8 +895,10 @@ ProcessInputProc backupproc;
        COND_WRAP_PROCESS_INPUT_PROC(xkbi->device, xkbPrivPtr,
                                     backupproc,xkbUnwrapProc);
 
-       if ( mask || mods )
+       if ( mask || mods ) {
            xkbi->state= old;
+           xkbi->prev_state= old_prev;
+       }
 
        filter->keycode= 0;
        filter->active= 0;
@@ -1155,6 +1168,11 @@ xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(dev);
                    break;
                case XkbSA_RedirectKey:
                    filter = _XkbNextFreeFilter(xkbi);
+                   /* redirect actions must create a new DeviceEvent.  The
+                    * source device id for this event cannot be obtained from
+                    * xkbi, so we pass it here explicitly. The field deviceid
+                    * equals to xkbi->device->id. */
+                   filter->priv = event->sourceid;
                    sendEvent= _XkbFilterRedirectKey(xkbi,filter,key,&act);
                    break;
                case XkbSA_DeviceBtn:
-- 
1.7.6

_______________________________________________
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

Reply via email to