Commit bf1cabd1 authored by Alexandros Frantzis's avatar Alexandros Frantzis Committed by Alexandre Julliard

winewayland.drv: Implement ClipCursor.

Use the zwp_pointer_constraints_v1 protocol to implement cursor clipping. Note that Wayland only allows us to constrain the cursor within the extents of a particular target surface.
parent cf267c60
......@@ -6,6 +6,7 @@ UNIX_LIBS = -lwin32u $(WAYLAND_CLIENT_LIBS) $(XKBCOMMON_LIBS) $(XKBREGISTRY_LIBS
SOURCES = \
display.c \
dllmain.c \
pointer-constraints-unstable-v1.xml \
version.rc \
viewporter.xml \
vulkan.c \
......
......@@ -154,6 +154,11 @@ static void registry_handle_global(void *data, struct wl_registry *registry,
process_wayland.wl_subcompositor =
wl_registry_bind(registry, id, &wl_subcompositor_interface, 1);
}
else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0)
{
process_wayland.zwp_pointer_constraints_v1 =
wl_registry_bind(registry, id, &zwp_pointer_constraints_v1_interface, 1);
}
}
static void registry_handle_global_remove(void *data, struct wl_registry *registry,
......@@ -259,6 +264,11 @@ BOOL wayland_process_init(void)
ERR("Wayland compositor doesn't support wl_subcompositor\n");
return FALSE;
}
if (!process_wayland.zwp_pointer_constraints_v1)
{
ERR("Wayland compositor doesn't support zwp_pointer_constraints_v1\n");
return FALSE;
}
wayland_init_display_devices(FALSE);
......
......@@ -24,6 +24,7 @@
#include "config.h"
#include <assert.h>
#include <linux/input.h>
#undef SW_MAX /* Also defined in winuser.rh */
#include <math.h>
......@@ -245,6 +246,11 @@ void wayland_pointer_deinit(void)
struct wayland_pointer *pointer = &process_wayland.pointer;
pthread_mutex_lock(&pointer->mutex);
if (pointer->zwp_confined_pointer_v1)
{
zwp_confined_pointer_v1_destroy(pointer->zwp_confined_pointer_v1);
pointer->zwp_confined_pointer_v1 = NULL;
}
wl_pointer_release(pointer->wl_pointer);
pointer->wl_pointer = NULL;
pointer->focused_hwnd = NULL;
......@@ -578,6 +584,106 @@ static void wayland_set_cursor(HWND hwnd, HCURSOR hcursor, BOOL use_hcursor)
pthread_mutex_unlock(&pointer->mutex);
}
/**********************************************************************
* wayland_surface_calc_confine
*
* Calculates the pointer confine rect (in surface-local coords)
* for the specified clip rectangle (in screen coords using thread dpi).
*/
static void wayland_surface_calc_confine(struct wayland_surface *surface,
const RECT *clip, RECT *confine)
{
RECT window_clip;
TRACE("hwnd=%p clip=%s window=%s\n",
surface->hwnd, wine_dbgstr_rect(clip),
wine_dbgstr_rect(&surface->window.rect));
/* FIXME: surface->window.(client_)rect is in window dpi, whereas
* clip is in thread dpi. */
if (!intersect_rect(&window_clip, clip, &surface->window.rect))
{
SetRectEmpty(confine);
return;
}
OffsetRect(&window_clip,
-surface->window.rect.left,
-surface->window.rect.top);
wayland_surface_coords_from_window(surface,
window_clip.left, window_clip.top,
(int *)&confine->left, (int *)&confine->top);
wayland_surface_coords_from_window(surface,
window_clip.right, window_clip.bottom,
(int *)&confine->right, (int *)&confine->bottom);
}
/***********************************************************************
* wayland_pointer_update_constraint
*
* Enables/disables pointer confinement.
*
* Passing a NULL confine_rect disables all constraints.
*/
static void wayland_pointer_update_constraint(RECT *confine_rect,
struct wl_surface *wl_surface)
{
struct wayland_pointer *pointer = &process_wayland.pointer;
assert(!confine_rect || wl_surface);
if (confine_rect)
{
HWND hwnd = wl_surface_get_user_data(wl_surface);
struct wl_region *region;
region = wl_compositor_create_region(process_wayland.wl_compositor);
wl_region_add(region, confine_rect->left, confine_rect->top,
confine_rect->right - confine_rect->left,
confine_rect->bottom - confine_rect->top);
if (!pointer->zwp_confined_pointer_v1 || pointer->constraint_hwnd != hwnd)
{
if (pointer->zwp_confined_pointer_v1)
zwp_confined_pointer_v1_destroy(pointer->zwp_confined_pointer_v1);
pointer->zwp_confined_pointer_v1 =
zwp_pointer_constraints_v1_confine_pointer(
process_wayland.zwp_pointer_constraints_v1,
wl_surface,
pointer->wl_pointer,
region,
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
pointer->constraint_hwnd = hwnd;
}
else
{
zwp_confined_pointer_v1_set_region(pointer->zwp_confined_pointer_v1,
region);
}
TRACE("Confining to hwnd=%p wayland=%d,%d+%d,%d\n",
pointer->constraint_hwnd,
(int)confine_rect->left, (int)confine_rect->top,
(int)(confine_rect->right - confine_rect->left),
(int)(confine_rect->bottom - confine_rect->top));
wl_region_destroy(region);
}
else if (pointer->zwp_confined_pointer_v1)
{
TRACE("Unconfining from hwnd=%p\n", pointer->constraint_hwnd);
zwp_confined_pointer_v1_destroy(pointer->zwp_confined_pointer_v1);
pointer->zwp_confined_pointer_v1 = NULL;
pointer->constraint_hwnd = NULL;
}
}
void wayland_pointer_clear_constraint(void)
{
wayland_pointer_update_constraint(NULL, NULL);
}
/***********************************************************************
* WAYLAND_SetCursor
*/
......@@ -587,3 +693,38 @@ void WAYLAND_SetCursor(HWND hwnd, HCURSOR hcursor)
wayland_set_cursor(hwnd, hcursor, TRUE);
}
/***********************************************************************
* WAYLAND_ClipCursor
*/
BOOL WAYLAND_ClipCursor(const RECT *clip, BOOL reset)
{
struct wayland_pointer *pointer = &process_wayland.pointer;
struct wl_surface *wl_surface = NULL;
RECT confine_rect;
TRACE("clip=%s reset=%d\n", wine_dbgstr_rect(clip), reset);
if (clip)
{
struct wayland_surface *surface = NULL;
if ((surface = wayland_surface_lock_hwnd(NtUserGetForegroundWindow())))
{
wl_surface = surface->wl_surface;
wayland_surface_calc_confine(surface, clip, &confine_rect);
pthread_mutex_unlock(&surface->mutex);
}
}
/* Since we are running in the context of the foreground thread we know
* that the wl_surface of the foreground HWND will not be invalidated,
* so we can access it without having the surface lock. */
pthread_mutex_lock(&pointer->mutex);
wayland_pointer_update_constraint(wl_surface ? &confine_rect : NULL, wl_surface);
pthread_mutex_unlock(&pointer->mutex);
wl_display_flush(process_wayland.wl_display);
return TRUE;
}
......@@ -188,6 +188,8 @@ void wayland_surface_destroy(struct wayland_surface *surface)
process_wayland.pointer.focused_hwnd = NULL;
process_wayland.pointer.enter_serial = 0;
}
if (process_wayland.pointer.constraint_hwnd == surface->hwnd)
wayland_pointer_clear_constraint();
pthread_mutex_unlock(&process_wayland.pointer.mutex);
pthread_mutex_lock(&process_wayland.keyboard.mutex);
......
......@@ -29,6 +29,7 @@
#include <wayland-client.h>
#include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbregistry.h>
#include "pointer-constraints-unstable-v1-client-protocol.h"
#include "viewporter-client-protocol.h"
#include "xdg-output-unstable-v1-client-protocol.h"
#include "xdg-shell-client-protocol.h"
......@@ -89,7 +90,9 @@ struct wayland_cursor
struct wayland_pointer
{
struct wl_pointer *wl_pointer;
struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1;
HWND focused_hwnd;
HWND constraint_hwnd;
uint32_t enter_serial;
uint32_t button_serial;
struct wayland_cursor cursor;
......@@ -115,6 +118,7 @@ struct wayland
struct wl_shm *wl_shm;
struct wp_viewporter *wp_viewporter;
struct wl_subcompositor *wl_subcompositor;
struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1;
struct wayland_seat seat;
struct wayland_keyboard keyboard;
struct wayland_pointer pointer;
......@@ -280,6 +284,7 @@ void WAYLAND_ReleaseKbdTables(const KBDTABLES *);
void wayland_pointer_init(struct wl_pointer *wl_pointer);
void wayland_pointer_deinit(void);
void wayland_pointer_clear_constraint(void);
/**********************************************************************
* Helpers
......@@ -305,6 +310,7 @@ RGNDATA *get_region_data(HRGN region);
* USER driver functions
*/
BOOL WAYLAND_ClipCursor(const RECT *clip, BOOL reset);
LRESULT WAYLAND_DesktopWindowProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
void WAYLAND_DestroyWindow(HWND hwnd);
void WAYLAND_SetCursor(HWND hwnd, HCURSOR hcursor);
......
......@@ -31,6 +31,7 @@
static const struct user_driver_funcs waylanddrv_funcs =
{
.pClipCursor = WAYLAND_ClipCursor,
.pDesktopWindowProc = WAYLAND_DesktopWindowProc,
.pDestroyWindow = WAYLAND_DestroyWindow,
.pKbdLayerDescriptor = WAYLAND_KbdLayerDescriptor,
......
......@@ -194,6 +194,7 @@ static void wayland_win_data_update_wayland_surface(struct wayland_win_data *dat
struct wayland_surface *surface = data->wayland_surface;
HWND parent = NtUserGetAncestor(data->hwnd, GA_PARENT);
BOOL visible, xdg_visible;
RECT clip;
TRACE("hwnd=%p\n", data->hwnd);
......@@ -232,6 +233,11 @@ static void wayland_win_data_update_wayland_surface(struct wayland_win_data *dat
if (data->window_surface)
wayland_window_surface_update_wayland_surface(data->window_surface, surface);
/* Size/position changes affect the effective pointer constraint, so update
* it as needed. */
if (data->hwnd == NtUserGetForegroundWindow() && NtUserGetClipCursor(&clip))
NtUserClipCursor(&clip);
out:
TRACE("hwnd=%p surface=%p=>%p\n", data->hwnd, data->wayland_surface, surface);
data->wayland_surface = surface;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment