Просмотр исходного кода

dbus: Use OpenFile for opening local 'file://' URIs

Per the spec, OpenURI can't open local paths, so OpenFile needs to be used instead.
Frank Praznik 2 дней назад
Родитель
Сommit
0a54fdb862
1 измененных файлов с 39 добавлено и 9 удалено
  1. 39 9
      src/core/linux/SDL_dbus.c

+ 39 - 9
src/core/linux/SDL_dbus.c

@@ -22,6 +22,9 @@
 #include "SDL_dbus.h"
 #include "../../stdlib/SDL_vacopy.h"
 
+#include <fcntl.h>
+#include <unistd.h>
+
 #ifdef SDL_USE_LIBDBUS
 // we never link directly to libdbus.
 #define SDL_DRIVER_DBUS_DYNAMIC "libdbus-1.so.3"
@@ -473,11 +476,9 @@ static bool SDL_DBus_AppendDictWithKeyValue(DBusMessageIter *iterInit, const cha
 
 bool SDL_DBus_OpenURI(const char *uri, const char *window_id, const char *activation_token)
 {
-    const char *bus_name = "org.freedesktop.portal.Desktop";
-    const char *path = "/org/freedesktop/portal/desktop";
-    const char *interface = "org.freedesktop.portal.OpenURI";
-    DBusMessageIter iterInit;
-    bool ret = false;
+    static const char *bus_name = "org.freedesktop.portal.Desktop";
+    static const char *path = "/org/freedesktop/portal/desktop";
+    static const char *interface = "org.freedesktop.portal.OpenURI";
 
     if (!dbus.session_conn) {
         /* We either lost connection to the session bus or were not able to
@@ -486,19 +487,42 @@ bool SDL_DBus_OpenURI(const char *uri, const char *window_id, const char *activa
         return false;
     }
 
-    DBusMessage *msg = dbus.message_new_method_call(bus_name, path, interface, "OpenURI");
+    // The OpenURI method can't open local 'file://' URIs, so OpenFile must be used instead.
+    DBusMessageIter iterInit;
+    DBusMessage *msg = NULL;
+    int fd = -1;
+    bool ret = false;
+
+    if (SDL_strncasecmp(uri, "file://", 7) == 0) {
+        fd = open(uri + 7, O_RDWR | O_CLOEXEC);
+        if (fd >= 0) {
+            msg = dbus.message_new_method_call(bus_name, path, interface, "OpenFile");
+        }
+    } else {
+        msg = dbus.message_new_method_call(bus_name, path, interface, "OpenURI");
+    }
     if (!msg) {
-        return false;
+        goto done;
     }
 
+    dbus.message_iter_init_append(msg, &iterInit);
+
     if (!window_id) {
         window_id = "";
     }
-    if (!dbus.message_append_args(msg, DBUS_TYPE_STRING, &window_id, DBUS_TYPE_STRING, &uri, DBUS_TYPE_INVALID)) {
+    if (!dbus.message_iter_append_basic(&iterInit, DBUS_TYPE_STRING, &window_id)) {
         goto done;
     }
 
-    dbus.message_iter_init_append(msg, &iterInit);
+    if (fd >= 0) {
+        if (!dbus.message_iter_append_basic(&iterInit, DBUS_TYPE_UNIX_FD, &fd)) {
+            goto done;
+        }
+    } else {
+        if (!dbus.message_iter_append_basic(&iterInit, DBUS_TYPE_STRING, &uri)) {
+            goto done;
+        }
+    }
 
     if (activation_token) {
         if (!SDL_DBus_AppendDictWithKeyValue(&iterInit, "activation_token", activation_token)) {
@@ -525,6 +549,12 @@ bool SDL_DBus_OpenURI(const char *uri, const char *window_id, const char *activa
 
 done:
     dbus.message_unref(msg);
+
+    // The file descriptor is duplicated by D-Bus, so it can be closed on this end.
+    if (fd >= 0) {
+        close(fd);
+    }
+
     return ret;
 }