Compare commits

...

8 Commits

Author SHA1 Message Date
Tau Gärtli
3e05648c66
Merge b39236c11a into dbadda2683 2025-12-10 12:04:30 +00:00
Tau Gärtli
b39236c11a
Load DBus at runtime 2025-12-10 13:02:45 +01:00
Tau Gärtli
a1777976be
Wayland: Add support for dropping files when sandboxed
Adds support for receiving drops that make use
of the [File Transfer][1] portal. This is the case
in sandboxed environments such as Flatpak or Snap.

[1]: https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.FileTransfer.html
2025-12-10 13:02:41 +01:00
Camilla Löwy
dbadda2683 Formatting 2025-12-05 13:33:10 +01:00
Camilla Löwy
08449b7183 Linux: Add missing header for ioctl
Fixes #2778
2025-12-04 20:30:12 +01:00
Camilla Löwy
1ce855b0b1 Wayland: Fix missing checks for optional protocol 2025-12-04 20:30:12 +01:00
Camilla Löwy
ebff6606ee Simplify test for shared library build 2025-11-17 22:57:23 +01:00
Doug Binks
162896e5b9
Wayland: free modules at end of terminate function
- Fixes #2744
2025-11-14 16:35:47 +00:00
13 changed files with 387 additions and 42 deletions

View File

@ -21,7 +21,7 @@ jobs:
- name: Install dependencies
run: |
sudo apt update
sudo apt install libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libxext-dev libwayland-dev libxkbcommon-dev
sudo apt install libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libxext-dev libwayland-dev libxkbcommon-dev libdbus-1-dev
- name: Configure Null shared library
run: cmake -B build-null-shared -D GLFW_BUILD_WAYLAND=OFF -D GLFW_BUILD_X11=OFF -D BUILD_SHARED_LIBS=ON

View File

@ -38,11 +38,7 @@ set(GLFW_LIBRARY_TYPE "${GLFW_LIBRARY_TYPE}" CACHE STRING
"Library type override for GLFW (SHARED, STATIC, OBJECT, or empty to follow BUILD_SHARED_LIBS)")
if (GLFW_LIBRARY_TYPE)
if (GLFW_LIBRARY_TYPE STREQUAL "SHARED")
set(GLFW_BUILD_SHARED_LIBRARY TRUE)
else()
set(GLFW_BUILD_SHARED_LIBRARY FALSE)
endif()
string(COMPARE EQUAL "${GLFW_LIBRARY_TYPE}" "SHARED" GLFW_BUILD_SHARED_LIBRARY)
else()
set(GLFW_BUILD_SHARED_LIBRARY ${BUILD_SHARED_LIBS})
endif()

View File

@ -162,6 +162,7 @@ video tutorials.
- Marcel Metz
- Liam Middlebrook
- mightgoyardstill
- Mihail
- Ave Milia
- Icyllis Milica
- Jonathan Miller

View File

