diff --git a/src/video/wayland/SDL_waylanddatamanager.c b/src/video/wayland/SDL_waylanddatamanager.c index 0fab6fe21f..dd0b8aeb71 100644 --- a/src/video/wayland/SDL_waylanddatamanager.c +++ b/src/video/wayland/SDL_waylanddatamanager.c @@ -381,6 +381,9 @@ void *Wayland_data_offer_receive(SDL_WaylandDataOffer *offer, } close(pipefd[0]); } + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + ". In Wayland_data_offer_receive for '%s', buffer (%ld) at %p\n", + mime_type, *length, buffer); return buffer; } @@ -414,6 +417,9 @@ void *Wayland_primary_selection_offer_receive(SDL_WaylandPrimarySelectionOffer * } close(pipefd[0]); } + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + ". In Wayland_primary_selection_offer_receive for '%s', buffer (%ld) at %p\n", + mime_type, *length, buffer); return buffer; } diff --git a/src/video/wayland/SDL_waylanddatamanager.h b/src/video/wayland/SDL_waylanddatamanager.h index 19fbc004ee..6b0f880adc 100644 --- a/src/video/wayland/SDL_waylanddatamanager.h +++ b/src/video/wayland/SDL_waylanddatamanager.h @@ -85,6 +85,7 @@ typedef struct uint32_t drag_serial; SDL_WaylandDataOffer *drag_offer; SDL_WaylandDataOffer *selection_offer; + SDL_bool has_mime_file, has_mime_text; SDL_Window *dnd_window; /* Clipboard and Primary Selection */ diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index 3ec8d90ce3..76e9856be3 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -1956,16 +1956,28 @@ static void data_offer_handle_offer(void *data, struct wl_data_offer *wl_data_of { SDL_WaylandDataOffer *offer = data; Wayland_data_offer_add_mime(offer, mime_type); + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + ". In wl_data_offer_listener . data_offer_handle_offer on data_offer 0x%08x for MIME '%s'\n", + (wl_data_offer ? WAYLAND_wl_proxy_get_id((struct wl_proxy *) wl_data_offer) : -1), + mime_type); } static void data_offer_handle_source_actions(void *data, struct wl_data_offer *wl_data_offer, uint32_t source_actions) { + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + ". In wl_data_offer_listener . data_offer_handle_source_actions on data_offer 0x%08x for Source Actions '%d'\n", + (wl_data_offer ? WAYLAND_wl_proxy_get_id((struct wl_proxy *) wl_data_offer) : -1), + source_actions); } static void data_offer_handle_actions(void *data, struct wl_data_offer *wl_data_offer, uint32_t dnd_action) { + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + ". In wl_data_offer_listener . data_offer_handle_actions on data_offer 0x%08x for DND Actions '%d'\n", + (wl_data_offer ? WAYLAND_wl_proxy_get_id((struct wl_proxy *) wl_data_offer) : -1), + dnd_action); } static const struct wl_data_offer_listener data_offer_listener = { @@ -1979,6 +1991,10 @@ static void primary_selection_offer_handle_offer(void *data, struct zwp_primary_ { SDL_WaylandPrimarySelectionOffer *offer = data; Wayland_primary_selection_offer_add_mime(offer, mime_type); + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + ". In zwp_primary_selection_offer_v1_listener . primary_selection_offer_handle_offer on primary_selection_offer 0x%08x for MIME '%s'\n", + (zwp_primary_selection_offer_v1 ? WAYLAND_wl_proxy_get_id((struct wl_proxy *) zwp_primary_selection_offer_v1) : -1), + mime_type); } static const struct zwp_primary_selection_offer_v1_listener primary_selection_offer_listener = { @@ -1995,6 +2011,9 @@ static void data_device_handle_data_offer(void *data, struct wl_data_device *wl_ WAYLAND_wl_list_init(&(data_offer->mimes)); wl_data_offer_set_user_data(id, data_offer); wl_data_offer_add_listener(id, &data_offer_listener, data_offer); + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + ". In wl_data_device_listener . data_device_handle_data_offer on data_offer 0x%08x\n", + (id ? WAYLAND_wl_proxy_get_id((struct wl_proxy *) id) : -1)); } } @@ -2003,7 +2022,8 @@ 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_bool has_mime = SDL_FALSE; + data_device->has_mime_file = SDL_FALSE; + data_device->has_mime_text = SDL_FALSE; uint32_t dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE; data_device->drag_serial = serial; @@ -2014,17 +2034,23 @@ static void data_device_handle_enter(void *data, struct wl_data_device *wl_data_ /* TODO: SDL Support more mime types */ #ifdef SDL_USE_LIBDBUS if (Wayland_data_offer_has_mime(data_device->drag_offer, FILE_PORTAL_MIME)) { - has_mime = SDL_TRUE; + data_device->has_mime_file = SDL_TRUE; wl_data_offer_accept(id, serial, FILE_PORTAL_MIME); } #endif if (Wayland_data_offer_has_mime(data_device->drag_offer, FILE_MIME)) { - has_mime = SDL_TRUE; + data_device->has_mime_file = SDL_TRUE; wl_data_offer_accept(id, serial, FILE_MIME); } + if (Wayland_data_offer_has_mime(data_device->drag_offer, TEXT_MIME)) { + data_device->has_mime_text = SDL_TRUE; + wl_data_offer_accept(id, serial, TEXT_MIME); + } + /* SDL only supports "copy" style drag and drop */ - if (has_mime) { + if (data_device->has_mime_file == SDL_TRUE || + data_device->has_mime_text == SDL_TRUE) { dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY; } else { /* drag_mime is NULL this will decline the offer */ @@ -2041,10 +2067,30 @@ static void data_device_handle_enter(void *data, struct wl_data_device *wl_data_ 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_LogDebug(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\n", + 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_LogDebug(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\n", + WAYLAND_wl_proxy_get_id((struct wl_proxy *) id), + wl_fixed_to_int(x), wl_fixed_to_int(y), serial); } + } else { + SDL_LogDebug(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\n", + WAYLAND_wl_proxy_get_id((struct wl_proxy *) id), + wl_fixed_to_int(x), wl_fixed_to_int(y), serial); } + } else { + SDL_LogDebug(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\n", + -1, wl_fixed_to_int(x), wl_fixed_to_int(y), serial); } } @@ -2053,9 +2099,26 @@ static void data_device_handle_leave(void *data, struct wl_data_device *wl_data_ SDL_WaylandDataDevice *data_device = data; if (data_device->drag_offer) { + if (data_device->dnd_window) { + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + ". In wl_data_device_listener . data_device_handle_leave on data_offer 0x%08x from window %d for serial %d\n", + WAYLAND_wl_proxy_get_id((struct wl_proxy *) data_device->drag_offer->offer), + SDL_GetWindowID(data_device->dnd_window), data_device->drag_serial); + } else { + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + ". In wl_data_device_listener . data_device_handle_leave on data_offer 0x%08x for serial %d\n", + WAYLAND_wl_proxy_get_id((struct wl_proxy *) data_device->drag_offer->offer), + data_device->drag_serial); + } Wayland_data_offer_destroy(data_device->drag_offer); data_device->drag_offer = NULL; + } else { + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + ". In wl_data_device_listener . data_device_handle_leave on data_offer 0x%08x for serial %d\n", + -1, -1); } + data_device->has_mime_file = SDL_FALSE; + data_device->has_mime_text = SDL_FALSE; } static void data_device_handle_motion(void *data, struct wl_data_device *wl_data_device, @@ -2063,7 +2126,9 @@ 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) { + if (data_device->drag_offer && data_device->dnd_window && + (data_device->has_mime_file == SDL_TRUE || + data_device->has_mime_text == SDL_TRUE)) { const float dx = (float)wl_fixed_to_double(x); const float dy = (float)wl_fixed_to_double(y); @@ -2072,6 +2137,15 @@ static void data_device_handle_motion(void *data, struct wl_data_device *wl_data * hammer the DBus interface hundreds or even thousands of times per second. */ SDL_SendDropPosition(data_device->dnd_window, dx, dy); + SDL_LogDebug(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\n", + WAYLAND_wl_proxy_get_id((struct wl_proxy *) data_device->drag_offer->offer), + wl_fixed_to_int(x), wl_fixed_to_int(y), + SDL_GetWindowID(data_device->dnd_window), data_device->drag_serial); + } else { + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + ". In wl_data_device_listener . data_device_handle_motion on data_offer 0x%08x at %d x %d serial %d\n", + -1, wl_fixed_to_int(x), wl_fixed_to_int(y), -1); } } @@ -2079,13 +2153,18 @@ static void data_device_handle_drop(void *data, struct wl_data_device *wl_data_d { SDL_WaylandDataDevice *data_device = data; - if (data_device->drag_offer && data_device->dnd_window) { + if (data_device->drag_offer && data_device->dnd_window && + (data_device->has_mime_file == SDL_TRUE || + data_device->has_mime_text == SDL_TRUE)) { + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + ". In wl_data_device_listener . data_device_handle_drop on data_offer 0x%08x in window %d serial %d\n", + WAYLAND_wl_proxy_get_id((struct wl_proxy *) data_device->drag_offer->offer), + SDL_GetWindowID(data_device->dnd_window), data_device->drag_serial); /* TODO: SDL Support more mime types */ size_t length; SDL_bool drop_handled = SDL_FALSE; #ifdef SDL_USE_LIBDBUS - if (Wayland_data_offer_has_mime( - data_device->drag_offer, FILE_PORTAL_MIME)) { + if (Wayland_data_offer_has_mime(data_device->drag_offer, FILE_PORTAL_MIME)) { void *buffer = Wayland_data_offer_receive(data_device->drag_offer, FILE_PORTAL_MIME, &length); if (buffer) { @@ -2112,21 +2191,46 @@ static void data_device_handle_drop(void *data, struct wl_data_device *wl_data_d * When running a flatpak sandbox this will most likely be a list of * non paths that are not visible to the application */ - if (!drop_handled && Wayland_data_offer_has_mime( - data_device->drag_offer, FILE_MIME)) { + if (!drop_handled) { + const char *mime_type = (data_device->has_mime_file ? FILE_MIME : + (data_device->has_mime_text ? TEXT_MIME : "")); void *buffer = Wayland_data_offer_receive(data_device->drag_offer, - FILE_MIME, &length); - if (buffer) { - char *saveptr = NULL; - char *token = SDL_strtok_r((char *)buffer, "\r\n", &saveptr); - while (token) { - if (SDL_URIToLocal(token, token) >= 0) { - SDL_SendDropFile(data_device->dnd_window, NULL, token); + mime_type, &length); + if (data_device->has_mime_file) { + if (buffer) { + char *saveptr = NULL; + char *token = SDL_strtok_r((char *)buffer, "\r\n", &saveptr); + while (token) { + if (SDL_URIToLocal(token, token) >= 0) { + SDL_SendDropFile(data_device->dnd_window, NULL, token); + } + token = SDL_strtok_r(NULL, "\r\n", &saveptr); } - token = SDL_strtok_r(NULL, "\r\n", &saveptr); + SDL_free(buffer); + SDL_SendDropComplete(data_device->dnd_window); + } else { + SDL_SendDropComplete(data_device->dnd_window); + } + drop_handled = SDL_TRUE; + } else if (data_device->has_mime_text) { + if (buffer) { + char *saveptr = NULL; + char *token = SDL_strtok_r((char *)buffer, "\r\n", &saveptr); + while (token) { + SDL_SendDropText(data_device->dnd_window, token); + token = SDL_strtok_r(NULL, "\r\n", &saveptr); + } + SDL_free(buffer); + SDL_SendDropComplete(data_device->dnd_window); + } else { + /* Even though there has been a valid data offer, + * and there have been valid Enter, Motion, and Drop callbacks, + * Wayland_data_offer_receive may return an empty buffer, + * because the data is actually in the primary selection device, + * not in the data device. + */ + SDL_SendDropComplete(data_device->dnd_window); } - SDL_SendDropComplete(data_device->dnd_window); - SDL_free(buffer); drop_handled = SDL_TRUE; } } @@ -2135,6 +2239,10 @@ static void data_device_handle_drop(void *data, struct wl_data_device *wl_data_d WL_DATA_OFFER_FINISH_SINCE_VERSION) { wl_data_offer_finish(data_device->drag_offer->offer); } + } else { + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + ". In wl_data_device_listener . data_device_handle_drop on data_offer 0x%08x serial %d\n", + -1, -1); } Wayland_data_offer_destroy(data_device->drag_offer); @@ -2151,6 +2259,9 @@ static void data_device_handle_selection(void *data, struct wl_data_device *wl_d offer = wl_data_offer_get_user_data(id); } + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + ". In data_device_listener . data_device_handle_selection on data_offer 0x%08x\n", + (id ? WAYLAND_wl_proxy_get_id((struct wl_proxy *) id) : -1)); if (data_device->selection_offer != offer) { Wayland_data_offer_destroy(data_device->selection_offer); data_device->selection_offer = offer; @@ -2179,6 +2290,9 @@ static void primary_selection_device_handle_offer(void *data, struct zwp_primary zwp_primary_selection_offer_v1_set_user_data(id, primary_selection_offer); zwp_primary_selection_offer_v1_add_listener(id, &primary_selection_offer_listener, primary_selection_offer); } + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + ". In zwp_primary_selection_device_v1_listener . primary_selection_device_handle_offer on primary_selection_offer 0x%08x\n", + (id ? WAYLAND_wl_proxy_get_id((struct wl_proxy *) id) : -1)); } static void primary_selection_device_handle_selection(void *data, struct zwp_primary_selection_device_v1 *zwp_primary_selection_device_v1, @@ -2195,6 +2309,9 @@ static void primary_selection_device_handle_selection(void *data, struct zwp_pri Wayland_primary_selection_offer_destroy(primary_selection_device->selection_offer); primary_selection_device->selection_offer = offer; } + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + ". In zwp_primary_selection_device_v1_listener . primary_selection_device_handle_selection on primary_selection_offer 0x%08x\n", + (id ? WAYLAND_wl_proxy_get_id((struct wl_proxy *) id) : -1)); SDL_SendClipboardUpdate(); }