This commit is contained in:
Tau Gärtli 2025-12-10 12:04:30 +00:00 committed by GitHub
commit 3e05648c66
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 314 additions and 4 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

@ -148,6 +148,7 @@ information on what to include when reporting a bug.
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
@ -174,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

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

View File

@ -330,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;
@ -342,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
@ -454,6 +546,7 @@ typedef struct _GLFWlibraryWayland
struct wl_data_offer* dragOffer;
_GLFWwindow* dragFocus;
uint32_t dragSerial;
GLFWbool dragUsePortal;
const char* tag;
@ -589,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)
{
@ -1972,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;
}
@ -2034,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");
}
}
}
}
@ -2074,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)
{