Compare commits

...

10 Commits

Author SHA1 Message Date
Alex Sanchez-Stern
bbe868d44e
Merge 06f21df20e into 63a7e8b7f8 2025-08-22 13:04:40 +02:00
Camilla Löwy
63a7e8b7f8 Add and update Wayland-specific notes in docs
Fixes #2746
2025-08-20 20:13:07 +02:00
Doug Binks
acb92944d4 Revert readme for "Wayland: Keyboard leave event handler now processes key repeats" 2025-08-19 11:30:52 +02:00
Camilla Löwy
7ef6efeb66 Wayland: Fix cursor position after a modal
If a modal surface like the window menu was active, clicking on the GLFW
window content area to close it would correctly emit the cursor enter
event but would not propagate the cursor position from the event.
2025-08-18 20:58:12 +02:00
Camilla Löwy
3cf9f6726d Wayland: Fix fallback decoration cursor updating
When a click through to the fallback decorations caused the end of
a modal like the window menu, the cursor shape would not be updated
until the next time the cursor moved.

This commit adds an update of the cursor for the pointer enter event for
fallback decoration surfaces, in addition to the updates at pointer
motion events.
2025-08-18 18:06:46 +02:00
Camilla Löwy
bfa1c424e5 Wayland: Fix fallback decoration menu placement
The fallback decorations would place the menu at the wrong position, by
not translating the last decoration surface position into toplevel
surface coordinates.

This also limits the menu to the caption area of the top decoration
surface, similar to how other toolkits work.
2025-08-18 18:06:46 +02:00
Alex Sanchez-Stern
06f21df20e Add documentation of the change as described in the GLFW contributers guide 2024-10-13 15:33:42 -07:00
Alex Sanchez-Stern
c31de75111 Don't expose the function pointer symbol directly for encapsulation 2024-10-13 15:30:39 -07:00
Alex Sanchez-Stern
f269a6af97 Add ability to get the clipboard target window
This allows users to claim the selection independently in a way that's
compatible with the handlers from GLFW.
2024-10-13 15:30:39 -07:00
Alex Sanchez-Stern
f1f869acf7 Hooks to allow serving non-text selections 2024-10-13 15:30:39 -07:00
12 changed files with 174 additions and 32 deletions

View File

@ -55,6 +55,7 @@ video tutorials.
- Jason Daly
- danhambleton
- Jarrod Davis
- decce
- Olivier Delannoy
- Paul R. Deppe
- Michael Dickens
@ -296,6 +297,7 @@ video tutorials.
- Jonas Ådahl
- Lasse Öörni
- Leonard König
- Alex Sanchez-Stern
- All the unmentioned and anonymous contributors in the GLFW community, for bug
reports, patches, feedback, testing and encouragement

View File

@ -134,17 +134,25 @@ information on what to include when reporting a bug.
- [Wayland] Bugfix: Ignore key repeat events when no window has keyboard focus (#2727)
- [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
- [Wayland] Bugfix: Keyboard repeat events halted when any key is released (#2568)
- [Wayland] Bugfix: Fallback decorations would show menu at wrong position
- [Wayland] Bugfix: The cursor was not updated when clicking through from
a modal to a fallback decoration
- [Wayland] Bugfix: The cursor position was not updated when clicking through
from a modal to the content area
- [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`
- [EGL] Allowed native access on Wayland with `GLFW_CONTEXT_CREATION_API` set to
`GLFW_NATIVE_CONTEXT_API` (#2518)
- [X11] Added `getSelectionRequestHandler`, `setSelectionRequestHander`,
`getGLFWDisplay`, and `getGLFWHelperWindow` functions. to allow
clients to implement more X clipboard functionality than is
built-in; with these primitives clients can add copy paste support
for files, images, colors, and other non-text data types.
## Contact
@ -160,4 +168,3 @@ request, please file it in the
Finally, if you're interested in helping out with the development of GLFW or
porting it to your favorite platform, join us on the forum or GitHub.

View File

@ -973,6 +973,53 @@ The contents of the system clipboard can be set to a UTF-8 encoded string with
glfwSetClipboardString(NULL, "A string with words in it");
```
\par Advanced Usage
While GLFW does not directly support using other data types with the
system clipboard, on many platforms this is possible using platform
specific code. If you are primarily targetting a small set of
platforms, this may be viable for your application.
\par
On Windows, you can do clipboard operations directly using <a
href="https://learn.microsoft.com/en-us/windows/win32/api/winuser/">winuser.h</a>,
allowing you to copy and paste datatypes other than text. On X11 you
can also use the platform specific API to get this functionality, but
you must hook into GLFW's X11 event handling code to allow copying
<i>out</i> of your application. Example code for most of this functionality
can be found in general X11 documentation like <a
href="http://www.uninformativ.de/blog/postings/2017-04-02/0/POSTING-en.html">this
page</a>; the GLFW-specific part is including
\par
@code
#include <GLFW/glfw3.h>
#include <X11/Xlib.h>
#define GLFW_EXPOSE_NATIVE_X11
#include <GLFW/glfw3native.h>
@endcode
\par
At the top of your file (guarded by platform), and then running
\par
@code
setSelectionRequestHandler(myHandler);
@endcode
\par
on initialization. Your selection handler must have the signature:
\par
@code
void myHandler(XEvent*);
@endcode
\par
and it will receive all X Selection events. To ensure compatibility
use `getGLFWDisplay()` to get a display object instead of
`XOpenDisplay()` and use the result of `getGLFWHelperWindow()` as the
target window for the selection.
## Path drop input {#path_drop}

View File

@ -255,3 +255,7 @@ hardware gamma correction, which today is typically an approximation of sRGB
gamma. This means that setting a perfectly linear ramp, or gamma 1.0, will
produce the default (usually sRGB-like) behavior.
@note @wayland An application cannot read or modify the monitor gamma ramp. The
@ref glfwGetGammaRamp, @ref glfwSetGammaRamp and @ref glfwSetGamma functions
emit @ref GLFW_FEATURE_UNAVAILABLE.

View File

@ -14,6 +14,25 @@ values over 8. For compatibility with older versions, the
@ref GLFW_UNLIMITED_MOUSE_BUTTONS input mode needs to be set to make use of
this.
### Support for custom X11 clipboard functionality {#x11_custom_selection}
This change allows clients to implement custom X11 clipboard
functionality like the copying and pasting of files across
applications.
GLFW itself only allows plain text to be copied to the
clipboard and back on all platforms. On some platforms, like Windows,
you can use platform specific APIs to add extra clipboard
functionality like copying of other data types. However, on X11, this
was previously not fully possible due to the fact that GLFW internal
code has full control over the X11 event queue.
This change exposes several new symbols that allow you to get and set
the handler for X11 selection events that GLFW will use. It also
allows getting the internal display connection and selection helper
window, for use in that kind of code.
## Caveats {#caveats}
## Deprecations {#deprecations}
@ -39,6 +58,12 @@ actively maintained and available on many platforms.
### New functions {#new_functions}
#### X11-specific
- @ref getSelectionRequestHandler
- @ref setSelectionRequestHanddler
- @ref getGLFWDisplay
- @ref getGLFWHelperWindow
### New types {#new_types}
### New constants {#new_constants}

View File

@ -893,6 +893,12 @@ int xpos, ypos;
glfwGetWindowPos(window, &xpos, &ypos);
```
@note @wayland An applications cannot know the positions of its windows or
whether one has been moved. The @ref GLFW_POSITION_X and @ref GLFW_POSITION_Y
window hints are ignored. The @ref glfwGetWindowPos and @ref glfwSetWindowPos
functions emit @ref GLFW_FEATURE_UNAVAILABLE. The window position callback will
not be called.
### Window title {#window_title}
@ -1038,6 +1044,12 @@ You can also get the current iconification state with @ref glfwGetWindowAttrib.
int iconified = glfwGetWindowAttrib(window, GLFW_ICONIFIED);
```
@note @wayland An application cannot know if any of its windows have been
iconified or restore one from iconification. The @ref glfwRestoreWindow
function can only restore windows from maximization and the iconify callback
will not be called. The [GLFW_ICONIFIED](@ref GLFW_ICONIFIED_attrib) attribute
will be false. The @ref glfwIconifyWindow function works normally.
### Window maximization {#window_maximize}

View File

@ -2915,8 +2915,8 @@ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref GLFW_INVALID_VALUE,
* @ref GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks).
*
* @remark @wayland Gamma handling is a privileged protocol, this function
* will thus never be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE.
* @remark @wayland Monitor gamma is a privileged protocol, so this function
* cannot be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE.
*
* @thread_safety This function must only be called from the main thread.
*
@ -2939,8 +2939,8 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* monitor, float gamma);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref GLFW_PLATFORM_ERROR
* and @ref GLFW_FEATURE_UNAVAILABLE (see remarks).
*
* @remark @wayland Gamma handling is a privileged protocol, this function
* will thus never be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE while
* @remark @wayland Monitor gamma is a privileged protocol, so this function
* cannot be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE while
* returning `NULL`.
*
* @pointer_lifetime The returned structure and its arrays are allocated and
@ -2983,8 +2983,8 @@ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor);
*
* @remark @win32 The gamma ramp size must be 256.
*
* @remark @wayland Gamma handling is a privileged protocol, this function
* will thus never be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE.
* @remark @wayland Monitor gamma is a privileged protocol, so this function
* cannot be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE.
*
* @pointer_lifetime The specified gamma ramp is copied before this function
* returns.
@ -3430,8 +3430,8 @@ GLFWAPI void glfwSetWindowIcon(GLFWwindow* window, int count, const GLFWimage* i
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
* GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks).
*
* @remark @wayland There is no way for an application to retrieve the global
* position of its windows. This function will emit @ref
* @remark @wayland Window positions are not currently part of any common
* Wayland protocol, so this function cannot be implemented and will emit @ref
* GLFW_FEATURE_UNAVAILABLE.
*
* @thread_safety This function must only be called from the main thread.
@ -3464,8 +3464,8 @@ GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
* GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks).
*
* @remark @wayland There is no way for an application to set the global
* position of its windows. This function will emit @ref
* @remark @wayland Window positions are not currently part of any common
* Wayland protocol, so this function cannot be implemented and will emit @ref
* GLFW_FEATURE_UNAVAILABLE.
*
* @thread_safety This function must only be called from the main thread.
@ -3807,10 +3807,6 @@ GLFWAPI void glfwSetWindowOpacity(GLFWwindow* window, float opacity);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR.
*
* @remark @wayland Once a window is iconified, @ref glfwRestoreWindow wont
* be able to restore it. This is a design decision of the xdg-shell
* protocol.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref window_iconify
@ -3838,6 +3834,10 @@ GLFWAPI void glfwIconifyWindow(GLFWwindow* window);
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR.
*
* @remark @wayland Restoring a window from maximization is not currently part
* of any common Wayland protocol, so this function can only restore windows
* from maximization.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref window_iconify
@ -4058,8 +4058,8 @@ GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window);
* affected by any resizing or mode switching, although you may need to update
* your viewport if the framebuffer size has changed.
*
* @remark @wayland The desired window position is ignored, as there is no way
* for an application to set this property.
* @remark @wayland Window positions are not currently part of any common
* Wayland protocol. The window position arguments are ignored.
*
* @thread_safety This function must only be called from the main thread.
*
@ -4096,8 +4096,9 @@ GLFWAPI void glfwSetWindowMonitor(GLFWwindow* window, GLFWmonitor* monitor, int
* errors. However, this function should not fail as long as it is passed
* valid arguments and the library has been [initialized](@ref intro_init).
*
* @remark @wayland The Wayland protocol provides no way to check whether a
* window is iconfied, so @ref GLFW_ICONIFIED always returns `GLFW_FALSE`.
* @remark @wayland Checking whether a window is iconified is not currently
* part of any common Wayland protocol, so the @ref GLFW_ICONIFIED attribute
* cannot be implemented and is always `GLFW_FALSE`.
*
* @thread_safety This function must only be called from the main thread.
*
@ -4219,8 +4220,8 @@ GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* window);
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
*
* @remark @wayland This callback will never be called, as there is no way for
* an application to know its global position.
* @remark @wayland This callback will not be called. The Wayland protocol
* provides no way to be notified of when a window is moved.
*
* @thread_safety This function must only be called from the main thread.
*
@ -4395,6 +4396,10 @@ GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwi
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
*
* @remark @wayland This callback will not be called. The Wayland protocol
* provides no way to be notified of when a window is iconified, and no way to
* check whether a window is currently iconified.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref window_iconify

