mirror of
https://github.com/glfw/glfw.git
synced 2024-11-22 21:14:35 +00:00
Fixed X11 clipboard regressions, event waiting.
This commit is contained in:
parent
f3e39ce680
commit
e209ac7a42
@ -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;
|
||||||
|
@ -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,
|
||||||
|
@ -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,21 +1012,24 @@ void _glfwPlatformPollEvents(void)
|
|||||||
|
|
||||||
void _glfwPlatformWaitEvents(void)
|
void _glfwPlatformWaitEvents(void)
|
||||||
{
|
{
|
||||||
int fd;
|
if (!XPending(_glfw.x11.display))
|
||||||
fd_set fds;
|
{
|
||||||
|
int fd;
|
||||||
|
fd_set fds;
|
||||||
|
|
||||||
fd = ConnectionNumber(_glfw.x11.display);
|
fd = ConnectionNumber(_glfw.x11.display);
|
||||||
|
|
||||||
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
|
||||||
|
// 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
|
_glfwPlatformPollEvents();
|
||||||
// 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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwPlatformSetCursorPos(_GLFWwindow* window, int x, int y)
|
void _glfwPlatformSetCursorPos(_GLFWwindow* window, int x, int y)
|
||||||
|
Loading…
Reference in New Issue
Block a user