Add CcHostnameEntry widget and use it in the info panel

https://bugzilla.gnome.org/show_bug.cgi?id=687772
This commit is contained in:
Thomas Wood 2013-01-08 11:46:13 +00:00
parent b577e6a679
commit f3a35fb573
12 changed files with 393 additions and 256 deletions

View file

@ -4,6 +4,8 @@ INCLUDES = \
$(CHEESE_CFLAGS) \
-I$(top_srcdir)/libgd
all-local: check-local
bin_PROGRAMS = gnome-control-center
BUILT_SOURCES = \
@ -31,6 +33,10 @@ gnome_control_center_SOURCES = \
cc-panel.h \
cc-shell.c \
cc-shell.h \
hostname-helper.c \
hostname-helper.h \
cc-hostname-entry.c \
cc-hostname-entry.h \
$(MARSHAL_FILES)
gnome_control_center_LDFLAGS = -export-dynamic
@ -102,4 +108,14 @@ EXTRA_DIST = \
CLEANFILES = $(BUILT_SOURCES) $(completion_DATA)
DISTCLEANFILES = gnome-control-center.desktop gnome-control-center.desktop.in
noinst_PROGRAMS = test-hostname
test_hostname_SOURCES = hostname-helper.c hostname-helper.h test-hostname.c
test_hostname_LDADD = $(PANEL_LIBS) $(INFO_PANEL_LIBS)
test_hostname_CFLAGS = $(INCLUDES)
EXTRA_DIST = hostnames-test.txt
check-local: test-hostname
$(builddir)/test-hostname $(srcdir)/hostnames-test.txt > /dev/null
-include $(top_srcdir)/git.mk

299
shell/cc-hostname-entry.c Normal file
View file

