diff --git a/examples/gvncviewer.c b/examples/gvncviewer.c
index 6373564..5cf3668 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,
@@ -210,6 +220,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;
@@ -347,7 +496,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;
@@ -361,6 +510,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 */
@@ -435,6 +585,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);
@@ -508,6 +668,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 74d284a..52d89c9 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 = ""
 
@@ -168,6 +175,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 fcd7c8e..e214dd7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -15,7 +15,8 @@ libgtk_vnc_1_0_la_LDFLAGS = -Wl, @LD_VERSION_SCRIPT_SUPPORT@ \
                             -version-info 0:1:0 -no-undefined
 
 gtk_vnc_includedir = $(includedir)/gtk-vnc-1.0/
-gtk_vnc_include_HEADERS = vncdisplay.h
+gtk_vnc_include_HEADERS = vncdisplay.h \
+			vncgrabsequence.h
 
 libgtk_vnc_1_0_la_SOURCES = blt.h blt1.h \
 	coroutine.h \
@@ -25,6 +26,7 @@ libgtk_vnc_1_0_la_SOURCES = blt.h blt1.h \
 	vncdisplay.h vncdisplay.c \
         vncmarshal.h vncmarshal.c \
 	x_keymap.h x_keymap.c vnc_keycodes.h \
+	vncgrabsequence.h vncgrabsequence.c \
 	utils.h
 
 if WITH_UCONTEXT
diff --git a/src/Makefile.in b/src/Makefile.in
index b149080..8fe3dd1 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -114,7 +114,7 @@ am__libgtk_vnc_1_0_la_SOURCES_DIST = blt.h blt1.h coroutine.h d3des.h \
 	d3des.c dh.h dh.c gvnc.h gvnc.c vncdisplay.h vncdisplay.c \
 	vncmarshal.h vncmarshal.c x_keymap.h x_keymap.c vnc_keycodes.h \
 	utils.h continuation.h continuation.c coroutine_ucontext.c \
-	coroutine_gthread.c
+	coroutine_gthread.c vncgrabsequence.h vncgrabsequence.c
 @WITH_UCONTEXT_TRUE@am__objects_1 = libgtk_vnc_1_0_la-continuation.lo \
 @WITH_UCONTEXT_TRUE@	libgtk_vnc_1_0_la-coroutine_ucontext.lo
 @WITH_UCONTEXT_FALSE@am__objects_2 =  \
@@ -122,6 +122,7 @@ am__libgtk_vnc_1_0_la_SOURCES_DIST = blt.h blt1.h coroutine.h d3des.h \
 am_libgtk_vnc_1_0_la_OBJECTS = libgtk_vnc_1_0_la-d3des.lo \
 	libgtk_vnc_1_0_la-dh.lo libgtk_vnc_1_0_la-gvnc.lo \
 	libgtk_vnc_1_0_la-vncdisplay.lo \
+	libgtk_vnc_1_0_la-vncgrabsequence.lo \
 	libgtk_vnc_1_0_la-vncmarshal.lo libgtk_vnc_1_0_la-x_keymap.lo \
 	$(am__objects_1) $(am__objects_2)
 libgtk_vnc_1_0_la_OBJECTS = $(am_libgtk_vnc_1_0_la_OBJECTS)
@@ -521,10 +522,11 @@ libgtk_vnc_1_0_la_LDFLAGS = -Wl, @LD_VERSION_SCRIPT_SUPPORT@ \
                             -version-info 0:1:0 -no-undefined
 
 gtk_vnc_includedir = $(includedir)/gtk-vnc-1.0/
-gtk_vnc_include_HEADERS = vncdisplay.h
+gtk_vnc_include_HEADERS = vncdisplay.h vncgrabsequence.h
 libgtk_vnc_1_0_la_SOURCES = blt.h blt1.h coroutine.h d3des.h d3des.c \
 	dh.h dh.c gvnc.h gvnc.c vncdisplay.h vncdisplay.c vncmarshal.h \
 	vncmarshal.c x_keymap.h x_keymap.c vnc_keycodes.h utils.h \
+    vncgrabsequence.h vncgrabsequence.c \
 	$(am__append_1) $(am__append_3)
 CLEANFILES = vncmarshal.c vncmarshal.h $(am__append_5)
 @WITH_PYTHON_TRUE@pyexec_LTLIBRARIES = gtkvnc.la
@@ -647,6 +649,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgtk_vnc_1_0_la-vncdisplay.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgtk_vnc_1_0_la-vncmarshal.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgtk_vnc_1_0_la-x_keymap.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgtk_vnc_1_0_la-vncgrabsequence.Plo@am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -711,6 +714,13 @@ libgtk_vnc_1_0_la-vncdisplay.lo: vncdisplay.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgtk_vnc_1_0_la_CFLAGS) $(CFLAGS) -c -o libgtk_vnc_1_0_la-vncdisplay.lo `test -f 'vncdisplay.c' || echo '$(srcdir)/'`vncdisplay.c
 
