Skip to content

Commit

Permalink
remote-desktop: Add persistent sessions
Browse files Browse the repository at this point in the history
This adds persistent remote desktop sessions similar to persistent
screen cast sessions. What it means is that applications can ask for
sessions to be "saved" either temporarily in the portal, or in the
permission store, and later be restored at will, without any interactive
dialog showing up.

It works the same way, by the Start() method returning a restore token,
and similarly to the screen cast variant, passing the same restore token
to the SelectDevices() method the next time.

Closes: #850
  • Loading branch information
jadahl committed Jul 11, 2023
1 parent cbce8c6 commit 33bac33
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 5 deletions.
41 changes: 41 additions & 0 deletions data/org.freedesktop.impl.portal.RemoteDesktop.xml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,47 @@
Default is all.
</para></listitem>
</varlistentry>
<varlistentry>
<term>restore_data (suv)</term>
<listitem><para>
The data to restore from a previous session.
</para>
<para>
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.
</para>
<para>
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.
</para>
<para>
This option was added in version 2 of this interface.
</para></listitem>
</varlistentry>
<varlistentry>
<term>persist_mode u</term>
<listitem><para>
How this session should persist. Default is 0. Accepted values are:
</para>
<para>
<simplelist>
<member>0: Do not persist (default)</member>
<member>1: Permissions persist as long as the application is running</member>
<member>2: Permissions persist until explicitly revoked</member>
</simplelist>
</para>
<para>
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.
</para>
<para>
This option was added in version 2 of this interface.
</para></listitem>
</varlistentry>
</variablelist>
For available device types, see the AvailableDeviceTypes property.
Expand Down
45 changes: 45 additions & 0 deletions data/org.freedesktop.portal.RemoteDesktop.xml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,41 @@
Default is all.
</para></listitem>
</varlistentry>
<varlistentry>
<term>restore_token s</term>
<listitem><para>
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.
</para></listitem>
</varlistentry>
<varlistentry>
<term>persist_mode u</term>
<listitem><para>
How this session should persist. Default is 0. Accepted values are:
<simplelist>
<member>0: Do not persist (default)</member>
<member>1: Permissions persist as long as the application is running</member>
<member>2: Permissions persist until explicitly revoked</member>
</simplelist>
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.
</para></listitem>
</varlistentry>
</variablelist>
For available device types, see the AvailableDeviceTypes property.
Expand Down Expand Up @@ -159,6 +194,16 @@
Since version 2.
</para></listitem>
</varlistentry>
<varlistentry>
<term>restore_token s</term>
<listitem><para>
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.
</para></listitem>
</varlistentry>
</variablelist>
If a screen cast source was selected, the results of the
Expand Down
9 changes: 7 additions & 2 deletions data/org.freedesktop.portal.ScreenCast.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
</para></listitem>
</varlistentry>
Expand All @@ -147,8 +151,9 @@
<member>2: Permissions persist until explicitly revoked</member>
</simplelist>
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
Expand Down
107 changes: 104 additions & 3 deletions src/remote-desktop.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -30,6 +31,8 @@

#include <stdint.h>

#define REMOTE_DESKTOP_TABLE "remote-desktop"

typedef struct _RemoteDesktop RemoteDesktop;
typedef struct _RemoteDesktopClass RemoteDesktopClass;

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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);

Expand Down Expand Up @@ -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),
Expand All @@ -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));
Expand All @@ -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;

Expand All @@ -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;
}

Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 33bac33

Please sign in to comment.