PATCH: Add configurable key grab sequences (v3)



Allow the key grab sequence to be configured by applications.
The grab sequence is represented by a new boxed data object

  VncGrabSequence

This can be created from an array of keysyms

  guint keys[] = { GDK_Control_L, GDK_Alt_L };
  guint len = sizeof(keys)/sizeof(keys[0]);
  vnc_grab_sequence_new(len, keys);

Or from a string format

  vnc_grab_sequence_new_from_string("Control_L+Alt_L");

The gvncviewer.c example program shows a user interface for
configuring key sequences. The gvncviewer.py example program
demonstrates access from the python binding.

This patch is heavily based on the original proposal from
Michal Novotny
---
 examples/gvncviewer.c      |  182 +++++++++++++++++++++++++++++++++++++++++---
 examples/gvncviewer.py     |   14 +++-
 src/Makefile.am            |    3 +
 src/libgtk-vnc_sym.version |   10 +++
 src/vnc.override           |   57 ++++++++++++++
 src/vncdisplay.c           |   82 +++++++++++++++++++-
 src/vncdisplay.h           |    3 +
 src/vncgrabsequence.c      |  121 +++++++++++++++++++++++++++++
 src/vncgrabsequence.h      |   58 ++++++++++++++
 9 files changed, 515 insertions(+), 15 deletions(-)
 create mode 100644 src/vncgrabsequence.c
 create mode 100644 src/vncgrabsequence.h

diff --git a/examples/gvncviewer.c b/examples/gvncviewer.c
index c3fbd74..1799e32 100644
--- a/examples/gvncviewer.c
+++ b/examples/gvncviewer.c
@@ -43,23 +43,33 @@ static const GOptionEntry options [] =
 
 static GtkWidget *vnc;
 
+typedef struct {
+	GtkWidget *label;
+	guint curkeys;
+	guint numkeys;
+	guint *keysyms;
+	gboolean set;
+} VncGrabDefs;
+
 static void set_title(VncDisplay *vncdisplay, GtkWidget *window,
 	gboolean grabbed)
 {
-	const char *name;
-	char title[1024];
-	const char *subtitle;
+	const gchar *name = vnc_display_get_name(VNC_DISPLAY(vncdisplay));
+	VncGrabSequence *seq = vnc_display_get_grab_keys(vncdisplay);
+	gchar *seqstr = vnc_grab_sequence_as_string(seq);
+	gchar *title;
 
 	if (grabbed)
-		subtitle = "(Press Ctrl+Alt to release pointer) ";
+		title = g_strdup_printf("(Press %s to release pointer) %s - GVncViewer",
+					seqstr, name);
 	else
-		subtitle = "";
-
-	name = vnc_display_get_name(VNC_DISPLAY(vncdisplay));
-	snprintf(title, sizeof(title), "%s%s - GVncViewer",
-		 subtitle, name);
+		title = g_strdup_printf("%s - GVncViewer",
+					name);
 
 	gtk_window_set_title(GTK_WINDOW(window), title);
+
+	g_free(seqstr);
+	g_free(title);
 }
 
 static gboolean vnc_screenshot(GtkWidget *window G_GNUC_UNUSED,
@@ -216,6 +226,145 @@ static void do_scaling(GtkWidget *menu, GtkWidget *vncdisplay)
 		vnc_display_set_scaling(VNC_DISPLAY(vncdisplay), FALSE);
 }
 
