Files
grd/grd-daemon-user.c
2026-02-13 13:06:50 +09:00

292 lines
9.0 KiB
C

/*
* Copyright (C) 2022 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Jonas Ådahl <jadahl@gmail.com>
*/
#include "config.h"
#include "grd-daemon-user.h"
#include <glib/gi18n.h>
#include "grd-private.h"
#include "grd-prompt.h"
struct _GrdDaemonUser
{
GrdDaemon parent;
#ifdef HAVE_RDP
GrdDBusRemoteDesktopRdpServer *system_rdp_server;
GrdPrompt *prompt;
GCancellable *prompt_cancellable;
#endif /* HAVE_RDP */
};
G_DEFINE_TYPE (GrdDaemonUser, grd_daemon_user, GRD_TYPE_DAEMON)
#ifdef HAVE_RDP
static void
on_rdp_server_stopped (GrdDaemonUser *daemon_user)
{
if (daemon_user->prompt_cancellable)
{
g_cancellable_cancel (daemon_user->prompt_cancellable);
g_clear_object (&daemon_user->prompt_cancellable);
}
g_clear_object (&daemon_user->prompt);
g_signal_handlers_disconnect_by_func (daemon_user,
G_CALLBACK (on_rdp_server_stopped),
NULL);
}
static void
prompt_response_callback (GObject *source_object,
GAsyncResult *async_result,
gpointer user_data)
{
GrdDaemonUser *daemon_user = GRD_DAEMON_USER (user_data);
g_autoptr (GError) error = NULL;
GrdPromptResponse response;
if (!grd_prompt_query_finish (daemon_user->prompt,
async_result,
&response,
&error))
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{
g_warning ("Failed to query user about port change: %s",
error->message);
}
}
g_clear_object (&daemon_user->prompt);
g_clear_object (&daemon_user->prompt_cancellable);
}
static void
show_port_changed_prompt (GrdDaemonUser *daemon_user,
const int system_rdp_port,
const int selected_rdp_port)
{
g_autoptr (GrdPromptDefinition) prompt_definition = NULL;
daemon_user->prompt = g_object_new (GRD_TYPE_PROMPT, NULL);
daemon_user->prompt_cancellable = g_cancellable_new ();
prompt_definition = g_new0 (GrdPromptDefinition, 1);
prompt_definition->summary =
g_strdup_printf (_("Desktop Sharing port changed"));
prompt_definition->body =
g_strdup_printf (_("The Desktop Sharing port has changed from <b>%i</b> to "
"<b>%i</b>.\n"
"This is because the Remote Sessions service has been "
"activated and it has a higher priority to use port "
"<b>%i</b>."),
system_rdp_port, selected_rdp_port, system_rdp_port);
prompt_definition->accept_label = g_strdup_printf (_("Accept"));
grd_prompt_query_async (daemon_user->prompt,
prompt_definition,
daemon_user->prompt_cancellable,
prompt_response_callback,
daemon_user);
}
static void
on_rdp_server_started (GrdDaemonUser *daemon_user)
{
GrdContext *context = grd_daemon_get_context (GRD_DAEMON (daemon_user));
GrdDBusRemoteDesktopRdpServer *rdp_server_iface =
grd_context_get_rdp_server_interface (context);
int selected_rdp_port =
grd_dbus_remote_desktop_rdp_server_get_port (rdp_server_iface);
int system_rdp_port =
grd_dbus_remote_desktop_rdp_server_get_port (daemon_user->system_rdp_server);
g_assert (selected_rdp_port != system_rdp_port);
show_port_changed_prompt (daemon_user, system_rdp_port, selected_rdp_port);
g_signal_handlers_disconnect_by_func (daemon_user,
G_CALLBACK (on_rdp_server_started),
NULL);
}
static void
on_system_rdp_server_binding (GrdDBusRemoteDesktopRdpServer *system_rdp_server,
int system_rdp_port,
GrdDaemonUser *daemon_user)
{
GrdContext *context = grd_daemon_get_context (GRD_DAEMON (daemon_user));
GrdDBusRemoteDesktopRdpServer *user_rdp_server =
grd_context_get_rdp_server_interface (context);
int user_rdp_port =
grd_dbus_remote_desktop_rdp_server_get_port (user_rdp_server);
if (system_rdp_port != user_rdp_port)
return;
g_debug ("[DaemonUser] Restarting RDP server due to port conflict with the "
"system daemon");
g_signal_connect (daemon_user, "rdp-server-stopped",
G_CALLBACK (on_rdp_server_stopped), NULL);
g_signal_connect (daemon_user, "rdp-server-started",
G_CALLBACK (on_rdp_server_started), NULL);
grd_daemon_restart_rdp_server_with_delay (GRD_DAEMON (daemon_user));
}
static void
on_remote_desktop_rdp_server_proxy_acquired (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
GrdDaemonUser *daemon_user = user_data;
g_autoptr (GError) error = NULL;
daemon_user->system_rdp_server =
grd_dbus_remote_desktop_rdp_server_proxy_new_for_bus_finish (result, &error);
if (!daemon_user->system_rdp_server)
{
g_warning ("[DaemonUser] Failed to create system RDP server proxy: "
"%s", error->message);
return;
}
g_signal_connect (daemon_user->system_rdp_server, "binding",
G_CALLBACK (on_system_rdp_server_binding),
daemon_user);
}
#endif /* HAVE_RDP */
GrdDaemonUser *
grd_daemon_user_new (GrdRuntimeMode runtime_mode,
GError **error)
{
GrdContext *context;
GrdDaemonUser *daemon_user;
const char *application_id = NULL;
context = grd_context_new (runtime_mode, error);
if (!context)
return NULL;
switch (runtime_mode)
{
case GRD_RUNTIME_MODE_SCREEN_SHARE:
application_id = GRD_DAEMON_USER_APPLICATION_ID;
break;
case GRD_RUNTIME_MODE_HEADLESS:
application_id = GRD_DAEMON_HEADLESS_APPLICATION_ID;
break;
case GRD_RUNTIME_MODE_SYSTEM:
case GRD_RUNTIME_MODE_HANDOVER:
g_assert_not_reached ();
}
daemon_user = g_object_new (GRD_TYPE_DAEMON_USER,
"application-id", application_id,
"flags", G_APPLICATION_IS_SERVICE,
"context", context,
NULL);
return daemon_user;
}
static void
grd_daemon_user_init (GrdDaemonUser *daemon_user)
{
}
static void
grd_daemon_user_startup (GApplication *app)
{
GrdDaemonUser *daemon_user = GRD_DAEMON_USER (app);
#ifdef HAVE_RDP
GCancellable *cancellable =
grd_daemon_get_cancellable (GRD_DAEMON (daemon_user));
#endif /* HAVE_RDP */
grd_daemon_acquire_mutter_dbus_proxies (GRD_DAEMON (daemon_user));
g_signal_connect (daemon_user, "mutter-proxy-acquired",
G_CALLBACK (grd_daemon_maybe_enable_services), NULL);
#ifdef HAVE_RDP
grd_dbus_remote_desktop_rdp_server_proxy_new_for_bus (
G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
REMOTE_DESKTOP_BUS_NAME,
GRD_RDP_SERVER_OBJECT_PATH,
cancellable,
on_remote_desktop_rdp_server_proxy_acquired,
daemon_user);
#endif /* HAVE_RDP */
G_APPLICATION_CLASS (grd_daemon_user_parent_class)->startup (app);
}
static void
grd_daemon_user_shutdown (GApplication *app)
{
#ifdef HAVE_RDP
GrdDaemonUser *daemon_user = GRD_DAEMON_USER (app);
g_clear_object (&daemon_user->system_rdp_server);
if (daemon_user->prompt_cancellable)
{
g_cancellable_cancel (daemon_user->prompt_cancellable);
g_clear_object (&daemon_user->prompt_cancellable);
}
g_clear_object (&daemon_user->prompt);
#endif /* HAVE_RDP */
G_APPLICATION_CLASS (grd_daemon_user_parent_class)->shutdown (app);
}
static gboolean
grd_daemon_user_is_ready (GrdDaemon *daemon)
{
GrdContext *context = grd_daemon_get_context (daemon);
if (!grd_context_get_mutter_remote_desktop_proxy (context) ||
!grd_context_get_mutter_screen_cast_proxy (context))
return FALSE;
return TRUE;
}
static void
grd_daemon_user_class_init (GrdDaemonUserClass *klass)
{
GApplicationClass *g_application_class = G_APPLICATION_CLASS (klass);
GrdDaemonClass *daemon_class = GRD_DAEMON_CLASS (klass);
g_application_class->startup = grd_daemon_user_startup;
g_application_class->shutdown = grd_daemon_user_shutdown;
daemon_class->is_daemon_ready = grd_daemon_user_is_ready;
}