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 ...@@ -6,6 +6,7 @@ UNIX_LIBS = -lwin32u $(WAYLAND_CLIENT_LIBS) $(XKBCOMMON_LIBS) $(XKBREGISTRY_LIBS
SOURCES = \ SOURCES = \
display.c \ display.c \
dllmain.c \ dllmain.c \
pointer-constraints-unstable-v1.xml \
version.rc \ version.rc \
viewporter.xml \ viewporter.xml \
vulkan.c \ vulkan.c \
......
...@@ -154,6 +154,11 @@ static void registry_handle_global(void *data, struct wl_registry *registry, ...@@ -154,6 +154,11 @@ static void registry_handle_global(void *data, struct wl_registry *registry,
process_wayland.wl_subcompositor = process_wayland.wl_subcompositor =
wl_registry_bind(registry, id, &wl_subcompositor_interface, 1); 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, static void registry_handle_global_remove(void *data, struct wl_registry *registry,
...@@ -259,6 +264,11 @@ BOOL wayland_process_init(void) ...@@ -259,6 +264,11 @@ BOOL wayland_process_init(void)
ERR("Wayland compositor doesn't support wl_subcompositor\n"); ERR("Wayland compositor doesn't support wl_subcompositor\n");
return FALSE; 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); wayland_init_display_devices(FALSE);
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "config.h" #include "config.h"
#include <assert.h>
#include <linux/input.h> #include <linux/input.h>
#undef SW_MAX /* Also defined in winuser.rh */ #undef SW_MAX /* Also defined in winuser.rh */
#include <math.h> #include <math.h>
...@@ -245,6 +246,11 @@ void wayland_pointer_deinit(void) ...@@ -245,6 +246,11 @@ void wayland_pointer_deinit(void)
struct wayland_pointer *pointer = &process_wayland.pointer; struct wayland_pointer *pointer = &process_wayland.pointer;
pthread_mutex_lock(&pointer->mutex); 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); wl_pointer_release(pointer->wl_pointer);
pointer->wl_pointer = NULL; pointer->wl_pointer = NULL;
pointer->focused_hwnd = NULL; pointer->focused_hwnd = NULL;
...@@ -578,6 +584,106 @@ static void wayland_set_cursor(HWND hwnd, HCURSOR hcursor, BOOL use_hcursor) ...@@ -578,6 +584,106 @@ static void wayland_set_cursor(HWND hwnd, HCURSOR hcursor, BOOL use_hcursor)
pthread_mutex_unlock(&pointer->mutex); 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 * WAYLAND_SetCursor
*/ */
...@@ -587,3 +693,38 @@ void WAYLAND_SetCursor(HWND hwnd, HCURSOR hcursor) ...@@ -587,3 +693,38 @@ void WAYLAND_SetCursor(HWND hwnd, HCURSOR hcursor)
wayland_set_cursor(hwnd, hcursor, TRUE); 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) ...@@ -188,6 +188,8 @@ void wayland_surface_destroy(struct wayland_surface *surface)
process_wayland.pointer.focused_hwnd = NULL; process_wayland.pointer.focused_hwnd = NULL;
process_wayland.pointer.enter_serial = 0; 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_unlock(&process_wayland.pointer.mutex);
pthread_mutex_lock(&process_wayland.keyboard.mutex); pthread_mutex_lock(&process_wayland.keyboard.mutex);
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <wayland-client.h> #include <wayland-client.h>
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbregistry.h> #include <xkbcommon/xkbregistry.h>
#include "pointer-constraints-unstable-v1-client-protocol.h"
#include "viewporter-client-protocol.h" #include "viewporter-client-protocol.h"
#include "xdg-output-unstable-v1-client-protocol.h" #include "xdg-output-unstable-v1-client-protocol.h"
#include "xdg-shell-client-protocol.h" #include "xdg-shell-client-protocol.h"
...@@ -89,7 +90,9 @@ struct wayland_cursor ...@@ -89,7 +90,9 @@ struct wayland_cursor
struct wayland_pointer struct wayland_pointer
{ {
struct wl_pointer *wl_pointer; struct wl_pointer *wl_pointer;
struct zwp_confined_pointer_v1 *zwp_confined_pointer_v1;
HWND focused_hwnd; HWND focused_hwnd;
HWND constraint_hwnd;
uint32_t enter_serial; uint32_t enter_serial;
uint32_t button_serial; uint32_t button_serial;
struct wayland_cursor cursor; struct wayland_cursor cursor;
...@@ -115,6 +118,7 @@ struct wayland ...@@ -115,6 +118,7 @@ struct wayland
struct wl_shm *wl_shm; struct wl_shm *wl_shm;
struct wp_viewporter *wp_viewporter; struct wp_viewporter *wp_viewporter;
struct wl_subcompositor *wl_subcompositor; struct wl_subcompositor *wl_subcompositor;
struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1;
struct wayland_seat seat; struct wayland_seat seat;
struct wayland_keyboard keyboard; struct wayland_keyboard keyboard;
struct wayland_pointer pointer; struct wayland_pointer pointer;
...@@ -280,6 +284,7 @@ void WAYLAND_ReleaseKbdTables(const KBDTABLES *); ...@@ -280,6 +284,7 @@ void WAYLAND_ReleaseKbdTables(const KBDTABLES *);
void wayland_pointer_init(struct wl_pointer *wl_pointer); void wayland_pointer_init(struct wl_pointer *wl_pointer);
void wayland_pointer_deinit(void); void wayland_pointer_deinit(void);
void wayland_pointer_clear_constraint(void);
/********************************************************************** /**********************************************************************
* Helpers * Helpers
...@@ -305,6 +310,7 @@ RGNDATA *get_region_data(HRGN region); ...@@ -305,6 +310,7 @@ RGNDATA *get_region_data(HRGN region);
* USER driver functions * USER driver functions
*/ */
BOOL WAYLAND_ClipCursor(const RECT *clip, BOOL reset);
LRESULT WAYLAND_DesktopWindowProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); LRESULT WAYLAND_DesktopWindowProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
void WAYLAND_DestroyWindow(HWND hwnd); void WAYLAND_DestroyWindow(HWND hwnd);
void WAYLAND_SetCursor(HWND hwnd, HCURSOR hcursor); void WAYLAND_SetCursor(HWND hwnd, HCURSOR hcursor);
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
static const struct user_driver_funcs waylanddrv_funcs = static const struct user_driver_funcs waylanddrv_funcs =
{ {
.pClipCursor = WAYLAND_ClipCursor,
.pDesktopWindowProc = WAYLAND_DesktopWindowProc, .pDesktopWindowProc = WAYLAND_DesktopWindowProc,
.pDestroyWindow = WAYLAND_DestroyWindow, .pDestroyWindow = WAYLAND_DestroyWindow,
.pKbdLayerDescriptor = WAYLAND_KbdLayerDescriptor, .pKbdLayerDescriptor = WAYLAND_KbdLayerDescriptor,
......
...@@ -194,6 +194,7 @@ static void wayland_win_data_update_wayland_surface(struct wayland_win_data *dat ...@@ -194,6 +194,7 @@ static void wayland_win_data_update_wayland_surface(struct wayland_win_data *dat
struct wayland_surface *surface = data->wayland_surface; struct wayland_surface *surface = data->wayland_surface;
HWND parent = NtUserGetAncestor(data->hwnd, GA_PARENT); HWND parent = NtUserGetAncestor(data->hwnd, GA_PARENT);
BOOL visible, xdg_visible; BOOL visible, xdg_visible;
RECT clip;
TRACE("hwnd=%p\n", data->hwnd); TRACE("hwnd=%p\n", data->hwnd);
...@@ -232,6 +233,11 @@ static void wayland_win_data_update_wayland_surface(struct wayland_win_data *dat ...@@ -232,6 +233,11 @@ static void wayland_win_data_update_wayland_surface(struct wayland_win_data *dat
if (data->window_surface) if (data->window_surface)
wayland_window_surface_update_wayland_surface(data->window_surface, 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: out:
TRACE("hwnd=%p surface=%p=>%p\n", data->hwnd, data->wayland_surface, surface); TRACE("hwnd=%p surface=%p=>%p\n", data->hwnd, data->wayland_surface, surface);
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