Fixed X11 clipboard regressions, event waiting.
This commit is contained in:
parent
f3e39ce680
commit
e209ac7a42
@ -39,43 +39,6 @@
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//========================================================================
|
||||
// Save the contents of the specified property
|
||||
//========================================================================
|
||||
|
||||
GLboolean _glfwReadSelection(XSelectionEvent* request)
|
||||
{
|
||||
Atom actualType;
|
||||
int actualFormat;
|
||||
unsigned long itemCount, bytesAfter;
|
||||
char* data;
|
||||
|
||||
if (request->property == None)
|
||||
return GL_FALSE;
|
||||
|
||||
XGetWindowProperty(_glfw.x11.display,
|
||||
request->requestor,
|
||||
request->property,
|
||||
0, LONG_MAX,
|
||||
False,
|
||||
request->target,
|
||||
&actualType,
|
||||
&actualFormat,
|
||||
&itemCount,
|
||||
&bytesAfter,
|
||||
(unsigned char**) &data);
|
||||
|
||||
if (actualType == None)
|
||||
return GL_FALSE;
|
||||
|
||||
free(_glfw.x11.selection.string);
|
||||
_glfw.x11.selection.string = strdup(data);
|
||||
|
||||
XFree(data);
|
||||
return GL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Set the specified property to the contents of the requested selection
|
||||
//========================================================================
|
||||
@ -83,10 +46,12 @@ GLboolean _glfwReadSelection(XSelectionEvent* request)
|
||||
Atom _glfwWriteSelection(XSelectionRequestEvent* request)
|
||||
{
|
||||
int i;
|
||||
Atom property = request->property;
|
||||
|
||||
if (property == None)
|
||||
property = _glfw.x11.selection.property;
|
||||
if (request->property == None)
|
||||
{
|
||||
// The requestor is a legacy client (ICCCM section 2.2)
|
||||
return None;
|
||||
}
|
||||
|
||||
if (request->target == _glfw.x11.TARGETS)
|
||||
{
|
||||
@ -94,14 +59,14 @@ Atom _glfwWriteSelection(XSelectionRequestEvent* request)
|
||||
|
||||
XChangeProperty(_glfw.x11.display,
|
||||
request->requestor,
|
||||
property,
|
||||
request->property,
|
||||
XA_ATOM,
|
||||
32,
|
||||
PropModeReplace,
|
||||
(unsigned char*) _glfw.x11.selection.formats,
|
||||
_GLFW_CLIPBOARD_FORMAT_COUNT);
|
||||
|
||||
return property;
|
||||
return request->property;
|
||||
}
|
||||
|
||||
for (i = 0; i < _GLFW_CLIPBOARD_FORMAT_COUNT; i++)
|
||||
@ -112,14 +77,14 @@ Atom _glfwWriteSelection(XSelectionRequestEvent* request)
|
||||
|
||||
XChangeProperty(_glfw.x11.display,
|
||||
request->requestor,
|
||||
property,
|
||||
request->property,
|
||||
request->target,
|
||||
8,
|
||||
PropModeReplace,
|
||||
(unsigned char*) _glfw.x11.selection.string,
|
||||
strlen(_glfw.x11.selection.string));
|
||||
|
||||
return property;
|
||||
return request->property;
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,47 +98,87 @@ Atom _glfwWriteSelection(XSelectionRequestEvent* request)
|
||||
|
||||
void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
|
||||
{
|
||||
// Store the new string in preparation for a selection request event
|
||||
free(_glfw.x11.selection.string);
|
||||
_glfw.x11.selection.string = strdup(string);
|
||||
|
||||
// Set the specified window as owner of the selection
|
||||
XSetSelectionOwner(_glfw.x11.display,
|
||||
_glfw.x11.CLIPBOARD,
|
||||
window->x11.handle, CurrentTime);
|
||||
|
||||
if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) !=
|
||||
window->x11.handle)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"X11: Failed to become owner of the clipboard selection");
|
||||
}
|
||||
}
|
||||
|
||||
const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
|
||||
{
|
||||
int i;
|
||||
|
||||
_glfw.x11.selection.status = _GLFW_CONVERSION_INACTIVE;
|
||||
if (_glfwFindWindowByHandle(XGetSelectionOwner(_glfw.x11.display,
|
||||
_glfw.x11.CLIPBOARD)))
|
||||
{
|
||||
// Instead of doing a large number of X round-trips just to put this
|
||||
// string into a window property and then read it back, just return it
|
||||
return _glfw.x11.selection.string;
|
||||
}
|
||||
|
||||
free(_glfw.x11.selection.string);
|
||||
_glfw.x11.selection.string = NULL;
|
||||
|
||||
for (i = 0; i < _GLFW_CLIPBOARD_FORMAT_COUNT; i++)
|
||||
{
|
||||
// Request conversion to the selected format
|
||||
_glfw.x11.selection.target = _glfw.x11.selection.formats[i];
|
||||
Atom actualType;
|
||||
int actualFormat;
|
||||
unsigned long itemCount, bytesAfter;
|
||||
char* data;
|
||||
XEvent event;
|
||||
|
||||
XConvertSelection(_glfw.x11.display,
|
||||
_glfw.x11.CLIPBOARD,
|
||||
_glfw.x11.selection.target,
|
||||
_glfw.x11.selection.formats[i],
|
||||
_glfw.x11.selection.property,
|
||||
window->x11.handle, CurrentTime);
|
||||
|
||||
// Process the resulting SelectionNotify event
|
||||
XSync(_glfw.x11.display, False);
|
||||
while (_glfw.x11.selection.status == _GLFW_CONVERSION_INACTIVE)
|
||||
_glfwPlatformWaitEvents();
|
||||
// XCheckTypedEvent is used instead of XIfEvent in order not to lock
|
||||
// other threads out from the display during the entire wait period
|
||||
while (!XCheckTypedEvent(_glfw.x11.display, SelectionNotify, &event))
|
||||
;
|
||||
|
||||
if (_glfw.x11.selection.status == _GLFW_CONVERSION_SUCCEEDED)
|
||||
if (event.xselection.property == None)
|
||||
continue;
|
||||
|
||||
XGetWindowProperty(_glfw.x11.display,
|
||||
event.xselection.requestor,
|
||||
event.xselection.property,
|
||||
0, LONG_MAX,
|
||||
False,
|
||||
event.xselection.target,
|
||||
&actualType,
|
||||
&actualFormat,
|
||||
&itemCount,
|
||||
&bytesAfter,
|
||||
(unsigned char**) &data);
|
||||
|
||||
XDeleteProperty(_glfw.x11.display,
|
||||
event.xselection.requestor,
|
||||
event.xselection.property);
|
||||
|
||||
if (actualType == event.xselection.target)
|
||||
_glfw.x11.selection.string = strdup(data);
|
||||
|
||||
XFree(data);
|
||||
|
||||
if (_glfw.x11.selection.string)
|
||||
break;
|
||||
}
|
||||
|
||||
if (_glfw.x11.selection.status == _GLFW_CONVERSION_FAILED)
|
||||
if (_glfw.x11.selection.string == NULL)
|
||||
{
|
||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||
"X11: Failed to convert selection to string");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return _glfw.x11.selection.string;
|
||||
|
@ -63,17 +63,12 @@
|
||||
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11
|
||||
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorX11 x11
|
||||
|
||||
// Clipboard format atom indices
|
||||
// Clipboard format atom indices (in order of preference)
|
||||
#define _GLFW_CLIPBOARD_FORMAT_UTF8 0
|
||||
#define _GLFW_CLIPBOARD_FORMAT_COMPOUND 1
|
||||
#define _GLFW_CLIPBOARD_FORMAT_STRING 2
|
||||
#define _GLFW_CLIPBOARD_FORMAT_COUNT 3
|
||||
|
||||
// Clipboard conversion status tokens
|
||||
#define _GLFW_CONVERSION_INACTIVE 0
|
||||
#define _GLFW_CONVERSION_SUCCEEDED 1
|
||||
#define _GLFW_CONVERSION_FAILED 2
|
||||
|
||||
|
||||
//========================================================================
|
||||
// GLFW platform specific types
|
||||
@ -184,9 +179,7 @@ typedef struct _GLFWlibraryX11
|
||||
struct {
|
||||
Atom formats[_GLFW_CLIPBOARD_FORMAT_COUNT];
|
||||
char* string;
|
||||
Atom target;
|
||||
Atom property;
|
||||
int status;
|
||||
} selection;
|
||||
|
||||
struct {
|
||||
@ -251,13 +244,13 @@ void _glfwTerminateJoysticks(void);
|
||||
long _glfwKeySym2Unicode(KeySym keysym);
|
||||
|
||||
// Clipboard handling
|
||||
GLboolean _glfwReadSelection(XSelectionEvent* request);
|
||||
Atom _glfwWriteSelection(XSelectionRequestEvent* request);
|
||||
|
||||
// Event processing
|
||||
void _glfwProcessPendingEvents(void);
|
||||
|
||||
// Window support
|
||||
_GLFWwindow* _glfwFindWindowByHandle(Window handle);
|
||||
unsigned long _glfwGetWindowProperty(Window window,
|
||||
Atom property,
|
||||
Atom type,
|
||||
|
@ -451,7 +451,7 @@ static void leaveFullscreenMode(_GLFWwindow* window)
|
||||
// Return the GLFW window corresponding to the specified X11 window
|
||||
//========================================================================
|
||||
|
||||
static _GLFWwindow* findWindow(Window handle)
|
||||
_GLFWwindow* _glfwFindWindowByHandle(Window handle)
|
||||
{
|
||||
_GLFWwindow* window;
|
||||
|
||||
@ -475,7 +475,7 @@ static void processEvent(XEvent *event)
|
||||
|
||||
if (event->type != GenericEvent)
|
||||
{
|
||||
window = findWindow(event->xany.window);
|
||||
window = _glfwFindWindowByHandle(event->xany.window);
|
||||
if (window == NULL)
|
||||
{
|
||||
// This is either an event for a destroyed GLFW window or an event
|
||||
@ -710,20 +710,6 @@ static void processEvent(XEvent *event)
|
||||
break;
|
||||
}
|
||||
|
||||
case SelectionNotify:
|
||||
{
|
||||
// The clipboard selection conversion status is available
|
||||
|
||||
XSelectionEvent* request = &event->xselection;
|
||||
|
||||
if (_glfwReadSelection(request))
|
||||
_glfw.x11.selection.status = _GLFW_CONVERSION_SUCCEEDED;
|
||||
else
|
||||
_glfw.x11.selection.status = _GLFW_CONVERSION_FAILED;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SelectionRequest:
|
||||
{
|
||||
// The contents of the clipboard selection was requested
|
||||
@ -993,11 +979,11 @@ void _glfwPlatformHideWindow(_GLFWwindow* window)
|
||||
|
||||
void _glfwPlatformPollEvents(void)
|
||||
{
|
||||
XEvent event;
|
||||
|
||||
while (XCheckMaskEvent(_glfw.x11.display, ~0, &event) ||
|
||||
XCheckTypedEvent(_glfw.x11.display, ClientMessage, &event))
|
||||
int count = XPending(_glfw.x11.display);
|
||||
while (count--)
|
||||
{
|
||||
XEvent event;
|
||||
XNextEvent(_glfw.x11.display, &event);
|
||||
processEvent(&event);
|
||||
}
|
||||
|
||||
@ -1026,21 +1012,24 @@ void _glfwPlatformPollEvents(void)
|
||||
|
||||
void _glfwPlatformWaitEvents(void)
|
||||
{
|
||||
int fd;
|
||||
fd_set fds;
|
||||
if (!XPending(_glfw.x11.display))
|
||||
{
|
||||
int fd;
|
||||
fd_set fds;
|
||||
|
||||
fd = ConnectionNumber(_glfw.x11.display);
|
||||
fd = ConnectionNumber(_glfw.x11.display);
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fd, &fds);
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fd, &fds);
|
||||
|
||||
XFlush(_glfw.x11.display);
|
||||
// select(1) is used instead of an X function like XNextEvent, as the
|
||||
// wait inside those are guarded by the mutex protecting the display
|
||||
// struct, locking out other threads from using X (including GLX)
|
||||
if (select(fd + 1, &fds, NULL, NULL, NULL) < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
// select(1) is used instead of an X function like XNextEvent, as the
|
||||
// wait inside those are guarded by the mutex protecting the display
|
||||
// struct, locking out other threads from using X (including GLX)
|
||||
if (select(fd + 1, &fds, NULL, NULL, NULL) > 0)
|
||||
_glfwPlatformPollEvents();
|
||||
_glfwPlatformPollEvents();
|
||||
}
|
||||
|
||||
void _glfwPlatformSetCursorPos(_GLFWwindow* window, int x, int y)
|
||||
|
Loading…
Reference in New Issue
Block a user