mirror of
https://github.com/glfw/glfw.git
synced 2025-12-21 06:31:58 +00:00
Compare commits
8 Commits
034a1fd076
...
26afb5cae5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26afb5cae5 | ||
|
|
161fb1b6f6 | ||
|
|
645a35a38e | ||
|
|
7523b0e6bd | ||
|
|
5190a30d8a | ||
|
|
ddbb8e0f2c | ||
|
|
5245180c56 | ||
|
|
11d96a4ab4 |
@ -135,6 +135,9 @@ information on what to include when reporting a bug.
|
||||
- [Wayland] Bugfix: Reset key repeat timer when window destroyed (#2741,#2727)
|
||||
- [Wayland] Bugfix: Memory would leak if reading a data offer failed midway
|
||||
- [Wayland] Bugfix: Keyboard leave event handler now processes key repeats (#2736)
|
||||
- [Wayland] Bugfix: Retrieved cursor position would be incorrect when hovering over
|
||||
fallback decorations
|
||||
- [Wayland] Bugfix: Fallback decorations would report scroll events
|
||||
- [X11] Bugfix: Running without a WM could trigger an assert (#2593,#2601,#2631)
|
||||
- [Null] Added Vulkan 'window' surface creation via `VK_EXT_headless_surface`
|
||||
- [Null] Added EGL context creation on Mesa via `EGL_MESA_platform_surfaceless`
|
||||
|
||||
@ -153,10 +153,23 @@ the `VK_KHR_xlib_surface` extension. Possible values are `GLFW_TRUE` and
|
||||
`GLFW_FALSE`. This is ignored on other platforms.
|
||||
|
||||
|
||||
#### Windows specific init hints {#init_hints_windows}
|
||||
|
||||
@anchor GLFW_WIN32_MESSAGES_IN_FIBER_hint
|
||||
__GLFW_WIN32_MESSAGES_IN_FIBER__ specifies whether to use separate fiber for
|
||||
processing Windows message, and not the main thread. This allows to unblock
|
||||
window move and resize operations, and application can do updates and rendering
|
||||
in its main loop. __Warning__ - setting this hint is not safe for environments
|
||||
or frameworks where stack inspection is required (for example, moving garbage
|
||||
collected languages such as Java or C#). Set this with @ref glfwInitHint.
|
||||
|
||||
|
||||
#### Supported and default values {#init_hints_values}
|
||||
|
||||
Initialization hint | Default value | Supported values
|
||||
-------------------------------- | ------------------------------- | ----------------
|
||||
--------------------------------- | ------------------------------- | ----------------
|
||||
|
||||
--------------------------------- | ------------------------------- | ----------------
|
||||
@ref GLFW_PLATFORM | `GLFW_ANY_PLATFORM` | `GLFW_ANY_PLATFORM`, `GLFW_PLATFORM_WIN32`, `GLFW_PLATFORM_COCOA`, `GLFW_PLATFORM_WAYLAND`, `GLFW_PLATFORM_X11` or `GLFW_PLATFORM_NULL`
|
||||
@ref GLFW_JOYSTICK_HAT_BUTTONS | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE`
|
||||
@ref GLFW_ANGLE_PLATFORM_TYPE | `GLFW_ANGLE_PLATFORM_TYPE_NONE` | `GLFW_ANGLE_PLATFORM_TYPE_NONE`, `GLFW_ANGLE_PLATFORM_TYPE_OPENGL`, `GLFW_ANGLE_PLATFORM_TYPE_OPENGLES`, `GLFW_ANGLE_PLATFORM_TYPE_D3D9`, `GLFW_ANGLE_PLATFORM_TYPE_D3D11`, `GLFW_ANGLE_PLATFORM_TYPE_VULKAN` or `GLFW_ANGLE_PLATFORM_TYPE_METAL`
|
||||
@ -164,6 +177,7 @@ Initialization hint | Default value | Supported v
|
||||
@ref GLFW_COCOA_MENUBAR | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE`
|
||||
@ref GLFW_WAYLAND_LIBDECOR | `GLFW_WAYLAND_PREFER_LIBDECOR` | `GLFW_WAYLAND_PREFER_LIBDECOR` or `GLFW_WAYLAND_DISABLE_LIBDECOR`
|
||||
@ref GLFW_X11_XCB_VULKAN_SURFACE | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE`
|
||||
@ref GLFW_WIN32_MESSAGES_IN_FIBER | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE`
|
||||
|
||||
|
||||
### Runtime platform selection {#platform}
|
||||
|
||||
@ -1328,6 +1328,11 @@ extern "C" {
|
||||
* Wayland specific [init hint](@ref GLFW_WAYLAND_LIBDECOR_hint).
|
||||
*/
|
||||
#define GLFW_WAYLAND_LIBDECOR 0x00053001
|
||||
/*! @brief Windows specific init hint.
|
||||
*
|
||||
* Windows specific [init hint](@ref GLFW_WIN32_MESSAGES_IN_FIBER_hint).
|
||||
*/
|
||||
#define GLFW_WIN32_MESSAGES_IN_FIBER 0x00054001
|
||||
/*! @} */
|
||||
|
||||
/*! @addtogroup init
|
||||
@ -1604,6 +1609,10 @@ typedef void (* GLFWerrorfun)(int error_code, const char* description);
|
||||
* @param[in] ypos The new y-coordinate, in screen coordinates, of the
|
||||
* upper-left corner of the content area of the window.
|
||||
*
|
||||
* @remark @win32 On Windows moving or resizing of window will block event
|
||||
* processing. Workaround for this is @ref GLFW_WIN32_MESSAGES_IN_FIBER init
|
||||
* hint.
|
||||
*
|
||||
* @sa @ref window_pos
|
||||
* @sa @ref glfwSetWindowPosCallback
|
||||
*
|
||||
@ -1625,6 +1634,10 @@ typedef void (* GLFWwindowposfun)(GLFWwindow* window, int xpos, int ypos);
|
||||
* @param[in] width The new width, in screen coordinates, of the window.
|
||||
* @param[in] height The new height, in screen coordinates, of the window.
|
||||
*
|
||||
* @remark @win32 On Windows moving or resizing of window will block event
|
||||
* processing. Workaround for this is @ref GLFW_WIN32_MESSAGES_IN_FIBER init
|
||||
* hint.
|
||||
*
|
||||
* @sa @ref window_size
|
||||
* @sa @ref glfwSetWindowSizeCallback
|
||||
*
|
||||
|
||||
@ -66,6 +66,10 @@ static _GLFWinitconfig _glfwInitHints =
|
||||
{
|
||||
.libdecorMode = GLFW_WAYLAND_PREFER_LIBDECOR
|
||||
},
|
||||
.win32 =
|
||||
{
|
||||
.msgInFiber = GLFW_FALSE,
|
||||
}
|
||||
};
|
||||
|
||||
// The allocation function used when no custom allocator is set
|
||||
@ -462,6 +466,9 @@ GLFWAPI void glfwInitHint(int hint, int value)
|
||||
case GLFW_WAYLAND_LIBDECOR:
|
||||
_glfwInitHints.wl.libdecorMode = value;
|
||||
return;
|
||||
case GLFW_WIN32_MESSAGES_IN_FIBER:
|
||||
_glfwInitHints.win32.msgInFiber = value;
|
||||
return;
|
||||
}
|
||||
|
||||
_glfwInputError(GLFW_INVALID_ENUM,
|
||||
|
||||
@ -388,6 +388,9 @@ struct _GLFWinitconfig
|
||||
struct {
|
||||
int libdecorMode;
|
||||
} wl;
|
||||
struct {
|
||||
GLFWbool msgInFiber;
|
||||
} win32;
|
||||
};
|
||||
|
||||
// Window configuration
|
||||
|
||||
@ -366,7 +366,6 @@ static LRESULT CALLBACK helperWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LP
|
||||
//
|
||||
static GLFWbool createHelperWindow(void)
|
||||
{
|
||||
MSG msg;
|
||||
WNDCLASSEXW wc = { sizeof(wc) };
|
||||
|
||||
wc.style = CS_OWNDC;
|
||||
@ -417,11 +416,19 @@ static GLFWbool createHelperWindow(void)
|
||||
DEVICE_NOTIFY_WINDOW_HANDLE);
|
||||
}
|
||||
|
||||
if (_glfw.hints.init.win32.msgInFiber)
|
||||
{
|
||||
SwitchToFiber(_glfw.win32.messageFiber);
|
||||
}
|
||||
else
|
||||
{
|
||||
MSG msg;
|
||||
while (PeekMessageW(&msg, _glfw.win32.helperWindowHandle, 0, 0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
@ -594,6 +601,45 @@ BOOL _glfwIsWindows10BuildOrGreaterWin32(WORD build)
|
||||
return RtlVerifyVersionInfo(&osvi, mask, cond) == 0;
|
||||
}
|
||||
|
||||
void _glfwPollMessageLoopWin32(void)
|
||||
{
|
||||
_GLFWwindow* window;
|
||||
MSG msg;
|
||||
while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
|
||||
{
|
||||
if (msg.message == WM_QUIT)
|
||||
{
|
||||
// NOTE: While GLFW does not itself post WM_QUIT, other processes
|
||||
// may post it to this one, for example Task Manager
|
||||
// HACK: Treat WM_QUIT as a close on all windows
|
||||
|
||||
window = _glfw.windowListHead;
|
||||
while (window)
|
||||
{
|
||||
_glfwInputWindowCloseRequest(window);
|
||||
window = window->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Windows message dispatch fiber
|
||||
void CALLBACK messageFiberProc(LPVOID lpFiberParameter)
|
||||
{
|
||||
(void)lpFiberParameter;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
_glfwPollMessageLoopWin32();
|
||||
SwitchToFiber(_glfw.win32.mainFiber);
|
||||
}
|
||||
}
|
||||
|
||||
GLFWbool _glfwConnectWin32(int platformID, _GLFWplatform* platform)
|
||||
{
|
||||
const _GLFWplatform win32 =
|
||||
@ -691,6 +737,17 @@ int _glfwInitWin32(void)
|
||||
else
|
||||
SetProcessDPIAware();
|
||||
|
||||
if (_glfw.hints.init.win32.msgInFiber)
|
||||
{
|
||||
_glfw.win32.mainFiber = ConvertThreadToFiber(NULL);
|
||||
if (!_glfw.win32.mainFiber)
|
||||
return GLFW_FALSE;
|
||||
|
||||
_glfw.win32.messageFiber = CreateFiber(0, &messageFiberProc, NULL);
|
||||
if (!_glfw.win32.messageFiber)
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
|
||||
if (!createHelperWindow())
|
||||
return GLFW_FALSE;
|
||||
|
||||
@ -713,6 +770,12 @@ void _glfwTerminateWin32(void)
|
||||
if (_glfw.win32.mainWindowClass)
|
||||
UnregisterClassW(MAKEINTATOM(_glfw.win32.mainWindowClass), _glfw.win32.instance);
|
||||
|
||||
if (_glfw.hints.init.win32.msgInFiber)
|
||||
{
|
||||
DeleteFiber(_glfw.win32.messageFiber);
|
||||
ConvertFiberToThread();
|
||||
}
|
||||
|
||||
_glfw_free(_glfw.win32.clipboardString);
|
||||
_glfw_free(_glfw.win32.rawInput);
|
||||
|
||||
|
||||
@ -375,6 +375,11 @@ typedef struct _GLFWwindowWin32
|
||||
int lastCursorPosX, lastCursorPosY;
|
||||
// The last received high surrogate when decoding pairs of UTF-16 messages
|
||||
WCHAR highSurrogate;
|
||||
|
||||
// If user pressed mouse button on window title bar
|
||||
UINT ncMouseButton;
|
||||
LPARAM ncMousePos;
|
||||
|
||||
} _GLFWwindowWin32;
|
||||
|
||||
// Win32-specific global data
|
||||
@ -403,6 +408,9 @@ typedef struct _GLFWlibraryWin32
|
||||
// The cursor handle to use to hide the cursor (NULL or a transparent cursor)
|
||||
HCURSOR blankCursor;
|
||||
|
||||
LPVOID messageFiber;
|
||||
LPVOID mainFiber;
|
||||
|
||||
struct {
|
||||
HINSTANCE instance;
|
||||
PFN_DirectInput8Create Create;
|
||||
@ -519,6 +527,7 @@ void _glfwSetWindowOpacityWin32(_GLFWwindow* window, float opacity);
|
||||
void _glfwSetRawMouseMotionWin32(_GLFWwindow *window, GLFWbool enabled);
|
||||
GLFWbool _glfwRawMouseMotionSupportedWin32(void);
|
||||
|
||||
void _glfwPollMessageLoopWin32(void);
|
||||
void _glfwPollEventsWin32(void);
|
||||
void _glfwWaitEventsWin32(void);
|
||||
void _glfwWaitEventsTimeoutWin32(double timeout);
|
||||
|
||||
@ -853,11 +853,46 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
|
||||
return 0;
|
||||
}
|
||||
|
||||
case WM_NCLBUTTONDOWN:
|
||||
{
|
||||
if (wParam == HTCAPTION)
|
||||
{
|
||||
window->win32.ncMouseButton = uMsg;
|
||||
window->win32.ncMousePos = lParam;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_NCMOUSEMOVE:
|
||||
{
|
||||
if (window->win32.ncMouseButton)
|
||||
{
|
||||
if (GET_X_LPARAM(window->win32.ncMousePos) != GET_X_LPARAM(lParam) ||
|
||||
GET_Y_LPARAM(window->win32.ncMousePos) != GET_Y_LPARAM(lParam))
|
||||
{
|
||||
DefWindowProcW(hWnd, window->win32.ncMouseButton, HTCAPTION, window->win32.ncMousePos);
|
||||
window->win32.ncMouseButton = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_MOUSEMOVE:
|
||||
{
|
||||
const int x = GET_X_LPARAM(lParam);
|
||||
const int y = GET_Y_LPARAM(lParam);
|
||||
|
||||
if (window->win32.ncMouseButton)
|
||||
{
|
||||
if (GET_X_LPARAM(window->win32.ncMousePos) != x ||
|
||||
GET_Y_LPARAM(window->win32.ncMousePos) != y)
|
||||
{
|
||||
DefWindowProcW(hWnd, window->win32.ncMouseButton, HTCAPTION, window->win32.ncMousePos);
|
||||
window->win32.ncMouseButton = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!window->win32.cursorTracked)
|
||||
{
|
||||
TRACKMOUSEEVENT tme;
|
||||
@ -998,6 +1033,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
|
||||
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
|
||||
releaseCursor();
|
||||
|
||||
if (_glfw.hints.init.win32.msgInFiber)
|
||||
SetTimer(hWnd, 1, 1, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1014,6 +1051,15 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
|
||||
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
|
||||
captureCursor(window);
|
||||
|
||||
if (_glfw.hints.init.win32.msgInFiber)
|
||||
KillTimer(hWnd, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_TIMER:
|
||||
{
|
||||
if (_glfw.hints.init.win32.msgInFiber && wParam == 1)
|
||||
SwitchToFiber(_glfw.win32.mainFiber);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2088,31 +2134,13 @@ GLFWbool _glfwRawMouseMotionSupportedWin32(void)
|
||||
|
||||
void _glfwPollEventsWin32(void)
|
||||
{
|
||||
MSG msg;
|
||||
HWND handle;
|
||||
_GLFWwindow* window;
|
||||
|
||||
while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
|
||||
{
|
||||
if (msg.message == WM_QUIT)
|
||||
{
|
||||
// NOTE: While GLFW does not itself post WM_QUIT, other processes
|
||||
// may post it to this one, for example Task Manager
|
||||
// HACK: Treat WM_QUIT as a close on all windows
|
||||
|
||||
window = _glfw.windowListHead;
|
||||
while (window)
|
||||
{
|
||||
_glfwInputWindowCloseRequest(window);
|
||||
window = window->next;
|
||||
}
|
||||
}
|
||||
if (_glfw.hints.init.win32.msgInFiber)
|
||||
SwitchToFiber(_glfw.win32.messageFiber);
|
||||
else
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
}
|
||||
_glfwPollMessageLoopWin32();
|
||||
|
||||
// HACK: Release modifier keys that the system did not emit KEYUP for
|
||||
// NOTE: Shift keys on Windows tend to "stick" when both are pressed as
|
||||
|
||||
@ -413,6 +413,8 @@ typedef struct _GLFWwindowWayland
|
||||
struct wl_buffer* buffer;
|
||||
_GLFWfallbackEdgeWayland top, left, right, bottom;
|
||||
struct wl_surface* focus;
|
||||
wl_fixed_t pointerX, pointerY;
|
||||
const char* cursorName;
|
||||
} fallback;
|
||||
} _GLFWwindowWayland;
|
||||
|
||||
@ -454,7 +456,6 @@ typedef struct _GLFWlibraryWayland
|
||||
struct wl_cursor_theme* cursorTheme;
|
||||
struct wl_cursor_theme* cursorThemeHiDPI;
|
||||
struct wl_surface* cursorSurface;
|
||||
const char* cursorPreviousName;
|
||||
int cursorTimerfd;
|
||||
uint32_t serial;
|
||||
uint32_t pointerEnterSerial;
|
||||
|
||||
292
src/wl_window.c
292
src/wl_window.c
@ -275,6 +275,146 @@ static void destroyFallbackDecorations(_GLFWwindow* window)
|
||||
destroyFallbackEdge(&window->wl.fallback.bottom);
|
||||
}
|
||||
|
||||
static void updateFallbackDecorationCursor(_GLFWwindow* window,
|
||||
wl_fixed_t sx,
|
||||
wl_fixed_t sy)
|
||||
{
|
||||
window->wl.fallback.pointerX = sx;
|
||||
window->wl.fallback.pointerY = sy;
|
||||
|
||||
const double xpos = wl_fixed_to_double(sx);
|
||||
const double ypos = wl_fixed_to_double(sy);
|
||||
const char* cursorName = "left_ptr";
|
||||
|
||||
if (window->resizable)
|
||||
{
|
||||
if (window->wl.fallback.focus == window->wl.fallback.top.surface)
|
||||
{
|
||||
if (ypos < GLFW_BORDER_SIZE)
|
||||
cursorName = "n-resize";
|
||||
}
|
||||
else if (window->wl.fallback.focus == window->wl.fallback.left.surface)
|
||||
{
|
||||
if (ypos < GLFW_BORDER_SIZE)
|
||||
cursorName = "nw-resize";
|
||||
else
|
||||
cursorName = "w-resize";
|
||||
}
|
||||
else if (window->wl.fallback.focus == window->wl.fallback.right.surface)
|
||||
{
|
||||
if (ypos < GLFW_BORDER_SIZE)
|
||||
cursorName = "ne-resize";
|
||||
else
|
||||
cursorName = "e-resize";
|
||||
}
|
||||
else if (window->wl.fallback.focus == window->wl.fallback.bottom.surface)
|
||||
{
|
||||
if (xpos < GLFW_BORDER_SIZE)
|
||||
cursorName = "sw-resize";
|
||||
else if (xpos > window->wl.width + GLFW_BORDER_SIZE)
|
||||
cursorName = "se-resize";
|
||||
else
|
||||
cursorName = "s-resize";
|
||||
}
|
||||
}
|
||||
|
||||
if (window->wl.fallback.cursorName != cursorName)
|
||||
{
|
||||
struct wl_surface* surface = _glfw.wl.cursorSurface;
|
||||
struct wl_cursor_theme* theme = _glfw.wl.cursorTheme;
|
||||
int scale = 1;
|
||||
|
||||
if (window->wl.bufferScale > 1 && _glfw.wl.cursorThemeHiDPI)
|
||||
{
|
||||
// We only support up to scale=2 for now, since libwayland-cursor
|
||||
// requires us to load a different theme for each size.
|
||||
scale = 2;
|
||||
theme = _glfw.wl.cursorThemeHiDPI;
|
||||
}
|
||||
|
||||
struct wl_cursor* cursor = wl_cursor_theme_get_cursor(theme, cursorName);
|
||||
if (!cursor)
|
||||
return;
|
||||
|
||||
// TODO: handle animated cursors too.
|
||||
struct wl_cursor_image* image = cursor->images[0];
|
||||
if (!image)
|
||||
return;
|
||||
|
||||
struct wl_buffer* buffer = wl_cursor_image_get_buffer(image);
|
||||
if (!buffer)
|
||||
return;
|
||||
|
||||
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial,
|
||||
surface,
|
||||
image->hotspot_x / scale,
|
||||
image->hotspot_y / scale);
|
||||
wl_surface_set_buffer_scale(surface, scale);
|
||||
wl_surface_attach(surface, buffer, 0, 0);
|
||||
wl_surface_damage(surface, 0, 0, image->width, image->height);
|
||||
wl_surface_commit(surface);
|
||||
|
||||
window->wl.fallback.cursorName = cursorName;
|
||||
}
|
||||
}
|
||||
|
||||
static void handleFallbackDecorationButton(_GLFWwindow* window,
|
||||
uint32_t serial,
|
||||
uint32_t button)
|
||||
{
|
||||
const double xpos = wl_fixed_to_double(window->wl.fallback.pointerX);
|
||||
const double ypos = wl_fixed_to_double(window->wl.fallback.pointerY);
|
||||
|
||||
if (button == BTN_LEFT)
|
||||
{
|
||||
uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE;
|
||||
|
||||
if (window->wl.fallback.focus == window->wl.fallback.top.surface)
|
||||
{
|
||||
if (ypos < GLFW_BORDER_SIZE)
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP;
|
||||
else
|
||||
xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial);
|
||||
}
|
||||
else if (window->wl.fallback.focus == window->wl.fallback.left.surface)
|
||||
{
|
||||
if (ypos < GLFW_BORDER_SIZE)
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
|
||||
else
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
|
||||
}
|
||||
else if (window->wl.fallback.focus == window->wl.fallback.right.surface)
|
||||
{
|
||||
if (ypos < GLFW_BORDER_SIZE)
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
|
||||
else
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
|
||||
}
|
||||
else if (window->wl.fallback.focus == window->wl.fallback.bottom.surface)
|
||||
{
|
||||
if (xpos < GLFW_BORDER_SIZE)
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
|
||||
else if (xpos > window->wl.width + GLFW_BORDER_SIZE)
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
|
||||
else
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
|
||||
}
|
||||
|
||||
if (edges != XDG_TOPLEVEL_RESIZE_EDGE_NONE)
|
||||
xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat, serial, edges);
|
||||
}
|
||||
else if (button == BTN_RIGHT)
|
||||
{
|
||||
if (window->wl.xdg.toplevel)
|
||||
{
|
||||
xdg_toplevel_show_window_menu(window->wl.xdg.toplevel,
|
||||
_glfw.wl.seat, serial,
|
||||
window->wl.cursorPosX,
|
||||
window->wl.cursorPosY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void xdgDecorationHandleConfigure(void* userData,
|
||||
struct zxdg_toplevel_decoration_v1* decoration,
|
||||
uint32_t mode)
|
||||
@ -1417,7 +1557,6 @@ static void pointerHandleLeave(void* userData,
|
||||
|
||||
_glfw.wl.serial = serial;
|
||||
_glfw.wl.pointerFocus = NULL;
|
||||
_glfw.wl.cursorPreviousName = NULL;
|
||||
|
||||
if (window->wl.hovered)
|
||||
{
|
||||
@ -1427,7 +1566,10 @@ static void pointerHandleLeave(void* userData,
|
||||
else
|
||||
{
|
||||
if (window->wl.fallback.decorations)
|
||||
{
|
||||
window->wl.fallback.focus = NULL;
|
||||
window->wl.fallback.cursorName = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1444,92 +1586,16 @@ static void pointerHandleMotion(void* userData,
|
||||
if (window->cursorMode == GLFW_CURSOR_DISABLED)
|
||||
return;
|
||||
|
||||
const double xpos = wl_fixed_to_double(sx);
|
||||
const double ypos = wl_fixed_to_double(sy);
|
||||
window->wl.cursorPosX = xpos;
|
||||
window->wl.cursorPosY = ypos;
|
||||
|
||||
if (window->wl.hovered)
|
||||
{
|
||||
_glfw.wl.cursorPreviousName = NULL;
|
||||
_glfwInputCursorPos(window, xpos, ypos);
|
||||
return;
|
||||
window->wl.cursorPosX = wl_fixed_to_double(sx);
|
||||
window->wl.cursorPosY = wl_fixed_to_double(sy);
|
||||
_glfwInputCursorPos(window, window->wl.cursorPosX, window->wl.cursorPosY);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (window->wl.fallback.decorations)
|
||||
{
|
||||
const char* cursorName = "left_ptr";
|
||||
|
||||
if (window->resizable)
|
||||
{
|
||||
if (window->wl.fallback.focus == window->wl.fallback.top.surface)
|
||||
{
|
||||
if (ypos < GLFW_BORDER_SIZE)
|
||||
cursorName = "n-resize";
|
||||
}
|
||||
else if (window->wl.fallback.focus == window->wl.fallback.left.surface)
|
||||
{
|
||||
if (ypos < GLFW_BORDER_SIZE)
|
||||
cursorName = "nw-resize";
|
||||
else
|
||||
cursorName = "w-resize";
|
||||
}
|
||||
else if (window->wl.fallback.focus == window->wl.fallback.right.surface)
|
||||
{
|
||||
if (ypos < GLFW_BORDER_SIZE)
|
||||
cursorName = "ne-resize";
|
||||
else
|
||||
cursorName = "e-resize";
|
||||
}
|
||||
else if (window->wl.fallback.focus == window->wl.fallback.bottom.surface)
|
||||
{
|
||||
if (xpos < GLFW_BORDER_SIZE)
|
||||
cursorName = "sw-resize";
|
||||
else if (xpos > window->wl.width + GLFW_BORDER_SIZE)
|
||||
cursorName = "se-resize";
|
||||
else
|
||||
cursorName = "s-resize";
|
||||
}
|
||||
}
|
||||
|
||||
if (_glfw.wl.cursorPreviousName != cursorName)
|
||||
{
|
||||
struct wl_surface* surface = _glfw.wl.cursorSurface;
|
||||
struct wl_cursor_theme* theme = _glfw.wl.cursorTheme;
|
||||
int scale = 1;
|
||||
|
||||
if (window->wl.bufferScale > 1 && _glfw.wl.cursorThemeHiDPI)
|
||||
{
|
||||
// We only support up to scale=2 for now, since libwayland-cursor
|
||||
// requires us to load a different theme for each size.
|
||||
scale = 2;
|
||||
theme = _glfw.wl.cursorThemeHiDPI;
|
||||
}
|
||||
|
||||
struct wl_cursor* cursor = wl_cursor_theme_get_cursor(theme, cursorName);
|
||||
if (!cursor)
|
||||
return;
|
||||
|
||||
// TODO: handle animated cursors too.
|
||||
struct wl_cursor_image* image = cursor->images[0];
|
||||
if (!image)
|
||||
return;
|
||||
|
||||
struct wl_buffer* buffer = wl_cursor_image_get_buffer(image);
|
||||
if (!buffer)
|
||||
return;
|
||||
|
||||
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial,
|
||||
surface,
|
||||
image->hotspot_x / scale,
|
||||
image->hotspot_y / scale);
|
||||
wl_surface_set_buffer_scale(surface, scale);
|
||||
wl_surface_attach(surface, buffer, 0, 0);
|
||||
wl_surface_damage(surface, 0, 0, image->width, image->height);
|
||||
wl_surface_commit(surface);
|
||||
|
||||
_glfw.wl.cursorPreviousName = cursorName;
|
||||
}
|
||||
updateFallbackDecorationCursor(window, sx, sy);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1552,62 +1618,11 @@ static void pointerHandleButton(void* userData,
|
||||
button - BTN_LEFT,
|
||||
state == WL_POINTER_BUTTON_STATE_PRESSED,
|
||||
_glfw.wl.xkb.modifiers);
|
||||
return;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (window->wl.fallback.decorations)
|
||||
{
|
||||
if (button == BTN_LEFT)
|
||||
{
|
||||
uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE;
|
||||
|
||||
if (window->wl.fallback.focus == window->wl.fallback.top.surface)
|
||||
{
|
||||
if (window->wl.cursorPosY < GLFW_BORDER_SIZE)
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP;
|
||||
else
|
||||
xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial);
|
||||
}
|
||||
else if (window->wl.fallback.focus == window->wl.fallback.left.surface)
|
||||
{
|
||||
if (window->wl.cursorPosY < GLFW_BORDER_SIZE)
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
|
||||
else
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
|
||||
}
|
||||
else if (window->wl.fallback.focus == window->wl.fallback.right.surface)
|
||||
{
|
||||
if (window->wl.cursorPosY < GLFW_BORDER_SIZE)
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
|
||||
else
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
|
||||
}
|
||||
else if (window->wl.fallback.focus == window->wl.fallback.bottom.surface)
|
||||
{
|
||||
if (window->wl.cursorPosX < GLFW_BORDER_SIZE)
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
|
||||
else if (window->wl.cursorPosX > window->wl.width + GLFW_BORDER_SIZE)
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
|
||||
else
|
||||
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
|
||||
}
|
||||
|
||||
if (edges != XDG_TOPLEVEL_RESIZE_EDGE_NONE)
|
||||
{
|
||||
xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat,
|
||||
serial, edges);
|
||||
}
|
||||
}
|
||||
else if (button == BTN_RIGHT)
|
||||
{
|
||||
if (window->wl.xdg.toplevel)
|
||||
{
|
||||
xdg_toplevel_show_window_menu(window->wl.xdg.toplevel,
|
||||
_glfw.wl.seat, serial,
|
||||
window->wl.cursorPosX,
|
||||
window->wl.cursorPosY);
|
||||
}
|
||||
}
|
||||
handleFallbackDecorationButton(window, serial, button);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1621,12 +1636,15 @@ static void pointerHandleAxis(void* userData,
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
if (window->wl.hovered)
|
||||
{
|
||||
// NOTE: 10 units of motion per mouse wheel step seems to be a common ratio
|
||||
if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
|
||||
_glfwInputScroll(window, -wl_fixed_to_double(value) / 10.0, 0.0);
|
||||
else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
|
||||
_glfwInputScroll(window, 0.0, -wl_fixed_to_double(value) / 10.0);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct wl_pointer_listener pointerListener =
|
||||
{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user