[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