Fixed X11 clipboard regressions, event waiting.

This commit is contained in:
Camilla Berglund 2013-01-31 00:26:37 +01:00
parent f3e39ce680
commit e209ac7a42
3 changed files with 84 additions and 97 deletions

View File

@ -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;

View File

@ -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,

View File

@ -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);
}
@ -1025,6 +1011,8 @@ void _glfwPlatformPollEvents(void)
}
void _glfwPlatformWaitEvents(void)
{
if (!XPending(_glfw.x11.display))
{
int fd;
fd_set fds;
@ -1034,12 +1022,13 @@ void _glfwPlatformWaitEvents(void)
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)
if (select(fd + 1, &fds, NULL, NULL, NULL) < 0)
return;
}
_glfwPlatformPollEvents();
}