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
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt update
|
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
|
- 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
|
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
|
a modal to a fallback decoration
|
||||||
- [Wayland] Bugfix: The cursor position was not updated when clicking through
|
- [Wayland] Bugfix: The cursor position was not updated when clicking through
|
||||||
from a modal to the content area
|
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)
|
- [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 Vulkan 'window' surface creation via `VK_EXT_headless_surface`
|
||||||
- [Null] Added EGL context creation on Mesa via `EGL_MESA_platform_surfaceless`
|
- [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
|
wayland-egl>=0.2.7
|
||||||
xkbcommon>=0.5.0)
|
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})
|
target_include_directories(glfw PRIVATE ${Wayland_INCLUDE_DIRS})
|
||||||
|
|
||||||
if (NOT CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
if (NOT CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
|
@ -338,6 +338,7 @@ typedef struct _GLFWofferWayland
|
|||||||
struct wl_data_offer* offer;
|
struct wl_data_offer* offer;
|
||||||
GLFWbool text_plain_utf8;
|
GLFWbool text_plain_utf8;
|
||||||
GLFWbool text_uri_list;
|
GLFWbool text_uri_list;
|
||||||
|
GLFWbool portal_file_transfer;
|
||||||
} _GLFWofferWayland;
|
} _GLFWofferWayland;
|
||||||
|
|
||||||
typedef struct _GLFWscaleWayland
|
typedef struct _GLFWscaleWayland
|
||||||
@ -450,6 +451,7 @@ typedef struct _GLFWlibraryWayland
|
|||||||
struct wl_data_offer* dragOffer;
|
struct wl_data_offer* dragOffer;
|
||||||
_GLFWwindow* dragFocus;
|
_GLFWwindow* dragFocus;
|
||||||
uint32_t dragSerial;
|
uint32_t dragSerial;
|
||||||
|
GLFWbool dragUsePortal;
|
||||||
|
|
||||||
const char* tag;
|
const char* tag;
|
||||||
|
|
||||||
|
128
src/wl_window.c
128
src/wl_window.c
@ -41,6 +41,7 @@
|
|||||||
#include <sys/timerfd.h>
|
#include <sys/timerfd.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <linux/input-event-codes.h>
|
#include <linux/input-event-codes.h>
|
||||||
|
#include <dbus/dbus.h>
|
||||||
|
|
||||||
#include "wayland-client-protocol.h"
|
#include "wayland-client-protocol.h"
|
||||||
#include "xdg-shell-client-protocol.h"
|
#include "xdg-shell-client-protocol.h"
|
||||||
@ -54,6 +55,7 @@
|
|||||||
|
|
||||||
#define GLFW_BORDER_SIZE 4
|
#define GLFW_BORDER_SIZE 4
|
||||||
#define GLFW_CAPTION_HEIGHT 24
|
#define GLFW_CAPTION_HEIGHT 24
|
||||||
|
#define FILE_TRANSFER_PORTAL_MIME_TYPE "application/vnd.portal.filetransfer"
|
||||||
|
|
||||||
static int createTmpfileCloexec(char* tmpname)
|
static int createTmpfileCloexec(char* tmpname)
|
||||||
{
|
{
|
||||||
@ -1969,6 +1971,8 @@ static void dataOfferHandleOffer(void* userData,
|
|||||||
_glfw.wl.offers[i].text_plain_utf8 = GLFW_TRUE;
|
_glfw.wl.offers[i].text_plain_utf8 = GLFW_TRUE;
|
||||||
else if (strcmp(mimeType, "text/uri-list") == 0)
|
else if (strcmp(mimeType, "text/uri-list") == 0)
|
||||||
_glfw.wl.offers[i].text_uri_list = GLFW_TRUE;
|
_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;
|
break;
|
||||||
}
|
}
|
||||||
@ -2031,13 +2035,19 @@ static void dataDeviceHandleEnter(void* userData,
|
|||||||
_GLFWwindow* window = wl_surface_get_user_data(surface);
|
_GLFWwindow* window = wl_surface_get_user_data(surface);
|
||||||
if (window->wl.surface == 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.dragOffer = offer;
|
||||||
_glfw.wl.dragFocus = window;
|
_glfw.wl.dragFocus = window;
|
||||||
_glfw.wl.dragSerial = serial;
|
_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 +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,
|
static void dataDeviceHandleDrop(void* userData,
|
||||||
struct wl_data_device* device)
|
struct wl_data_device* device)
|
||||||
{
|
{
|
||||||
if (!_glfw.wl.dragOffer)
|
if (!_glfw.wl.dragOffer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (_glfw.wl.dragUsePortal)
|
||||||
|
{
|
||||||
|
dataDeviceHandleFileTransferPortalDrop(userData, device);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
char* string = readDataOfferAsString(_glfw.wl.dragOffer, "text/uri-list");
|
char* string = readDataOfferAsString(_glfw.wl.dragOffer, "text/uri-list");
|
||||||
if (string)
|
if (string)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user