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:
parent
12ad6a1b18
commit
02c288ab6f
4 changed files with 187 additions and 40 deletions
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue