Wayland: Improve handling of pending data offers
The code assumed that all data offers were selections that supported
plaintext UTF-8.
The initial data offer events are now handled almost tolerably. Only
selection data offers are used for clipboard string and only if they
provide plaintext UTF-8. Drag and drop data offers are now rejected as
soon as they enter a surface.
Related to #2040
(cherry picked from commit 8d87be1268
)
This commit is contained in:
parent
c89899a428
commit
a31c648127
@ -134,6 +134,8 @@ information on what to include when reporting a bug.
|
|||||||
- [Wayland] Bugfix: Data source creation error would cause double free at termination
|
- [Wayland] Bugfix: Data source creation error would cause double free at termination
|
||||||
- [Wayland] Bugfix: Partial writes of clipboard string would cause beginning to repeat
|
- [Wayland] Bugfix: Partial writes of clipboard string would cause beginning to repeat
|
||||||
- [Wayland] Bugfix: Some errors would cause clipboard string transfer to hang
|
- [Wayland] Bugfix: Some errors would cause clipboard string transfer to hang
|
||||||
|
- [Wayland] Bugfix: Drag and drop data was misinterpreted as clipboard string
|
||||||
|
- [Wayland] Bugfix: MIME type matching was not performed for clipboard string
|
||||||
|
|
||||||
|
|
||||||
## Contact
|
## Contact
|
||||||
|
@ -700,6 +700,16 @@ static void dataOfferHandleOffer(void* userData,
|
|||||||
struct wl_data_offer* offer,
|
struct wl_data_offer* offer,
|
||||||
const char* mimeType)
|
const char* mimeType)
|
||||||
{
|
{
|
||||||
|
for (unsigned int i = 0; i < _glfw.wl.offerCount; i++)
|
||||||
|
{
|
||||||
|
if (_glfw.wl.offers[i].offer == offer)
|
||||||
|
{
|
||||||
|
if (strcmp(mimeType, "text/plain;charset=utf-8") == 0)
|
||||||
|
_glfw.wl.offers[i].text_plain_utf8 = GLFW_TRUE;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_data_offer_listener dataOfferListener = {
|
static const struct wl_data_offer_listener dataOfferListener = {
|
||||||
@ -710,11 +720,19 @@ static void dataDeviceHandleDataOffer(void* userData,
|
|||||||
struct wl_data_device* device,
|
struct wl_data_device* device,
|
||||||
struct wl_data_offer* offer)
|
struct wl_data_offer* offer)
|
||||||
{
|
{
|
||||||
if (_glfw.wl.dataOffer)
|
_GLFWofferWayland* offers =
|
||||||
wl_data_offer_destroy(_glfw.wl.dataOffer);
|
realloc(_glfw.wl.offers, _glfw.wl.offerCount + 1);
|
||||||
|
if (!offers)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_OUT_OF_MEMORY, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_glfw.wl.dataOffer = offer;
|
_glfw.wl.offers = offers;
|
||||||
wl_data_offer_add_listener(_glfw.wl.dataOffer, &dataOfferListener, NULL);
|
_glfw.wl.offerCount++;
|
||||||
|
|
||||||
|
_glfw.wl.offers[_glfw.wl.offerCount - 1] = (_GLFWofferWayland) { offer };
|
||||||
|
wl_data_offer_add_listener(offer, &dataOfferListener, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dataDeviceHandleEnter(void* userData,
|
static void dataDeviceHandleEnter(void* userData,
|
||||||
@ -725,6 +743,19 @@ static void dataDeviceHandleEnter(void* userData,
|
|||||||
wl_fixed_t y,
|
wl_fixed_t y,
|
||||||
struct wl_data_offer* offer)
|
struct wl_data_offer* offer)
|
||||||
{
|
{
|
||||||
|
for (unsigned int i = 0; i < _glfw.wl.offerCount; i++)
|
||||||
|
{
|
||||||
|
if (_glfw.wl.offers[i].offer == offer)
|
||||||
|
{
|
||||||
|
_glfw.wl.offers[i] = _glfw.wl.offers[_glfw.wl.offerCount - 1];
|
||||||
|
_glfw.wl.offerCount--;
|
||||||
|
|
||||||
|
// We don't yet handle drag and drop
|
||||||
|
wl_data_offer_accept(offer, serial, NULL);
|
||||||
|
wl_data_offer_destroy(offer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dataDeviceHandleLeave(void* userData,
|
static void dataDeviceHandleLeave(void* userData,
|
||||||
@ -749,6 +780,26 @@ static void dataDeviceHandleSelection(void* userData,
|
|||||||
struct wl_data_device* device,
|
struct wl_data_device* device,
|
||||||
struct wl_data_offer* offer)
|
struct wl_data_offer* offer)
|
||||||
{
|
{
|
||||||
|
if (_glfw.wl.selectionOffer)
|
||||||
|
{
|
||||||
|
wl_data_offer_destroy(_glfw.wl.selectionOffer);
|
||||||
|
_glfw.wl.selectionOffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < _glfw.wl.offerCount; i++)
|
||||||
|
{
|
||||||
|
if (_glfw.wl.offers[i].offer == offer)
|
||||||
|
{
|
||||||
|
if (_glfw.wl.offers[i].text_plain_utf8)
|
||||||
|
_glfw.wl.selectionOffer = offer;
|
||||||
|
else
|
||||||
|
wl_data_offer_destroy(offer);
|
||||||
|
|
||||||
|
_glfw.wl.offers[i] = _glfw.wl.offers[_glfw.wl.offerCount - 1];
|
||||||
|
_glfw.wl.offerCount--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_data_device_listener dataDeviceListener = {
|
static const struct wl_data_device_listener dataDeviceListener = {
|
||||||
@ -1240,6 +1291,11 @@ void _glfwPlatformTerminate(void)
|
|||||||
_glfw.wl.cursor.handle = NULL;
|
_glfw.wl.cursor.handle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < _glfw.wl.offerCount; i++)
|
||||||
|
wl_data_offer_destroy(_glfw.wl.offers[i].offer);
|
||||||
|
|
||||||
|
free(_glfw.wl.offers);
|
||||||
|
|
||||||
if (_glfw.wl.cursorSurface)
|
if (_glfw.wl.cursorSurface)
|
||||||
wl_surface_destroy(_glfw.wl.cursorSurface);
|
wl_surface_destroy(_glfw.wl.cursorSurface);
|
||||||
if (_glfw.wl.subcompositor)
|
if (_glfw.wl.subcompositor)
|
||||||
@ -1256,12 +1312,12 @@ void _glfwPlatformTerminate(void)
|
|||||||
zxdg_decoration_manager_v1_destroy(_glfw.wl.decorationManager);
|
zxdg_decoration_manager_v1_destroy(_glfw.wl.decorationManager);
|
||||||
if (_glfw.wl.wmBase)
|
if (_glfw.wl.wmBase)
|
||||||
xdg_wm_base_destroy(_glfw.wl.wmBase);
|
xdg_wm_base_destroy(_glfw.wl.wmBase);
|
||||||
if (_glfw.wl.dataSource)
|
if (_glfw.wl.selectionOffer)
|
||||||
wl_data_source_destroy(_glfw.wl.dataSource);
|
wl_data_offer_destroy(_glfw.wl.selectionOffer);
|
||||||
|
if (_glfw.wl.selectionSource)
|
||||||
|
wl_data_source_destroy(_glfw.wl.selectionSource);
|
||||||
if (_glfw.wl.dataDevice)
|
if (_glfw.wl.dataDevice)
|
||||||
wl_data_device_destroy(_glfw.wl.dataDevice);
|
wl_data_device_destroy(_glfw.wl.dataDevice);
|
||||||
if (_glfw.wl.dataOffer)
|
|
||||||
wl_data_offer_destroy(_glfw.wl.dataOffer);
|
|
||||||
if (_glfw.wl.dataDeviceManager)
|
if (_glfw.wl.dataDeviceManager)
|
||||||
wl_data_device_manager_destroy(_glfw.wl.dataDeviceManager);
|
wl_data_device_manager_destroy(_glfw.wl.dataDeviceManager);
|
||||||
if (_glfw.wl.pointer)
|
if (_glfw.wl.pointer)
|
||||||
|
@ -167,6 +167,12 @@ typedef struct _GLFWdecorationWayland
|
|||||||
struct wp_viewport* viewport;
|
struct wp_viewport* viewport;
|
||||||
} _GLFWdecorationWayland;
|
} _GLFWdecorationWayland;
|
||||||
|
|
||||||
|
typedef struct _GLFWofferWayland
|
||||||
|
{
|
||||||
|
struct wl_data_offer* offer;
|
||||||
|
GLFWbool text_plain_utf8;
|
||||||
|
} _GLFWofferWayland;
|
||||||
|
|
||||||
// Wayland-specific per-window data
|
// Wayland-specific per-window data
|
||||||
//
|
//
|
||||||
typedef struct _GLFWwindowWayland
|
typedef struct _GLFWwindowWayland
|
||||||
@ -231,8 +237,6 @@ typedef struct _GLFWlibraryWayland
|
|||||||
struct wl_keyboard* keyboard;
|
struct wl_keyboard* keyboard;
|
||||||
struct wl_data_device_manager* dataDeviceManager;
|
struct wl_data_device_manager* dataDeviceManager;
|
||||||
struct wl_data_device* dataDevice;
|
struct wl_data_device* dataDevice;
|
||||||
struct wl_data_offer* dataOffer;
|
|
||||||
struct wl_data_source* dataSource;
|
|
||||||
struct xdg_wm_base* wmBase;
|
struct xdg_wm_base* wmBase;
|
||||||
struct zxdg_decoration_manager_v1* decorationManager;
|
struct zxdg_decoration_manager_v1* decorationManager;
|
||||||
struct wp_viewporter* viewporter;
|
struct wp_viewporter* viewporter;
|
||||||
@ -240,6 +244,12 @@ typedef struct _GLFWlibraryWayland
|
|||||||
struct zwp_pointer_constraints_v1* pointerConstraints;
|
struct zwp_pointer_constraints_v1* pointerConstraints;
|
||||||
struct zwp_idle_inhibit_manager_v1* idleInhibitManager;
|
struct zwp_idle_inhibit_manager_v1* idleInhibitManager;
|
||||||
|
|
||||||
|
_GLFWofferWayland* offers;
|
||||||
|
unsigned int offerCount;
|
||||||
|
|
||||||
|
struct wl_data_offer* selectionOffer;
|
||||||
|
struct wl_data_source* selectionSource;
|
||||||
|
|
||||||
int compositorVersion;
|
int compositorVersion;
|
||||||
int seatVersion;
|
int seatVersion;
|
||||||
|
|
||||||
|
@ -1712,7 +1712,7 @@ static void dataSourceHandleTarget(void* userData,
|
|||||||
struct wl_data_source* source,
|
struct wl_data_source* source,
|
||||||
const char* mimeType)
|
const char* mimeType)
|
||||||
{
|
{
|
||||||
if (_glfw.wl.dataSource != source)
|
if (_glfw.wl.selectionSource != source)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"Wayland: Unknown clipboard data source");
|
"Wayland: Unknown clipboard data source");
|
||||||
@ -1729,7 +1729,7 @@ static void dataSourceHandleSend(void* userData,
|
|||||||
size_t len = strlen(string);
|
size_t len = strlen(string);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (_glfw.wl.dataSource != source)
|
if (_glfw.wl.selectionSource != source)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"Wayland: Unknown clipboard data source");
|
"Wayland: Unknown clipboard data source");
|
||||||
@ -1777,14 +1777,14 @@ static void dataSourceHandleCancelled(void* userData,
|
|||||||
{
|
{
|
||||||
wl_data_source_destroy(source);
|
wl_data_source_destroy(source);
|
||||||
|
|
||||||
if (_glfw.wl.dataSource != source)
|
if (_glfw.wl.selectionSource != source)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"Wayland: Unknown clipboard data source");
|
"Wayland: Unknown clipboard data source");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_glfw.wl.dataSource = NULL;
|
_glfw.wl.selectionSource = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_data_source_listener dataSourceListener = {
|
static const struct wl_data_source_listener dataSourceListener = {
|
||||||
@ -1795,10 +1795,10 @@ static const struct wl_data_source_listener dataSourceListener = {
|
|||||||
|
|
||||||
void _glfwPlatformSetClipboardString(const char* string)
|
void _glfwPlatformSetClipboardString(const char* string)
|
||||||
{
|
{
|
||||||
if (_glfw.wl.dataSource)
|
if (_glfw.wl.selectionSource)
|
||||||
{
|
{
|
||||||
wl_data_source_destroy(_glfw.wl.dataSource);
|
wl_data_source_destroy(_glfw.wl.selectionSource);
|
||||||
_glfw.wl.dataSource = NULL;
|
_glfw.wl.selectionSource = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* copy = _glfw_strdup(string);
|
char* copy = _glfw_strdup(string);
|
||||||
@ -1812,9 +1812,9 @@ void _glfwPlatformSetClipboardString(const char* string)
|
|||||||
free(_glfw.wl.clipboardSendString);
|
free(_glfw.wl.clipboardSendString);
|
||||||
_glfw.wl.clipboardSendString = copy;
|
_glfw.wl.clipboardSendString = copy;
|
||||||
|
|
||||||
_glfw.wl.dataSource =
|
_glfw.wl.selectionSource =
|
||||||
wl_data_device_manager_create_data_source(_glfw.wl.dataDeviceManager);
|
wl_data_device_manager_create_data_source(_glfw.wl.dataDeviceManager);
|
||||||
if (!_glfw.wl.dataSource)
|
if (!_glfw.wl.selectionSource)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||||
"Wayland: Failed to create clipboard data source");
|
"Wayland: Failed to create clipboard data source");
|
||||||
@ -1822,12 +1822,12 @@ void _glfwPlatformSetClipboardString(const char* string)
|
|||||||
_glfw.wl.clipboardSendString = NULL;
|
_glfw.wl.clipboardSendString = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
wl_data_source_add_listener(_glfw.wl.dataSource,
|
wl_data_source_add_listener(_glfw.wl.selectionSource,
|
||||||
&dataSourceListener,
|
&dataSourceListener,
|
||||||
NULL);
|
NULL);
|
||||||
wl_data_source_offer(_glfw.wl.dataSource, "text/plain;charset=utf-8");
|
wl_data_source_offer(_glfw.wl.selectionSource, "text/plain;charset=utf-8");
|
||||||
wl_data_device_set_selection(_glfw.wl.dataDevice,
|
wl_data_device_set_selection(_glfw.wl.dataDevice,
|
||||||
_glfw.wl.dataSource,
|
_glfw.wl.selectionSource,
|
||||||
_glfw.wl.serial);
|
_glfw.wl.serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1853,14 +1853,14 @@ const char* _glfwPlatformGetClipboardString(void)
|
|||||||
int ret;
|
int ret;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
|
||||||
if (!_glfw.wl.dataOffer)
|
if (!_glfw.wl.selectionOffer)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||||
"Wayland: No clipboard data available");
|
"Wayland: No clipboard data available");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_glfw.wl.dataSource)
|
if (_glfw.wl.selectionSource)
|
||||||
return _glfw.wl.clipboardSendString;
|
return _glfw.wl.clipboardSendString;
|
||||||
|
|
||||||
ret = pipe2(fds, O_CLOEXEC);
|
ret = pipe2(fds, O_CLOEXEC);
|
||||||
@ -1872,7 +1872,7 @@ const char* _glfwPlatformGetClipboardString(void)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
wl_data_offer_receive(_glfw.wl.dataOffer, "text/plain;charset=utf-8", fds[1]);
|
wl_data_offer_receive(_glfw.wl.selectionOffer, "text/plain;charset=utf-8", fds[1]);
|
||||||
|
|
||||||
flushDisplay();
|
flushDisplay();
|
||||||
close(fds[1]);
|
close(fds[1]);
|
||||||
|
Loading…
Reference in New Issue
Block a user