2
* Copyright (C) 2003 Sun Microsystems, Inc.
3
* Copyright (C) 2006 Jonh Wendell <wendell@bani.com.br>
4
* Copyright © 2010 Codethink Limited
6
* This program is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License as
8
* published by the Free Software Foundation; either version 2 of the
9
* License, or (at your option) any later version.
11
* This program is distributed in the hope that it will be useful, but
12
* WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
22
* Mark McLoughlin <mark@skynet.ie>
23
* Jonh Wendell <wendell@bani.com.br>
24
* Ryan Lortie <desrt@desrt.ca>
29
#include "vino-connectivity-info.h"
30
#include "vino-radio-button.h"
31
#include "vino-message-box.h"
32
#include "vino-keyring.h"
34
#include <glib/gi18n.h>
39
GtkApplication parent_instance;
41
VinoConnectivityInfo *info;
44
typedef GtkApplicationClass VinoPreferencesClass;
46
static GType vino_preferences_get_type (void);
47
G_DEFINE_TYPE (VinoPreferences, vino_preferences, GTK_TYPE_APPLICATION)
50
/* We define three GSettings mappings here:
52
* First, a relatively boring boolean inversion mapping.
55
get_inverted (GValue *value,
59
g_value_set_boolean (value, !g_variant_get_boolean (variant));
64
set_inverted (const GValue *value,
65
const GVariantType *type,
68
return g_variant_new_boolean (!g_value_get_boolean (value));
71
/* Next, one that maps between the array-of-strings list of
72
* authentication mechanisms and a boolean that is FALSE if the 'none'
73
* and TRUE otherwise (ie: for 'vnc' in the list).
76
get_authtype (GValue *value,
83
g_variant_iter_init (&iter, variant);
84
g_value_set_boolean (value, TRUE);
86
while (g_variant_iter_next (&iter, "s", &type))
87
if (strcmp (type, "none") == 0)
88
g_value_set_boolean (value, FALSE);
94
set_authtype (const GValue *value,
95
const GVariantType *type,
98
const gchar *authtype;
100
if (g_value_get_boolean (value))
105
return g_variant_new_strv (&authtype, 1);
109
/* Finally, a somewhat evil mapping for the password setting:
111
* If the setting is 'keyring' then we load the password from the
112
* keyring. Else, it is assumed to be a base64-encoded string which is
113
* the actual password.
115
* On setting the password, we always first try to use the keyring. If
116
* that is successful we write 'keyring' to the settings. If it fails
117
* then we base64-encode the password and write it to the settings.
119
* Doing it this way ensures that there is no ambiguity about what the
120
* password is in the event that gnome-keyring becomes available then
124
get_password (GValue *value,
128
const gchar *setting;
130
setting = g_variant_get_string (variant, NULL);
132
if (strcmp (setting, "keyring") == 0)
134
g_value_take_string (value, vino_keyring_get_password ());
143
decoded = (gchar *) g_base64_decode (setting, &length);
145
if ((ok = g_utf8_validate (decoded, length, NULL)))
146
g_value_take_string (value, g_strndup (decoded, length));
153
set_password (const GValue *value,
154
const GVariantType *type,
160
string = g_value_get_string (value);
162
/* first, try to put it in the keyring */
163
if (vino_keyring_set_password (string))
164
return g_variant_new_string ("keyring");
166
/* if that failed, store it in GSettings, base64 */
167
base64 = g_base64_encode ((guchar *) string, strlen (string));
168
return g_variant_new_from_data (G_VARIANT_TYPE_STRING,
169
base64, strlen (base64) + 1,
170
TRUE, g_free, base64);
175
VINO_ICON_VISIBILITY_NEVER,
176
VINO_ICON_VISIBILITY_ALWAYS,
177
VINO_ICON_VISIBILITY_CLIENT
178
} VinoIconVisibility;
181
get_icon_visibility (GValue *value,
188
setting = g_variant_get_string (variant, NULL);
190
g_object_get (user_data, "name", &name, NULL);
192
/* If the button name matches the setting, it should be active. */
193
if (g_strcmp0 (name, setting) == 0)
194
g_value_set_boolean (value, TRUE);
202
set_icon_visibility (const GValue *value,
203
const GVariantType *type,
206
GVariant *variant = NULL;
209
/* Don't act unless the button has been activated (turned ON). */
210
if (!g_value_get_boolean (value))
213
/* GtkToggleButton *button = GTK_TOGGLE_BUTTON(user_data); */
214
g_object_get (user_data, "name", &name, NULL);
215
variant = g_variant_new_string (name);
223
vino_preferences_dialog_response (GtkWidget *widget,
227
GError *error = NULL;
232
case GTK_RESPONSE_HELP:
233
screen = gtk_widget_get_screen (widget);
235
if (!gtk_show_uri (screen, "help:ubuntu-help/sharing-desktop",
236
GDK_CURRENT_TIME, &error))
238
GtkWidget *message_dialog;
241
gtk_message_dialog_new (GTK_WINDOW (widget),
242
GTK_DIALOG_DESTROY_WITH_PARENT,
245
_("There was an error displaying help:\n%s"),
247
gtk_window_set_resizable (GTK_WINDOW (message_dialog), FALSE);
249
g_signal_connect (message_dialog, "response",
250
G_CALLBACK (gtk_widget_destroy),
253
gtk_widget_show (message_dialog);
255
g_error_free (error);
260
gtk_widget_destroy (widget);
265
vino_preferences_info_changed (VinoConnectivityInfo *info,
268
VinoMessageBox *message_box = VINO_MESSAGE_BOX (user_data);
269
gchar *internal_host, *external_host, *avahi_host;
270
guint16 internal_port, external_port;
272
if (!vino_connectivity_info_get (info,
273
&internal_host, &internal_port,
274
&external_host, &external_port,
277
vino_message_box_set_label (message_box,
278
_("Checking the connectivity of this machine..."));
279
vino_message_box_show_image (message_box);
284
if (external_host || internal_host)
291
message = g_string_new (NULL);
292
url = g_string_new (NULL);
293
host = external_host;
294
port = external_port;
298
g_string_append (message, _("Your desktop is only reachable over "
299
"the local network."));
300
g_string_append_c (message, ' ');
302
host = internal_host;
303
port = internal_port;
306
g_string_append_printf (url, "<a href=\"vnc://%s::%d\">%s</a>",
307
host, (guint) port, host);
311
g_string_append (url, _(" or "));
312
g_string_append_printf (url, "<a href=\"vnc://%s::%d\">%s</a>",
313
avahi_host, internal_port, avahi_host);
315
g_string_append_printf (message, _("Others can access your computer "
316
"using the address %s."), url->str);
318
vino_message_box_set_label (message_box, message->str);
319
g_string_free (message, TRUE);
320
g_string_free (url, TRUE);
323
vino_message_box_set_label (message_box,
324
_("Nobody can access your desktop."));
326
vino_message_box_hide_image (message_box);
328
g_free (internal_host);
329
g_free (external_host);
334
vino_preferences_connect_ui (VinoPreferences *app,
338
const gchar *setting;
340
const gchar *property;
341
GSettingsBindFlags flags;
342
GSettingsBindGetMapping get_mapping;
343
GSettingsBindSetMapping set_mapping;
345
{ "enabled", "allowed_toggle", "active", G_SETTINGS_BIND_DEFAULT, NULL, NULL },
347
{ "enabled", "control_settings", "sensitive", G_SETTINGS_BIND_GET, NULL, NULL },
348
{ "view-only", "view_only_toggle", "active", G_SETTINGS_BIND_DEFAULT, get_inverted, set_inverted },
350
{ "enabled", "security_settings", "sensitive", G_SETTINGS_BIND_GET, NULL, NULL },
351
{ "prompt-enabled", "prompt_enabled_toggle", "active", G_SETTINGS_BIND_DEFAULT, NULL, NULL },
352
{ "authentication-methods", "password_toggle", "active", G_SETTINGS_BIND_DEFAULT, get_authtype, set_authtype },
353
{ "authentication-methods", "password_box", "sensitive", G_SETTINGS_BIND_GET, get_authtype, NULL },
354
{ "vnc-password", "password_entry", "text", G_SETTINGS_BIND_DEFAULT, get_password, set_password },
355
{ "use-upnp", "use_upnp_toggle", "active", G_SETTINGS_BIND_DEFAULT, NULL, NULL },
357
{ "enabled", "notification_settings", "sensitive", G_SETTINGS_BIND_GET, NULL, NULL },
359
{ "icon-visibility", "icon_always_radio", "active", G_SETTINGS_BIND_DEFAULT, get_icon_visibility, set_icon_visibility },
360
{ "icon-visibility", "icon_client_radio", "active", G_SETTINGS_BIND_DEFAULT, get_icon_visibility, set_icon_visibility },
361
{ "icon-visibility", "icon_never_radio", "active", G_SETTINGS_BIND_DEFAULT, get_icon_visibility, set_icon_visibility }
367
settings = g_settings_new ("org.gnome.Vino");
369
for (i = 0; i < G_N_ELEMENTS (bindings); i++)
371
GObject *object = gtk_builder_get_object (builder, bindings[i].name);
372
g_settings_bind_with_mapping (settings, bindings[i].setting,
374
bindings[i].property,
376
bindings[i].get_mapping,
377
bindings[i].set_mapping,
381
window = gtk_builder_get_object (builder, "vino_dialog");
382
g_signal_connect (window, "response",
383
G_CALLBACK (vino_preferences_dialog_response), NULL);
385
/* Remove reporting of reachability from network to workaround GNOME bug
387
* TODO: Fix the bug and remove this workaround. */
389
app->info = vino_connectivity_info_new (gdk_screen_get_number (gtk_window_get_screen (window)));
390
g_signal_connect (app->info, "changed",
391
G_CALLBACK (vino_preferences_info_changed),
392
gtk_builder_get_object (builder, "message"));
393
vino_preferences_info_changed (app->info,
394
gtk_builder_get_object (builder, "message"));
397
g_object_unref (settings);
398
g_object_unref (builder);
404
vino_preferences_create_window (GApplication *g_app)
406
VinoPreferences *app = (VinoPreferences *) g_app;
407
GError *error = NULL;
412
vino_radio_button_get_type ();
413
vino_message_box_get_type ();
415
#define VINO_UI_FILE "vino-preferences.ui"
416
if (g_file_test (VINO_UI_FILE, G_FILE_TEST_EXISTS))
417
ui_file = VINO_UI_FILE;
419
ui_file = VINO_UIDIR "/" VINO_UI_FILE;
422
builder = gtk_builder_new ();
423
if (!gtk_builder_add_from_file (builder, ui_file, &error))
425
g_warning ("Unable to load ui file '%s': %s", ui_file, error->message);
426
g_error_free (error);
429
window = vino_preferences_connect_ui (app, builder);
430
gtk_window_set_application (GTK_WINDOW (window), GTK_APPLICATION (app));
431
gtk_widget_show_all(GTK_WIDGET(window));
435
vino_preferences_finalize (GObject *object)
437
VinoPreferences *app = (VinoPreferences *) object;
439
/* Remove reporting of reachability from network to workaround GNOME bug
441
* TODO: Fix the bug and remove this workaround. */
443
g_object_unref (app->info);
446
G_OBJECT_CLASS (vino_preferences_parent_class)->finalize (object);
450
vino_preferences_init (VinoPreferences *app)
454
static GtkApplication *
455
vino_preferences_new (void)
459
return g_object_new (vino_preferences_get_type (),
460
"application-id", "org.gnome.Vino.Preferences",
461
"flags", G_APPLICATION_FLAGS_NONE,
466
vino_preferences_activate (GApplication *app)
470
list = gtk_application_get_windows (GTK_APPLICATION(app));
473
gtk_window_present (GTK_WINDOW (list->data));
475
vino_preferences_create_window (app);
479
vino_preferences_class_init (VinoPreferencesClass *class)
481
GObjectClass *object_class = G_OBJECT_CLASS (class);
483
G_APPLICATION_CLASS (class)->activate = vino_preferences_activate;
484
object_class->finalize = vino_preferences_finalize;
488
main (int argc, char **argv)
493
bindtextdomain (GETTEXT_PACKAGE, VINO_LOCALEDIR);
494
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
495
textdomain (GETTEXT_PACKAGE);
497
gtk_init (&argc, &argv);
498
app = vino_preferences_new ();
499
status = g_application_run (G_APPLICATION(app), argc, argv);
500
g_object_unref (app);
501
/* g_settings_sync() is not required with GApplication in recent versions of
502
* Gio, bug 653914. */
503
#if GLIB_CHECK_VERSION (2, 29, 2)