Merge branch '3.3-stable' into new-cursors-on-3.3-stable

This commit is contained in:
Camilla Löwy 2022-03-20 18:03:04 +01:00
commit 74a1ae065a
20 changed files with 449 additions and 148 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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`.

View File

@ -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

View File

@ -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",

View File

@ -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))

View File

@ -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",

View File

@ -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");

View File

@ -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)
{

View File

@ -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,

View File

@ -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;

View File

@ -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 {

View File

@ -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)
{
ShowWindow(window->win32.handle, SW_MAXIMIZE);
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);

View File

@ -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,10 +1294,8 @@ 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);
free(_glfw.wl.clipboardString);
free(_glfw.wl.clipboardSendString);
}
const char* _glfwPlatformGetVersionString(void)

View File

@ -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,30 +908,38 @@ static void handleEvents(int timeout)
{ _glfw.wl.cursorTimerfd, POLLIN },
};
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)
while (!event)
{
_GLFWwindow* window = _glfw.windowListHead;
while (window)
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 (!flushDisplay())
{
_glfwInputWindowCloseRequest(window);
window = window->next;
wl_display_cancel_read(_glfw.wl.display);
_GLFWwindow* window = _glfw.windowListHead;
while (window)
{
_glfwInputWindowCloseRequest(window);
window = window->next;
}
return;
}
wl_display_cancel_read(_glfw.wl.display);
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 shouldnt 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.

View File

@ -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)

View File

@ -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;

View File

@ -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)
return GLFW_TRUE;
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,
&notification))
{
waitForEvent(NULL);
waitForX11Event(NULL);
}
if (notification.xselection.property == None)
@ -1007,7 +1087,7 @@ static const char* getSelectionString(Atom selection)
isSelPropNewValueNotify,
(XPointer) &notification))
{
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)