source: proiecte/PPPP/gdm/gui/simple-greeter/gdm-user.c @ 134

Last change on this file since 134 was 134, checked in by (none), 14 years ago

gdm sources with the modifications for webcam

File size: 36.2 KB
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2004-2005 James M. Cape <jcape@ignore-your.tv>.
4 * Copyright (C) 2007-2008 William Jon McCann <mccann@jhu.edu>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21#include <config.h>
22
23#include <float.h>
24#include <string.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <unistd.h>
28
29#include <glib/gi18n.h>
30#include <gio/gio.h>
31#include <gtk/gtk.h>
32
33#include "gdm-user-manager.h"
34#include "gdm-user-private.h"
35
36#define GDM_USER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDM_TYPE_USER, GdmUserClass))
37#define GDM_IS_USER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDM_TYPE_USER))
38#define GDM_USER_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS ((object), GDM_TYPE_USER, GdmUserClass))
39
40#define GLOBAL_FACEDIR    DATADIR "/faces"
41#define MAX_ICON_SIZE     128
42#define MAX_FILE_SIZE     65536
43#define MINIMAL_UID       100
44
45enum {
46        PROP_0,
47        PROP_MANAGER,
48        PROP_REAL_NAME,
49        PROP_DISPLAY_NAME,
50        PROP_USER_NAME,
51        PROP_UID,
52        PROP_HOME_DIR,
53        PROP_SHELL,
54        PROP_LOGIN_FREQUENCY,
55};
56
57enum {
58        ICON_CHANGED,
59        SESSIONS_CHANGED,
60        LAST_SIGNAL
61};
62
63struct _GdmUser {
64        GObject         parent;
65
66        GdmUserManager *manager;
67
68        uid_t           uid;
69        char           *user_name;
70        char           *real_name;
71        char           *display_name;
72        char           *home_dir;
73        char           *shell;
74        GList          *sessions;
75        gulong          login_frequency;
76
77        GFileMonitor   *icon_monitor;
78};
79
80typedef struct _GdmUserClass
81{
82        GObjectClass parent_class;
83
84        void (* icon_changed)     (GdmUser *user);
85        void (* sessions_changed) (GdmUser *user);
86} GdmUserClass;
87
88static void gdm_user_finalize     (GObject      *object);
89
90static guint signals[LAST_SIGNAL] = { 0 };
91
92G_DEFINE_TYPE (GdmUser, gdm_user, G_TYPE_OBJECT)
93
94static int
95session_compare (const char *a,
96                 const char *b)
97{
98        if (a == NULL) {
99                return 1;
100        } else if (b == NULL) {
101                return -1;
102        }
103
104        return strcmp (a, b);
105}
106
107void
108_gdm_user_add_session (GdmUser    *user,
109                       const char *ssid)
110{
111        GList *li;
112
113        g_return_if_fail (GDM_IS_USER (user));
114        g_return_if_fail (ssid != NULL);
115
116        li = g_list_find_custom (user->sessions, ssid, (GCompareFunc)session_compare);
117        if (li == NULL) {
118                g_debug ("GdmUser: adding session %s", ssid);
119                user->sessions = g_list_prepend (user->sessions, g_strdup (ssid));
120                g_signal_emit (user, signals[SESSIONS_CHANGED], 0);
121        } else {
122                g_debug ("GdmUser: session already present: %s", ssid);
123        }
124}
125
126void
127_gdm_user_remove_session (GdmUser    *user,
128                          const char *ssid)
129{
130        GList *li;
131
132        g_return_if_fail (GDM_IS_USER (user));
133        g_return_if_fail (ssid != NULL);
134
135        li = g_list_find_custom (user->sessions, ssid, (GCompareFunc)session_compare);
136        if (li != NULL) {
137                g_debug ("GdmUser: removing session %s", ssid);
138                g_free (li->data);
139                user->sessions = g_list_delete_link (user->sessions, li);
140                g_signal_emit (user, signals[SESSIONS_CHANGED], 0);
141        } else {
142                g_debug ("GdmUser: session not found: %s", ssid);
143        }
144}
145
146guint
147gdm_user_get_num_sessions (GdmUser    *user)
148{
149        return g_list_length (user->sessions);
150}
151
152GList *
153gdm_user_get_sessions (GdmUser *user)
154{
155        return user->sessions;
156}
157
158static void
159_gdm_user_set_login_frequency (GdmUser *user,
160                               gulong   login_frequency)
161{
162        user->login_frequency = login_frequency;
163        g_object_notify (G_OBJECT (user), "login-frequency");
164}
165
166static void
167gdm_user_set_property (GObject      *object,
168                       guint         param_id,
169                       const GValue *value,
170                       GParamSpec   *pspec)
171{
172        GdmUser *user;
173
174        user = GDM_USER (object);
175
176        switch (param_id) {
177        case PROP_MANAGER:
178                user->manager = g_value_get_object (value);
179                g_assert (user->manager);
180                break;
181        case PROP_LOGIN_FREQUENCY:
182                _gdm_user_set_login_frequency (user, g_value_get_ulong (value));
183                break;
184        default:
185                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
186                break;
187        }
188}
189
190static void
191gdm_user_get_property (GObject    *object,
192                       guint       param_id,
193                       GValue     *value,
194                       GParamSpec *pspec)
195{
196        GdmUser *user;
197
198        user = GDM_USER (object);
199
200        switch (param_id) {
201        case PROP_MANAGER:
202                g_value_set_object (value, user->manager);
203                break;
204        case PROP_USER_NAME:
205                g_value_set_string (value, user->user_name);
206                break;
207        case PROP_REAL_NAME:
208                g_value_set_string (value, user->real_name);
209                break;
210        case PROP_DISPLAY_NAME:
211                g_value_set_string (value, user->display_name);
212                break;
213        case PROP_HOME_DIR:
214                g_value_set_string (value, user->home_dir);
215                break;
216        case PROP_UID:
217                g_value_set_ulong (value, user->uid);
218                break;
219        case PROP_SHELL:
220                g_value_set_string (value, user->shell);
221                break;
222        case PROP_LOGIN_FREQUENCY:
223                g_value_set_ulong (value, user->login_frequency);
224                break;
225        default:
226                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
227                break;
228        }
229}
230
231static void
232gdm_user_class_init (GdmUserClass *class)
233{
234        GObjectClass *gobject_class;
235
236        gobject_class = G_OBJECT_CLASS (class);
237
238        gobject_class->set_property = gdm_user_set_property;
239        gobject_class->get_property = gdm_user_get_property;
240        gobject_class->finalize = gdm_user_finalize;
241
242        g_object_class_install_property (gobject_class,
243                                         PROP_MANAGER,
244                                         g_param_spec_object ("manager",
245                                                              _("Manager"),
246                                                              _("The user manager object this user is controlled by."),
247                                                              GDM_TYPE_USER_MANAGER,
248                                                              (G_PARAM_READWRITE |
249                                                               G_PARAM_CONSTRUCT_ONLY)));
250
251        g_object_class_install_property (gobject_class,
252                                         PROP_REAL_NAME,
253                                         g_param_spec_string ("real-name",
254                                                              "Real Name",
255                                                              "The real name to display for this user.",
256                                                              NULL,
257                                                              G_PARAM_READABLE));
258
259        g_object_class_install_property (gobject_class,
260                                         PROP_DISPLAY_NAME,
261                                         g_param_spec_string ("display-name",
262                                                              "Display Name",
263                                                              "The unique name to display for this user.",
264                                                              NULL,
265                                                              G_PARAM_READABLE));
266
267        g_object_class_install_property (gobject_class,
268                                         PROP_UID,
269                                         g_param_spec_ulong ("uid",
270                                                             "User ID",
271                                                             "The UID for this user.",
272                                                             0, G_MAXULONG, 0,
273                                                             G_PARAM_READABLE));
274        g_object_class_install_property (gobject_class,
275                                         PROP_USER_NAME,
276                                         g_param_spec_string ("user-name",
277                                                              "User Name",
278                                                              "The login name for this user.",
279                                                              NULL,
280                                                              G_PARAM_READABLE));
281        g_object_class_install_property (gobject_class,
282                                         PROP_HOME_DIR,
283                                         g_param_spec_string ("home-directory",
284                                                              "Home Directory",
285                                                              "The home directory for this user.",
286                                                              NULL,
287                                                              G_PARAM_READABLE));
288        g_object_class_install_property (gobject_class,
289                                         PROP_SHELL,
290                                         g_param_spec_string ("shell",
291                                                              "Shell",
292                                                              "The shell for this user.",
293                                                              NULL,
294                                                              G_PARAM_READABLE));
295        g_object_class_install_property (gobject_class,
296                                         PROP_LOGIN_FREQUENCY,
297                                         g_param_spec_ulong ("login-frequency",
298                                                             "login frequency",
299                                                             "login frequency",
300                                                             0,
301                                                             G_MAXULONG,
302                                                             0,
303                                                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
304
305        signals [ICON_CHANGED] =
306                g_signal_new ("icon-changed",
307                              G_TYPE_FROM_CLASS (class),
308                              G_SIGNAL_RUN_LAST,
309                              G_STRUCT_OFFSET (GdmUserClass, icon_changed),
310                              NULL, NULL,
311                              g_cclosure_marshal_VOID__VOID,
312                              G_TYPE_NONE, 0);
313        signals [SESSIONS_CHANGED] =
314                g_signal_new ("sessions-changed",
315                              G_TYPE_FROM_CLASS (class),
316                              G_SIGNAL_RUN_LAST,
317                              G_STRUCT_OFFSET (GdmUserClass, sessions_changed),
318                              NULL, NULL,
319                              g_cclosure_marshal_VOID__VOID,
320                              G_TYPE_NONE, 0);
321}
322
323
324static void
325on_icon_monitor_changed (GFileMonitor     *monitor,
326                         GFile            *file,
327                         GFile            *other_file,
328                         GFileMonitorEvent event_type,
329                         GdmUser          *user)
330{
331        g_debug ("Icon changed: %d", event_type);
332
333        if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
334            event_type != G_FILE_MONITOR_EVENT_CREATED) {
335                return;
336        }
337
338        _gdm_user_icon_changed (user);
339}
340
341static void
342update_icon_monitor (GdmUser *user)
343{
344        GFile  *file;
345        GError *error;
346        char   *path;
347
348        if (user->home_dir == NULL) {
349                return;
350        }
351
352        if (user->icon_monitor != NULL) {
353                g_file_monitor_cancel (user->icon_monitor);
354                user->icon_monitor = NULL;
355        }
356
357        path = g_build_filename (user->home_dir, ".face", NULL);
358        g_debug ("adding monitor for '%s'", path);
359        file = g_file_new_for_path (path);
360        error = NULL;
361        user->icon_monitor = g_file_monitor_file (file,
362                                                  G_FILE_MONITOR_NONE,
363                                                  NULL,
364                                                  &error);
365        if (user->icon_monitor != NULL) {
366                g_signal_connect (user->icon_monitor,
367                                  "changed",
368                                  G_CALLBACK (on_icon_monitor_changed),
369                                  user);
370        } else {
371                g_warning ("Unable to monitor %s: %s", path, error->message);
372                g_error_free (error);
373        }
374        g_object_unref (file);
375        g_free (path);
376}
377
378static void
379gdm_user_init (GdmUser *user)
380{
381        user->manager = NULL;
382        user->user_name = NULL;
383        user->real_name = NULL;
384        user->display_name = NULL;
385        user->sessions = NULL;
386}
387
388static void
389gdm_user_finalize (GObject *object)
390{
391        GdmUser *user;
392
393        user = GDM_USER (object);
394
395        g_file_monitor_cancel (user->icon_monitor);
396
397        g_free (user->user_name);
398        g_free (user->real_name);
399        g_free (user->display_name);
400
401        if (G_OBJECT_CLASS (gdm_user_parent_class)->finalize)
402                (*G_OBJECT_CLASS (gdm_user_parent_class)->finalize) (object);
403}
404
405/**
406 * _gdm_user_update:
407 * @user: the user object to update.
408 * @pwent: the user data to use.
409 *
410 * Updates the properties of @user using the data in @pwent.
411 *
412 * Since: 1.0
413 **/
414void
415_gdm_user_update (GdmUser             *user,
416                  const struct passwd *pwent)
417{
418        gchar *real_name;
419
420        g_return_if_fail (GDM_IS_USER (user));
421        g_return_if_fail (pwent != NULL);
422
423        g_object_freeze_notify (G_OBJECT (user));
424
425        /* Display Name */
426        if (pwent->pw_gecos && pwent->pw_gecos[0] != '\0') {
427                gchar *first_comma;
428                gchar *real_name_utf8;
429
430                real_name_utf8 = g_locale_to_utf8 (pwent->pw_gecos, -1, NULL, NULL, NULL);
431
432                first_comma = strchr (real_name_utf8, ',');
433                if (first_comma) {
434                        real_name = g_strndup (real_name_utf8, first_comma - real_name_utf8);
435                        g_free (real_name_utf8);
436                } else {
437                        real_name = real_name_utf8;
438                }
439
440                if (real_name[0] == '\0') {
441                        g_free (real_name);
442                        real_name = NULL;
443                }
444        } else {
445                real_name = NULL;
446        }
447
448        if ((real_name && !user->real_name) ||
449            (!real_name && user->real_name) ||
450            (real_name &&
451             user->real_name &&
452             strcmp (real_name, user->real_name) != 0)) {
453                g_free (user->real_name);
454                user->real_name = real_name;
455                g_object_notify (G_OBJECT (user), "real-name");
456        } else {
457                g_free (real_name);
458        }
459
460        /* Unique Display Name */
461        if ((!user->real_name && user->display_name) ||
462            (user->real_name &&
463             user->display_name &&
464             strncmp (user->real_name, user->display_name, strlen (user->real_name)) != 0)) {
465                g_free (user->display_name);
466                user->display_name = NULL;
467                g_object_notify (G_OBJECT (user), "display-name");
468        }
469
470        /* UID */
471        if (pwent->pw_uid != user->uid) {
472                user->uid = pwent->pw_uid;
473                g_object_notify (G_OBJECT (user), "uid");
474        }
475
476        /* Username */
477        if ((pwent->pw_name && !user->user_name) ||
478            (!pwent->pw_name && user->user_name) ||
479            (pwent->pw_name &&
480             user->user_name &&
481             strcmp (user->user_name, pwent->pw_name) != 0)) {
482                g_free (user->user_name);
483                user->user_name = g_strdup (pwent->pw_name);
484                g_object_notify (G_OBJECT (user), "user-name");
485        }
486
487        /* Home Directory */
488        if ((pwent->pw_dir && !user->home_dir) ||
489            (!pwent->pw_dir && user->home_dir) ||
490            strcmp (user->home_dir, pwent->pw_dir) != 0) {
491                g_free (user->home_dir);
492                user->home_dir = g_strdup (pwent->pw_dir);
493                g_object_notify (G_OBJECT (user), "home-directory");
494                g_signal_emit (user, signals[ICON_CHANGED], 0);
495        }
496
497        /* Shell */
498        if ((pwent->pw_shell && !user->shell) ||
499            (!pwent->pw_shell && user->shell) ||
500            (pwent->pw_shell &&
501             user->shell &&
502             strcmp (user->shell, pwent->pw_shell) != 0)) {
503                g_free (user->shell);
504                user->shell = g_strdup (pwent->pw_shell);
505                g_object_notify (G_OBJECT (user), "shell");
506        }
507
508        update_icon_monitor (user);
509
510        g_object_thaw_notify (G_OBJECT (user));
511}
512
513/**
514 * _gdm_user_icon_changed:
515 * @user: the user to emit the signal for.
516 *
517 * Emits the "icon-changed" signal for @user.
518 *
519 * Since: 1.0
520 **/
521void
522_gdm_user_icon_changed (GdmUser *user)
523{
524        g_return_if_fail (GDM_IS_USER (user));
525
526        g_signal_emit (user, signals[ICON_CHANGED], 0);
527}
528
529/**
530 * gdm_user_get_uid:
531 * @user: the user object to examine.
532 *
533 * Retrieves the ID of @user.
534 *
535 * Returns: a pointer to an array of characters which must not be modified or
536 *  freed, or %NULL.
537 *
538 * Since: 1.0
539 **/
540
541uid_t
542gdm_user_get_uid (GdmUser *user)
543{
544        g_return_val_if_fail (GDM_IS_USER (user), -1);
545
546        return user->uid;
547}
548
549/**
550 * gdm_user_get_real_name:
551 * @user: the user object to examine.
552 *
553 * Retrieves the display name of @user.
554 *
555 * Returns: a pointer to an array of characters which must not be modified or
556 *  freed, or %NULL.
557 *
558 * Since: 1.0
559 **/
560G_CONST_RETURN gchar *
561gdm_user_get_real_name (GdmUser *user)
562{
563        g_return_val_if_fail (GDM_IS_USER (user), NULL);
564
565        return (user->real_name ? user->real_name : user->user_name);
566}
567
568/**
569 * gdm_user_get_display_name:
570 * @user: the user object to examine.
571 *
572 * Retrieves the unique display name of @user.
573 *
574 * Returns: a pointer to an array of characters which must not be modified or
575 *  freed, or %NULL.
576 *
577 * Since: 1.0
578 **/
579G_CONST_RETURN gchar *
580gdm_user_get_display_name (GdmUser *user)
581{
582        g_return_val_if_fail (GDM_IS_USER (user), NULL);
583
584        return (user->display_name ? user->display_name
585                : gdm_user_get_real_name (user));
586}
587
588/**
589 * gdm_user_get_user_name:
590 * @user: the user object to examine.
591 *
592 * Retrieves the login name of @user.
593 *
594 * Returns: a pointer to an array of characters which must not be modified or
595 *  freed, or %NULL.
596 *
597 * Since: 1.0
598 **/
599
600G_CONST_RETURN gchar *
601gdm_user_get_user_name (GdmUser *user)
602{
603        g_return_val_if_fail (GDM_IS_USER (user), NULL);
604
605        return user->user_name;
606}
607
608/**
609 * gdm_user_get_home_directory:
610 * @user: the user object to examine.
611 *
612 * Retrieves the home directory of @user.
613 *
614 * Returns: a pointer to an array of characters which must not be modified or
615 *  freed, or %NULL.
616 *
617 * Since: 1.0
618 **/
619
620G_CONST_RETURN gchar *
621gdm_user_get_home_directory (GdmUser *user)
622{
623        g_return_val_if_fail (GDM_IS_USER (user), NULL);
624
625        return user->home_dir;
626}
627
628/**
629 * gdm_user_get_shell:
630 * @user: the user object to examine.
631 *
632 * Retrieves the login shell of @user.
633 *
634 * Returns: a pointer to an array of characters which must not be modified or
635 *  freed, or %NULL.
636 *
637 * Since: 1.0
638 **/
639
640G_CONST_RETURN gchar *
641gdm_user_get_shell (GdmUser *user)
642{
643        g_return_val_if_fail (GDM_IS_USER (user), NULL);
644
645        return user->shell;
646}
647
648gulong
649gdm_user_get_login_frequency (GdmUser *user)
650{
651        g_return_val_if_fail (GDM_IS_USER (user), 0);
652
653        return user->login_frequency;
654}
655
656/**
657 * _gdm_user_show_full_display_name:
658 * @user: the user object to examine.
659 *
660 * Updates the unique display name of @user to "Real Name (username)".
661 *
662 * Since: 1.0
663 **/
664void
665_gdm_user_show_full_display_name (GdmUser *user)
666{
667        char *uniq_name;
668
669        g_return_if_fail (GDM_IS_USER (user));
670
671        if (user->real_name != NULL) {
672                uniq_name = g_strdup_printf ("%s (%s)",
673                                             user->real_name,
674                                             user->user_name);
675        } else {
676                uniq_name = NULL;
677        }
678
679        if ((user->real_name && !user->display_name) ||
680            (!user->real_name && user->display_name) ||
681            (user->real_name &&
682             user->display_name &&
683             strcmp (uniq_name, user->display_name) != 0)) {
684                g_free (user->display_name);
685                user->display_name = uniq_name;
686                g_object_notify (G_OBJECT (user), "display-name");
687        } else {
688                g_free (uniq_name);
689        }
690}
691
692/**
693 * _gdm_user_show_short_display_name:
694 * @user: the user object to examine.
695 *
696 * Resets the unique display name of @user.
697 *
698 * Since: 1.0
699 **/
700void
701_gdm_user_show_short_display_name (GdmUser *user)
702{
703        g_return_if_fail (GDM_IS_USER (user));
704
705        if (user->display_name) {
706                g_free (user->display_name);
707                user->display_name = NULL;
708                g_object_notify (G_OBJECT (user), "display-name");
709        }
710}
711
712int
713gdm_user_collate (GdmUser *user1,
714                  GdmUser *user2)
715{
716        const char *str1;
717        const char *str2;
718        gulong      num1;
719        gulong      num2;
720
721        g_return_val_if_fail (GDM_IS_USER (user1), 0);
722        g_return_val_if_fail (GDM_IS_USER (user2), 0);
723
724        if (user1->real_name != NULL) {
725                str1 = user1->real_name;
726        } else {
727                str1 = user1->user_name;
728        }
729
730        if (user2->real_name != NULL) {
731                str2 = user2->real_name;
732        } else {
733                str2 = user2->user_name;
734        }
735
736        num1 = user1->login_frequency;
737        num2 = user2->login_frequency;
738        g_debug ("Login freq 1=%u 2=%u", (guint)num1, (guint)num2);
739        if (num1 > num2) {
740                return -1;
741        }
742
743        if (num1 < num2) {
744                return 1;
745        }
746
747        /* if login frequency is equal try names */
748        if (str1 == NULL && str2 != NULL) {
749                return -1;
750        }
751
752        if (str1 != NULL && str2 == NULL) {
753                return 1;
754        }
755
756        if (str1 == NULL && str2 == NULL) {
757                return 0;
758        }
759
760        return g_utf8_collate (str1, str2);
761}
762
763static gboolean
764check_user_file (const char *filename,
765                 gssize      max_file_size)
766{
767        struct stat fileinfo;
768
769        if (max_file_size < 0) {
770                max_file_size = G_MAXSIZE;
771        }
772
773        /* Exists/Readable? */
774        if (stat (filename, &fileinfo) < 0) {
775                g_debug ("File does not exist");
776                return FALSE;
777        }
778
779        /* Is a regular file */
780        if (G_UNLIKELY (!S_ISREG (fileinfo.st_mode))) {
781                g_debug ("File is not a regular file");
782                return FALSE;
783        }
784
785        /* Size is kosher? */
786        if (G_UNLIKELY (fileinfo.st_size > max_file_size)) {
787                g_debug ("File is too large");
788                return FALSE;
789        }
790
791        return TRUE;
792}
793
794static char *
795get_filesystem_type (const char *path)
796{
797        GFile      *file;
798        GFileInfo  *file_info;
799        GError     *error;
800        char       *filesystem_type;
801
802        file = g_file_new_for_path (path);
803        error = NULL;
804        file_info = g_file_query_filesystem_info (file,
805                                                  G_FILE_ATTRIBUTE_FILESYSTEM_TYPE,
806                                                  NULL,
807                                                  &error);
808        if (file_info == NULL) {
809                g_warning ("Unable to query filesystem type for %s: %s", path, error->message);
810                g_error_free (error);
811                g_object_unref (file);
812                return NULL;
813        }
814
815        filesystem_type = g_strdup (g_file_info_get_attribute_string (file_info,
816                                                                      G_FILE_ATTRIBUTE_FILESYSTEM_TYPE));
817        if (filesystem_type == NULL) {
818                g_warning ("GIO returned NULL filesystem type for %s", path);
819        }
820
821        g_object_unref (file);
822        g_object_unref (file_info);
823
824        return filesystem_type;
825}
826
827static GdkPixbuf *
828render_icon_from_cache (GdmUser *user,
829                        int      icon_size)
830{
831        GdkPixbuf  *retval;
832        char       *path;
833        gboolean    is_autofs;
834        gboolean    res;
835        char       *filesystem_type;
836
837        path = g_build_filename (GDM_CACHE_DIR, user->user_name, "face", NULL);
838        res = check_user_file (path,
839                               MAX_FILE_SIZE);
840        if (res) {
841                retval = gdk_pixbuf_new_from_file_at_size (path,
842                                                           icon_size,
843                                                           icon_size,
844                                                           NULL);
845        } else {
846                g_debug ("Could not access face icon %s", path);
847                retval = NULL;
848        }
849        g_free (path);
850
851        return retval;
852}
853
854static void
855curved_rectangle (cairo_t *cr,
856                  double   x0,
857                  double   y0,
858                  double   width,
859                  double   height,
860                  double   radius)
861{
862        double x1;
863        double y1;
864
865        x1 = x0 + width;
866        y1 = y0 + height;
867
868        if (width < FLT_EPSILON || height < FLT_EPSILON) {
869                return;
870        }
871
872        if (width / 2 < radius) {
873                if (height / 2 < radius) {
874                        cairo_move_to  (cr, x0, (y0 + y1) / 2);
875                        cairo_curve_to (cr, x0 ,y0, x0, y0, (x0 + x1) / 2, y0);
876                        cairo_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1) / 2);
877                        cairo_curve_to (cr, x1, y1, x1, y1, (x1 + x0) / 2, y1);
878                        cairo_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1) / 2);
879                } else {
880                        cairo_move_to  (cr, x0, y0 + radius);
881                        cairo_curve_to (cr, x0, y0, x0, y0, (x0 + x1) / 2, y0);
882                        cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius);
883                        cairo_line_to (cr, x1, y1 - radius);
884                        cairo_curve_to (cr, x1, y1, x1, y1, (x1 + x0) / 2, y1);
885                        cairo_curve_to (cr, x0, y1, x0, y1, x0, y1 - radius);
886                }
887        } else {
888                if (height / 2 < radius) {
889                        cairo_move_to  (cr, x0, (y0 + y1) / 2);
890                        cairo_curve_to (cr, x0, y0, x0 , y0, x0 + radius, y0);
891                        cairo_line_to (cr, x1 - radius, y0);
892                        cairo_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1) / 2);
893                        cairo_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1);
894                        cairo_line_to (cr, x0 + radius, y1);
895                        cairo_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1) / 2);
896                } else {
897                        cairo_move_to  (cr, x0, y0 + radius);
898                        cairo_curve_to (cr, x0 , y0, x0 , y0, x0 + radius, y0);
899                        cairo_line_to (cr, x1 - radius, y0);
900                        cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius);
901                        cairo_line_to (cr, x1, y1 - radius);
902                        cairo_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1);
903                        cairo_line_to (cr, x0 + radius, y1);
904                        cairo_curve_to (cr, x0, y1, x0, y1, x0, y1 - radius);
905                }
906        }
907
908        cairo_close_path (cr);
909}
910
911static cairo_surface_t *
912surface_from_pixbuf (GdkPixbuf *pixbuf)
913{
914        cairo_surface_t *surface;
915        cairo_t         *cr;
916
917        surface = cairo_image_surface_create (gdk_pixbuf_get_has_alpha (pixbuf) ?
918                                              CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24,
919                                              gdk_pixbuf_get_width (pixbuf),
920                                              gdk_pixbuf_get_height (pixbuf));
921        cr = cairo_create (surface);
922        gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
923        cairo_paint (cr);
924        cairo_destroy (cr);
925
926        return surface;
927}
928
929/**
930 * go_cairo_convert_data_to_pixbuf:
931 * @src: a pointer to pixel data in cairo format
932 * @dst: a pointer to pixel data in pixbuf format
933 * @width: image width
934 * @height: image height
935 * @rowstride: data rowstride
936 *
937 * Converts the pixel data stored in @src in CAIRO_FORMAT_ARGB32 cairo format
938 * to GDK_COLORSPACE_RGB pixbuf format and move them
939 * to @dst. If @src == @dst, pixel are converted in place.
940 **/
941
942static void
943go_cairo_convert_data_to_pixbuf (unsigned char *dst,
944                                 unsigned char const *src,
945                                 int width,
946                                 int height,
947                                 int rowstride)
948{
949        int i,j;
950        unsigned int t;
951        unsigned char a, b, c;
952
953        g_return_if_fail (dst != NULL);
954
955#define MULT(d,c,a,t) G_STMT_START { t = (a)? c * 255 / a: 0; d = t;} G_STMT_END
956
957        if (src == dst || src == NULL) {
958                for (i = 0; i < height; i++) {
959                        for (j = 0; j < width; j++) {
960#if G_BYTE_ORDER == G_LITTLE_ENDIAN
961                                MULT(a, dst[2], dst[3], t);
962                                MULT(b, dst[1], dst[3], t);
963                                MULT(c, dst[0], dst[3], t);
964                                dst[0] = a;
965                                dst[1] = b;
966                                dst[2] = c;
967#else
968                                MULT(a, dst[1], dst[0], t);
969                                MULT(b, dst[2], dst[0], t);
970                                MULT(c, dst[3], dst[0], t);
971                                dst[3] = dst[0];
972                                dst[0] = a;
973                                dst[1] = b;
974                                dst[2] = c;
975#endif
976                                dst += 4;
977                        }
978                        dst += rowstride - width * 4;
979                }
980        } else {
981                for (i = 0; i < height; i++) {
982                        for (j = 0; j < width; j++) {
983#if G_BYTE_ORDER == G_LITTLE_ENDIAN
984                                MULT(dst[0], src[2], src[3], t);
985                                MULT(dst[1], src[1], src[3], t);
986                                MULT(dst[2], src[0], src[3], t);
987                                dst[3] = src[3];
988#else
989                                MULT(dst[0], src[1], src[0], t);
990                                MULT(dst[1], src[2], src[0], t);
991                                MULT(dst[2], src[3], src[0], t);
992                                dst[3] = src[0];
993#endif
994                                src += 4;
995                                dst += 4;
996                        }
997                        src += rowstride - width * 4;
998                        dst += rowstride - width * 4;
999                }
1000        }
1001#undef MULT
1002}
1003
1004static void
1005cairo_to_pixbuf (guint8    *src_data,
1006                 GdkPixbuf *dst_pixbuf)
1007{
1008        unsigned char *src;
1009        unsigned char *dst;
1010        guint          w;
1011        guint          h;
1012        guint          rowstride;
1013
1014        w = gdk_pixbuf_get_width (dst_pixbuf);
1015        h = gdk_pixbuf_get_height (dst_pixbuf);
1016        rowstride = gdk_pixbuf_get_rowstride (dst_pixbuf);
1017
1018        dst = gdk_pixbuf_get_pixels (dst_pixbuf);
1019        src = src_data;
1020
1021        go_cairo_convert_data_to_pixbuf (dst, src, w, h, rowstride);
1022}
1023
1024static GdkPixbuf *
1025frame_pixbuf (GdkPixbuf *source)
1026{
1027        GdkPixbuf       *dest;
1028        cairo_t         *cr;
1029        cairo_surface_t *surface;
1030        guint            w;
1031        guint            h;
1032        guint            rowstride;
1033        int              frame_width;
1034        double           radius;
1035        guint8          *data;
1036
1037        frame_width = 2;
1038
1039        w = gdk_pixbuf_get_width (source) + frame_width * 2;
1040        h = gdk_pixbuf_get_height (source) + frame_width * 2;
1041        radius = w / 3.0;
1042
1043        dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
1044                               TRUE,
1045                               8,
1046                               w,
1047                               h);
1048        rowstride = gdk_pixbuf_get_rowstride (dest);
1049
1050
1051        data = g_new0 (guint8, h * rowstride);
1052
1053        surface = cairo_image_surface_create_for_data (data,
1054                                                       CAIRO_FORMAT_ARGB32,
1055                                                       w,
1056                                                       h,
1057                                                       rowstride);
1058        cr = cairo_create (surface);
1059        cairo_surface_destroy (surface);
1060
1061        /* set up image */
1062        cairo_rectangle (cr, 0, 0, w, h);
1063        cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0);
1064        cairo_fill (cr);
1065
1066        curved_rectangle (cr, frame_width, frame_width,
1067                          w - frame_width * 2, h - frame_width * 2,
1068                          radius);
1069        cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 0.3);
1070        cairo_fill_preserve (cr);
1071
1072        surface = surface_from_pixbuf (source);
1073        cairo_set_source_surface (cr, surface, frame_width, frame_width);
1074        cairo_fill (cr);
1075        cairo_surface_destroy (surface);
1076
1077        cairo_to_pixbuf (data, dest);
1078
1079        cairo_destroy (cr);
1080        g_free (data);
1081
1082        return dest;
1083}
1084
1085GdkPixbuf *
1086gdm_user_render_icon (GdmUser   *user,
1087                      gint       icon_size)
1088{
1089        GdkPixbuf    *pixbuf;
1090        GdkPixbuf    *framed;
1091        char         *path;
1092        char         *tmp;
1093        gboolean      res;
1094
1095        g_return_val_if_fail (GDM_IS_USER (user), NULL);
1096        g_return_val_if_fail (icon_size > 12, NULL);
1097
1098        path = NULL;
1099
1100        pixbuf = render_icon_from_cache (user, icon_size);
1101        if (pixbuf != NULL) {
1102                goto out;
1103        }
1104
1105        /* Try ${GlobalFaceDir}/${username} */
1106        path = g_build_filename (GLOBAL_FACEDIR, user->user_name, NULL);
1107        res = check_user_file (path,
1108                               MAX_FILE_SIZE);
1109        if (res) {
1110                pixbuf = gdk_pixbuf_new_from_file_at_size (path,
1111                                                           icon_size,
1112                                                           icon_size,
1113                                                           NULL);
1114        } else {
1115                g_debug ("Could not access global face icon %s", path);
1116                pixbuf = NULL;
1117        }
1118
1119        g_free (path);
1120        if (pixbuf != NULL) {
1121                goto out;
1122        }
1123
1124        /* Finally, ${GlobalFaceDir}/${username}.png */
1125        tmp = g_strconcat (user->user_name, ".png", NULL);
1126        path = g_build_filename (GLOBAL_FACEDIR, tmp, NULL);
1127        g_free (tmp);
1128        res = check_user_file (path,
1129                               MAX_FILE_SIZE);
1130        if (res) {
1131                pixbuf = gdk_pixbuf_new_from_file_at_size (path,
1132                                                           icon_size,
1133                                                           icon_size,
1134                                                           NULL);
1135        } else {
1136                g_debug ("Could not access global face icon %s", path);
1137                pixbuf = NULL;
1138        }
1139        g_free (path);
1140 out:
1141
1142        if (pixbuf != NULL) {
1143                framed = frame_pixbuf (pixbuf);
1144                if (framed != NULL) {
1145                        g_object_unref (pixbuf);
1146                        pixbuf = framed;
1147                }
1148        }
1149
1150        return pixbuf;
1151}
Note: See TracBrowser for help on using the repository browser.