1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
4
* Copyright (C) 2007 Ray Strode <rstrode@redhat.com>
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.
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.
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.
33
#include <glib/gi18n.h>
34
#include <glib/gstdio.h>
37
#include <gconf/gconf-client.h>
39
#include "gdm-user-manager.h"
40
#include "gdm-user-chooser-widget.h"
43
#define KEY_DISABLE_USER_LIST "/apps/gdm/simple-greeter/disable_user_list"
46
USER_NO_DISPLAY = 1 << 0,
47
USER_ACCOUNT_DISABLED = 1 << 1,
50
#define DEFAULT_USER_ICON "stock_person"
52
#define GDM_USER_CHOOSER_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_USER_CHOOSER_WIDGET, GdmUserChooserWidgetPrivate))
54
#define MAX_ICON_SIZE 128
56
struct GdmUserChooserWidgetPrivate
58
GdmUserManager *manager;
59
GtkIconTheme *icon_theme;
61
GdkPixbuf *logged_in_pixbuf;
62
GdkPixbuf *stock_person_pixbuf;
65
guint show_user_other : 1;
66
guint show_user_guest : 1;
67
guint show_user_auto : 1;
68
guint show_normal_users : 1;
70
guint has_user_other : 1;
82
static void gdm_user_chooser_widget_class_init (GdmUserChooserWidgetClass *klass);
83
static void gdm_user_chooser_widget_init (GdmUserChooserWidget *user_chooser_widget);
84
static void gdm_user_chooser_widget_finalize (GObject *object);
86
G_DEFINE_TYPE (GdmUserChooserWidget, gdm_user_chooser_widget, GDM_TYPE_CHOOSER_WIDGET)
88
static void add_user_other (GdmUserChooserWidget *widget);
89
static void remove_user_other (GdmUserChooserWidget *widget);
92
get_font_height_for_widget (GtkWidget *widget)
94
PangoFontMetrics *metrics;
95
PangoContext *context;
100
gtk_widget_ensure_style (widget);
101
context = gtk_widget_get_pango_context (widget);
102
metrics = pango_context_get_metrics (context,
103
widget->style->font_desc,
104
pango_context_get_language (context));
106
ascent = pango_font_metrics_get_ascent (metrics);
107
descent = pango_font_metrics_get_descent (metrics);
108
height = PANGO_PIXELS (ascent + descent);
109
pango_font_metrics_unref (metrics);
114
get_icon_height_for_widget (GtkWidget *widget)
119
font_height = get_font_height_for_widget (widget);
120
height = 3 * font_height;
121
if (height > MAX_ICON_SIZE) {
122
height = MAX_ICON_SIZE;
125
g_debug ("GdmUserChooserWidget: font height %d; using icon size %d", font_height, height);
131
update_other_user_visibility (GdmUserChooserWidget *widget)
135
if (!widget->priv->show_user_other) {
136
if (widget->priv->has_user_other) {
137
remove_user_other (widget);
143
number_of_users = gdm_chooser_widget_get_number_of_items (GDM_CHOOSER_WIDGET (widget));
145
/* we hide the Other user if it's the last one, and we show it
146
* if there's another user */
147
if (number_of_users == 1 && widget->priv->has_user_other) {
148
remove_user_other (widget);
149
} if (number_of_users >= 1 && !widget->priv->has_user_other) {
150
add_user_other (widget);
155
add_user_other (GdmUserChooserWidget *widget)
157
widget->priv->has_user_other = TRUE;
158
gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget),
159
GDM_USER_CHOOSER_USER_OTHER,
161
/* translators: This option prompts
162
* the user to type in a username
163
* manually instead of choosing from
166
C_("user", "Other..."),
167
_("Choose a different account"),
174
add_user_guest (GdmUserChooserWidget *widget)
176
gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget),
177
GDM_USER_CHOOSER_USER_GUEST,
178
widget->priv->stock_person_pixbuf,
180
_("Login as a temporary guest"),
184
update_other_user_visibility (widget);
188
add_user_auto (GdmUserChooserWidget *widget)
190
gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget),
191
GDM_USER_CHOOSER_USER_AUTO,
193
_("Automatic Login"),
194
_("Automatically login to the system after selecting options"),
198
update_other_user_visibility (widget);
202
remove_user_other (GdmUserChooserWidget *widget)
204
widget->priv->has_user_other = FALSE;
205
gdm_chooser_widget_remove_item (GDM_CHOOSER_WIDGET (widget),
206
GDM_USER_CHOOSER_USER_OTHER);
210
remove_user_guest (GdmUserChooserWidget *widget)
212
gdm_chooser_widget_remove_item (GDM_CHOOSER_WIDGET (widget),
213
GDM_USER_CHOOSER_USER_GUEST);
214
update_other_user_visibility (widget);
218
remove_user_auto (GdmUserChooserWidget *widget)
220
gdm_chooser_widget_remove_item (GDM_CHOOSER_WIDGET (widget),
221
GDM_USER_CHOOSER_USER_AUTO);
222
update_other_user_visibility (widget);
226
gdm_user_chooser_widget_set_show_user_other (GdmUserChooserWidget *widget,
229
g_return_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget));
231
if (widget->priv->show_user_other != show_user) {
232
widget->priv->show_user_other = show_user;
233
update_other_user_visibility (widget);
238
gdm_user_chooser_widget_set_show_user_guest (GdmUserChooserWidget *widget,
241
g_return_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget));
243
if (widget->priv->show_user_guest != show_user) {
244
widget->priv->show_user_guest = show_user;
246
add_user_guest (widget);
248
remove_user_guest (widget);
254
gdm_user_chooser_widget_set_show_user_auto (GdmUserChooserWidget *widget,
257
g_return_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget));
259
if (widget->priv->show_user_auto != show_user) {
260
widget->priv->show_user_auto = show_user;
262
add_user_auto (widget);
264
remove_user_auto (widget);
270
gdm_user_chooser_widget_get_chosen_user_name (GdmUserChooserWidget *widget)
272
g_return_val_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget), NULL);
274
return gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (widget));
278
gdm_user_chooser_widget_set_chosen_user_name (GdmUserChooserWidget *widget,
281
g_return_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget));
283
gdm_chooser_widget_set_active_item (GDM_CHOOSER_WIDGET (widget), name);
287
gdm_user_chooser_widget_set_show_only_chosen (GdmUserChooserWidget *widget,
288
gboolean show_only) {
289
g_return_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget));
291
gdm_chooser_widget_set_hide_inactive_items (GDM_CHOOSER_WIDGET (widget),
296
gdm_user_chooser_widget_set_property (GObject *object,
301
GdmUserChooserWidget *self;
303
self = GDM_USER_CHOOSER_WIDGET (object);
306
case PROP_SHOW_USER_AUTO:
307
gdm_user_chooser_widget_set_show_user_auto (self, g_value_get_boolean (value));
309
case PROP_SHOW_USER_GUEST:
310
gdm_user_chooser_widget_set_show_user_guest (self, g_value_get_boolean (value));
312
case PROP_SHOW_USER_OTHER:
313
gdm_user_chooser_widget_set_show_user_other (self, g_value_get_boolean (value));
316
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
322
gdm_user_chooser_widget_get_property (GObject *object,
327
GdmUserChooserWidget *self;
329
self = GDM_USER_CHOOSER_WIDGET (object);
332
case PROP_SHOW_USER_AUTO:
333
g_value_set_boolean (value, self->priv->show_user_auto);
335
case PROP_SHOW_USER_GUEST:
336
g_value_set_boolean (value, self->priv->show_user_guest);
338
case PROP_SHOW_USER_OTHER:
339
g_value_set_boolean (value, self->priv->show_user_other);
342
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
348
is_user_list_disabled (GdmUserChooserWidget *widget)
354
client = gconf_client_get_default ();
356
result = gconf_client_get_bool (client, KEY_DISABLE_USER_LIST, &error);
358
g_debug ("GdmUserChooserWidget: unable to get disable-user-list configuration: %s", error->message);
359
g_error_free (error);
361
g_object_unref (client);
367
add_user (GdmUserChooserWidget *widget,
372
gboolean is_logged_in;
375
if (!widget->priv->show_normal_users) {
379
size = get_icon_height_for_widget (GTK_WIDGET (widget));
380
pixbuf = gdm_user_render_icon (user, size);
381
if (pixbuf == NULL && widget->priv->stock_person_pixbuf != NULL) {
382
pixbuf = g_object_ref (widget->priv->stock_person_pixbuf);
385
tooltip = g_strdup_printf (_("Log in as %s"),
386
gdm_user_get_user_name (user));
388
is_logged_in = gdm_user_get_num_sessions (user) > 0;
390
g_debug ("GdmUserChooserWidget: User added name:%s logged-in:%d pixbuf:%p",
391
gdm_user_get_user_name (user),
395
gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget),
396
gdm_user_get_user_name (user),
398
gdm_user_get_display_name (user),
400
gdm_user_get_login_frequency (user),
405
if (pixbuf != NULL) {
406
g_object_unref (pixbuf);
409
update_other_user_visibility (widget);
413
on_user_added (GdmUserManager *manager,
415
GdmUserChooserWidget *widget)
417
/* wait for all users to be loaded */
418
if (! widget->priv->loaded) {
421
add_user (widget, user);
425
on_user_removed (GdmUserManager *manager,
427
GdmUserChooserWidget *widget)
429
const char *user_name;
431
g_debug ("GdmUserChooserWidget: User removed: %s", gdm_user_get_user_name (user));
432
/* wait for all users to be loaded */
433
if (! widget->priv->loaded) {
437
user_name = gdm_user_get_user_name (user);
439
gdm_chooser_widget_remove_item (GDM_CHOOSER_WIDGET (widget),
442
update_other_user_visibility (widget);
446
on_user_is_logged_in_changed (GdmUserManager *manager,
448
GdmUserChooserWidget *widget)
450
const char *user_name;
451
gboolean is_logged_in;
453
g_debug ("GdmUserChooserWidget: User logged in changed: %s", gdm_user_get_user_name (user));
455
user_name = gdm_user_get_user_name (user);
456
is_logged_in = gdm_user_get_num_sessions (user) > 0;
458
gdm_chooser_widget_set_item_in_use (GDM_CHOOSER_WIDGET (widget),
464
on_user_login_frequency_changed (GdmUserManager *manager,
466
GdmUserChooserWidget *widget)
468
const char *user_name;
471
g_debug ("GdmUserChooserWidget: User login frequency changed: %s", gdm_user_get_user_name (user));
473
user_name = gdm_user_get_user_name (user);
474
freq = gdm_user_get_login_frequency (user);
476
gdm_chooser_widget_set_item_priority (GDM_CHOOSER_WIDGET (widget),
482
on_users_loaded (GdmUserManager *manager,
483
GdmUserChooserWidget *widget)
486
gboolean list_visible;
488
g_debug ("GdmUserChooserWidget: Users loaded");
490
users = gdm_user_manager_list_users (manager);
491
while (users != NULL) {
492
add_user (widget, users->data);
493
users = g_slist_delete_link (users, users);
496
g_object_get (G_OBJECT (widget), "list-visible", &list_visible, NULL);
499
gtk_widget_grab_focus (GTK_WIDGET (widget));
501
widget->priv->loaded = TRUE;
503
gdm_chooser_widget_loaded (GDM_CHOOSER_WIDGET (widget));
507
load_users (GdmUserChooserWidget *widget)
510
if (widget->priv->show_normal_users) {
511
widget->priv->manager = gdm_user_manager_ref_default ();
512
g_signal_connect (widget->priv->manager,
514
G_CALLBACK (on_user_added),
516
g_signal_connect (widget->priv->manager,
518
G_CALLBACK (on_user_removed),
520
g_signal_connect (widget->priv->manager,
522
G_CALLBACK (on_users_loaded),
524
g_signal_connect (widget->priv->manager,
525
"user-is-logged-in-changed",
526
G_CALLBACK (on_user_is_logged_in_changed),
528
g_signal_connect (widget->priv->manager,
529
"user-login-frequency-changed",
530
G_CALLBACK (on_user_login_frequency_changed),
533
gdm_chooser_widget_loaded (GDM_CHOOSER_WIDGET (widget));
536
widget->priv->load_idle_id = 0;
542
gdm_user_chooser_widget_constructor (GType type,
543
guint n_construct_properties,
544
GObjectConstructParam *construct_properties)
546
GdmUserChooserWidget *widget;
548
widget = GDM_USER_CHOOSER_WIDGET (G_OBJECT_CLASS (gdm_user_chooser_widget_parent_class)->constructor (type,
549
n_construct_properties,
550
construct_properties));
552
widget->priv->show_normal_users = !is_user_list_disabled (widget);
554
widget->priv->load_idle_id = g_idle_add ((GSourceFunc)load_users, widget);
556
return G_OBJECT (widget);
560
gdm_user_chooser_widget_dispose (GObject *object)
562
GdmUserChooserWidget *widget;
564
widget = GDM_USER_CHOOSER_WIDGET (object);
566
G_OBJECT_CLASS (gdm_user_chooser_widget_parent_class)->dispose (object);
568
if (widget->priv->load_idle_id > 0) {
569
g_source_remove (widget->priv->load_idle_id);
570
widget->priv->load_idle_id = 0;
573
if (widget->priv->logged_in_pixbuf != NULL) {
574
g_object_unref (widget->priv->logged_in_pixbuf);
575
widget->priv->logged_in_pixbuf = NULL;
578
if (widget->priv->stock_person_pixbuf != NULL) {
579
g_object_unref (widget->priv->stock_person_pixbuf);
580
widget->priv->stock_person_pixbuf = NULL;
585
gdm_user_chooser_widget_class_init (GdmUserChooserWidgetClass *klass)
587
GObjectClass *object_class = G_OBJECT_CLASS (klass);
589
object_class->get_property = gdm_user_chooser_widget_get_property;
590
object_class->set_property = gdm_user_chooser_widget_set_property;
591
object_class->constructor = gdm_user_chooser_widget_constructor;
592
object_class->dispose = gdm_user_chooser_widget_dispose;
593
object_class->finalize = gdm_user_chooser_widget_finalize;
596
g_object_class_install_property (object_class,
598
g_param_spec_boolean ("show-user-auto",
602
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
603
g_object_class_install_property (object_class,
604
PROP_SHOW_USER_GUEST,
605
g_param_spec_boolean ("show-user-guest",
609
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
610
g_object_class_install_property (object_class,
611
PROP_SHOW_USER_OTHER,
612
g_param_spec_boolean ("show-user-other",
616
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
618
g_type_class_add_private (klass, sizeof (GdmUserChooserWidgetPrivate));
622
get_stock_person_pixbuf (GdmUserChooserWidget *widget)
627
size = get_icon_height_for_widget (GTK_WIDGET (widget));
629
pixbuf = gtk_icon_theme_load_icon (widget->priv->icon_theme,
639
get_logged_in_pixbuf (GdmUserChooserWidget *widget)
644
size = get_icon_height_for_widget (GTK_WIDGET (widget));
646
pixbuf = gtk_icon_theme_load_icon (widget->priv->icon_theme,
661
update_icons (GdmChooserWidget *widget,
668
gboolean *is_separate,
669
IconUpdateData *data)
671
if (data->old_icon == *image) {
672
*image = data->new_icon;
680
load_icons (GdmUserChooserWidget *widget)
682
GdkPixbuf *old_pixbuf;
685
if (widget->priv->logged_in_pixbuf != NULL) {
686
g_object_unref (widget->priv->logged_in_pixbuf);
688
widget->priv->logged_in_pixbuf = get_logged_in_pixbuf (widget);
690
old_pixbuf = widget->priv->stock_person_pixbuf;
691
widget->priv->stock_person_pixbuf = get_stock_person_pixbuf (widget);
692
/* update the icons in the model */
693
data.old_icon = old_pixbuf;
694
data.new_icon = widget->priv->stock_person_pixbuf;
695
gdm_chooser_widget_update_foreach_item (GDM_CHOOSER_WIDGET (widget),
696
(GdmChooserUpdateForeachFunc)update_icons,
698
if (old_pixbuf != NULL) {
699
g_object_unref (old_pixbuf);
704
on_icon_theme_changed (GtkIconTheme *icon_theme,
705
GdmUserChooserWidget *widget)
707
g_debug ("GdmUserChooserWidget: icon theme changed");
712
setup_icons (GdmUserChooserWidget *widget)
714
if (gtk_widget_has_screen (GTK_WIDGET (widget))) {
715
widget->priv->icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (widget)));
717
widget->priv->icon_theme = gtk_icon_theme_get_default ();
720
if (widget->priv->icon_theme != NULL) {
721
g_signal_connect (widget->priv->icon_theme,
723
G_CALLBACK (on_icon_theme_changed),
731
gdm_user_chooser_widget_init (GdmUserChooserWidget *widget)
733
widget->priv = GDM_USER_CHOOSER_WIDGET_GET_PRIVATE (widget);
735
gdm_chooser_widget_set_separator_position (GDM_CHOOSER_WIDGET (widget),
736
GDM_CHOOSER_WIDGET_POSITION_BOTTOM);
737
gdm_chooser_widget_set_in_use_message (GDM_CHOOSER_WIDGET (widget),
738
_("Currently logged in"));
740
setup_icons (widget);
744
gdm_user_chooser_widget_finalize (GObject *object)
746
GdmUserChooserWidget *widget;
748
g_return_if_fail (object != NULL);
749
g_return_if_fail (GDM_IS_USER_CHOOSER_WIDGET (object));
751
widget = GDM_USER_CHOOSER_WIDGET (object);
753
g_return_if_fail (widget->priv != NULL);
755
G_OBJECT_CLASS (gdm_user_chooser_widget_parent_class)->finalize (object);
759
gdm_user_chooser_widget_new (void)
763
object = g_object_new (GDM_TYPE_USER_CHOOSER_WIDGET,
766
return GTK_WIDGET (object);