Windows grab do not exist like on X11, so we need to clip the cursor to our client window, while making sure it doesn't overlap with windows statusbar. When wrapping the cursor, we need to make sure we also stay within the clip region, or else the clip is inverted (pointer can't enter the clip region anymore), and we also lose the keyboard hook/grab. The end result works better than spicec, which didn't exclude the Windows statusbar, and was subject to losing pointer when wrapping mouse over it. Another approach I have been playing with is to clip the cursor, and process raw input messages, this will have the advantage to work even when the client is completely out of the working area (under the statusbar for example), but the complexity involved is too high for very poor benefit (interacting with a non-visible client), we could even argue that the behaviour implemented by this patch is more correct (it refuses to grab the cursor if the client isn't visible in the working area). This solves the following bugs: https://bugzilla.redhat.com/show_bug.cgi?id=857430 https://bugzilla.redhat.com/show_bug.cgi?id=857389 --- gtk/spice-widget.c | 69 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 51 insertions(+), 18 deletions(-) diff --git a/gtk/spice-widget.c b/gtk/spice-widget.c index 023ec5e..63f8425 100644 --- a/gtk/spice-widget.c +++ b/gtk/spice-widget.c @@ -599,17 +599,57 @@ static void update_keyboard_grab(SpiceDisplay *display) try_keyboard_ungrab(display); } +#ifdef WIN32 +static gboolean win32_clip_cursor(void) +{ + RECT window, workarea, rect; + + g_return_val_if_fail(win32_window != NULL, FALSE); + + if (!GetWindowRect(win32_window, &window)) + goto error; + + if (!SystemParametersInfo(SPI_GETWORKAREA, 0, &workarea, 0)) + goto error; + + if (!IntersectRect(&rect, &window, &workarea)) + return false; + + SPICE_DEBUG("clip rect %ld %ld %ld %ld\n", + rect.left, rect.right, rect.top, rect.bottom); + + if (!ClipCursor(&rect)) + goto error; + + return true; + +error: + { + DWORD errval = GetLastError(); + gchar *errstr = g_win32_error_message(errval); + g_warning("failed to clip cursor (%ld) %s", errval, errstr); + } + + return false; +} +#endif + static GdkGrabStatus do_pointer_grab(SpiceDisplay *display) { SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); GdkWindow *window = GDK_WINDOW(gtk_widget_get_window(GTK_WIDGET(display))); - GdkGrabStatus status; + GdkGrabStatus status = GDK_GRAB_BROKEN; GdkCursor *blank = get_blank_cursor(); if (!gtk_widget_get_realized(GTK_WIDGET(display))) - return GDK_GRAB_BROKEN; - try_keyboard_grab(display); + goto end; + +#ifdef WIN32 + if (!win32_clip_cursor()) + goto end; +#endif + try_keyboard_grab(display); /* * from gtk-vnc: * For relative mouse to work correctly when grabbed we need to @@ -635,18 +675,6 @@ static GdkGrabStatus do_pointer_grab(SpiceDisplay *display) d->mouse_grab_active = true; g_signal_emit(display, signals[SPICE_DISPLAY_MOUSE_GRAB], 0, true); } -#ifdef WIN32 - { - RECT client_rect; - POINT origin; - - origin.x = origin.y = 0; - ClientToScreen(focus_window, &origin); - GetClientRect(focus_window, &client_rect); - OffsetRect(&client_rect, origin.x, origin.y); - ClipCursor(&client_rect); - } -#endif #ifdef GDK_WINDOWING_X11 if (status == GDK_GRAB_SUCCESS) { @@ -663,6 +691,7 @@ static GdkGrabStatus do_pointer_grab(SpiceDisplay *display) } #endif +end: gdk_cursor_unref(blank); return status; } @@ -722,10 +751,14 @@ static void mouse_wrap(SpiceDisplay *display, GdkEventMotion *motion) { SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display); GdkScreen *screen = gtk_widget_get_screen(GTK_WIDGET(display)); + gint xr, yr; - gint xr = gdk_screen_get_width(screen) / 2; - gint yr = gdk_screen_get_height(screen) / 2; - +#ifdef WIN32 + RECT clip; + g_return_if_fail(GetClipCursor(&clip)); + xr = clip.left + (clip.right - clip.left) / 2; + yr = clip.top + (clip.bottom - clip.top) / 2; +#endif if (xr != (gint)motion->x_root || yr != (gint)motion->y_root) { /* FIXME: we try our best to ignore that next pointer move event.. */ gdk_display_sync(gdk_screen_get_display(screen)); -- 1.7.11.7 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel