~ubuntu-branches/ubuntu/dapper/gnome-screensaver/dapper

« back to all changes in this revision

Viewing changes to src/gs-lock-plug.c

  • Committer: Bazaar Package Importer
  • Author(s): Oliver Grawert
  • Date: 2005-10-10 00:18:18 UTC
  • Revision ID: james.westby@ubuntu.com-20051010001818-3mujs05r8rht7xi1
Tags: upstream-0.0.15
ImportĀ upstreamĀ versionĀ 0.0.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
 
2
 *
 
3
 * Copyright (C) 2004-2005 William Jon McCann <mccann@jhu.edu>
 
4
 *
 
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.
 
9
 *
 
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.
 
14
 *
 
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.
 
18
 *
 
19
 * Authors: William Jon McCann <mccann@jhu.edu>
 
20
 *
 
21
 */
 
22
 
 
23
#include "config.h"
 
24
 
 
25
#include <stdlib.h>
 
26
#include <unistd.h>
 
27
#include <string.h>
 
28
#include <errno.h>
 
29
#include <time.h>
 
30
#include <glib/gprintf.h>
 
31
#include <glib/gstdio.h>
 
32
#include <glib/gi18n.h>
 
33
#include <gdk/gdkkeysyms.h>
 
34
#include <gdk/gdkx.h>
 
35
#include <X11/XKBlib.h>
 
36
#include <gtk/gtk.h>
 
37
 
 
38
/* for fast user switching */
 
39
#include <libgnomevfs/gnome-vfs-init.h>
 
40
 
 
41
#include "gs-lock-plug.h"
 
42
 
 
43
#include "passwd.h"
 
44
 
 
45
#include "fusa-manager.h"
 
46
 
 
47
/* Profiling stuff adapted from gtkfilechooserdefault */
 
48
 
 
49
#undef PROFILE_LOCK_DIALOG
 
50
#ifdef PROFILE_LOCK_DIALOG
 
51
 
 
52
#define PROFILE_INDENT 4
 
53
static int profile_indent;
 
54
 
 
55
static void
 
56
profile_add_indent (int indent)
 
57
{
 
58
        profile_indent += indent;
 
59
        if (profile_indent < 0)
 
60
                g_error ("You screwed up your indentation");
 
61
}
 
62
 
 
63
static void
 
64
_gs_lock_plug_profile_log (const char *func,
 
65
                           int         indent,
 
66
                           const char *msg1,
 
67
                           const char *msg2)
 
68
{
 
69
        char    *str;
 
70
        GTimeVal now;
 
71
 
 
72
        if (indent < 0)
 
73
                profile_add_indent (indent);
 
74
 
 
75
        g_get_current_time (&now);
 
76
 
 
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 : "");
 
79
        else
 
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 : "");
 
81
 
 
82
        fprintf (stderr, "%s\n", str);
 
83
        g_free (str);
 
84
 
 
85
        if (indent > 0)
 
86
                profile_add_indent (indent);
 
87
}
 
88
 
 
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)
 
92
#else
 
93
#define profile_start(x, y)
 
94
#define profile_end(x, y)
 
95
#define profile_msg(x, y)
 
96
#endif
 
97
 
 
98
 
 
99
enum { 
 
100
        AUTH_PAGE = 0,
 
101
        SWITCH_PAGE
 
102
};
 
103
 
 
104
#define FACE_ICON_SIZE 48
 
105
#define DIALOG_TIMEOUT_MSEC 60000
 
106
 
 
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);
 
110
 
 
111
static gboolean password_check_idle_cb (GSLockPlug *plug);
 
112
 
 
113
#define GS_LOCK_PLUG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GS_TYPE_LOCK_PLUG, GSLockPlugPrivate))
 
114
 
 
115
struct GSLockPlugPrivate
 
116
{
 
117
        GtkWidget   *notebook;
 
118
        GtkWidget   *username_label;
 
119
        GtkWidget   *password_entry;
 
120
        GtkWidget   *capslock_label;
 
121
        GtkWidget   *status_label;
 
122
        GtkWidget   *user_treeview;
 
123
 
 
124
        GtkWidget   *ok_button;
 
125
        GtkWidget   *cancel_button;
 
126
        GtkWidget   *logout_button;
 
127
        GtkWidget   *switch_button;
 
128
 
 
129
        FusaManager *fusa_manager;
 
130
 
 
131
        gboolean     caps_lock_on;
 
132
        gboolean     switch_enabled;
 
133
        gboolean     logout_enabled;
 
134
 
 
135
        guint        timeout;
 
136
 
 
137
        guint        idle_id;
 
138
        guint        password_check_idle_id;
 
139
        guint        response_idle_id;
 
140
 
 
141
        GTimeVal     start_time;
 
142
};
 
143
 
 
144
typedef struct _ResponseData ResponseData;
 
145
 
 
146
struct _ResponseData
 
147
{
 
148
        gint response_id;
 
149
};
 
150
 
 
151
 
 
152
enum {
 
153
        RESPONSE,
 
154
        LAST_SIGNAL
 
155
};
 
156
 
 
157
enum {
 
158
        PROP_0,
 
159
        PROP_LOGOUT_ENABLED,
 
160
        PROP_SWITCH_ENABLED
 
161
};
 
162
 
 
163
static GObjectClass *parent_class = NULL;
 
164
static guint         lock_plug_signals [LAST_SIGNAL];
 
165
 
 
166
G_DEFINE_TYPE (GSLockPlug, gs_lock_plug, GTK_TYPE_PLUG);
 
167
 
 
168
static void
 
169
gs_lock_plug_style_set (GtkWidget *widget,
 
170
                        GtkStyle  *previous_style)
 
171
{
 
172
        GSLockPlug *plug;
 
173
 
 
174
        if (GTK_WIDGET_CLASS (parent_class)->style_set)
 
175
                GTK_WIDGET_CLASS (parent_class)->style_set (widget, previous_style);
 
176
 
 
177
        plug = GS_LOCK_PLUG (widget);
 
178
 
 
179
        gtk_container_set_border_width (GTK_CONTAINER (plug->vbox), 24);
 
180
        gtk_box_set_spacing (GTK_BOX (plug->vbox), 12);
 
181
 
 
182
        gtk_container_set_border_width (GTK_CONTAINER (plug->action_area), 0);
 
183
        gtk_box_set_spacing (GTK_BOX (plug->action_area), 5);
 
184
}
 
185
 
 
186
static void
 
187
manager_new_console_cb (FusaManager  *manager,
 
188
                        FusaDisplay  *display,
 
189
                        const GError *error,
 
190
                        gpointer      data)
 
191
{
 
192
        GSLockPlug *plug = data;
 
193
        g_signal_emit (plug,
 
194
                       lock_plug_signals [RESPONSE],
 
195
                       0,
 
196
                       GS_LOCK_PLUG_RESPONSE_CANCEL);
 
197
}
 
198
 
 
199
static void
 
200
do_user_switch (GSLockPlug  *plug,
 
201
                FusaDisplay *display)
 
