On Thu, Sep 08, 2016 at 06:46:41PM +0800, Jonas Ådahl wrote: > Emulate pointer warps by locking the pointer and sending relative > motion events instead of absolute. X will keep track of the "fake" > pointer cursor position given the relative motion events, and the > client warping the cursor will warp the faked cursor position. > > Various requirements need to be met for the pointer warp emulator to > enable: > > The cursor must be invisible: since it would not be acceptable that a > fake cursor position would be different from the visual representation > of the cursor, emulation can only be done when there is no visual > representation done by the Wayland compositor. Thus, for the emulator > to enable, the cursor must be hidden, and would the cursor be displayed > while the emulator is active, the emulator would be destroyed. > > The window that is warped within must be likely to have pointer focus. > For example, warping outside of the window region will be ignored. > > The pointer warp emulator will disable itself once the fake cursor > position leaves the window region, or the cursor is made visible. > > This makes various games depending on pointer warping (such as 3D > first-person shooters and stategy games using click-to-drag-map like > things) work. > > Signed-off-by: Jonas Ådahl <jad...@gmail.com> > --- > hw/xwayland/xwayland-cursor.c | 7 ++ > hw/xwayland/xwayland-input.c | 267 > +++++++++++++++++++++++++++++++++++++++++- > hw/xwayland/xwayland.c | 27 +++++ > hw/xwayland/xwayland.h | 17 +++ > 4 files changed, 317 insertions(+), 1 deletion(-) > > diff --git a/hw/xwayland/xwayland-cursor.c b/hw/xwayland/xwayland-cursor.c > index 7d14a3d..20ddf6e 100644 > --- a/hw/xwayland/xwayland-cursor.c > +++ b/hw/xwayland/xwayland-cursor.c > @@ -168,12 +168,19 @@ xwl_set_cursor(DeviceIntPtr device, > ScreenPtr screen, CursorPtr cursor, int x, int y) > { > struct xwl_seat *xwl_seat; > + Bool cursor_visibility_changed; > > xwl_seat = device->public.devicePrivate; > if (xwl_seat == NULL) > return; > > + cursor_visibility_changed = !!xwl_seat->x_cursor ^ !!cursor; > + > xwl_seat->x_cursor = cursor; > + > + if (cursor_visibility_changed) > + xwl_seat_cursor_visibility_changed(xwl_seat); > + > xwl_seat_set_cursor(xwl_seat); > } > > diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c > index d73448a..aa67a00 100644 > --- a/hw/xwayland/xwayland-input.c > +++ b/hw/xwayland/xwayland-input.c > @@ -47,6 +47,21 @@ struct sync_pending { > }; > > static void > +xwl_pointer_warp_emulator_handle_motion(struct xwl_pointer_warp_emulator > *warp_emulator, > + double dx, > + double dy, > + double dx_unaccel, > + double dy_unaccel); > +static void > +xwl_pointer_warp_emulator_maybe_lock(struct xwl_pointer_warp_emulator > *warp_emulator, > + struct xwl_window *xwl_window, > + SpritePtr sprite, > + int x, int y); > + > +static void > +xwl_seat_destroy_confined_pointer(struct xwl_seat *xwl_seat); > + > +static void > xwl_pointer_control(DeviceIntPtr device, PtrCtrl *ctrl) > { > /* Nothing to do, dix handles all settings */ > @@ -320,6 +335,12 @@ pointer_handle_enter(void *data, struct wl_pointer > *pointer, > xwl_seat->cursor_frame_cb = NULL; > xwl_seat_set_cursor(xwl_seat); > } > + > + if (xwl_seat->pointer_warp_emulator) { > + xwl_pointer_warp_emulator_maybe_lock(xwl_seat->pointer_warp_emulator, > + xwl_seat->focus_window, > + NULL, 0, 0); > + } > } > > static void > @@ -340,8 +361,22 @@ dispatch_pointer_motion_event(struct xwl_seat *xwl_seat) > { > ValuatorMask mask; > > - if (xwl_seat->pending_pointer_event.has_absolute || > + if (xwl_seat->pointer_warp_emulator && > xwl_seat->pending_pointer_event.has_relative) { > + double dx; > + double dy; > + double dx_unaccel; > + double dy_unaccel; > + > + dx = xwl_seat->pending_pointer_event.dx; > + dy = xwl_seat->pending_pointer_event.dy; > + dx_unaccel = xwl_seat->pending_pointer_event.dx_unaccel; > + dy_unaccel = xwl_seat->pending_pointer_event.dy_unaccel; > + > xwl_pointer_warp_emulator_handle_motion(xwl_seat->pointer_warp_emulator, > + dx, dy, > + dx_unaccel, dy_unaccel); > + } else if (xwl_seat->pending_pointer_event.has_absolute || > + xwl_seat->pending_pointer_event.has_relative) { > int x; > int y; > > @@ -1236,6 +1271,233 @@ xwl_seat_clear_touch(struct xwl_seat *xwl_seat, > WindowPtr window) > } > } > > +static void > +xwl_pointer_warp_emulator_set_fake_pos(struct xwl_pointer_warp_emulator > *warp_emulator, > + int x, > + int y) > +{ > + struct zwp_locked_pointer_v1 *locked_pointer = > + warp_emulator->locked_pointer; > + WindowPtr window; > + int sx, sy; > + > + if (!warp_emulator->locked_pointer) > + return; > + > + window = warp_emulator->xwl_seat->focus_window->window; > + if (x >= window->drawable.x || > + y >= window->drawable.y || > + x < (window->drawable.x + window->drawable.width) || > + y < (window->drawable.x + window->drawable.height)) {
typo, drawable.y > + sx = x - window->drawable.x; > + sy = y - window->drawable.y; > + zwp_locked_pointer_v1_set_cursor_position_hint(locked_pointer, > + wl_fixed_from_int(sx), > + > wl_fixed_from_int(sy)); > + wl_surface_commit(warp_emulator->xwl_seat->focus_window->surface); > + } > +} > + > +static Bool > +xwl_pointer_warp_emulator_is_locked(struct xwl_pointer_warp_emulator > *warp_emulator) > +{ > + if (warp_emulator->locked_pointer) > + return TRUE; > + else > + return FALSE; > +} > + > +static void > +xwl_pointer_warp_emulator_lock(struct xwl_pointer_warp_emulator > *warp_emulator) > +{ > + struct xwl_seat *xwl_seat = warp_emulator->xwl_seat; > + struct xwl_screen *xwl_screen = xwl_seat->xwl_screen; > + struct zwp_pointer_constraints_v1 *pointer_constraints = > + xwl_screen->pointer_constraints; > + struct xwl_window *lock_window = xwl_seat->focus_window; > + > + warp_emulator->locked_window = lock_window; > + > + warp_emulator->locked_pointer = > + zwp_pointer_constraints_v1_lock_pointer(pointer_constraints, > + lock_window->surface, > + xwl_seat->wl_pointer, > + NULL, > + > ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); > +} > + > +static void > +xwl_pointer_warp_emulator_maybe_lock(struct xwl_pointer_warp_emulator > *warp_emulator, > + struct xwl_window *xwl_window, > + SpritePtr sprite, > + int x, int y) > +{ > + struct xwl_seat *xwl_seat = warp_emulator->xwl_seat; > + GrabPtr pointer_grab = xwl_seat->pointer->deviceGrab.grab; > + > + if (warp_emulator->locked_pointer) > + return; > + > + /* > + * If there is no grab, and the window doesn't have pointer focus, ignore > + * the warp, as under Wayland it won't receive input anyway. > + */ > + if (!pointer_grab && xwl_seat->focus_window != xwl_window) > + return; > + > + /* > + * If there is a grab, but it's not an ownerEvents grab and the > destination > + * is not the pointer focus, ignore it, as events wouldn't be delivered > + * there anyway. > + */ > + if (pointer_grab && > + !pointer_grab->ownerEvents && > + XYToWindow(sprite, x, y) != xwl_seat->focus_window->window) > + return; > + > + xwl_pointer_warp_emulator_lock(warp_emulator); > +} > + > +static void > +xwl_pointer_warp_emulator_warp(struct xwl_pointer_warp_emulator > *warp_emulator, > + struct xwl_window *xwl_window, > + SpritePtr sprite, > + int x, int y) > +{ > + xwl_pointer_warp_emulator_maybe_lock(warp_emulator, > + xwl_window, > + sprite, > + x, y); > + xwl_pointer_warp_emulator_set_fake_pos(warp_emulator, x, y); > +} > + > +static void > +xwl_pointer_warp_emulator_handle_motion(struct xwl_pointer_warp_emulator > *warp_emulator, > + double dx, > + double dy, > + double dx_unaccel, > + double dy_unaccel) > +{ > + struct xwl_seat *xwl_seat = warp_emulator->xwl_seat; > + ValuatorMask mask; > + WindowPtr window; > + int x, y; > + > + valuator_mask_zero(&mask); > + valuator_mask_set_unaccelerated(&mask, 0, dx, dx_unaccel); > + valuator_mask_set_unaccelerated(&mask, 1, dy, dy_unaccel); > + > + QueuePointerEvents(xwl_seat->relative_pointer, MotionNotify, 0, > + POINTER_RELATIVE, &mask); > + > + window = xwl_seat->focus_window->window; > + miPointerGetPosition(xwl_seat->pointer, &x, &y); > + > + if (xwl_pointer_warp_emulator_is_locked(warp_emulator) && > + xwl_seat->cursor_confinement_window != warp_emulator->locked_window > && > + (x < window->drawable.x || > + y < window->drawable.y || > + x >= (window->drawable.x + window->drawable.width) || > + y >= (window->drawable.x + window->drawable.height))) typo, drawable.y > + xwl_seat_destroy_pointer_warp_emulator(xwl_seat); > + else > + xwl_pointer_warp_emulator_set_fake_pos(warp_emulator, x, y); > +} > + > +static struct xwl_pointer_warp_emulator * > +xwl_pointer_warp_emulator_create(struct xwl_seat *xwl_seat) > +{ > + struct xwl_pointer_warp_emulator *warp_emulator; > + > + warp_emulator = calloc(sizeof *warp_emulator, 1); > + if (!warp_emulator) { > + ErrorF("xwl_pointer_warp_emulator_create ENOMEM"); use __func__ here please. Reviewed-by: Peter Hutterer <peter.hutte...@who-t.net> otherwise Cheers, Peter > + return NULL; > + } > + > + warp_emulator->xwl_seat = xwl_seat; > + > + return warp_emulator; > +} > + > +static void > +xwl_pointer_warp_emulator_destroy(struct xwl_pointer_warp_emulator > *warp_emulator) > +{ > + if (warp_emulator->locked_pointer) > + zwp_locked_pointer_v1_destroy(warp_emulator->locked_pointer); > + free(warp_emulator); > +} > + > +static void > +xwl_seat_create_pointer_warp_emulator(struct xwl_seat *xwl_seat) > +{ > + if (xwl_seat->confined_pointer) > + xwl_seat_destroy_confined_pointer(xwl_seat); > + > + xwl_seat->pointer_warp_emulator = > + xwl_pointer_warp_emulator_create(xwl_seat); > +} > + > +static Bool > +xwl_seat_can_emulate_pointer_warp(struct xwl_seat *xwl_seat) > +{ > + struct xwl_screen *xwl_screen = xwl_seat->xwl_screen; > + > + if (!xwl_screen->relative_pointer_manager) > + return FALSE; > + > + if (!xwl_screen->pointer_constraints) > + return FALSE; > + > + return TRUE; > +} > + > +void > +xwl_seat_emulate_pointer_warp(struct xwl_seat *xwl_seat, > + struct xwl_window *xwl_window, > + SpritePtr sprite, > + int x, int y) > +{ > + if (!xwl_seat_can_emulate_pointer_warp(xwl_seat)) > + return; > + > + if (xwl_seat->x_cursor != NULL) > + return; > + > + if (!xwl_seat->pointer_warp_emulator) > + xwl_seat_create_pointer_warp_emulator(xwl_seat); > + > + if (!xwl_seat->pointer_warp_emulator) > + return; > + > + xwl_pointer_warp_emulator_warp(xwl_seat->pointer_warp_emulator, > + xwl_window, > + sprite, > + x, y); > +} > + > +void > +xwl_seat_cursor_visibility_changed(struct xwl_seat *xwl_seat) > +{ > + if (xwl_seat->pointer_warp_emulator && xwl_seat->x_cursor != NULL) > + xwl_seat_destroy_pointer_warp_emulator(xwl_seat); > +} > + > +void > +xwl_seat_destroy_pointer_warp_emulator(struct xwl_seat *xwl_seat) > +{ > + if (!xwl_seat->pointer_warp_emulator) > + return; > + > + xwl_pointer_warp_emulator_destroy(xwl_seat->pointer_warp_emulator); > + xwl_seat->pointer_warp_emulator = NULL; > + > + if (xwl_seat->cursor_confinement_window) { > + xwl_seat_confine_pointer(xwl_seat, > + xwl_seat->cursor_confinement_window); > + } > +} > + > void > xwl_seat_confine_pointer(struct xwl_seat *xwl_seat, > struct xwl_window *xwl_window) > @@ -1253,6 +1515,9 @@ xwl_seat_confine_pointer(struct xwl_seat *xwl_seat, > > xwl_seat->cursor_confinement_window = xwl_window; > > + if (xwl_seat->pointer_warp_emulator) > + return; > + > xwl_seat->confined_pointer = > zwp_pointer_constraints_v1_confine_pointer(pointer_constraints, > xwl_window->surface, > diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c > index d22aba3..02c2250 100644 > --- a/hw/xwayland/xwayland.c > +++ b/hw/xwayland/xwayland.c > @@ -164,6 +164,28 @@ xwl_screen_get_default_seat(struct xwl_screen > *xwl_screen) > } > > static void > +xwl_cursor_warped_to(DeviceIntPtr device, > + ScreenPtr screen, > + ClientPtr client, > + WindowPtr window, > + SpritePtr sprite, > + int x, int y) > +{ > + struct xwl_screen *xwl_screen = xwl_screen_get(screen); > + struct xwl_seat *xwl_seat = device->public.devicePrivate; > + struct xwl_window *xwl_window; > + > + if (!xwl_seat) > + xwl_seat = xwl_screen_get_default_seat(xwl_screen); > + > + xwl_window = xwl_window_from_window(window); > + if (!xwl_window) > + return; > + > + xwl_seat_emulate_pointer_warp(xwl_seat, xwl_window, sprite, x, y); > +} > + > +static void > xwl_cursor_confined_to(DeviceIntPtr device, > ScreenPtr screen, > WindowPtr window) > @@ -383,6 +405,10 @@ xwl_unrealize_window(WindowPtr window) > if (xwl_seat->cursor_confinement_window && > xwl_seat->cursor_confinement_window->window == window) > xwl_seat_unconfine_pointer(xwl_seat); > + if (xwl_seat->pointer_warp_emulator && > + xwl_seat->pointer_warp_emulator->locked_window && > + xwl_seat->pointer_warp_emulator->locked_window->window == window) > + xwl_seat_destroy_pointer_warp_emulator(xwl_seat); > xwl_seat_clear_touch(xwl_seat, window); > } > > @@ -782,6 +808,7 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) > xwl_screen->CloseScreen = pScreen->CloseScreen; > pScreen->CloseScreen = xwl_close_screen; > > + pScreen->CursorWarpedTo = xwl_cursor_warped_to; > pScreen->CursorConfinedTo = xwl_cursor_confined_to; > > return ret; > diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h > index d62f49a..2e59d7f 100644 > --- a/hw/xwayland/xwayland.h > +++ b/hw/xwayland/xwayland.h > @@ -119,6 +119,12 @@ struct xwl_touch { > struct xorg_list link_touch; > }; > > +struct xwl_pointer_warp_emulator { > + struct xwl_seat *xwl_seat; > + struct xwl_window *locked_window; > + struct zwp_locked_pointer_v1 *locked_pointer; > +}; > + > struct xwl_seat { > DeviceIntPtr pointer; > DeviceIntPtr relative_pointer; > @@ -149,6 +155,8 @@ struct xwl_seat { > > struct xorg_list sync_pending; > > + struct xwl_pointer_warp_emulator *pointer_warp_emulator; > + > struct xwl_window *cursor_confinement_window; > struct zwp_confined_pointer_v1 *confined_pointer; > > @@ -190,6 +198,15 @@ void xwl_seat_destroy(struct xwl_seat *xwl_seat); > > void xwl_seat_clear_touch(struct xwl_seat *xwl_seat, WindowPtr window); > > +void xwl_seat_emulate_pointer_warp(struct xwl_seat *xwl_seat, > + struct xwl_window *xwl_window, > + SpritePtr sprite, > + int x, int y); > + > +void xwl_seat_destroy_pointer_warp_emulator(struct xwl_seat *xwl_seat); > + > +void xwl_seat_cursor_visibility_changed(struct xwl_seat *xwl_seat); > + > void xwl_seat_confine_pointer(struct xwl_seat *xwl_seat, > struct xwl_window *xwl_window); > void xwl_seat_unconfine_pointer(struct xwl_seat *xwl_seat); > -- > 2.7.4 _______________________________________________ xorg-devel@lists.x.org: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: https://lists.x.org/mailman/listinfo/xorg-devel