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 ////// ////// 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 // Set the specified property to the contents of the requested selection
//======================================================================== //========================================================================
@ -83,10 +46,12 @@ GLboolean _glfwReadSelection(XSelectionEvent* request)
Atom _glfwWriteSelection(XSelectionRequestEvent* request) Atom _glfwWriteSelection(XSelectionRequestEvent* request)
{ {
int i; int i;
Atom property = request->property;
if (property == None) if (request->property == None)
property = _glfw.x11.selection.property; {
// The requestor is a legacy client (ICCCM section 2.2)
return None;
}
if (request->target == _glfw.x11.TARGETS) if (request->target == _glfw.x11.TARGETS)
{ {
@ -94,14 +59,14 @@ Atom _glfwWriteSelection(XSelectionRequestEvent* request)
XChangeProperty(_glfw.x11.display, XChangeProperty(_glfw.x11.display,
request->requestor, request->requestor,
property, request->property,
XA_ATOM, XA_ATOM,
32, 32,
PropModeReplace, PropModeReplace,
(unsigned char*) _glfw.x11.selection.formats, (unsigned char*) _glfw.x11.selection.formats,
_GLFW_CLIPBOARD_FORMAT_COUNT); _GLFW_CLIPBOARD_FORMAT_COUNT);
return property; return request->property;
} }
for (i = 0; i < _GLFW_CLIPBOARD_FORMAT_COUNT; i++) for (i = 0; i < _GLFW_CLIPBOARD_FORMAT_COUNT; i++)
@ -112,14 +77,14 @@ Atom _glfwWriteSelection(XSelectionRequestEvent* request)
XChangeProperty(_glfw.x11.display, XChangeProperty(_glfw.x11.display,
request->requestor, request->requestor,
property, request->property,
request->target, request->target,
8, 8,
PropModeReplace, PropModeReplace,
(unsigned char*) _glfw.x11.selection.string, (unsigned char*) _glfw.x11.selection.string,
strlen(_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) void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
{ {
// Store the new string in preparation for a selection request event
free(_glfw.x11.selection.string); free(_glfw.x11.selection.string);
_glfw.x11.selection.string = strdup(string); _glfw.x11.selection.string = strdup(string);
// Set the specified window as owner of the selection
XSetSelectionOwner(_glfw.x11.display, XSetSelectionOwner(_glfw.x11.display,
_glfw.x11.CLIPBOARD, _glfw.x11.CLIPBOARD,
window->x11.handle, CurrentTime); 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) const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
{ {
int i; 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++) for (i = 0; i < _GLFW_CLIPBOARD_FORMAT_COUNT; i++)
{ {
// Request conversion to the selected format Atom actualType;
_glfw.x11.selection.target = _glfw.x11.selection.formats[i]; int actualFormat;
unsigned long itemCount, bytesAfter;
char* data;
XEvent event;
XConvertSelection(_glfw.x11.display, XConvertSelection(_glfw.x11.display,
_glfw.x11.CLIPBOARD, _glfw.x11.CLIPBOARD,
_glfw.x11.selection.target, _glfw.x11.selection.formats[i],
_glfw.x11.selection.property, _glfw.x11.selection.property,
window->x11.handle, CurrentTime); window->x11.handle, CurrentTime);
// Process the resulting SelectionNotify event // XCheckTypedEvent is used instead of XIfEvent in order not to lock
XSync(_glfw.x11.display, False); // other threads out from the display during the entire wait period
while (_glfw.x11.selection.status == _GLFW_CONVERSION_INACTIVE) while (!XCheckTypedEvent(_glfw.x11.display, SelectionNotify, &event))
_glfwPlatformWaitEvents(); ;
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; break;
} }
if (_glfw.x11.selection.status == _GLFW_CONVERSION_FAILED) if (_glfw.x11.selection.string == NULL)
{ {
_glfwInputError(GLFW_FORMAT_UNAVAILABLE, _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
"X11: Failed to convert selection to string"); "X11: Failed to convert selection to string");
return NULL;
} }
return _glfw.x11.selection.string; return _glfw.x11.selection.string;

View File

@ -63,17 +63,12 @@
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11 #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorX11 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_UTF8 0
#define _GLFW_CLIPBOARD_FORMAT_COMPOUND 1 #define _GLFW_CLIPBOARD_FORMAT_COMPOUND 1
#define _GLFW_CLIPBOARD_FORMAT_STRING 2 #define _GLFW_CLIPBOARD_FORMAT_STRING 2
#define _GLFW_CLIPBOARD_FORMAT_COUNT 3 #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 // GLFW platform specific types
@ -184,9 +179,7 @@ typedef struct _GLFWlibraryX11
struct { struct {
Atom formats[_GLFW_CLIPBOARD_FORMAT_COUNT]; Atom formats[_GLFW_CLIPBOARD_FORMAT_COUNT];
char* string; char* string;
Atom target;
Atom property; Atom property;
int status;
} selection; } selection;
struct { struct {
@ -251,13 +244,13 @@ void _glfwTerminateJoysticks(void);
long _glfwKeySym2Unicode(KeySym keysym); long _glfwKeySym2Unicode(KeySym keysym);
// Clipboard handling // Clipboard handling
GLboolean _glfwReadSelection(XSelectionEvent* request);
Atom _glfwWriteSelection(XSelectionRequestEvent* request); Atom _glfwWriteSelection(XSelectionRequestEvent* request);
// Event processing // Event processing
void _glfwProcessPendingEvents(void); void _glfwProcessPendingEvents(void);
// Window support // Window support
_GLFWwindow* _glfwFindWindowByHandle(Window handle);
unsigned long _glfwGetWindowProperty(Window window, unsigned long _glfwGetWindowProperty(Window window,
Atom property, Atom property,
Atom type, Atom type,

View File

@ -451,7 +451,7 @@ static void leaveFullscreenMode(_GLFWwindow* window)
// Return the GLFW window corresponding to the specified X11 window // Return the GLFW window corresponding to the specified X11 window
//======================================================================== //========================================================================
static _GLFWwindow* findWindow(Window handle) _GLFWwindow* _glfwFindWindowByHandle(Window handle)
{ {
_GLFWwindow* window; _GLFWwindow* window;
@ -475,7 +475,7 @@ static void processEvent(XEvent *event)
if (event->type != GenericEvent) if (event->type != GenericEvent)
{ {
window = findWindow(event->xany.window); window = _glfwFindWindowByHandle(event->xany.window);
if (window == NULL) if (window == NULL)
{ {
// This is either an event for a destroyed GLFW window or an event // This is either an event for a destroyed GLFW window or an event
@ -710,20 +710,6 @@ static void processEvent(XEvent *event)
break; 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: case SelectionRequest:
{ {
// The contents of the clipboard selection was requested // The contents of the clipboard selection was requested
@ -993,11 +979,11 @@ void _glfwPlatformHideWindow(_GLFWwindow* window)
void _glfwPlatformPollEvents(void) void _glfwPlatformPollEvents(void)
{ {
XEvent event; int count = XPending(_glfw.x11.display);
while (count--)
while (XCheckMaskEvent(_glfw.x11.display, ~0, &event) ||
XCheckTypedEvent(_glfw.x11.display, ClientMessage, &event))
{ {
XEvent event;
XNextEvent(_glfw.x11.display, &event);
processEvent(&event); processEvent(&event);
} }
@ -1026,6 +1012,8 @@ void _glfwPlatformPollEvents(void)
void _glfwPlatformWaitEvents(void) void _glfwPlatformWaitEvents(void)
{ {
if (!XPending(_glfw.x11.display))
{
int fd; int fd;
fd_set fds; fd_set fds;
@ -1034,12 +1022,13 @@ void _glfwPlatformWaitEvents(void)
FD_ZERO(&fds); FD_ZERO(&fds);
FD_SET(fd, &fds); FD_SET(fd, &fds);
XFlush(_glfw.x11.display);
// select(1) is used instead of an X function like XNextEvent, as the // select(1) is used instead of an X function like XNextEvent, as the
// wait inside those are guarded by the mutex protecting the display // wait inside those are guarded by the mutex protecting the display
// struct, locking out other threads from using X (including GLX) // 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(); _glfwPlatformPollEvents();
} }