202
{
 
203
        GdkScreen *screen;
 
204
 
 
205
        if (gtk_widget_has_screen (plug->priv->user_treeview)) {
 
206
                screen = gtk_widget_get_screen (plug->priv->user_treeview);
 
207
        } else {
 
208
                screen = gdk_screen_get_default ();
 
209
        }
 
210
 
 
211
        if (display) {
 
212
                fusa_manager_activate_display (plug->priv->fusa_manager, display, screen,
 
213
                                               manager_new_console_cb, plug, NULL);
 
214
                return;
 
215
        }
 
216
 
 
217
        fusa_manager_new_console (plug->priv->fusa_manager, screen,
 
218
                                  manager_new_console_cb, plug, NULL);
 
219
}
 
220
 
 
221
enum {
 
222
        DISPLAY_NAME_COLUMN,
 
223
        NAME_COLUMN,
 
224
        ACTIVE_COLUMN,
 
225
        PIXBUF_COLUMN,
 
226
        N_COLUMNS
 
227
};
 
228
 
 
229
static void
 
230
switch_user_response (GSLockPlug *plug)
 
231
{
 
232
        FusaDisplay      *display = NULL;
 
233
        FusaUser         *user;
 
234
        GtkTreeSelection *selection;
 
235
        GtkTreeModel     *model;
 
236
        GtkTreeIter       iter;
 
237
        GSList           *displays;
 
238
        char             *name;
 
239
 
 
240
        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (plug->priv->user_treeview));
 
241
        gtk_tree_selection_get_selected (selection,
 
242
                                         &model,
 
243
                                         &iter);
 
244
        gtk_tree_model_get (model, &iter, NAME_COLUMN, &name, -1);
 
245
        if (name
 
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);
 
250
                if (displays) {
 
251
                        /* FIXME: just pick the first one for now */
 
252
                        display = displays->data;
 
253
                }
 
254
        }
 
255
 
 
256
        g_free (name);
 
257
 
 
258
        do_user_switch (plug, display);
 
259
}
 
260
 
 
261
static void
 
262
set_status_text (GSLockPlug *plug,
 
263
                 const char *text)
 
264
{
 
265
        gtk_label_set_text (GTK_LABEL (plug->priv->status_label), text);
 
266
}
 
267
 
 
268
static void
 
269
gs_lock_plug_response (GSLockPlug *plug,
 
270
                       gint        response_id)
 
271
{
 
272
        int new_response;
 
273
 
 
274
        new_response = response_id;
 
275
 
 
276
        g_return_if_fail (GS_IS_LOCK_PLUG (plug));
 
277
 
 
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)) {
 
281
                return;
 
282
        }
 
283
 
 
284
        if (plug->priv->idle_id > 0) {
 
285
                g_source_remove (plug->priv->idle_id);
 
286
                plug->priv->idle_id = 0;
 
287
        }
 
288
 
 
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;
 
292
        }
 
293
 
 
294
        if (plug->priv->response_idle_id > 0) {
 
295
                g_source_remove (plug->priv->response_idle_id);
 
296
                plug->priv->response_idle_id = 0;
 
297
        }
 
298
 
 
299
        if (response_id == GS_LOCK_PLUG_RESPONSE_CANCEL) {
 
300
                gtk_entry_set_text (GTK_ENTRY (plug->priv->password_entry), "");
 
301
        }
 
302
 
 
303
        if (response_id == GS_LOCK_PLUG_RESPONSE_OK) {
 
304
                gint current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (plug->priv->notebook));
 
305
 
 
306
                if (current_page == 0) {
 
307
                        gtk_widget_set_sensitive (plug->priv->password_entry, FALSE);
 
308
                        set_status_text (plug, _("Checking password..."));
 
309
 
 
310
                        plug->priv->password_check_idle_id = g_idle_add ((GSourceFunc)password_check_idle_cb,
 
311
                                                                         plug);
 
312
                        return;
 
313
                } else {
 
314
                        /* switch user */
 
315
                        switch_user_response (plug);
 
316
                        return;
 
317
                }
 
318
        }
 
319
 
 
320
        g_signal_emit (plug,
 
321
                       lock_plug_signals [RESPONSE],
 
322
                       0,
 
323
                       new_response);
 
324
}
 
325
 
 
326
static gboolean
 
327
response_idle_cb (GSLockPlug *plug)
 
328
{
 
329
        plug->priv->response_idle_id = 0;
 
330
 
 
331
        gs_lock_plug_response (plug, GS_LOCK_PLUG_RESPONSE_CANCEL);
 
332
 
 
333
        return FALSE;
 
334
}
 
335
 
 
336
static gboolean
 
337
monitor_progress (GSLockPlug *plug)
 
338
{
 
339
        GTimeVal now;
 
340
        glong    elapsed;
 
341
        glong    remaining;
 
342
        char    *message;
 
343
 
 
344
        g_get_current_time (&now);
 
345
 
 
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;
 
349
 
 
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);
 
354
                g_free (message);
 
355
 
 
356
                if (plug->priv->response_idle_id == 0)
 
357
                        plug->priv->response_idle_id = g_timeout_add (1000,
 
358
                                                                      (GSourceFunc)response_idle_cb,
 
359
                                                                      plug);
 
360
                return FALSE;
 
361
        }
 
362
        return TRUE;
 
363
}
 
364
 
 
365
 
 
366
static void
 
367
capslock_update (GSLockPlug *plug,
 
368
                 gboolean    is_on)
 
369
{
 
370
 
 
371
        plug->priv->caps_lock_on = is_on;
 
372
 
 
373
        if (is_on)
 
374
                gtk_label_set_text (GTK_LABEL (plug->priv->capslock_label),
 
375
                                    _("You have the Caps Lock key on."));
 
376
        else
 
377
                gtk_label_set_text (GTK_LABEL (plug->priv->capslock_label),
 
378
                                    "");
 
379
}
 
380
 
 
381
/* adapted from GDM2 */
 
382
static gboolean
 
383
is_capslock_on (void)
 
384
{
 
385
        unsigned int states;
 
386
        Display     *dsp;
 
387
 
 
388
        dsp = GDK_DISPLAY ();
 
389
 
 
390
        if (XkbGetIndicatorState (dsp, XkbUseCoreKbd, &states) != Success)
 
391
                return FALSE;
 
392
 
 
393
        return (states & ShiftMask) != 0;
 
394
}
 
395
 
 
396
static void
 
397
restart_monitor_progress (GSLockPlug *plug)
 
398
{
 
399
        if (plug->priv->idle_id > 0) {
 
400
                g_source_remove (plug->priv->idle_id);
 
401
                plug->priv->idle_id = 0;
 
402
        }
 
403
 
 
404
        g_get_current_time (&plug->priv->start_time);
 
405
        plug->priv->idle_id = g_timeout_add (50,
 
406
                                             (GSourceFunc)monitor_progress,
 
407
                                             plug);
 
408
}
 
409
 
 
410
static void
 
411
gs_lock_plug_show (GtkWidget *widget)
 
412
{
 
413
        profile_start ("start", NULL);
 
414
 
 
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");
 
419
 
 
420
        capslock_update (GS_LOCK_PLUG (widget), is_capslock_on ());
 
421
 
 
422
        restart_monitor_progress (GS_LOCK_PLUG (widget));
 
423
 
 
424
        profile_end ("end", NULL);
 
425
}
 
426
 
 
427
static void
 
428
gs_lock_plug_hide (GtkWidget *widget)
 
429
{
 
430
        if (GTK_WIDGET_CLASS (parent_class)->hide)
 
431
                GTK_WIDGET_CLASS (parent_class)->hide (widget);
 
432
}
 
433
 
 
434
static void
 
435
gs_lock_plug_set_logout_enabled (GSLockPlug *plug,
 
436
                                 gboolean    logout_enabled)
 
437
{
 
438
        g_return_if_fail (GS_LOCK_PLUG (plug));
 
439
 
 
440
        if (plug->priv->logout_enabled == logout_enabled)
 
441
                return;
 
442
 
 
443
        plug->priv->logout_enabled = logout_enabled;
 
444
        g_object_notify (G_OBJECT (plug), "logout-enabled");
 
445
 
 
446
        if (logout_enabled)
 
447
                gtk_widget_show (plug->priv->logout_button);
 
448
        else
 
449
                gtk_widget_hide (plug->priv->logout_button);
 
450
}
 
451
 
 
452
static void
 
453
gs_lock_plug_set_switch_enabled (GSLockPlug *plug,
 
454
                                 gboolean    switch_enabled)
 
455
{
 
456
        g_return_if_fail (GS_LOCK_PLUG (plug));
 
457
 
 
458
        if (plug->priv->switch_enabled == switch_enabled)
 
459
                return;
 
460
 
 
461
        plug->priv->switch_enabled = switch_enabled;
 
462
        g_object_notify (G_OBJECT (plug), "switch-enabled");
 
463
 
 
464
        if (switch_enabled)
 
465
                gtk_widget_show (plug->priv->switch_button);
 
466
        else
 
467
                gtk_widget_hide (plug->priv->switch_button);
 
468
}
 
469
 
 
470
static void
 
471
gs_lock_plug_set_property (GObject            *object,
 
472
                           guint               prop_id,
 
473
                           const GValue       *value,
 
474
                           GParamSpec         *pspec)
 
475
{
 
476
        GSLockPlug *self;
 
477
 
 
478
        self = GS_LOCK_PLUG (object);
 
479
 
 
480
        switch (prop_id) {
 
481
        case PROP_LOGOUT_ENABLED:
 
482
                gs_lock_plug_set_logout_enabled (self, g_value_get_boolean (value));
 
483
                break;
 
484
        case PROP_SWITCH_ENABLED:
 
485
                gs_lock_plug_set_switch_enabled (self, g_value_get_boolean (value));
 
486
                break;
 
487
        default:
 
488
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
489
                break;
 
490
        }
 
491
}
 
492
 
 
493
static void
 
494
gs_lock_plug_get_property (GObject    *object,
 
495
                           guint       prop_id,
 
496
                           GValue     *value,
 
497
                           GParamSpec *pspec)
 
498
{
 
499
        GSLockPlug *self;
 
500
 
 
501
        self = GS_LOCK_PLUG (object);
 
502
 
 
503
        switch (prop_id) {
 
504
        case PROP_LOGOUT_ENABLED:
 
505
                g_value_set_boolean (value, self->priv->logout_enabled);
 
506
                break;
 
507
        case PROP_SWITCH_ENABLED:
 
508
                g_value_set_boolean (value, self->priv->switch_enabled);
 
509
                break;
 
510
        default:
 
511
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
512
                break;
 
513
        }
 
514
}
 
515
 
 
516
static void
 
517
gs_lock_plug_class_init (GSLockPlugClass *klass)
 
518
{
 
519
        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
 
520
        GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 
521
 
 
522
        parent_class = g_type_class_peek_parent (klass);
 
523
 
 
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;
 
527
 
 
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;
 
531
 
 
532
        g_type_class_add_private (klass, sizeof (GSLockPlugPrivate));
 
533
 
 
534
 
 
535
        lock_plug_signals [RESPONSE] = g_signal_new ("response",
 
536
                                                     G_OBJECT_CLASS_TYPE (klass),
 
537
                                                     G_SIGNAL_RUN_LAST,
 
538
                                                     G_STRUCT_OFFSET (GSLockPlugClass, response),
 
539
                                                     NULL, NULL,
 
540
                                                     g_cclosure_marshal_VOID__INT,
 
541
                                                     G_TYPE_NONE, 1,
 
542
                                                     G_TYPE_INT);
 
543
 
 
544
        g_object_class_install_property (object_class,
 
545
                                         PROP_LOGOUT_ENABLED,
 
546
                                         g_param_spec_boolean ("logout-enabled",
 
547
                                                               NULL,
 
548
                                                               NULL,
 
549
                                                               FALSE,
 
550
                                                               G_PARAM_READWRITE));
 
551
        g_object_class_install_property (object_class,
 
552
                                         PROP_SWITCH_ENABLED,
 
553
                                         g_param_spec_boolean ("switch-enabled",
 
554
                                                               NULL,
 
555
                                                               NULL,
 
556
                                                               FALSE,
 
557
                                                               G_PARAM_READWRITE));
 
558
}
 
559
 
 
560
static gboolean
 
561
password_check_idle_cb (GSLockPlug *plug)
 
562
{
 
563
        const char *typed_password;
 
564
        char       *null_password;
 
565
        char       *local_password;
 
566
 
 
567
        plug->priv->password_check_idle_id = 0;
 
568
 
 
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);
 
571
 
 
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);
 
576
 
 
577
        if (validate_password (local_password, FALSE)) {
 
578
                g_signal_emit (plug,
 
579
                               lock_plug_signals [RESPONSE],
 
580
                               0,
 
581
                               GS_LOCK_PLUG_RESPONSE_OK);
 
582
        } else {
 
583
                if (plug->priv->response_idle_id == 0)
 
584
                        plug->priv->response_idle_id = g_timeout_add (1000,
 
585
                                                                      (GSourceFunc)response_idle_cb,
 
586
                                                                      plug);
 
587
 
 
588
                set_status_text (plug, _("That password was incorrect."));
 
589
        }
 
590
 
 
591
        memset (local_password, '\b', strlen (local_password));
 
592
        g_free (local_password);
 
593
 
 
594
        return FALSE;
 
595
}
 
596
 
 
597
static GtkWidget *
 
598
get_ok_button_for_page (gint page)
 
599
{
 
600
        GtkWidget *align;
 
601
        GtkWidget *hbox;
 
602
        GtkWidget *widget;
 
603
        const char *label = NULL;
 
604
 
 
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);
 