+libgtk_vnc_1_0_la-vncgrabsequence.lo: vncgrabsequence.c
+@am__fastdepCC_TRUE@	$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgtk_vnc_1_0_la_CFLAGS) $(CFLAGS) -MT libgtk_vnc_1_0_la-vncgrabsequence.lo -MD -MP -MF $(DEPDIR)/libgtk_vnc_1_0_la-vncgrabsequence.Tpo -c -o libgtk_vnc_1_0_la-vncgrabsequence.lo `test -f 'vncgrabsequence.c' || echo '$(srcdir)/'`vncgrabsequence.c
+@am__fastdepCC_TRUE@	mv -f $(DEPDIR)/libgtk_vnc_1_0_la-vncgrabsequence.Tpo $(DEPDIR)/libgtk_vnc_1_0_la-vncgrabsequence.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='vncgrabsequence.c' object='libgtk_vnc_1_0_la-vncgrabsequence.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgtk_vnc_1_0_la_CFLAGS) $(CFLAGS) -c -o libgtk_vnc_1_0_la-vncgrabsequence.lo `test -f 'vncgrabsequence.c' || echo '$(srcdir)/'`vncgrabsequence.c
+
 libgtk_vnc_1_0_la-vncmarshal.lo: vncmarshal.c
 @am__fastdepCC_TRUE@	$(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgtk_vnc_1_0_la_CFLAGS) $(CFLAGS) -MT libgtk_vnc_1_0_la-vncmarshal.lo -MD -MP -MF $(DEPDIR)/libgtk_vnc_1_0_la-vncmarshal.Tpo -c -o libgtk_vnc_1_0_la-vncmarshal.lo `test -f 'vncmarshal.c' || echo '$(srcdir)/'`vncmarshal.c
 @am__fastdepCC_TRUE@	mv -f $(DEPDIR)/libgtk_vnc_1_0_la-vncmarshal.Tpo $(DEPDIR)/libgtk_vnc_1_0_la-vncmarshal.Plo
diff --git a/src/libgtk-vnc_sym.version b/src/libgtk-vnc_sym.version
index 4a88740..3bab1b5 100644
--- a/src/libgtk-vnc_sym.version
+++ b/src/libgtk-vnc_sym.version
@@ -53,6 +53,16 @@
     vnc_display_set_force_size;
     vnc_display_get_force_size;
 
+# 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 dc823d6..9628742 100644
--- a/src/vnc.override
+++ b/src/vnc.override
@@ -51,3 +51,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 e587dfb..be1e5b7 100644
--- a/src/vncdisplay.c
+++ b/src/vncdisplay.c
@@ -89,6 +89,9 @@ struct _VncDisplayPrivate
 	gboolean force_size;
 
 	GSList *preferable_auths;
+
+	VncGrabSequence *vncgrabseq; /* the configured key sequence */
+	gboolean *vncactiveseq; /* the currently pressed keys */
 };
 
 /* Delayed signal emission.
@@ -129,7 +132,8 @@ enum
   PROP_LOSSY_ENCODING,
   PROP_SCALING,
   PROP_SHARED_FLAG,
-  PROP_FORCE_SIZE
+  PROP_FORCE_SIZE,
+  PROP_GRAB_KEYS,
 };
 
 /* Signals */
@@ -212,6 +216,9 @@ vnc_display_get_property (GObject    *object,
       case PROP_FORCE_SIZE:
         g_value_set_boolean (value, vnc->priv->force_size);
 	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;
@@ -252,6 +259,9 @@ vnc_display_set_property (GObject      *object,
       case PROP_FORCE_SIZE:
         vnc_display_set_force_size (vnc, g_value_get_boolean (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;
@@ -674,6 +684,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;
@@ -749,9 +790,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)
@@ -1563,6 +1602,10 @@ static void vnc_display_finalize (GObject *obj)
 		g_object_unref(priv->image);
 		priv->image = NULL;
 	}
+	if (priv->vncgrabseq) {
+		vnc_grab_sequence_free(priv->vncgrabseq);
+		priv->vncgrabseq = NULL;
+	}
 
 	g_slist_free (priv->preferable_auths);
 
@@ -1722,6 +1765,18 @@ static void vnc_display_class_init(VncDisplayClass *klass)
 					    0,
 					    G_PARAM_READABLE);
 
+	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",
 			      G_OBJECT_CLASS_TYPE (object_class),
@@ -1904,6 +1959,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
@@ -2031,6 +2088,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 7c6a64e..27046cb 100644
--- a/src/vncdisplay.h
+++ b/src/vncdisplay.h
@@ -27,6 +27,7 @@ typedef struct _VncDisplayPrivate VncDisplayPrivate;
 
 #include <gtk/gtkdrawingarea.h>
 #include <glib.h>
+#include <vncgrabsequence.h>
 
 #define VNC_TYPE_DISPLAY (vnc_display_get_type())
 #define VNC_TYPE_DISPLAY_CREDENTIAL (vnc_display_credential_get_type())
@@ -97,6 +98,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:
+ */
