Skip to content
Commits on Source (27)
  • Quentin PAGÈS's avatar
    Update Occitan translation · 9135089c
    Quentin PAGÈS authored
    9135089c
  • Pascal Nowack's avatar
  • Pascal Nowack's avatar
    35f74704
  • Pascal Nowack's avatar
  • Pascal Nowack's avatar
  • Pascal Nowack's avatar
    72c0b4ff
  • Pascal Nowack's avatar
    3e0ed824
  • Pascal Nowack's avatar
  • Pascal Nowack's avatar
    0855858d
  • Pascal Nowack's avatar
  • Pascal Nowack's avatar
    daemon: Also clear context on destruction · bdeb8077
    Pascal Nowack authored
    bdeb8077
  • Pascal Nowack's avatar
    context: Clear proxies before setting new proxies · 7e34046c
    Pascal Nowack authored
    Since the context has the last reference on the proxies, it has to take
    care of their destruction.
    So, destroy the remote-desktop- and screen-cast-proxy before setting new
    values.
    Also make sure that both proxies are cleared on destruction of the
    context.
    7e34046c
  • Pascal Nowack's avatar
    clipboard-rdp: Fix error message, when runtime directory creation fails · 70ed8418
    Pascal Nowack authored
    Since the introduction of the support of copy pasting files with FUSE,
    this error message is not correct any more, as the parent directory for
    gnome-remote-desktops base directory changed from the user cache
    directory to the XDG runtime directory.
    70ed8418
  • Pascal Nowack's avatar
    rdp/nw-auto: Only create ping source if required and non-existent · 51e94ba8
    Pascal Nowack authored
    When updating the ping source, gnome-remote-desktop clears the previous
    GSource first, if it is required.
    If it is not required, then gnome-remote-desktop won't clear the
    existing GSource.
    This behaviour is correct. However, when it is not required to update
    the ping source, gnome-remote-desktop will still attempt to create a
    new GSource and replace the existing GSource with the new one.
    The old GSource will then remain to exist and cannot be removed any
    more, since no reference to that GSource is left.
    
    Fix this behaviour by just returning from the function in such
    situation.
    Currently, gnome-remote-desktop does not run into this situation, since
    it seems that all known RDP clients seem to behave well with the
    SuppressOutput PDU.
    51e94ba8
  • Pascal Nowack's avatar
    session: Only handle Selection* signals when clipboard is enabled · 3dfb2d15
    Pascal Nowack authored
    When the RDP or VNC backend disable the clipboard, since the session is
    about to be destroyed, then gnome-remote-desktop could still receive
    SelectionOwnerChanged- and SelectionTransfer-signals.
    Currently, these signals are handled unconditionally.
    
    To ensure that this won't be the case any more, ignore these signals,
    when the clipboard instance is unavailable.
    3dfb2d15
  • Pascal Nowack's avatar
    clipboard-rdp: Fix small style issues · 850bc09c
    Pascal Nowack authored
    850bc09c
  • Pascal Nowack's avatar
    clipboard: Split up SelectionTransfer handling · 8e855503
    Pascal Nowack authored
    Currently, when gnome-remote-desktop handles a SelectionTransfer-
    signal, the mime type content is requested synchronously from the
    respective backend.
    Since this process is done synchronously, the main thread is blocked
    and cannot handle any other events, such as input events.
    With additional network latency, this becomes worse.
    
    To allow the backend implementations to transform to an asynchronous
    implementation, split up the SelectionTransfer handling.
    The signal will now just emit the request on the backend and the
    backend will, when it has the response ready submit the response
    itself.
    
    Both the RDP and VNC backend will currently still function as before,
    as the handling is just split up.
    Since the VNC backend does not support delayed rendering of clipboard
    data, no further changes will happen for the VNC backend.
    The RDP backend, on the other hand, will be reworked in the next commit
    to handle mime type content requests asynchronously.
    8e855503
  • Pascal Nowack's avatar
    clipboard-rdp: Make SelectionTransfer requests async · 25b0822e
    Pascal Nowack authored
    The previous commit split up the SelectionTransfer handling, allowing
    the backends to handle mime type content requests for the client in an
    asynchronous way.
    In order to handle the mime type content requests asynchronously, split
    up grd_clipboard_rdp_request_client_content_for_mime_type() into
    multiple parts:
    
    The first part, about retrieving the mime type content from the
    FormatData cache remains.
    Same with the next part, when gnome-remote-desktop fails a request,
    when a new FormatList is received from the client, since mstsc will
    then not submit any FormatDataResponse in that situation.
    
    Next, implement the new part:
    
    If a there is currently already a mime type content request pending,
    just enqueue the new request.
    This is done with a hash table and a queue.
    The hash table tracks all serials for a request for each specific mime
    type.
    This allows gnome-remote-desktop to group multiple requests into one
    request.
    If a response for the mime type content request is received, all
    serials are answered together.
    The queue preserves the order of these mime type content requests, so
    that all requests are handled fairly, while also tracking the
    respective MimeTypeTables, which contain the foreign format ids, which
    are necessary for the mime type content conversion operations.
    
    If no mime type content request is pending, send the mime type content
    request via a FormatDataRequest and save the serial.
    Also create a timeout source to abort the current request in case no
    FormatDataResponse is sent by the client.
    
    After sending the mime type content request, the new
    grd_clipboard_rdp_request_client_content_for_mime_type() procedure ends
    here.
    
    If the client did not send the FormatDataResponse and the timeout
    source runs, abort the current mime type content request by answering
    all serials for this request with a fail response.
    Then send the next mime type content request, if there is one queued.
    
    If the mime type content request is still pending, but a new FormatList
    is received from the client, abort all pending and queued mime type
    content requests.
    This is necessary, since mstsc will not answer these requests any more,
    so gnome-remote-desktop has to fake their responses.
    
    If a FormatDataResponse is received, gnome-remote-desktop can handle
    the response for the mime type request.
    For this, the CLIPRDR thread queues the task via a GSource onto the
    main thread and duplicates the response.
    This is necessary, as the FormatDataResponse, owned by the CLIPRDR
    thread, is only valid as long as the callback function runs.
    If there is no current mime type content request pending, the response
    is discarded.
    
    The handling of the FormatDataResponse on the main thread uses the last
    part of the old
    grd_clipboard_rdp_request_client_content_for_mime_type() function.
    First, the data is extracted and the flags are checked.
    If the response was successful, convert the received mime type content,
    if necessary.
    After this, answer all serials for the given mime type.
    If the response was not successful, answer all serials for the given
    mime type with a fail response.
    At the end of this handling, send the next mime type content request,
    if there is one queued.
    25b0822e
  • Pascal Nowack's avatar
    clipboard-rdp: Make a warning message a little bit more explicit · 48ea40ca
    Pascal Nowack authored
    Indicate in the warning message, that the conversion failed for a
    request from the client.
    48ea40ca
  • Pascal Nowack's avatar
    settings: Set error if username or password is NULL · b17d0bef
    Pascal Nowack authored
    When looking up the username or password for an RDP session,
    gnome-remote-desktop will parse the credentials string, returned via
    libsecret.
    This credentials string may exist, but it can contain garbage values,
    when e.g. the user changed them to such garbage values.
    In such case, the parsed username or password may be NULL, leading into
    gnome-remote-desktop to crash, as the error is not set.
    
    Fix this behaviour by always setting the GError, when the username or
    password is NULL.
    b17d0bef
  • Pascal Nowack's avatar
    settings: Don't leak credentials, when username or password is NULL · 41d407a1
    Pascal Nowack authored
    While commit b17d0bef fixes a crash,
    when the username or password is NULL, it accidentally leaks the string
    with the credentials, which is in such case not NULL.
    
    Use the autofree- and autoptr- helpers to get rid of any leaks here.
    
    Fixes: b17d0bef
    41d407a1
  • Pascal Nowack's avatar
    session: Fix small style issue · a68a5ed2
    Pascal Nowack authored
    a68a5ed2
  • Jonas Ådahl's avatar
    session: Disconnect num/caps lock changed signals when stopping · b50308b8
    Jonas Ådahl authored
    Otherwise we might receive notifications after stopping or even
    finalizing, causing crashes.
    b50308b8
  • Pascal Nowack's avatar
    stream: Add method to disconnect proxy signals · 2c968f5d
    Pascal Nowack authored
    This method will be called in the next commit, when the session is
    stopped to prevent calling the connected callback, when the actual
    session is already stopped or destroyed.
    2c968f5d
  • Pascal Nowack's avatar
    session: Stop trying to stop the session, when it is already destroyed · aed99b38
    Pascal Nowack authored
    In order to start a remote desktop session, gnome-remote-desktop calls
    several dbus methods on the remote desktop- and screencast interface of
    mutter.
    These calls use in glib internally GTasks and will always run their
    async-ready-callback, when the task is done, aborted, or cancelled.
    This also applies to situations, where the session is immediately
    stopped or destroyed.
    In such cases, the callback should not be handled any more, as parts of
    the session are already destroyed, due to the session already been
    stopped, or the complete session is already destroyed.
    The result is usually a crash, as gnome-remote-desktop tries to stop
    the session, although it is already stopped or destroyed.
    
    To prevent these situations, always cancel the cancellable, when
    stopping the session.
    When a async-ready-callback is called, don't directly derenference the
    user date.
    Instead, call the finish function first and check the error code.
    When the cancellable was cancelled, the finish function will not return
    successfully and set the error.
    The error code will in such cases be G_IO_ERROR_CANCELLED.
    If that is the case, just return, as the session is already stopped.
    aed99b38
  • Jonas Ådahl's avatar
    build: Bump version to 41.2 · 32c8d66a
    Jonas Ådahl authored
    32c8d66a
  • Jeremy Bicha's avatar
    New upstream version 41.2 · 8798020f
    Jeremy Bicha authored
    8798020f