608
 
 
609
        switch (page) {
 
610
        case (AUTH_PAGE):
 
611
                label = _("_Unlock");
 
612
                break;
 
613
        case (SWITCH_PAGE):
 
614
                label = _("_Switch User...");
 
615
                break;
 
616
        default:
 
617
                g_assert ("Invalid notebook page");
 
618
                break;
 
619
        }
 
620
 
 
621
        widget = gtk_label_new_with_mnemonic (label);
 
622
        gtk_box_pack_end (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
 
623
 
 
624
        return align;
 
625
}
 
626
 
 
627
static GtkWidget *
 
628
get_switch_button_for_page (gint page)
 
629
{
 
630
        GtkWidget *align;
 
631
        GtkWidget *hbox;
 
632
        GtkWidget *widget;
 
633
        const char *label = NULL;
 
634
 
 
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);
 
638
 
 
639
        switch (page) {
 
640
        case (AUTH_PAGE):
 
641
                label = _("_Switch User...");
 
642
                break;
 
643
        case (SWITCH_PAGE):
 
644
                label = _("_Unlock");
 
645
                break;
 
646
        default:
 
647
                g_assert ("Invalid notebook page");
 
648
                break;
 
649
        }
 
650
 
 
651
        widget = gtk_label_new_with_mnemonic (label);
 
652
        gtk_box_pack_end (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
 
653
 
 
654
        return align;
 
655
}
 
656
 
 
657
static void
 
658
switch_page (GSLockPlug *plug,
 
659
             GtkButton  *button)
 
660
{
 
661
        GtkWidget *ok_widget;
 
662
        GtkWidget *other_widget;
 
663
        gint       current_page;
 
664
        gint       next_page;
 
665
 
 
666
        g_return_if_fail (plug != NULL);
 
667
 
 
668
        current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (plug->priv->notebook));
 
669
        next_page = (current_page == AUTH_PAGE) ? SWITCH_PAGE : AUTH_PAGE;
 
670
 
 
671
        other_widget = get_switch_button_for_page (next_page);
 
672
        ok_widget = get_ok_button_for_page (next_page);
 
673
 
 
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);
 
677
 
 
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);
 
681
 
 
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);
 
685
        }
 
686
 
 
687
        gtk_notebook_set_current_page (GTK_NOTEBOOK (plug->priv->notebook), next_page);
 
688
 
 
689
        /* this counts as activity so restart the timer */
 
690
        restart_monitor_progress (plug);
 
691
}
 
692
 
 
693
static void
 
694
logout_button_clicked (GtkButton  *button,
 
695
                       GSLockPlug *plug)
 
696
{
 
697
        char   *argv [4];
 
698
        GError *error = NULL;
 
699
 
 
700
        argv [0] = BINDIR "/gnome-session-save";
 
701
        argv [1] = "--kill";
 
702
        argv [2] = "--silent";
 
703
        argv [3] = NULL;
 
704
 
 
705
        g_spawn_async (g_get_home_dir (),
 
706
                       argv,
 
707
                       NULL,
 
708
                       0,
 
709
                       NULL,
 
710
                       NULL,
 
711
                       NULL,
 
712
                       &error);
 
713
        if (error) {
 
714
                g_warning ("Could not run logout command: %s", error->message);
 
715
                g_error_free (error);
 
716
        }
 
717
}
 
718
 
 
719
/* button press handler used to inhibit popup menu */
 
720
static gint
 
721
entry_button_press (GtkWidget      *widget,
 
722
                    GdkEventButton *event)
 
723
{
 
724
        if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
 
725
                return TRUE;
 
726
 
 
727
        return FALSE;
 
728
}
 
729
 
 
730
static gint
 
731
entry_key_press (GtkWidget   *widget,
 
732
                 GdkEventKey *event,
 
733
                 GSLockPlug  *plug)
 
734
{
 
735
        gboolean capslock_on;
 
736
 
 
737
        restart_monitor_progress (plug);
 
738
 
 
739
        capslock_on = is_capslock_on ();
 
740
 
 
741
        if (capslock_on != plug->priv->caps_lock_on)
 
742
                capslock_update (plug, capslock_on);
 
743
 
 
744
        switch (event->keyval) {
 
745
        case GDK_Return:
 
746
        case GDK_KP_Enter:
 
747
                gs_lock_plug_response (plug, GS_LOCK_PLUG_RESPONSE_OK);
 
748
                break;
 
749
        default:
 
750
                break;
 
751
        }
 
752
        
 
753
        return FALSE;
 
754
}
 
755
 
 
756
static ResponseData*
 
757
get_response_data (GtkWidget *widget,
 
758
                   gboolean   create)
 
759
{
 
760
        ResponseData *ad = g_object_get_data (G_OBJECT (widget),
 
761
                                              "gs-lock-plug-response-data");
 
762
 
 
763
        if (ad == NULL && create) {
 
764
                ad = g_new (ResponseData, 1);
 
765
      
 
766
                g_object_set_data_full (G_OBJECT (widget),
 
767
                                        "gs-lock-plug-response-data",
 
768
                                        ad,
 
769
                                        g_free);
 
770
        }
 
771
 
 
772
        return ad;
 
773
}
 
774
 
 
775
/* adapted from gtkdialog */
 
776
static void
 
777
action_widget_activated (GtkWidget  *widget,
 
778
                         GSLockPlug *plug)
 
779
{
 
780
        ResponseData *ad;
 
781
        gint response_id;
 
782
  
 
783
        g_return_if_fail (GS_IS_LOCK_PLUG (plug));
 
784
 
 
785
        response_id = GS_LOCK_PLUG_RESPONSE_NONE;
 
786
  
 
787
        ad = get_response_data (widget, TRUE);
 
788
 
 
789
        g_assert (ad != NULL);
 
790
  
 
791
        response_id = ad->response_id;
 
792
 
 
793
        gs_lock_plug_response (plug, response_id);
 
794
}
 
795
 
 
796
/* adapted from gtk_dialog_add_action_widget */
 
797
static void
 
798
gs_lock_plug_add_action_widget (GSLockPlug *plug,
 
799
                                GtkWidget  *child,
 
800
                                gint        response_id)
 
801
{
 
802
        ResponseData *ad;
 
803
        gint signal_id = 0;
 
804
  
 
805
        g_return_if_fail (GS_IS_LOCK_PLUG (plug));
 
806
        g_return_if_fail (GTK_IS_WIDGET (child));
 
807
 
 
808
        ad = get_response_data (child, TRUE);
 
809
 
 
810
        ad->response_id = response_id;
 
811
 
 
812
        if (GTK_IS_BUTTON (child))
 
813
                signal_id = g_signal_lookup ("clicked", GTK_TYPE_BUTTON);
 
814
        else
 
815
                signal_id = GTK_WIDGET_GET_CLASS (child)->activate_signal != 0;
 
816
 
 
817
        if (signal_id) {
 
818
                GClosure *closure;
 
819
 
 
820
                closure = g_cclosure_new_object (G_CALLBACK (action_widget_activated),
 
821
                                                 G_OBJECT (plug));
 
822
                g_signal_connect_closure_by_id (child,
 
823
                                                signal_id,
 
824
                                                0,
 
825
                                                closure,
 
826
                                                FALSE);
 
827
        } else
 
828
                g_warning ("Only 'activatable' widgets can be packed into the action area of a GSLockPlug");
 
829
 
 
830
        gtk_box_pack_end (GTK_BOX (plug->action_area),
 
831
                          child,
 
832
                          FALSE, TRUE, 0);
 
833
  
 
834
        if (response_id == GTK_RESPONSE_HELP)
 
835
                gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (plug->action_area), child, TRUE);
 