+static void dialog_update_keysyms(GtkWidget *window, guint *keysyms, guint numsyms)
+{
+	gchar *keys;
+	int i;
+
+	keys = g_strdup("");
+	for (i = 0; i < numsyms; i++)
+	{
+		keys = g_strdup_printf("%s%s%s", keys,
+			(strlen(keys) > 0) ? "+" : " ", gdk_keyval_name(keysyms[i]));
+	}
+
+	gtk_label_set_text( GTK_LABEL(window), keys);
+}
+
+static gboolean dialog_key_ignore(int keyval)
+{
+	switch (keyval) {
+		case GDK_Return:
+		case GDK_Escape:
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
+static gboolean dialog_key_press(GtkWidget *window G_GNUC_UNUSED,
+        GdkEvent *ev, VncGrabDefs *defs)
+{
+	gboolean keySymExists;
+	int i;
+
+	if (dialog_key_ignore(ev->key.keyval))
+		return FALSE;
+
+	if (defs->set && defs->curkeys)
+		return FALSE;
+
+	/* Check whether we already have keysym in array - i.e. it was handler by something else */
+	keySymExists = FALSE;
+	for (i = 0; i < defs->curkeys; i++) {
+		if (defs->keysyms[i] == ev->key.keyval)
+			keySymExists = TRUE;
+	}
+
+	if (!keySymExists) {
+		defs->keysyms = g_renew(guint, defs->keysyms, defs->curkeys + 1);
+		defs->keysyms[defs->curkeys] = ev->key.keyval;
+		defs->curkeys++;
+	}
+
+	dialog_update_keysyms(defs->label, defs->keysyms, defs->curkeys);
+
+	if (!ev->key.is_modifier) {
+		defs->set = TRUE;
+		defs->numkeys = defs->curkeys;
+		defs->curkeys--;
+	}
+
+	return FALSE;
+}
+
+static gboolean dialog_key_release(GtkWidget *window G_GNUC_UNUSED,
+        GdkEvent *ev, VncGrabDefs *defs)
+{
+	int i;
+
+	if (dialog_key_ignore(ev->key.keyval))
+		return FALSE;
+
+	if (defs->set) {
+		if (defs->curkeys == 0)
+			defs->set = FALSE;
+		if (defs->curkeys)
+			defs->curkeys--;
+		return FALSE;
+	}
+
+	for (i = 0; i < defs->curkeys; i++)
+	{
+		if (defs->keysyms[i] == ev->key.keyval)
+		{
+			defs->keysyms[i] = defs->keysyms[defs->curkeys - 1];
+			defs->curkeys--;
+			defs->keysyms = g_renew(guint, defs->keysyms, defs->curkeys);
+		}
+	}
+
+	dialog_update_keysyms(defs->label, defs->keysyms, defs->curkeys);
+
+	return FALSE;
+}
+
+static void do_set_grab_keys(GtkWidget *menu G_GNUC_UNUSED, GtkWidget *window)
+{
+	VncGrabDefs *defs;
+	VncGrabSequence *seq;
+	GtkWidget *dialog, *content_area, *label;
+	gint result;
+
+	dialog = gtk_dialog_new_with_buttons ("Key recorder",
+						GTK_WINDOW(window),
+						GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+						GTK_STOCK_OK,
+						GTK_RESPONSE_ACCEPT,
+						GTK_STOCK_CANCEL,
+						GTK_RESPONSE_REJECT,
+						NULL);
+
+	label = gtk_label_new("Please press desired grab key combination");
+	defs = g_new(VncGrabDefs, 1);
+	defs->label = label;
+	defs->keysyms = 0;
+	defs->numkeys = 0;
+	defs->curkeys = 0;
+	defs->set = FALSE;
+	g_signal_connect(dialog, "key-press-event",
+			G_CALLBACK(dialog_key_press), defs);
+	g_signal_connect(dialog, "key-release-event",
+			G_CALLBACK(dialog_key_release), defs);
+	gtk_widget_set_size_request(dialog, 300, 100);
+	content_area = gtk_dialog_get_content_area( GTK_DIALOG(dialog) );
+	gtk_container_add( GTK_CONTAINER(content_area), label);
+	gtk_widget_show_all(dialog);
+
+	result = gtk_dialog_run(GTK_DIALOG(dialog));
+	if (result == GTK_RESPONSE_ACCEPT) {
+		/* Accepted so we make a grab sequence from it */
+		seq = vnc_grab_sequence_new(defs->numkeys,
+					    defs->keysyms);
+
+		vnc_display_set_grab_keys(VNC_DISPLAY(vnc), seq);
+		set_title(VNC_DISPLAY(vnc), window, FALSE);
+		vnc_grab_sequence_free(seq);
+	}
+	g_free(defs);
+	gtk_widget_destroy(dialog);
+}
+
 static void vnc_credential(GtkWidget *vncdisplay, GValueArray *credList)
 {
 	GtkWidget *dialog = NULL;
@@ -353,7 +502,7 @@ int main(int argc, char **argv)
 	GtkWidget *window;
 	GtkWidget *layout;
 	GtkWidget *menubar;
-	GtkWidget *sendkey, *view;
+	GtkWidget *sendkey, *view, *settings;
 	GtkWidget *submenu;
 	GtkWidget *caf1;
 	GtkWidget *caf2;
@@ -367,6 +516,7 @@ int main(int argc, char **argv)
 	GtkWidget *cab;
 	GtkWidget *fullscreen;
 	GtkWidget *scaling;
+	GtkWidget *showgrabkeydlg;
 	const char *help_msg = "Run 'gvncviewer --help' to see a full list of available command line options";
 
 	/* Setup command line options */
@@ -441,6 +591,16 @@ int main(int argc, char **argv)
 
 	gtk_menu_item_set_submenu(GTK_MENU_ITEM(view), submenu);
 
+	settings = gtk_menu_item_new_with_mnemonic("_Settings");
+	gtk_menu_shell_append(GTK_MENU_SHELL(menubar), settings);
+
+	submenu = gtk_menu_new();
+
+	showgrabkeydlg = gtk_menu_item_new_with_mnemonic("_Set grab keys");
+	gtk_menu_shell_append(GTK_MENU_SHELL(submenu), showgrabkeydlg);
+
+	gtk_menu_item_set_submenu(GTK_MENU_ITEM(settings), submenu);
+
 #if WITH_LIBVIEW
 	ViewAutoDrawer_SetActive(VIEW_AUTODRAWER(layout), FALSE);
 	ViewOvBox_SetOver(VIEW_OV_BOX(layout), menubar);
@@ -516,6 +676,8 @@ int main(int argc, char **argv)
 			 G_CALLBACK(send_cad), vnc);
 	g_signal_connect(cab, "activate",
 			 G_CALLBACK(send_cab), vnc);
+	g_signal_connect(showgrabkeydlg, "activate",
+			 G_CALLBACK(do_set_grab_keys), window);
 	g_signal_connect(fullscreen, "toggled",
 			 G_CALLBACK(do_fullscreen), window);
 	g_signal_connect(scaling, "toggled",
diff --git a/examples/gvncviewer.py b/examples/gvncviewer.py
index 9a74268..c5769f3 100644
--- a/examples/gvncviewer.py
+++ b/examples/gvncviewer.py
@@ -28,8 +28,15 @@ if len(sys.argv) != 2 and len(sys.argv) != 3:
 
 def set_title(vnc, window, grabbed):
     name = vnc.get_name()
+    keys = vnc.get_grab_keys()
+    keystr = None
+    for k in keys:
+        if keystr is None:
+            keystr = gtk.gdk.keyval_name(k)
+        else:
+            keystr = keystr + "+" + gtk.gdk.keyval_name(k)
     if grabbed:
-        subtitle = "(Press Ctrl+Alt to release pointer) "
+        subtitle = "(Press %s to release pointer) " % keystr
     else:
         subtitle = ""
 
@@ -173,6 +180,11 @@ layout.add(vnc)
 vnc.realize()
 vnc.set_pointer_grab(True)
 vnc.set_keyboard_grab(True)
+
+# Example to change grab key combination to Ctrl+Alt+g
+grab_keys = [ gtk.keysyms.Control_L, gtk.keysyms.Alt_L, gtk.keysyms.g ]
+vnc.set_grab_keys(grab_keys)
+
 #v.set_pointer_local(True)
 
 if len(sys.argv) == 3:
diff --git a/src/Makefile.am b/src/Makefile.am
index 393d76a..745ca99 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -85,6 +85,7 @@ gtk_vnc_includedir = $(includedir)/gtk-vnc-1.0/
 gtk_vnc_include_HEADERS = \
 			vncdisplay.h \
 			vncdisplayenums.h \
+			vncgrabsequence.h \
 			vncimageframebuffer.h
 
 libgtk_vnc_1_0_la_SOURCES = \
@@ -92,6 +93,7 @@ libgtk_vnc_1_0_la_SOURCES = \
 			vncdisplay.h vncdisplay.c \
 			vncdisplayenums.h vncdisplayenums.c \
 			vncdisplaykeymap.h vncdisplaykeymap.c \
+			vncgrabsequence.h vncgrabsequence.c \
 			vncmarshal.h vncmarshal.c
 
 vncdisplayenums.c: vncdisplay.h
@@ -204,6 +206,7 @@ GVNC_INTROSPECTION_SRCS = \
 GTK_VNC_INTROSPECTION_SRCS = \
 			$(srcdir)/vncimageframebuffer.h $(srcdir)/vncimageframebuffer.c \
 			$(srcdir)/vncdisplay.h $(srcdir)/vncdisplay.c \
+			$(srcdir)/vncgrabsequence.h $(srcdir)/vncgrabsequence.c \
 			$(builddir)/vncdisplayenums.h $(builddir)/vncdisplayenums.c
 
 GVnc-1.0.gir: libgvnc-1.0.la $(G_IR_SCANNER) Makefile.am
diff --git a/src/libgtk-vnc_sym.version b/src/libgtk-vnc_sym.version
index b6f5347..dc219d4 100644
--- a/src/libgtk-vnc_sym.version
+++ b/src/libgtk-vnc_sym.version
@@ -68,6 +68,16 @@
     vnc_image_framebuffer_new;
     vnc_image_framebuffer_get_image;
 
+# grab key settings support
+    vnc_display_set_grab_keys;
+    vnc_display_get_grab_keys;
+    vnc_grab_sequence_new;
+    vnc_grab_sequence_new_from_string;
+    vnc_grab_sequence_copy;
+    vnc_grab_sequence_free;
+    vnc_grab_sequence_as_string;
+    vnc_grab_sequence_get_type;
+
   local:
       *;
 };
diff --git a/src/vnc.override b/src/vnc.override
index dfc346e..2098358 100644
--- a/src/vnc.override
+++ b/src/vnc.override
@@ -52,3 +52,60 @@ _wrap_vnc_display_send_keys(PyGObject *self,
     Py_INCREF(Py_None);
     return Py_None;
 }
+%%
+override vnc_display_get_grab_keys kwargs
+static PyObject*
+_wrap_vnc_display_get_grab_keys(PyGObject *self,
+                            PyObject *args, PyObject *kwargs)
+{
+    VncGrabSequence *seq;
+    PyObject *keyList;
+    int i;
+
+    seq = vnc_display_get_grab_keys(VNC_DISPLAY(self->obj));
+
+    keyList = PyList_New(0);
+    for (i = 0 ; i < seq->nkeysyms ; i++)
+       PyList_Append(keyList, PyInt_FromLong(seq->keysyms[i]));
+
+    return keyList;
+}
+%%
+override vnc_display_set_grab_keys kwargs
+static PyObject*
+_wrap_vnc_display_set_grab_keys(PyGObject *self,
+                            PyObject *args, PyObject *kwargs)
+{
+    static char *kwlist[] = {"keys", NULL};
+    PyObject *keyList;
+    int i;
+    guint nkeysyms;
+    guint *keysyms;
+    VncGrabSequence *seq;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+                                     "O|I:VncDisplay.set_grab_keys", kwlist,
+                                     &keyList))
+        return NULL;
+
+    if (!PyList_Check(keyList))
+        return NULL;
+
+    nkeysyms = PyList_Size(keyList);
+    keysyms = g_new0(guint, nkeysyms);
+
+    for (i = 0 ; i < nkeysyms ; i++) {
+        PyObject *val = PyList_GetItem(keyList, i);
+        keysyms[i] = (guint)PyInt_AsLong(val);
+    }
+
+    seq = vnc_grab_sequence_new(nkeysyms, keysyms);
+    g_free(keysyms);
+
+    vnc_display_set_grab_keys(VNC_DISPLAY(self->obj), seq);
+
+    vnc_grab_sequence_free(seq);
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
diff --git a/src/vncdisplay.c b/src/vncdisplay.c
index 71e158b..8eeb243 100644
--- a/src/vncdisplay.c
+++ b/src/vncdisplay.c
@@ -85,6 +85,9 @@ struct _VncDisplayPrivate
 
 	GSList *preferable_auths;
 	const guint8 const *keycode_map;
+
+	VncGrabSequence *vncgrabseq; /* the configured key sequence */
+	gboolean *vncactiveseq; /* the currently pressed keys */
 };
 
 G_DEFINE_TYPE(VncDisplay, vnc_display, GTK_TYPE_DRAWING_AREA)
