mirror of
https://github.com/glfw/glfw.git
synced 2024-11-22 18:15:10 +00:00
X11: Add support for reading clipboard via INCR
This allows glfwGetClipboardString to retrieve clipboard contents larger than (typically) 2^18 bytes. Related to #275.
This commit is contained in:
parent
f30acd8f74
commit
f7dc6df02c
@ -205,6 +205,7 @@ information on what to include when reporting a bug.
|
||||
- [X11] Bugfix: IM-duplicated key events would leak at low polling rates (#747)
|
||||
- [X11] Bugfix: Gamma ramp setting via RandR did not validate ramp size
|
||||
- [X11] Bugfix: Key name string encoding depended on current locale (#981,#983)
|
||||
- [X11] Bugfix: Incremental reading of selections was not supported (#275)
|
||||
- [Linux] Moved to evdev for joystick input (#906,#1005)
|
||||
- [Linux] Bugfix: Event processing did not detect joystick disconnection (#932)
|
||||
- [Linux] Bugfix: The joystick device path could be truncated (#1025)
|
||||
|
@ -675,6 +675,7 @@ static GLFWbool initExtensions(void)
|
||||
_glfw.x11.TARGETS = XInternAtom(_glfw.x11.display, "TARGETS", False);
|
||||
_glfw.x11.MULTIPLE = XInternAtom(_glfw.x11.display, "MULTIPLE", False);
|
||||
_glfw.x11.PRIMARY = XInternAtom(_glfw.x11.display, "PRIMARY", False);
|
||||
_glfw.x11.INCR = XInternAtom(_glfw.x11.display, "INCR", False);
|
||||
_glfw.x11.CLIPBOARD = XInternAtom(_glfw.x11.display, "CLIPBOARD", False);
|
||||
|
||||
// Clipboard manager atoms
|
||||
|
@ -265,6 +265,7 @@ typedef struct _GLFWlibraryX11
|
||||
// Selection (clipboard) atoms
|
||||
Atom TARGETS;
|
||||
Atom MULTIPLE;
|
||||
Atom INCR;
|
||||
Atom CLIPBOARD;
|
||||
Atom PRIMARY;
|
||||
Atom CLIPBOARD_MANAGER;
|
||||
|
@ -164,6 +164,17 @@ static Bool isFrameExtentsEvent(Display* display, XEvent* event, XPointer pointe
|
||||
event->xproperty.atom == _glfw.x11.NET_FRAME_EXTENTS;
|
||||
}
|
||||
|
||||
// Returns whether it is a property event for the specified selection transfer
|
||||
//
|
||||
static Bool isSelPropNewValueNotify(Display* display, XEvent* event, XPointer pointer)
|
||||
{
|
||||
XEvent* notification = (XEvent*) pointer;
|
||||
return event->type == PropertyNotify &&
|
||||
event->xproperty.state == PropertyNewValue &&
|
||||
event->xproperty.window == notification->xselection.requestor &&
|
||||
event->xproperty.atom == notification->xselection.property;
|
||||
}
|
||||
|
||||
// Translates a GLFW standard cursor to a font cursor shape
|
||||
//
|
||||
static int translateCursorShape(int shape)
|
||||
@ -841,10 +852,10 @@ static const char* getSelectionString(Atom selection)
|
||||
{
|
||||
size_t i;
|
||||
char** selectionString = NULL;
|
||||
const Atom formats[] = { _glfw.x11.UTF8_STRING,
|
||||
const Atom targets[] = { _glfw.x11.UTF8_STRING,
|
||||
_glfw.x11.COMPOUND_STRING,
|
||||
XA_STRING };
|
||||
const size_t formatCount = sizeof(formats) / sizeof(formats[0]);
|
||||
const size_t targetCount = sizeof(targets) / sizeof(targets[0]);
|
||||
|
||||
if (selection == _glfw.x11.PRIMARY)
|
||||
selectionString = &_glfw.x11.primarySelectionString;
|
||||
@ -862,14 +873,17 @@ static const char* getSelectionString(Atom selection)
|
||||
free(*selectionString);
|
||||
*selectionString = NULL;
|
||||
|
||||
for (i = 0; i < formatCount; i++)
|
||||
for (i = 0; i < targetCount; i++)
|
||||
{
|
||||
char* data;
|
||||
XEvent event;
|
||||
Atom actualType;
|
||||
int actualFormat;
|
||||
unsigned long itemCount, bytesAfter;
|
||||
XEvent notification, dummy;
|
||||
|
||||
XConvertSelection(_glfw.x11.display,
|
||||
selection,
|
||||
formats[i],
|
||||
targets[i],
|
||||
_glfw.x11.GLFW_SELECTION,
|
||||
_glfw.x11.helperWindowHandle,
|
||||
CurrentTime);
|
||||
@ -877,28 +891,76 @@ static const char* getSelectionString(Atom selection)
|
||||
while (!XCheckTypedWindowEvent(_glfw.x11.display,
|
||||
_glfw.x11.helperWindowHandle,
|
||||
SelectionNotify,
|
||||
&event))
|
||||
¬ification))
|
||||
{
|
||||
waitForEvent(NULL);
|
||||
}
|
||||
|
||||
if (event.xselection.property == None)
|
||||
if (notification.xselection.property == None)
|
||||
continue;
|
||||
|
||||
if (_glfwGetWindowPropertyX11(event.xselection.requestor,
|
||||
event.xselection.property,
|
||||
event.xselection.target,
|
||||
(unsigned char**) &data))
|
||||
XCheckIfEvent(_glfw.x11.display,
|
||||
&dummy,
|
||||
isSelPropNewValueNotify,
|
||||
(XPointer) ¬ification);
|
||||
|
||||
XGetWindowProperty(_glfw.x11.display,
|
||||
notification.xselection.requestor,
|
||||
notification.xselection.property,
|
||||
0,
|
||||
LONG_MAX,
|
||||
True,
|
||||
AnyPropertyType,
|
||||
&actualType,
|
||||
&actualFormat,
|
||||
&itemCount,
|
||||
&bytesAfter,
|
||||
(unsigned char**) &data);
|
||||
|
||||
if (actualType == _glfw.x11.INCR)
|
||||
{
|
||||
*selectionString = strdup(data);
|
||||
size_t size = 1;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
while (!XCheckIfEvent(_glfw.x11.display,
|
||||
&dummy,
|
||||
isSelPropNewValueNotify,
|
||||
(XPointer) ¬ification))
|
||||
{
|
||||
waitForEvent(NULL);
|
||||
}
|
||||
|
||||
if (data)
|
||||
XFree(data);
|
||||
XGetWindowProperty(_glfw.x11.display,
|
||||
notification.xselection.requestor,
|
||||
notification.xselection.property,
|
||||
0,
|
||||
LONG_MAX,
|
||||
True,
|
||||
AnyPropertyType,
|
||||
&actualType,
|
||||
&actualFormat,
|
||||
&itemCount,
|
||||
&bytesAfter,
|
||||
(unsigned char**) &data);
|
||||
|
||||
XDeleteProperty(_glfw.x11.display,
|
||||
event.xselection.requestor,
|
||||
event.xselection.property);
|
||||
if (itemCount)
|
||||
{
|
||||
size += itemCount;
|
||||
*selectionString = realloc(*selectionString, size);
|
||||
(*selectionString)[size - itemCount - 1] = '\0';
|
||||
strcat(*selectionString, data);
|
||||
}
|
||||
|
||||
if (!itemCount)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (actualType == targets[i])
|
||||
*selectionString = strdup(data);
|
||||
|
||||
XFree(data);
|
||||
|
||||
if (*selectionString)
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user