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
This commit is contained in:
Felipe Borges 2019-02-04 15:46:16 +00:00 committed by Ondrej Holy
parent 12ad6a1b18
commit 02c288ab6f
4 changed files with 187 additions and 40 deletions

View file

@ -66,46 +66,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,

View file

@ -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);

View file

@ -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);
}

View file

@ -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