project('gnome-remote-desktop', 'c',
version: '41.1',
version: '41.2',
meson_version: '>= 0.47.0',
default_options: ['warning_level=1',
'buildtype=debugoptimized'])
......
......@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: gnome-remote-desktop master\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-remote-desktop/"
"issues\n"
"POT-Creation-Date: 2021-07-22 17:48+0000\n"
"PO-Revision-Date: 2021-10-03 19:06+0200\n"
"POT-Creation-Date: 2021-10-03 17:07+0000\n"
"PO-Revision-Date: 2021-11-10 19:22+0100\n"
"Last-Translator: Quentin PAGÈS\n"
"Language-Team: Occitan <totenoc@gmail.com>\n"
"Language: oc\n"
......@@ -18,7 +18,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 3.0\n"
#: src/grd-daemon.c:351
#: src/grd-daemon.c:365
msgid "GNOME Remote Desktop"
msgstr "Burèu distant de GNOME"
......@@ -95,3 +95,9 @@ msgid ""
"access to the workstation to explicitly approve the new connection. * "
"password - by requiring the remote client to provide a known password"
msgstr ""
"Lo metòde d’autentificacion VNC descriu cossí una connexion distanta es "
"autentificada. Se pòt generalament far de dos biases : *fenèstra de convit - "
"en convidant l’utilizaire per cada connexion, en demandant qu’una persona "
"amb un accès fisic a l’estacion de trabalh qu’accepte explicitament la "
"connexion. *senhal - en demandant al client alonhat de provesir un senhal "
"conegut"
This diff is collapsed.
/*
* Copyright (C) 2020 Pascal Nowack
* Copyright (C) 2020-2021 Pascal Nowack
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
......@@ -79,16 +79,17 @@ grd_clipboard_vnc_update_client_mime_type_list (GrdClipboard *clipboard,
g_list_free (mime_type_list);
}
static uint8_t *
static void
grd_clipboard_vnc_request_client_content_for_mime_type (GrdClipboard *clipboard,
GrdMimeTypeTable *mime_type_table,
uint32_t *size)
unsigned int serial)
{
GrdClipboardVnc *clipboard_vnc = GRD_CLIPBOARD_VNC (clipboard);
uint32_t size;
*size = strlen (clipboard_vnc->clipboard_utf8_string);
return g_memdup2 (clipboard_vnc->clipboard_utf8_string, *size);
size = strlen (clipboard_vnc->clipboard_utf8_string);
grd_clipboard_submit_client_content_for_mime_type (
clipboard, serial, (uint8_t *) clipboard_vnc->clipboard_utf8_string, size);
}
static void
......
......@@ -383,6 +383,8 @@ grd_clipboard_update_client_mime_type_list (GrdClipboard *clipboard,
*/
abort_current_read_operation (clipboard);
g_assert (priv->enabled);
if (!klass->update_client_mime_type_list)
return;
......@@ -394,36 +396,51 @@ grd_clipboard_update_client_mime_type_list (GrdClipboard *clipboard,
g_debug ("Clipboard[SelectionOwnerChanged]: Update complete");
}
uint8_t *
void
grd_clipboard_submit_client_content_for_mime_type (GrdClipboard *clipboard,
unsigned int serial,
const uint8_t *data,
uint32_t size)
{
GrdClipboardPrivate *priv = grd_clipboard_get_instance_private (clipboard);
g_assert (priv->enabled);
if (data && size)
g_debug ("Clipboard[SelectionTransfer]: Request for serial %u was successful", serial);
else
g_debug ("Clipboard[SelectionTransfer]: Request for serial %u failed", serial);
grd_session_selection_write (priv->session, serial, data, size);
}
void
grd_clipboard_request_client_content_for_mime_type (GrdClipboard *clipboard,
GrdMimeType mime_type,
uint32_t *size)
unsigned int serial)
{
GrdClipboardClass *klass = GRD_CLIPBOARD_GET_CLASS (clipboard);
GrdClipboardPrivate *priv = grd_clipboard_get_instance_private (clipboard);
GrdMimeTypeTable *mime_type_table = NULL;
uint8_t *mime_type_content = NULL;
*size = 0;
g_assert (priv->enabled);
if (!klass->request_client_content_for_mime_type)
return NULL;
g_return_if_fail (klass->request_client_content_for_mime_type);
g_debug ("Clipboard[SelectionTransfer]: Requesting data from clients clipboard"
" (mime type: %s)", grd_mime_type_to_string (mime_type));
" (mime type: %s, serial: %u)",
grd_mime_type_to_string (mime_type), serial);
mime_type_table = g_hash_table_lookup (priv->client_mime_type_tables,
GUINT_TO_POINTER (mime_type));
if (mime_type_table)
if (!mime_type_table)
{
mime_type_content = klass->request_client_content_for_mime_type (
clipboard, mime_type_table, size);
grd_clipboard_submit_client_content_for_mime_type (clipboard, serial,
NULL, 0);
return;
}
if (mime_type_content)
g_debug ("Clipboard[SelectionTransfer]: Request successful");
else
g_debug ("Clipboard[SelectionTransfer]: Request failed");
return mime_type_content;
klass->request_client_content_for_mime_type (clipboard, mime_type_table,
serial);
}
static void
......@@ -447,6 +464,18 @@ grd_clipboard_dispose (GObject *object)
G_OBJECT_CLASS (grd_clipboard_parent_class)->dispose (object);
}
static void
grd_clipboard_finalize (GObject *object)
{
GrdClipboard *clipboard = GRD_CLIPBOARD (object);
GrdClipboardPrivate *priv = grd_clipboard_get_instance_private (clipboard);
g_mutex_clear (&priv->pending_read_mutex);
g_cond_clear (&priv->pending_read_cond);
G_OBJECT_CLASS (grd_clipboard_parent_class)->finalize (object);
}
static void
grd_clipboard_init (GrdClipboard *clipboard)
{
......@@ -465,4 +494,5 @@ grd_clipboard_class_init (GrdClipboardClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = grd_clipboard_dispose;
object_class->finalize = grd_clipboard_finalize;
}
/*
* Copyright (C) 2020 Pascal Nowack
* Copyright (C) 2020-2021 Pascal Nowack
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
......@@ -35,9 +35,9 @@ struct _GrdClipboardClass
void (*update_client_mime_type_list) (GrdClipboard *clipboard,
GList *mime_type_list);
uint8_t *(*request_client_content_for_mime_type) (GrdClipboard *clipboard,
GrdMimeTypeTable *mime_type_table,
uint32_t *size);
void (*request_client_content_for_mime_type) (GrdClipboard *clipboard,
GrdMimeTypeTable *mime_type_table,
unsigned int serial);
void (*submit_requested_server_content) (GrdClipboard *clipboard,
uint8_t *data,
uint32_t size);
......@@ -59,8 +59,13 @@ void grd_clipboard_disable_clipboard (GrdClipboard *clipboard);
void grd_clipboard_update_client_mime_type_list (GrdClipboard *clipboard,
GList *mime_type_list);
uint8_t *grd_clipboard_request_client_content_for_mime_type (GrdClipboard *clipboard,
GrdMimeType mime_type,
uint32_t *size);
void grd_clipboard_submit_client_content_for_mime_type (GrdClipboard *clipboard,
unsigned int serial,
const uint8_t *data,
uint32_t size);
void grd_clipboard_request_client_content_for_mime_type (GrdClipboard *clipboard,
GrdMimeType mime_type,
unsigned int serial);
#endif /* GRD_CLIPBOARD_H */
......@@ -65,6 +65,7 @@ void
grd_context_set_remote_desktop_proxy (GrdContext *context,
GrdDBusRemoteDesktop *proxy)
{
g_clear_object (&context->remote_desktop_proxy);
context->remote_desktop_proxy = proxy;
}
......@@ -72,6 +73,7 @@ void
grd_context_set_screen_cast_proxy (GrdContext *context,
GrdDBusScreenCast *proxy)
{
g_clear_object (&context->screen_cast_proxy);
context->screen_cast_proxy = proxy;
}
......@@ -135,6 +137,8 @@ grd_context_finalize (GObject *object)
{
GrdContext *context = GRD_CONTEXT (object);
g_clear_object (&context->remote_desktop_proxy);
g_clear_object (&context->screen_cast_proxy);
g_clear_object (&context->settings);
G_OBJECT_CLASS (grd_context_parent_class)->finalize (object);
......
......@@ -311,6 +311,8 @@ grd_daemon_shutdown (GApplication *app)
g_bus_unwatch_name (daemon->screen_cast_watch_name_id);
daemon->screen_cast_watch_name_id = 0;
g_clear_object (&daemon->context);
G_APPLICATION_CLASS (grd_daemon_parent_class)->shutdown (app);
}
......
......@@ -389,6 +389,16 @@ grd_rdp_event_queue_dispose (GObject *object)
G_OBJECT_CLASS (grd_rdp_event_queue_parent_class)->dispose (object);
}
static void
grd_rdp_event_queue_finalize (GObject *object)
{
GrdRdpEventQueue *rdp_event_queue = GRD_RDP_EVENT_QUEUE (object);
g_mutex_clear (&rdp_event_queue->event_mutex);
G_OBJECT_CLASS (grd_rdp_event_queue_parent_class)->finalize (object);
}
static void
grd_rdp_event_queue_init (GrdRdpEventQueue *rdp_event_queue)
{
......@@ -406,4 +416,5 @@ grd_rdp_event_queue_class_init (GrdRdpEventQueueClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = grd_rdp_event_queue_dispose;
object_class->finalize = grd_rdp_event_queue_finalize;
}
......@@ -1432,6 +1432,17 @@ grd_rdp_fuse_clipboard_dispose (GObject *object)
G_OBJECT_CLASS (grd_rdp_fuse_clipboard_parent_class)->dispose (object);
}
static void
grd_rdp_fuse_clipboard_finalize (GObject *object)
{
GrdRdpFuseClipboard *rdp_fuse_clipboard = GRD_RDP_FUSE_CLIPBOARD (object);
g_mutex_clear (&rdp_fuse_clipboard->selection_mutex);
g_mutex_clear (&rdp_fuse_clipboard->filesystem_mutex);
G_OBJECT_CLASS (grd_rdp_fuse_clipboard_parent_class)->finalize (object);
}
static void
clip_data_entry_free (gpointer data)
{
......@@ -1550,4 +1561,5 @@ grd_rdp_fuse_clipboard_class_init (GrdRdpFuseClipboardClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = grd_rdp_fuse_clipboard_dispose;
object_class->finalize = grd_rdp_fuse_clipboard_finalize;
}
......@@ -1332,6 +1332,16 @@ grd_rdp_graphics_pipeline_dispose (GObject *object)
G_OBJECT_CLASS (grd_rdp_graphics_pipeline_parent_class)->dispose (object);
}
static void
grd_rdp_graphics_pipeline_finalize (GObject *object)
{
GrdRdpGraphicsPipeline *graphics_pipeline = GRD_RDP_GRAPHICS_PIPELINE (object);
g_mutex_clear (&graphics_pipeline->gfx_mutex);
G_OBJECT_CLASS (grd_rdp_graphics_pipeline_parent_class)->finalize (object);
}
static const char *
rdpgfx_caps_version_to_string (uint32_t caps_version)
{
......@@ -1519,4 +1529,5 @@ grd_rdp_graphics_pipeline_class_init (GrdRdpGraphicsPipelineClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = grd_rdp_graphics_pipeline_dispose;
object_class->finalize = grd_rdp_graphics_pipeline_finalize;
}
......@@ -166,9 +166,11 @@ update_ping_source (GrdRdpNetworkAutodetection *network_autodetection)
g_clear_pointer (&network_autodetection->ping_source, g_source_unref);
}
if (network_autodetection->rtt_consumers == GRD_RDP_NW_AUTODETECT_RTT_CONSUMER_NONE)
if (network_autodetection->rtt_consumers == GRD_RDP_NW_AUTODETECT_RTT_CONSUMER_NONE ||
network_autodetection->ping_interval == new_ping_interval_type)
return;
g_assert (!network_autodetection->ping_source);
emit_ping (network_autodetection);
switch (new_ping_interval_type)
......@@ -410,6 +412,19 @@ grd_rdp_network_autodetection_dispose (GObject *object)
G_OBJECT_CLASS (grd_rdp_network_autodetection_parent_class)->dispose (object);
}
static void
grd_rdp_network_autodetection_finalize (GObject *object)
{
GrdRdpNetworkAutodetection *network_autodetection =
GRD_RDP_NETWORK_AUTODETECTION (object);
g_mutex_clear (&network_autodetection->sequence_mutex);
g_mutex_clear (&network_autodetection->consumer_mutex);
g_mutex_clear (&network_autodetection->shutdown_mutex);
G_OBJECT_CLASS (grd_rdp_network_autodetection_parent_class)->finalize (object);
}
static void
grd_rdp_network_autodetection_init (GrdRdpNetworkAutodetection *network_autodetection)
{
......@@ -428,4 +443,5 @@ grd_rdp_network_autodetection_class_init (GrdRdpNetworkAutodetectionClass *klass
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = grd_rdp_network_autodetection_dispose;
object_class->finalize = grd_rdp_network_autodetection_finalize;
}
......@@ -651,6 +651,8 @@ grd_rdp_pipewire_stream_finalize (GObject *object)
g_clear_pointer (&stream->pending_frame, g_free);
}
g_mutex_clear (&stream->frame_mutex);
G_OBJECT_CLASS (grd_rdp_pipewire_stream_parent_class)->finalize (object);
}
......
......@@ -2189,6 +2189,19 @@ grd_session_rdp_dispose (GObject *object)
G_OBJECT_CLASS (grd_session_rdp_parent_class)->dispose (object);
}
static void
grd_session_rdp_finalize (GObject *object)
{
GrdSessionRdp *session_rdp = GRD_SESSION_RDP (object);
g_mutex_clear (&session_rdp->close_session_mutex);
g_mutex_clear (&session_rdp->rdp_flags_mutex);
g_mutex_clear (&session_rdp->pending_jobs_mutex);
g_cond_clear (&session_rdp->pending_jobs_cond);
G_OBJECT_CLASS (grd_session_rdp_parent_class)->finalize (object);
}
static gboolean
are_pointer_bitmaps_equal (gconstpointer a,
gconstpointer b)
......@@ -2277,6 +2290,7 @@ grd_session_rdp_class_init (GrdSessionRdpClass *klass)
GrdSessionClass *session_class = GRD_SESSION_CLASS (klass);
object_class->dispose = grd_session_rdp_dispose;
object_class->finalize = grd_session_rdp_finalize;
session_class->remote_desktop_session_ready =
grd_session_rdp_remote_desktop_session_ready;
......
/*
* Copyright (C) 2015 Red Hat Inc.
* Copyright (C) 2020 Pascal Nowack
* Copyright (C) 2020-2021 Pascal Nowack
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
......@@ -73,6 +73,9 @@ typedef struct _GrdSessionPrivate
GCancellable *cancellable;
gboolean started;
gulong caps_lock_state_changed_id;
gulong num_lock_state_changed_id;
} GrdSessionPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (GrdSession, grd_session, G_TYPE_OBJECT);
......@@ -90,6 +93,9 @@ grd_session_stop (GrdSession *session)
{
GrdSessionPrivate *priv = grd_session_get_instance_private (session);
if (priv->cancellable && g_cancellable_is_cancelled (priv->cancellable))
return;
GRD_SESSION_GET_CLASS (session)->stop (session);
if (priv->remote_desktop_session && priv->started)
......@@ -104,6 +110,17 @@ grd_session_stop (GrdSession *session)
}
}
if (priv->cancellable)
g_cancellable_cancel (priv->cancellable);
g_clear_signal_handler (&priv->caps_lock_state_changed_id,
priv->remote_desktop_session);
g_clear_signal_handler (&priv->num_lock_state_changed_id,
priv->remote_desktop_session);
if (priv->stream)
grd_stream_disconnect_proxy_signals (priv->stream);
g_clear_object (&priv->remote_desktop_session);
g_clear_object (&priv->screen_cast_session);
......@@ -143,9 +160,9 @@ grd_session_notify_keyboard_keysym (GrdSession *session,
}
void
grd_session_notify_pointer_button (GrdSession *session,
int32_t button,
GrdButtonState state)
grd_session_notify_pointer_button (GrdSession *session,
int32_t button,
GrdButtonState state)
{
GrdSessionPrivate *priv = grd_session_get_instance_private (session);
GrdDBusRemoteDesktopSession *session_proxy = priv->remote_desktop_session;
......@@ -266,6 +283,7 @@ grd_session_disable_clipboard (GrdSession *session)
{
GrdSessionPrivate *priv = grd_session_get_instance_private (session);
priv->clipboard = NULL;
if (!priv->remote_desktop_session)
return;
......@@ -324,6 +342,59 @@ acquire_fd_from_list (GUnixFDList *fd_list,
return fd;
}
void
grd_session_selection_write (GrdSession *session,
unsigned int serial,
const uint8_t *data,
uint32_t size)
{
GrdSessionPrivate *priv = grd_session_get_instance_private (session);
g_autoptr (GError) error = NULL;
g_autoptr (GVariant) fd_variant = NULL;
g_autoptr (GUnixFDList) fd_list = NULL;
int fd_idx;
int fd;
if (!data || !size)
{
grd_dbus_remote_desktop_session_call_selection_write_done (
priv->remote_desktop_session, serial, FALSE, NULL, NULL, NULL);
return;
}
if (!grd_dbus_remote_desktop_session_call_selection_write_sync (
priv->remote_desktop_session, serial, NULL, &fd_variant, &fd_list,
NULL, &error))
{
g_warning ("Failed to write selection for serial %u: %s",
serial, error->message);
return;
}
g_variant_get (fd_variant, "h", &fd_idx);
fd = acquire_fd_from_list (fd_list, fd_idx, &error);
if (fd == -1)
{
g_warning ("Failed to acquire file descriptor for serial %u: %s",
serial, error->message);
return;
}
if (write (fd, data, size) < 0)
{
grd_dbus_remote_desktop_session_call_selection_write_done (
priv->remote_desktop_session, serial, FALSE, NULL, NULL, NULL);
close (fd);
return;
}
grd_dbus_remote_desktop_session_call_selection_write_done (
priv->remote_desktop_session, serial, TRUE, NULL, NULL, NULL);
close (fd);
}
int
grd_session_selection_read (GrdSession *session,
GrdMimeType mime_type)
......@@ -375,23 +446,27 @@ on_session_start_finished (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GrdSession *session = user_data;
GrdSessionPrivate *priv = grd_session_get_instance_private (session);
GrdDBusRemoteDesktopSession *proxy = priv->remote_desktop_session;
GError *error = NULL;
GrdDBusRemoteDesktopSession *proxy;
GrdSession *session;
GrdSessionPrivate *priv;
g_autoptr (GError) error = NULL;
proxy = GRD_DBUS_REMOTE_DESKTOP_SESSION (object);
if (!grd_dbus_remote_desktop_session_call_start_finish (proxy,
result,
&error))
{
g_warning ("Failed to start session: %s", error->message);
g_error_free (error);
grd_session_stop (session);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
g_warning ("Failed to start session: %s", error->message);
grd_session_stop (GRD_SESSION (user_data));
return;
}
session = GRD_SESSION (user_data);
priv = grd_session_get_instance_private (session);
priv->started = TRUE;
}
......@@ -412,23 +487,26 @@ on_screen_cast_stream_proxy_acquired (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GrdSession *session = user_data;
GrdSessionPrivate *priv = grd_session_get_instance_private (session);
GrdDBusScreenCastStream *stream_proxy;
GError *error = NULL;
GrdSession *session;
GrdSessionPrivate *priv;
g_autoptr (GError) error = NULL;
GrdStream *stream;
stream_proxy = grd_dbus_screen_cast_stream_proxy_new_finish (result, &error);
if (!stream_proxy)
{
g_warning ("Failed to acquire stream proxy: %s", error->message);
g_error_free (error);
grd_session_stop (session);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
g_warning ("Failed to acquire stream proxy: %s", error->message);
grd_session_stop (GRD_SESSION (user_data));
return;
}
session = GRD_SESSION (user_data);
priv = grd_session_get_instance_private (session);
stream = grd_stream_new (priv->context, stream_proxy);
g_signal_connect (stream, "ready", G_CALLBACK (on_stream_ready),
session);
......@@ -444,26 +522,30 @@ on_record_monitor_finished (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GrdSession *session = user_data;
GrdSessionPrivate *priv = grd_session_get_instance_private (session);
GrdDBusScreenCastSession *proxy = priv->screen_cast_session;
g_autofree char *stream_path = NULL;
GError *error = NULL;
GrdDBusScreenCastSession *proxy;
GrdSession *session;
GrdSessionPrivate *priv;
GDBusConnection *connection;
g_autofree char *stream_path = NULL;
g_autoptr (GError) error = NULL;
proxy = GRD_DBUS_SCREEN_CAST_SESSION (object);
if (!grd_dbus_screen_cast_session_call_record_monitor_finish (proxy,
&stream_path,
result,
&error))
{
g_warning ("Failed to record monitor: %s", error->message);
g_error_free (error);
grd_session_stop (session);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
g_warning ("Failed to record monitor: %s", error->message);
grd_session_stop (GRD_SESSION (user_data));
return;
}
session = GRD_SESSION (user_data);
priv = grd_session_get_instance_private (session);
connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (proxy));
grd_dbus_screen_cast_stream_proxy_new (connection,
G_DBUS_PROXY_FLAGS_NONE,
......@@ -479,25 +561,28 @@ on_screen_cast_session_proxy_acquired (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GrdSession *session = user_data;
GrdSessionPrivate *priv = grd_session_get_instance_private (session);
GrdDBusScreenCastSession *session_proxy;
GrdSession *session;
GrdSessionPrivate *priv;
GVariantBuilder properties_builder;
GError *error = NULL;
g_autoptr (GError) error = NULL;
session_proxy =
grd_dbus_screen_cast_session_proxy_new_finish (result, &error);
if (!session_proxy)
{
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
g_warning ("Failed to acquire screen cast session proxy: %s\n",
error->message);
g_error_free (error);
grd_session_stop (session);
grd_session_stop (GRD_SESSION (user_data));
return;
}
session = GRD_SESSION (user_data);
priv = grd_session_get_instance_private (session);
priv->screen_cast_session = session_proxy;
g_variant_builder_init (&properties_builder, G_VARIANT_TYPE ("a{sv}"));
......@@ -519,28 +604,31 @@ on_screen_cast_session_created (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GrdSession *session = user_data;
GrdSessionPrivate *priv = grd_session_get_instance_private (session);
GrdDBusScreenCast *screen_cast_proxy;
g_autofree char *session_path = NULL;
GError *error = NULL;
GrdSession *session;
GrdSessionPrivate *priv;
GDBusConnection *connection;
g_autofree char *session_path = NULL;
g_autoptr (GError) error = NULL;
screen_cast_proxy = grd_context_get_screen_cast_proxy (priv->context);
screen_cast_proxy = GRD_DBUS_SCREEN_CAST (source_object);
if (!grd_dbus_screen_cast_call_create_session_finish (screen_cast_proxy,
&session_path,
res,
&error))
{
g_warning ("Failed to start screen cast session: %s\n", error->message);
g_error_free (error);
grd_session_stop (session);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
g_warning ("Failed to start screen cast session: %s\n", error->message);
grd_session_stop (GRD_SESSION (user_data));
return;
}
session = GRD_SESSION (user_data);
priv = grd_session_get_instance_private (session);
connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (screen_cast_proxy));
grd_dbus_screen_cast_session_proxy_new (connection,
G_DBUS_PROXY_FLAGS_NONE,
MUTTER_SCREEN_CAST_BUS_NAME,
......@@ -574,6 +662,9 @@ on_remote_desktop_session_selection_owner_changed (GrdDBusRemoteDesktopSession *
GrdMimeType mime_type;
GList *mime_type_list = NULL;
if (!priv->clipboard)
return;
is_owner_variant = g_variant_lookup_value (options_variant, "session-is-owner",
G_VARIANT_TYPE ("b"));
if (is_owner_variant && g_variant_get_boolean (is_owner_variant))
......@@ -613,15 +704,11 @@ on_remote_desktop_session_selection_transfer (GrdDBusRemoteDesktopSession *sessi
GrdSession *session)
{
GrdSessionPrivate *priv = grd_session_get_instance_private (session);
uint8_t *data;
uint32_t size;
g_autoptr (GError) error = NULL;
g_autoptr (GVariant) fd_variant = NULL;
g_autoptr (GUnixFDList) fd_list = NULL;
int fd_idx;
int fd;
GrdMimeType mime_type;
if (!priv->clipboard)
return;
mime_type = grd_mime_type_from_string (mime_type_string);
if (mime_type == GRD_MIME_TYPE_NONE)
{
......@@ -630,39 +717,8 @@ on_remote_desktop_session_selection_transfer (GrdDBusRemoteDesktopSession *sessi
return;
}
if (!grd_dbus_remote_desktop_session_call_selection_write_sync (
priv->remote_desktop_session, serial, NULL, &fd_variant, &fd_list,
NULL, &error))
{
g_warning ("Failed to write selection: %s", error->message);
return;
}
g_variant_get (fd_variant, "h", &fd_idx);
fd = acquire_fd_from_list (fd_list, fd_idx, &error);
if (fd == -1)
{
g_warning ("Failed to acquire file descriptor: %s", error->message);
return;
}
data = grd_clipboard_request_client_content_for_mime_type (priv->clipboard,
mime_type, &size);
if (!size || write (fd, data, size) < 0)
{
grd_dbus_remote_desktop_session_call_selection_write_done (
priv->remote_desktop_session, serial, FALSE, NULL, NULL, NULL);
close (fd);
g_free (data);
return;
}
grd_dbus_remote_desktop_session_call_selection_write_done (
priv->remote_desktop_session, serial, TRUE, NULL, NULL, NULL);
close (fd);
g_free (data);
grd_clipboard_request_client_content_for_mime_type (priv->clipboard,
mime_type, serial);
}
static void
......@@ -700,11 +756,11 @@ on_remote_desktop_session_proxy_acquired (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GrdSession *session = user_data;
GrdSessionPrivate *priv = grd_session_get_instance_private (session);
GrdSessionClass *klass = GRD_SESSION_GET_CLASS (session);
GrdDBusRemoteDesktopSession *session_proxy;
GError *error = NULL;
GrdSession *session;
GrdSessionPrivate *priv;
GrdSessionClass *klass;
g_autoptr (GError) error = NULL;
const char *remote_desktop_session_id;
GrdDBusScreenCast *screen_cast_proxy;
GVariantBuilder properties_builder;
......@@ -714,15 +770,19 @@ on_remote_desktop_session_proxy_acquired (GObject *object,
grd_dbus_remote_desktop_session_proxy_new_finish (result, &error);
if (!session_proxy)
{
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
g_warning ("Failed to acquire remote desktop session proxy: %s\n",
error->message);
g_error_free (error);
grd_session_stop (session);
grd_session_stop (GRD_SESSION (user_data));
return;
}
session = GRD_SESSION (user_data);
priv = grd_session_get_instance_private (session);
klass = GRD_SESSION_GET_CLASS (session);
g_signal_connect (session_proxy, "closed",
G_CALLBACK (on_remote_desktop_session_closed),
session);
......@@ -754,12 +814,14 @@ on_remote_desktop_session_proxy_acquired (GObject *object,
on_screen_cast_session_created,
session);
g_signal_connect (session_proxy, "notify::caps-lock-state",
G_CALLBACK (on_caps_lock_state_changed),
session);
g_signal_connect (session_proxy, "notify::num-lock-state",
G_CALLBACK (on_num_lock_state_changed),
session);
priv->caps_lock_state_changed_id =
g_signal_connect (session_proxy, "notify::caps-lock-state",
G_CALLBACK (on_caps_lock_state_changed),
session);
priv->num_lock_state_changed_id =
g_signal_connect (session_proxy, "notify::num-lock-state",
G_CALLBACK (on_num_lock_state_changed),
session);
if (klass->remote_desktop_session_ready)
klass->remote_desktop_session_ready (session);
......@@ -773,28 +835,31 @@ on_remote_desktop_session_created (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GrdSession *session = user_data;
GrdSessionPrivate *priv = grd_session_get_instance_private (session);
GrdDBusRemoteDesktop *remote_desktop_proxy;
g_autofree char *session_path = NULL;
GrdSession *session;
GrdSessionPrivate *priv;
GDBusConnection *connection;
GError *error = NULL;
g_autofree char *session_path = NULL;
g_autoptr (GError) error = NULL;
remote_desktop_proxy = grd_context_get_remote_desktop_proxy (priv->context);
remote_desktop_proxy = GRD_DBUS_REMOTE_DESKTOP (source_object);
if (!grd_dbus_remote_desktop_call_create_session_finish (remote_desktop_proxy,
&session_path,
res,
&error))
{
g_warning ("Failed to start remote desktop session: %s\n", error->message);
g_error_free (error);
grd_session_stop (session);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
g_warning ("Failed to start remote desktop session: %s\n", error->message);
grd_session_stop (GRD_SESSION (user_data));
return;
}
session = GRD_SESSION (user_data);
priv = grd_session_get_instance_private (session);
connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (remote_desktop_proxy));
grd_dbus_remote_desktop_session_proxy_new (connection,
G_DBUS_PROXY_FLAGS_NONE,
MUTTER_REMOTE_DESKTOP_BUS_NAME,
......@@ -839,7 +904,7 @@ grd_session_finalize (GObject *object)
g_assert (!priv->remote_desktop_session);
if (priv->cancellable)
g_cancellable_cancel (priv->cancellable);
g_assert (g_cancellable_is_cancelled (priv->cancellable));
g_clear_object (&priv->cancellable);
G_OBJECT_CLASS (grd_session_parent_class)->finalize (object);
......
/*
* Copyright (C) 2015 Red Hat Inc.
* Copyright (C) 2020 Pascal Nowack
* Copyright (C) 2020-2021 Pascal Nowack
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
......@@ -110,6 +110,11 @@ void grd_session_disable_clipboard (GrdSession *session);
void grd_session_set_selection (GrdSession *session,
GList *mime_type_tables);
void grd_session_selection_write (GrdSession *session,
unsigned int serial,
const uint8_t *data,
uint32_t size);
int grd_session_selection_read (GrdSession *session,
GrdMimeType mime_type);
......
......@@ -138,8 +138,8 @@ grd_settings_get_rdp_username (GrdSettings *settings,
GError **error)
{
const char *test_password_override;
GVariant *credentials;
char *credentials_string;
g_autofree char *credentials_string = NULL;
g_autoptr (GVariant) credentials = NULL;
char *username = NULL;
test_password_override = g_getenv ("GNOME_REMOTE_DESKTOP_TEST_RDP_PASSWORD");
......@@ -158,9 +158,12 @@ grd_settings_get_rdp_username (GrdSettings *settings,
credentials = g_variant_parse (NULL, credentials_string, NULL, NULL, NULL);
g_variant_lookup (credentials, "username", "s", &username);
g_variant_unref (credentials);
g_free (credentials_string);
if (!username)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
"Username not set");
return NULL;
}
return username;
}
......@@ -170,8 +173,8 @@ grd_settings_get_rdp_password (GrdSettings *settings,
GError **error)
{
const char *test_password_override;
GVariant *credentials;
char *credentials_string;
g_autofree char *credentials_string = NULL;
g_autoptr (GVariant) credentials = NULL;
char *password = NULL;
test_password_override = g_getenv ("GNOME_REMOTE_DESKTOP_TEST_RDP_PASSWORD");
......@@ -190,9 +193,12 @@ grd_settings_get_rdp_password (GrdSettings *settings,
credentials = g_variant_parse (NULL, credentials_string, NULL, NULL, NULL);
g_variant_lookup (credentials, "password", "s", &password);
g_variant_unref (credentials);
g_free (credentials_string);
if (!password)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
"Password not set");
return NULL;
}
return password;
}
......@@ -245,6 +251,7 @@ grd_settings_get_vnc_auth_method (GrdSettings *settings)
static void
update_rdp_tls_cert (GrdSettings *settings)
{
g_clear_pointer (&settings->rdp.server_cert, g_free);
settings->rdp.server_cert = g_settings_get_string (settings->rdp.settings,
"tls-cert");
}
......@@ -252,6 +259,7 @@ update_rdp_tls_cert (GrdSettings *settings)
static void
update_rdp_tls_key (GrdSettings *settings)
{
g_clear_pointer (&settings->rdp.server_key, g_free);
settings->rdp.server_key = g_settings_get_string (settings->rdp.settings,
"tls-key");
}
......@@ -321,6 +329,9 @@ grd_settings_finalize (GObject *object)
{
GrdSettings *settings = GRD_SETTINGS (object);
g_clear_pointer (&settings->rdp.server_cert, g_free);
g_clear_pointer (&settings->rdp.server_key, g_free);
g_clear_object (&settings->rdp.settings);
g_clear_object (&settings->vnc.settings);
......
......@@ -41,6 +41,8 @@ typedef struct _GrdStreamPrivate
uint32_t pipewire_node_id;
GrdDBusScreenCastStream *proxy;
unsigned long pipewire_stream_added_id;
} GrdStreamPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (GrdStream, grd_stream, G_TYPE_OBJECT)
......@@ -61,6 +63,14 @@ grd_stream_get_object_path (GrdStream *stream)
return g_dbus_proxy_get_object_path (G_DBUS_PROXY (priv->proxy));
}
void
grd_stream_disconnect_proxy_signals (GrdStream *stream)
{
GrdStreamPrivate *priv = grd_stream_get_instance_private (stream);
g_clear_signal_handler (&priv->pipewire_stream_added_id, priv->proxy);
}
static void
on_pipewire_stream_added (GrdDBusScreenCastStream *proxy,
unsigned int node_id,
......@@ -85,9 +95,10 @@ grd_stream_new (GrdContext *context,
priv->context = context;
priv->proxy = proxy;
g_signal_connect (proxy, "pipewire-stream-added",
G_CALLBACK (on_pipewire_stream_added),
stream);
priv->pipewire_stream_added_id =
g_signal_connect (proxy, "pipewire-stream-added",
G_CALLBACK (on_pipewire_stream_added),
stream);
return stream;
}
......
......@@ -39,6 +39,8 @@ uint32_t grd_stream_get_pipewire_node_id (GrdStream *stream);
const char * grd_stream_get_object_path (GrdStream *stream);
void grd_stream_disconnect_proxy_signals (GrdStream *stream);
GrdStream * grd_stream_new (GrdContext *context,
GrdDBusScreenCastStream *proxy);
......
......@@ -611,6 +611,8 @@ grd_vnc_pipewire_stream_finalize (GObject *object)
g_clear_pointer (&stream->pipewire_source, g_source_unref);
}
g_mutex_clear (&stream->frame_mutex);
G_OBJECT_CLASS (grd_vnc_pipewire_stream_parent_class)->finalize (object);
}
......