diff options
author | Felipe Borges <felipeborges@gnome.org> | 2019-02-04 15:46:16 +0000 |
---|---|---|
committer | Ondrej Holy <oholy@redhat.com> | 2019-02-06 11:53:56 +0000 |
commit | 02c288ab6f069a0c106323a93400f192a63cb67e (patch) | |
tree | a2dc988beda9ffb223ad9e91d40049166b9e1cb4 /panels/user-accounts | |
parent | 12ad6a1b18d58027939305468db4c5bee82a4a2f (diff) | |
download | gnome-control-center-02c288ab6f069a0c106323a93400f192a63cb67e.tar.gz |
user-accounts: Generate a default avatar for new users
When a user is created, we generate an avatar with their initials.
See https://gitlab.gnome.org/GNOME/Initiatives/issues/6
Diffstat (limited to 'panels/user-accounts')
-rw-r--r-- | panels/user-accounts/cc-avatar-chooser.c | 40 | ||||
-rw-r--r-- | panels/user-accounts/cc-user-panel.c | 2 | ||||
-rw-r--r-- | panels/user-accounts/user-utils.c | 180 | ||||
-rw-r--r-- | panels/user-accounts/user-utils.h | 5 |
4 files changed, 187 insertions, 40 deletions
diff --git a/panels/user-accounts/cc-avatar-chooser.c b/panels/user-accounts/cc-avatar-chooser.c index ca3c8d967..0db3adb8c 100644 --- a/panels/user-accounts/cc-avatar-chooser.c +++ b/panels/user-accounts/cc-avatar-chooser.c @@ -67,46 +67,6 @@ struct _CcAvatarChooser { G_DEFINE_TYPE (CcAvatarChooser, cc_avatar_chooser, GTK_TYPE_POPOVER) static void -set_user_icon_data (ActUser *user, - GdkPixbuf *pixbuf) -{ - gchar *path; - gint fd; - GOutputStream *stream; - GError *error; - - path = g_build_filename (g_get_tmp_dir (), "gnome-control-center-user-icon-XXXXXX", NULL); - fd = g_mkstemp (path); - - if (fd == -1) { - g_warning ("failed to create temporary file for image data"); - g_free (path); - return; - } - - stream = g_unix_output_stream_new (fd, TRUE); - - error = NULL; - if (!gdk_pixbuf_save_to_stream (pixbuf, stream, "png", NULL, &error, NULL)) { - g_warning ("failed to save image: %s", error->message); - g_error_free (error); - g_object_unref (stream); - return; - } - - g_object_unref (stream); - - act_user_set_icon_file (user, path); - - /* if we ever make the dbus call async, the g_remove call needs - * to wait for its completion - */ - g_remove (path); - - g_free (path); -} - -static void crop_dialog_response (GtkWidget *dialog, gint response_id, CcAvatarChooser *self) diff --git a/panels/user-accounts/cc-user-panel.c b/panels/user-accounts/cc-user-panel.c index ab933e47f..f71e83b1a 100644 --- a/panels/user-accounts/cc-user-panel.c +++ b/panels/user-accounts/cc-user-panel.c @@ -354,6 +354,7 @@ static void add_user (CcUserPanel *self) { CcAddUserDialog *dialog; + g_autoptr(GdkPixbuf) pixbuf = NULL; GtkWindow *toplevel; ActUser *user; @@ -364,6 +365,7 @@ add_user (CcUserPanel *self) gtk_dialog_run (GTK_DIALOG (dialog)); user = cc_add_user_dialog_get_user (dialog); + generate_user_avatar (user); if (user != NULL) reload_users (self, user); diff --git a/panels/user-accounts/user-utils.c b/panels/user-accounts/user-utils.c index 70e578887..c5dfa9c05 100644 --- a/panels/user-accounts/user-utils.c +++ b/panels/user-accounts/user-utils.c @@ -29,10 +29,14 @@ #include <pwd.h> #include <gio/gio.h> +#include <gio/gunixoutputstream.h> #include <glib/gi18n.h> +#include <glib/gstdio.h> #include "user-utils.h" +#define IMAGE_SIZE 512 + typedef struct { gchar *text; gchar *placeholder_str; @@ -469,3 +473,179 @@ round_image (GdkPixbuf *pixbuf, return dest; } + +static gchar * +extract_initials_from_name (const gchar *name) +{ + GString *initials; + g_autofree gchar *p = NULL; + g_autofree gchar *normalized = NULL; + gunichar unichar; + gpointer q = NULL; + + p = g_utf8_strup (name, -1); + normalized = g_utf8_normalize (g_strstrip (p), -1, G_NORMALIZE_DEFAULT_COMPOSE); + if (normalized == NULL) { + return NULL; + } + + initials = g_string_new (""); + + unichar = g_utf8_get_char (normalized); + g_string_append_unichar (initials, unichar); + + q = g_utf8_strrchr (normalized, -1, ' '); + if (q != NULL && g_utf8_next_char (q) != NULL) { + q = g_utf8_next_char (q); + + unichar = g_utf8_get_char (q); + g_string_append_unichar (initials, unichar); + } + + return g_string_free (initials, FALSE); +} + +static GdkRGBA +get_color_for_name (const gchar *name) +{ + // https://gitlab.gnome.org/Community/Design/HIG-app-icons/blob/master/GNOME%20HIG.gpl + static gdouble gnome_color_palette[][3] = { + { 98, 160, 234 }, + { 53, 132, 228 }, + { 28, 113, 216 }, + { 26, 95, 180 }, + { 87, 227, 137 }, + { 51, 209, 122 }, + { 46, 194, 126 }, + { 38, 162, 105 }, + { 248, 228, 92 }, + { 246, 211, 45 }, + { 245, 194, 17 }, + { 229, 165, 10 }, + { 255, 163, 72 }, + { 255, 120, 0 }, + { 230, 97, 0 }, + { 198, 70, 0 }, + { 237, 51, 59 }, + { 224, 27, 36 }, + { 192, 28, 40 }, + { 165, 29, 45 }, + { 192, 97, 203 }, + { 163, 71, 186 }, + { 129, 61, 156 }, + { 97, 53, 131 }, + { 181, 131, 90 }, + { 152, 106, 68 }, + { 134, 94, 60 }, + { 99, 69, 44 } + }; + + GdkRGBA color = { 255, 255, 255, 1.0 }; + guint hash; + gint number_of_colors; + gint idx; + + if (name == NULL || strlen (name) == 0) + return color; + + hash = g_str_hash (name); + number_of_colors = G_N_ELEMENTS (gnome_color_palette); + idx = hash % number_of_colors; + + color.red = gnome_color_palette[idx][0]; + color.green = gnome_color_palette[idx][1]; + color.blue = gnome_color_palette[idx][2]; + + return color; +} + +static cairo_surface_t * +generate_user_picture (const gchar *name) +{ + PangoFontDescription *font_desc; + g_autofree gchar *initials = extract_initials_from_name (name); + g_autofree gchar *font = g_strdup_printf ("Sans %d", (int)ceil (IMAGE_SIZE / 2.5)); + PangoLayout *layout; + GdkRGBA color = get_color_for_name (name); + cairo_surface_t *surface; + gint width, height; + cairo_t *cr; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + IMAGE_SIZE, + IMAGE_SIZE); + cr = cairo_create (surface); + cairo_rectangle (cr, 0, 0, IMAGE_SIZE, IMAGE_SIZE); + cairo_set_source_rgb (cr, color.red/255.0, color.green/255.0, color.blue/255.0); + cairo_fill (cr); + + /* Draw the initials on top */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + layout = pango_cairo_create_layout (cr); + pango_layout_set_text (layout, initials, -1); + font_desc = pango_font_description_from_string (font); + pango_layout_set_font_description (layout, font_desc); + pango_font_description_free (font_desc); + + pango_layout_get_size (layout, &width, &height); + cairo_translate (cr, IMAGE_SIZE/2, IMAGE_SIZE/2); + cairo_move_to (cr, - ((double)width / PANGO_SCALE)/2, - ((double)height/PANGO_SCALE)/2); + pango_cairo_show_layout (cr, layout); + cairo_destroy (cr); + + return surface; +} + +void +set_user_icon_data (ActUser *user, + GdkPixbuf *pixbuf) +{ + gchar *path; + gint fd; + GOutputStream *stream; + GError *error; + + path = g_build_filename (g_get_tmp_dir (), "gnome-control-center-user-icon-XXXXXX", NULL); + fd = g_mkstemp (path); + + if (fd == -1) { + g_warning ("failed to create temporary file for image data"); + g_free (path); + return; + } + + stream = g_unix_output_stream_new (fd, TRUE); + + error = NULL; + if (!gdk_pixbuf_save_to_stream (pixbuf, stream, "png", NULL, &error, NULL)) { + g_warning ("failed to save image: %s", error->message); + g_error_free (error); + g_object_unref (stream); + return; + } + + g_object_unref (stream); + + act_user_set_icon_file (user, path); + + /* if we ever make the dbus call async, the g_remove call needs + * to wait for its completion + */ + g_remove (path); + + g_free (path); +} + +void +generate_user_avatar (ActUser *user) +{ + g_autoptr(GdkPixbuf) pixbuf = NULL; + cairo_surface_t *surface; + + surface = generate_user_picture (act_user_get_real_name (user)); + + pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0, IMAGE_SIZE, IMAGE_SIZE); + cairo_surface_destroy (surface); + + set_user_icon_data (user, pixbuf); +} diff --git a/panels/user-accounts/user-utils.h b/panels/user-accounts/user-utils.h index 2c49524c3..a40f0d5d1 100644 --- a/panels/user-accounts/user-utils.h +++ b/panels/user-accounts/user-utils.h @@ -21,6 +21,7 @@ #pragma once #include <gtk/gtk.h> +#include <act/act.h> G_BEGIN_DECLS @@ -44,4 +45,8 @@ gboolean is_valid_username (const gchar *name, gchar **tip); GdkPixbuf *round_image (GdkPixbuf *pixbuf, gint icon_size); +void generate_user_avatar (ActUser *user); +void set_user_icon_data (ActUser *user, + GdkPixbuf *pixbuf); + G_END_DECLS |