[Spice-devel] [PATCH spice-gtk 3/3] win32: clip and move cursor within window region
Christophe Fergeau
cfergeau at redhat.com
Tue Nov 13 08:48:34 PST 2012
On Wed, Oct 31, 2012 at 04:51:05PM +0100, Marc-André Lureau wrote:
> 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) {
xr and yr are no longer initialized at this point on !WIN32
Patch looks good otherwise.
Christophe
> /* 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 at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.freedesktop.org/archives/spice-devel/attachments/20121113/1822ef26/attachment.pgp>
More information about the Spice-devel
mailing list