diff --git a/examples/gvncviewer.c b/examples/gvncviewer.c
index c3fbd74..960b4cc 100644
--- a/examples/gvncviewer.c
+++ b/examples/gvncviewer.c
@@ -32,8 +32,18 @@
 #endif
 
 static gchar **args = NULL;
+static gboolean keyboard_grab = TRUE;
+static gboolean relative_pointer = TRUE;
 static const GOptionEntry options [] =
 {
+	{ "absolute", 'a', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE,
+		&relative_pointer, "Turn off relative pointer extension", NULL },
+	{ "relative", 'r', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE,
+		&relative_pointer, "Turn on relative pointer extension", NULL },
+	{ "no-keyboard-grab", 'k', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE,
+		&keyboard_grab, "Turn off keyboard grab", NULL },
+	{ "keyboard-grab", '\0', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE,
+		&keyboard_grab, NULL, NULL },
 	{
 		G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &args,
 		NULL, "[hostname][:display]" },
@@ -216,6 +226,26 @@ static void do_scaling(GtkWidget *menu, GtkWidget *vncdisplay)
 		vnc_display_set_scaling(VNC_DISPLAY(vncdisplay), FALSE);
 }
 
+static void do_keyboard_grab(GtkWidget *menu, GtkWidget *vncdisplay)
+{
+	if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu)))
+		keyboard_grab = TRUE;
+	else
+		keyboard_grab = FALSE;
+
+	vnc_display_set_keyboard_grab(VNC_DISPLAY(vncdisplay), keyboard_grab);;
+}
+
+static void do_relative(GtkWidget *menu, GtkWidget *vncdisplay)
+{
+	if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu)))
+		relative_pointer = TRUE;
+	else
+		relative_pointer = FALSE;
+
+	vnc_display_set_pointer_allow_relative(VNC_DISPLAY(vncdisplay), relative_pointer);
+}
+
 static void vnc_credential(GtkWidget *vncdisplay, GValueArray *credList)
 {
 	GtkWidget *dialog = NULL;
@@ -367,6 +397,8 @@ int main(int argc, char **argv)
 	GtkWidget *cab;
 	GtkWidget *fullscreen;
 	GtkWidget *scaling;
+	GtkWidget *grab_toggle;
+	GtkWidget *relative_toggle;
 	const char *help_msg = "Run 'gvncviewer --help' to see a full list of available command line options";
 
 	/* Setup command line options */
@@ -441,6 +473,14 @@ int main(int argc, char **argv)
 
 	gtk_menu_item_set_submenu(GTK_MENU_ITEM(view), submenu);
 
+	grab_toggle = gtk_check_menu_item_new_with_mnemonic("Keyboard _Grab");
+	gtk_menu_bar_append(GTK_MENU_BAR(menubar), grab_toggle);
+	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(grab_toggle), keyboard_grab);
+
+	relative_toggle = gtk_check_menu_item_new_with_mnemonic("_Relative Pointer");
+	gtk_menu_bar_append(GTK_MENU_BAR(menubar), relative_toggle);
+	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(relative_toggle), relative_pointer);
+
 #if WITH_LIBVIEW
 	ViewAutoDrawer_SetActive(VIEW_AUTODRAWER(layout), FALSE);
 	ViewOvBox_SetOver(VIEW_OV_BOX(layout), menubar);
@@ -461,11 +501,12 @@ int main(int argc, char **argv)
 	} else
 		snprintf(port, sizeof(port), "%d", 5900);
 
-	if (!*hostname) 
+	if (!*hostname)
 		snprintf(hostname, sizeof(hostname), "%s", "127.0.0.1");
 	vnc_display_open_host(VNC_DISPLAY(vnc), hostname, port);
-	vnc_display_set_keyboard_grab(VNC_DISPLAY(vnc), TRUE);
+	vnc_display_set_keyboard_grab(VNC_DISPLAY(vnc), keyboard_grab);;
 	vnc_display_set_pointer_grab(VNC_DISPLAY(vnc), TRUE);
+	vnc_display_set_pointer_allow_relative(VNC_DISPLAY(vnc), relative_pointer);
 
 	if (!gtk_widget_is_composited(window)) {
 		vnc_display_set_scaling(VNC_DISPLAY(vnc), TRUE);
@@ -520,6 +561,10 @@ int main(int argc, char **argv)
 			 G_CALLBACK(do_fullscreen), window);
 	g_signal_connect(scaling, "toggled",
 			 G_CALLBACK(do_scaling), vnc);
+	g_signal_connect(grab_toggle, "toggled",
+			 G_CALLBACK(do_keyboard_grab), vnc);
+	g_signal_connect(relative_toggle, "toggled",
+			 G_CALLBACK(do_relative), vnc);
 #if WITH_LIBVIEW
 	g_signal_connect(window, "window-state-event",
 			 G_CALLBACK(window_state_event), layout);
diff --git a/src/vncdisplay.c b/src/vncdisplay.c
index 1f080fe..757616c 100644
--- a/src/vncdisplay.c
+++ b/src/vncdisplay.c
@@ -80,6 +80,7 @@ struct _VncDisplayPrivate
 	int last_y;
 
 	gboolean absolute;
+	gboolean allow_relative;
 
 	gboolean grab_pointer;
 	gboolean grab_keyboard;
@@ -93,6 +94,11 @@ struct _VncDisplayPrivate
 	GSList *preferable_auths;
 };
 
+inline static gboolean absolute(const struct _VncDisplayPrivate * priv)
+{
+	return priv->absolute || !priv->allow_relative;
+}
+
 /* Delayed signal emission.
  *
  * We want signals to be delivered in the system coroutine.  This helps avoid
@@ -131,7 +137,8 @@ enum
   PROP_LOSSY_ENCODING,
   PROP_SCALING,
   PROP_SHARED_FLAG,
-  PROP_FORCE_SIZE
+  PROP_FORCE_SIZE,
+  PROP_POINTER_ALLOW_RELATIVE
 };
 
 /* Signals */