@ -0,0 +1,299 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2013 Intel, Inc
* Copyright (C) 2011,2012 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.
*
*/
#include "cc-hostname-entry.h"
#include "hostname-helper.h"
#include <polkit/polkit.h>
G_DEFINE_TYPE (CcHostnameEntry, cc_hostname_entry, GTK_TYPE_ENTRY)
#define HOSTNAME_ENTRY_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_HOSTNAME_ENTRY, CcHostnameEntryPrivate))
#define SET_HOSTNAME_TIMEOUT 1
struct _CcHostnameEntryPrivate
{
GDBusProxy *hostnamed_proxy;
guint set_hostname_timeout_source_id;
};
static void
cc_hostname_entry_set_hostname (CcHostnameEntry *self)
{
char *hostname;
GVariant *variant;
GError *error = NULL;
const gchar *text;
text = gtk_entry_get_text (GTK_ENTRY (self));
g_debug ("Setting PrettyHostname to '%s'", text);
variant = g_dbus_proxy_call_sync (self->priv->hostnamed_proxy,
"SetPrettyHostname",
g_variant_new ("(sb)", text, FALSE),
G_DBUS_CALL_FLAGS_NONE,
-1, NULL, &error);
if (variant == NULL)
{
g_warning ("Could not set PrettyHostname: %s", error->message);
g_error_free (error);
error = NULL;
}
else
{
g_variant_unref (variant);
}
/* Set the static hostname */
hostname = pretty_hostname_to_static (text, FALSE);
g_assert (hostname);
g_debug ("Setting StaticHostname to '%s'", hostname);
variant = g_dbus_proxy_call_sync (self->priv->hostnamed_proxy,
"SetStaticHostname",
g_variant_new ("(sb)", hostname, FALSE),
G_DBUS_CALL_FLAGS_NONE,
-1, NULL, &error);
if (variant == NULL)
{
g_warning ("Could not set StaticHostname: %s", error->message);
g_error_free (error);
}
else
{
g_variant_unref (variant);
}
g_free (hostname);
}
static char *
get_hostname_property (CcHostnameEntry *self,
const char *property)
{
CcHostnameEntryPrivate *priv = self->priv;
GVariant *variant;
char *str;
if (!priv->hostnamed_proxy)
return g_strdup ("");
variant = g_dbus_proxy_get_cached_property (priv->hostnamed_proxy,
property);
if (!variant)
{
GError *error = NULL;
GVariant *inner;
/* Work around systemd-hostname not sending us back
* the property value when changing values */
variant = g_dbus_proxy_call_sync (priv->hostnamed_proxy,
"org.freedesktop.DBus.Properties.Get",
g_variant_new ("(ss)", "org.freedesktop.hostname1", property),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error);
if (variant == NULL)
{
g_warning ("Failed to get property '%s': %s", property, error->message);
g_error_free (error);
return NULL;
}
g_variant_get (variant, "(v)", &inner);
str = g_variant_dup_string (inner, NULL);
g_variant_unref (variant);
}
else
{
str = g_variant_dup_string (variant, NULL);
g_variant_unref (variant);
}
return str;
}
static char *
cc_hostname_entry_get_display_hostname (CcHostnameEntry *self)
{
char *str;
str = get_hostname_property (self, "PrettyHostname");
/* Empty strings means that we need to fallback */
if (str != NULL &&
*str == '\0')
{
g_free (str);
str = get_hostname_property (self, "Hostname");
}
return str;
}
static gboolean
set_hostname_timeout (CcHostnameEntry *self)
{
self->priv->set_hostname_timeout_source_id = 0;
cc_hostname_entry_set_hostname (self);
return FALSE;
}
static void
remove_hostname_timeout (CcHostnameEntry *entry)
{
CcHostnameEntryPrivate *priv = entry->priv;
if (priv->set_hostname_timeout_source_id)
g_source_remove (priv->set_hostname_timeout_source_id);
priv->set_hostname_timeout_source_id = 0;
}
static void
reset_hostname_timeout (CcHostnameEntry *entry)
{
remove_hostname_timeout (entry);
entry->priv->set_hostname_timeout_source_id = g_timeout_add_seconds (SET_HOSTNAME_TIMEOUT,
(GSourceFunc) set_hostname_timeout,
entry);
}
static void
text_changed_cb (CcHostnameEntry *entry)
{
reset_hostname_timeout (entry);
}
static void
cc_hostname_entry_dispose (GObject *object)
{
CcHostnameEntry *entry = CC_HOSTNAME_ENTRY (object);
CcHostnameEntryPrivate *priv = entry->priv;
if (priv->set_hostname_timeout_source_id)
{
remove_hostname_timeout (entry);
set_hostname_timeout (entry);
}
g_clear_object (&priv->hostnamed_proxy);
G_OBJECT_CLASS (cc_hostname_entry_parent_class)->dispose (object);
}
static void
cc_hostname_entry_constructed (GObject *self)
{
CcHostnameEntryPrivate *priv = CC_HOSTNAME_ENTRY (self)->priv;
GError *error = NULL;
GPermission *permission;
char *str;
permission = polkit_permission_new_sync ("org.freedesktop.hostname1.set-static-hostname",
NULL, NULL, NULL);
/* Is hostnamed installed? */
if (permission == NULL)
{
g_debug ("Will not show hostname, hostnamed not installed");
gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
return;
}
if (g_permission_get_allowed (permission))
gtk_widget_set_sensitive (GTK_WIDGET (self), TRUE);
else
{
g_debug ("Not allowed to change the hostname");
gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
}
gtk_widget_set_sensitive (GTK_WIDGET (self),
g_permission_get_allowed (permission));
priv->hostnamed_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
"org.freedesktop.hostname1",
"/org/freedesktop/hostname1",
"org.freedesktop.hostname1",
NULL,
&error);
/* This could only happen if the policy file was installed
* but not hostnamed, which points to a system bug */
if (priv->hostnamed_proxy == NULL)
{
g_debug ("Couldn't get hostnamed to start, bailing: %s", error->message);
g_error_free (error);
return;
}
str = cc_hostname_entry_get_display_hostname (CC_HOSTNAME_ENTRY (self));
if (str != NULL)
gtk_entry_set_text (GTK_ENTRY (self), str);
else
gtk_entry_set_text (GTK_ENTRY (self), "");
g_free (str);
g_signal_connect (G_OBJECT (self), "changed", G_CALLBACK (text_changed_cb),
self);
}
static void
cc_hostname_entry_class_init (CcHostnameEntryClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (CcHostnameEntryPrivate));
object_class->constructed = cc_hostname_entry_constructed;
object_class->dispose = cc_hostname_entry_dispose;
}
static void
cc_hostname_entry_init (CcHostnameEntry *self)
{
self->priv = HOSTNAME_ENTRY_PRIVATE (self);
}
CcHostnameEntry *
cc_hostname_entry_new (void)
{
return g_object_new (CC_TYPE_HOSTNAME_ENTRY, NULL);
}
gchar*
cc_hostname_entry_get_hostname (CcHostnameEntry *entry)
{
return get_hostname_property (entry, "Hostname");
}