@@ -104,7 +107,8 @@ enum
   PROP_SCALING,
   PROP_SHARED_FLAG,
   PROP_FORCE_SIZE,
-  PROP_DEPTH
+  PROP_DEPTH,
+  PROP_GRAB_KEYS,
 };
 
 /* Signals */
@@ -198,6 +202,9 @@ vnc_display_get_property (GObject    *object,
       case PROP_DEPTH:
         g_value_set_enum (value, vnc->priv->depth);
 	break;
+      case PROP_GRAB_KEYS:
+	g_value_set_boxed(value, vnc->priv->vncgrabseq);
+	break;
       default:
 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 	break;
@@ -241,6 +248,9 @@ vnc_display_set_property (GObject      *object,
       case PROP_DEPTH:
         vnc_display_set_depth (vnc, g_value_get_enum (value));
         break;
+      case PROP_GRAB_KEYS:
+	vnc_display_set_grab_keys(vnc, g_value_get_boxed(value));
+	break;
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
         break;
@@ -673,6 +683,37 @@ static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion)
 	return TRUE;
 }
 
+
+static gboolean check_for_grab_key(GtkWidget *widget, int type, int keyval)
+{
+	VncDisplayPrivate *priv = VNC_DISPLAY(widget)->priv;
+	int i;
+
+	if (!priv->vncgrabseq->nkeysyms)
+		return FALSE;
+
+	if (type == GDK_KEY_RELEASE) {
+		/* Any key release resets the whole grab sequence */
+		memset(priv->vncactiveseq, 0,
+		       sizeof(gboolean)*priv->vncgrabseq->nkeysyms);
+
+		return FALSE;
+	} else {
+		/* Record the new key press */
+		for (i = 0 ; i < priv->vncgrabseq->nkeysyms ; i++)
+			if (priv->vncgrabseq->keysyms[i] == keyval)
+				priv->vncactiveseq[i] = TRUE;
+
+		/* Return if any key is not pressed */
+		for (i = 0 ; i < priv->vncgrabseq->nkeysyms ; i++)
+			if (priv->vncactiveseq[i] == FALSE)
+				return FALSE;
+
+		return TRUE;
+	}
+}
+
+
 static gboolean key_event(GtkWidget *widget, GdkEventKey *key)
 {
 	VncDisplayPrivate *priv = VNC_DISPLAY(widget)->priv;
@@ -752,9 +793,7 @@ static gboolean key_event(GtkWidget *widget, GdkEventKey *key)
 		}
 	}
 