836
}
 
837
 
 
838
/* adapted from gtk_dialog_add_button */
 
839
static GtkWidget *
 
840
gs_lock_plug_add_button (GSLockPlug  *plug,
 
841
                         const gchar *button_text,
 
842
                         gint         response_id)
 
843
{
 
844
        GtkWidget *button;
 
845
 
 
846
        g_return_val_if_fail (GS_IS_LOCK_PLUG (plug), NULL);
 
847
        g_return_val_if_fail (button_text != NULL, NULL);
 
848
 
 
849
        button = gtk_button_new_from_stock (button_text);
 
850
 
 
851
        GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
 
852
 
 
853
        gtk_widget_show (button);
 
854
 
 
855
        gs_lock_plug_add_action_widget (plug,
 
856
                                        button,
 
857
                                        response_id);
 
858
 
 
859
        return button;
 
860
}
 
861
 
 
862
static void
 
863
gs_lock_plug_set_default_response (GSLockPlug *plug,
 
864
                                   gint        response_id)
 
865
{
 
866
        GList *children;
 
867
        GList *tmp_list;
 
868
 
 
869
        g_return_if_fail (GS_IS_LOCK_PLUG (plug));
 
870
 
 
871
        children = gtk_container_get_children (GTK_CONTAINER (plug->action_area));
 
872
 
 
873
        tmp_list = children;
 
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");
 
878
 
 
879
                if (rd && rd->response_id == response_id)
 
880
                        gtk_widget_grab_default (widget);
 
881
            
 
882
                tmp_list = g_list_next (tmp_list);
 
883
        }
 
884
 
 
885
        g_list_free (children);
 
886
}
 
887
 
 
888
typedef struct
 
889
{
 
890
        GtkTreeIter iter;
 
891
        GtkWidget  *tree;
 
892
} DisplayChangedData;
 
893
 
 
894
static void
 
895
user_displays_changed_cb (FusaUser           *user,
 
896
                          DisplayChangedData *data)
 
897
{
 
898
        const char   *name;
 
899
        gboolean      is_active;
 
900
        int           n_displays;
 
901
        GdkPixbuf    *pixbuf;
 
902
        int           icon_size = FACE_ICON_SIZE;
 
903
        GtkTreeModel *filter_model;
 
904
        GtkTreeModel *model;
 
905
 
 
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);
 
910
 
 
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));
 
913
 
 
914
        gtk_list_store_set (GTK_LIST_STORE (model), &data->iter,
 
915
                            NAME_COLUMN, name,
 
916
                            DISPLAY_NAME_COLUMN, fusa_user_get_display_name (user),
 
917
                            ACTIVE_COLUMN, is_active,
 
918
                            PIXBUF_COLUMN, pixbuf,
 
919
                            -1);
 
920
}
 
921
 
 
922
static void
 
923
populate_model (GSLockPlug   *plug,
 
924
                GtkListStore *store)
 
925
{
 
926
        GtkTreeIter   iter;
 
927
        GSList       *users;
 
928
        GdkPixbuf    *pixbuf;
 
929
        int           icon_size = FACE_ICON_SIZE;
 
930
        GtkIconTheme *theme;
 
931
 
 
932
        profile_start ("start", NULL);
 
933
 
 
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));
 
936
        else
 
937
                theme = gtk_icon_theme_get_default ();
 
938
        
 
939
        pixbuf = gtk_icon_theme_load_icon (theme, "gdm", icon_size, 0, NULL);
 
940
 
 
941
#if 0
 
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,
 
947
                            -1);
 
948
        gtk_list_store_append (store, &iter);
 
949
        gtk_list_store_set (store, &iter,
 
950
                            DISPLAY_NAME_COLUMN, NULL,
 
951
                            NAME_COLUMN, "__separator",
 
952
                            -1);
 
953
#endif
 
954
 
 
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");
 
962
                gnome_vfs_init ();
 
963
                profile_end ("end", "gnome_vfs_init");
 
964
 
 
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");
 
968
        }
 
969
 
 
970
        users = fusa_manager_list_users (plug->priv->fusa_manager);
 
971
        profile_end ("end", "FUSA list users");
 
972
 
 
973
        while (users) {
 
974
                FusaUser           *user;
 
975
                gboolean            is_active;
 
976
                guint               n_displays;
 
977
                DisplayChangedData *ddata;
 
978
 
 
979
                user = users->data;
 
980
 
 
981
                /* skip the current user */
 
982
                if (fusa_user_get_uid (user) == getuid ()) {
 
983
                        users = g_slist_delete_link (users, users);
 
984
                        continue;
 
985
                }
 
986
 
 
987
                n_displays = fusa_user_get_n_displays (user);
 
988
                is_active = n_displays > 0;
 
989
 
 
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);
 
993
 
 
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,
 
1000
                                    -1);
 
1001
 
 
1002
                ddata = g_new0 (DisplayChangedData, 1);
 
1003
                ddata->iter = iter;
 
1004
                ddata->tree = plug->priv->user_treeview;
 
1005
 
 
1006
                g_signal_connect_data (user, "displays-changed",
 
1007
                                       G_CALLBACK (user_displays_changed_cb), ddata,
 
1008
                                       (GClosureNotify) g_free, 0);
 
1009
 
 
1010
                users = g_slist_delete_link (users, users);
 
1011
        }
 
1012
 
 
1013
        profile_end ("end", NULL);
 
1014
}
 
1015
 
 
1016
static int
 
1017
compare_users (GtkTreeModel *model,
 
1018
               GtkTreeIter  *a,
 
1019
               GtkTreeIter  *b,
 
1020
               gpointer      user_data)
 
1021
{
 
1022
        char *name_a;
 
1023
        char *name_b;
 
1024
        char *label_a;
 
1025
        char *label_b;
 
1026
        int   result;
 
1027
 
 
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);
 
1032
 
 
1033
        if (! name_a)
 
1034
                return 1;
 
1035
        else if (! name_b)
 
1036
                return -1;
 
1037
 
 
1038
        if (strcmp (name_a, "__new_user") == 0)
 
1039
                return -1;
 
1040
        else if (strcmp (name_b, "__new_user") == 0)
 
1041
                return 1;
 
1042
        else if (strcmp (name_a, "__separator") == 0)
 
1043
                return -1;
 
1044
        else if (strcmp (name_b, "__separator") == 0)
 