73
shell/cc-hostname-entry.h Normal file
View file

@ -0,0 +1,73 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2013 Intel, 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.
*
*/
#ifndef __CC_HOSTNAME_ENTRY_H__
#define __CC_HOSTNAME_ENTRY_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define CC_TYPE_HOSTNAME_ENTRY cc_hostname_entry_get_type()
#define CC_HOSTNAME_ENTRY(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
CC_TYPE_HOSTNAME_ENTRY, CcHostnameEntry))
#define CC_HOSTNAME_ENTRY_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), \
CC_TYPE_HOSTNAME_ENTRY, CcHostnameEntryClass))
#define CC_IS_HOSTNAME_ENTRY(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
CC_TYPE_HOSTNAME_ENTRY))
#define CC_IS_HOSTNAME_ENTRY_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
CC_TYPE_HOSTNAME_ENTRY))
#define CC_HOSTNAME_ENTRY_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
CC_TYPE_HOSTNAME_ENTRY, CcHostnameEntryClass))
typedef struct _CcHostnameEntry CcHostnameEntry;
typedef struct _CcHostnameEntryClass CcHostnameEntryClass;
typedef struct _CcHostnameEntryPrivate CcHostnameEntryPrivate;
struct _CcHostnameEntry
{
GtkEntry parent;
CcHostnameEntryPrivate *priv;
};
struct _CcHostnameEntryClass
{
GtkEntryClass parent_class;
};
GType cc_hostname_entry_get_type (void) G_GNUC_CONST;
CcHostnameEntry *cc_hostname_entry_new (void);
gchar* cc_hostname_entry_get_hostname (CcHostnameEntry *entry);
G_END_DECLS
#endif /* __CC_HOSTNAME_ENTRY_H__ */

173
shell/hostname-helper.c Normal file
View file

@ -0,0 +1,173 @@
/*
* Copyright (C) 2011 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.
*
*/
#include <glib.h>
#include <string.h>
#include "hostname-helper.h"
static char *
allowed_chars (void)
{
GString *s;
char i;
s = g_string_new (NULL);
for (i = 'a'; i <= 'z'; i++)
g_string_append_c (s, i);
for (i = 'A'; i <= 'Z'; i++)
g_string_append_c (s, i);
for (i = '0'; i <= '9'; i++)
g_string_append_c (s, i);
g_string_append_c (s, '-');
return g_string_free (s, FALSE);
}
static char *
remove_leading_dashes (char *input)
{
char *start;
for (start = input; *start && (*start == '-'); start++)
;
g_memmove (input, start, strlen (start) + 1);
return input;
}
static gboolean
is_empty (const char *input)
{
if (input == NULL ||
*input == '\0')
return TRUE;
return FALSE;
}
static char *
remove_trailing_dashes (char *input)
{
int len;
len = strlen (input);
while (len--) {
if (input[len] == '-')
input[len] = '\0';
else
break;
}
return input;
}
static char *
remove_apostrophes (char *input)
{
char *apo;
while ((apo = strchr (input, '\'')) != NULL)
g_memmove (apo, apo + 1, strlen (apo));
return input;
}
static char *
remove_duplicate_dashes (char *input)
{
char *dashes;
while ((dashes = strstr (input, "--")) != NULL)
g_memmove (dashes, dashes + 1, strlen (dashes));
return input;
}
#define CHECK if (is_empty (result)) goto bail
char *
pretty_hostname_to_static (const char *pretty,
gboolean for_display)
{
char *result;
char *valid_chars;
g_return_val_if_fail (pretty != NULL, NULL);
g_return_val_if_fail (g_utf8_validate (pretty, -1, NULL), NULL);
g_debug ("Input: '%s'", pretty);
/* Transform the pretty hostname to ASCII */
result = g_convert (pretty,
-1,
"ASCII//TRANSLIT//IGNORE",
"UTF-8",
NULL,
NULL,
NULL);
g_debug ("\ttranslit: '%s'", result);
CHECK;
/* Remove apostrophes */
result = remove_apostrophes (result);
g_debug ("\tapostrophes: '%s'", result);
CHECK;
/* Remove all the not-allowed chars */
valid_chars = allowed_chars ();
result = g_strcanon (result, valid_chars, '-');
g_free (valid_chars);
g_debug ("\tcanon: '%s'", result);
CHECK;
/* Remove the leading dashes */
result = remove_leading_dashes (result);
g_debug ("\tleading: '%s'", result);
CHECK;
/* Remove trailing dashes */
result = remove_trailing_dashes (result);
g_debug ("\ttrailing: '%s'", result);
CHECK;
/* Remove duplicate dashes */
result = remove_duplicate_dashes (result);
g_debug ("\tduplicate: '%s'", result);
CHECK;
/* Lower case */
if (!for_display) {
char *tmp;
tmp = g_ascii_strdown (result, -1);
g_free (result);
result = tmp;
}
return result;
bail:
g_free (result);
return g_strdup ("localhost");
}
#undef CHECK

