mirror of
https://github.com/glfw/glfw.git
synced 2024-11-22 13:04:35 +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: 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: Gamma ramp setting via RandR did not validate ramp size
|
||||||
- [X11] Bugfix: Key name string encoding depended on current locale (#981,#983)
|
- [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] Moved to evdev for joystick input (#906,#1005)
|
||||||
- [Linux] Bugfix: Event processing did not detect joystick disconnection (#932)
|
- [Linux] Bugfix: Event processing did not detect joystick disconnection (#932)
|
||||||
- [Linux] Bugfix: The joystick device path could be truncated (#1025)
|
- [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.TARGETS = XInternAtom(_glfw.x11.display, "TARGETS", False);
|
||||||
_glfw.x11.MULTIPLE = XInternAtom(_glfw.x11.display, "MULTIPLE", False);
|
_glfw.x11.MULTIPLE = XInternAtom(_glfw.x11.display, "MULTIPLE", False);
|
||||||
_glfw.x11.PRIMARY = XInternAtom(_glfw.x11.display, "PRIMARY", 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);
|
_glfw.x11.CLIPBOARD = XInternAtom(_glfw.x11.display, "CLIPBOARD", False);
|
||||||
|
|
||||||
// Clipboard manager atoms
|
// Clipboard manager atoms
|
||||||
|
@ -265,6 +265,7 @@ typedef struct _GLFWlibraryX11
|
|||||||
// Selection (clipboard) atoms
|
// Selection (clipboard) atoms
|
||||||
Atom TARGETS;
|
Atom TARGETS;
|
||||||
Atom MULTIPLE;
|
Atom MULTIPLE;
|
||||||
|
Atom INCR;
|
||||||
Atom CLIPBOARD;
|
Atom CLIPBOARD;
|
||||||
Atom PRIMARY;
|
Atom PRIMARY;
|
||||||
Atom CLIPBOARD_MANAGER;
|
Atom CLIPBOARD_MANAGER;
|
||||||
|
@ -164,6 +164,17 @@ static Bool isFrameExtentsEvent(Display* display, XEvent* event, XPointer pointe
|
|||||||
event->xproperty.atom == _glfw.x11.NET_FRAME_EXTENTS;
|
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
|
// Translates a GLFW standard cursor to a font cursor shape
|
||||||
//
|
//
|
||||||
static int translateCursorShape(int shape)
|
static int translateCursorShape(int shape)
|
||||||
@ -841,10 +852,10 @@ static const char* getSelectionString(Atom selection)
|
|||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
char** selectionString = NULL;
|
char** selectionString = NULL;
|
||||||
const Atom formats[] = { _glfw.x11.UTF8_STRING,
|
const Atom targets[] = { _glfw.x11.UTF8_STRING,
|
||||||
_glfw.x11.COMPOUND_STRING,
|
_glfw.x11.COMPOUND_STRING,
|
||||||
XA_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)
|
if (selection == _glfw.x11.PRIMARY)
|
||||||
selectionString = &_glfw.x11.primarySelectionString;
|
selectionString = &_glfw.x11.primarySelectionString;
|
||||||
@ -862,14 +873,17 @@ static const char* getSelectionString(Atom selection)
|
|||||||
free(*selectionString);
|
free(*selectionString);
|
||||||
*selectionString = NULL;
|
*selectionString = NULL;
|
||||||
|
|
||||||
for (i = 0; i < formatCount; i++)
|
for (i = 0; i < targetCount; i++)
|
||||||
{
|
{
|
||||||
char* data;
|
char* data;
|
||||||
XEvent event;
|
Atom actualType;
|
||||||
|
int actualFormat;
|
||||||
|
unsigned long itemCount, bytesAfter;
|
||||||
|
XEvent notification, dummy;
|
||||||
|
|
||||||
XConvertSelection(_glfw.x11.display,
|
XConvertSelection(_glfw.x11.display,
|
||||||
selection,
|
selection,
|
||||||
formats[i],
|
targets[i],
|
||||||
_glfw.x11.GLFW_SELECTION,
|
_glfw.x11.GLFW_SELECTION,
|
||||||
_glfw.x11.helperWindowHandle,
|
_glfw.x11.helperWindowHandle,
|
||||||
CurrentTime);
|
CurrentTime);
|
||||||
@ -877,28 +891,76 @@ static const char* getSelectionString(Atom selection)
|
|||||||
while (!XCheckTypedWindowEvent(_glfw.x11.display,
|
while (!XCheckTypedWindowEvent(_glfw.x11.display,
|
||||||
_glfw.x11.helperWindowHandle,
|
_glfw.x11.helperWindowHandle,
|
||||||
SelectionNotify,
|
SelectionNotify,
|
||||||
&event))
|
¬ification))
|
||||||
{
|
{
|
||||||
waitForEvent(NULL);
|
waitForEvent(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.xselection.property == None)
|
if (notification.xselection.property == None)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (_glfwGetWindowPropertyX11(event.xselection.requestor,
|
XCheckIfEvent(_glfw.x11.display,
|
||||||
event.xselection.property,
|
&dummy,
|
||||||
event.xselection.target,
|
isSelPropNewValueNotify,
|
||||||
(unsigned char**) &data))
|
(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
XFree(data);
|
||||||
|
XGetWindowProperty(_glfw.x11.display,
|
||||||
|
notification.xselection.requestor,
|
||||||
|
notification.xselection.property,
|
||||||
|
0,
|
||||||
|
LONG_MAX,
|
||||||
|
True,
|
||||||
|
AnyPropertyType,
|
||||||
|
&actualType,
|
||||||
|
&actualFormat,
|
||||||
|
&itemCount,
|
||||||
|
&bytesAfter,
|
||||||
|
(unsigned char**) &data);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
if (data)
|
XFree(data);
|
||||||
XFree(data);
|
|
||||||
|
|
||||||
XDeleteProperty(_glfw.x11.display,
|
|
||||||
event.xselection.requestor,
|
|
||||||
event.xselection.property);
|
|
||||||
|
|
||||||
if (*selectionString)
|
if (*selectionString)
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user