[gtk-vnc] Only trigger grab sequence upon release



commit af4fc65182f8a51d81fab2d7e46bc4a11a9da452
Author: Daniel P. Berrange <berrange redhat com>
Date:   Fri Sep 13 14:22:17 2013 +0100

    Only trigger grab sequence upon release
    
    GTK-VNC uses the keyboard shortcut ctrl+alt to toggle inside/outside
    the VM (aka release pointer). Now Gnome uses ctrl+alt+arrow_key to
    switch virtual desktops. So these two shortcuts collide and gtk-vnc
    will grab the key presses as soon as ctrl+alt is pressed and toogle
    inside/outside the VM, which makes switching desktops impossible.
    
    The solution is to only trigger the grab sequence when the user
    releases the key. So if they press Ctrl+alt and then release it,
    we trigger, but if they press Ctrl+alt+left-arrow we don't trigger
    
    https://bugzilla.gnome.org/show_bug.cgi?id=685257
    
    Signed-off-by: Daniel P. Berrange <berrange redhat com>

 src/vncdisplay.c |   50 +++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 41 insertions(+), 9 deletions(-)
---
diff --git a/src/vncdisplay.c b/src/vncdisplay.c
index 37de008..51a6b0f 100644
--- a/src/vncdisplay.c
+++ b/src/vncdisplay.c
@@ -80,6 +80,7 @@ struct _VncDisplayPrivate
     size_t keycode_maplen;
     const guint16 *keycode_map;
 
+    gboolean vncgrabpending; /* Key sequence detected, waiting for release */
     VncGrabSequence *vncgrabseq; /* the configured key sequence */
     gboolean *vncactiveseq; /* the currently pressed keys */
 };
@@ -784,6 +785,17 @@ static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion)
 }
 
 
+/*
+ * Lets say the grab sequence of Ctrl_L + Alt_L
+ *
+ * We first need to detect when both Ctrl_L and Alt_L are pressed.
+ * When this happens we are "primed" to tigger.
+ *
+ * If any further key is pressed though, we unprime ourselves
+ *
+ * If any key is released while we are primed, then we
+ * trigger.
+ */ 
 static gboolean check_for_grab_key(GtkWidget *widget, int type, int keyval)
 {
     VncDisplayPrivate *priv = VNC_DISPLAY(widget)->priv;
@@ -793,23 +805,42 @@ static gboolean check_for_grab_key(GtkWidget *widget, int type, int keyval)
         return FALSE;
 
     if (type == GDK_KEY_RELEASE) {
+        gboolean active = priv->vncgrabpending;
         /* Any key release resets the whole grab sequence */
         memset(priv->vncactiveseq, 0,
                sizeof(gboolean)*priv->vncgrabseq->nkeysyms);
-
-        return FALSE;
+        priv->vncgrabpending = FALSE;
+        return active;
     } else {
+        gboolean setone = FALSE;
+
         /* Record the new key press */
-        for (i = 0 ; i < priv->vncgrabseq->nkeysyms ; i++)
-            if (priv->vncgrabseq->keysyms[i] == keyval)
+        for (i = 0 ; i < priv->vncgrabseq->nkeysyms ; i++) {
+            if (priv->vncgrabseq->keysyms[i] == keyval) {
                 priv->vncactiveseq[i] = TRUE;
+                setone = TRUE;
+            }
+        }
 
-        /* Return if any key is not pressed */
-        for (i = 0 ; i < priv->vncgrabseq->nkeysyms ; i++)
-            if (priv->vncactiveseq[i] == FALSE)
-                return FALSE;
+        if (setone) {
+            /* Return if any key is not pressed */
+            for (i = 0 ; i < priv->vncgrabseq->nkeysyms ; i++)
+                if (priv->vncactiveseq[i] == FALSE)
+                    return FALSE;
 
-        return TRUE;
+            /* All keys in grab seq are pressed, so prime
+             * to trigger on release
+             */
+            priv->vncgrabpending = TRUE;
+        } else {
+            /* Key not in grab seq, so must reset any pending
+             * grab keys we have */
+            memset(priv->vncactiveseq, 0,
+                   sizeof(gboolean)*priv->vncgrabseq->nkeysyms);
+            priv->vncgrabpending = FALSE;
+        }
+
+        return FALSE;
     }
 }
 
@@ -2238,6 +2269,7 @@ void vnc_display_set_pointer_grab(VncDisplay *obj, gboolean enable)
  */
 void vnc_display_set_grab_keys(VncDisplay *obj, VncGrabSequence *seq)
 {
+    obj->priv->vncgrabpending = FALSE;
     if (obj->priv->vncgrabseq) {
         vnc_grab_sequence_free(obj->priv->vncgrabseq);
         g_free(obj->priv->vncactiveseq);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]