Просмотр исходного кода

wayland: Adjust DnD coordinates when dragging over a mask subsurface

Frank Praznik 4 дней назад
Родитель
Сommit
9aae258aeb

+ 1 - 0
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;

+ 28 - 6
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),

+ 6 - 4
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) {