[Spice-devel] [PATCH spice-gtk] win32: clip and move cursor within window region
Christophe Fergeau
cfergeau at redhat.com
Thu Nov 15 03:18:18 PST 2012
Looks good,
On Wed, Nov 14, 2012 at 03:21:36PM +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).
>
> v2:
> - choose the nearest monitor for clipping
> - the ClipRegion is in Windows coordinate, we can't use gdk warp
> - fix https://bugzilla.redhat.com/show_bug.cgi?id=872640
Minor nit, this should not be in the commit log, but below the --- so that
it's there for the reviewer, but does not end in git history. But thanks
for adding such a log :)
ACK
Christophe
>
> 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 | 90 ++++++++++++++++++++++++++++++++++++++++++------------
> 1 file changed, 71 insertions(+), 19 deletions(-)
>
> diff --git a/gtk/spice-widget.c b/gtk/spice-widget.c
> index 1858499..fd4d9e6 100644
> --- a/gtk/spice-widget.c
> +++ b/gtk/spice-widget.c
> @@ -725,17 +725,66 @@ static void set_mouse_accel(SpiceDisplay *display, gboolean enabled)
> #endif
> }
>
> +#ifdef WIN32
> +static gboolean win32_clip_cursor(void)
> +{
> + RECT window, workarea, rect;
> + HMONITOR monitor;
> + MONITORINFO mi = { 0, };
> +
> + g_return_val_if_fail(win32_window != NULL, FALSE);
> +
> + if (!GetWindowRect(win32_window, &window))
> + goto error;
> +
> + monitor = MonitorFromRect(&window, MONITOR_DEFAULTTONEAREST);
> + g_return_val_if_fail(monitor != NULL, false);
> +
> + mi.cbSize = sizeof(mi);
> + if (!GetMonitorInfo(monitor, &mi))
> + goto error;
> + workarea = mi.rcWork;
> +
> + if (!IntersectRect(&rect, &window, &workarea)) {
> + g_critical("error clipping cursor");
> + 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
> @@ -761,22 +810,11 @@ 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
>
> if (status == GDK_GRAB_SUCCESS)
> set_mouse_accel(display, FALSE);
>
> +end:
> gdk_cursor_unref(blank);
> return status;
> }
> @@ -835,10 +873,21 @@ static void try_mouse_grab(SpiceDisplay *display)
> 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;
> + /* the clip rectangle has no offset, so we can't use gdk_wrap_pointer */
> + SetCursorPos(xr, yr);
> + d->mouse_last_x = -1;
> + d->mouse_last_y = -1;
> +#else
> + GdkScreen *screen = gtk_widget_get_screen(GTK_WIDGET(display));
> + xr = gdk_screen_get_width(screen) / 2;
> + yr = gdk_screen_get_height(screen) / 2;
>
> if (xr != (gint)motion->x_root || yr != (gint)motion->y_root) {
> /* FIXME: we try our best to ignore that next pointer move event.. */
> @@ -849,6 +898,8 @@ static void mouse_wrap(SpiceDisplay *display, GdkEventMotion *motion)
> d->mouse_last_x = -1;
> d->mouse_last_y = -1;
> }
> +#endif
> +
> }
>
> static void try_mouse_ungrab(SpiceDisplay *display)
> @@ -1409,7 +1460,8 @@ static gboolean motion_event(GtkWidget *widget, GdkEventMotion *motion)
>
> d->mouse_last_x = x;
> d->mouse_last_y = y;
> - mouse_wrap(display, motion);
> + if (dx != 0 || dy != 0)
> + mouse_wrap(display, motion);
> }
> break;
> default:
> --
> 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/20121115/ca5b2c20/attachment-0001.pgp>
More information about the Spice-devel
mailing list