mirror of
https://github.com/glfw/glfw.git
synced 2024-11-22 13:04:35 +00:00
5ccc756c56
There is a seemingly unavoidable race condition when waiting for data on
the X11 display connection, as long as any other thread is also making
Xlib calls. The event data we are waiting for could be read by the
other thread as part of looking for the reply to its request, before our
poll has begun.
This commit replaces the X11 event sent by glfwPostEmptyEvent with
writing to an unnamed pipe. The race condition remains if other Xlib
calls are made on other threads, but glfwPostEmptyEvent should now be
race-free.
This commit is based on work by pcwalton, OlivierSohn, kovidgoyal and
joaodasilva.
Closes #2033
Related to #379
Related to #1281
Related to #1285
(cherry picked from commit cd22e28495
)
449 lines
16 KiB
C
449 lines
16 KiB
C
//========================================================================
|
|
// GLFW 3.3 X11 - www.glfw.org
|
|
//------------------------------------------------------------------------
|
|
// Copyright (c) 2002-2006 Marcus Geelnard
|
|
// Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
|
|
//
|
|
// This software is provided 'as-is', without any express or implied
|
|
// warranty. In no event will the authors be held liable for any damages
|
|
// arising from the use of this software.
|
|
//
|
|
// Permission is granted to anyone to use this software for any purpose,
|
|
// including commercial applications, and to alter it and redistribute it
|
|
// freely, subject to the following restrictions:
|
|
//
|
|
// 1. The origin of this software must not be misrepresented; you must not
|
|
// claim that you wrote the original software. If you use this software
|
|
// in a product, an acknowledgment in the product documentation would
|
|
// be appreciated but is not required.
|
|
//
|
|
// 2. Altered source versions must be plainly marked as such, and must not
|
|
// be misrepresented as being the original software.
|
|
//
|
|
// 3. This notice may not be removed or altered from any source
|
|
// distribution.
|
|
//
|
|
//========================================================================
|
|
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
#include <stdint.h>
|
|
#include <dlfcn.h>
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/keysym.h>
|
|
#include <X11/Xatom.h>
|
|
#include <X11/Xcursor/Xcursor.h>
|
|
|
|
// The XRandR extension provides mode setting and gamma control
|
|
#include <X11/extensions/Xrandr.h>
|
|
|
|
// The Xkb extension provides improved keyboard support
|
|
#include <X11/XKBlib.h>
|
|
|
|
// The Xinerama extension provides legacy monitor indices
|
|
#include <X11/extensions/Xinerama.h>
|
|
|
|
// The XInput extension provides raw mouse motion input
|
|
#include <X11/extensions/XInput2.h>
|
|
|
|
typedef XRRCrtcGamma* (* PFN_XRRAllocGamma)(int);
|
|
typedef void (* PFN_XRRFreeCrtcInfo)(XRRCrtcInfo*);
|
|
typedef void (* PFN_XRRFreeGamma)(XRRCrtcGamma*);
|
|
typedef void (* PFN_XRRFreeOutputInfo)(XRROutputInfo*);
|
|
typedef void (* PFN_XRRFreeScreenResources)(XRRScreenResources*);
|
|
typedef XRRCrtcGamma* (* PFN_XRRGetCrtcGamma)(Display*,RRCrtc);
|
|
typedef int (* PFN_XRRGetCrtcGammaSize)(Display*,RRCrtc);
|
|
typedef XRRCrtcInfo* (* PFN_XRRGetCrtcInfo) (Display*,XRRScreenResources*,RRCrtc);
|
|
typedef XRROutputInfo* (* PFN_XRRGetOutputInfo)(Display*,XRRScreenResources*,RROutput);
|
|
typedef RROutput (* PFN_XRRGetOutputPrimary)(Display*,Window);
|
|
typedef XRRScreenResources* (* PFN_XRRGetScreenResourcesCurrent)(Display*,Window);
|
|
typedef Bool (* PFN_XRRQueryExtension)(Display*,int*,int*);
|
|
typedef Status (* PFN_XRRQueryVersion)(Display*,int*,int*);
|
|
typedef void (* PFN_XRRSelectInput)(Display*,Window,int);
|
|
typedef Status (* PFN_XRRSetCrtcConfig)(Display*,XRRScreenResources*,RRCrtc,Time,int,int,RRMode,Rotation,RROutput*,int);
|
|
typedef void (* PFN_XRRSetCrtcGamma)(Display*,RRCrtc,XRRCrtcGamma*);
|
|
typedef int (* PFN_XRRUpdateConfiguration)(XEvent*);
|
|
#define XRRAllocGamma _glfw.x11.randr.AllocGamma
|
|
#define XRRFreeCrtcInfo _glfw.x11.randr.FreeCrtcInfo
|
|
#define XRRFreeGamma _glfw.x11.randr.FreeGamma
|
|
#define XRRFreeOutputInfo _glfw.x11.randr.FreeOutputInfo
|
|
#define XRRFreeScreenResources _glfw.x11.randr.FreeScreenResources
|
|
#define XRRGetCrtcGamma _glfw.x11.randr.GetCrtcGamma
|
|
#define XRRGetCrtcGammaSize _glfw.x11.randr.GetCrtcGammaSize
|
|
#define XRRGetCrtcInfo _glfw.x11.randr.GetCrtcInfo
|
|
#define XRRGetOutputInfo _glfw.x11.randr.GetOutputInfo
|
|
#define XRRGetOutputPrimary _glfw.x11.randr.GetOutputPrimary
|
|
#define XRRGetScreenResourcesCurrent _glfw.x11.randr.GetScreenResourcesCurrent
|
|
#define XRRQueryExtension _glfw.x11.randr.QueryExtension
|
|
#define XRRQueryVersion _glfw.x11.randr.QueryVersion
|
|
#define XRRSelectInput _glfw.x11.randr.SelectInput
|
|
#define XRRSetCrtcConfig _glfw.x11.randr.SetCrtcConfig
|
|
#define XRRSetCrtcGamma _glfw.x11.randr.SetCrtcGamma
|
|
#define XRRUpdateConfiguration _glfw.x11.randr.UpdateConfiguration
|
|
|
|
typedef XcursorImage* (* PFN_XcursorImageCreate)(int,int);
|
|
typedef void (* PFN_XcursorImageDestroy)(XcursorImage*);
|
|
typedef Cursor (* PFN_XcursorImageLoadCursor)(Display*,const XcursorImage*);
|
|
#define XcursorImageCreate _glfw.x11.xcursor.ImageCreate
|
|
#define XcursorImageDestroy _glfw.x11.xcursor.ImageDestroy
|
|
#define XcursorImageLoadCursor _glfw.x11.xcursor.ImageLoadCursor
|
|
|
|
typedef Bool (* PFN_XineramaIsActive)(Display*);
|
|
typedef Bool (* PFN_XineramaQueryExtension)(Display*,int*,int*);
|
|
typedef XineramaScreenInfo* (* PFN_XineramaQueryScreens)(Display*,int*);
|
|
#define XineramaIsActive _glfw.x11.xinerama.IsActive
|
|
#define XineramaQueryExtension _glfw.x11.xinerama.QueryExtension
|
|
#define XineramaQueryScreens _glfw.x11.xinerama.QueryScreens
|
|
|
|
typedef XID xcb_window_t;
|
|
typedef XID xcb_visualid_t;
|
|
typedef struct xcb_connection_t xcb_connection_t;
|
|
typedef xcb_connection_t* (* PFN_XGetXCBConnection)(Display*);
|
|
#define XGetXCBConnection _glfw.x11.x11xcb.GetXCBConnection
|
|
|
|
typedef Bool (* PFN_XF86VidModeQueryExtension)(Display*,int*,int*);
|
|
typedef Bool (* PFN_XF86VidModeGetGammaRamp)(Display*,int,int,unsigned short*,unsigned short*,unsigned short*);
|
|
typedef Bool (* PFN_XF86VidModeSetGammaRamp)(Display*,int,int,unsigned short*,unsigned short*,unsigned short*);
|
|
typedef Bool (* PFN_XF86VidModeGetGammaRampSize)(Display*,int,int*);
|
|
#define XF86VidModeQueryExtension _glfw.x11.vidmode.QueryExtension
|
|
#define XF86VidModeGetGammaRamp _glfw.x11.vidmode.GetGammaRamp
|
|
#define XF86VidModeSetGammaRamp _glfw.x11.vidmode.SetGammaRamp
|
|
#define XF86VidModeGetGammaRampSize _glfw.x11.vidmode.GetGammaRampSize
|
|
|
|
typedef Status (* PFN_XIQueryVersion)(Display*,int*,int*);
|
|
typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int);
|
|
#define XIQueryVersion _glfw.x11.xi.QueryVersion
|
|
#define XISelectEvents _glfw.x11.xi.SelectEvents
|
|
|
|
typedef Bool (* PFN_XRenderQueryExtension)(Display*,int*,int*);
|
|
typedef Status (* PFN_XRenderQueryVersion)(Display*dpy,int*,int*);
|
|
typedef XRenderPictFormat* (* PFN_XRenderFindVisualFormat)(Display*,Visual const*);
|
|
#define XRenderQueryExtension _glfw.x11.xrender.QueryExtension
|
|
#define XRenderQueryVersion _glfw.x11.xrender.QueryVersion
|
|
#define XRenderFindVisualFormat _glfw.x11.xrender.FindVisualFormat
|
|
|
|
typedef VkFlags VkXlibSurfaceCreateFlagsKHR;
|
|
typedef VkFlags VkXcbSurfaceCreateFlagsKHR;
|
|
|
|
typedef struct VkXlibSurfaceCreateInfoKHR
|
|
{
|
|
VkStructureType sType;
|
|
const void* pNext;
|
|
VkXlibSurfaceCreateFlagsKHR flags;
|
|
Display* dpy;
|
|
Window window;
|
|
} VkXlibSurfaceCreateInfoKHR;
|
|
|
|
typedef struct VkXcbSurfaceCreateInfoKHR
|
|
{
|
|
VkStructureType sType;
|
|
const void* pNext;
|
|
VkXcbSurfaceCreateFlagsKHR flags;
|
|
xcb_connection_t* connection;
|
|
xcb_window_t window;
|
|
} VkXcbSurfaceCreateInfoKHR;
|
|
|
|
typedef VkResult (APIENTRY *PFN_vkCreateXlibSurfaceKHR)(VkInstance,const VkXlibSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
|
|
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice,uint32_t,Display*,VisualID);
|
|
typedef VkResult (APIENTRY *PFN_vkCreateXcbSurfaceKHR)(VkInstance,const VkXcbSurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
|
|
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice,uint32_t,xcb_connection_t*,xcb_visualid_t);
|
|
|
|
#include "posix_thread.h"
|
|
#include "posix_time.h"
|
|
#include "xkb_unicode.h"
|
|
#include "glx_context.h"
|
|
#include "egl_context.h"
|
|
#include "osmesa_context.h"
|
|
#if defined(__linux__)
|
|
#include "linux_joystick.h"
|
|
#else
|
|
#include "null_joystick.h"
|
|
#endif
|
|
|
|
#define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
|
|
#define _glfw_dlclose(handle) dlclose(handle)
|
|
#define _glfw_dlsym(handle, name) dlsym(handle, name)
|
|
|
|
#define _GLFW_EGL_NATIVE_WINDOW ((EGLNativeWindowType) window->x11.handle)
|
|
#define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.x11.display)
|
|
|
|
#define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowX11 x11
|
|
#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11
|
|
#define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorX11 x11
|
|
#define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorX11 x11
|
|
|
|
|
|
// X11-specific per-window data
|
|
//
|
|
typedef struct _GLFWwindowX11
|
|
{
|
|
Colormap colormap;
|
|
Window handle;
|
|
Window parent;
|
|
XIC ic;
|
|
|
|
GLFWbool overrideRedirect;
|
|
GLFWbool iconified;
|
|
GLFWbool maximized;
|
|
|
|
// Whether the visual supports framebuffer transparency
|
|
GLFWbool transparent;
|
|
|
|
// Cached position and size used to filter out duplicate events
|
|
int width, height;
|
|
int xpos, ypos;
|
|
|
|
// The last received cursor position, regardless of source
|
|
int lastCursorPosX, lastCursorPosY;
|
|
// The last position the cursor was warped to by GLFW
|
|
int warpCursorPosX, warpCursorPosY;
|
|
|
|
// The time of the last KeyPress event per keycode, for discarding
|
|
// duplicate key events generated for some keys by ibus
|
|
Time keyPressTimes[256];
|
|
} _GLFWwindowX11;
|
|
|
|
// X11-specific global data
|
|
//
|
|
typedef struct _GLFWlibraryX11
|
|
{
|
|
Display* display;
|
|
int screen;
|
|
Window root;
|
|
|
|
// System content scale
|
|
float contentScaleX, contentScaleY;
|
|
// Helper window for IPC
|
|
Window helperWindowHandle;
|
|
// Invisible cursor for hidden cursor mode
|
|
Cursor hiddenCursorHandle;
|
|
// Context for mapping window XIDs to _GLFWwindow pointers
|
|
XContext context;
|
|
// XIM input method
|
|
XIM im;
|
|
// Most recent error code received by X error handler
|
|
int errorCode;
|
|
// Primary selection string (while the primary selection is owned)
|
|
char* primarySelectionString;
|
|
// Clipboard string (while the selection is owned)
|
|
char* clipboardString;
|
|
// Key name string
|
|
char keynames[GLFW_KEY_LAST + 1][5];
|
|
// X11 keycode to GLFW key LUT
|
|
short int keycodes[256];
|
|
// GLFW key to X11 keycode LUT
|
|
short int scancodes[GLFW_KEY_LAST + 1];
|
|
// Where to place the cursor when re-enabled
|
|
double restoreCursorPosX, restoreCursorPosY;
|
|
// The window whose disabled cursor mode is active
|
|
_GLFWwindow* disabledCursorWindow;
|
|
int emptyEventPipe[2];
|
|
|
|
// Window manager atoms
|
|
Atom NET_SUPPORTED;
|
|
Atom NET_SUPPORTING_WM_CHECK;
|
|
Atom WM_PROTOCOLS;
|
|
Atom WM_STATE;
|
|
Atom WM_DELETE_WINDOW;
|
|
Atom NET_WM_NAME;
|
|
Atom NET_WM_ICON_NAME;
|
|
Atom NET_WM_ICON;
|
|
Atom NET_WM_PID;
|
|
Atom NET_WM_PING;
|
|
Atom NET_WM_WINDOW_TYPE;
|
|
Atom NET_WM_WINDOW_TYPE_NORMAL;
|
|
Atom NET_WM_STATE;
|
|
Atom NET_WM_STATE_ABOVE;
|
|
Atom NET_WM_STATE_FULLSCREEN;
|
|
Atom NET_WM_STATE_MAXIMIZED_VERT;
|
|
Atom NET_WM_STATE_MAXIMIZED_HORZ;
|
|
Atom NET_WM_STATE_DEMANDS_ATTENTION;
|
|
Atom NET_WM_BYPASS_COMPOSITOR;
|
|
Atom NET_WM_FULLSCREEN_MONITORS;
|
|
Atom NET_WM_WINDOW_OPACITY;
|
|
Atom NET_WM_CM_Sx;
|
|
Atom NET_WORKAREA;
|
|
Atom NET_CURRENT_DESKTOP;
|
|
Atom NET_ACTIVE_WINDOW;
|
|
Atom NET_FRAME_EXTENTS;
|
|
Atom NET_REQUEST_FRAME_EXTENTS;
|
|
Atom MOTIF_WM_HINTS;
|
|
|
|
// Xdnd (drag and drop) atoms
|
|
Atom XdndAware;
|
|
Atom XdndEnter;
|
|
Atom XdndPosition;
|
|
Atom XdndStatus;
|
|
Atom XdndActionCopy;
|
|
Atom XdndDrop;
|
|
Atom XdndFinished;
|
|
Atom XdndSelection;
|
|
Atom XdndTypeList;
|
|
Atom text_uri_list;
|
|
|
|
// Selection (clipboard) atoms
|
|
Atom TARGETS;
|
|
Atom MULTIPLE;
|
|
Atom INCR;
|
|
Atom CLIPBOARD;
|
|
Atom PRIMARY;
|
|
Atom CLIPBOARD_MANAGER;
|
|
Atom SAVE_TARGETS;
|
|
Atom NULL_;
|
|
Atom UTF8_STRING;
|
|
Atom COMPOUND_STRING;
|
|
Atom ATOM_PAIR;
|
|
Atom GLFW_SELECTION;
|
|
|
|
struct {
|
|
GLFWbool available;
|
|
void* handle;
|
|
int eventBase;
|
|
int errorBase;
|
|
int major;
|
|
int minor;
|
|
GLFWbool gammaBroken;
|
|
GLFWbool monitorBroken;
|
|
PFN_XRRAllocGamma AllocGamma;
|
|
PFN_XRRFreeCrtcInfo FreeCrtcInfo;
|
|
PFN_XRRFreeGamma FreeGamma;
|
|
PFN_XRRFreeOutputInfo FreeOutputInfo;
|
|
PFN_XRRFreeScreenResources FreeScreenResources;
|
|
PFN_XRRGetCrtcGamma GetCrtcGamma;
|
|
PFN_XRRGetCrtcGammaSize GetCrtcGammaSize;
|
|
PFN_XRRGetCrtcInfo GetCrtcInfo;
|
|
PFN_XRRGetOutputInfo GetOutputInfo;
|
|
PFN_XRRGetOutputPrimary GetOutputPrimary;
|
|
PFN_XRRGetScreenResourcesCurrent GetScreenResourcesCurrent;
|
|
PFN_XRRQueryExtension QueryExtension;
|
|
PFN_XRRQueryVersion QueryVersion;
|
|
PFN_XRRSelectInput SelectInput;
|
|
PFN_XRRSetCrtcConfig SetCrtcConfig;
|
|
PFN_XRRSetCrtcGamma SetCrtcGamma;
|
|
PFN_XRRUpdateConfiguration UpdateConfiguration;
|
|
} randr;
|
|
|
|
struct {
|
|
GLFWbool available;
|
|
GLFWbool detectable;
|
|
int majorOpcode;
|
|
int eventBase;
|
|
int errorBase;
|
|
int major;
|
|
int minor;
|
|
unsigned int group;
|
|
} xkb;
|
|
|
|
struct {
|
|
int count;
|
|
int timeout;
|
|
int interval;
|
|
int blanking;
|
|
int exposure;
|
|
} saver;
|
|
|
|
struct {
|
|
int version;
|
|
Window source;
|
|
Atom format;
|
|
} xdnd;
|
|
|
|
struct {
|
|
void* handle;
|
|
PFN_XcursorImageCreate ImageCreate;
|
|
PFN_XcursorImageDestroy ImageDestroy;
|
|
PFN_XcursorImageLoadCursor ImageLoadCursor;
|
|
} xcursor;
|
|
|
|
struct {
|
|
GLFWbool available;
|
|
void* handle;
|
|
int major;
|
|
int minor;
|
|
PFN_XineramaIsActive IsActive;
|
|
PFN_XineramaQueryExtension QueryExtension;
|
|
PFN_XineramaQueryScreens QueryScreens;
|
|
} xinerama;
|
|
|
|
struct {
|
|
void* handle;
|
|
PFN_XGetXCBConnection GetXCBConnection;
|
|
} x11xcb;
|
|
|
|
struct {
|
|
GLFWbool available;
|
|
void* handle;
|
|
int eventBase;
|
|
int errorBase;
|
|
PFN_XF86VidModeQueryExtension QueryExtension;
|
|
PFN_XF86VidModeGetGammaRamp GetGammaRamp;
|
|
PFN_XF86VidModeSetGammaRamp SetGammaRamp;
|
|
PFN_XF86VidModeGetGammaRampSize GetGammaRampSize;
|
|
} vidmode;
|
|
|
|
struct {
|
|
GLFWbool available;
|
|
void* handle;
|
|
int majorOpcode;
|
|
int eventBase;
|
|
int errorBase;
|
|
int major;
|
|
int minor;
|
|
PFN_XIQueryVersion QueryVersion;
|
|
PFN_XISelectEvents SelectEvents;
|
|
} xi;
|
|
|
|
struct {
|
|
GLFWbool available;
|
|
void* handle;
|
|
int major;
|
|
int minor;
|
|
int eventBase;
|
|
int errorBase;
|
|
PFN_XRenderQueryExtension QueryExtension;
|
|
PFN_XRenderQueryVersion QueryVersion;
|
|
PFN_XRenderFindVisualFormat FindVisualFormat;
|
|
} xrender;
|
|
} _GLFWlibraryX11;
|
|
|
|
// X11-specific per-monitor data
|
|
//
|
|
typedef struct _GLFWmonitorX11
|
|
{
|
|
RROutput output;
|
|
RRCrtc crtc;
|
|
RRMode oldMode;
|
|
|
|
// Index of corresponding Xinerama screen,
|
|
// for EWMH full screen window placement
|
|
int index;
|
|
} _GLFWmonitorX11;
|
|
|
|
// X11-specific per-cursor data
|
|
//
|
|
typedef struct _GLFWcursorX11
|
|
{
|
|
Cursor handle;
|
|
} _GLFWcursorX11;
|
|
|
|
|
|
void _glfwPollMonitorsX11(void);
|
|
void _glfwSetVideoModeX11(_GLFWmonitor* monitor, const GLFWvidmode* desired);
|
|
void _glfwRestoreVideoModeX11(_GLFWmonitor* monitor);
|
|
|
|
Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot);
|
|
|
|
unsigned long _glfwGetWindowPropertyX11(Window window,
|
|
Atom property,
|
|
Atom type,
|
|
unsigned char** value);
|
|
GLFWbool _glfwIsVisualTransparentX11(Visual* visual);
|
|
|
|
void _glfwGrabErrorHandlerX11(void);
|
|
void _glfwReleaseErrorHandlerX11(void);
|
|
void _glfwInputErrorX11(int error, const char* message);
|
|
|
|
void _glfwPushSelectionToManagerX11(void);
|
|
|