View File

@ -442,6 +442,13 @@ GLFWAPI void glfwSetX11SelectionString(const char* string);
* @ingroup native
*/
GLFWAPI const char* glfwGetX11SelectionString(void);
#include <X11/Xlib.h>
void (*getSelectionRequestHandler(void))(XEvent*);
void setSelectionRequestHandler(void (*handler)(XEvent*));
Display* getGLFWDisplay(void);
Window getGLFWHelperWindow(void);
#endif
#if defined(GLFW_EXPOSE_NATIVE_GLX)

View File

@ -405,13 +405,19 @@ static void handleFallbackDecorationButton(_GLFWwindow* window,
}
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);
}
if (!window->wl.xdg.toplevel)
return;
if (window->wl.fallback.focus != window->wl.fallback.top.surface)
return;
if (ypos < GLFW_BORDER_SIZE)
return;
xdg_toplevel_show_window_menu(window->wl.xdg.toplevel,
_glfw.wl.seat, serial,
xpos,
ypos - GLFW_CAPTION_HEIGHT - GLFW_BORDER_SIZE);
}
}
@ -1532,11 +1538,21 @@ static void pointerHandleEnter(void* userData,
window->wl.hovered = GLFW_TRUE;
_glfwSetCursorWayland(window, window->wl.currentCursor);
_glfwInputCursorEnter(window, GLFW_TRUE);
if (window->cursorMode != GLFW_CURSOR_DISABLED)
{
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)
{
window->wl.fallback.focus = surface;
updateFallbackDecorationCursor(window, sx, sy);
}
}
}

