From 13578d60455b9200e9498172d96997cbd2ef2645 Mon Sep 17 00:00:00 2001 From: Alexandros Frantzis Date: Tue, 24 Oct 2023 15:40:00 +0300 Subject: [PATCH] winewayland.drv: Prepare to handle different coordinate spaces. Introduce and use functions to convert between the window logical and Wayland surface coordinate spaces. At the moment the two are the same but this will change with the introduction of scaling support. --- dlls/winewayland.drv/wayland_pointer.c | 36 ++++++++++++++++-------- dlls/winewayland.drv/wayland_surface.c | 51 +++++++++++++++++++++++++++------- dlls/winewayland.drv/waylanddrv.h | 6 ++++ dlls/winewayland.drv/window.c | 22 ++++++++++----- 4 files changed, 86 insertions(+), 29 deletions(-) diff --git a/dlls/winewayland.drv/wayland_pointer.c b/dlls/winewayland.drv/wayland_pointer.c index ff376882d73..025793c15d6 100644 --- a/dlls/winewayland.drv/wayland_pointer.c +++ b/dlls/winewayland.drv/wayland_pointer.c @@ -50,30 +50,42 @@ static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy) { INPUT input = {0}; - RECT window_rect; + RECT *window_rect; HWND hwnd; - int screen_x, screen_y; + POINT screen; + struct wayland_surface *surface; if (!(hwnd = wayland_pointer_get_focused_hwnd())) return; - if (!NtUserGetWindowRect(hwnd, &window_rect)) return; + if (!(surface = wayland_surface_lock_hwnd(hwnd))) return; - screen_x = round(wl_fixed_to_double(sx)) + window_rect.left; - screen_y = round(wl_fixed_to_double(sy)) + window_rect.top; + window_rect = &surface->window.rect; + + wayland_surface_coords_to_window(surface, + wl_fixed_to_double(sx), + wl_fixed_to_double(sy), + (int *)&screen.x, (int *)&screen.y); + screen.x += window_rect->left; + screen.y += window_rect->top; /* Sometimes, due to rounding, we may end up with pointer coordinates * slightly outside the target window, so bring them within bounds. */ - if (screen_x >= window_rect.right) screen_x = window_rect.right - 1; - else if (screen_x < window_rect.left) screen_x = window_rect.left; - if (screen_y >= window_rect.bottom) screen_y = window_rect.bottom - 1; - else if (screen_y < window_rect.top) screen_y = window_rect.top; + if (screen.x >= window_rect->right) screen.x = window_rect->right - 1; + else if (screen.x < window_rect->left) screen.x = window_rect->left; + if (screen.y >= window_rect->bottom) screen.y = window_rect->bottom - 1; + else if (screen.y < window_rect->top) screen.y = window_rect->top; + + pthread_mutex_unlock(&surface->mutex); + + /* Hardware input events are in physical coordinates. */ + if (!NtUserLogicalToPerMonitorDPIPhysicalPoint(hwnd, &screen)) return; input.type = INPUT_MOUSE; - input.mi.dx = screen_x; - input.mi.dy = screen_y; + input.mi.dx = screen.x; + input.mi.dy = screen.y; input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE; TRACE("hwnd=%p wayland_xy=%.2f,%.2f screen_xy=%d,%d\n", hwnd, wl_fixed_to_double(sx), wl_fixed_to_double(sy), - screen_x, screen_y); + (int)screen.x, (int)screen.y); __wine_send_input(hwnd, &input, NULL); } diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c index 8bda2a5420b..bd0b0839bcf 100644 --- a/dlls/winewayland.drv/wayland_surface.c +++ b/dlls/winewayland.drv/wayland_surface.c @@ -385,14 +385,11 @@ static void wayland_surface_get_rect_in_monitor(struct wayland_surface *surface, * * Sets the xdg_surface geometry */ -static void wayland_surface_reconfigure_geometry(struct wayland_surface *surface) +static void wayland_surface_reconfigure_geometry(struct wayland_surface *surface, + int width, int height) { - int width, height; RECT rect; - width = surface->window.rect.right - surface->window.rect.left; - height = surface->window.rect.bottom - surface->window.rect.top; - /* If the window size is bigger than the current state accepts, use the * largest visible (from Windows' perspective) subregion of the window. */ if ((surface->current.state & (WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED | @@ -401,6 +398,11 @@ static void wayland_surface_reconfigure_geometry(struct wayland_surface *surface { wayland_surface_get_rect_in_monitor(surface, &rect); + wayland_surface_coords_from_window(surface, rect.left, rect.top, + (int *)&rect.left, (int *)&rect.top); + wayland_surface_coords_from_window(surface, rect.right, rect.bottom, + (int *)&rect.right, (int *)&rect.bottom); + /* If the window rect in the monitor is smaller than required, * fall back to an appropriately sized rect at the top-left. */ if ((surface->current.state & WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED) && @@ -441,15 +443,18 @@ static void wayland_surface_reconfigure_geometry(struct wayland_surface *surface BOOL wayland_surface_reconfigure(struct wayland_surface *surface) { struct wayland_window_config *window = &surface->window; - int width, height; + int win_width, win_height, width, height; if (!surface->xdg_toplevel) return TRUE; - width = surface->window.rect.right - surface->window.rect.left; - height = surface->window.rect.bottom - surface->window.rect.top; + win_width = surface->window.rect.right - surface->window.rect.left; + win_height = surface->window.rect.bottom - surface->window.rect.top; + + wayland_surface_coords_from_window(surface, win_width, win_height, + &width, &height); TRACE("hwnd=%p window=%dx%d,%#x processing=%dx%d,%#x current=%dx%d,%#x\n", - surface->hwnd, width, height, window->state, + surface->hwnd, win_width, win_height, window->state, surface->processing.width, surface->processing.height, surface->processing.state, surface->current.width, surface->current.height, surface->current.state); @@ -484,7 +489,7 @@ BOOL wayland_surface_reconfigure(struct wayland_surface *surface) return FALSE; } - wayland_surface_reconfigure_geometry(surface); + wayland_surface_reconfigure_geometry(surface, width, height); return TRUE; } @@ -621,3 +626,29 @@ err: if (shm_buffer) wayland_shm_buffer_unref(shm_buffer); return NULL; } + +/********************************************************************** + * wayland_surface_coords_from_window + * + * Converts the window (logical) coordinates to wayland surface-local coordinates. + */ +void wayland_surface_coords_from_window(struct wayland_surface *surface, + int window_x, int window_y, + int *surface_x, int *surface_y) +{ + *surface_x = window_x; + *surface_y = window_y; +} + +/********************************************************************** + * wayland_surface_coords_to_window + * + * Converts the surface-local coordinates to window (logical) coordinates. + */ +void wayland_surface_coords_to_window(struct wayland_surface *surface, + double surface_x, double surface_y, + int *window_x, int *window_y) +{ + *window_x = round(surface_x); + *window_y = round(surface_y); +} diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 78ed68d3881..b9346c1443e 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -214,6 +214,12 @@ BOOL wayland_surface_reconfigure(struct wayland_surface *surface) DECLSPEC_HIDDE BOOL wayland_surface_config_is_compatible(struct wayland_surface_config *conf, int width, int height, enum wayland_surface_config_state state) DECLSPEC_HIDDEN; +void wayland_surface_coords_from_window(struct wayland_surface *surface, + int window_x, int window_y, + int *surface_x, int *surface_y) DECLSPEC_HIDDEN; +void wayland_surface_coords_to_window(struct wayland_surface *surface, + double surface_x, double surface_y, + int *window_x, int *window_y) DECLSPEC_HIDDEN; /********************************************************************** * Wayland SHM buffer diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index 57d2f15a06b..78022670a10 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -384,7 +384,8 @@ static void wayland_resize_desktop(void) static void wayland_configure_window(HWND hwnd) { struct wayland_surface *surface; - INT width, height; + INT width, height, window_width, window_height; + INT window_surf_width, window_surf_height; UINT flags = 0; uint32_t state; DWORD style; @@ -434,21 +435,28 @@ static void wayland_configure_window(HWND hwnd) flags |= SWP_FRAMECHANGED; } + wayland_surface_coords_from_window(surface, + surface->window.rect.right - + surface->window.rect.left, + surface->window.rect.bottom - + surface->window.rect.top, + &window_surf_width, &window_surf_height); + /* If the window is already fullscreen and its size is compatible with what * the compositor is requesting, don't force a resize, since some applications * are very insistent on a particular fullscreen size (which may not match * the monitor size). */ if ((surface->window.state & WAYLAND_SURFACE_CONFIG_STATE_FULLSCREEN) && wayland_surface_config_is_compatible(&surface->processing, - surface->window.rect.right - - surface->window.rect.left, - surface->window.rect.bottom - - surface->window.rect.top, + window_surf_width, window_surf_height, surface->window.state)) { flags |= SWP_NOSIZE; } + wayland_surface_coords_to_window(surface, width, height, + &window_width, &window_height); + pthread_mutex_unlock(&surface->mutex); TRACE("processing=%dx%d,%#x\n", width, height, state); @@ -457,7 +465,7 @@ static void wayland_configure_window(HWND hwnd) if (needs_exit_size_move) send_message(hwnd, WM_EXITSIZEMOVE, 0, 0); flags |= SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE; - if (width == 0 || height == 0) flags |= SWP_NOSIZE; + if (window_width == 0 || window_height == 0) flags |= SWP_NOSIZE; style = NtUserGetWindowLongW(hwnd, GWL_STYLE); if (!(state & WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED) != !(style & WS_MAXIMIZE)) @@ -474,7 +482,7 @@ static void wayland_configure_window(HWND hwnd) flags |= SWP_NOSENDCHANGING; } - NtUserSetWindowPos(hwnd, 0, 0, 0, width, height, flags); + NtUserSetWindowPos(hwnd, 0, 0, 0, window_width, window_height, flags); } /********************************************************************** -- 2.11.4.GIT