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