diff options
author | Felipe Borges <felipeborges@gnome.org> | 2022-01-10 13:46:44 +0100 |
---|---|---|
committer | Felipe Borges <felipeborges@gnome.org> | 2022-01-14 11:47:40 +0100 |
commit | c993f7b72ffd646fa59c0fa6bc944ebe65e80325 (patch) | |
tree | 8e301d7ad9fc4340eaae129ad2fbd85ef0a6a5b8 | |
parent | 3622e967e3c2dc3f3991f0ea1fda46500e393504 (diff) | |
download | gnome-control-center-wip/feborges/introduce-rdp-remote-desktop-panel.tar.gz |
remote-desktop: Introduce new panel for configuring the RDP serverwip/feborges/introduce-rdp-remote-desktop-panel
Fixes #1413
-rw-r--r-- | panels/meson.build | 1 | ||||
-rw-r--r-- | panels/remote-desktop/cc-remote-desktop-panel.c | 327 | ||||
-rw-r--r-- | panels/remote-desktop/cc-remote-desktop-panel.h | 30 | ||||
-rw-r--r-- | panels/remote-desktop/cc-remote-desktop-panel.ui | 96 | ||||
-rw-r--r-- | panels/remote-desktop/gnome-remote-desktop-panel.desktop.in.in | 19 | ||||
-rw-r--r-- | panels/remote-desktop/meson.build | 45 | ||||
-rw-r--r-- | panels/remote-desktop/remote-desktop.gresource.xml | 6 | ||||
-rw-r--r-- | shell/cc-panel-list.c | 1 | ||||
-rw-r--r-- | shell/cc-panel-loader.c | 2 |
9 files changed, 527 insertions, 0 deletions
diff --git a/panels/meson.build b/panels/meson.build index d379a9fb1..be84fa8a8 100644 --- a/panels/meson.build +++ b/panels/meson.build @@ -21,6 +21,7 @@ panels = [ 'power', 'printers', 'region', + 'remote-desktop', 'removable-media', 'search', 'sharing', diff --git a/panels/remote-desktop/cc-remote-desktop-panel.c b/panels/remote-desktop/cc-remote-desktop-panel.c new file mode 100644 index 000000000..40267a665 --- /dev/null +++ b/panels/remote-desktop/cc-remote-desktop-panel.c @@ -0,0 +1,327 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Author: Felipe Borges <feborges@redhat.com> + */ + +#include "cc-remote-desktop-panel.h" +#include "cc-remote-desktop-resources.h" +#include "cc-util.h" + +#include <glib/gi18n.h> +#include <libsecret/secret.h> + +struct _CcRemoteDesktopPanel +{ + CcPanel parent_instance; + + GSettings *remote_desktop_settings; + GCancellable *cancellable; + guint remote_desktop_name_watch; + + GtkStack *stack; + GtkWidget *remote_desktop_page; + GtkSwitch *view_only_switch; + GtkEntry *username_entry; + GtkPasswordEntry *password_entry; + GtkButton *tls_key_button; + GtkButton *tls_cert_button; +}; + +CC_PANEL_REGISTER (CcRemoteDesktopPanel, cc_remote_desktop_panel) + +#define GRD_RDP_SCHEMA_ID "org.gnome.desktop.remote-desktop" +#define GRD_RDP_CREDENTIALS_SCHEMA grd_rdp_credentials_get_schema () + +static const SecretSchema * +grd_rdp_credentials_get_schema (void) +{ + static const SecretSchema grd_rdp_credentials_schema = + { + .name = "org.gnome.RemoteDesktop.RdpCredentials", + .flags = SECRET_SCHEMA_NONE, + .attributes = + { + { "credentials", SECRET_SCHEMA_ATTRIBUTE_STRING }, + { "NULL", 0 }, + }, + }; + + return &grd_rdp_credentials_schema; +} + +static void +store_rdp_credentials (const char *username, + const char *password) +{ + GVariantBuilder builder; + char *credentials; + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (&builder, "{sv}", "username", g_variant_new_string (username)); + g_variant_builder_add (&builder, "{sv}", "password", g_variant_new_string (password)); + credentials = g_variant_print (g_variant_builder_end (&builder), TRUE); + + secret_password_store_sync (GRD_RDP_CREDENTIALS_SCHEMA, + SECRET_COLLECTION_DEFAULT, + "GNOME Remote Desktop RDP credentials", + credentials, + NULL, NULL, + NULL); + + g_free (credentials); +} + +static void +load_rdp_credentials (CcRemoteDesktopPanel *self) +{ + g_autoptr(GError) error = NULL; + g_autofree gchar *secret; + GVariant *variant = NULL; + const gchar *username = NULL; + const gchar *password = NULL; + + secret = secret_password_lookup_sync (GRD_RDP_CREDENTIALS_SCHEMA, + self->cancellable, + &error, + NULL); + if (error) { + g_warning ("Failed to get password: %s", error->message); + return; + } + + variant = g_variant_parse (NULL, secret, NULL, NULL, &error); + if (variant == NULL) + g_warning ("Invalid credentials format in the keyring: %s", error->message); + + g_variant_lookup (variant, "username", "&s", &username); + g_variant_lookup (variant, "password", "&s", &password); + + if (username != NULL) + gtk_editable_set_text (GTK_EDITABLE (self->username_entry), username); + if (password != NULL) + gtk_editable_set_text (GTK_EDITABLE (self->password_entry), password); +} + +static void +on_credential_entries_changed (CcRemoteDesktopPanel *self) +{ + const gchar *username = NULL; + const gchar *password = NULL; + + username = gtk_editable_get_text (GTK_EDITABLE (self->username_entry)); + password = gtk_editable_get_text (GTK_EDITABLE (self->password_entry)); + + if (username != NULL && password != NULL) + store_rdp_credentials (username, password); +} + +static void +on_tls_key_file_selected (GtkDialog *filechooser, + gint response, + CcRemoteDesktopPanel *self) +{ + g_autoptr(GFile) tls_key_file = NULL; + const gchar *path; + + if (response != GTK_RESPONSE_ACCEPT) + return; + + tls_key_file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (filechooser)); + path = g_file_get_path (tls_key_file); + g_settings_set_string (self->remote_desktop_settings, + "tls-key", path); + gtk_button_set_label (self->tls_key_button, path); + gtk_window_destroy (GTK_WINDOW (filechooser)); +} + +static void +on_tls_key_button_clicked (GtkWidget *widget, + CcRemoteDesktopPanel *self) +{ + GtkWindow *toplevel; + GtkWidget *filechooser; + + toplevel = (GtkWindow *) gtk_widget_get_native (GTK_WIDGET (self)); + filechooser = gtk_file_chooser_dialog_new (_("Select a TLS Key file"), + toplevel, + GTK_FILE_CHOOSER_ACTION_OPEN, + _("_Cancel"), GTK_RESPONSE_CANCEL, + _("_Open"), GTK_RESPONSE_ACCEPT, + NULL); + gtk_window_set_modal (GTK_WINDOW (filechooser), TRUE); + + g_signal_connect_object (filechooser, + "response", + G_CALLBACK (on_tls_key_file_selected), + self, + 0); + gtk_window_present (GTK_WINDOW (filechooser)); +} + +static void +on_tls_cert_file_selected (GtkDialog *filechooser, + gint response, + CcRemoteDesktopPanel *self) +{ + g_autoptr(GFile) tls_cert_file = NULL; + const gchar *path; + + if (response != GTK_RESPONSE_ACCEPT) + return; + + tls_cert_file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (filechooser)); + path = g_file_get_path (tls_cert_file); + g_settings_set_string (self->remote_desktop_settings, + "tls-cert", path); + gtk_button_set_label (self->tls_cert_button, path); + gtk_window_destroy (GTK_WINDOW (filechooser)); +} + +static void +on_tls_cert_button_clicked (GtkWidget *widget, + CcRemoteDesktopPanel *self) +{ + GtkWindow *toplevel; + GtkWidget *filechooser; + + toplevel = (GtkWindow *) gtk_widget_get_native (GTK_WIDGET (self)); + filechooser = gtk_file_chooser_dialog_new (_("Select a TLS Cert"), + toplevel, + GTK_FILE_CHOOSER_ACTION_OPEN, + _("_Cancel"), GTK_RESPONSE_CANCEL, + _("_Open"), GTK_RESPONSE_ACCEPT, + NULL); + gtk_window_set_modal (GTK_WINDOW (filechooser), TRUE); + + g_signal_connect_object (filechooser, + "response", + G_CALLBACK (on_tls_cert_file_selected), + self, + 0); + gtk_window_present (GTK_WINDOW (filechooser)); +} + +static void +remote_desktop_name_appeared (GDBusConnection *connection, + const gchar *name, + const gchar *name_owner, + gpointer user_data) +{ + CcRemoteDesktopPanel *self = CC_REMOTE_DESKTOP_PANEL (user_data); + + g_bus_unwatch_name (self->remote_desktop_name_watch); + self->remote_desktop_name_watch = 0; + + gtk_stack_set_visible_child (self->stack, self->remote_desktop_page); +} + +static void +check_remote_desktop_available (CcRemoteDesktopPanel *self) +{ + GSettingsSchemaSource *source; + g_autoptr(GSettingsSchema) schema = NULL; + + source = g_settings_schema_source_get_default (); + if (!source) + return; + + schema = g_settings_schema_source_lookup (source, GRD_RDP_SCHEMA_ID, TRUE); + if (!schema) + return; + + self->remote_desktop_name_watch = g_bus_watch_name (G_BUS_TYPE_SESSION, + "org.gnome.Mutter.RemoteDesktop", + G_BUS_NAME_WATCHER_FLAGS_NONE, + remote_desktop_name_appeared, + NULL, + self, + NULL); +} + +static void +cc_remote_desktop_panel_finalize (GObject *object) +{ + CcRemoteDesktopPanel *self = CC_REMOTE_DESKTOP_PANEL (object); + + if (self->remote_desktop_name_watch) + g_bus_unwatch_name (self->remote_desktop_name_watch); + self->remote_desktop_name_watch = 0; + + g_cancellable_cancel (self->cancellable); + g_clear_object (&self->cancellable); + g_clear_object (&self->remote_desktop_settings); + + G_OBJECT_CLASS (cc_remote_desktop_panel_parent_class)->finalize (object); +} + +static void +cc_remote_desktop_panel_class_init (CcRemoteDesktopPanelClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + oclass->finalize = cc_remote_desktop_panel_finalize; + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/remote-desktop/cc-remote-desktop-panel.ui"); + + gtk_widget_class_bind_template_child (widget_class, CcRemoteDesktopPanel, stack); + gtk_widget_class_bind_template_child (widget_class, CcRemoteDesktopPanel, remote_desktop_page); + gtk_widget_class_bind_template_child (widget_class, CcRemoteDesktopPanel, view_only_switch); + gtk_widget_class_bind_template_child (widget_class, CcRemoteDesktopPanel, password_entry); + gtk_widget_class_bind_template_child (widget_class, CcRemoteDesktopPanel, username_entry); + gtk_widget_class_bind_template_child (widget_class, CcRemoteDesktopPanel, tls_cert_button); + gtk_widget_class_bind_template_child (widget_class, CcRemoteDesktopPanel, tls_key_button); + + gtk_widget_class_bind_template_callback (widget_class, on_credential_entries_changed); + gtk_widget_class_bind_template_callback (widget_class, on_tls_cert_button_clicked); + gtk_widget_class_bind_template_callback (widget_class, on_tls_key_button_clicked); +} + +static void +cc_remote_desktop_panel_init (CcRemoteDesktopPanel *self) +{ + g_resources_register (cc_remote_desktop_get_resource ()); + + gtk_widget_init_template (GTK_WIDGET (self)); + + check_remote_desktop_available (self); + + self->cancellable = g_cancellable_new (); + + self->remote_desktop_settings = g_settings_new ("org.gnome.desktop.remote-desktop.rdp"); + + g_settings_bind (self->remote_desktop_settings, + "view-only", + self->view_only_switch, + "active", + G_SETTINGS_BIND_DEFAULT); + + g_settings_bind (self->remote_desktop_settings, + "tls-cert", + self->tls_cert_button, + "label", + G_SETTINGS_BIND_DEFAULT); + + g_settings_bind (self->remote_desktop_settings, + "tls-key", + self->tls_key_button, + "label", + G_SETTINGS_BIND_DEFAULT); + + load_rdp_credentials (self); +} diff --git a/panels/remote-desktop/cc-remote-desktop-panel.h b/panels/remote-desktop/cc-remote-desktop-panel.h new file mode 100644 index 000000000..daf39f9a9 --- /dev/null +++ b/panels/remote-desktop/cc-remote-desktop-panel.h @@ -0,0 +1,30 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * 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, see <http://www.gnu.org/licenses/>. + * + * Author: Felipe Borges <feborges@redhat.com> + */ + +#pragma once + +#include <shell/cc-panel.h> + +G_BEGIN_DECLS + +#define CC_TYPE_LOCK_PANEL (cc_remote_desktop_panel_get_type ()) +G_DECLARE_FINAL_TYPE (CcRemoteDesktopPanel, cc_remote_desktop_panel, CC, REMOTE_DESKTOP_PANEL, CcPanel) + +G_END_DECLS diff --git a/panels/remote-desktop/cc-remote-desktop-panel.ui b/panels/remote-desktop/cc-remote-desktop-panel.ui new file mode 100644 index 000000000..b24c6d092 --- /dev/null +++ b/panels/remote-desktop/cc-remote-desktop-panel.ui @@ -0,0 +1,96 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.18.1 --> +<interface> + <template class="CcRemoteDesktopPanel" parent="CcPanel"> + <child> + <object class="GtkStack" id="stack"> + <child> + <object class="AdwStatusPage"> + <property name="icon-name">preferences-desktop-remote-desktop-symbolic</property> + <property name="title">Remote desktop server not available</property> + </object> + </child> + <child> + <object class="AdwPreferencesPage" id="remote_desktop_page"> + <child> + <object class="AdwPreferencesGroup"> + <property name="description" translatable="yes">Remote desktop makes it possible to view and control your desktop from other computers.</property> + <child> + <object class="AdwActionRow"> + <property name="title" translatable="yes">Remote Control</property> + <property name="subtitle" translatable="yes">Allows control of the desktop as well as vieweing.</property> + <child> + <object class="GtkSwitch" id="view_only_switch"> + <property name="valign">center</property> + </object> + </child> + </object> + </child> + </object> + </child> + <child> + <object class="AdwPreferencesGroup"> + <property name="title" translatable="yes">Access Control</property> + <child> + <object class="AdwActionRow"> + <property name="title" translatable="yes">Username</property> + <child> + <object class="GtkEntry" id="username_entry"> + <property name="valign">center</property> + <signal name="changed" handler="on_credential_entries_changed" object="CcRemoteDesktopPanel" swapped="yes"/>/> + </object> + </child> + </object> + </child> + <child> + <object class="AdwActionRow"> + <property name="title" translatable="yes">Password</property> + <child> + <object class="GtkPasswordEntry" id="password_entry"> + <property name="valign">center</property> + <signal name="changed" handler="on_credential_entries_changed" object="CcRemoteDesktopPanel" swapped="yes"/>/> + </object> + </child> + </object> + </child> + <child> + <object class="AdwActionRow"> + <property name="title" translatable="yes">TLS Cert</property> + <child> + <object class="GtkButton" id="tls_cert_button"> + <property name="label" translatable="yes">Select TLS Certificate file...</property> + <property name="valign">center</property> + <signal name="clicked" handler="on_tls_cert_button_clicked"/> + </object> + </child> + </object> + </child> + <child> + <object class="AdwActionRow"> + <property name="title" translatable="yes">TLS Key</property> + <child> + <object class="GtkButton" id="tls_key_button"> + <property name="label" translatable="yes">Select TLS Key file...</property> + <property name="valign">center</property> + <signal name="clicked" handler="on_tls_key_button_clicked"/> + </object> + </child> + </object> + </child> + </object> + </child> + </object> + </child> + </object> + </child> + </template> + + <object class="GtkSizeGroup"> + <widgets> + <widget name="username_entry"/> + <widget name="password_entry"/> + <widget name="tls_cert_button"/> + <widget name="tls_key_button"/> + </widgets> + </object> +</interface> diff --git a/panels/remote-desktop/gnome-remote-desktop-panel.desktop.in.in b/panels/remote-desktop/gnome-remote-desktop-panel.desktop.in.in new file mode 100644 index 000000000..053c26043 --- /dev/null +++ b/panels/remote-desktop/gnome-remote-desktop-panel.desktop.in.in @@ -0,0 +1,19 @@ +[Desktop Entry] +Name=Remote Desktop +Comment=Configure your desktop to be controlled by other computers +Exec=gnome-control-center remote-desktop +# FIXME +# Translators: Do NOT translate or transliterate this text (this is an icon file name)! +Icon=preferences-desktop-remote-desktop-symbolic +Terminal=false +Type=Application +NoDisplay=true +StartupNotify=true +Categories=GNOME;GTK;Settings;DesktopSettings;X-GNOME-Settings-Panel;X-GNOME-PrivacySettings; +OnlyShowIn=GNOME;Unity; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-control-center +X-GNOME-Bugzilla-Component=privacy +X-GNOME-Bugzilla-Version=@VERSION@ +# Translators: Search terms to find the Privacy panel. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! +Keywords=privacy;remote;rdp;vnc;sharing; diff --git a/panels/remote-desktop/meson.build b/panels/remote-desktop/meson.build new file mode 100644 index 000000000..ce84b0e95 --- /dev/null +++ b/panels/remote-desktop/meson.build @@ -0,0 +1,45 @@ +panels_list += cappletname +desktop = 'gnome-@0@-panel.desktop'.format(cappletname) + +desktop_in = configure_file( + input: desktop + '.in.in', + output: desktop + '.in', + configuration: desktop_conf +) + +i18n.merge_file( + desktop, + type: 'desktop', + input: desktop_in, + output: desktop, + po_dir: po_dir, + install: true, + install_dir: control_center_desktopdir +) + +sources = files('cc-remote-desktop-panel.c') + +resource_data = files('cc-remote-desktop-panel.ui') + +sources += gnome.compile_resources( + 'cc-' + cappletname + '-resources', + cappletname + '.gresource.xml', + c_name: 'cc_' + cappletname.underscorify (), + dependencies: resource_data, + export: true +) + +cflags += '-DGNOMELOCALEDIR="@0@"'.format(control_center_localedir) + +deps = [ + dependency('gcr-base-3'), + dependency('libsecret-1'), +] + +panels_libs += static_library( + cappletname, + sources: sources, + include_directories: [top_inc, common_inc], + dependencies: common_deps + deps, + c_args: cflags +) diff --git a/panels/remote-desktop/remote-desktop.gresource.xml b/panels/remote-desktop/remote-desktop.gresource.xml new file mode 100644 index 000000000..aaaf13480 --- /dev/null +++ b/panels/remote-desktop/remote-desktop.gresource.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<gresources> + <gresource prefix="/org/gnome/control-center/remote-desktop"> + <file preprocess="xml-stripblanks">cc-remote-desktop-panel.ui</file> + </gresource> +</gresources> diff --git a/shell/cc-panel-list.c b/shell/cc-panel-list.c index 9ab6b7b80..b12cce131 100644 --- a/shell/cc-panel-list.c +++ b/shell/cc-panel-list.c @@ -398,6 +398,7 @@ static const gchar * const panel_order[] = { "usage", "lock", "diagnostics", + "remote-desktop", /* Devices page */ "sound", diff --git a/shell/cc-panel-loader.c b/shell/cc-panel-loader.c index 403a44267..b46284efd 100644 --- a/shell/cc-panel-loader.c +++ b/shell/cc-panel-loader.c @@ -53,6 +53,7 @@ extern GType cc_notifications_panel_get_type (void); extern GType cc_power_panel_get_type (void); extern GType cc_printers_panel_get_type (void); extern GType cc_region_panel_get_type (void); +extern GType cc_remote_desktop_panel_get_type (void); extern GType cc_removable_media_panel_get_type (void); extern GType cc_search_panel_get_type (void); extern GType cc_sharing_panel_get_type (void); @@ -124,6 +125,7 @@ static CcPanelLoaderVtable default_panels[] = PANEL_TYPE("power", cc_power_panel_get_type, NULL), PANEL_TYPE("printers", cc_printers_panel_get_type, NULL), PANEL_TYPE("region", cc_region_panel_get_type, NULL), + PANEL_TYPE("remote-desktop", cc_remote_desktop_panel_get_type, NULL), PANEL_TYPE("removable-media", cc_removable_media_panel_get_type, NULL), PANEL_TYPE("search", cc_search_panel_get_type, NULL), PANEL_TYPE("sharing", cc_sharing_panel_get_type, NULL), |