diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index d2d492afbc..7d0fef62dc 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -2798,15 +2798,18 @@ static void data_device_handle_enter(void *data, struct wl_data_device *wl_data_ wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *id) { SDL_WaylandDataDevice *data_device = data; + SDL_WindowData *window = surface ? Wayland_GetWindowDataForOwnedSurface(surface) : NULL; data_device->has_mime_file = false; data_device->has_mime_text = false; - uint32_t dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; data_device->drag_serial = serial; + // Save the drag offer so it can be freed later. if (id) { data_device->drag_offer = wl_data_offer_get_user_data(id); + } + if (data_device->drag_offer && window && window->accepts_drag_and_drop) { // TODO: SDL Support more mime types #ifdef SDL_USE_LIBDBUS if (Wayland_data_offer_has_mime(data_device->drag_offer, FILE_PORTAL_MIME)) { @@ -2832,48 +2835,46 @@ static void data_device_handle_enter(void *data, struct wl_data_device *wl_data_ } } - // SDL only supports "copy" style drag and drop if (data_device->has_mime_file || data_device->has_mime_text) { - dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; - } else { - // drag_mime is NULL this will decline the offer - wl_data_offer_accept(id, serial, NULL); - } - if (wl_data_offer_get_version(data_device->drag_offer->offer) >= - WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION) { - wl_data_offer_set_actions(data_device->drag_offer->offer, - dnd_action, dnd_action); - } - - // find the current window - if (surface) { - SDL_WindowData *window = Wayland_GetWindowDataForOwnedSurface(surface); - if (window) { - data_device->dnd_window = window->sdlwindow; - const float dx = (float)wl_fixed_to_double(x); - const float dy = (float)wl_fixed_to_double(y); - SDL_SendDropPosition(data_device->dnd_window, dx, 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), - wl_fixed_to_int(x), wl_fixed_to_int(y), SDL_GetWindowID(data_device->dnd_window), serial); - } else { - data_device->dnd_window = NULL; - SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, - ". In wl_data_device_listener . data_device_handle_enter on data_offer 0x%08x at %d x %d for serial %d", - WAYLAND_wl_proxy_get_id((struct wl_proxy *)id), - wl_fixed_to_int(x), wl_fixed_to_int(y), serial); + // SDL only supports "copy" style drag and drop + if (wl_data_offer_get_version(data_device->drag_offer->offer) >= WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION) { + wl_data_offer_set_actions(data_device->drag_offer->offer, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY); } + + // 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); + 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), + wl_fixed_to_int(x), wl_fixed_to_int(y), SDL_GetWindowID(data_device->dnd_window), serial); } else { + // Decline the offer. + wl_data_offer_accept(id, serial, NULL); + if (wl_data_offer_get_version(data_device->drag_offer->offer) >= WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION) { + wl_data_offer_set_actions(data_device->drag_offer->offer, WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE, WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE); + } + SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, ". In wl_data_device_listener . data_device_handle_enter on data_offer 0x%08x at %d x %d for serial %d", - WAYLAND_wl_proxy_get_id((struct wl_proxy *)id), - wl_fixed_to_int(x), wl_fixed_to_int(y), serial); + WAYLAND_wl_proxy_get_id((struct wl_proxy *)id), wl_fixed_to_int(x), wl_fixed_to_int(y), serial); } } else { + data_device->dnd_window = NULL; + + // Decline the offer. + if (id) { + wl_data_offer_accept(id, serial, NULL); + if (wl_data_offer_get_version(data_device->drag_offer->offer) >= WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION) { + wl_data_offer_set_actions(data_device->drag_offer->offer, WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE, WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE); + } + } SDL_LogTrace(SDL_LOG_CATEGORY_INPUT, ". In wl_data_device_listener . data_device_handle_enter on data_offer 0x%08x at %d x %d for serial %d", - -1, wl_fixed_to_int(x), wl_fixed_to_int(y), serial); + id ? WAYLAND_wl_proxy_get_id((struct wl_proxy *)id) : -1, + wl_fixed_to_int(x), wl_fixed_to_int(y), serial); } } @@ -2911,8 +2912,8 @@ 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); - const float dy = (float)wl_fixed_to_double(y); + 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); /* 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 diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c index 2a29d632c9..f3facbd7f0 100644 --- a/src/video/wayland/SDL_waylandvideo.c +++ b/src/video/wayland/SDL_waylandvideo.c @@ -732,6 +732,7 @@ static SDL_VideoDevice *Wayland_CreateDevice(bool require_preferred_protocols) device->SyncWindow = Wayland_SyncWindow; device->SetWindowFocusable = Wayland_SetWindowFocusable; device->ReconfigureWindow = Wayland_ReconfigureWindow; + device->AcceptDragAndDrop = Wayland_AcceptDragAndDrop; #ifdef SDL_USE_LIBDBUS if (SDL_SystemTheme_Init()) diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index 10d4524fa2..d7e70c63c4 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -3426,6 +3426,11 @@ bool Wayland_SyncWindow(SDL_VideoDevice *_this, SDL_Window *window) return true; } +void Wayland_AcceptDragAndDrop(SDL_Window *window, bool accept) +{ + window->internal->accepts_drag_and_drop = accept; +} + bool Wayland_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, bool focusable) { if (window->flags & SDL_WINDOW_POPUP_MENU) { diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h index e061855352..b9d0a257e2 100644 --- a/src/video/wayland/SDL_waylandwindow.h +++ b/src/video/wayland/SDL_waylandwindow.h @@ -234,6 +234,7 @@ struct SDL_WindowData bool scale_to_display; bool reparenting_required; bool double_buffer; + bool accepts_drag_and_drop; SDL_HitTestResult hit_test_result; @@ -271,6 +272,7 @@ extern bool Wayland_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SD extern bool Wayland_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, bool focusable); extern float Wayland_GetWindowContentScale(SDL_VideoDevice *_this, SDL_Window *window); extern void *Wayland_GetWindowICCProfile(SDL_VideoDevice *_this, SDL_Window *window, size_t *size); +extern void Wayland_AcceptDragAndDrop(SDL_Window *window, bool accept); extern bool Wayland_SetWindowHitTest(SDL_Window *window, bool enabled); extern bool Wayland_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);