-	if (key->type == GDK_KEY_PRESS &&
-	    ((keyval == GDK_Control_L && (key->state & GDK_MOD1_MASK)) ||
-	     (keyval == GDK_Alt_L && (key->state & GDK_CONTROL_MASK)))) {
+	if (check_for_grab_key(widget, key->type, key->keyval)) {
 		if (priv->in_pointer_grab)
 			do_pointer_ungrab(VNC_DISPLAY(widget), FALSE);
 		else if (!priv->grab_keyboard || !priv->absolute)
@@ -1472,6 +1511,10 @@ static void vnc_display_finalize (GObject *obj)
 		g_object_unref (priv->gc);
 		priv->gc = NULL;
 	}
+	if (priv->vncgrabseq) {
+		vnc_grab_sequence_free(priv->vncgrabseq);
+		priv->vncgrabseq = NULL;
+	}
 
 	g_slist_free (priv->preferable_auths);
 
@@ -1640,6 +1683,17 @@ static void vnc_display_class_init(VncDisplayClass *klass)
 								G_PARAM_STATIC_NAME |
 								G_PARAM_STATIC_NICK |
 								G_PARAM_STATIC_BLURB));
+	g_object_class_install_property (object_class,
+					 PROP_GRAB_KEYS,
+					 g_param_spec_boxed( "grab-keys",
+							     "Grab keys",
+							     "The key grab sequence",
+							     VNC_TYPE_GRAB_SEQUENCE,
+							     G_PARAM_READWRITE |
+							     G_PARAM_CONSTRUCT |
+							     G_PARAM_STATIC_NAME |
+							     G_PARAM_STATIC_NICK |
+							     G_PARAM_STATIC_BLURB));
 
 	signals[VNC_CONNECTED] =
 		g_signal_new ("vnc-connected",
@@ -1823,6 +1877,8 @@ static void vnc_display_init(VncDisplay *display)
 	priv->local_pointer = FALSE;
 	priv->shared_flag = FALSE;
 	priv->force_size = TRUE;
+	priv->vncgrabseq = vnc_grab_sequence_new_from_string("Control_L+Alt_L");
+	priv->vncactiveseq = g_new0(gboolean, priv->vncgrabseq->nkeysyms);
 
 	/*
 	 * Both these two provide TLS based auth, and can layer
@@ -1905,6 +1961,24 @@ void vnc_display_set_pointer_grab(VncDisplay *obj, gboolean enable)
 		do_pointer_ungrab(obj, FALSE);
 }
 
+void vnc_display_set_grab_keys(VncDisplay *obj, VncGrabSequence *seq)
+{
+	if (obj->priv->vncgrabseq) {
+		vnc_grab_sequence_free(obj->priv->vncgrabseq);
+		g_free(obj->priv->vncactiveseq);
+	}
+	if (seq)
+		obj->priv->vncgrabseq = vnc_grab_sequence_copy(seq);
+	else
+		obj->priv->vncgrabseq = vnc_grab_sequence_new_from_string("Control_L+Alt_L");
+	obj->priv->vncactiveseq = g_new0(gboolean, obj->priv->vncgrabseq->nkeysyms);
+}
+
+VncGrabSequence *vnc_display_get_grab_keys(VncDisplay *obj)
+{
+	return obj->priv->vncgrabseq;
+}
+
 void vnc_display_set_keyboard_grab(VncDisplay *obj, gboolean enable)
 {
 	VncDisplayPrivate *priv = obj->priv;
diff --git a/src/vncdisplay.h b/src/vncdisplay.h
index 1b5b297..dc043d1 100644
--- a/src/vncdisplay.h
+++ b/src/vncdisplay.h
@@ -24,6 +24,7 @@
 
 #include <gtk/gtkdrawingarea.h>
 #include <glib.h>
+#include <vncgrabsequence.h>
 
 G_BEGIN_DECLS
 
@@ -94,6 +95,8 @@ void            vnc_display_send_keys_ex(VncDisplay *obj, const guint *keyvals,
 					 int nkeyvals, VncDisplayKeyEvent kind);
 
 void		vnc_display_send_pointer(VncDisplay *obj, gint x, gint y, int button_mask);
+void		vnc_display_set_grab_keys(VncDisplay *obj, VncGrabSequence *seq);
+VncGrabSequence	*vnc_display_get_grab_keys(VncDisplay *obj);
 
 gboolean	vnc_display_set_credential(VncDisplay *obj, int type, const gchar *data);
 
diff --git a/src/vncgrabsequence.c b/src/vncgrabsequence.c
new file mode 100644
index 0000000..6e23ed2
--- /dev/null
+++ b/src/vncgrabsequence.c
@@ -0,0 +1,121 @@
+/*
+ * GTK VNC Widget
+ *
+ * Copyright (C) 2010 Daniel P. Berrange <dan berrange com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.0 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <gdk/gdk.h>
+
+#include "vncgrabsequence.h"
+
+GType vnc_grab_sequence_get_type(void)
+{
+	static GType grab_sequence_type = 0;
+
+	if (G_UNLIKELY(grab_sequence_type == 0)) {
+		grab_sequence_type = g_boxed_type_register_static
+			("VncGrabSequence",
+			 (GBoxedCopyFunc)vnc_grab_sequence_copy,
+			 (GBoxedFreeFunc)vnc_grab_sequence_free);
+	}
+
+	return grab_sequence_type;
+}
+
+
+VncGrabSequence *vnc_grab_sequence_new(guint nkeysyms, guint *keysyms)
+{
+	VncGrabSequence *sequence;
+
+	sequence = g_slice_new0(VncGrabSequence);
+	sequence->nkeysyms = nkeysyms;
+	sequence->keysyms = g_new0(guint, nkeysyms);
+	memcpy(sequence->keysyms, keysyms, sizeof(guint)*nkeysyms);
+
+	return sequence;
+}
+
+
+VncGrabSequence *vnc_grab_sequence_new_from_string(const gchar *str)
+{
+	gchar **keysymstr;
+	int i;
+	VncGrabSequence *sequence;
+
+	sequence = g_slice_new0(VncGrabSequence);
+
+	keysymstr = g_strsplit(str, "+", 5);
+
+	sequence->nkeysyms = 0;
+	while (keysymstr[sequence->nkeysyms])
+		sequence->nkeysyms++;
+
+	sequence->keysyms = g_new0(guint, sequence->nkeysyms);
+	for (i = 0 ; i < sequence->nkeysyms ; i++)
+		sequence->keysyms[i] =
+			(guint)gdk_keyval_from_name(keysymstr[i]);
+	
+	return sequence;
+
+}
+
+
+VncGrabSequence *vnc_grab_sequence_copy(VncGrabSequence *srcSequence)
+{
+	VncGrabSequence *sequence;
+
+	sequence = g_slice_dup(VncGrabSequence, srcSequence);
+	sequence->keysyms = g_new0(guint, srcSequence->nkeysyms);
+	memcpy(sequence->keysyms, srcSequence->keysyms,
+	       sizeof(guint) * sequence->nkeysyms);
+
+	return sequence;
+}
+
+
+void vnc_grab_sequence_free(VncGrabSequence *sequence)
+{
+	g_slice_free(VncGrabSequence, sequence);
+}
+
+
+gchar *vnc_grab_sequence_as_string(VncGrabSequence *sequence)
+{
+	GString *str = g_string_new("");
+	int i;
+
+	for (i = 0 ; i < sequence->nkeysyms ; i++) {
+		if (i > 0)
+			g_string_append_c(str, '+');
+		g_string_append(str, gdk_keyval_name(sequence->keysyms[i]));
+	}
+
+	return g_string_free(str, FALSE);
+
+}
+
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/src/vncgrabsequence.h b/src/vncgrabsequence.h
new file mode 100644
index 0000000..94007ef
--- /dev/null
+++ b/src/vncgrabsequence.h
@@ -0,0 +1,58 @@
+/*
+ * GTK VNC Widget
+ *
+ * Copyright (C) 2006  Anthony Liguori <anthony codemonkey ws>
+ * Copyright (C) 2009-2010 Daniel P. Berrange <dan berrange com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.0 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef VNC_GRAB_SEQUENCE_H
+#define VNC_GRAB_SEQUENCE_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define VNC_TYPE_GRAB_SEQUENCE            (vnc_grab_sequence_get_type ())
+
+typedef struct _VncGrabSequence VncGrabSequence;
+
+struct _VncGrabSequence {
+	guint nkeysyms;
+	guint *keysyms;
+};
+
+GType vnc_grab_sequence_get_type(void);
+
+VncGrabSequence *vnc_grab_sequence_new(guint nkeysyms, guint *keysyms);
+VncGrabSequence *vnc_grab_sequence_new_from_string(const gchar *str);
+VncGrabSequence *vnc_grab_sequence_copy(VncGrabSequence *sequence);
+void vnc_grab_sequence_free(VncGrabSequence *sequence);
+gchar *vnc_grab_sequence_as_string(VncGrabSequence *sequence);
+
+
+G_END_DECLS
+
+#endif /* VNC_GRAB_SEQUENCE_H */
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
-- 
1.7.0.1


-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|

Attachment: signature.asc
Description: Digital signature



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