From 9aae258aeb3271fbd1e571fc0da799473f90ff57 Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Fri, 15 May 2026 14:02:18 -0400 Subject: [PATCH] wayland: Adjust DnD coordinates when dragging over a mask subsurface --- src/video/wayland/SDL_waylanddatamanager.h | 1 + src/video/wayland/SDL_waylandevents.c | 34 ++++++++++++++++++---- src/video/wayland/SDL_waylandwindow.c | 10 ++++--- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/video/wayland/SDL_waylanddatamanager.h b/src/video/wayland/SDL_waylanddatamanager.h index 1ac0dbfc2f..c9bc93d1f9 100644 --- a/src/video/wayland/SDL_waylanddatamanager.h +++ b/src/video/wayland/SDL_waylanddatamanager.h @@ -98,6 +98,7 @@ struct SDL_WaylandDataDevice const char *mime_type; bool has_mime_file, has_mime_text; SDL_Window *dnd_window; + struct wl_surface *dnd_surface; // Clipboard and Primary Selection uint32_t selection_serial; diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index 7d0fef62dc..b38ef441db 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -2843,9 +2843,20 @@ static void data_device_handle_enter(void *data, struct wl_data_device *wl_data_ // Set the destination window and send the initial position. data_device->dnd_window = window->sdlwindow; - const float dx = (float)(wl_fixed_to_double(x) * data_device->dnd_window->internal->pointer_scale.x); - const float dy = (float)(wl_fixed_to_double(y) * data_device->dnd_window->internal->pointer_scale.y); - SDL_SendDropPosition(data_device->dnd_window, dx, dy); + data_device->dnd_surface = surface; + double dx = wl_fixed_to_double(x); + double dy = wl_fixed_to_double(y); + + // If over the mask, adjust the offset. + if (surface == window->mask.surface) { + dx += (double)window->mask.offset_x; + dy += (double)window->mask.offset_y; + } + + dx *= window->pointer_scale.x; + dy *= window->pointer_scale.y; + + SDL_SendDropPosition(data_device->dnd_window, (float)dx, (float)dy); SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, ". In wl_data_device_listener . data_device_handle_enter on data_offer 0x%08x at %d x %d into window %d for serial %d", WAYLAND_wl_proxy_get_id((struct wl_proxy *)id), @@ -2863,6 +2874,7 @@ static void data_device_handle_enter(void *data, struct wl_data_device *wl_data_ } } else { data_device->dnd_window = NULL; + data_device->dnd_surface = NULL; // Decline the offer. if (id) { @@ -2912,14 +2924,24 @@ static void data_device_handle_motion(void *data, struct wl_data_device *wl_data SDL_WaylandDataDevice *data_device = data; if (data_device->drag_offer && data_device->dnd_window && (data_device->has_mime_file || data_device->has_mime_text)) { - const float dx = (float)(wl_fixed_to_double(x) * data_device->dnd_window->internal->pointer_scale.x); - const float dy = (float)(wl_fixed_to_double(y) * data_device->dnd_window->internal->pointer_scale.y); + SDL_WindowData *window_data = data_device->dnd_window->internal; + double dx = wl_fixed_to_double(x); + double dy = wl_fixed_to_double(y); + + // If over the mask, adjust the offset. + if (data_device->dnd_surface == window_data->mask.surface) { + dx += (double)window_data->mask.offset_x; + dy += (double)window_data->mask.offset_y; + } + + dx *= window_data->pointer_scale.x; + dy *= window_data->pointer_scale.y; /* XXX: Send the filename here if the event system ever starts passing it though. * Any future implementation should cache the filenames, as otherwise this could * hammer the DBus interface hundreds or even thousands of times per second. */ - SDL_SendDropPosition(data_device->dnd_window, dx, dy); + SDL_SendDropPosition(data_device->dnd_window, (float)dx, (float)dy); SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, ". In wl_data_device_listener . data_device_handle_motion on data_offer 0x%08x at %d x %d in window %d serial %d", WAYLAND_wl_proxy_get_id((struct wl_proxy *)data_device->drag_offer->offer), diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index d7e70c63c4..dda72ce311 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -543,14 +543,16 @@ static void ConfigureWindowGeometry(SDL_Window *window) SetSurfaceOpaqueRegion(data->mask.surface, 0, 0); } - data->mask.offset_x = -(data->current.logical_width - viewport_width) / 2; - data->mask.offset_y = -(data->current.logical_height - viewport_height) / 2; - // Can't use an offset subsurface with libdecor (yet), or the decorations won't line up properly. if (data->shell_surface_type != WAYLAND_SHELL_SURFACE_TYPE_LIBDECOR) { - wl_subsurface_set_position(data->mask.subsurface, data->mask.offset_x, data->mask.offset_y); + data->mask.offset_x = -(data->current.logical_width - viewport_width) / 2; + data->mask.offset_y = -(data->current.logical_height - viewport_height) / 2; + } else { + data->mask.offset_x = 0; + data->mask.offset_y = 0; } + wl_subsurface_set_position(data->mask.subsurface, data->mask.offset_x, data->mask.offset_y); wl_surface_commit(data->mask.surface); if (old_buffer) {