1045
                return 1;
 
1046
 
 
1047
        if (! label_a)
 
1048
                return 1;
 
1049
        else if (! label_b)
 
1050
                return -1;
 
1051
 
 
1052
        result = strcmp (label_a, label_b);
 
1053
 
 
1054
        g_free (label_a);
 
1055
        g_free (label_b);
 
1056
        g_free (name_a);
 
1057
        g_free (name_b);
 
1058
 
 
1059
        return result;
 
1060
}
 
1061
 
 
1062
static gboolean
 
1063
separator_func (GtkTreeModel *model,
 
1064
                GtkTreeIter  *iter,
 
1065
                gpointer      data)
 
1066
{
 
1067
        int   column = GPOINTER_TO_INT (data);
 
1068
        char *text;
 
1069
        
 
1070
        gtk_tree_model_get (model, iter, column, &text, -1);
 
1071
        
 
1072
        if (text && strcmp (text, "__separator") == 0)
 
1073
                return TRUE;
 
1074
        
 
1075
        g_free (text);
 
1076
 
 
1077
        return FALSE;
 
1078
}
 
1079
 
 
1080
static gboolean
 
1081
filter_out_users (GtkTreeModel *model,
 
1082
                  GtkTreeIter  *iter,
 
1083
                  GSLockPlug   *plug)
 
1084
{
 
1085
        gboolean is_active;
 
1086
        gboolean visible;
 
1087
        char    *name;
 
1088
 
 
1089
        gtk_tree_model_get (model, iter,
 
1090
                            NAME_COLUMN, &name,
 
1091
                            ACTIVE_COLUMN, &is_active,
 
1092
                            -1);
 
1093
        if (! name)
 
1094
                return FALSE;
 
1095
 
 
1096
        if (strcmp (name, "__new_user") == 0
 
1097
            || strcmp (name, "__separator") == 0) {
 
1098
                visible = TRUE;
 
1099
        } else {
 
1100
                /* FIXME: do we show all users or only active ones? */
 
1101
                visible = TRUE;
 
1102
                /*visible = is_active;*/
 
1103
        }
 
1104
 
 
1105
        g_free (name);
 
1106
 
 
1107
        return visible;
 
1108
}
 
1109
 
 
1110
static void
 
1111
setup_treeview (GSLockPlug *plug)
 
1112
{
 
1113
        GtkListStore      *store;
 
1114
        GtkTreeViewColumn *column;
 
1115
        GtkCellRenderer   *renderer;
 
1116
        GtkTreeModel      *filter;
 
1117
 
 
1118
        /* if user switching is not enabled then do nothing */
 
1119
        if (! plug->priv->switch_enabled)
 
1120
                return;
 
1121
 
 
1122
        profile_start ("start", NULL);
 
1123
 
 
1124
        store = gtk_list_store_new (N_COLUMNS,
 
1125
                                    G_TYPE_STRING,
 
1126
                                    G_TYPE_STRING,
 
1127
                                    G_TYPE_BOOLEAN,
 
1128
                                    GDK_TYPE_PIXBUF);
 
1129
        populate_model (plug, store);
 
1130
 
 
1131
        filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
 
1132
 
 
1133
        gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
 
1134
                                                (GtkTreeModelFilterVisibleFunc) filter_out_users,
 
1135
                                                plug,
 
1136
                                                NULL);
 
1137
 
 
1138
        gtk_tree_view_set_model (GTK_TREE_VIEW (plug->priv->user_treeview),
 
1139
                                 filter);
 
1140
 
 
1141
        g_object_unref (store);
 
1142
        g_object_unref (filter);
 
1143
 
 
1144
        renderer = gtk_cell_renderer_pixbuf_new ();
 
1145
        column = gtk_tree_view_column_new_with_attributes ("Image", renderer,
 
1146
                                                           "pixbuf", PIXBUF_COLUMN,
 
1147
                                                           NULL);
 
1148
        gtk_tree_view_append_column (GTK_TREE_VIEW (plug->priv->user_treeview), column);
 
1149
 
 
1150
        renderer = gtk_cell_renderer_text_new ();
 
1151
        column = gtk_tree_view_column_new_with_attributes ("Name", renderer,
 
1152
                                                           "text", DISPLAY_NAME_COLUMN,
 
1153
                                                           NULL);
 
1154
        gtk_tree_view_append_column (GTK_TREE_VIEW (plug->priv->user_treeview), column);
 
1155
 
 
1156
        gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (plug->priv->user_treeview),
 
1157
                                              separator_func,
 
1158
                                              GINT_TO_POINTER (NAME_COLUMN),
 
1159
                                              NULL);
 
1160
 
 
1161
        gtk_tree_view_column_set_sort_column_id (column, 0);
 
1162
        gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store),
 
1163
                                         0,
 
1164
                                         compare_users,
 
1165
                                         NULL, NULL);
 
1166
        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
 
1167
                                              0,
 
1168
                                              GTK_SORT_ASCENDING);
 
1169
        profile_end ("end", NULL);
 
1170
}
 
1171
 
 
1172
static gboolean
 
1173
setup_treeview_idle (GSLockPlug *plug)
 
1174
{
 
1175
        setup_treeview (plug);
 
1176
 
 
1177
        return FALSE;
 
1178
}
 
1179
 
 
1180
static const char *
 
1181
get_user_display_name (void)
 
1182
{
 
1183
        const char *name;
 
1184
 
 
1185
        name = g_get_real_name ();
 
1186
 
 
1187
        if (name == NULL || strcmp (name, "Unknown") == 0) {
 
1188
                name = g_get_user_name ();
 
1189
        }
 
1190
 
 
1191
        return name;
 
1192
}
 
1193
 
 
1194
static void
 
1195
label_set_big_bold (GtkLabel *label)
 
1196
{
 
1197
        PangoAttrList        *pattrlist;
 
1198
        PangoAttribute       *attr;
 
1199
 
 
1200
        pattrlist = pango_attr_list_new ();
 
1201
 
 
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);
 
1206
 
 
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);
 
1211
 
 
1212
        gtk_label_set_attributes (label, pattrlist);
 
1213
 
 
1214
        pango_attr_list_unref (pattrlist);
 
1215
}
 
1216
 
 
1217
static void
 
1218
label_set_bigger (GtkLabel *label)
 
1219
{
 
1220
        PangoAttrList        *pattrlist;
 
1221
        PangoAttribute       *attr;
 
1222
 
 
1223
        pattrlist = pango_attr_list_new ();
 
1224
 
 
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);
 
1229
 
 
1230
        gtk_label_set_attributes (label, pattrlist);
 
1231
 
 
1232
        pango_attr_list_unref (pattrlist);
 
1233
}
 
1234
 
 
1235
static void
 
1236
label_set_big (GtkLabel *label)
 
1237
{
 
1238
        PangoAttrList        *pattrlist;
 
1239
        PangoAttribute       *attr;
 
1240
 
 
1241
        pattrlist = pango_attr_list_new ();
 
1242
 
 
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);
 
1247
 
 
1248
        gtk_label_set_attributes (label, pattrlist);
 
1249
 
 
1250
        pango_attr_list_unref (pattrlist);
 
1251
}
 
1252
 
 
1253
static gboolean
 
1254
check_user_file (const gchar *filename,
 
1255
                 uid_t        user,
 
1256
                 gssize       max_file_size,
 
1257
                 gboolean     relax_group,
 
1258
                 gboolean     relax_other)
 
1259
{
 
1260
        struct stat fileinfo;
 
1261
 
 
1262
        if (max_file_size < 0)
 
1263
                max_file_size = G_MAXSIZE;
 
1264
 
 
1265
        /* Exists/Readable? */
 
1266
        if (g_stat (filename, &fileinfo) < 0)
 
1267
                return FALSE;
 
1268
 
 
1269
        /* Is a regular file */
 
1270
        if (G_UNLIKELY (!S_ISREG (fileinfo.st_mode)))
 
1271
                return FALSE;
 
1272
 
 
1273
        /* Owned by user? */
 
1274
        if (G_UNLIKELY (fileinfo.st_uid != user))
 
1275
                return FALSE;
 
1276
 
 
1277
        /* Group not writable or relax_group? */
 
1278
        if (G_UNLIKELY ((fileinfo.st_mode & S_IWGRP) == S_IWGRP && !relax_group))
 
1279
                return FALSE;
 
1280
 
 
1281
        /* Other not writable or relax_other? */
 
1282
        if (G_UNLIKELY ((fileinfo.st_mode & S_IWOTH) == S_IWOTH && !relax_other))
 
1283
                return FALSE;
 
1284
 
 
1285
        /* Size is kosher? */
 
1286
        if (G_UNLIKELY (fileinfo.st_size > max_file_size))
 
1287
                return FALSE;
 
1288
 
 
1289
        return TRUE;
 
1290
}
 
1291
 
 
1292
static GtkWidget *
 
1293
get_face_image ()
 
1294
{
 
1295
        GtkWidget    *image;
 
1296
        GdkPixbuf    *pixbuf;
 
1297
        GtkIconTheme *theme;
 
1298
        const char   *homedir;
 
1299
        char         *path;
 
1300
        int           icon_size = 96;
 
1301
        gsize         user_max_file = 65536;
 
1302
        uid_t         uid;
 
1303
 
 
1304
        homedir = g_get_home_dir ();
 
1305
        uid = getuid ();
 
1306
 
 
1307
        path = g_build_filename (homedir, ".face", NULL);
 
1308
 
 
1309
        pixbuf = NULL;
 
1310
        if (check_user_file (path, uid, user_max_file, 0, 0)) {
 
1311
                pixbuf = gdk_pixbuf_new_from_file_at_size (path,
 
1312
                                                           icon_size,
 
1313
                                                           icon_size,
 
1314
                                                           NULL);
 
1315
        }
 
1316
 
 
1317
        theme = gtk_icon_theme_get_default ();
 
1318
 
 
1319
        if (! pixbuf) {
 
1320
                pixbuf = gtk_icon_theme_load_icon (theme,
 
1321
                                                   "stock_person",
 
1322
                                                   icon_size,
 
1323
                                                   0,
 
1324
                                                   NULL);
 
1325
        }
 
1326
 
 
1327
        if (! pixbuf) {
 
1328
                pixbuf = gtk_icon_theme_load_icon (theme,
 
1329
                                                   GTK_STOCK_MISSING_IMAGE,
 
1330
                                                   icon_size,
 
1331
                                                   0,
 
1332
                                                   NULL);
 
1333
        }
 
1334
 
 
1335
        image = gtk_image_new_from_pixbuf (pixbuf);
 
1336
 
 
1337
        g_object_unref (pixbuf);
 
1338
 
 
1339
        return image;
 
1340
}
 
1341
 
 
1342
static void
 
1343
create_page_one (GSLockPlug *plug)
 
1344
{
 
1345
        GtkWidget            *widget;
 
1346
        GtkWidget            *password_label;
 
1347
        GtkWidget            *align;
 
1348
        GtkWidget            *vbox;
 
1349
        GtkWidget            *vbox2;
 
1350
        GtkWidget            *hbox;
 
1351
        char                 *str;
 
1352
 
 
1353
        profile_start ("start", "page one");
 
1354
 
 
1355
        align = gtk_alignment_new (0.5, 0.5, 1, 1);
 
1356
        gtk_notebook_append_page (GTK_NOTEBOOK (plug->priv->notebook), align, NULL);
 
1357
 
 
1358
        vbox = gtk_vbox_new (FALSE, 12);
 
1359
        gtk_container_add (GTK_CONTAINER (align), vbox);
 
1360
 
 
1361
        /* should we make this a gconf preference? */
 
1362
        if (0) {
 
1363
                char *str;
 
1364
 
 
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);
 
1370
                g_free (str);
 
1371
 
 
1372
                label_set_big_bold (GTK_LABEL (widget));
 
1373
        }
 
1374
 
 
1375
        widget = get_face_image ();
 
1376
        gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
 
1377
 
 
1378
        vbox2 = gtk_vbox_new (FALSE, 0);
 
1379
        gtk_box_pack_start (GTK_BOX (vbox), vbox2, FALSE, FALSE, 0);
 
1380
 
 
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);
 
1384
 
 
1385
        label_set_bigger (GTK_LABEL (plug->priv->username_label));
 
1386
 
 
1387
        str = g_strdup_printf ("(%s)", g_get_user_name ());
 
1388
        widget = gtk_label_new (str);
 
1389
        g_free (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);
 
1392
 
 
1393
        vbox2 = gtk_vbox_new (FALSE, 0);
 
1394
        gtk_box_pack_start (GTK_BOX (vbox), vbox2, FALSE, FALSE, 0);
 
1395
 
 
1396
        hbox = gtk_hbox_new (FALSE, 6);
 
1397
        gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, FALSE, 0);
 
1398
 
 
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);
 
1402
 
 
1403
        plug->priv->password_entry = gtk_entry_new ();
 
1404
        gtk_box_pack_start (GTK_BOX (hbox), plug->priv->password_entry, TRUE, TRUE, 0);
 
1405
 
 
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);
 
1413
 
 
1414
        gtk_label_set_mnemonic_widget (GTK_LABEL (password_label),
 
1415
                                       plug->priv->password_entry);
 
1416
 
 
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);
 
1420
 
 
1421
        profile_end ("end", "page one");
 
1422
}
 
1423
 
 
1424
static void
 
1425
create_page_two (GSLockPlug *plug)
 
1426
{
 
1427
        GtkWidget            *widget;
 
1428
        GtkWidget            *vbox;
 
1429
 
 
1430
        profile_start ("start", "page two");
 
1431
 
 
1432
        vbox = gtk_vbox_new (FALSE, 6);
 
1433
        gtk_notebook_append_page (GTK_NOTEBOOK (plug->priv->notebook), vbox, NULL);
 
1434
 
 
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);
 
