mirror of
https://github.com/glfw/glfw.git
synced 2025-09-18 05:40:56 +00:00
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
This commit is contained in:
parent
63a7e8b7f8
commit
9af90886c8
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -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
|
||||
|
@ -143,6 +143,7 @@ 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]: Add support for dropping files when sandboxed
|
||||
- [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`
|
||||
|
@ -161,6 +161,10 @@ if (GLFW_BUILD_WAYLAND)
|
||||
wayland-egl>=0.2.7
|
||||
xkbcommon>=0.5.0)
|
||||
|
||||
pkg_check_modules(DBUS REQUIRED dbus-1)
|
||||
target_include_directories(glfw PRIVATE ${DBUS_INCLUDE_DIRS})
|
||||
target_link_libraries(glfw PRIVATE ${DBUS_LIBRARIES})
|
||||
|
||||
target_include_directories(glfw PRIVATE ${Wayland_INCLUDE_DIRS})
|
||||
|
||||
if (NOT CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
|
@ -338,6 +338,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 +451,7 @@ typedef struct _GLFWlibraryWayland
|
||||
struct wl_data_offer* dragOffer;
|
||||
_GLFWwindow* dragFocus;
|
||||
uint32_t dragSerial;
|
||||
GLFWbool dragUsePortal;
|
||||
|
||||
const char* tag;
|
||||
|
||||
|
126
src/wl_window.c
126
src/wl_window.c
@ -41,6 +41,7 @@
|
||||
#include <sys/timerfd.h>
|
||||
#include <poll.h>
|
||||
#include <linux/input-event-codes.h>
|
||||
#include <dbus/dbus.h>
|
||||
|
||||
#include "wayland-client-protocol.h"
|
||||
#include "xdg-shell-client-protocol.h"
|
||||
@ -54,6 +55,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)
|
||||
{
|
||||
@ -1969,6 +1971,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,16 +2035,22 @@ 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;
|
||||
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;
|
||||
|
||||
if (portal) {
|
||||
wl_data_offer_accept(offer, serial, FILE_TRANSFER_PORTAL_MIME_TYPE);
|
||||
} else {
|
||||
wl_data_offer_accept(offer, serial, "text/uri-list");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!_glfw.wl.dragOffer)
|
||||
{
|
||||
@ -2071,12 +2081,126 @@ 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)
|
||||
{
|
||||
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, 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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user