summaryrefslogtreecommitdiff
path: root/gtk/spice-widget.c
diff options
context:
space:
mode:
Diffstat (limited to 'gtk/spice-widget.c')
-rw-r--r--gtk/spice-widget.c122
1 files changed, 116 insertions, 6 deletions
diff --git a/gtk/spice-widget.c b/gtk/spice-widget.c
index c514dea..3f4db9a 100644
--- a/gtk/spice-widget.c
+++ b/gtk/spice-widget.c
@@ -19,6 +19,7 @@ struct spice_display {
/* options */
bool keyboard_grab_enable;
+ bool mouse_grab_enable;
bool resize_guest_enable;
/* state */
@@ -44,8 +45,11 @@ struct spice_display {
SpiceChannel *inputs;
enum SpiceMouseMode mouse_mode;
+ int mouse_grab_active;
bool mouse_have_pointer;
GdkCursor *mouse_cursor;
+ int mouse_last_x;
+ int mouse_last_y;
bool keyboard_grab_active;
bool keyboard_have_focus;
@@ -64,6 +68,7 @@ G_DEFINE_TYPE(SpiceDisplay, spice_display, GTK_TYPE_DRAWING_AREA)
enum {
PROP_0,
PROP_KEYBOARD_GRAB,
+ PROP_MOUSE_GRAB,
PROP_RESIZE_GUEST,
};
@@ -81,6 +86,8 @@ static bool no_mitshm;
static void try_keyboard_grab(GtkWidget *widget);
static void try_keyboard_ungrab(GtkWidget *widget);
+static void try_mouse_grab(GtkWidget *widget);
+static void try_mouse_ungrab(GtkWidget *widget);
static void recalc_geometry(GtkWidget *widget);
/* ---------------------------------------------------------------- */
@@ -130,6 +137,9 @@ static void spice_display_get_property(GObject *object,
case PROP_KEYBOARD_GRAB:
g_value_set_boolean(value, d->keyboard_grab_enable);
break;
+ case PROP_MOUSE_GRAB:
+ g_value_set_boolean(value, d->mouse_grab_enable);
+ break;
case PROP_RESIZE_GUEST:
g_value_set_boolean(value, d->resize_guest_enable);
break;
@@ -156,6 +166,12 @@ static void spice_display_set_property(GObject *object,
try_keyboard_ungrab(GTK_WIDGET(display));
}
break;
+ case PROP_MOUSE_GRAB:
+ d->mouse_grab_enable = g_value_get_boolean(value);
+ if (!d->mouse_grab_enable) {
+ try_mouse_ungrab(GTK_WIDGET(display));
+ }
+ break;
case PROP_RESIZE_GUEST:
d->resize_guest_enable = g_value_get_boolean(value);
if (d->resize_guest_enable) {
@@ -271,6 +287,74 @@ static void try_keyboard_ungrab(GtkWidget *widget)
d->keyboard_grab_active = false;
}
+static void try_mouse_grab(GtkWidget *widget)
+{
+ SpiceDisplay *display = SPICE_DISPLAY(widget);
+ spice_display *d = SPICE_DISPLAY_GET_PRIVATE(display);
+
+ if (!d->mouse_grab_enable)
+ return;
+ if (d->mouse_mode != SPICE_MOUSE_MODE_SERVER)
+ return;
+ if (d->mouse_grab_active)
+ return;
+
+ gdk_pointer_grab(gtk_widget_get_window(widget),
+ FALSE, /* All events to come to our window directly */
+ GDK_POINTER_MOTION_MASK |
+ GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_BUTTON_MOTION_MASK,
+ NULL, /* Allow cursor to move over entire desktop */
+ gdk_cursor_new(GDK_BLANK_CURSOR),
+ GDK_CURRENT_TIME);
+ d->mouse_grab_active = true;
+ d->mouse_last_x = -1;
+ d->mouse_last_y = -1;
+}
+
+static void check_mouse_edges(GtkWidget *widget, GdkEventMotion *motion)
+{
+ SpiceDisplay *display = SPICE_DISPLAY(widget);
+ spice_display *d = SPICE_DISPLAY_GET_PRIVATE(display);
+ GdkDrawable *drawable = GDK_DRAWABLE(gtk_widget_get_window(widget));
+ GdkScreen *screen = gdk_drawable_get_screen(drawable);
+ int x = (int)motion->x_root;
+ int y = (int)motion->y_root;
+
+ /* In relative mode check to see if client pointer hit
+ * one of the screen edges, and if so move it back by
+ * 200 pixels. This is important because the pointer
+ * in the server doesn't correspond 1-for-1, and so
+ * may still be only half way across the screen. Without
+ * this warp, the server pointer would thus appear to hit
+ * an invisible wall */
+ if (x == 0) x += 200;
+ if (y == 0) y += 200;
+ if (x == (gdk_screen_get_width(screen) - 1)) x -= 200;
+ if (y == (gdk_screen_get_height(screen) - 1)) y -= 200;
+
+ if (x != (int)motion->x_root || y != (int)motion->y_root) {
+ gdk_display_warp_pointer(gdk_drawable_get_display(drawable),
+ screen, x, y);
+ d->mouse_last_x = -1;
+ d->mouse_last_y = -1;
+ }
+}
+
+static void try_mouse_ungrab(GtkWidget *widget)
+{
+ SpiceDisplay *display = SPICE_DISPLAY(widget);
+ spice_display *d = SPICE_DISPLAY_GET_PRIVATE(display);
+
+ if (!d->mouse_grab_active)
+ return;
+
+ gdk_pointer_ungrab(GDK_CURRENT_TIME);
+ gdk_window_set_cursor(gtk_widget_get_window(widget), NULL);
+ d->mouse_grab_active = false;
+}
+
static gboolean geometry_timer(gpointer data)
{
SpiceDisplay *display = data;
@@ -346,7 +430,6 @@ static XVisualInfo *get_visual_default(GtkWidget *widget)
static int catch_no_mitshm(Display * dpy, XErrorEvent * event)
{
- fprintf(stderr,"WARNING: MIT shared memory extention not available\n");
no_mitshm = true;
return 0;
}
@@ -398,12 +481,10 @@ static int ximage_create(GtkWidget *widget)
if (no_mitshm)
goto shm_fail;
XSetErrorHandler(old_handler);
- fprintf(stderr, "%s: mitshm OK\n", __FUNCTION__);
return 0;
}
shm_fail:
- fprintf(stderr, "%s: mitshm FAIL\n", __FUNCTION__);
d->have_mitshm = false;
if (old_handler)
XSetErrorHandler(old_handler);
@@ -508,9 +589,11 @@ static gboolean key_event(GtkWidget *widget, GdkEventKey *key)
spice_display *d = SPICE_DISPLAY_GET_PRIVATE(display);
int scancode;
+#if 0
fprintf(stderr, "%s %s: keycode: %d state: %d group %d\n",
__FUNCTION__, key->type == GDK_KEY_PRESS ? "press" : "release",
key->hardware_keycode, key->state, key->group);
+#endif
if (!d->inputs)
return true;
@@ -635,7 +718,18 @@ static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion)
}
break;
case SPICE_MOUSE_MODE_SERVER:
- /* TODO */
+ if (d->mouse_grab_active) {
+ if (d->mouse_last_x != -1 &&
+ d->mouse_last_y != -1) {
+ spice_inputs_motion(d->inputs,
+ motion->x - d->mouse_last_x,
+ motion->y - d->mouse_last_y,
+ button_mask_gdk_to_spice(motion->state));
+ }
+ d->mouse_last_x = motion->x;
+ d->mouse_last_y = motion->y;
+ check_mouse_edges(widget, motion);
+ }
break;
default:
break;
@@ -654,9 +748,11 @@ static gboolean button_event(GtkWidget *widget, GdkEventButton *button)
button->button);
#endif
gtk_widget_grab_focus(widget);
+ try_mouse_grab(widget);
if (!d->inputs)
return true;
+
switch (button->type) {
case GDK_BUTTON_PRESS:
spice_inputs_button_press(d->inputs,
@@ -727,6 +823,18 @@ static void spice_display_class_init(SpiceDisplayClass *klass)
G_PARAM_STATIC_BLURB));
g_object_class_install_property
+ (gobject_class, PROP_MOUSE_GRAB,
+ g_param_spec_boolean("grab-mouse",
+ "Grab Mouse",
+ "Whether we should grab the mouse.",
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_NICK |
+ G_PARAM_STATIC_BLURB));
+
+ g_object_class_install_property
(gobject_class, PROP_RESIZE_GUEST,
g_param_spec_boolean("resize-guest",
"Resize guest",
@@ -750,7 +858,6 @@ static void mouse_mode(SpiceChannel *channel, enum SpiceMouseMode mode,
SpiceDisplay *display = data;
spice_display *d = SPICE_DISPLAY_GET_PRIVATE(display);
- fprintf(stderr, "%s: mouse mode: %d\n", __FUNCTION__, mode);
d->mouse_mode = mode;
}
@@ -781,7 +888,6 @@ static void primary_destroy(SpiceChannel *channel, gpointer data)
SpiceDisplay *display = SPICE_DISPLAY(data);
spice_display *d = SPICE_DISPLAY_GET_PRIVATE(display);
- fprintf(stderr, "%s:\n", __FUNCTION__);
d->format = 0;
d->width = 0;
d->height = 0;
@@ -894,3 +1000,7 @@ GtkWidget *spice_display_new(SpiceSession *session, int id)
return GTK_WIDGET(display);
}
+void spice_display_mouse_ungrab(GtkWidget *widget)
+{
+ try_mouse_ungrab(widget);
+}