21
shell/hostname-helper.h Normal file
View file

@ -0,0 +1,21 @@
/*
* Copyright (C) 2011 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.
*
*/
char *pretty_hostname_to_static (const char *pretty,
gboolean for_display);

11
shell/hostnames-test.txt Normal file
View file

@ -0,0 +1,11 @@
# Pretty hostname, tab, display hostname, tab, real hostname
Lennart's PC Lennarts-PC lennarts-pc
Müllers Computer Mullers-Computer mullers-computer
Voran! Voran voran
Es war einmal ein Männlein Es-war-einmal-ein-Mannlein es-war-einmal-ein-mannlein
Jawoll. Ist doch wahr! Jawoll-Ist-doch-wahr jawoll-ist-doch-wahr
レナート localhost localhost
!!! localhost localhost
...zack!!! zack!... zack-zack zack-zack
Bãstien's computer... Foo-bar Bastiens-computer-Foo-bar bastiens-computer-foo-bar
localhost localhost

79
shell/test-hostname.c Normal file
View file

@ -0,0 +1,79 @@
#include "config.h"
#include <glib.h>
#include <glib/gi18n.h>
#include <locale.h>
#include "hostname-helper.h"
int main (int argc, char **argv)
{
char *result;
guint i;
char *contents;
char **lines;
char *locale;
/* Running in some locales will
* break the tests as "ü" will be transliterated to
* "ue" in de_DE, and 'u"' in the C locale.
*
* Work around that by forcing en_US with UTF-8 in
* our tests
* https://bugzilla.gnome.org/show_bug.cgi?id=650342 */
locale = setlocale (LC_ALL, "en_US.UTF-8");
if (locale == NULL) {
g_debug("Missing en_US.UTF-8 locale, ignoring test.");
return 0;
}
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
if (g_file_get_contents (argv[1], &contents, NULL, NULL) == FALSE) {
g_warning ("Failed to load '%s'", argv[1]);
return 1;
}
lines = g_strsplit (contents, "\n", -1);
if (lines == NULL) {
g_warning ("Test file is empty");
return 1;
}
for (i = 0; lines[i] != NULL; i++) {
char *utf8;
char **items;
if (*lines[i] == '#')
continue;
if (*lines[i] == '\0')
break;
items = g_strsplit (lines[i], "\t", -1);
utf8 = g_locale_from_utf8 (items[0], -1, NULL, NULL, NULL);
result = pretty_hostname_to_static (items[0], FALSE);
if (g_strcmp0 (result, items[2]) != 0)
g_error ("Result for '%s' doesn't match '%s' (got: '%s')",
utf8, items[2], result);
else
g_debug ("Result for '%s' matches '%s'",
utf8, result);
g_free (result);
g_free (utf8);
result = pretty_hostname_to_static (items[0], TRUE);
utf8 = g_locale_from_utf8 (items[0], -1, NULL, NULL, NULL);
if (g_strcmp0 (result, items[1]) != 0)
g_error ("Result for '%s' doesn't match '%s' (got: '%s')",
utf8, items[1], result);
else
g_debug ("Result for '%s' matches '%s'",
utf8, result);
g_free (result);
g_free (utf8);
g_strfreev (items);
}
g_strfreev (lines);
return 0;
}