1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3
* Copyright (C) 2004-2005 William Jon McCann <mccann@jhu.edu>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
* Authors: William Jon McCann <mccann@jhu.edu>
30
#include <glib/gprintf.h>
31
#include <glib/gstdio.h>
32
#include <glib/gi18n.h>
33
#include <gdk/gdkkeysyms.h>
35
#include <X11/XKBlib.h>
38
/* for fast user switching */
39
#include <libgnomevfs/gnome-vfs-init.h>
41
#include "gs-lock-plug.h"
45
#include "fusa-manager.h"
47
/* Profiling stuff adapted from gtkfilechooserdefault */
49
#undef PROFILE_LOCK_DIALOG
50
#ifdef PROFILE_LOCK_DIALOG
52
#define PROFILE_INDENT 4
53
static int profile_indent;
56
profile_add_indent (int indent)
58
profile_indent += indent;
59
if (profile_indent < 0)
60
g_error ("You screwed up your indentation");
64
_gs_lock_plug_profile_log (const char *func,
73
profile_add_indent (indent);
75
g_get_current_time (&now);
77
if (profile_indent == 0)
78
str = g_strdup_printf ("MARK %ld.%6.6ld: %s: %s %s %s", now.tv_sec, now.tv_usec, G_STRLOC, func, msg1 ? msg1 : "", msg2 ? msg2 : "");
80
str = g_strdup_printf ("MARK %ld.%6.6ld: %s: %*c %s %s %s", now.tv_sec, now.tv_usec, G_STRLOC, profile_indent - 1, ' ', func, msg1 ? msg1 : "", msg2 ? msg2 : "");
82
fprintf (stderr, "%s\n", str);
86
profile_add_indent (indent);
89
#define profile_start(x, y) _gs_lock_plug_profile_log (G_STRFUNC, PROFILE_INDENT, x, y)
90
#define profile_end(x, y) _gs_lock_plug_profile_log (G_STRFUNC, -PROFILE_INDENT, x, y)
91
#define profile_msg(x, y) _gs_lock_plug_profile_log (NULL, 0, x, y)
93
#define profile_start(x, y)
94
#define profile_end(x, y)
95
#define profile_msg(x, y)
104
#define FACE_ICON_SIZE 48
105
#define DIALOG_TIMEOUT_MSEC 60000
107
static void gs_lock_plug_class_init (GSLockPlugClass *klass);
108
static void gs_lock_plug_init (GSLockPlug *plug);
109
static void gs_lock_plug_finalize (GObject *object);
111
static gboolean password_check_idle_cb (GSLockPlug *plug);
113
#define GS_LOCK_PLUG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GS_TYPE_LOCK_PLUG, GSLockPlugPrivate))
115
struct GSLockPlugPrivate
118
GtkWidget *username_label;
119
GtkWidget *password_entry;
120
GtkWidget *capslock_label;
121
GtkWidget *status_label;
122
GtkWidget *user_treeview;
124
GtkWidget *ok_button;
125
GtkWidget *cancel_button;
126
GtkWidget *logout_button;
127
GtkWidget *switch_button;
129
FusaManager *fusa_manager;
131
gboolean caps_lock_on;
132
gboolean switch_enabled;
133
gboolean logout_enabled;
138
guint password_check_idle_id;
139
guint response_idle_id;
144
typedef struct _ResponseData ResponseData;
163
static GObjectClass *parent_class = NULL;
164
static guint lock_plug_signals [LAST_SIGNAL];
166
G_DEFINE_TYPE (GSLockPlug, gs_lock_plug, GTK_TYPE_PLUG);
169
gs_lock_plug_style_set (GtkWidget *widget,
170
GtkStyle *previous_style)
174
if (GTK_WIDGET_CLASS (parent_class)->style_set)
175
GTK_WIDGET_CLASS (parent_class)->style_set (widget, previous_style);
177
plug = GS_LOCK_PLUG (widget);
179
gtk_container_set_border_width (GTK_CONTAINER (plug->vbox), 24);
180
gtk_box_set_spacing (GTK_BOX (plug->vbox), 12);
182
gtk_container_set_border_width (GTK_CONTAINER (plug->action_area), 0);
183
gtk_box_set_spacing (GTK_BOX (plug->action_area), 5);
187
manager_new_console_cb (FusaManager *manager,
188
FusaDisplay *display,
192
GSLockPlug *plug = data;
194
lock_plug_signals [RESPONSE],
196
GS_LOCK_PLUG_RESPONSE_CANCEL);
200
do_user_switch (GSLockPlug *plug,
201
FusaDisplay *display)
205
if (gtk_widget_has_screen (plug->priv->user_treeview)) {
206
screen = gtk_widget_get_screen (plug->priv->user_treeview);
208
screen = gdk_screen_get_default ();
212
fusa_manager_activate_display (plug->priv->fusa_manager, display, screen,
213
manager_new_console_cb, plug, NULL);
217
fusa_manager_new_console (plug->priv->fusa_manager, screen,
218
manager_new_console_cb, plug, NULL);
230
switch_user_response (GSLockPlug *plug)
232
FusaDisplay *display = NULL;
234
GtkTreeSelection *selection;
240
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (plug->priv->user_treeview));
241
gtk_tree_selection_get_selected (selection,
244
gtk_tree_model_get (model, &iter, NAME_COLUMN, &name, -1);
246
&& strcmp (name, "__new_user") != 0
247
&& strcmp (name, "__separator") != 0) {
248
user = fusa_manager_get_user (plug->priv->fusa_manager, name);
249
displays = fusa_user_get_displays (user);
251
/* FIXME: just pick the first one for now */
252
display = displays->data;
258
do_user_switch (plug, display);
262
set_status_text (GSLockPlug *plug,
265
gtk_label_set_text (GTK_LABEL (plug->priv->status_label), text);
269
gs_lock_plug_response (GSLockPlug *plug,
274
new_response = response_id;
276
g_return_if_fail (GS_IS_LOCK_PLUG (plug));
278
/* Act only on response IDs we recognize */
279
if (!(response_id == GS_LOCK_PLUG_RESPONSE_OK
280
|| response_id == GS_LOCK_PLUG_RESPONSE_CANCEL)) {
284
if (plug->priv->idle_id > 0) {
285
g_source_remove (plug->priv->idle_id);
286
plug->priv->idle_id = 0;
289
if (plug->priv->password_check_idle_id > 0) {
290
g_source_remove (plug->priv->password_check_idle_id);
291
plug->priv->password_check_idle_id = 0;
294
if (plug->priv->response_idle_id > 0) {
295
g_source_remove (plug->priv->response_idle_id);
296
plug->priv->response_idle_id = 0;
299
if (response_id == GS_LOCK_PLUG_RESPONSE_CANCEL) {
300
gtk_entry_set_text (GTK_ENTRY (plug->priv->password_entry), "");
303
if (response_id == GS_LOCK_PLUG_RESPONSE_OK) {
304
gint current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (plug->priv->notebook));
306
if (current_page == 0) {
307
gtk_widget_set_sensitive (plug->priv->password_entry, FALSE);
308
set_status_text (plug, _("Checking password..."));
310
plug->priv->password_check_idle_id = g_idle_add ((GSourceFunc)password_check_idle_cb,
315
switch_user_response (plug);
321
lock_plug_signals [RESPONSE],
327
response_idle_cb (GSLockPlug *plug)
329
plug->priv->response_idle_id = 0;
331
gs_lock_plug_response (plug, GS_LOCK_PLUG_RESPONSE_CANCEL);
337
monitor_progress (GSLockPlug *plug)
344
g_get_current_time (&now);
346
elapsed = (now.tv_sec - plug->priv->start_time.tv_sec) * 1000
347
+ (now.tv_usec - plug->priv->start_time.tv_usec) / 1000;
348
remaining = plug->priv->timeout - elapsed;
350
if ((remaining <= 0) || (remaining > plug->priv->timeout)) {
351
message = g_strdup (_("Time has expired."));
352
gtk_widget_set_sensitive (plug->priv->password_entry, FALSE);
353
set_status_text (plug, message);
356
if (plug->priv->response_idle_id == 0)
357
plug->priv->response_idle_id = g_timeout_add (1000,
358
(GSourceFunc)response_idle_cb,
367
capslock_update (GSLockPlug *plug,
371
plug->priv->caps_lock_on = is_on;
374
gtk_label_set_text (GTK_LABEL (plug->priv->capslock_label),
375
_("You have the Caps Lock key on."));
377
gtk_label_set_text (GTK_LABEL (plug->priv->capslock_label),
381
/* adapted from GDM2 */
383
is_capslock_on (void)
388
dsp = GDK_DISPLAY ();
390
if (XkbGetIndicatorState (dsp, XkbUseCoreKbd, &states) != Success)
393
return (states & ShiftMask) != 0;
397
restart_monitor_progress (GSLockPlug *plug)
399
if (plug->priv->idle_id > 0) {
400
g_source_remove (plug->priv->idle_id);
401
plug->priv->idle_id = 0;
404
g_get_current_time (&plug->priv->start_time);
405
plug->priv->idle_id = g_timeout_add (50,
406
(GSourceFunc)monitor_progress,
411
gs_lock_plug_show (GtkWidget *widget)
413
profile_start ("start", NULL);
415
profile_start ("start", "parent");
416
if (GTK_WIDGET_CLASS (parent_class)->show)
417
GTK_WIDGET_CLASS (parent_class)->show (widget);
418
profile_end ("end", "parent");
420
capslock_update (GS_LOCK_PLUG (widget), is_capslock_on ());
422
restart_monitor_progress (GS_LOCK_PLUG (widget));
424
profile_end ("end", NULL);
428
gs_lock_plug_hide (GtkWidget *widget)
430
if (GTK_WIDGET_CLASS (parent_class)->hide)
431
GTK_WIDGET_CLASS (parent_class)->hide (widget);
435
gs_lock_plug_set_logout_enabled (GSLockPlug *plug,
436
gboolean logout_enabled)
438
g_return_if_fail (GS_LOCK_PLUG (plug));
440
if (plug->priv->logout_enabled == logout_enabled)
443
plug->priv->logout_enabled = logout_enabled;
444
g_object_notify (G_OBJECT (plug), "logout-enabled");
447
gtk_widget_show (plug->priv->logout_button);
449
gtk_widget_hide (plug->priv->logout_button);
453
gs_lock_plug_set_switch_enabled (GSLockPlug *plug,
454
gboolean switch_enabled)
456
g_return_if_fail (GS_LOCK_PLUG (plug));
458
if (plug->priv->switch_enabled == switch_enabled)
461
plug->priv->switch_enabled = switch_enabled;
462
g_object_notify (G_OBJECT (plug), "switch-enabled");
465
gtk_widget_show (plug->priv->switch_button);
467
gtk_widget_hide (plug->priv->switch_button);
471
gs_lock_plug_set_property (GObject *object,
478
self = GS_LOCK_PLUG (object);
481
case PROP_LOGOUT_ENABLED:
482
gs_lock_plug_set_logout_enabled (self, g_value_get_boolean (value));
484
case PROP_SWITCH_ENABLED:
485
gs_lock_plug_set_switch_enabled (self, g_value_get_boolean (value));
488
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
494
gs_lock_plug_get_property (GObject *object,
501
self = GS_LOCK_PLUG (object);
504
case PROP_LOGOUT_ENABLED:
505
g_value_set_boolean (value, self->priv->logout_enabled);
507
case PROP_SWITCH_ENABLED:
508
g_value_set_boolean (value, self->priv->switch_enabled);
511
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
517
gs_lock_plug_class_init (GSLockPlugClass *klass)
519
GObjectClass *object_class = G_OBJECT_CLASS (klass);
520
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
522
parent_class = g_type_class_peek_parent (klass);
524
object_class->finalize = gs_lock_plug_finalize;
525
object_class->get_property = gs_lock_plug_get_property;
526
object_class->set_property = gs_lock_plug_set_property;
528
widget_class->style_set = gs_lock_plug_style_set;
529
widget_class->show = gs_lock_plug_show;
530
widget_class->hide = gs_lock_plug_hide;
532
g_type_class_add_private (klass, sizeof (GSLockPlugPrivate));
535
lock_plug_signals [RESPONSE] = g_signal_new ("response",
536
G_OBJECT_CLASS_TYPE (klass),
538
G_STRUCT_OFFSET (GSLockPlugClass, response),
540
g_cclosure_marshal_VOID__INT,
544
g_object_class_install_property (object_class,
546
g_param_spec_boolean ("logout-enabled",
551
g_object_class_install_property (object_class,
553
g_param_spec_boolean ("switch-enabled",
561
password_check_idle_cb (GSLockPlug *plug)
563
const char *typed_password;
565
char *local_password;
567
plug->priv->password_check_idle_id = 0;
569
typed_password = gtk_entry_get_text (GTK_ENTRY (plug->priv->password_entry));
570
local_password = g_locale_from_utf8 (typed_password, strlen (typed_password), NULL, NULL, NULL);
572
null_password = g_strnfill (strlen (typed_password) + 1, '\b');
573
gtk_entry_set_text (GTK_ENTRY (plug->priv->password_entry), null_password);
574
gtk_entry_set_text (GTK_ENTRY (plug->priv->password_entry), "");
575
g_free (null_password);
577
if (validate_password (local_password, FALSE)) {
579
lock_plug_signals [RESPONSE],
581
GS_LOCK_PLUG_RESPONSE_OK);
583
if (plug->priv->response_idle_id == 0)
584
plug->priv->response_idle_id = g_timeout_add (1000,
585
(GSourceFunc)response_idle_cb,
588
set_status_text (plug, _("That password was incorrect."));
591
memset (local_password, '\b', strlen (local_password));
592
g_free (local_password);
598
get_ok_button_for_page (gint page)
603
const char *label = NULL;
605
align = gtk_alignment_new (0.5, 0.5, 0, 0);
606
hbox = gtk_hbox_new (FALSE, 2);
607
gtk_container_add (GTK_CONTAINER (align), hbox);
611
label = _("_Unlock");
614
label = _("_Switch User...");
617
g_assert ("Invalid notebook page");
621
widget = gtk_label_new_with_mnemonic (label);
622
gtk_box_pack_end (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
628
get_switch_button_for_page (gint page)
633
const char *label = NULL;
635
align = gtk_alignment_new (0.5, 0.5, 0, 0);
636
hbox = gtk_hbox_new (FALSE, 2);
637
gtk_container_add (GTK_CONTAINER (align), hbox);
641
label = _("_Switch User...");
644
label = _("_Unlock");
647
g_assert ("Invalid notebook page");
651
widget = gtk_label_new_with_mnemonic (label);
652
gtk_box_pack_end (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
658
switch_page (GSLockPlug *plug,
661
GtkWidget *ok_widget;
662
GtkWidget *other_widget;
666
g_return_if_fail (plug != NULL);
668
current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (plug->priv->notebook));
669
next_page = (current_page == AUTH_PAGE) ? SWITCH_PAGE : AUTH_PAGE;
671
other_widget = get_switch_button_for_page (next_page);
672
ok_widget = get_ok_button_for_page (next_page);
674
gtk_widget_destroy (GTK_BIN (plug->priv->switch_button)->child);
675
gtk_widget_show_all (other_widget);
676
gtk_container_add (GTK_CONTAINER (plug->priv->switch_button), other_widget);
678
gtk_widget_destroy (GTK_BIN (plug->priv->ok_button)->child);
679
gtk_widget_show_all (ok_widget);
680
gtk_container_add (GTK_CONTAINER (plug->priv->ok_button), ok_widget);
682
/* don't show the switch button on the switch page */
683
if (next_page == SWITCH_PAGE) {
684
gtk_widget_hide (plug->priv->switch_button);
687
gtk_notebook_set_current_page (GTK_NOTEBOOK (plug->priv->notebook), next_page);
689
/* this counts as activity so restart the timer */
690
restart_monitor_progress (plug);
694
logout_button_clicked (GtkButton *button,
698
GError *error = NULL;
700
argv [0] = BINDIR "/gnome-session-save";
702
argv [2] = "--silent";
705
g_spawn_async (g_get_home_dir (),
714
g_warning ("Could not run logout command: %s", error->message);
715
g_error_free (error);
719
/* button press handler used to inhibit popup menu */
721
entry_button_press (GtkWidget *widget,
722
GdkEventButton *event)
724
if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
731
entry_key_press (GtkWidget *widget,
735
gboolean capslock_on;
737
restart_monitor_progress (plug);
739
capslock_on = is_capslock_on ();
741
if (capslock_on != plug->priv->caps_lock_on)
742
capslock_update (plug, capslock_on);
744
switch (event->keyval) {
747
gs_lock_plug_response (plug, GS_LOCK_PLUG_RESPONSE_OK);
757
get_response_data (GtkWidget *widget,
760
ResponseData *ad = g_object_get_data (G_OBJECT (widget),
761
"gs-lock-plug-response-data");
763
if (ad == NULL && create) {
764
ad = g_new (ResponseData, 1);
766
g_object_set_data_full (G_OBJECT (widget),
767
"gs-lock-plug-response-data",
775
/* adapted from gtkdialog */
777
action_widget_activated (GtkWidget *widget,
783
g_return_if_fail (GS_IS_LOCK_PLUG (plug));
785
response_id = GS_LOCK_PLUG_RESPONSE_NONE;
787
ad = get_response_data (widget, TRUE);
789
g_assert (ad != NULL);
791
response_id = ad->response_id;
793
gs_lock_plug_response (plug, response_id);
796
/* adapted from gtk_dialog_add_action_widget */
798
gs_lock_plug_add_action_widget (GSLockPlug *plug,
805
g_return_if_fail (GS_IS_LOCK_PLUG (plug));
806
g_return_if_fail (GTK_IS_WIDGET (child));
808
ad = get_response_data (child, TRUE);
810
ad->response_id = response_id;
812
if (GTK_IS_BUTTON (child))
813
signal_id = g_signal_lookup ("clicked", GTK_TYPE_BUTTON);
815
signal_id = GTK_WIDGET_GET_CLASS (child)->activate_signal != 0;
820
closure = g_cclosure_new_object (G_CALLBACK (action_widget_activated),
822
g_signal_connect_closure_by_id (child,
828
g_warning ("Only 'activatable' widgets can be packed into the action area of a GSLockPlug");
830
gtk_box_pack_end (GTK_BOX (plug->action_area),
834
if (response_id == GTK_RESPONSE_HELP)
835
gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (plug->action_area), child, TRUE);
838
/* adapted from gtk_dialog_add_button */
840
gs_lock_plug_add_button (GSLockPlug *plug,
841
const gchar *button_text,
846
g_return_val_if_fail (GS_IS_LOCK_PLUG (plug), NULL);
847
g_return_val_if_fail (button_text != NULL, NULL);
849
button = gtk_button_new_from_stock (button_text);
851
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
853
gtk_widget_show (button);
855
gs_lock_plug_add_action_widget (plug,
863
gs_lock_plug_set_default_response (GSLockPlug *plug,
869
g_return_if_fail (GS_IS_LOCK_PLUG (plug));
871
children = gtk_container_get_children (GTK_CONTAINER (plug->action_area));
874
while (tmp_list != NULL) {
875
GtkWidget *widget = tmp_list->data;
876
ResponseData *rd = g_object_get_data (G_OBJECT (widget),
877
"gs-lock-plug-response-data");
879
if (rd && rd->response_id == response_id)
880
gtk_widget_grab_default (widget);
882
tmp_list = g_list_next (tmp_list);
885
g_list_free (children);
892
} DisplayChangedData;
895
user_displays_changed_cb (FusaUser *user,
896
DisplayChangedData *data)
902
int icon_size = FACE_ICON_SIZE;
903
GtkTreeModel *filter_model;
906
name = fusa_user_get_user_name (user);
907
n_displays = fusa_user_get_n_displays (user);
908
is_active = n_displays > 0;
909
pixbuf = fusa_user_render_icon (user, data->tree, icon_size, is_active);
911
filter_model = gtk_tree_view_get_model (GTK_TREE_VIEW (data->tree));
912
model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filter_model));
914
gtk_list_store_set (GTK_LIST_STORE (model), &data->iter,
916
DISPLAY_NAME_COLUMN, fusa_user_get_display_name (user),
917
ACTIVE_COLUMN, is_active,
918
PIXBUF_COLUMN, pixbuf,
923
populate_model (GSLockPlug *plug,
929
int icon_size = FACE_ICON_SIZE;
932
profile_start ("start", NULL);
934
if (gtk_widget_has_screen (plug->priv->user_treeview))
935
theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (plug->priv->user_treeview));
937
theme = gtk_icon_theme_get_default ();
939
pixbuf = gtk_icon_theme_load_icon (theme, "gdm", icon_size, 0, NULL);
942
gtk_list_store_append (store, &iter);
943
gtk_list_store_set (store, &iter,
944
DISPLAY_NAME_COLUMN, _("Log in as a new user"),
945
NAME_COLUMN, "__new_user",
946
PIXBUF_COLUMN, pixbuf,
948
gtk_list_store_append (store, &iter);
949
gtk_list_store_set (store, &iter,
950
DISPLAY_NAME_COLUMN, NULL,
951
NAME_COLUMN, "__separator",
955
profile_start ("start", "FUSA list users");
956
if (! plug->priv->fusa_manager) {
957
/* for fast user switching */
958
profile_start ("start", "g_thread_init");
959
g_thread_init (NULL);
960
profile_end ("end", "g_thread_init");
961
profile_start ("start", "gnome_vfs_init");
963
profile_end ("end", "gnome_vfs_init");
965
profile_start ("start", "fusa_manager_ref_default");
966
plug->priv->fusa_manager = fusa_manager_ref_default ();
967
profile_end ("end", "fusa_manager_ref_default");
970
users = fusa_manager_list_users (plug->priv->fusa_manager);
971
profile_end ("end", "FUSA list users");
977
DisplayChangedData *ddata;
981
/* skip the current user */
982
if (fusa_user_get_uid (user) == getuid ()) {
983
users = g_slist_delete_link (users, users);
987
n_displays = fusa_user_get_n_displays (user);
988
is_active = n_displays > 0;
990
/* this requires the following to scale well:
991
http://bugzilla.gnome.org/show_bug.cgi?id=310418 */
992
pixbuf = fusa_user_render_icon (user, plug->priv->user_treeview, icon_size, is_active);
994
gtk_list_store_append (store, &iter);
995
gtk_list_store_set (store, &iter,
996
NAME_COLUMN, fusa_user_get_user_name (user),
997
DISPLAY_NAME_COLUMN, fusa_user_get_display_name (user),
998
ACTIVE_COLUMN, is_active,
999
PIXBUF_COLUMN, pixbuf,
1002
ddata = g_new0 (DisplayChangedData, 1);
1004
ddata->tree = plug->priv->user_treeview;
1006
g_signal_connect_data (user, "displays-changed",
1007
G_CALLBACK (user_displays_changed_cb), ddata,
1008
(GClosureNotify) g_free, 0);
1010
users = g_slist_delete_link (users, users);
1013
profile_end ("end", NULL);
1017
compare_users (GtkTreeModel *model,
1028
gtk_tree_model_get (model, a, NAME_COLUMN, &name_a, -1);
1029
gtk_tree_model_get (model, b, NAME_COLUMN, &name_b, -1);
1030
gtk_tree_model_get (model, a, DISPLAY_NAME_COLUMN, &label_a, -1);
1031
gtk_tree_model_get (model, b, DISPLAY_NAME_COLUMN, &label_b, -1);
1038
if (strcmp (name_a, "__new_user") == 0)
1040
else if (strcmp (name_b, "__new_user") == 0)
1042
else if (strcmp (name_a, "__separator") == 0)
1044
else if (strcmp (name_b, "__separator") == 0)
1052
result = strcmp (label_a, label_b);
1063
separator_func (GtkTreeModel *model,
1067
int column = GPOINTER_TO_INT (data);
1070
gtk_tree_model_get (model, iter, column, &text, -1);
1072
if (text && strcmp (text, "__separator") == 0)
1081
filter_out_users (GtkTreeModel *model,
1089
gtk_tree_model_get (model, iter,
1091
ACTIVE_COLUMN, &is_active,
1096
if (strcmp (name, "__new_user") == 0
1097
|| strcmp (name, "__separator") == 0) {
1100
/* FIXME: do we show all users or only active ones? */
1102
/*visible = is_active;*/
1111
setup_treeview (GSLockPlug *plug)
1113
GtkListStore *store;
1114
GtkTreeViewColumn *column;
1115
GtkCellRenderer *renderer;
1116
GtkTreeModel *filter;
1118
/* if user switching is not enabled then do nothing */
1119
if (! plug->priv->switch_enabled)
1122
profile_start ("start", NULL);
1124
store = gtk_list_store_new (N_COLUMNS,
1129
populate_model (plug, store);
1131
filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
1133
gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
1134
(GtkTreeModelFilterVisibleFunc) filter_out_users,
1138
gtk_tree_view_set_model (GTK_TREE_VIEW (plug->priv->user_treeview),
1141
g_object_unref (store);
1142
g_object_unref (filter);
1144
renderer = gtk_cell_renderer_pixbuf_new ();
1145
column = gtk_tree_view_column_new_with_attributes ("Image", renderer,
1146
"pixbuf", PIXBUF_COLUMN,
1148
gtk_tree_view_append_column (GTK_TREE_VIEW (plug->priv->user_treeview), column);
1150
renderer = gtk_cell_renderer_text_new ();
1151
column = gtk_tree_view_column_new_with_attributes ("Name", renderer,
1152
"text", DISPLAY_NAME_COLUMN,
1154
gtk_tree_view_append_column (GTK_TREE_VIEW (plug->priv->user_treeview), column);
1156
gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (plug->priv->user_treeview),
1158
GINT_TO_POINTER (NAME_COLUMN),
1161
gtk_tree_view_column_set_sort_column_id (column, 0);
1162
gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store),
1166
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
1168
GTK_SORT_ASCENDING);
1169
profile_end ("end", NULL);
1173
setup_treeview_idle (GSLockPlug *plug)
1175
setup_treeview (plug);
1181
get_user_display_name (void)
1185
name = g_get_real_name ();
1187
if (name == NULL || strcmp (name, "Unknown") == 0) {
1188
name = g_get_user_name ();
1195
label_set_big_bold (GtkLabel *label)
1197
PangoAttrList *pattrlist;
1198
PangoAttribute *attr;
1200
pattrlist = pango_attr_list_new ();
1202
attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
1203
attr->start_index = 0;
1204
attr->end_index = G_MAXINT;
1205
pango_attr_list_insert (pattrlist, attr);
1207
attr = pango_attr_scale_new (1.2);
1208
attr->start_index = 0;
1209
attr->end_index = G_MAXINT;
1210
pango_attr_list_insert (pattrlist, attr);
1212
gtk_label_set_attributes (label, pattrlist);
1214
pango_attr_list_unref (pattrlist);
1218
label_set_bigger (GtkLabel *label)
1220
PangoAttrList *pattrlist;
1221
PangoAttribute *attr;
1223
pattrlist = pango_attr_list_new ();
1225
attr = pango_attr_scale_new (1.4);
1226
attr->start_index = 0;
1227
attr->end_index = G_MAXINT;
1228
pango_attr_list_insert (pattrlist, attr);
1230
gtk_label_set_attributes (label, pattrlist);
1232
pango_attr_list_unref (pattrlist);
1236
label_set_big (GtkLabel *label)
1238
PangoAttrList *pattrlist;
1239
PangoAttribute *attr;
1241
pattrlist = pango_attr_list_new ();
1243
attr = pango_attr_scale_new (1.2);
1244
attr->start_index = 0;
1245
attr->end_index = G_MAXINT;
1246
pango_attr_list_insert (pattrlist, attr);
1248
gtk_label_set_attributes (label, pattrlist);
1250
pango_attr_list_unref (pattrlist);
1254
check_user_file (const gchar *filename,
1256
gssize max_file_size,
1257
gboolean relax_group,
1258
gboolean relax_other)
1260
struct stat fileinfo;
1262
if (max_file_size < 0)
1263
max_file_size = G_MAXSIZE;
1265
/* Exists/Readable? */
1266
if (g_stat (filename, &fileinfo) < 0)
1269
/* Is a regular file */
1270
if (G_UNLIKELY (!S_ISREG (fileinfo.st_mode)))
1273
/* Owned by user? */
1274
if (G_UNLIKELY (fileinfo.st_uid != user))
1277
/* Group not writable or relax_group? */
1278
if (G_UNLIKELY ((fileinfo.st_mode & S_IWGRP) == S_IWGRP && !relax_group))
1281
/* Other not writable or relax_other? */
1282
if (G_UNLIKELY ((fileinfo.st_mode & S_IWOTH) == S_IWOTH && !relax_other))
1285
/* Size is kosher? */
1286
if (G_UNLIKELY (fileinfo.st_size > max_file_size))
1297
GtkIconTheme *theme;
1298
const char *homedir;
1301
gsize user_max_file = 65536;
1304
homedir = g_get_home_dir ();
1307
path = g_build_filename (homedir, ".face", NULL);
1310
if (check_user_file (path, uid, user_max_file, 0, 0)) {
1311
pixbuf = gdk_pixbuf_new_from_file_at_size (path,
1317
theme = gtk_icon_theme_get_default ();
1320
pixbuf = gtk_icon_theme_load_icon (theme,
1328
pixbuf = gtk_icon_theme_load_icon (theme,
1329
GTK_STOCK_MISSING_IMAGE,
1335
image = gtk_image_new_from_pixbuf (pixbuf);
1337
g_object_unref (pixbuf);
1343
create_page_one (GSLockPlug *plug)
1346
GtkWidget *password_label;
1353
profile_start ("start", "page one");
1355
align = gtk_alignment_new (0.5, 0.5, 1, 1);
1356
gtk_notebook_append_page (GTK_NOTEBOOK (plug->priv->notebook), align, NULL);
1358
vbox = gtk_vbox_new (FALSE, 12);
1359
gtk_container_add (GTK_CONTAINER (align), vbox);
1361
/* should we make this a gconf preference? */
1365
/* translators: %s is a computer hostname */
1366
str = g_strdup_printf (_("Welcome to %s"), g_get_host_name ());
1367
widget = gtk_label_new (str);
1368
gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
1369
gtk_misc_set_alignment (GTK_MISC (widget), 0.5, 0.5);
1372
label_set_big_bold (GTK_LABEL (widget));
1375
widget = get_face_image ();
1376
gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
1378
vbox2 = gtk_vbox_new (FALSE, 0);
1379
gtk_box_pack_start (GTK_BOX (vbox), vbox2, FALSE, FALSE, 0);
1381
plug->priv->username_label = gtk_label_new (get_user_display_name ());
1382
gtk_misc_set_alignment (GTK_MISC (plug->priv->username_label), 0.5, 0.5);
1383
gtk_box_pack_start (GTK_BOX (vbox2), plug->priv->username_label, FALSE, FALSE, 0);
1385
label_set_bigger (GTK_LABEL (plug->priv->username_label));
1387
str = g_strdup_printf ("(%s)", g_get_user_name ());
1388
widget = gtk_label_new (str);
1390
gtk_misc_set_alignment (GTK_MISC (widget), 0.5, 0.5);
1391
gtk_box_pack_start (GTK_BOX (vbox2), widget, FALSE, FALSE, 0);
1393
vbox2 = gtk_vbox_new (FALSE, 0);
1394
gtk_box_pack_start (GTK_BOX (vbox), vbox2, FALSE, FALSE, 0);
1396
hbox = gtk_hbox_new (FALSE, 6);
1397
gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, FALSE, 0);
1399
password_label = gtk_label_new_with_mnemonic (_("_Password:"));
1400
gtk_misc_set_alignment (GTK_MISC (password_label), 0, 0.5);
1401
gtk_box_pack_start (GTK_BOX (hbox), password_label, FALSE, FALSE, 0);
1403
plug->priv->password_entry = gtk_entry_new ();
1404
gtk_box_pack_start (GTK_BOX (hbox), plug->priv->password_entry, TRUE, TRUE, 0);
1406
/* button press handler used to inhibit popup menu */
1407
g_signal_connect (plug->priv->password_entry, "button_press_event",
1408
G_CALLBACK (entry_button_press), NULL);
1409
g_signal_connect (plug->priv->password_entry, "key_press_event",
1410
G_CALLBACK (entry_key_press), plug);
1411
gtk_entry_set_activates_default (GTK_ENTRY (plug->priv->password_entry), TRUE);
1412
gtk_entry_set_visibility (GTK_ENTRY (plug->priv->password_entry), FALSE);
1414
gtk_label_set_mnemonic_widget (GTK_LABEL (password_label),
1415
plug->priv->password_entry);
1417
plug->priv->capslock_label = gtk_label_new ("");
1418
gtk_misc_set_alignment (GTK_MISC (plug->priv->capslock_label), 0.5, 0.5);
1419
gtk_box_pack_start (GTK_BOX (vbox2), plug->priv->capslock_label, FALSE, FALSE, 0);
1421
profile_end ("end", "page one");
1425
create_page_two (GSLockPlug *plug)
1430
profile_start ("start", "page two");
1432
vbox = gtk_vbox_new (FALSE, 6);
1433
gtk_notebook_append_page (GTK_NOTEBOOK (plug->priv->notebook), vbox, NULL);
1435
widget = gtk_label_new (_("Switch to user:"));
1436
gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
1437
gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
1439
label_set_big (GTK_LABEL (widget));
1441
widget = gtk_scrolled_window_new (NULL, NULL);
1442
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (widget),
1444
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget),
1446
GTK_POLICY_AUTOMATIC);
1447
gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0);
1449
plug->priv->user_treeview = gtk_tree_view_new ();
1450
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (plug->priv->user_treeview), FALSE);
1451
gtk_container_add (GTK_CONTAINER (widget), plug->priv->user_treeview);
1453
g_idle_add ((GSourceFunc)setup_treeview_idle, plug);
1455
profile_end ("end", "page two");
1459
create_buttons (GSLockPlug *plug)
1463
profile_start ("start", "buttons");
1465
plug->priv->switch_button = gtk_button_new ();
1466
gtk_button_set_focus_on_click (GTK_BUTTON (plug->priv->switch_button), FALSE);
1468
widget = get_switch_button_for_page (AUTH_PAGE);
1469
gtk_container_add (GTK_CONTAINER (plug->priv->switch_button), widget);
1471
GTK_WIDGET_SET_FLAGS (plug->priv->switch_button, GTK_CAN_DEFAULT);
1472
gtk_widget_show_all (plug->priv->switch_button);
1473
gtk_box_pack_start (GTK_BOX (plug->action_area), plug->priv->switch_button,
1475
gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (plug->action_area),
1476
plug->priv->switch_button,
1479
plug->priv->logout_button = gs_lock_plug_add_button (GS_LOCK_PLUG (plug),
1481
GS_LOCK_PLUG_RESPONSE_CANCEL);
1482
gtk_button_set_focus_on_click (GTK_BUTTON (plug->priv->logout_button), FALSE);
1484
plug->priv->cancel_button = gs_lock_plug_add_button (GS_LOCK_PLUG (plug),
1486
GS_LOCK_PLUG_RESPONSE_CANCEL);
1487
gtk_button_set_focus_on_click (GTK_BUTTON (plug->priv->cancel_button), FALSE);
1489
plug->priv->ok_button = gtk_button_new ();
1490
gtk_button_set_focus_on_click (GTK_BUTTON (plug->priv->ok_button), FALSE);
1492
widget = get_ok_button_for_page (AUTH_PAGE);
1493
gtk_container_add (GTK_CONTAINER (plug->priv->ok_button), widget);
1494
GTK_WIDGET_SET_FLAGS (plug->priv->ok_button, GTK_CAN_DEFAULT);
1495
gtk_window_set_default (GTK_WINDOW (plug), plug->priv->ok_button);
1496
gtk_widget_show_all (plug->priv->ok_button);
1497
gs_lock_plug_add_action_widget (GS_LOCK_PLUG (plug), plug->priv->ok_button,
1498
GS_LOCK_PLUG_RESPONSE_OK);
1500
gs_lock_plug_set_default_response (plug, GS_LOCK_PLUG_RESPONSE_OK);
1502
profile_end ("end", "buttons");
1506
gs_lock_plug_init (GSLockPlug *plug)
1508
profile_start ("start", NULL);
1510
plug->priv = GS_LOCK_PLUG_GET_PRIVATE (plug);
1512
plug->priv->fusa_manager = NULL;
1514
/* Dialog emulation */
1516
plug->vbox = gtk_vbox_new (FALSE, 0);
1518
gtk_container_add (GTK_CONTAINER (plug), plug->vbox);
1520
plug->action_area = gtk_hbutton_box_new ();
1522
gtk_button_box_set_layout (GTK_BUTTON_BOX (plug->action_area),
1525
gtk_box_pack_end (GTK_BOX (plug->vbox), plug->action_area,
1527
gtk_widget_show (plug->action_area);
1531
plug->priv->notebook = gtk_notebook_new ();
1532
gtk_notebook_set_show_tabs (GTK_NOTEBOOK (plug->priv->notebook), FALSE);
1533
gtk_notebook_set_show_border (GTK_NOTEBOOK (plug->priv->notebook), FALSE);
1534
gtk_box_pack_start (GTK_BOX (plug->vbox), plug->priv->notebook, FALSE, FALSE, 0);
1538
create_page_one (plug);
1542
create_page_two (plug);
1546
plug->priv->status_label = gtk_label_new (NULL);
1547
gtk_box_pack_start (GTK_BOX (plug->vbox), plug->priv->status_label,
1552
create_buttons (plug);
1554
gtk_widget_show_all (plug->vbox);
1556
if (! plug->priv->logout_enabled)
1557
gtk_widget_hide (plug->priv->logout_button);
1558
if (! plug->priv->switch_enabled)
1559
gtk_widget_hide (plug->priv->switch_button);
1561
plug->priv->timeout = DIALOG_TIMEOUT_MSEC;
1563
g_signal_connect_swapped (plug->priv->switch_button, "clicked",
1564
G_CALLBACK (switch_page), plug);
1566
g_signal_connect (plug->priv->logout_button, "clicked",
1567
G_CALLBACK (logout_button_clicked), plug);
1569
profile_end ("end", NULL);
1573
gs_lock_plug_finalize (GObject *object)
1577
g_return_if_fail (object != NULL);
1578
g_return_if_fail (GS_IS_LOCK_PLUG (object));
1580
plug = GS_LOCK_PLUG (object);
1582
g_return_if_fail (plug->priv != NULL);
1584
if (plug->priv->fusa_manager)
1585
g_object_unref (plug->priv->fusa_manager);
1587
if (plug->priv->password_check_idle_id > 0) {
1588
g_source_remove (plug->priv->password_check_idle_id);
1589
plug->priv->password_check_idle_id = 0;
1592
if (plug->priv->response_idle_id > 0) {
1593
g_source_remove (plug->priv->response_idle_id);
1594
plug->priv->response_idle_id = 0;
1597
if (plug->priv->idle_id > 0) {
1598
g_source_remove (plug->priv->idle_id);
1599
plug->priv->idle_id = 0;
1602
G_OBJECT_CLASS (parent_class)->finalize (object);
1606
gs_lock_plug_new (void)
1610
result = g_object_new (GS_TYPE_LOCK_PLUG, NULL);
1612
gtk_window_set_focus_on_map (GTK_WINDOW (result), TRUE);