Added support for multithreaded use of Xlib.

This commit is contained in:
Riku Salminen 2012-08-12 15:57:52 +02:00 committed by Camilla Berglund
parent cd37da470f
commit 3d6221c490
2 changed files with 73 additions and 66 deletions

View File

@ -634,6 +634,8 @@ static void terminateDisplay(void)
int _glfwPlatformInit(void) int _glfwPlatformInit(void)
{ {
XInitThreads();
if (!initDisplay()) if (!initDisplay())
return GL_FALSE; return GL_FALSE;

View File

@ -468,19 +468,16 @@ static _GLFWwindow* findWindow(Window handle)
// Get and process next X event (called by _glfwPlatformPollEvents) // Get and process next X event (called by _glfwPlatformPollEvents)
//======================================================================== //========================================================================
static void processSingleEvent(void) static void processSingleEvent(XEvent *event)
{ {
_GLFWwindow* window; _GLFWwindow* window;
XEvent event; switch (event->type)
XNextEvent(_glfwLibrary.X11.display, &event);
switch (event.type)
{ {
case KeyPress: case KeyPress:
{ {
// A keyboard key was pressed // A keyboard key was pressed
window = findWindow(event.xkey.window); window = findWindow(event->xkey.window);
if (window == NULL) if (window == NULL)
{ {
fprintf(stderr, "Cannot find GLFW window structure for KeyPress event\n"); fprintf(stderr, "Cannot find GLFW window structure for KeyPress event\n");
@ -488,10 +485,10 @@ static void processSingleEvent(void)
} }
// Translate and report key press // Translate and report key press
_glfwInputKey(window, translateKey(event.xkey.keycode), GLFW_PRESS); _glfwInputKey(window, translateKey(event->xkey.keycode), GLFW_PRESS);
// Translate and report character input // Translate and report character input
_glfwInputChar(window, translateChar(&event.xkey)); _glfwInputChar(window, translateChar(&event->xkey));
break; break;
} }
@ -499,7 +496,7 @@ static void processSingleEvent(void)
case KeyRelease: case KeyRelease:
{ {
// A keyboard key was released // A keyboard key was released
window = findWindow(event.xkey.window); window = findWindow(event->xkey.window);
if (window == NULL) if (window == NULL)
{ {
fprintf(stderr, "Cannot find GLFW window structure for KeyRelease event\n"); fprintf(stderr, "Cannot find GLFW window structure for KeyRelease event\n");
@ -516,15 +513,15 @@ static void processSingleEvent(void)
XPeekEvent(_glfwLibrary.X11.display, &nextEvent); XPeekEvent(_glfwLibrary.X11.display, &nextEvent);
if (nextEvent.type == KeyPress && if (nextEvent.type == KeyPress &&
nextEvent.xkey.window == event.xkey.window && nextEvent.xkey.window == event->xkey.window &&
nextEvent.xkey.keycode == event.xkey.keycode) nextEvent.xkey.keycode == event->xkey.keycode)
{ {
// This last check is a hack to work around key repeats // This last check is a hack to work around key repeats
// leaking through due to some sort of time drift // leaking through due to some sort of time drift
// Toshiyuki Takahashi can press a button 16 times per // Toshiyuki Takahashi can press a button 16 times per
// second so it's fairly safe to assume that no human is // second so it's fairly safe to assume that no human is
// pressing the key 50 times per second (value is ms) // pressing the key 50 times per second (value is ms)
if ((nextEvent.xkey.time - event.xkey.time) < 20) if ((nextEvent.xkey.time - event->xkey.time) < 20)
{ {
// Do not report anything for this event // Do not report anything for this event
break; break;
@ -533,7 +530,7 @@ static void processSingleEvent(void)
} }
// Translate and report key release // Translate and report key release
_glfwInputKey(window, translateKey(event.xkey.keycode), GLFW_RELEASE); _glfwInputKey(window, translateKey(event->xkey.keycode), GLFW_RELEASE);
break; break;
} }
@ -541,30 +538,30 @@ static void processSingleEvent(void)
case ButtonPress: case ButtonPress:
{ {
// A mouse button was pressed or a scrolling event occurred // A mouse button was pressed or a scrolling event occurred
window = findWindow(event.xbutton.window); window = findWindow(event->xbutton.window);
if (window == NULL) if (window == NULL)
{ {
fprintf(stderr, "Cannot find GLFW window structure for ButtonPress event\n"); fprintf(stderr, "Cannot find GLFW window structure for ButtonPress event\n");
return; return;
} }
if (event.xbutton.button == Button1) if (event->xbutton.button == Button1)
_glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS); _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS);
else if (event.xbutton.button == Button2) else if (event->xbutton.button == Button2)
_glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS); _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS);
else if (event.xbutton.button == Button3) else if (event->xbutton.button == Button3)
_glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS); _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS);
// XFree86 3.3.2 and later translates mouse wheel up/down into // XFree86 3.3.2 and later translates mouse wheel up/down into
// mouse button 4 & 5 presses // mouse button 4 & 5 presses
else if (event.xbutton.button == Button4) else if (event->xbutton.button == Button4)
_glfwInputScroll(window, 0.0, 1.0); _glfwInputScroll(window, 0.0, 1.0);
else if (event.xbutton.button == Button5) else if (event->xbutton.button == Button5)
_glfwInputScroll(window, 0.0, -1.0); _glfwInputScroll(window, 0.0, -1.0);
else if (event.xbutton.button == Button6) else if (event->xbutton.button == Button6)
_glfwInputScroll(window, -1.0, 0.0); _glfwInputScroll(window, -1.0, 0.0);
else if (event.xbutton.button == Button7) else if (event->xbutton.button == Button7)
_glfwInputScroll(window, 1.0, 0.0); _glfwInputScroll(window, 1.0, 0.0);
break; break;
@ -573,26 +570,26 @@ static void processSingleEvent(void)
case ButtonRelease: case ButtonRelease:
{ {
// A mouse button was released // A mouse button was released
window = findWindow(event.xbutton.window); window = findWindow(event->xbutton.window);
if (window == NULL) if (window == NULL)
{ {
fprintf(stderr, "Cannot find GLFW window structure for ButtonRelease event\n"); fprintf(stderr, "Cannot find GLFW window structure for ButtonRelease event\n");
return; return;
} }
if (event.xbutton.button == Button1) if (event->xbutton.button == Button1)
{ {
_glfwInputMouseClick(window, _glfwInputMouseClick(window,
GLFW_MOUSE_BUTTON_LEFT, GLFW_MOUSE_BUTTON_LEFT,
GLFW_RELEASE); GLFW_RELEASE);
} }
else if (event.xbutton.button == Button2) else if (event->xbutton.button == Button2)
{ {
_glfwInputMouseClick(window, _glfwInputMouseClick(window,
GLFW_MOUSE_BUTTON_MIDDLE, GLFW_MOUSE_BUTTON_MIDDLE,
GLFW_RELEASE); GLFW_RELEASE);
} }
else if (event.xbutton.button == Button3) else if (event->xbutton.button == Button3)
{ {
_glfwInputMouseClick(window, _glfwInputMouseClick(window,
GLFW_MOUSE_BUTTON_RIGHT, GLFW_MOUSE_BUTTON_RIGHT,
@ -604,7 +601,7 @@ static void processSingleEvent(void)
case EnterNotify: case EnterNotify:
{ {
// The cursor entered the window // The cursor entered the window
window = findWindow(event.xcrossing.window); window = findWindow(event->xcrossing.window);
if (window == NULL) if (window == NULL)
{ {
fprintf(stderr, "Cannot find GLFW window structure for EnterNotify event\n"); fprintf(stderr, "Cannot find GLFW window structure for EnterNotify event\n");
@ -621,7 +618,7 @@ static void processSingleEvent(void)
case LeaveNotify: case LeaveNotify:
{ {
// The cursor left the window // The cursor left the window
window = findWindow(event.xcrossing.window); window = findWindow(event->xcrossing.window);
if (window == NULL) if (window == NULL)
{ {
fprintf(stderr, "Cannot find GLFW window structure for LeaveNotify event\n"); fprintf(stderr, "Cannot find GLFW window structure for LeaveNotify event\n");
@ -638,15 +635,15 @@ static void processSingleEvent(void)
case MotionNotify: case MotionNotify:
{ {
// The cursor was moved // The cursor was moved
window = findWindow(event.xmotion.window); window = findWindow(event->xmotion.window);
if (window == NULL) if (window == NULL)
{ {
fprintf(stderr, "Cannot find GLFW window structure for MotionNotify event\n"); fprintf(stderr, "Cannot find GLFW window structure for MotionNotify event\n");
return; return;
} }
if (event.xmotion.x != window->X11.cursorPosX || if (event->xmotion.x != window->X11.cursorPosX ||
event.xmotion.y != window->X11.cursorPosY) event->xmotion.y != window->X11.cursorPosY)
{ {
// The cursor was moved and we didn't do it // The cursor was moved and we didn't do it
int x, y; int x, y;
@ -656,17 +653,17 @@ static void processSingleEvent(void)
if (_glfwLibrary.activeWindow != window) if (_glfwLibrary.activeWindow != window)
break; break;
x = event.xmotion.x - window->X11.cursorPosX; x = event->xmotion.x - window->X11.cursorPosX;
y = event.xmotion.y - window->X11.cursorPosY; y = event->xmotion.y - window->X11.cursorPosY;
} }
else else
{ {
x = event.xmotion.x; x = event->xmotion.x;
y = event.xmotion.y; y = event->xmotion.y;
} }
window->X11.cursorPosX = event.xmotion.x; window->X11.cursorPosX = event->xmotion.x;
window->X11.cursorPosY = event.xmotion.y; window->X11.cursorPosY = event->xmotion.y;
window->X11.cursorCentered = GL_FALSE; window->X11.cursorCentered = GL_FALSE;
_glfwInputCursorMotion(window, x, y); _glfwInputCursorMotion(window, x, y);
@ -678,7 +675,7 @@ static void processSingleEvent(void)
case ConfigureNotify: case ConfigureNotify:
{ {
// The window configuration changed somehow // The window configuration changed somehow
window = findWindow(event.xconfigure.window); window = findWindow(event->xconfigure.window);
if (window == NULL) if (window == NULL)
{ {
fprintf(stderr, "Cannot find GLFW window structure for ConfigureNotify event\n"); fprintf(stderr, "Cannot find GLFW window structure for ConfigureNotify event\n");
@ -686,12 +683,12 @@ static void processSingleEvent(void)
} }
_glfwInputWindowSize(window, _glfwInputWindowSize(window,
event.xconfigure.width, event->xconfigure.width,
event.xconfigure.height); event->xconfigure.height);
_glfwInputWindowPos(window, _glfwInputWindowPos(window,
event.xconfigure.x, event->xconfigure.x,
event.xconfigure.y); event->xconfigure.y);
break; break;
} }
@ -699,14 +696,14 @@ static void processSingleEvent(void)
case ClientMessage: case ClientMessage:
{ {
// Custom client message, probably from the window manager // Custom client message, probably from the window manager
window = findWindow(event.xclient.window); window = findWindow(event->xclient.window);
if (window == NULL) if (window == NULL)
{ {
fprintf(stderr, "Cannot find GLFW window structure for ClientMessage event\n"); fprintf(stderr, "Cannot find GLFW window structure for ClientMessage event\n");
return; return;
} }
if ((Atom) event.xclient.data.l[0] == _glfwLibrary.X11.wmDeleteWindow) if ((Atom) event->xclient.data.l[0] == _glfwLibrary.X11.wmDeleteWindow)
{ {
// The window manager was asked to close the window, for example by // The window manager was asked to close the window, for example by
// the user pressing a 'close' window decoration button // the user pressing a 'close' window decoration button
@ -714,17 +711,17 @@ static void processSingleEvent(void)
_glfwInputWindowCloseRequest(window); _glfwInputWindowCloseRequest(window);
} }
else if (_glfwLibrary.X11.wmPing != None && else if (_glfwLibrary.X11.wmPing != None &&
(Atom) event.xclient.data.l[0] == _glfwLibrary.X11.wmPing) (Atom) event->xclient.data.l[0] == _glfwLibrary.X11.wmPing)
{ {
// The window manager is pinging us to make sure we are still // The window manager is pinging us to make sure we are still
// responding to events // responding to events
event.xclient.window = _glfwLibrary.X11.root; event->xclient.window = _glfwLibrary.X11.root;
XSendEvent(_glfwLibrary.X11.display, XSendEvent(_glfwLibrary.X11.display,
event.xclient.window, event->xclient.window,
False, False,
SubstructureNotifyMask | SubstructureRedirectMask, SubstructureNotifyMask | SubstructureRedirectMask,
&event); event);
} }
break; break;
@ -733,7 +730,7 @@ static void processSingleEvent(void)
case MapNotify: case MapNotify:
{ {
// The window was mapped // The window was mapped
window = findWindow(event.xmap.window); window = findWindow(event->xmap.window);
if (window == NULL) if (window == NULL)
{ {
fprintf(stderr, "Cannot find GLFW window structure for MapNotify event\n"); fprintf(stderr, "Cannot find GLFW window structure for MapNotify event\n");
@ -747,7 +744,7 @@ static void processSingleEvent(void)
case UnmapNotify: case UnmapNotify:
{ {
// The window was unmapped // The window was unmapped
window = findWindow(event.xmap.window); window = findWindow(event->xmap.window);
if (window == NULL) if (window == NULL)
{ {
fprintf(stderr, "Cannot find GLFW window structure for UnmapNotify event\n"); fprintf(stderr, "Cannot find GLFW window structure for UnmapNotify event\n");
@ -761,7 +758,7 @@ static void processSingleEvent(void)
case FocusIn: case FocusIn:
{ {
// The window gained focus // The window gained focus
window = findWindow(event.xfocus.window); window = findWindow(event->xfocus.window);
if (window == NULL) if (window == NULL)
{ {
fprintf(stderr, "Cannot find GLFW window structure for FocusIn event\n"); fprintf(stderr, "Cannot find GLFW window structure for FocusIn event\n");
@ -779,7 +776,7 @@ static void processSingleEvent(void)
case FocusOut: case FocusOut:
{ {
// The window lost focus // The window lost focus
window = findWindow(event.xfocus.window); window = findWindow(event->xfocus.window);
if (window == NULL) if (window == NULL)
{ {
fprintf(stderr, "Cannot find GLFW window structure for FocusOut event\n"); fprintf(stderr, "Cannot find GLFW window structure for FocusOut event\n");
@ -797,7 +794,7 @@ static void processSingleEvent(void)
case Expose: case Expose:
{ {
// The window's contents was damaged // The window's contents was damaged
window = findWindow(event.xexpose.window); window = findWindow(event->xexpose.window);
if (window == NULL) if (window == NULL)
{ {
fprintf(stderr, "Cannot find GLFW window structure for Expose event\n"); fprintf(stderr, "Cannot find GLFW window structure for Expose event\n");
@ -821,7 +818,7 @@ static void processSingleEvent(void)
{ {
// The selection conversion status is available // The selection conversion status is available
XSelectionEvent* request = &event.xselection; XSelectionEvent* request = &event->xselection;
if (_glfwReadSelection(request)) if (_glfwReadSelection(request))
_glfwLibrary.X11.selection.status = _GLFW_CONVERSION_SUCCEEDED; _glfwLibrary.X11.selection.status = _GLFW_CONVERSION_SUCCEEDED;
@ -835,7 +832,7 @@ static void processSingleEvent(void)
{ {
// The contents of the selection was requested // The contents of the selection was requested
XSelectionRequestEvent* request = &event.xselectionrequest; XSelectionRequestEvent* request = &event->xselectionrequest;
XEvent response; XEvent response;
memset(&response, 0, sizeof(response)); memset(&response, 0, sizeof(response));
@ -860,12 +857,12 @@ static void processSingleEvent(void)
default: default:
{ {
#if defined(_GLFW_HAS_XRANDR) #if defined(_GLFW_HAS_XRANDR)
switch (event.type - _glfwLibrary.X11.RandR.eventBase) switch (event->type - _glfwLibrary.X11.RandR.eventBase)
{ {
case RRScreenChangeNotify: case RRScreenChangeNotify:
{ {
// Show XRandR that we really care // Show XRandR that we really care
XRRUpdateConfiguration(&event); XRRUpdateConfiguration(event);
break; break;
} }
} }
@ -1146,13 +1143,14 @@ void _glfwPlatformRefreshWindowParams(_GLFWwindow* window)
void _glfwPlatformPollEvents(void) void _glfwPlatformPollEvents(void)
{ {
_GLFWwindow* window; XEvent event;
while(XCheckMaskEvent(_glfwLibrary.X11.display, ~0, &event) ||
// Process all pending events XCheckTypedEvent(_glfwLibrary.X11.display, ClientMessage, &event))
while (XPending(_glfwLibrary.X11.display)) processSingleEvent(&event);
processSingleEvent();
#if 0
// Did the cursor move in an active window that has captured the cursor // Did the cursor move in an active window that has captured the cursor
_GLFWwindow* window;
window = _glfwLibrary.activeWindow; window = _glfwLibrary.activeWindow;
if (window) if (window)
{ {
@ -1170,8 +1168,10 @@ void _glfwPlatformPollEvents(void)
XFlush( _glfwLibrary.X11.display ); XFlush( _glfwLibrary.X11.display );
} }
} }
#endif
} }
#include <sys/select.h>
//======================================================================== //========================================================================
// Wait for new window and input events // Wait for new window and input events
@ -1179,13 +1179,18 @@ void _glfwPlatformPollEvents(void)
void _glfwPlatformWaitEvents(void) void _glfwPlatformWaitEvents(void)
{ {
XEvent event; fd_set set;
int fd;
// Block waiting for an event to arrive fd = ConnectionNumber(_glfwLibrary.X11.display);
XNextEvent(_glfwLibrary.X11.display, &event);
XPutBackEvent(_glfwLibrary.X11.display, &event);
_glfwPlatformPollEvents(); FD_ZERO(&set);
FD_SET(fd, &set);
XFlush(_glfwLibrary.X11.display);
if(select(fd+1, &set, NULL, NULL, NULL) > 0)
_glfwPlatformPollEvents();
} }