View File

@ -1315,6 +1315,8 @@ GLFWbool _glfwConnectX11(int platformID, _GLFWplatform* platform)
_glfw.x11.xlib.handle = module;
*platform = x11;
handleSelectionRequest = handleSelectionRequest_;
return GLFW_TRUE;
}

View File

@ -896,6 +896,8 @@ typedef struct _GLFWcursorX11
Cursor handle;
} _GLFWcursorX11;
extern void (*handleSelectionRequest)(XEvent*);
void handleSelectionRequest_(XEvent* event);
GLFWbool _glfwConnectX11(int platformID, _GLFWplatform* platform);
int _glfwInitX11(void);

View File

@ -921,7 +921,8 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent* request)
return None;
}
static void handleSelectionRequest(XEvent* event)
void (*handleSelectionRequest)(XEvent*);
void handleSelectionRequest_(XEvent* event)
{
const XSelectionRequestEvent* request = &event->xselectionrequest;
@ -3356,6 +3357,18 @@ GLFWAPI const char* glfwGetX11SelectionString(void)
return getSelectionString(_glfw.x11.PRIMARY);
}
void (*getSelectionRequestHandler(void))(XEvent*) {
return handleSelectionRequest;
}
void setSelectionRequestHandler(void (*handler)(XEvent*)) {
handleSelectionRequest = handler;
}
Display* getGLFWDisplay(void) {
return _glfw.x11.display;
}
Window getGLFWHelperWindow(void) {
return _glfw.x11.helperWindowHandle;
}
#endif // _GLFW_X11