diff options
Diffstat (limited to 'gtk/spice-widget.c')
-rw-r--r-- | gtk/spice-widget.c | 122 |
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); +} |