1438
 
 
1439
        label_set_big (GTK_LABEL (widget));
 
1440
 
 
1441
        widget = gtk_scrolled_window_new (NULL, NULL);
 
1442
        gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (widget),
 
1443
                                             GTK_SHADOW_IN);
 
1444
        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget),
 
1445
                                        GTK_POLICY_NEVER,
 
1446
                                        GTK_POLICY_AUTOMATIC);
 
1447
        gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0);
 
1448
 
 
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);
 
1452
 
 
1453
        g_idle_add ((GSourceFunc)setup_treeview_idle, plug);
 
1454
 
 
1455
        profile_end ("end", "page two");
 
1456
}
 
1457
 
 
1458
static void
 
1459
create_buttons (GSLockPlug *plug)
 
1460
{
 
1461
        GtkWidget            *widget;
 
1462
 
 
1463
        profile_start ("start", "buttons");
 
1464
 
 
1465
        plug->priv->switch_button = gtk_button_new ();
 
1466
        gtk_button_set_focus_on_click (GTK_BUTTON (plug->priv->switch_button), FALSE);
 
1467
 
 
1468
        widget = get_switch_button_for_page (AUTH_PAGE);
 
1469
        gtk_container_add (GTK_CONTAINER (plug->priv->switch_button), widget);
 
1470
 
 
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,
 
1474
                            TRUE, TRUE, 0);
 
1475
        gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (plug->action_area),
 
1476
                                            plug->priv->switch_button,
 
1477
                                            TRUE);
 
1478
 
 
1479
        plug->priv->logout_button =  gs_lock_plug_add_button (GS_LOCK_PLUG (plug),
 
1480
                                                              _("Log _Out"),
 
1481
                                                              GS_LOCK_PLUG_RESPONSE_CANCEL);
 
1482
        gtk_button_set_focus_on_click (GTK_BUTTON (plug->priv->logout_button), FALSE);
 
1483
 
 
1484
        plug->priv->cancel_button =  gs_lock_plug_add_button (GS_LOCK_PLUG (plug),
 
1485
                                                              GTK_STOCK_CANCEL,
 
1486
                                                              GS_LOCK_PLUG_RESPONSE_CANCEL);
 
1487
        gtk_button_set_focus_on_click (GTK_BUTTON (plug->priv->cancel_button), FALSE);
 
1488
 
 
1489
        plug->priv->ok_button = gtk_button_new ();
 
1490
        gtk_button_set_focus_on_click (GTK_BUTTON (plug->priv->ok_button), FALSE);
 
1491
 
 
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);
 
1499
 
 
1500
        gs_lock_plug_set_default_response (plug, GS_LOCK_PLUG_RESPONSE_OK);
 
1501
 
 
1502
        profile_end ("end", "buttons");
 
1503
}
 
1504
 
 
1505
static void
 
1506
gs_lock_plug_init (GSLockPlug *plug)
 
1507
{
 
1508
        profile_start ("start", NULL);
 
1509
 
 
1510
        plug->priv = GS_LOCK_PLUG_GET_PRIVATE (plug);
 
1511
 
 
1512
        plug->priv->fusa_manager = NULL;
 
1513
 
 
1514
        /* Dialog emulation */
 
1515
 
 
1516
        plug->vbox = gtk_vbox_new (FALSE, 0);
 
1517
 
 
1518
        gtk_container_add (GTK_CONTAINER (plug), plug->vbox);
 
1519
 
 
1520
        plug->action_area = gtk_hbutton_box_new ();
 
1521
 
 
1522
        gtk_button_box_set_layout (GTK_BUTTON_BOX (plug->action_area),
 
1523
                                   GTK_BUTTONBOX_END);
 
1524
 
 
1525
        gtk_box_pack_end (GTK_BOX (plug->vbox), plug->action_area,
 
1526
                          FALSE, TRUE, 0);
 
1527
        gtk_widget_show (plug->action_area);
 
1528
 
 
1529
        /* Notebook */
 
1530
 
 
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);
 
1535
 
 
1536
        /* Page 1 */
 
1537
 
 
1538
        create_page_one (plug);
 
1539
 
 
1540
        /* Page 2 */
 
1541
 
 
1542
        create_page_two (plug);
 
1543
 
 
1544
        /* Status text */
 
1545
 
 
1546
        plug->priv->status_label = gtk_label_new (NULL);
 
1547
        gtk_box_pack_start (GTK_BOX (plug->vbox), plug->priv->status_label,
 
1548
                            FALSE, FALSE, 0);
 
1549
 
 
1550
        /* Buttons */
 
1551
 
 
1552
        create_buttons (plug);
 
1553
 
 
1554
        gtk_widget_show_all (plug->vbox);
 
1555
 
 
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);
 
1560
 
 
1561
        plug->priv->timeout = DIALOG_TIMEOUT_MSEC;
 
1562
 
 
1563
        g_signal_connect_swapped (plug->priv->switch_button, "clicked",
 
1564
                                  G_CALLBACK (switch_page), plug);
 
1565
 
 
1566
        g_signal_connect (plug->priv->logout_button, "clicked",
 
1567
                          G_CALLBACK (logout_button_clicked), plug);
 
1568
 
 
1569
        profile_end ("end", NULL);
 
1570
}
 
1571
 
 
1572
static void
 
1573
gs_lock_plug_finalize (GObject *object)
 
1574
{
 
1575
        GSLockPlug *plug;
 
1576
 
 
1577
        g_return_if_fail (object != NULL);
 
1578
        g_return_if_fail (GS_IS_LOCK_PLUG (object));
 
1579
 
 
1580
        plug = GS_LOCK_PLUG (object);
 
1581
 
 
1582
        g_return_if_fail (plug->priv != NULL);
 
1583
 
 
1584
        if (plug->priv->fusa_manager)
 
1585
                g_object_unref (plug->priv->fusa_manager);
 
1586
 
 
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;
 
1590
        }
 
1591
 
 
1592
        if (plug->priv->response_idle_id > 0) {
 
1593
                g_source_remove (plug->priv->response_idle_id);
 
1594
                plug->priv->response_idle_id = 0;
 
1595
        }
 
1596
 
 
1597
        if (plug->priv->idle_id > 0) {
 
1598
                g_source_remove (plug->priv->idle_id);
 
1599
                plug->priv->idle_id = 0;
 
1600
        }
 
1601
 
 
1602
        G_OBJECT_CLASS (parent_class)->finalize (object);
 
1603
}
 
1604
 
 
1605
GtkWidget *
 
1606
gs_lock_plug_new (void)
 
1607
{
 
1608
        GtkWidget *result;
 
1609
 
 
1610
        result = g_object_new (GS_TYPE_LOCK_PLUG, NULL);
 
1611
 
 
1612
        gtk_window_set_focus_on_map (GTK_WINDOW (result), TRUE);
 
1613
 
 
1614
        return result;
 
1615
}