@@ -190,6 +197,9 @@ vnc_display_get_property (GObject    *object,
       case PROP_KEYBOARD_GRAB:
         g_value_set_boolean (value, vnc->priv->grab_keyboard);
 	break;
+      case PROP_POINTER_ALLOW_RELATIVE:
+        g_value_set_boolean (value, vnc->priv->allow_relative);
+	break;
       case PROP_READ_ONLY:
         g_value_set_boolean (value, vnc->priv->read_only);
 	break;
@@ -239,6 +249,8 @@ vnc_display_set_property (GObject      *object,
       case PROP_KEYBOARD_GRAB:
         vnc_display_set_keyboard_grab (vnc, g_value_get_boolean (value));
         break;
+      case PROP_POINTER_ALLOW_RELATIVE:
+        vnc_display_set_pointer_allow_relative (vnc, g_value_get_boolean (value));
       case PROP_READ_ONLY:
         vnc_display_set_read_only (vnc, g_value_get_boolean (value));
         break;
@@ -475,7 +487,7 @@ static void do_pointer_ungrab(VncDisplay *obj, gboolean quiet)
 	gdk_pointer_ungrab(GDK_CURRENT_TIME);
 	priv->in_pointer_grab = FALSE;
 
-	if (priv->absolute)
+	if (absolute(priv))
 		do_pointer_hide(obj);
 
 	if (!quiet)
@@ -503,7 +515,7 @@ static gboolean button_event(GtkWidget *widget, GdkEventButton *button)
 
 	gtk_widget_grab_focus (widget);
 
-	if (priv->grab_pointer && !priv->absolute && !priv->in_pointer_grab &&
+	if (priv->grab_pointer && !absolute(priv) && !priv->in_pointer_grab &&
 	    button->button == 1 && button->type == GDK_BUTTON_PRESS)
 		do_pointer_grab(VNC_DISPLAY(widget), FALSE);
 
@@ -513,7 +525,7 @@ static gboolean button_event(GtkWidget *widget, GdkEventButton *button)
 	else if (button->type == GDK_BUTTON_RELEASE)
 		priv->button_mask &= ~n;
 
-	if (priv->absolute) {
+	if (absolute(priv)) {
 		gvnc_pointer_event(priv->gvnc, priv->button_mask,
 				   priv->last_x, priv->last_y);
 	} else {
@@ -546,7 +558,7 @@ static gboolean scroll_event(GtkWidget *widget, GdkEventScroll *scroll)
 	else
 		return FALSE;
 
-	if (priv->absolute) {
+	if (absolute(priv)) {
 		gvnc_pointer_event(priv->gvnc, priv->button_mask | mask,
 				   priv->last_x, priv->last_y);
 		gvnc_pointer_event(priv->gvnc, priv->button_mask,
@@ -588,7 +600,7 @@ static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion)
 
 	/* In relative mode, only move the server mouse pointer
 	 * if the client grab is active */
-	if (!priv->absolute && !priv->in_pointer_grab)
+	if (!absolute(priv) && !priv->in_pointer_grab)
 		return FALSE;
 
 	if (priv->read_only)
@@ -622,7 +634,7 @@ static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion)
 	}
 
 	/* Next adjust the real client pointer */
-	if (!priv->absolute) {
+	if (!absolute(priv)) {
 		GdkDrawable *drawable = GDK_DRAWABLE(widget->window);
 		GdkDisplay *display = gdk_drawable_get_display(drawable);
 		GdkScreen *screen = gdk_drawable_get_screen(drawable);
@@ -652,7 +664,7 @@ static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion)
 	/* Finally send the event to server */
 	if (priv->last_x != -1) {
 		int dx, dy;
-		if (priv->absolute) {
+		if (absolute(priv)) {
 			dx = (int)motion->x;
 			dy = (int)motion->y;
 
@@ -756,7 +768,7 @@ static gboolean key_event(GtkWidget *widget, GdkEventKey *key)
 	     (keyval == GDK_Alt_L && (key->state & GDK_CONTROL_MASK)))) {
 		if (priv->in_pointer_grab)
 			do_pointer_ungrab(VNC_DISPLAY(widget), FALSE);
-		else if (!priv->grab_keyboard || !priv->absolute)
+		else if (!priv->grab_keyboard || !absolute(priv))
 			do_pointer_grab(VNC_DISPLAY(widget), FALSE);
 	}
 
@@ -980,7 +992,7 @@ static gboolean do_resize(void *opaque, int width, int height, gboolean quiet)
 		priv->null_cursor = create_null_cursor();
 		if (priv->local_pointer)
 			do_pointer_show(obj);
-		else if (priv->in_pointer_grab || priv->absolute)
+		else if (priv->in_pointer_grab || absolute(priv))
 			do_pointer_hide(obj);
 		priv->gc = gdk_gc_new(GTK_WIDGET(obj)->window);
 	}
@@ -1034,17 +1046,17 @@ static gboolean on_get_preferred_pixel_format(void *opaque,
 	return TRUE;
 }
 
-static gboolean on_pointer_type_change(void *opaque, int absolute)
+static gboolean on_pointer_type_change(void *opaque, int _absolute)
 {
 	VncDisplay *obj = VNC_DISPLAY(opaque);
 	VncDisplayPrivate *priv = obj->priv;
 
-	if (absolute && priv->in_pointer_grab && priv->grab_pointer)
-		do_pointer_ungrab(obj, FALSE);
+	priv->absolute = _absolute;
 
-	priv->absolute = absolute;
+	if (absolute(priv) && priv->in_pointer_grab && priv->grab_pointer)
+		do_pointer_ungrab(obj, FALSE);
 
-	if (!priv->in_pointer_grab && !priv->absolute)
+	if (!priv->in_pointer_grab && !absolute(priv))
 		do_pointer_show(obj);
 
 	return TRUE;
@@ -1210,7 +1222,7 @@ static gboolean on_local_cursor(void *opaque, int x, int y, int width, int heigh
 	if (priv->in_pointer_grab) {
 		do_pointer_ungrab(obj, TRUE);
 		do_pointer_grab(obj, TRUE);
-	} else if (priv->absolute) {
+	} else if (absolute(priv)) {
 		do_pointer_hide(obj);
 	}
 
@@ -1532,7 +1544,7 @@ void vnc_display_send_pointer(VncDisplay *obj, gint x, gint y, int button_mask)
 	if (priv->gvnc == NULL || !gvnc_is_open(obj->priv->gvnc))
 		return;
 
-	if (priv->absolute) {
+	if (absolute(priv)) {
 		priv->button_mask = button_mask;
 		priv->last_x = x;
 		priv->last_y = y;
@@ -1628,6 +1640,17 @@ static void vnc_display_class_init(VncDisplayClass *klass)
 								G_PARAM_STATIC_NICK |
 								G_PARAM_STATIC_BLURB));
 	g_object_class_install_property (object_class,
+					 PROP_POINTER_ALLOW_RELATIVE,
+					 g_param_spec_boolean ( "allow-relative-pointer",
+								"Allow Relative Pointer Extension",
+								"Whether we should allow relative mouse reportnig",
+								FALSE,
+								G_PARAM_READWRITE |
+								G_PARAM_CONSTRUCT |
+								G_PARAM_STATIC_NAME |
+								G_PARAM_STATIC_NICK |
+								G_PARAM_STATIC_BLURB));
+	g_object_class_install_property (object_class,
 					 PROP_READ_ONLY,
 					 g_param_spec_boolean ( "read-only",
 								"Read Only",
@@ -1897,6 +1920,7 @@ static void vnc_display_init(VncDisplay *display)
 	priv->last_x = -1;
 	priv->last_y = -1;
 	priv->absolute = 1;
+	priv->allow_relative = TRUE;
 	priv->fd = -1;
 	priv->read_only = FALSE;
 	priv->allow_lossy = FALSE;
@@ -2042,6 +2066,14 @@ void vnc_display_set_keyboard_grab(VncDisplay *obj, gboolean enable)
 		do_keyboard_ungrab(obj, FALSE);
 }
 
+void vnc_display_set_pointer_allow_relative(VncDisplay *obj, gboolean enable)
+{
+	VncDisplayPrivate *priv = obj->priv;
+
+	priv->allow_relative = enable;
+	on_pointer_type_change(obj, priv->absolute);
+}
+
 void vnc_display_set_read_only(VncDisplay *obj, gboolean enable)
 {
 	obj->priv->read_only = enable;
@@ -2234,7 +2266,7 @@ gboolean vnc_display_get_read_only(VncDisplay *obj)
 
 gboolean vnc_display_is_pointer_absolute(VncDisplay *obj)
 {
-	return obj->priv->absolute;
+	return absolute(obj->priv);
 }
 
 GOptionGroup *
diff --git a/src/vncdisplay.h b/src/vncdisplay.h
index 7c6a64e..2794404 100644
--- a/src/vncdisplay.h
+++ b/src/vncdisplay.h
@@ -106,6 +106,9 @@ gboolean	vnc_display_get_pointer_local(VncDisplay *obj);
 void		vnc_display_set_pointer_grab(VncDisplay *obj, gboolean enable);
 gboolean	vnc_display_get_pointer_grab(VncDisplay *obj);
 
+void		vnc_display_set_pointer_allow_relative(VncDisplay *obj, gboolean enable);
+gboolean	vnc_display_get_pointer_allow_relative(VncDisplay *obj);
+
 void		vnc_display_set_keyboard_grab(VncDisplay *obj, gboolean enable);
 gboolean	vnc_display_get_keyboard_grab(VncDisplay *obj);
 
