diff --git a/data/org.freedesktop.impl.portal.RemoteDesktop.xml b/data/org.freedesktop.impl.portal.RemoteDesktop.xml
index 0c6bdd609..e04c94141 100644
--- a/data/org.freedesktop.impl.portal.RemoteDesktop.xml
+++ b/data/org.freedesktop.impl.portal.RemoteDesktop.xml
@@ -81,6 +81,47 @@
Default is all.
+
+ restore_data (suv)
+
+ The data to restore from a previous session.
+
+
+ If the stored session cannot be restored, this value is ignored
+ and the user will be prompted normally. This may happen when, for
+ example, the session contains a monitor or a window that is not
+ available anymore, or when the stored permissions are withdrawn.
+
+
+ The restore data is composed of the vendor name (e.g. "GNOME" or
+ "KDE"), the version of the implementation-specific private data,
+ and the implementation-specific private data itself.
+
+
+ This option was added in version 2 of this interface.
+
+
+
+ persist_mode u
+
+ How this session should persist. Default is 0. Accepted values are:
+
+
+
+ 0: Do not persist (default)
+ 1: Permissions persist as long as the application is running
+ 2: Permissions persist until explicitly revoked
+
+
+
+ If the permission for the session to persist is granted, "restore_data"
+ will be returned via the #org.freedesktop.portal.Request::Response
+ signal of the #org.freedesktop.impl.portal.RemoteDesktop.Start method.
+
+
+ This option was added in version 2 of this interface.
+
+
For available device types, see the AvailableDeviceTypes property.
diff --git a/data/org.freedesktop.portal.RemoteDesktop.xml b/data/org.freedesktop.portal.RemoteDesktop.xml
index 9e1346f84..02b7466c6 100644
--- a/data/org.freedesktop.portal.RemoteDesktop.xml
+++ b/data/org.freedesktop.portal.RemoteDesktop.xml
@@ -109,6 +109,41 @@
Default is all.
+
+ restore_token s
+
+ The token to restore a previous session.
+
+ If the stored session cannot be restored, this value is ignored
+ and the user will be prompted normally. This may happen when, for
+ example, the session contains a monitor or a window that is not
+ available anymore, or when the stored permissions are withdrawn.
+
+ The restore token is invalidated after using it once. To restore
+ the same session again, use the new restore token sent in response
+ to starting this session.
+
+ This option was added in version 2 of this interface.
+
+
+
+ persist_mode u
+
+ How this session should persist. Default is 0. Accepted values are:
+
+
+ 0: Do not persist (default)
+ 1: Permissions persist as long as the application is running
+ 2: Permissions persist until explicitly revoked
+
+
+ If the permission for the session to persist is granted, a restore token will
+ be returned via the #org.freedesktop.portal.Request::Response signal of the
+ start method used to start the session.
+
+ This option was added in version 2 of this interface.
+
+
For available device types, see the AvailableDeviceTypes property.
@@ -159,6 +194,16 @@
Since version 2.
+
+ restore_token s
+
+ The restore token. This token is a single use token that can later
+ be used to restore a session. See
+ org.freedesktop.portal.RemoteDesktop.SelectDevices() for details.
+
+ This response option was added in version 2 of this interface.
+
+
If a screen cast source was selected, the results of the
diff --git a/data/org.freedesktop.portal.ScreenCast.xml b/data/org.freedesktop.portal.ScreenCast.xml
index 75309313a..3fc1d4e2f 100644
--- a/data/org.freedesktop.portal.ScreenCast.xml
+++ b/data/org.freedesktop.portal.ScreenCast.xml
@@ -133,6 +133,10 @@
the same session again, use the new restore token sent in response
to starting this session.
+ Setting a restore_token is only allowed for screen cast sessions.
+ Persistent remote desktop screen cast sessions can only be handled
+ via the #org.freedesktop.portal.RemoteDesktop interface.
+
This option was added in version 4 of this interface.
@@ -147,8 +151,9 @@
2: Permissions persist until explicitly revoked
- Remote desktop screen cast sessions cannot persist. The only allowed
- persist_mode for remote desktop sessions is 0.
+ Setting persist_mode is only allowed for screen cast sessions. Persistent
+ remote desktop screen cast sessions can only be handled via the
+ #org.freedesktop.portal.RemoteDesktop interface.
If the permission for the session to persist is granted, a restore token will
be returned via the #org.freedesktop.portal.Request::Response signal of the
diff --git a/src/remote-desktop.c b/src/remote-desktop.c
index 513ebf9b5..11b2a5c52 100644
--- a/src/remote-desktop.c
+++ b/src/remote-desktop.c
@@ -21,6 +21,7 @@
#include "remote-desktop.h"
#include "screen-cast.h"
#include "request.h"
+#include "restore-token.h"
#include "pipewire.h"
#include "call.h"
#include "session.h"
@@ -30,6 +31,8 @@
#include
+#define REMOTE_DESKTOP_TABLE "remote-desktop"
+
typedef struct _RemoteDesktop RemoteDesktop;
typedef struct _RemoteDesktopClass RemoteDesktopClass;
@@ -88,6 +91,10 @@ typedef struct _RemoteDesktopSession
gboolean sources_selected;
gboolean clipboard_enabled;
+
+ char *restore_token;
+ PersistMode persist_mode;
+ GVariant *restore_data;
} RemoteDesktopSession;
typedef struct _RemoteDesktopSessionClass
@@ -420,10 +427,75 @@ validate_device_types (const char *key,
return TRUE;
}
+static gboolean
+validate_restore_token (const char *key,
+ GVariant *value,
+ GVariant *options,
+ GError **error)
+{
+ const char *restore_token = g_variant_get_string (value, NULL);
+
+ if (!g_uuid_string_is_valid (restore_token))
+ {
+ g_set_error (error,
+ XDG_DESKTOP_PORTAL_ERROR,
+ XDG_DESKTOP_PORTAL_ERROR_INVALID_ARGUMENT,
+ "Restore token is not a valid UUID string");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+validate_persist_mode (const char *key,
+ GVariant *value,
+ GVariant *options,
+ GError **error)
+{
+ uint32_t mode = g_variant_get_uint32 (value);
+
+ if (mode > PERSIST_MODE_PERSISTENT)
+ {
+ g_set_error (error,
+ XDG_DESKTOP_PORTAL_ERROR,
+ XDG_DESKTOP_PORTAL_ERROR_INVALID_ARGUMENT,
+ "Invalid persist mode %x", mode);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static XdpOptionKey remote_desktop_select_devices_options[] = {
{ "types", G_VARIANT_TYPE_UINT32, validate_device_types },
+ { "restore_token", G_VARIANT_TYPE_STRING, validate_restore_token },
+ { "persist_mode", G_VARIANT_TYPE_UINT32, validate_persist_mode },
};
+static gboolean
+replace_remote_desktop_restore_token_with_data (Session *session,
+ GVariant **in_out_options,
+ GError **error)
+{
+ RemoteDesktopSession *remote_desktop_session = (RemoteDesktopSession *) session;
+ g_autoptr(GVariant) options = NULL;
+ PersistMode persist_mode;
+
+ options = *in_out_options;
+
+ if (!g_variant_lookup (options, "persist_mode", "u", &persist_mode))
+ persist_mode = PERSIST_MODE_NONE;
+
+ remote_desktop_session->persist_mode = persist_mode;
+ replace_restore_token_with_data (session,
+ REMOTE_DESKTOP_TABLE,
+ in_out_options,
+ &remote_desktop_session->restore_token);
+
+ return TRUE;
+}
+
static gboolean
handle_select_devices (XdpDbusRemoteDesktop *object,
GDBusMethodInvocation *invocation,
@@ -436,6 +508,7 @@ handle_select_devices (XdpDbusRemoteDesktop *object,
g_autoptr(GError) error = NULL;
g_autoptr(XdpDbusImplRequest) impl_request = NULL;
GVariantBuilder options_builder;
+ GVariant *options;
REQUEST_AUTOLOCK (request);
@@ -487,6 +560,18 @@ handle_select_devices (XdpDbusRemoteDesktop *object,
return G_DBUS_METHOD_INVOCATION_HANDLED;
}
+ options = g_variant_builder_end (&options_builder);
+
+ /* If 'restore_token' is passed, lookup the corresponding data in the
+ * permission store and / or the GHashTable with transient permissions.
+ * Portal implementations do not have access to the restore token.
+ */
+ if (!replace_remote_desktop_restore_token_with_data (session, &options, &error))
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ return G_DBUS_METHOD_INVOCATION_HANDLED;
+ }
+
g_object_set_qdata_full (G_OBJECT (request),
quark_request_session,
g_object_ref (session),
@@ -496,7 +581,7 @@ handle_select_devices (XdpDbusRemoteDesktop *object,
request->id,
arg_session_handle,
xdp_app_info_get_id (request->app_info),
- g_variant_builder_end (&options_builder),
+ options,
NULL,
select_devices_done,
g_object_ref (request));
@@ -506,12 +591,25 @@ handle_select_devices (XdpDbusRemoteDesktop *object,
return G_DBUS_METHOD_INVOCATION_HANDLED;
}
+static void
+replace_restore_remote_desktop_data_with_token (RemoteDesktopSession *remote_desktop_session,
+ GVariant **in_out_results)
+{
+ replace_restore_data_with_token ((Session *) remote_desktop_session,
+ REMOTE_DESKTOP_TABLE,
+ in_out_results,
+ &remote_desktop_session->persist_mode,
+ &remote_desktop_session->restore_token,
+ &remote_desktop_session->restore_data);
+}
+
static gboolean
process_results (RemoteDesktopSession *remote_desktop_session,
- GVariant *results,
+ GVariant **in_out_results,
GError **error)
{
g_autoptr(GVariantIter) streams_iter = NULL;
+ GVariant *results = *in_out_results;
uint32_t devices = 0;
gboolean clipboard_enabled = FALSE;
@@ -527,6 +625,9 @@ process_results (RemoteDesktopSession *remote_desktop_session,
if (g_variant_lookup (results, "clipboard_enabled", "b", &clipboard_enabled))
remote_desktop_session->clipboard_enabled = clipboard_enabled;
+ replace_restore_remote_desktop_data_with_token (remote_desktop_session,
+ in_out_results);
+
return TRUE;
}
@@ -566,7 +667,7 @@ start_done (GObject *source_object,
{
if (response == 0)
{
- if (!process_results (remote_desktop_session, results, &error))
+ if (!process_results (remote_desktop_session, &results, &error))
{
g_warning ("Could not start remote desktop session: %s",
error->message);