[gtk-vnc-devel] PATCH: make keyboard & pointer grabs configurable



The current code will automatically grab the pointer & keyboard whenever
the pointer is in relative mode. This is not sufficient, because even in
absolute mode, you may still wish to grab the pointer if the remote server
is translating absolute -> relative. Second, you may wish to grab the 
keyboard regardless of whether you are doing pointer grab, because this
lets you block window manager short cuts in the host. 

So this patch adds two options.

  - A pointer grab flag - if this is set, then the pointer will always be
    grabbed upon first click, regardless of mouse mode

  - A keyboard grabb flag - if this is set, then the keyboard will always
    be grabbed upon mouse enter, an ungrabed on mouse leave.

If also adds signals to be emitted when these events occur, so the controlling
app can notify the user in some way. In the example gvncviewer client I use
this to add 'Press Ctrl+Alt to release pointer' to the title bar.

Dan.
-- 
|=- Red Hat, Engineering, Emerging Technologies, Boston.  +1 978 392 2496 -=|
|=-           Perl modules: http://search.cpan.org/~danberr/              -=|
|=-               Projects: http://freshmeat.net/~danielpb/               -=|
|=-  GnuPG: 7D3B9505   F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505  -=| 
changeset:   25:f0724efc82b7
user:        "Daniel P. Berrange <berrange redhat com>"
date:        Fri Jul 06 10:57:07 2007 -0400
summary:     Make keyboard & pointer grab configurable

diff -r 725c05c132d2 -r f0724efc82b7 examples/gvncviewer.c
--- a/examples/gvncviewer.c	Thu Jul 05 16:43:33 2007 -0400
+++ b/examples/gvncviewer.c	Fri Jul 06 10:57:07 2007 -0400
@@ -33,6 +33,18 @@ void vnc_initialized(GtkWidget *vnc)
 	printf("VNC widget initialized\n");
 	gtk_widget_show_all(GTK_WIDGET(window));
 }
