summaryrefslogtreecommitdiff
path: root/panels/user-accounts
diff options
context:
space:
mode:
authorFelipe Borges <felipeborges@gnome.org>2019-02-04 15:46:16 +0000
committerOndrej Holy <oholy@redhat.com>2019-02-06 11:53:56 +0000
commit02c288ab6f069a0c106323a93400f192a63cb67e (patch)
treea2dc988beda9ffb223ad9e91d40049166b9e1cb4 /panels/user-accounts
parent12ad6a1b18d58027939305468db4c5bee82a4a2f (diff)
downloadgnome-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.c40
-rw-r--r--panels/user-accounts/cc-user-panel.c2
-rw-r--r--panels/user-accounts/user-utils.c180
-rw-r--r--panels/user-accounts/user-utils.h5
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