@ -144,11 +144,17 @@ information on what to include when reporting a bug.
a modal to a fallback decoration
- [Wayland] Bugfix: The cursor position was not updated when clicking through
from a modal to the content area
- [Wayland] Bugfix: free modules at end of terminate function to resolve
potential segmentation fault (#2744)
- [Wayland] Bugfix: Confining or disabling the cursor could segfault on
compositors without `pointer-constraints-unstable-v1`
- [Wayland]: Add support for dropping files when sandboxed
- [X11] Bugfix: Running without a WM could trigger an assert (#2593,#2601,#2631)
- [X11] Bugfix: Occasional crash when an idle display awakes (#2766)
- [X11] Bugfix: Prevent BadWindow when creating small windows with a content scale
less than 1 (#2754)
- [X11] Bugfix: Clamp width and height to >= 1 to prevent BadValue error and app exit
- [Linux] Bugfix: The header for `ioctl` was only implicitly included (#2778)
- [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
@ -169,4 +175,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

@ -161,6 +161,8 @@ if (GLFW_BUILD_WAYLAND)
wayland-egl>=0.2.7
xkbcommon>=0.5.0)
set(DBUS_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})
target_include_directories(glfw PRIVATE ${Wayland_INCLUDE_DIRS})
if (NOT CMAKE_SYSTEM_NAME STREQUAL "Linux")

View File

@ -555,7 +555,8 @@ void _glfwTerminateEGL(void)
_glfw.egl.display = EGL_NO_DISPLAY;
}
if (_glfw.egl.handle)
// Free modules only after all wayland termination functions are called
if (_glfw.egl.handle && _glfw.platform.platformID != GLFW_PLATFORM_WAYLAND)
{
_glfwPlatformFreeModule(_glfw.egl.handle);
_glfw.egl.handle = NULL;

View File

@ -32,6 +32,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/inotify.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>

View File

@ -528,7 +528,8 @@ void _glfwUpdateKeyNamesWin32(void)
if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_ADD)
{
const UINT vks[] = {
const UINT vks[] =
{
VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3,
VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
VK_NUMPAD8, VK_NUMPAD9, VK_DECIMAL, VK_DIVIDE,

View File

@ -829,6 +829,73 @@ int _glfwInitWayland(void)
}
}
_glfw.wl.dbus.handle = _glfwPlatformLoadModule("libdbus-1.so.3");
if (_glfw.wl.dbus.handle)
{
_glfw.wl.dbus.dbus_error_init_ = (PFN_dbus_error_init)
_glfwPlatformGetModuleSymbol(_glfw.wl.dbus.handle, "dbus_error_init");
_glfw.wl.dbus.dbus_error_free_ = (PFN_dbus_error_free)
_glfwPlatformGetModuleSymbol(_glfw.wl.dbus.handle, "dbus_error_free");
_glfw.wl.dbus.dbus_error_is_set_ = (PFN_dbus_error_is_set)
_glfwPlatformGetModuleSymbol(_glfw.wl.dbus.handle, "dbus_error_is_set");
_glfw.wl.dbus.dbus_bus_get_ = (PFN_dbus_bus_get)
_glfwPlatformGetModuleSymbol(_glfw.wl.dbus.handle, "dbus_bus_get");
_glfw.wl.dbus.dbus_connection_set_exit_on_disconnect_ = (PFN_dbus_connection_set_exit_on_disconnect)
_glfwPlatformGetModuleSymbol(_glfw.wl.dbus.handle, "dbus_connection_set_exit_on_disconnect");
_glfw.wl.dbus.dbus_connection_send_with_reply_and_block_ = (PFN_dbus_connection_send_with_reply_and_block)
_glfwPlatformGetModuleSymbol(_glfw.wl.dbus.handle, "dbus_connection_send_with_reply_and_block");
_glfw.wl.dbus.dbus_message_new_method_call_ = (PFN_dbus_message_new_method_call)
_glfwPlatformGetModuleSymbol(_glfw.wl.dbus.handle, "dbus_message_new_method_call");
_glfw.wl.dbus.dbus_message_unref_ = (PFN_dbus_message_unref)
_glfwPlatformGetModuleSymbol(_glfw.wl.dbus.handle, "dbus_message_unref");
_glfw.wl.dbus.dbus_message_iter_init_ = (PFN_dbus_message_iter_init)
_glfwPlatformGetModuleSymbol(_glfw.wl.dbus.handle, "dbus_message_iter_init");
_glfw.wl.dbus.dbus_message_iter_init_append_ = (PFN_dbus_message_iter_init_append)
_glfwPlatformGetModuleSymbol(_glfw.wl.dbus.handle, "dbus_message_iter_init_append");
_glfw.wl.dbus.dbus_message_iter_append_basic_ = (PFN_dbus_message_iter_append_basic)
_glfwPlatformGetModuleSymbol(_glfw.wl.dbus.handle, "dbus_message_iter_append_basic");
_glfw.wl.dbus.dbus_message_iter_open_container_ = (PFN_dbus_message_iter_open_container)
_glfwPlatformGetModuleSymbol(_glfw.wl.dbus.handle, "dbus_message_iter_open_container");
_glfw.wl.dbus.dbus_message_iter_close_container_ = (PFN_dbus_message_iter_close_container)
_glfwPlatformGetModuleSymbol(_glfw.wl.dbus.handle, "dbus_message_iter_close_container");
_glfw.wl.dbus.dbus_message_iter_get_arg_type_ = (PFN_dbus_message_iter_get_arg_type)
_glfwPlatformGetModuleSymbol(_glfw.wl.dbus.handle, "dbus_message_iter_get_arg_type");
_glfw.wl.dbus.dbus_message_iter_get_element_type_ = (PFN_dbus_message_iter_get_element_type)
_glfwPlatformGetModuleSymbol(_glfw.wl.dbus.handle, "dbus_message_iter_get_element_type");
_glfw.wl.dbus.dbus_message_iter_recurse_ = (PFN_dbus_message_iter_recurse)
_glfwPlatformGetModuleSymbol(_glfw.wl.dbus.handle, "dbus_message_iter_recurse");
_glfw.wl.dbus.dbus_message_iter_get_element_count_ = (PFN_dbus_message_iter_get_element_count)
_glfwPlatformGetModuleSymbol(_glfw.wl.dbus.handle, "dbus_message_iter_get_element_count");
_glfw.wl.dbus.dbus_message_iter_get_basic_ = (PFN_dbus_message_iter_get_basic)
_glfwPlatformGetModuleSymbol(_glfw.wl.dbus.handle, "dbus_message_iter_get_basic");
_glfw.wl.dbus.dbus_message_iter_next_ = (PFN_dbus_message_iter_next)
_glfwPlatformGetModuleSymbol(_glfw.wl.dbus.handle, "dbus_message_iter_next");
if (!_glfw.wl.dbus.dbus_error_init_ ||
!_glfw.wl.dbus.dbus_error_free_ ||
!_glfw.wl.dbus.dbus_error_is_set_ ||
!_glfw.wl.dbus.dbus_bus_get_ ||
!_glfw.wl.dbus.dbus_connection_set_exit_on_disconnect_ ||
!_glfw.wl.dbus.dbus_connection_send_with_reply_and_block_ ||
!_glfw.wl.dbus.dbus_message_new_method_call_ ||
!_glfw.wl.dbus.dbus_message_unref_ ||
!_glfw.wl.dbus.dbus_message_iter_init_ ||
!_glfw.wl.dbus.dbus_message_iter_init_append_ ||
!_glfw.wl.dbus.dbus_message_iter_append_basic_ ||
!_glfw.wl.dbus.dbus_message_iter_open_container_ ||
!_glfw.wl.dbus.dbus_message_iter_close_container_ ||
!_glfw.wl.dbus.dbus_message_iter_get_arg_type_ ||
!_glfw.wl.dbus.dbus_message_iter_get_element_type_ ||
!_glfw.wl.dbus.dbus_message_iter_recurse_ ||
!_glfw.wl.dbus.dbus_message_iter_get_element_count_ ||
!_glfw.wl.dbus.dbus_message_iter_get_basic_ ||
!_glfw.wl.dbus.dbus_message_iter_next_)
{
_glfwPlatformFreeModule(_glfw.wl.dbus.handle);
memset(&_glfw.wl.dbus, 0, sizeof(_glfw.wl.dbus));
}
}
_glfw.wl.registry = wl_display_get_registry(_glfw.wl.display);
wl_registry_add_listener(_glfw.wl.registry, &registryListener, NULL);
@ -907,18 +974,6 @@ void _glfwTerminateWayland(void)
libdecor_unref(_glfw.wl.libdecor.context);
}
if (_glfw.wl.libdecor.handle)
{
_glfwPlatformFreeModule(_glfw.wl.libdecor.handle);
_glfw.wl.libdecor.handle = NULL;
}
if (_glfw.wl.egl.handle)
{
_glfwPlatformFreeModule(_glfw.wl.egl.handle);
_glfw.wl.egl.handle = NULL;
}
if (_glfw.wl.xkb.composeState)
xkb_compose_state_unref(_glfw.wl.xkb.composeState);
if (_glfw.wl.xkb.keymap)
@ -927,21 +982,11 @@ void _glfwTerminateWayland(void)
xkb_state_unref(_glfw.wl.xkb.state);
if (_glfw.wl.xkb.context)
xkb_context_unref(_glfw.wl.xkb.context);
if (_glfw.wl.xkb.handle)
{
_glfwPlatformFreeModule(_glfw.wl.xkb.handle);
_glfw.wl.xkb.handle = NULL;
}
if (_glfw.wl.cursorTheme)
wl_cursor_theme_destroy(_glfw.wl.cursorTheme);
if (_glfw.wl.cursorThemeHiDPI)
wl_cursor_theme_destroy(_glfw.wl.cursorThemeHiDPI);
if (_glfw.wl.cursor.handle)
{
_glfwPlatformFreeModule(_glfw.wl.cursor.handle);
_glfw.wl.cursor.handle = NULL;
}
for (unsigned int i = 0; i < _glfw.wl.offerCount; i++)
wl_data_offer_destroy(_glfw.wl.offers[i].offer);
@ -1001,6 +1046,38 @@ void _glfwTerminateWayland(void)
if (_glfw.wl.cursorTimerfd >= 0)
close(_glfw.wl.cursorTimerfd);
// Free modules only after all Wayland termination functions are called
if (_glfw.egl.handle)
{
_glfwPlatformFreeModule(_glfw.egl.handle);
_glfw.egl.handle = NULL;
}
if (_glfw.wl.libdecor.handle)
{
_glfwPlatformFreeModule(_glfw.wl.libdecor.handle);
_glfw.wl.libdecor.handle = NULL;
}
if (_glfw.wl.egl.handle)
{
_glfwPlatformFreeModule(_glfw.wl.egl.handle);
_glfw.wl.egl.handle = NULL;
}
if (_glfw.wl.xkb.handle)
{
_glfwPlatformFreeModule(_glfw.wl.xkb.handle);
_glfw.wl.xkb.handle = NULL;
}
if (_glfw.wl.cursor.handle)
{
_glfwPlatformFreeModule(_glfw.wl.cursor.handle);
_glfw.wl.cursor.handle = NULL;
}
_glfw_free(_glfw.wl.clipboardString);
}

View File

@ -136,18 +136,22 @@ struct wl_output;
#define GLFW_WAYLAND_MONITOR_STATE _GLFWmonitorWayland wl;
#define GLFW_WAYLAND_CURSOR_STATE _GLFWcursorWayland wl;
struct wl_cursor_image {
struct wl_cursor_image
{
uint32_t width;
uint32_t height;
uint32_t hotspot_x;
uint32_t hotspot_y;
uint32_t delay;
};
struct wl_cursor {
struct wl_cursor
{
unsigned int image_count;
struct wl_cursor_image** images;
char* name;
};
typedef struct wl_cursor_theme* (* PFN_wl_cursor_theme_load)(const char*, int, struct wl_shm*);
typedef void (* PFN_wl_cursor_theme_destroy)(struct wl_cursor_theme*);
typedef struct wl_cursor* (* PFN_wl_cursor_theme_get_cursor)(struct wl_cursor_theme*, const char*);
@ -326,6 +330,97 @@ typedef void (* PFN_libdecor_state_free)(struct libdecor_state*);
#define libdecor_state_new _glfw.wl.libdecor.libdecor_state_new_
#define libdecor_state_free _glfw.wl.libdecor.libdecor_state_free_
#define DBUS_FALSE 0
#define DBUS_TYPE_STRING ((int) 's')
#define DBUS_TYPE_ARRAY ((int) 'a')
#define DBUS_TIMEOUT_INFINITE ((int) 0x7fffffff)
typedef uint32_t dbus_bool_t;
typedef struct DBusError
{
const char *name;
const char *message;
unsigned int dummy1 : 1;
unsigned int dummy2 : 1;
unsigned int dummy3 : 1;
unsigned int dummy4 : 1;
unsigned int dummy5 : 1;
void *padding1;
} DBusError;
typedef struct DBusConnection DBusConnection;
typedef enum DBusBusType
{
DBUS_BUS_SESSION,
DBUS_BUS_SYSTEM,
DBUS_BUS_STARTER,
} DBusBusType;
typedef struct DBusMessage DBusMessage;
typedef struct DBusMessageIter
{
#if DBUS_SIZEOF_VOID_P > 8
void *dummy[16];
#else
void *dummy1;
void *dummy2;
uint32_t dummy3;
int dummy4;
int dummy5;
int dummy6;
int dummy7;
int dummy8;
int dummy9;
int dummy10;
int dummy11;
int pad1;
void *pad2;
void *pad3;
#endif
} DBusMessageIter;
typedef void (* PFN_dbus_error_init) (DBusError*);
typedef void (* PFN_dbus_error_free) (DBusError*);
typedef dbus_bool_t (* PFN_dbus_error_is_set) (const DBusError*);
typedef DBusConnection* (* PFN_dbus_bus_get) (enum DBusBusType, DBusError*);
typedef void (* PFN_dbus_connection_set_exit_on_disconnect) (DBusConnection*, dbus_bool_t);
typedef DBusMessage* (* PFN_dbus_connection_send_with_reply_and_block) (DBusConnection*, DBusMessage*, int, DBusError*);
typedef DBusMessage* (* PFN_dbus_message_new_method_call) (const char*, const char*, const char*, const char*);
typedef void (* PFN_dbus_message_unref) (DBusMessage*);
typedef dbus_bool_t (* PFN_dbus_message_iter_init) (DBusMessage*, DBusMessageIter*);
typedef void (* PFN_dbus_message_iter_init_append) (DBusMessage*, DBusMessageIter*);
typedef dbus_bool_t (* PFN_dbus_message_iter_append_basic) (DBusMessageIter*, int, const void*);
typedef dbus_bool_t (* PFN_dbus_message_iter_open_container) (DBusMessageIter*, int, const char*, DBusMessageIter*);
typedef dbus_bool_t (* PFN_dbus_message_iter_close_container) (DBusMessageIter*, DBusMessageIter*);
typedef int (* PFN_dbus_message_iter_get_arg_type) (DBusMessageIter*);
typedef int (* PFN_dbus_message_iter_get_element_type) (DBusMessageIter*);
typedef void (* PFN_dbus_message_iter_recurse) (DBusMessageIter*, DBusMessageIter*);
typedef int (* PFN_dbus_message_iter_get_element_count) (DBusMessageIter*);
typedef void (* PFN_dbus_message_iter_get_basic) (DBusMessageIter*, void*);
typedef dbus_bool_t (* PFN_dbus_message_iter_next) (DBusMessageIter*);
#define dbus_error_init _glfw.wl.dbus.dbus_error_init_
#define dbus_error_free _glfw.wl.dbus.dbus_error_free_
#define dbus_error_is_set _glfw.wl.dbus.dbus_error_is_set_
#define dbus_bus_get _glfw.wl.dbus.dbus_bus_get_
#define dbus_connection_set_exit_on_disconnect _glfw.wl.dbus.dbus_connection_set_exit_on_disconnect_
#define dbus_connection_send_with_reply_and_block _glfw.wl.dbus.dbus_connection_send_with_reply_and_block_
#define dbus_message_new_method_call _glfw.wl.dbus.dbus_message_new_method_call_
#define dbus_message_unref _glfw.wl.dbus.dbus_message_unref_
#define dbus_message_iter_init _glfw.wl.dbus.dbus_message_iter_init_
#define dbus_message_iter_init_append _glfw.wl.dbus.dbus_message_iter_init_append_
#define dbus_message_iter_append_basic _glfw.wl.dbus.dbus_message_iter_append_basic_
#define dbus_message_iter_open_container _glfw.wl.dbus.dbus_message_iter_open_container_
#define dbus_message_iter_close_container _glfw.wl.dbus.dbus_message_iter_close_container_
#define dbus_message_iter_get_arg_type _glfw.wl.dbus.dbus_message_iter_get_arg_type_
#define dbus_message_iter_get_element_type _glfw.wl.dbus.dbus_message_iter_get_element_type_
#define dbus_message_iter_recurse _glfw.wl.dbus.dbus_message_iter_recurse_
#define dbus_message_iter_get_element_count _glfw.wl.dbus.dbus_message_iter_get_element_count_
#define dbus_message_iter_get_basic _glfw.wl.dbus.dbus_message_iter_get_basic_
#define dbus_message_iter_next _glfw.wl.dbus.dbus_message_iter_next_
typedef struct _GLFWfallbackEdgeWayland
{
struct wl_surface* surface;
@ -338,6 +433,7 @@ typedef struct _GLFWofferWayland
struct wl_data_offer* offer;
GLFWbool text_plain_utf8;
GLFWbool text_uri_list;
GLFWbool portal_file_transfer;
} _GLFWofferWayland;
typedef struct _GLFWscaleWayland
@ -450,6 +546,7 @@ typedef struct _GLFWlibraryWayland
struct wl_data_offer* dragOffer;
_GLFWwindow* dragFocus;
uint32_t dragSerial;
GLFWbool dragUsePortal;
const char* tag;
@ -585,6 +682,29 @@ typedef struct _GLFWlibraryWayland
PFN_libdecor_state_new libdecor_state_new_;
PFN_libdecor_state_free libdecor_state_free_;
} libdecor;
struct {
void* handle;
PFN_dbus_error_init dbus_error_init_;
PFN_dbus_error_free dbus_error_free_;
PFN_dbus_error_is_set dbus_error_is_set_;
PFN_dbus_bus_get dbus_bus_get_;
PFN_dbus_connection_set_exit_on_disconnect dbus_connection_set_exit_on_disconnect_;
PFN_dbus_connection_send_with_reply_and_block dbus_connection_send_with_reply_and_block_;
PFN_dbus_message_new_method_call dbus_message_new_method_call_;
PFN_dbus_message_unref dbus_message_unref_;
PFN_dbus_message_iter_init dbus_message_iter_init_;
PFN_dbus_message_iter_init_append dbus_message_iter_init_append_;
PFN_dbus_message_iter_append_basic dbus_message_iter_append_basic_;
PFN_dbus_message_iter_open_container dbus_message_iter_open_container_;
PFN_dbus_message_iter_close_container dbus_message_iter_close_container_;
PFN_dbus_message_iter_get_arg_type dbus_message_iter_get_arg_type_;
PFN_dbus_message_iter_get_element_type dbus_message_iter_get_element_type_;
PFN_dbus_message_iter_recurse dbus_message_iter_recurse_;
PFN_dbus_message_iter_get_element_count dbus_message_iter_get_element_count_;
PFN_dbus_message_iter_get_basic dbus_message_iter_get_basic_;
PFN_dbus_message_iter_next dbus_message_iter_next_;
} dbus;
} _GLFWlibraryWayland;
// Wayland-specific per-monitor data

View File

@ -54,6 +54,7 @@
#define GLFW_BORDER_SIZE 4
#define GLFW_CAPTION_HEIGHT 24
#define FILE_TRANSFER_PORTAL_MIME_TYPE "application/vnd.portal.filetransfer"
static int createTmpfileCloexec(char* tmpname)
{
@ -1413,7 +1414,7 @@ static void handleEvents(double* timeout)
if (read(_glfw.wl.keyRepeatTimerfd, &repeats, sizeof(repeats)) == 8)
{
if(_glfw.wl.keyboardFocus)
if (_glfw.wl.keyboardFocus)
{
for (uint64_t i = 0; i < repeats; i++)
{
@ -1692,7 +1693,8 @@ static void keyboardHandleKeymap(void* userData,
}
mapStr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
if (mapStr == MAP_FAILED) {
if (mapStr == MAP_FAILED)
{
close(fd);
return;
}
@ -1838,7 +1840,9 @@ static void keyboardHandleKey(void* userData,
timer.it_value.tv_nsec = (_glfw.wl.keyRepeatDelay % 1000) * 1000000;
timerfd_settime(_glfw.wl.keyRepeatTimerfd, 0, &timer, NULL);
}
} else if (scancode == _glfw.wl.keyRepeatScancode) {
}
else if (scancode == _glfw.wl.keyRepeatScancode)
{
timerfd_settime(_glfw.wl.keyRepeatTimerfd, 0, &timer, NULL);
}
@ -1969,6 +1973,8 @@ static void dataOfferHandleOffer(void* userData,
_glfw.wl.offers[i].text_plain_utf8 = GLFW_TRUE;
else if (strcmp(mimeType, "text/uri-list") == 0)
_glfw.wl.offers[i].text_uri_list = GLFW_TRUE;
else if (strcmp(mimeType, FILE_TRANSFER_PORTAL_MIME_TYPE) == 0)
_glfw.wl.offers[i].portal_file_transfer = GLFW_TRUE;
break;
}
@ -2031,13 +2037,19 @@ static void dataDeviceHandleEnter(void* userData,
_GLFWwindow* window = wl_surface_get_user_data(surface);
if (window->wl.surface == surface)
{
if (_glfw.wl.offers[i].text_uri_list)
GLFWbool portal = _glfw.wl.offers[i].portal_file_transfer && _glfw.wl.dbus.handle;
if (_glfw.wl.offers[i].text_uri_list || portal)
{
_glfw.wl.dragOffer = offer;
_glfw.wl.dragFocus = window;
_glfw.wl.dragSerial = serial;
_glfw.wl.dragUsePortal = portal;
wl_data_offer_accept(offer, serial, "text/uri-list");
if (portal) {
wl_data_offer_accept(offer, serial, FILE_TRANSFER_PORTAL_MIME_TYPE);
} else {
wl_data_offer_accept(offer, serial, "text/uri-list");
}
}
}
}
@ -2071,12 +2083,128 @@ static void dataDeviceHandleMotion(void* userData,
{
}
// Receives a dropped file that was sent using the
// [File Transfer](https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.FileTransfer.html) portal.
// This enables us to receive files when running as a Flatpak or Snap.
static void dataDeviceHandleFileTransferPortalDrop(void* userData,
struct wl_data_device* device)
{
assert(_glfw.wl.dbus.handle != NULL);
char* key = readDataOfferAsString(_glfw.wl.dragOffer, FILE_TRANSFER_PORTAL_MIME_TYPE);
if (!key)
return;
DBusError error;
dbus_error_init(&error);
DBusConnection* connection = dbus_bus_get(DBUS_BUS_SESSION, &error);
if (dbus_error_is_set(&error))
{
_glfwInputError(GLFW_PLATFORM_ERROR, "DBus: %s", error.message);
dbus_error_free(&error);
_glfw_free(key);
return;
}
dbus_connection_set_exit_on_disconnect(connection, DBUS_FALSE);
DBusMessage* message = dbus_message_new_method_call(
"org.freedesktop.portal.Documents",
"/org/freedesktop/portal/documents",
"org.freedesktop.portal.FileTransfer",
"RetrieveFiles"
);
if (!message)
{
_glfwInputError(GLFW_OUT_OF_MEMORY, NULL);
_glfw_free(key);
return;
}
DBusMessageIter args, options;
dbus_message_iter_init_append(message, &args);
if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &key))
{
_glfwInputError(GLFW_OUT_OF_MEMORY, NULL);
dbus_message_unref(message);
_glfw_free(key);
return;
}
if (!dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{sv}", &options))
{
_glfwInputError(GLFW_OUT_OF_MEMORY, NULL);
dbus_message_unref(message);
_glfw_free(key);
return;
}
if (!dbus_message_iter_close_container(&args, &options))
{
_glfwInputError(GLFW_OUT_OF_MEMORY, NULL);
dbus_message_unref(message);
_glfw_free(key);
return;
}
DBusMessage* reply = dbus_connection_send_with_reply_and_block(connection, message, DBUS_TIMEOUT_INFINITE, &error);
if (dbus_error_is_set(&error))
{
_glfwInputError(GLFW_PLATFORM_ERROR, "DBus: %s", error.message);
dbus_error_free(&error);
dbus_message_unref(message);
_glfw_free(key);
return;
}
DBusMessageIter out, array;
if (!dbus_message_iter_init(reply, &out))
{
_glfwInputError(GLFW_OUT_OF_MEMORY, NULL);
dbus_message_unref(reply);
dbus_message_unref(message);
_glfw_free(key);
return;
}
if (dbus_message_iter_get_arg_type(&out) != DBUS_TYPE_ARRAY
|| dbus_message_iter_get_element_type(&out) != DBUS_TYPE_STRING) {
_glfwInputError(GLFW_PLATFORM_ERROR, "DBus: Reply is not an array of strings");
dbus_message_unref(reply);
dbus_message_unref(message);
_glfw_free(key);
return;
}
dbus_message_iter_recurse(&out, &array);
int elements = dbus_message_iter_get_element_count(&out);
char** paths = _glfw_calloc(elements, sizeof(char*));
if (!paths) {
_glfwInputError(GLFW_OUT_OF_MEMORY, NULL);
dbus_message_unref(reply);
dbus_message_unref(message);
_glfw_free(key);
return;
}
int i = 0;
do {
dbus_message_iter_get_basic(&array, &paths[i++]);
} while (dbus_message_iter_next(&array));
_glfwInputDrop(_glfw.wl.dragFocus, elements, (const char**) paths);
_glfw_free(paths);
dbus_message_unref(reply);
dbus_message_unref(message);
_glfw_free(key);
}
static void dataDeviceHandleDrop(void* userData,
struct wl_data_device* device)
{
if (!_glfw.wl.dragOffer)
return;
if (_glfw.wl.dragUsePortal)
{
dataDeviceHandleFileTransferPortalDrop(userData, device);
return;
}
char* string = readDataOfferAsString(_glfw.wl.dragOffer, "text/uri-list");
if (string)
{
@ -2974,10 +3102,16 @@ static void lockPointer(_GLFWwindow* window)
if (!_glfw.wl.relativePointerManager)
{
_glfwInputError(GLFW_FEATURE_UNAVAILABLE,
"Wayland: The compositor does not support pointer locking");
"Wayland: The compositor does not support relative pointer motion");
return;
}
if (!_glfw.wl.pointerConstraints)
{
_glfwInputError(GLFW_FEATURE_UNAVAILABLE,
"Wayland: The compositor does not support locking the pointer");
}
window->wl.relativePointer =
zwp_relative_pointer_manager_v1_get_relative_pointer(
_glfw.wl.relativePointerManager,
@ -3025,6 +3159,12 @@ static const struct zwp_confined_pointer_v1_listener confinedPointerListener =
static void confinePointer(_GLFWwindow* window)
{
if (!_glfw.wl.pointerConstraints)
{
_glfwInputError(GLFW_FEATURE_UNAVAILABLE,
"Wayland: The compositor does not support confining the pointer");
}
window->wl.confinedPointer =
zwp_pointer_constraints_v1_confine_pointer(
_glfw.wl.pointerConstraints,

View File

@ -151,7 +151,8 @@ void _glfwPollMonitorsX11(void)
}
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc);
if (!ci) {
if (!ci)
{
XRRFreeOutputInfo(oi);
continue;
}

View File

@ -2207,10 +2207,10 @@ void _glfwGetWindowSizeX11(_GLFWwindow* window, int* width, int* height)
void _glfwSetWindowSizeX11(_GLFWwindow* window, int width, int height)
{
// The dimensions must be nonzero, or a BadValue error results.
// The dimensions must be nonzero, or a BadValue error results
width = _glfw_max(1, width);
height = _glfw_max(1, height);
if (window->monitor)
{
if (window->monitor->window == window)