+
+void vnc_grab(GtkWidget *vnc)
+{
+        gtk_window_set_title(GTK_WINDOW(window), "Press Ctrl+Alt to release pointer. GVncViewer");
+}
+
+
+void vnc_ungrab(GtkWidget *vnc)
+{
+        gtk_window_set_title(GTK_WINDOW(window), "GVncViewer");
+}
+
 
 void vnc_credential(GtkWidget *vnc, int cred)
 {
@@ -109,6 +121,8 @@ int main(int argc, char **argv)
 	if (argc == 4)
 		vnc_display_set_credential(VNC_DISPLAY(vnc), VNC_DISPLAY_CREDENTIAL_PASSWORD, argv[3]);
 
+	vnc_display_set_keyboard_grab(VNC_DISPLAY(vnc), TRUE);
+	vnc_display_set_pointer_grab(VNC_DISPLAY(vnc), TRUE);
 	vnc_display_open_name(VNC_DISPLAY(vnc), argv[1], argv[2]);
 
 	gtk_signal_connect(GTK_OBJECT(window), "delete-event",
@@ -123,6 +137,12 @@ int main(int argc, char **argv)
 	gtk_signal_connect(GTK_OBJECT(vnc), "vnc-auth-credential",
 			   GTK_SIGNAL_FUNC(vnc_credential), NULL);
 
+        gtk_signal_connect(GTK_OBJECT(vnc), "vnc-pointer-grab",
+                           GTK_SIGNAL_FUNC(vnc_grab), NULL);
+
+        gtk_signal_connect(GTK_OBJECT(vnc), "vnc-pointer-ungrab",
+                           GTK_SIGNAL_FUNC(vnc_ungrab), NULL);
+
 	gtk_signal_connect(GTK_OBJECT(window), "key-press-event",
 			   GTK_SIGNAL_FUNC(vnc_screenshot), NULL);
 
diff -r 725c05c132d2 -r f0724efc82b7 examples/gvncviewer.py
--- a/examples/gvncviewer.py	Thu Jul 05 16:43:33 2007 -0400
+++ b/examples/gvncviewer.py	Fri Jul 06 10:57:07 2007 -0400
@@ -18,6 +18,13 @@ def vnc_keypress(src, ev):
         pix.save("gvncviewer.png", "png", { "tEXt::Generator App": "gvncviewer.py" })
         print "Screenshot saved to gvncviewer.png"
     return False
+
+def vnc_grab(src):
+    w.set_title("Press Ctrl+Alt to release pointer. GVncViewer")
+
+def vnc_ungrab(src):
+    w.set_title("GVncViewer")
+
 
 def vnc_disconnect(src):
     print "VNC disconnected"
@@ -60,6 +67,8 @@ def vnc_credential(src, type):
 
 w.add(v)
 v.realize()
+v.set_pointer_grab(True)
+v.set_keyboard_grab(True)
 
 if len(sys.argv) == 4:
     v.set_credential(gtkvnc.CREDENTIAL_PASSWORD, sys.argv[3])
@@ -68,6 +77,8 @@ v.connect("vnc-disconnected", vnc_discon
 v.connect("vnc-disconnected", vnc_disconnect)
 v.connect("vnc-initialized", vnc_initialize)
 v.connect("vnc-auth-credential", vnc_credential)
+v.connect("vnc-pointer-grab", vnc_grab)
+v.connect("vnc-pointer-ungrab", vnc_ungrab)
 w.connect("key-press-event", vnc_keypress)
 w.connect("delete-event", gtk.main_quit)
 
diff -r 725c05c132d2 -r f0724efc82b7 src/libgtk-vnc_sym.version
--- a/src/libgtk-vnc_sym.version	Thu Jul 05 16:43:33 2007 -0400
+++ b/src/libgtk-vnc_sym.version	Fri Jul 06 10:57:07 2007 -0400
@@ -15,6 +15,9 @@
     vnc_display_get_pixbuf;
 
     vnc_display_set_use_shm;
+    vnc_display_set_pointer_grab;
+    vnc_display_set_keyboard_grab;
+
     vnc_display_get_width;
     vnc_display_get_height;
     vnc_display_get_host_name;
diff -r 725c05c132d2 -r f0724efc82b7 src/vncdisplay.c
--- a/src/vncdisplay.c	Thu Jul 05 16:43:33 2007 -0400
+++ b/src/vncdisplay.c	Fri Jul 06 10:57:07 2007 -0400
@@ -36,28 +36,38 @@ struct _VncDisplayPrivate
 	struct coroutine coroutine;
 	struct gvnc *gvnc;
 
-	int in_grab;
+	gboolean in_pointer_grab;
+	gboolean in_keyboard_grab;
 
 	int button_mask;
 	int last_x;
 	int last_y;
 
-	int absolute;
-
-	int use_shm;
+	gboolean absolute;
+
+	gboolean use_shm;
+	gboolean grab_pointer;
+	gboolean grab_keyboard;
 };
 
 /* Signals */
 enum
 {
+	VNC_POINTER_GRAB,
+	VNC_POINTER_UNGRAB,
+	VNC_KEYBOARD_GRAB,
+	VNC_KEYBOARD_UNGRAB,
+
 	VNC_CONNECTED,
 	VNC_INITIALIZED,
 	VNC_DISCONNECTED,
 	VNC_AUTH_CREDENTIAL,
+
 	LAST_SIGNAL
 };
 
-static guint signals[LAST_SIGNAL] = { 0, 0, 0, 0 };
+static guint signals[LAST_SIGNAL] = { 0, 0, 0, 0,
+				      0, 0, 0, 0 };
 
 GtkWidget *vnc_display_new(void)
 {
@@ -104,42 +114,64 @@ static gboolean expose_event(GtkWidget *
 	return TRUE;
 }
 
-static void toggle_grab(VncDisplay *obj)
-{
-	VncDisplayPrivate *priv = obj->priv;
-	VncDisplayClass *klass = VNC_DISPLAY_GET_CLASS(obj);
-
-	if (priv->in_grab) {
-		priv->in_grab = 0;
-		gdk_keyboard_ungrab(GDK_CURRENT_TIME);
-		gdk_pointer_ungrab(GDK_CURRENT_TIME);
-		if (priv->absolute)
-			gdk_window_set_cursor(GTK_WIDGET(obj)->window,
-					      priv->null_cursor);
-		else
-			gdk_window_set_cursor(GTK_WIDGET(obj)->window,
-					      NULL);
-		priv->last_x = -1;
-		priv->last_y = -1;
-		g_signal_emit(obj, klass->leave_grab_event_id, 0);
-	} else {
-		priv->in_grab = 1;
-		gdk_keyboard_grab(GTK_WIDGET(obj)->window,
-				  FALSE,
-				  GDK_CURRENT_TIME);
-		gdk_pointer_grab(GTK_WIDGET(obj)->window,
-				 TRUE,
-				 GDK_POINTER_MOTION_MASK |
-				 GDK_BUTTON_PRESS_MASK |
-				 GDK_BUTTON_RELEASE_MASK |
-				 GDK_BUTTON_MOTION_MASK |
-				 GDK_SCROLL_MASK,
-				 NULL,
-				 priv->null_cursor,
-				 GDK_CURRENT_TIME);
-		g_signal_emit(obj, klass->enter_grab_event_id, 0);
-	}
-}
+static void do_keyboard_grab(VncDisplay *obj)
+{
+	VncDisplayPrivate *priv = obj->priv;
+
+	gdk_keyboard_grab(GTK_WIDGET(obj)->window,
+			  FALSE,
+			  GDK_CURRENT_TIME);
+	priv->in_keyboard_grab = TRUE;
+	g_signal_emit(obj, signals[VNC_KEYBOARD_GRAB], 0);
+}
+
+
+static void do_keyboard_ungrab(VncDisplay *obj)
+{
+	VncDisplayPrivate *priv = obj->priv;
+
+	gdk_keyboard_ungrab(GDK_CURRENT_TIME);
+	priv->in_keyboard_grab = FALSE;
+	g_signal_emit(obj, signals[VNC_KEYBOARD_UNGRAB], 0);
+}
+
+
+static void do_pointer_grab(VncDisplay *obj)
+{
+	VncDisplayPrivate *priv = obj->priv;
+
+	/* If we're not already grabbing keyboard, grab it now */
+	if (!priv->grab_keyboard)
+		do_keyboard_grab(obj);
+
+	gdk_pointer_grab(GTK_WIDGET(obj)->window,
+			 TRUE,
+			 GDK_POINTER_MOTION_MASK |
+			 GDK_BUTTON_PRESS_MASK |
+			 GDK_BUTTON_RELEASE_MASK |
+			 GDK_BUTTON_MOTION_MASK |
+			 GDK_SCROLL_MASK,
+			 GTK_WIDGET(obj)->window,
+			 priv->null_cursor,
+			 GDK_CURRENT_TIME);
+	priv->in_pointer_grab = TRUE;
+	g_signal_emit(obj, signals[VNC_POINTER_GRAB], 0);
+}
+
+static void do_pointer_ungrab(VncDisplay *obj)
+{
+	VncDisplayPrivate *priv = obj->priv;
+
+	/* If we grabed keyboard upon pointer grab, then ungrab it now */
+	if (!priv->grab_keyboard)
+		do_keyboard_ungrab(obj);
+
+	gdk_pointer_ungrab(GDK_CURRENT_TIME);
+	priv->in_pointer_grab = FALSE;
+	g_signal_emit(obj, signals[VNC_POINTER_UNGRAB], 0);
+}
+
+
 
 static gboolean button_event(GtkWidget *widget, GdkEventButton *button,
 			     gpointer data G_GNUC_UNUSED)
@@ -150,9 +182,10 @@ static gboolean button_event(GtkWidget *
 	if (priv->gvnc == NULL)
 		return TRUE;
 
-	if (!priv->absolute && !priv->in_grab &&
+	if ((priv->grab_pointer || !priv->absolute) &&
+	    !priv->in_pointer_grab &&
 	    button->button == 1 && button->type == GDK_BUTTON_PRESS)
-		toggle_grab(VNC_DISPLAY(widget));
+		do_pointer_grab(VNC_DISPLAY(widget));
 
 	n = 1 << (button->button - 1);
 	if (button->type == GDK_BUTTON_PRESS)
@@ -166,7 +199,7 @@ static gboolean button_event(GtkWidget *
 	} else {
 		gvnc_pointer_event(priv->gvnc, priv->button_mask,
 				   0x7FFF, 0x7FFF);
-	}		
+	}
 
 	return TRUE;
 }
@@ -201,7 +234,7 @@ static gboolean scroll_event(GtkWidget *
 				   0x7FFF, 0x7FFF);
 		gvnc_pointer_event(priv->gvnc, priv->button_mask,
 				   0x7FFF, 0x7FFF);
-	}		
+	}
 
 	return TRUE;
 }
