mirror of
https://github.com/glfw/glfw.git
synced 2024-11-10 00:51:47 +00:00
Merge branch '3.3-stable' into new-cursors-on-3.3-stable
This commit is contained in:
commit
74a1ae065a
8
.github/workflows/build.yml
vendored
8
.github/workflows/build.yml
vendored
@ -96,8 +96,8 @@ jobs:
|
||||
- name: Build shared library
|
||||
run: cmake --build build-shared --parallel
|
||||
|
||||
build-windows-win32-vs2019:
|
||||
name: Win32 (Windows, VS2019)
|
||||
build-windows-win32-vs2022:
|
||||
name: Win32 (Windows, VS2022)
|
||||
runs-on: windows-latest
|
||||
env:
|
||||
CFLAGS: /WX
|
||||
@ -105,12 +105,12 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Configure static library
|
||||
run: cmake -S . -B build-static -G "Visual Studio 16 2019"
|
||||
run: cmake -S . -B build-static -G "Visual Studio 17 2022"
|
||||
- name: Build static library
|
||||
run: cmake --build build-static --parallel
|
||||
|
||||
- name: Configure shared library
|
||||
run: cmake -S . -B build-shared -G "Visual Studio 16 2019" -D BUILD_SHARED_LIBS=ON
|
||||
run: cmake -S . -B build-shared -G "Visual Studio 17 2022" -D BUILD_SHARED_LIBS=ON
|
||||
- name: Build shared library
|
||||
run: cmake --build build-shared --parallel
|
||||
|
||||
|
@ -29,6 +29,7 @@ video tutorials.
|
||||
- David Carlier
|
||||
- Arturo Castro
|
||||
- Chi-kwan Chan
|
||||
- TheChocolateOre
|
||||
- Joseph Chua
|
||||
- Ian Clarkson
|
||||
- Michał Cichoń
|
||||
@ -81,6 +82,7 @@ video tutorials.
|
||||
- Paul Holden
|
||||
- Warren Hu
|
||||
- Charles Huber
|
||||
- illustris
|
||||
- InKryption
|
||||
- IntellectualKitty
|
||||
- Aaron Jacobs
|
||||
@ -179,12 +181,15 @@ video tutorials.
|
||||
- Ali Sherief
|
||||
- Yoshiki Shibukawa
|
||||
- Dmitri Shuralyov
|
||||
- Joao da Silva
|
||||
- Daniel Sieger
|
||||
- Daniel Skorupski
|
||||
- Slemmie
|
||||
- Bradley Smith
|
||||
- Cliff Smolinsky
|
||||
- Patrick Snape
|
||||
- Erlend Sogge Heggen
|
||||
- Olivier Sohn
|
||||
- Julian Squires
|
||||
- Johannes Stein
|
||||
- Pontus Stenetorp
|
||||
|
15
README.md
15
README.md
@ -123,8 +123,21 @@ information on what to include when reporting a bug.
|
||||
|
||||
## Changelog
|
||||
|
||||
- [Win32] Bugfix: A window created maximized and undecorated would cover the whole
|
||||
monitor (#1806)
|
||||
- [Win32] Bugfix: The default restored window position was lost when creating a maximized
|
||||
window
|
||||
- [Win32] Bugfix: `glfwMaximizeWindow` would make a hidden window visible
|
||||
- [Cocoa] Bugfix: `kUTTypeURL` was deprecated in macOS 12.0 (#2003)
|
||||
- [X11] Bugfix: Dynamic loading on OpenBSD failed due to soname differences
|
||||
- [X11] Bugfix: Waiting for events would fail if file descriptor was too large
|
||||
(#2024)
|
||||
- [X11] Bugfix: Joystick events could lead to busy-waiting (#1872)
|
||||
- [X11] Bugfix: `glfwWaitEvents*` did not continue for joystick events
|
||||
- [X11] Bugfix: `glfwPostEmptyEvent` could be ignored due to race condition
|
||||
(#379,#1281,#1285,#2033)
|
||||
- [X11] Bugfix: Dynamic loading on NetBSD failed due to soname differences
|
||||
- [X11] Bugfix: Left shift of int constant relied on undefined behavior (#1951)
|
||||
- [Wayland] Added support for key names via xkbcommon
|
||||
- [Wayland] Bugfix: Key repeat could lead to a race condition (#1710)
|
||||
- [Wayland] Bugfix: Activating a window would emit two input focus events
|
||||
@ -135,6 +148,8 @@ information on what to include when reporting a bug.
|
||||
- [Wayland] Bugfix: Full screen window creation did not ignore `GLFW_VISIBLE`
|
||||
- [Wayland] Bugfix: Some keys were reported as wrong key or `GLFW_KEY_UNKNOWN`
|
||||
- [Wayland] Bugfix: Text input did not repeat along with key repeat
|
||||
- [Wayland] Bugfix: `glfwPostEmptyEvent` sometimes had no effect (#1520,#1521)
|
||||
- [GLX] Bugfix: Context creation failed if GLX 1.4 was not exported by GLX library
|
||||
|
||||
|
||||
## Contact
|
||||
|
@ -68,8 +68,10 @@ install the `xorgproto` package.
|
||||
pkg install xorgproto
|
||||
@endcode
|
||||
|
||||
On Cygwin the `xorgproto` package in the Devel section of the GUI installer will
|
||||
install the headers and other development related files for all of X11.
|
||||
On Cygwin the `libXcursor-devel`, `libXi-devel`, `libXinerama-devel`,
|
||||
`libXrandr-devel` and `libXrender-devel` packages in the Libs section of the GUI
|
||||
installer will install all the headers and other development related files GLFW
|
||||
requires for X11.
|
||||
|
||||
Once you have the required depdendencies, move on to @ref compile_generate.
|
||||
|
||||
|
@ -821,7 +821,7 @@ The second value is always the human-readable name of the gamepad.
|
||||
All subsequent values are in the form `<field>:<value>` and describe the layout
|
||||
of the mapping. These fields may not all be present and may occur in any order.
|
||||
|
||||
The button fields are `a`, `b`, `c`, `d`, `back`, `start`, `guide`, `dpup`,
|
||||
The button fields are `a`, `b`, `x`, `y`, `back`, `start`, `guide`, `dpup`,
|
||||
`dpright`, `dpdown`, `dpleft`, `leftshoulder`, `rightshoulder`, `leftstick` and
|
||||
`rightstick`.
|
||||
|
||||
|
@ -306,6 +306,12 @@ GLFW_TRANSPARENT_FRAMEBUFFER on Windows 7 if DWM transparency is off
|
||||
(the Transparency setting under Personalization > Window Color).
|
||||
|
||||
|
||||
@subsubsection emptyevents_33 Empty events on X11 no longer roundtrip to server
|
||||
|
||||
Starting with GLFW 3.3.7, events posted with @ref glfwPostEmptyEvent now use a separate
|
||||
unnamed pipe instead of sending an X11 client event to the helper window.
|
||||
|
||||
|
||||
@subsection deprecations_33 Deprecations in version 3.3
|
||||
|
||||
@subsubsection charmods_callback_33 Character with modifiers callback
|
||||
|
@ -320,7 +320,7 @@ GLFWbool _glfwInitEGL(void)
|
||||
"libEGL.dylib",
|
||||
#elif defined(__CYGWIN__)
|
||||
"libEGL-1.so",
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
"libEGL.so",
|
||||
#else
|
||||
"libEGL.so.1",
|
||||
@ -643,7 +643,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
"libGLES_CM.dll",
|
||||
#elif defined(_GLFW_COCOA)
|
||||
"libGLESv1_CM.dylib",
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
"libGLESv1_CM.so",
|
||||
#else
|
||||
"libGLESv1_CM.so.1",
|
||||
@ -662,7 +662,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
"libGLESv2.dylib",
|
||||
#elif defined(__CYGWIN__)
|
||||
"libGLESv2-2.so",
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
"libGLESv2.so",
|
||||
#else
|
||||
"libGLESv2.so.2",
|
||||
@ -675,7 +675,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
_GLFW_OPENGL_LIBRARY,
|
||||
#elif defined(_GLFW_WIN32)
|
||||
#elif defined(_GLFW_COCOA)
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
"libGL.so",
|
||||
#else
|
||||
"libGL.so.1",
|
||||
|
@ -260,7 +260,7 @@ GLFWbool _glfwInitGLX(void)
|
||||
_GLFW_GLX_LIBRARY,
|
||||
#elif defined(__CYGWIN__)
|
||||
"libGL-1.so",
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
"libGL.so",
|
||||
#else
|
||||
"libGL.so.1",
|
||||
@ -309,10 +309,6 @@ GLFWbool _glfwInitGLX(void)
|
||||
_glfw_dlsym(_glfw.glx.handle, "glXCreateWindow");
|
||||
_glfw.glx.DestroyWindow =
|
||||
_glfw_dlsym(_glfw.glx.handle, "glXDestroyWindow");
|
||||
_glfw.glx.GetProcAddress =
|
||||
_glfw_dlsym(_glfw.glx.handle, "glXGetProcAddress");
|
||||
_glfw.glx.GetProcAddressARB =
|
||||
_glfw_dlsym(_glfw.glx.handle, "glXGetProcAddressARB");
|
||||
_glfw.glx.GetVisualFromFBConfig =
|
||||
_glfw_dlsym(_glfw.glx.handle, "glXGetVisualFromFBConfig");
|
||||
|
||||
@ -328,8 +324,6 @@ GLFWbool _glfwInitGLX(void)
|
||||
!_glfw.glx.CreateNewContext ||
|
||||
!_glfw.glx.CreateWindow ||
|
||||
!_glfw.glx.DestroyWindow ||
|
||||
!_glfw.glx.GetProcAddress ||
|
||||
!_glfw.glx.GetProcAddressARB ||
|
||||
!_glfw.glx.GetVisualFromFBConfig)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
@ -337,6 +331,12 @@ GLFWbool _glfwInitGLX(void)
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
// NOTE: Unlike GLX 1.3 entry points these are not required to be present
|
||||
_glfw.glx.GetProcAddress = (PFNGLXGETPROCADDRESSPROC)
|
||||
_glfw_dlsym(_glfw.glx.handle, "glXGetProcAddress");
|
||||
_glfw.glx.GetProcAddressARB = (PFNGLXGETPROCADDRESSPROC)
|
||||
_glfw_dlsym(_glfw.glx.handle, "glXGetProcAddressARB");
|
||||
|
||||
if (!glXQueryExtension(_glfw.x11.display,
|
||||
&_glfw.glx.errorBase,
|
||||
&_glfw.glx.eventBase))
|
||||
|
@ -124,7 +124,7 @@ GLFWbool _glfwInitOSMesa(void)
|
||||
"libOSMesa.8.dylib",
|
||||
#elif defined(__CYGWIN__)
|
||||
"libOSMesa-8.so",
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
"libOSMesa.so",
|
||||
#else
|
||||
"libOSMesa.so.8",
|
||||
|
@ -59,7 +59,7 @@ GLFWbool _glfwInitVulkan(int mode)
|
||||
_glfw.vk.handle = _glfw_dlopen("libvulkan.1.dylib");
|
||||
if (!_glfw.vk.handle)
|
||||
_glfw.vk.handle = _glfwLoadLocalVulkanLoaderNS();
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
_glfw.vk.handle = _glfw_dlopen("libvulkan.so");
|
||||
#else
|
||||
_glfw.vk.handle = _glfw_dlopen("libvulkan.so.1");
|
||||
|
@ -92,6 +92,8 @@ static GLFWbool loadLibraries(void)
|
||||
GetProcAddress(_glfw.win32.user32.instance, "GetDpiForWindow");
|
||||
_glfw.win32.user32.AdjustWindowRectExForDpi_ = (PFN_AdjustWindowRectExForDpi)
|
||||
GetProcAddress(_glfw.win32.user32.instance, "AdjustWindowRectExForDpi");
|
||||
_glfw.win32.user32.GetSystemMetricsForDpi_ = (PFN_GetSystemMetricsForDpi)
|
||||
GetProcAddress(_glfw.win32.user32.instance, "GetSystemMetricsForDpi");
|
||||
|
||||
_glfw.win32.dinput8.instance = LoadLibraryA("dinput8.dll");
|
||||
if (_glfw.win32.dinput8.instance)
|
||||
@ -484,7 +486,7 @@ void _glfwUpdateKeyNamesWin32(void)
|
||||
vk = vks[key - GLFW_KEY_KP_0];
|
||||
}
|
||||
else
|
||||
vk = MapVirtualKey(scancode, MAPVK_VSC_TO_VK);
|
||||
vk = MapVirtualKeyW(scancode, MAPVK_VSC_TO_VK);
|
||||
|
||||
length = ToUnicode(vk, scancode, state,
|
||||
chars, sizeof(chars) / sizeof(WCHAR),
|
||||
@ -507,7 +509,8 @@ void _glfwUpdateKeyNamesWin32(void)
|
||||
}
|
||||
}
|
||||
|
||||
// Replacement for IsWindowsVersionOrGreater as MinGW lacks versionhelpers.h
|
||||
// Replacement for IsWindowsVersionOrGreater, as we cannot rely on the
|
||||
// application having a correct embedded manifest
|
||||
//
|
||||
BOOL _glfwIsWindowsVersionOrGreaterWin32(WORD major, WORD minor, WORD sp)
|
||||
{
|
||||
|
@ -497,7 +497,7 @@ void _glfwInitJoysticksWin32(void)
|
||||
{
|
||||
if (_glfw.win32.dinput8.instance)
|
||||
{
|
||||
if (FAILED(DirectInput8Create(GetModuleHandle(NULL),
|
||||
if (FAILED(DirectInput8Create(GetModuleHandleW(NULL),
|
||||
DIRECTINPUT_VERSION,
|
||||
&IID_IDirectInput8W,
|
||||
(void**) &_glfw.win32.dinput8.api,
|
||||
|
@ -382,7 +382,7 @@ void _glfwPlatformGetMonitorWorkarea(_GLFWmonitor* monitor,
|
||||
int* width, int* height)
|
||||
{
|
||||
MONITORINFO mi = { sizeof(mi) };
|
||||
GetMonitorInfo(monitor->win32.handle, &mi);
|
||||
GetMonitorInfoW(monitor->win32.handle, &mi);
|
||||
|
||||
if (xpos)
|
||||
*xpos = mi.rcWork.left;
|
||||
|
@ -162,7 +162,9 @@ typedef enum
|
||||
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE) -4)
|
||||
#endif /*DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2*/
|
||||
|
||||
// HACK: Define versionhelpers.h functions manually as MinGW lacks the header
|
||||
// Replacement for versionhelpers.h macros, as we cannot rely on the
|
||||
// application having a correct embedded manifest
|
||||
//
|
||||
#define IsWindowsXPOrGreater() \
|
||||
_glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WINXP), \
|
||||
LOBYTE(_WIN32_WINNT_WINXP), 0)
|
||||
@ -235,12 +237,14 @@ typedef BOOL (WINAPI * PFN_EnableNonClientDpiScaling)(HWND);
|
||||
typedef BOOL (WINAPI * PFN_SetProcessDpiAwarenessContext)(HANDLE);
|
||||
typedef UINT (WINAPI * PFN_GetDpiForWindow)(HWND);
|
||||
typedef BOOL (WINAPI * PFN_AdjustWindowRectExForDpi)(LPRECT,DWORD,BOOL,DWORD,UINT);
|
||||
typedef int (WINAPI * PFN_GetSystemMetricsForDpi)(int,UINT);
|
||||
#define SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware_
|
||||
#define ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx_
|
||||
#define EnableNonClientDpiScaling _glfw.win32.user32.EnableNonClientDpiScaling_
|
||||
#define SetProcessDpiAwarenessContext _glfw.win32.user32.SetProcessDpiAwarenessContext_
|
||||
#define GetDpiForWindow _glfw.win32.user32.GetDpiForWindow_
|
||||
#define AdjustWindowRectExForDpi _glfw.win32.user32.AdjustWindowRectExForDpi_
|
||||
#define GetSystemMetricsForDpi _glfw.win32.user32.GetSystemMetricsForDpi_
|
||||
|
||||
// dwmapi.dll function pointer typedefs
|
||||
typedef HRESULT (WINAPI * PFN_DwmIsCompositionEnabled)(BOOL*);
|
||||
@ -366,6 +370,7 @@ typedef struct _GLFWlibraryWin32
|
||||
PFN_SetProcessDpiAwarenessContext SetProcessDpiAwarenessContext_;
|
||||
PFN_GetDpiForWindow GetDpiForWindow_;
|
||||
PFN_AdjustWindowRectExForDpi AdjustWindowRectExForDpi_;
|
||||
PFN_GetSystemMetricsForDpi GetSystemMetricsForDpi_;
|
||||
} user32;
|
||||
|
||||
struct {
|
||||
|
@ -435,7 +435,7 @@ static int getKeyMods(void)
|
||||
static void fitToMonitor(_GLFWwindow* window)
|
||||
{
|
||||
MONITORINFO mi = { sizeof(mi) };
|
||||
GetMonitorInfo(window->monitor->win32.handle, &mi);
|
||||
GetMonitorInfoW(window->monitor->win32.handle, &mi);
|
||||
SetWindowPos(window->win32.handle, HWND_TOPMOST,
|
||||
mi.rcMonitor.left,
|
||||
mi.rcMonitor.top,
|
||||
@ -456,8 +456,8 @@ static void acquireMonitor(_GLFWwindow* window)
|
||||
// the OpenGL ICD switches to page flipping
|
||||
if (IsWindowsXPOrGreater())
|
||||
{
|
||||
SystemParametersInfo(SPI_GETMOUSETRAILS, 0, &_glfw.win32.mouseTrailSize, 0);
|
||||
SystemParametersInfo(SPI_SETMOUSETRAILS, 0, 0, 0);
|
||||
SystemParametersInfoW(SPI_GETMOUSETRAILS, 0, &_glfw.win32.mouseTrailSize, 0);
|
||||
SystemParametersInfoW(SPI_SETMOUSETRAILS, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -482,13 +482,66 @@ static void releaseMonitor(_GLFWwindow* window)
|
||||
|
||||
// HACK: Restore mouse trail length saved in acquireMonitor
|
||||
if (IsWindowsXPOrGreater())
|
||||
SystemParametersInfo(SPI_SETMOUSETRAILS, _glfw.win32.mouseTrailSize, 0, 0);
|
||||
SystemParametersInfoW(SPI_SETMOUSETRAILS, _glfw.win32.mouseTrailSize, 0, 0);
|
||||
}
|
||||
|
||||
_glfwInputMonitorWindow(window->monitor, NULL);
|
||||
_glfwRestoreVideoModeWin32(window->monitor);
|
||||
}
|
||||
|
||||
// Manually maximize the window, for when SW_MAXIMIZE cannot be used
|
||||
//
|
||||
static void maximizeWindowManually(_GLFWwindow* window)
|
||||
{
|
||||
RECT rect;
|
||||
DWORD style;
|
||||
MONITORINFO mi = { sizeof(mi) };
|
||||
|
||||
GetMonitorInfoW(MonitorFromWindow(window->win32.handle,
|
||||
MONITOR_DEFAULTTONEAREST), &mi);
|
||||
|
||||
rect = mi.rcWork;
|
||||
|
||||
if (window->maxwidth != GLFW_DONT_CARE && window->maxheight != GLFW_DONT_CARE)
|
||||
{
|
||||
if (rect.right - rect.left > window->maxwidth)
|
||||
rect.right = rect.left + window->maxwidth;
|
||||
if (rect.bottom - rect.top > window->maxheight)
|
||||
rect.bottom = rect.top + window->maxheight;
|
||||
}
|
||||
|
||||
style = GetWindowLongW(window->win32.handle, GWL_STYLE);
|
||||
style |= WS_MAXIMIZE;
|
||||
SetWindowLongW(window->win32.handle, GWL_STYLE, style);
|
||||
|
||||
if (window->decorated)
|
||||
{
|
||||
const DWORD exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE);
|
||||
|
||||
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
|
||||
{
|
||||
const UINT dpi = GetDpiForWindow(window->win32.handle);
|
||||
AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, dpi);
|
||||
OffsetRect(&rect, 0, GetSystemMetricsForDpi(SM_CYCAPTION, dpi));
|
||||
}
|
||||
else
|
||||
{
|
||||
AdjustWindowRectEx(&rect, style, FALSE, exStyle);
|
||||
OffsetRect(&rect, 0, GetSystemMetrics(SM_CYCAPTION));
|
||||
}
|
||||
|
||||
if (rect.bottom > mi.rcWork.bottom)
|
||||
rect.bottom = mi.rcWork.bottom;
|
||||
}
|
||||
|
||||
SetWindowPos(window->win32.handle, HWND_TOP,
|
||||
rect.left,
|
||||
rect.top,
|
||||
rect.right - rect.left,
|
||||
rect.bottom - rect.top,
|
||||
SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
|
||||
}
|
||||
|
||||
// Window callback function (handles window messages)
|
||||
//
|
||||
static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
||||
@ -1067,7 +1120,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
||||
|
||||
ZeroMemory(&mi, sizeof(mi));
|
||||
mi.cbSize = sizeof(mi);
|
||||
GetMonitorInfo(mh, &mi);
|
||||
GetMonitorInfoW(mh, &mi);
|
||||
|
||||
mmi->ptMaxPosition.x = mi.rcWork.left - mi.rcMonitor.left;
|
||||
mmi->ptMaxPosition.y = mi.rcWork.top - mi.rcMonitor.top;
|
||||
@ -1285,18 +1338,22 @@ static int createNativeWindow(_GLFWwindow* window,
|
||||
|
||||
window->win32.scaleToMonitor = wndconfig->scaleToMonitor;
|
||||
|
||||
// Adjust window rect to account for DPI scaling of the window frame and
|
||||
// (if enabled) DPI scaling of the content area
|
||||
// This cannot be done until we know what monitor the window was placed on
|
||||
if (!window->monitor)
|
||||
{
|
||||
RECT rect = { 0, 0, wndconfig->width, wndconfig->height };
|
||||
WINDOWPLACEMENT wp = { sizeof(wp) };
|
||||
const HMONITOR mh = MonitorFromWindow(window->win32.handle,
|
||||
MONITOR_DEFAULTTONEAREST);
|
||||
|
||||
// Adjust window rect to account for DPI scaling of the window frame and
|
||||
// (if enabled) DPI scaling of the content area
|
||||
// This cannot be done until we know what monitor the window was placed on
|
||||
// Only update the restored window rect as the window may be maximized
|
||||
|
||||
if (wndconfig->scaleToMonitor)
|
||||
{
|
||||
float xscale, yscale;
|
||||
_glfwPlatformGetWindowContentScale(window, &xscale, &yscale);
|
||||
_glfwGetMonitorContentScaleWin32(mh, &xscale, &yscale);
|
||||
|
||||
if (xscale > 0.f && yscale > 0.f)
|
||||
{
|
||||
@ -1305,9 +1362,6 @@ static int createNativeWindow(_GLFWwindow* window,
|
||||
}
|
||||
}
|
||||
|
||||
ClientToScreen(window->win32.handle, (POINT*) &rect.left);
|
||||
ClientToScreen(window->win32.handle, (POINT*) &rect.right);
|
||||
|
||||
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
|
||||
{
|
||||
AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle,
|
||||
@ -1316,11 +1370,30 @@ static int createNativeWindow(_GLFWwindow* window,
|
||||
else
|
||||
AdjustWindowRectEx(&rect, style, FALSE, exStyle);
|
||||
|
||||
// Only update the restored window rect as the window may be maximized
|
||||
GetWindowPlacement(window->win32.handle, &wp);
|
||||
OffsetRect(&rect,
|
||||
wp.rcNormalPosition.left - rect.left,
|
||||
wp.rcNormalPosition.top - rect.top);
|
||||
|
||||
wp.rcNormalPosition = rect;
|
||||
wp.showCmd = SW_HIDE;
|
||||
SetWindowPlacement(window->win32.handle, &wp);
|
||||
|
||||
// Adjust rect of maximized undecorated window, because by default Windows will
|
||||
// make such a window cover the whole monitor instead of its workarea
|
||||
|
||||
if (wndconfig->maximized && !wndconfig->decorated)
|
||||
{
|
||||
MONITORINFO mi = { sizeof(mi) };
|
||||
GetMonitorInfoW(mh, &mi);
|
||||
|
||||
SetWindowPos(window->win32.handle, HWND_TOP,
|
||||
mi.rcWork.left,
|
||||
mi.rcWork.top,
|
||||
mi.rcWork.right - mi.rcWork.left,
|
||||
mi.rcWork.bottom - mi.rcWork.top,
|
||||
SWP_NOACTIVATE | SWP_NOZORDER);
|
||||
}
|
||||
}
|
||||
|
||||
DragAcceptFiles(window->win32.handle, TRUE);
|
||||
@ -1491,8 +1564,8 @@ void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
|
||||
smallIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICONSM);
|
||||
}
|
||||
|
||||
SendMessage(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon);
|
||||
SendMessage(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon);
|
||||
SendMessageW(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon);
|
||||
SendMessageW(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon);
|
||||
|
||||
if (window->win32.bigIcon)
|
||||
DestroyIcon(window->win32.bigIcon);
|
||||
@ -1672,7 +1745,10 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window)
|
||||
|
||||
void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
|
||||
{
|
||||
if (IsWindowVisible(window->win32.handle))
|
||||
ShowWindow(window->win32.handle, SW_MAXIMIZE);
|
||||
else
|
||||
maximizeWindowManually(window);
|
||||
}
|
||||
|
||||
void _glfwPlatformShowWindow(_GLFWwindow* window)
|
||||
@ -1759,7 +1835,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
|
||||
|
||||
acquireMonitor(window);
|
||||
|
||||
GetMonitorInfo(window->monitor->win32.handle, &mi);
|
||||
GetMonitorInfoW(window->monitor->win32.handle, &mi);
|
||||
SetWindowPos(window->win32.handle, HWND_TOPMOST,
|
||||
mi.rcMonitor.left,
|
||||
mi.rcMonitor.top,
|
||||
@ -2023,7 +2099,7 @@ void _glfwPlatformWaitEventsTimeout(double timeout)
|
||||
|
||||
void _glfwPlatformPostEmptyEvent(void)
|
||||
{
|
||||
PostMessage(_glfw.win32.helperWindowHandle, WM_NULL, 0, 0);
|
||||
PostMessageW(_glfw.win32.helperWindowHandle, WM_NULL, 0, 0);
|
||||
}
|
||||
|
||||
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
|
||||
@ -2278,7 +2354,7 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
|
||||
|
||||
memset(&sci, 0, sizeof(sci));
|
||||
sci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
|
||||
sci.hinstance = GetModuleHandle(NULL);
|
||||
sci.hinstance = GetModuleHandleW(NULL);
|
||||
sci.hwnd = window->win32.handle;
|
||||
|
||||
err = vkCreateWin32SurfaceKHR(instance, &sci, allocator, surface);
|
||||
|
@ -1195,14 +1195,15 @@ int _glfwPlatformInit(void)
|
||||
wl_data_device_manager_get_data_device(_glfw.wl.dataDeviceManager,
|
||||
_glfw.wl.seat);
|
||||
wl_data_device_add_listener(_glfw.wl.dataDevice, &dataDeviceListener, NULL);
|
||||
_glfw.wl.clipboardString = malloc(4096);
|
||||
|
||||
_glfw.wl.clipboardSize = 4096;
|
||||
_glfw.wl.clipboardString = calloc(_glfw.wl.clipboardSize, 1);
|
||||
if (!_glfw.wl.clipboardString)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
_glfwInputError(GLFW_OUT_OF_MEMORY,
|
||||
"Wayland: Unable to allocate clipboard memory");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
_glfw.wl.clipboardSize = 4096;
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
@ -1293,9 +1294,7 @@ void _glfwPlatformTerminate(void)
|
||||
if (_glfw.wl.cursorTimerfd >= 0)
|
||||
close(_glfw.wl.cursorTimerfd);
|
||||
|
||||
if (_glfw.wl.clipboardString)
|
||||
free(_glfw.wl.clipboardString);
|
||||
if (_glfw.wl.clipboardSendString)
|
||||
free(_glfw.wl.clipboardSendString);
|
||||
}
|
||||
|
||||
|
129
src/wl_window.c
129
src/wl_window.c
@ -39,7 +39,8 @@
|
||||
#include <sys/mman.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
|
||||
static void shellSurfaceHandlePing(void* data,
|
||||
struct wl_shell_surface* shellSurface,
|
||||
@ -248,6 +249,53 @@ static struct wl_buffer* createShmBuffer(const GLFWimage* image)
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Wait for data to arrive on any of the specified file descriptors
|
||||
//
|
||||
static GLFWbool waitForData(struct pollfd* fds, nfds_t count, double* timeout)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (timeout)
|
||||
{
|
||||
const uint64_t base = _glfwPlatformGetTimerValue();
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__)
|
||||
const time_t seconds = (time_t) *timeout;
|
||||
const long nanoseconds = (long) ((*timeout - seconds) * 1e9);
|
||||
const struct timespec ts = { seconds, nanoseconds };
|
||||
const int result = ppoll(fds, count, &ts, NULL);
|
||||
#elif defined(__NetBSD__)
|
||||
const time_t seconds = (time_t) *timeout;
|
||||
const long nanoseconds = (long) ((*timeout - seconds) * 1e9);
|
||||
const struct timespec ts = { seconds, nanoseconds };
|
||||
const int result = pollts(fds, count, &ts, NULL);
|
||||
#else
|
||||
const int milliseconds = (int) (*timeout * 1e3);
|
||||
const int result = poll(fds, count, milliseconds);
|
||||
#endif
|
||||
const int error = errno; // clock_gettime may overwrite our error
|
||||
|
||||
*timeout -= (_glfwPlatformGetTimerValue() - base) /
|
||||
(double) _glfwPlatformGetTimerFrequency();
|
||||
|
||||
if (result > 0)
|
||||
return GLFW_TRUE;
|
||||
else if (result == -1 && error != EINTR && error != EAGAIN)
|
||||
return GLFW_FALSE;
|
||||
else if (*timeout <= 0.0)
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
const int result = poll(fds, count, -1);
|
||||
if (result > 0)
|
||||
return GLFW_TRUE;
|
||||
else if (result == -1 && errno != EINTR && errno != EAGAIN)
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void createDecoration(_GLFWdecorationWayland* decoration,
|
||||
struct wl_surface* parent,
|
||||
struct wl_buffer* buffer, GLFWbool opaque,
|
||||
@ -404,27 +452,25 @@ static void resizeWindow(_GLFWwindow* window)
|
||||
|
||||
static void checkScaleChange(_GLFWwindow* window)
|
||||
{
|
||||
int scale = 1;
|
||||
int i;
|
||||
int monitorScale;
|
||||
|
||||
// Check if we will be able to set the buffer scale or not.
|
||||
if (_glfw.wl.compositorVersion < 3)
|
||||
return;
|
||||
|
||||
// Get the scale factor from the highest scale monitor.
|
||||
for (i = 0; i < window->wl.monitorsCount; ++i)
|
||||
int maxScale = 1;
|
||||
|
||||
for (int i = 0; i < window->wl.monitorsCount; i++)
|
||||
{
|
||||
monitorScale = window->wl.monitors[i]->wl.scale;
|
||||
if (scale < monitorScale)
|
||||
scale = monitorScale;
|
||||
const int scale = window->wl.monitors[i]->wl.scale;
|
||||
if (maxScale < scale)
|
||||
maxScale = scale;
|
||||
}
|
||||
|
||||
// Only change the framebuffer size if the scale changed.
|
||||
if (scale != window->wl.scale)
|
||||
if (window->wl.scale != maxScale)
|
||||
{
|
||||
window->wl.scale = scale;
|
||||
wl_surface_set_buffer_scale(window->wl.surface, scale);
|
||||
window->wl.scale = maxScale;
|
||||
wl_surface_set_buffer_scale(window->wl.surface, maxScale);
|
||||
resizeWindow(window);
|
||||
}
|
||||
}
|
||||
@ -833,8 +879,28 @@ static void incrementCursorImage(_GLFWwindow* window)
|
||||
}
|
||||
}
|
||||
|
||||
static void handleEvents(int timeout)
|
||||
static GLFWbool flushDisplay(void)
|
||||
{
|
||||
while (wl_display_flush(_glfw.wl.display) == -1)
|
||||
{
|
||||
if (errno != EAGAIN)
|
||||
return GLFW_FALSE;
|
||||
|
||||
struct pollfd fd = { wl_display_get_fd(_glfw.wl.display), POLLOUT };
|
||||
|
||||
while (poll(&fd, 1, -1) == -1)
|
||||
{
|
||||
if (errno != EINTR && errno != EAGAIN)
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
static void handleEvents(double* timeout)
|
||||
{
|
||||
GLFWbool event = GLFW_FALSE;
|
||||
struct pollfd fds[] =
|
||||
{
|
||||
{ wl_display_get_fd(_glfw.wl.display), POLLIN },
|
||||
@ -842,13 +908,17 @@ static void handleEvents(int timeout)
|
||||
{ _glfw.wl.cursorTimerfd, POLLIN },
|
||||
};
|
||||
|
||||
while (!event)
|
||||
{
|
||||
while (wl_display_prepare_read(_glfw.wl.display) != 0)
|
||||
wl_display_dispatch_pending(_glfw.wl.display);
|
||||
|
||||
// If an error other than EAGAIN happens, we have likely been disconnected
|
||||
// from the Wayland session; try to handle that the best we can.
|
||||
if (wl_display_flush(_glfw.wl.display) < 0 && errno != EAGAIN)
|
||||
if (!flushDisplay())
|
||||
{
|
||||
wl_display_cancel_read(_glfw.wl.display);
|
||||
|
||||
_GLFWwindow* window = _glfw.windowListHead;
|
||||
while (window)
|
||||
{
|
||||
@ -856,16 +926,20 @@ static void handleEvents(int timeout)
|
||||
window = window->next;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!waitForData(fds, 3, timeout))
|
||||
{
|
||||
wl_display_cancel_read(_glfw.wl.display);
|
||||
return;
|
||||
}
|
||||
|
||||
if (poll(fds, 3, timeout) > 0)
|
||||
{
|
||||
if (fds[0].revents & POLLIN)
|
||||
{
|
||||
wl_display_read_events(_glfw.wl.display);
|
||||
wl_display_dispatch_pending(_glfw.wl.display);
|
||||
if (wl_display_dispatch_pending(_glfw.wl.display) > 0)
|
||||
event = GLFW_TRUE;
|
||||
}
|
||||
else
|
||||
wl_display_cancel_read(_glfw.wl.display);
|
||||
@ -886,6 +960,8 @@ static void handleEvents(int timeout)
|
||||
_glfwInputTextWayland(_glfw.wl.keyboardFocus,
|
||||
_glfw.wl.keyboardLastScancode);
|
||||
}
|
||||
|
||||
event = GLFW_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
@ -894,11 +970,12 @@ static void handleEvents(int timeout)
|
||||
uint64_t repeats;
|
||||
|
||||
if (read(_glfw.wl.cursorTimerfd, &repeats, sizeof(repeats)) == 8)
|
||||
{
|
||||
incrementCursorImage(_glfw.wl.pointerFocus);
|
||||
event = GLFW_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
wl_display_cancel_read(_glfw.wl.display);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -1288,22 +1365,24 @@ GLFWbool _glfwPlatformRawMouseMotionSupported(void)
|
||||
|
||||
void _glfwPlatformPollEvents(void)
|
||||
{
|
||||
handleEvents(0);
|
||||
double timeout = 0.0;
|
||||
handleEvents(&timeout);
|
||||
}
|
||||
|
||||
void _glfwPlatformWaitEvents(void)
|
||||
{
|
||||
handleEvents(-1);
|
||||
handleEvents(NULL);
|
||||
}
|
||||
|
||||
void _glfwPlatformWaitEventsTimeout(double timeout)
|
||||
{
|
||||
handleEvents((int) (timeout * 1e3));
|
||||
handleEvents(&timeout);
|
||||
}
|
||||
|
||||
void _glfwPlatformPostEmptyEvent(void)
|
||||
{
|
||||
wl_display_sync(_glfw.wl.display);
|
||||
flushDisplay();
|
||||
}
|
||||
|
||||
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
|
||||
@ -1793,7 +1872,7 @@ static GLFWbool growClipboardString(void)
|
||||
clipboard = realloc(clipboard, _glfw.wl.clipboardSize * 2);
|
||||
if (!clipboard)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
_glfwInputError(GLFW_OUT_OF_MEMORY,
|
||||
"Wayland: Impossible to grow clipboard string");
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
@ -1828,9 +1907,9 @@ const char* _glfwPlatformGetClipboardString(void)
|
||||
close(fds[1]);
|
||||
|
||||
// XXX: this is a huge hack, this function shouldn’t be synchronous!
|
||||
handleEvents(-1);
|
||||
handleEvents(NULL);
|
||||
|
||||
while (1)
|
||||
for (;;)
|
||||
{
|
||||
// Grow the clipboard if we need to paste something bigger, there is no
|
||||
// shrink operation yet.
|
||||
|
@ -36,6 +36,9 @@
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <locale.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
// Translate the X11 KeySyms for a key to a GLFW key code
|
||||
@ -568,7 +571,7 @@ static void detectEWMH(void)
|
||||
//
|
||||
static GLFWbool initExtensions(void)
|
||||
{
|
||||
#if defined(__OpenBSD__)
|
||||
#if defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
_glfw.x11.vidmode.handle = _glfw_dlopen("libXxf86vm.so");
|
||||
#else
|
||||
_glfw.x11.vidmode.handle = _glfw_dlopen("libXxf86vm.so.1");
|
||||
@ -592,7 +595,7 @@ static GLFWbool initExtensions(void)
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
_glfw.x11.xi.handle = _glfw_dlopen("libXi-6.so");
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
_glfw.x11.xi.handle = _glfw_dlopen("libXi.so");
|
||||
#else
|
||||
_glfw.x11.xi.handle = _glfw_dlopen("libXi.so.6");
|
||||
@ -624,7 +627,7 @@ static GLFWbool initExtensions(void)
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
_glfw.x11.randr.handle = _glfw_dlopen("libXrandr-2.so");
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
_glfw.x11.randr.handle = _glfw_dlopen("libXrandr.so");
|
||||
#else
|
||||
_glfw.x11.randr.handle = _glfw_dlopen("libXrandr.so.2");
|
||||
@ -718,7 +721,7 @@ static GLFWbool initExtensions(void)
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
_glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor-1.so");
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
_glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor.so");
|
||||
#else
|
||||
_glfw.x11.xcursor.handle = _glfw_dlopen("libXcursor.so.1");
|
||||
@ -741,7 +744,7 @@ static GLFWbool initExtensions(void)
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
_glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama-1.so");
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
_glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama.so");
|
||||
#else
|
||||
_glfw.x11.xinerama.handle = _glfw_dlopen("libXinerama.so.1");
|
||||
@ -794,7 +797,7 @@ static GLFWbool initExtensions(void)
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
_glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb-1.so");
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
_glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb.so");
|
||||
#else
|
||||
_glfw.x11.x11xcb.handle = _glfw_dlopen("libX11-xcb.so.1");
|
||||
@ -807,7 +810,7 @@ static GLFWbool initExtensions(void)
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
_glfw.x11.xrender.handle = _glfw_dlopen("libXrender-1.so");
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
_glfw.x11.xrender.handle = _glfw_dlopen("libXrender.so");
|
||||
#else
|
||||
_glfw.x11.xrender.handle = _glfw_dlopen("libXrender.so.1");
|
||||
@ -974,6 +977,37 @@ static Window createHelperWindow(void)
|
||||
CWEventMask, &wa);
|
||||
}
|
||||
|
||||
// Create the pipe for empty events without assumuing the OS has pipe2(2)
|
||||
//
|
||||
static GLFWbool createEmptyEventPipe(void)
|
||||
{
|
||||
if (pipe(_glfw.x11.emptyEventPipe) != 0)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"X11: Failed to create empty event pipe: %s",
|
||||
strerror(errno));
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
const int sf = fcntl(_glfw.x11.emptyEventPipe[i], F_GETFL, 0);
|
||||
const int df = fcntl(_glfw.x11.emptyEventPipe[i], F_GETFD, 0);
|
||||
|
||||
if (sf == -1 || df == -1 ||
|
||||
fcntl(_glfw.x11.emptyEventPipe[i], F_SETFL, sf | O_NONBLOCK) == -1 ||
|
||||
fcntl(_glfw.x11.emptyEventPipe[i], F_SETFD, df | FD_CLOEXEC) == -1)
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"X11: Failed to set flags for empty event pipe: %s",
|
||||
strerror(errno));
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// X error handler
|
||||
//
|
||||
static int errorHandler(Display *display, XErrorEvent* event)
|
||||
@ -1095,6 +1129,9 @@ int _glfwPlatformInit(void)
|
||||
|
||||
getSystemContentScale(&_glfw.x11.contentScaleX, &_glfw.x11.contentScaleY);
|
||||
|
||||
if (!createEmptyEventPipe())
|
||||
return GLFW_FALSE;
|
||||
|
||||
if (!initExtensions())
|
||||
return GLFW_FALSE;
|
||||
|
||||
@ -1212,6 +1249,12 @@ void _glfwPlatformTerminate(void)
|
||||
#if defined(__linux__)
|
||||
_glfwTerminateJoysticksLinux();
|
||||
#endif
|
||||
|
||||
if (_glfw.x11.emptyEventPipe[0] || _glfw.x11.emptyEventPipe[1])
|
||||
{
|
||||
close(_glfw.x11.emptyEventPipe[0]);
|
||||
close(_glfw.x11.emptyEventPipe[1]);
|
||||
}
|
||||
}
|
||||
|
||||
const char* _glfwPlatformGetVersionString(void)
|
||||
|
@ -244,6 +244,7 @@ typedef struct _GLFWlibraryX11
|
||||
double restoreCursorPosX, restoreCursorPosY;
|
||||
// The window whose disabled cursor mode is active
|
||||
_GLFWwindow* disabledCursorWindow;
|
||||
int emptyEventPipe[2];
|
||||
|
||||
// Window manager atoms
|
||||
Atom NET_SUPPORTED;
|
||||
|
171
src/x11_window.c
171
src/x11_window.c
@ -27,12 +27,16 @@
|
||||
// It is fine to use C99 in this file because it will not be built with VS
|
||||
//========================================================================
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#include <X11/cursorfont.h>
|
||||
#include <X11/Xmd.h>
|
||||
|
||||
#include <sys/select.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
@ -56,50 +60,126 @@
|
||||
|
||||
#define _GLFW_XDND_VERSION 5
|
||||
|
||||
|
||||
// Wait for data to arrive using select
|
||||
// This avoids blocking other threads via the per-display Xlib lock that also
|
||||
// covers GLX functions
|
||||
// Wait for data to arrive on any of the specified file descriptors
|
||||
//
|
||||
static GLFWbool waitForEvent(double* timeout)
|
||||
static GLFWbool waitForData(struct pollfd* fds, nfds_t count, double* timeout)
|
||||
{
|
||||
fd_set fds;
|
||||
const int fd = ConnectionNumber(_glfw.x11.display);
|
||||
int count = fd + 1;
|
||||
|
||||
#if defined(__linux__)
|
||||
if (_glfw.linjs.inotify > fd)
|
||||
count = _glfw.linjs.inotify + 1;
|
||||
#endif
|
||||
for (;;)
|
||||
{
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fd, &fds);
|
||||
#if defined(__linux__)
|
||||
if (_glfw.linjs.inotify > 0)
|
||||
FD_SET(_glfw.linjs.inotify, &fds);
|
||||
#endif
|
||||
|
||||
if (timeout)
|
||||
{
|
||||
const long seconds = (long) *timeout;
|
||||
const long microseconds = (long) ((*timeout - seconds) * 1e6);
|
||||
struct timeval tv = { seconds, microseconds };
|
||||
const uint64_t base = _glfwPlatformGetTimerValue();
|
||||
|
||||
const int result = select(count, &fds, NULL, NULL, &tv);
|
||||
const int error = errno;
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__)
|
||||
const time_t seconds = (time_t) *timeout;
|
||||
const long nanoseconds = (long) ((*timeout - seconds) * 1e9);
|
||||
const struct timespec ts = { seconds, nanoseconds };
|
||||
const int result = ppoll(fds, count, &ts, NULL);
|
||||
#elif defined(__NetBSD__)
|
||||
const time_t seconds = (time_t) *timeout;
|
||||
const long nanoseconds = (long) ((*timeout - seconds) * 1e9);
|
||||
const struct timespec ts = { seconds, nanoseconds };
|
||||
const int result = pollts(fds, count, &ts, NULL);
|
||||
#else
|
||||
const int milliseconds = (int) (*timeout * 1e3);
|
||||
const int result = poll(fds, count, milliseconds);
|
||||
#endif
|
||||
const int error = errno; // clock_gettime may overwrite our error
|
||||
|
||||
*timeout -= (_glfwPlatformGetTimerValue() - base) /
|
||||
(double) _glfwPlatformGetTimerFrequency();
|
||||
|
||||
if (result > 0)
|
||||
return GLFW_TRUE;
|
||||
if ((result == -1 && error == EINTR) || *timeout <= 0.0)
|
||||
else if (result == -1 && error != EINTR && error != EAGAIN)
|
||||
return GLFW_FALSE;
|
||||
else if (*timeout <= 0.0)
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
else if (select(count, &fds, NULL, NULL, NULL) != -1 || errno != EINTR)
|
||||
else
|
||||
{
|
||||
const int result = poll(fds, count, -1);
|
||||
if (result > 0)
|
||||
return GLFW_TRUE;
|
||||
else if (result == -1 && errno != EINTR && errno != EAGAIN)
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for event data to arrive on the X11 display socket
|
||||
// This avoids blocking other threads via the per-display Xlib lock that also
|
||||
// covers GLX functions
|
||||
//
|
||||
static GLFWbool waitForX11Event(double* timeout)
|
||||
{
|
||||
struct pollfd fd = { ConnectionNumber(_glfw.x11.display), POLLIN };
|
||||
|
||||
while (!XPending(_glfw.x11.display))
|
||||
{
|
||||
if (!waitForData(&fd, 1, timeout))
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Wait for event data to arrive on any event file descriptor
|
||||
// This avoids blocking other threads via the per-display Xlib lock that also
|
||||
// covers GLX functions
|
||||
//
|
||||
static GLFWbool waitForAnyEvent(double* timeout)
|
||||
{
|
||||
nfds_t count = 2;
|
||||
struct pollfd fds[3] =
|
||||
{
|
||||
{ ConnectionNumber(_glfw.x11.display), POLLIN },
|
||||
{ _glfw.x11.emptyEventPipe[0], POLLIN }
|
||||
};
|
||||
|
||||
#if defined(__linux__)
|
||||
if (_glfw.linjs.inotify > 0)
|
||||
fds[count++] = (struct pollfd) { _glfw.linjs.inotify, POLLIN };
|
||||
#endif
|
||||
|
||||
while (!XPending(_glfw.x11.display))
|
||||
{
|
||||
if (!waitForData(fds, count, timeout))
|
||||
return GLFW_FALSE;
|
||||
|
||||
for (int i = 1; i < count; i++)
|
||||
{
|
||||
if (fds[i].revents & POLLIN)
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
// Writes a byte to the empty event pipe
|
||||
//
|
||||
static void writeEmptyEvent(void)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
const char byte = 0;
|
||||
const int result = write(_glfw.x11.emptyEventPipe[1], &byte, 1);
|
||||
if (result == 1 || (result == -1 && errno != EINTR))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Drains available data from the empty event pipe
|
||||
//
|
||||
static void drainEmptyEvents(void)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
char dummy[64];
|
||||
const int result = read(_glfw.x11.emptyEventPipe[0], dummy, sizeof(dummy));
|
||||
if (result == -1 && errno != EINTR)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,7 +196,7 @@ static GLFWbool waitForVisibilityNotify(_GLFWwindow* window)
|
||||
VisibilityNotify,
|
||||
&dummy))
|
||||
{
|
||||
if (!waitForEvent(&timeout))
|
||||
if (!waitForX11Event(&timeout))
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
@ -971,7 +1051,7 @@ static const char* getSelectionString(Atom selection)
|
||||
SelectionNotify,
|
||||
¬ification))
|
||||
{
|
||||
waitForEvent(NULL);
|
||||
waitForX11Event(NULL);
|
||||
}
|
||||
|
||||
if (notification.xselection.property == None)
|
||||
@ -1007,7 +1087,7 @@ static const char* getSelectionString(Atom selection)
|
||||
isSelPropNewValueNotify,
|
||||
(XPointer) ¬ification))
|
||||
{
|
||||
waitForEvent(NULL);
|
||||
waitForX11Event(NULL);
|
||||
}
|
||||
|
||||
XFree(data);
|
||||
@ -1252,7 +1332,7 @@ static void processEvent(XEvent *event)
|
||||
// (the server never sends a timestamp of zero)
|
||||
// NOTE: Timestamp difference is compared to handle wrap-around
|
||||
Time diff = event->xkey.time - window->x11.keyPressTimes[keycode];
|
||||
if (diff == event->xkey.time || (diff > 0 && diff < (1 << 31)))
|
||||
if (diff == event->xkey.time || (diff > 0 && diff < ((Time)1 << 31)))
|
||||
{
|
||||
if (keycode)
|
||||
_glfwInputKey(window, key, keycode, GLFW_PRESS, mods);
|
||||
@ -1938,7 +2018,7 @@ void _glfwPushSelectionToManagerX11(void)
|
||||
}
|
||||
}
|
||||
|
||||
waitForEvent(NULL);
|
||||
waitForX11Event(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2256,7 +2336,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
|
||||
isFrameExtentsEvent,
|
||||
(XPointer) window))
|
||||
{
|
||||
if (!waitForEvent(&timeout))
|
||||
if (!waitForX11Event(&timeout))
|
||||
{
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue");
|
||||
@ -2748,7 +2828,7 @@ GLFWbool _glfwPlatformRawMouseMotionSupported(void)
|
||||
|
||||
void _glfwPlatformPollEvents(void)
|
||||
{
|
||||
_GLFWwindow* window;
|
||||
drainEmptyEvents();
|
||||
|
||||
#if defined(__linux__)
|
||||
_glfwDetectJoystickConnectionLinux();
|
||||
@ -2762,7 +2842,7 @@ void _glfwPlatformPollEvents(void)
|
||||
processEvent(&event);
|
||||
}
|
||||
|
||||
window = _glfw.x11.disabledCursorWindow;
|
||||
_GLFWwindow* window = _glfw.x11.disabledCursorWindow;
|
||||
if (window)
|
||||
{
|
||||
int width, height;
|
||||
@ -2782,32 +2862,19 @@ void _glfwPlatformPollEvents(void)
|
||||
|
||||
void _glfwPlatformWaitEvents(void)
|
||||
{
|
||||
while (!XPending(_glfw.x11.display))
|
||||
waitForEvent(NULL);
|
||||
|
||||
waitForAnyEvent(NULL);
|
||||
_glfwPlatformPollEvents();
|
||||
}
|
||||
|
||||
void _glfwPlatformWaitEventsTimeout(double timeout)
|
||||
{
|
||||
while (!XPending(_glfw.x11.display))
|
||||
{
|
||||
if (!waitForEvent(&timeout))
|
||||
break;
|
||||
}
|
||||
|
||||
waitForAnyEvent(&timeout);
|
||||
_glfwPlatformPollEvents();
|
||||
}
|
||||
|
||||
void _glfwPlatformPostEmptyEvent(void)
|
||||
{
|
||||
XEvent event = { ClientMessage };
|
||||
event.xclient.window = _glfw.x11.helperWindowHandle;
|
||||
event.xclient.format = 32; // Data is 32-bit longs
|
||||
event.xclient.message_type = _glfw.x11.NULL_;
|
||||
|
||||
XSendEvent(_glfw.x11.display, _glfw.x11.helperWindowHandle, False, 0, &event);
|
||||
XFlush(_glfw.x11.display);
|
||||
writeEmptyEvent();
|
||||
}
|
||||
|
||||
void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
|
||||
|
Loading…
Reference in New Issue
Block a user