@@ -215,10 +248,10 @@ static gboolean motion_event(GtkWidget *
 	if (priv->gvnc == NULL)
 		return TRUE;
 
-	if (!priv->absolute && !priv->in_grab)
-		return TRUE;
-
-	if (priv->in_grab) {
+	if (!priv->absolute && !priv->in_pointer_grab)
+		return TRUE;
+
+	if (!priv->absolute && priv->in_pointer_grab) {
 		GdkDrawable *drawable = GDK_DRAWABLE(widget->window);
 		GdkDisplay *display = gdk_drawable_get_display(drawable);
 		GdkScreen *screen = gdk_drawable_get_screen(drawable);
@@ -274,11 +307,50 @@ static gboolean key_event(GtkWidget *wid
 
 	if (key->type == GDK_KEY_PRESS &&
 	    ((key->keyval == GDK_Control_L && (key->state & GDK_MOD1_MASK)) ||
-	     (key->keyval == GDK_Alt_L && (key->state & GDK_CONTROL_MASK))))
-		toggle_grab(VNC_DISPLAY(widget));
-
-	return TRUE;
-}
+	     (key->keyval == GDK_Alt_L && (key->state & GDK_CONTROL_MASK)))) {
+		if (priv->in_pointer_grab)
+			do_pointer_ungrab(VNC_DISPLAY(widget));
+		else
+			do_pointer_grab(VNC_DISPLAY(widget));
+	}
+
+	return TRUE;
+}
+
+static gboolean enter_event(GtkWidget *widget, GdkEventCrossing *crossing,
+                            gpointer data G_GNUC_UNUSED)
+{
+        VncDisplayPrivate *priv = VNC_DISPLAY(widget)->priv;
+
+        if (priv->gvnc == NULL || !gvnc_is_connected(priv->gvnc))
+                return TRUE;
+
+        if (crossing->mode != GDK_CROSSING_NORMAL)
+                return TRUE;
+
+        if (priv->grab_keyboard)
+                do_keyboard_grab(VNC_DISPLAY(widget));
+
+        return TRUE;
+}
+
+static gboolean leave_event(GtkWidget *widget, GdkEventCrossing *crossing,
+                            gpointer data G_GNUC_UNUSED)
+{
+        VncDisplayPrivate *priv = VNC_DISPLAY(widget)->priv;
+
+        if (priv->gvnc == NULL || !gvnc_is_connected(priv->gvnc))
+                return TRUE;
+
+        if (crossing->mode != GDK_CROSSING_NORMAL)
+                return TRUE;
+
+        if (priv->grab_keyboard)
+                do_keyboard_ungrab(VNC_DISPLAY(widget));
+
+        return TRUE;
+}
+
 
 static gboolean on_update(void *opaque, int x, int y, int w, int h)
 {
@@ -335,7 +407,7 @@ static gboolean on_resize(void *opaque, 
 	gtk_widget_set_size_request(GTK_WIDGET(obj), width, height);
 
 	gvnc_set_local(priv->gvnc, &priv->fb);
-			
+
 	return TRUE;
 }
 
@@ -345,8 +417,8 @@ static gboolean on_pointer_type_change(v
 	VncDisplayPrivate *priv = obj->priv;
 
 	if (absolute) {
-		if (priv->in_grab)
-			toggle_grab(obj);
+		if (priv->in_pointer_grab && !priv->grab_pointer)
+			do_pointer_ungrab(obj);
 		gdk_window_set_cursor(GTK_WIDGET(obj)->window, priv->null_cursor);
 	} else
 		gdk_window_set_cursor(GTK_WIDGET(obj)->window, NULL);
@@ -611,8 +683,8 @@ static void vnc_display_class_init(VncDi
 			      1,
 			      G_TYPE_INT);
 
-	klass->enter_grab_event_id =
-		g_signal_new("enter-grab-event",
+	signals[VNC_POINTER_GRAB] =
+		g_signal_new("vnc-pointer-grab",
 			     G_TYPE_FROM_CLASS(klass),
 			     G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS,
 			     0,
@@ -622,8 +694,30 @@ static void vnc_display_class_init(VncDi
 			     G_TYPE_NONE,
 			     0);
 
-	klass->leave_grab_event_id =
-		g_signal_new("leave-grab-event",
+	signals[VNC_POINTER_UNGRAB] =
+		g_signal_new("vnc-pointer-ungrab",
+			     G_TYPE_FROM_CLASS(klass),
+			     G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS,
+			     0,
+			     NULL,
+			     NULL,
+			     g_cclosure_marshal_VOID__VOID,
+			     G_TYPE_NONE,
+			     0);
+
+	signals[VNC_KEYBOARD_GRAB] =
+		g_signal_new("vnc-keyboard-grab",
+			     G_TYPE_FROM_CLASS(klass),
+			     G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS,
+			     0,
+			     NULL,
+			     NULL,
+			     g_cclosure_marshal_VOID__VOID,
+			     G_TYPE_NONE,
+			     0);
+
+	signals[VNC_KEYBOARD_UNGRAB] =
+		g_signal_new("vnc-keyboard-ungrab",
 			     G_TYPE_FROM_CLASS(klass),
 			     G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS,
 			     0,
@@ -656,6 +750,10 @@ static void vnc_display_init(GTypeInstan
 			   GTK_SIGNAL_FUNC(key_event), NULL);
 	gtk_signal_connect(obj, "key-release-event",
 			   GTK_SIGNAL_FUNC(key_event), NULL);
+	gtk_signal_connect(obj, "enter-notify-event",
+			   GTK_SIGNAL_FUNC(enter_event), NULL);
+	gtk_signal_connect(obj, "leave-notify-event",
+			   GTK_SIGNAL_FUNC(leave_event), NULL);
 
 	GTK_WIDGET_SET_FLAGS(obj, GTK_CAN_FOCUS);
 
@@ -702,6 +800,25 @@ void vnc_display_set_use_shm(VncDisplay 
 	obj->priv->use_shm = enable;
 }
 
+void vnc_display_set_pointer_grab(VncDisplay *obj, gboolean enable)
+{
+	VncDisplayPrivate *priv = obj->priv;
+
+	priv->grab_pointer = enable;
+	if (!enable && priv->absolute && priv->in_pointer_grab)
+		do_pointer_ungrab(obj);
+}
+
+void vnc_display_set_keyboard_grab(VncDisplay *obj, gboolean enable)
+{
+	VncDisplayPrivate *priv = obj->priv;
+
+	priv->grab_keyboard = enable;
+	if (!enable && priv->in_keyboard_grab && !priv->in_pointer_grab)
+		do_keyboard_ungrab(obj);
+}
+
+
 GType vnc_display_get_type(void)
 {
 	static GType type;
diff -r 725c05c132d2 -r f0724efc82b7 src/vncdisplay.h
--- a/src/vncdisplay.h	Thu Jul 05 16:43:33 2007 -0400
+++ b/src/vncdisplay.h	Fri Jul 06 10:57:07 2007 -0400
@@ -52,9 +52,6 @@ struct _VncDisplayClass
 	void		(* vnc_initialized)	(VncDisplay *display);
 	void		(* vnc_disconnected)	(VncDisplay *display);
 	void		(* vnc_auth_credential)	(VncDisplay *display, int credential);
-
-	int enter_grab_event_id;
-	int leave_grab_event_id;
 };
 
 typedef enum
@@ -78,6 +75,9 @@ gboolean	vnc_display_set_credential(VncD
 gboolean	vnc_display_set_credential(VncDisplay *obj, int type, const gchar *data);
 
 void		vnc_display_set_use_shm(VncDisplay *obj, gboolean enable);
+void		vnc_display_set_pointer_grab(VncDisplay *obj, gboolean enable);
+void		vnc_display_set_keyboard_grab(VncDisplay *obj, gboolean enable);
+
 GdkPixbuf *     vnc_display_get_pixbuf(VncDisplay *obj);
 
 int		vnc_display_get_width(VncDisplay *obj);



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