~lightdm-gtk-greeter-team/lightdm-gtk-greeter/trunk

« back to all changes in this revision

Viewing changes to src/lightdm-gtk-greeter.c

  • Committer: Robert Ancell
  • Date: 2011-11-29 03:06:00 UTC
  • Revision ID: robert.ancell@canonical.com-20111129030600-a3yg839xmbd1kr0e
Split lightdm-gtk-greeter out of lightdm

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2010-2011 Robert Ancell.
 
3
 * Author: Robert Ancell <robert.ancell@canonical.com>
 
4
 * 
 
5
 * This program is free software: you can redistribute it and/or modify it under
 
6
 * the terms of the GNU General Public License as published by the Free Software
 
7
 * Foundation, either version 3 of the License, or (at your option) any later
 
8
 * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
 
9
 * license.
 
10
 */
 
11
 
 
12
#include <stdlib.h>
 
13
#include <gtk/gtk.h>
 
14
#include <glib/gi18n.h>
 
15
#include <cairo-xlib.h>
 
16
#include <gdk-pixbuf/gdk-pixbuf.h>
 
17
#include <gdk/gdkx.h>
 
18
 
 
19
#include "lightdm.h"
 
20
 
 
21
static LightDMGreeter *greeter;
 
22
static GKeyFile *state;
 
23
static gchar *state_filename;
 
24
static GtkWindow *login_window, *panel_window;
 
25
static GtkLabel *message_label, *prompt_label;
 
26
static GtkTreeView *user_view;
 
27
static GtkWidget *login_box, *prompt_box;
 
28
static GtkEntry *prompt_entry;
 
29
static GtkComboBox *session_combo;
 
30
static GtkComboBox *language_combo;
 
31
static gchar *default_font_name, *default_theme_name;
 
32
static gboolean cancelling = FALSE, prompted = FALSE;
 
33
 
 
34
static gchar *
 
35
get_session ()
 
36
{
 
37
    GtkTreeIter iter;
 
38
    gchar *session;
 
39
 
 
40
    if (!gtk_combo_box_get_active_iter (session_combo, &iter))
 
41
        return g_strdup (lightdm_greeter_get_default_session_hint (greeter));
 
42
 
 
43
    gtk_tree_model_get (gtk_combo_box_get_model (session_combo), &iter, 1, &session, -1);
 
44
 
 
45
    return session;
 
46
}
 
47
 
 
48
static void
 
49
set_session (const gchar *session)
 
50
{
 
51
    GtkTreeModel *model = gtk_combo_box_get_model (session_combo);
 
52
    GtkTreeIter iter;
 
53
    const gchar *default_session;
 
54
 
 
55
    if (session && gtk_tree_model_get_iter_first (model, &iter))
 
56
    {
 
57
        do
 
58
        {
 
59
            gchar *s;
 
60
            gboolean matched;
 
61
            gtk_tree_model_get (model, &iter, 1, &s, -1);
 
62
            matched = strcmp (s, session) == 0;
 
63
            g_free (s);
 
64
            if (matched)
 
65
            {
 
66
                gtk_combo_box_set_active_iter (session_combo, &iter);
 
67
                return;
 
68
            }
 
69
        } while (gtk_tree_model_iter_next (model, &iter));
 
70
    }
 
71
 
 
72
    /* If failed to find this session, then try the default */
 
73
    default_session = lightdm_greeter_get_default_session_hint (greeter);
 
74
    if (default_session && g_strcmp0 (session, default_session) != 0)
 
75
    {
 
76
        set_session (lightdm_greeter_get_default_session_hint (greeter));
 
77
        return;
 
78
    }
 
79
 
 
80
    /* Otherwise just pick the first session */
 
81
    gtk_combo_box_set_active (session_combo, 0);
 
82
}
 
83
 
 
84
static gchar *
 
85
get_language ()
 
86
{
 
87
    GtkTreeIter iter;
 
88
    gchar *language;
 
89
 
 
90
    if (!gtk_combo_box_get_active_iter (language_combo, &iter))
 
91
        return NULL;
 
92
 
 
93
    gtk_tree_model_get (gtk_combo_box_get_model (language_combo), &iter, 1, &language, -1);
 
94
 
 
95
    return language;
 
96
}
 
97
 
 
98
static void
 
99
set_language (const gchar *language)
 
100
{
 
101
    GtkTreeModel *model = gtk_combo_box_get_model (language_combo);
 
102
    GtkTreeIter iter;
 
103
    const gchar *default_language = NULL;
 
104
 
 
105
    if (language && gtk_tree_model_get_iter_first (model, &iter))
 
106
    {
 
107
        do
 
108
        {
 
109
            gchar *s;
 
110
            gboolean matched;
 
111
            gtk_tree_model_get (model, &iter, 1, &s, -1);
 
112
            matched = strcmp (s, language) == 0;
 
113
            g_free (s);
 
114
            if (matched)
 
115
            {
 
116
                gtk_combo_box_set_active_iter (language_combo, &iter);
 
117
                return;
 
118
            }
 
119
        } while (gtk_tree_model_iter_next (model, &iter));
 
120
    }
 
121
 
 
122
    /* If failed to find this language, then try the default */
 
123
    if (lightdm_get_language ())
 
124
        default_language = lightdm_language_get_code (lightdm_get_language ());
 
125
    if (default_language && g_strcmp0 (default_language, language) != 0)
 
126
        set_language (default_language);
 
127
}
 
128
 
 
129
static void
 
130
set_message_label (const gchar *text)
 
131
{
 
132
    gtk_widget_set_visible (GTK_WIDGET (message_label), strcmp (text, "") != 0);
 
133
    gtk_label_set_text (message_label, text);
 
134
}
 
135
 
 
136
static void
 
137
start_authentication (const gchar *username)
 
138
{
 
139
    gchar *data;
 
140
    gsize data_length;
 
141
    GError *error = NULL;
 
142
 
 
143
    cancelling = FALSE;
 
144
    prompted = FALSE;
 
145
 
 
146
    g_key_file_set_value (state, "greeter", "last-user", username);
 
147
    data = g_key_file_to_data (state, &data_length, &error);
 
148
    if (error)
 
149
        g_warning ("Failed to save state file: %s", error->message);
 
150
    g_clear_error (&error);
 
151
    if (data)
 
152
    {
 
153
        g_file_set_contents (state_filename, data, data_length, &error);
 
154
        if (error)
 
155
            g_warning ("Failed to save state file: %s", error->message);
 
156
        g_clear_error (&error);
 
157
    }
 
158
    g_free (data);
 
159
 
 
160
    if (strcmp (username, "*other") == 0)
 
161
    {
 
162
        lightdm_greeter_authenticate (greeter, NULL);
 
163
    }
 
164
    else if (strcmp (username, "*guest") == 0)
 
165
    {
 
166
        lightdm_greeter_authenticate_as_guest (greeter);
 
167
    }
 
168
    else
 
169
    {
 
170
        LightDMUser *user;
 
171
 
 
172
        user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username);
 
173
        if (user)
 
174
        {
 
175
            set_session (lightdm_user_get_session (user));
 
176
            set_language (lightdm_user_get_language (user));
 
177
        }
 
178
        else
 
179
        {
 
180
            set_session (NULL);
 
181
            set_language (NULL);
 
182
        }
 
183
 
 
184
        lightdm_greeter_authenticate (greeter, username);
 
185
    }
 
186
}
 
187
 
 
188
static void
 
189
cancel_authentication (void)
 
190
{
 
191
    /* If in authentication then stop that first */
 
192
    cancelling = FALSE;
 
193
    if (lightdm_greeter_get_in_authentication (greeter))
 
194
    {
 
195
        cancelling = TRUE;
 
196
        lightdm_greeter_cancel_authentication (greeter);
 
197
        return;
 
198
    }
 
199
 
 
200
    /* Start a new login or return to the user list */
 
201
    if (lightdm_greeter_get_hide_users_hint (greeter))
 
202
        start_authentication ("*other");
 
203
    else
 
204
    {
 
205
        gtk_widget_hide (login_box);
 
206
        gtk_widget_grab_focus (GTK_WIDGET (user_view));
 
207
    }
 
208
}
 
209
 
 
210
static void
 
211
start_session (void)
 
212
{
 
213
    gchar *language;
 
214
    gchar *session;
 
215
 
 
216
    language = get_language ();
 
217
    if (language)
 
218
        lightdm_greeter_set_language (greeter, language);
 
219
    g_free (language);
 
220
 
 
221
    session = get_session ();
 
222
    if (!lightdm_greeter_start_session_sync (greeter, session, NULL))
 
223
    {
 
224
        set_message_label (_("Failed to start session"));
 
225
        start_authentication (lightdm_greeter_get_authentication_user (greeter));
 
226
    }
 
227
    g_free (session);
 
228
}
 
229
 
 
230
void user_treeview_selection_changed_cb (GtkTreeSelection *selection);
 
231
G_MODULE_EXPORT
 
232
void
 
233
user_treeview_selection_changed_cb (GtkTreeSelection *selection)
 
234
{
 
235
    GtkTreeModel *model;
 
236
    GtkTreeIter iter;
 
237
 
 
238
    if (gtk_tree_selection_get_selected (selection, &model, &iter))
 
239
    {
 
240
        gchar *user;
 
241
 
 
242
        gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 0, &user, -1);
 
243
        start_authentication (user);
 
244
        g_free (user);
 
245
    }
 
246
}
 
247
 
 
248
void login_cb (GtkWidget *widget);
 
249
G_MODULE_EXPORT
 
250
void
 
251
login_cb (GtkWidget *widget)
 
252
{
 
253
    gtk_widget_set_sensitive (GTK_WIDGET (prompt_entry), FALSE);
 
254
    set_message_label ("");
 
255
 
 
256
    if (lightdm_greeter_get_is_authenticated (greeter))
 
257
        start_session ();
 
258
    else if (lightdm_greeter_get_in_authentication (greeter))
 
259
        lightdm_greeter_respond (greeter, gtk_entry_get_text (prompt_entry));
 
260
    else
 
261
        start_authentication (lightdm_greeter_get_authentication_user (greeter));
 
262
}
 
263
 
 
264
void cancel_cb (GtkWidget *widget);
 
265
G_MODULE_EXPORT
 
266
void
 
267
cancel_cb (GtkWidget *widget)
 
268
{
 
269
    cancel_authentication ();
 
270
}
 
271
 
 
272
static void
 
273
show_prompt_cb (LightDMGreeter *greeter, const gchar *text, LightDMPromptType type)
 
274
{
 
275
    prompted = TRUE;
 
276
 
 
277
    gtk_widget_show (GTK_WIDGET (login_box));
 
278
    gtk_label_set_text (prompt_label, text);
 
279
    gtk_widget_set_sensitive (GTK_WIDGET (prompt_entry), TRUE);
 
280
    gtk_entry_set_text (prompt_entry, "");
 
281
    gtk_entry_set_visibility (prompt_entry, type != LIGHTDM_PROMPT_TYPE_SECRET);
 
282
    gtk_widget_show (GTK_WIDGET (prompt_box));
 
283
    gtk_widget_grab_focus (GTK_WIDGET (prompt_entry));
 
284
}
 
285
 
 
286
static void
 
287
show_message_cb (LightDMGreeter *greeter, const gchar *text, LightDMMessageType type)
 
288
{
 
289
    set_message_label (text);
 
290
}
 
291
 
 
292
static void
 
293
authentication_complete_cb (LightDMGreeter *greeter)
 
294
{
 
295
    gtk_entry_set_text (prompt_entry, "");
 
296
 
 
297
    if (cancelling)
 
298
    {
 
299
        cancel_authentication ();
 
300
        return;
 
301
    }
 
302
 
 
303
    gtk_widget_hide (prompt_box);
 
304
    gtk_widget_show (login_box);
 
305
 
 
306
    if (lightdm_greeter_get_is_authenticated (greeter))
 
307
    {
 
308
        if (prompted)
 
309
            start_session ();
 
310
    }
 
311
    else
 
312
    {
 
313
        if (prompted)
 
314
        {
 
315
            set_message_label (_("Incorrect password, please try again"));
 
316
            start_authentication (lightdm_greeter_get_authentication_user (greeter));
 
317
        }
 
318
        else
 
319
            set_message_label (_("Failed to authenticate"));
 
320
    }
 
321
}
 
322
 
 
323
static void
 
324
autologin_timer_expired_cb (LightDMGreeter *greeter)
 
325
{
 
326
    if (lightdm_greeter_get_autologin_guest_hint (greeter))
 
327
        start_authentication ("*guest");
 
328
    else if (lightdm_greeter_get_autologin_user_hint (greeter))
 
329
        start_authentication (lightdm_greeter_get_autologin_user_hint (greeter));
 
330
}
 
331
 
 
332
static void
 
333
center_window (GtkWindow *window)
 
334
{
 
335
    GdkScreen *screen;
 
336
    GtkAllocation allocation;
 
337
    GdkRectangle monitor_geometry;
 
338
 
 
339
    screen = gtk_window_get_screen (window);
 
340
    gdk_screen_get_monitor_geometry (screen, gdk_screen_get_primary_monitor (screen), &monitor_geometry);
 
341
    gtk_widget_get_allocation (GTK_WIDGET (window), &allocation);
 
342
    gtk_window_move (window,
 
343
                     monitor_geometry.x + (monitor_geometry.width - allocation.width) / 2,
 
344
                     monitor_geometry.y + (monitor_geometry.height - allocation.height) / 2);
 
345
}
 
346
 
 
347
void suspend_cb (GtkWidget *widget, LightDMGreeter *greeter);
 
348
G_MODULE_EXPORT
 
349
void
 
350
suspend_cb (GtkWidget *widget, LightDMGreeter *greeter)
 
351
{
 
352
    lightdm_suspend (NULL);
 
353
}
 
354
 
 
355
void hibernate_cb (GtkWidget *widget, LightDMGreeter *greeter);
 
356
G_MODULE_EXPORT
 
357
void
 
358
hibernate_cb (GtkWidget *widget, LightDMGreeter *greeter)
 
359
{
 
360
    lightdm_hibernate (NULL);
 
361
}
 
362
 
 
363
void restart_cb (GtkWidget *widget, LightDMGreeter *greeter);
 
364
G_MODULE_EXPORT
 
365
void
 
366
restart_cb (GtkWidget *widget, LightDMGreeter *greeter)
 
367
{
 
368
    GtkWidget *dialog;
 
369
 
 
370
    gtk_widget_hide (GTK_WIDGET (login_window));
 
371
 
 
372
    dialog = gtk_message_dialog_new (NULL,
 
373
                                     GTK_DIALOG_MODAL,
 
374
                                     GTK_MESSAGE_OTHER,
 
375
                                     GTK_BUTTONS_NONE,
 
376
                                     "%s", _("Are you sure you want to close all programs and restart the computer?"));
 
377
    gtk_dialog_add_buttons (GTK_DIALOG (dialog), _("Return To Login"), FALSE, _("Restart"), TRUE, NULL);
 
378
    gtk_widget_show_all (dialog);
 
379
    center_window (GTK_WINDOW (dialog));
 
380
 
 
381
    if (gtk_dialog_run (GTK_DIALOG (dialog)))
 
382
        lightdm_restart (NULL);
 
383
 
 
384
    gtk_widget_destroy (dialog);
 
385
    gtk_widget_show (GTK_WIDGET (login_window));
 
386
}
 
387
 
 
388
void shutdown_cb (GtkWidget *widget, LightDMGreeter *greeter);
 
389
G_MODULE_EXPORT
 
390
void
 
391
shutdown_cb (GtkWidget *widget, LightDMGreeter *greeter)
 
392
{
 
393
    GtkWidget *dialog;
 
394
 
 
395
    gtk_widget_hide (GTK_WIDGET (login_window));
 
396
 
 
397
    dialog = gtk_message_dialog_new (NULL,
 
398
                                     GTK_DIALOG_MODAL,
 
399
                                     GTK_MESSAGE_OTHER,
 
400
                                     GTK_BUTTONS_NONE,
 
401
                                     "%s", _("Are you sure you want to close all programs and shutdown the computer?"));
 
402
    gtk_dialog_add_buttons (GTK_DIALOG (dialog), _("Return To Login"), FALSE, _("Shutdown"), TRUE, NULL);
 
403
    gtk_widget_show_all (dialog);
 
404
    center_window (GTK_WINDOW (dialog));
 
405
 
 
406
    if (gtk_dialog_run (GTK_DIALOG (dialog)))
 
407
        lightdm_shutdown (NULL);
 
408
 
 
409
    gtk_widget_destroy (dialog);
 
410
    gtk_widget_show (GTK_WIDGET (login_window));
 
411
}
 
412
 
 
413
static void
 
414
user_added_cb (LightDMUserList *user_list, LightDMUser *user)
 
415
{
 
416
    GtkTreeModel *model;
 
417
    GtkTreeIter iter;
 
418
 
 
419
    model = gtk_tree_view_get_model (user_view);
 
420
 
 
421
    gtk_list_store_append (GTK_LIST_STORE (model), &iter);
 
422
    gtk_list_store_set (GTK_LIST_STORE (model), &iter,
 
423
                        0, lightdm_user_get_name (user),
 
424
                        1, lightdm_user_get_display_name (user),
 
425
                        2, lightdm_user_get_logged_in (user) ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
 
426
                        /*3, pixbuf,*/
 
427
                        -1);
 
428
}
 
429
 
 
430
static gboolean
 
431
get_user_iter (const gchar *username, GtkTreeIter *iter)
 
432
{
 
433
    GtkTreeModel *model;
 
434
 
 
435
    model = gtk_tree_view_get_model (user_view);
 
436
  
 
437
    if (!gtk_tree_model_get_iter_first (model, iter))
 
438
        return FALSE;
 
439
    do
 
440
    {
 
441
        gchar *name;
 
442
        gboolean matched;
 
443
 
 
444
        gtk_tree_model_get (model, iter, 0, &name, -1);
 
445
        matched = g_strcmp0 (name, username) == 0;
 
446
        g_free (name);
 
447
        if (matched)
 
448
            return TRUE;
 
449
    } while (gtk_tree_model_iter_next (model, iter));
 
450
 
 
451
    return FALSE;
 
452
}
 
453
 
 
454
static void
 
455
user_changed_cb (LightDMUserList *user_list, LightDMUser *user)
 
456
{
 
457
    GtkTreeModel *model;
 
458
    GtkTreeIter iter;
 
459
 
 
460
    if (!get_user_iter (lightdm_user_get_name (user), &iter))
 
461
        return;
 
462
 
 
463
    model = gtk_tree_view_get_model (user_view);
 
464
    gtk_list_store_set (GTK_LIST_STORE (model), &iter,
 
465
                        0, lightdm_user_get_name (user),
 
466
                        1, lightdm_user_get_display_name (user),
 
467
                        2, lightdm_user_get_logged_in (user) ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
 
468
                        /*3, pixbuf,*/
 
469
                        -1);
 
470
}
 
471
 
 
472
static void
 
473
user_removed_cb (LightDMUserList *user_list, LightDMUser *user)
 
474
{
 
475
    GtkTreeModel *model;
 
476
    GtkTreeIter iter;
 
477
 
 
478
    if (!get_user_iter (lightdm_user_get_name (user), &iter))
 
479
        return;
 
480
 
 
481
    model = gtk_tree_view_get_model (user_view);  
 
482
    gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
 
483
}
 
484
 
 
485
void a11y_font_cb (GtkWidget *widget);
 
486
G_MODULE_EXPORT
 
487
void
 
488
a11y_font_cb (GtkWidget *widget)
 
489
{
 
490
    if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
 
491
    {
 
492
        gchar *font_name, **tokens;
 
493
 
 
494
        g_object_get (gtk_settings_get_default (), "gtk-font-name", &font_name, NULL);
 
495
        tokens = g_strsplit (font_name, " ", 2);
 
496
        if (g_strv_length (tokens) == 2)
 
497
        {
 
498
            gint size = atoi (tokens[1]);
 
499
            if (size > 0)
 
500
            {
 
501
                g_free (font_name);
 
502
                font_name = g_strdup_printf ("%s %d", tokens[0], size + 10);
 
503
            }
 
504
        }
 
505
        g_strfreev (tokens);
 
506
 
 
507
        g_object_set (gtk_settings_get_default (), "gtk-font-name", font_name, NULL);
 
508
    }
 
509
    else
 
510
        g_object_set (gtk_settings_get_default (), "gtk-font-name", default_font_name, NULL);
 
511
}
 
512
 
 
513
void a11y_contrast_cb (GtkWidget *widget);
 
514
G_MODULE_EXPORT
 
515
void
 
516
a11y_contrast_cb (GtkWidget *widget)
 
517
{
 
518
    if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
 
519
        g_object_set (gtk_settings_get_default (), "gtk-theme-name", "HighContrastInverse", NULL);
 
520
    else
 
521
        g_object_set (gtk_settings_get_default (), "gtk-theme-name", default_theme_name, NULL);
 
522
}
 
523
 
 
524
static void
 
525
sigterm_cb (int signum)
 
526
{
 
527
    exit (0);
 
528
}
 
529
 
 
530
static void
 
531
load_user_list ()
 
532
{
 
533
    const GList *items, *item;
 
534
    GtkTreeModel *model;
 
535
    GtkTreeIter iter;
 
536
    gchar *last_user;
 
537
    const gchar *selected_user;
 
538
 
 
539
    g_signal_connect (lightdm_user_list_get_instance (), "user-added", G_CALLBACK (user_added_cb), NULL);
 
540
    g_signal_connect (lightdm_user_list_get_instance (), "user-changed", G_CALLBACK (user_changed_cb), NULL);
 
541
    g_signal_connect (lightdm_user_list_get_instance (), "user-removed", G_CALLBACK (user_removed_cb), NULL);
 
542
 
 
543
    model = gtk_tree_view_get_model (user_view);
 
544
    items = lightdm_user_list_get_users (lightdm_user_list_get_instance ());
 
545
    for (item = items; item; item = item->next)
 
546
    {
 
547
        LightDMUser *user = item->data;
 
548
        const gchar *image;
 
549
        GdkPixbuf *pixbuf = NULL;
 
550
 
 
551
        image = lightdm_user_get_image (user);
 
552
        if (image)
 
553
            pixbuf = gdk_pixbuf_new_from_file_at_scale (image, 64, 64, TRUE, NULL);
 
554
        if (!pixbuf)
 
555
            pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
 
556
                                               "stock_person",
 
557
                                               64,
 
558
                                               GTK_ICON_LOOKUP_USE_BUILTIN,
 
559
                                               NULL);
 
560
        /*if (!pixbuf)
 
561
        {
 
562
            pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, 64, 64);
 
563
            memset (gdk_pixbuf_get_pixels (pixbuf), 0, gdk_pixbuf_get_height (pixbuf) * gdk_pixbuf_get_rowstride (pixbuf) * gdk_pixbuf_get_n_channels (pixbuf));
 
564
        }*/
 
565
 
 
566
        gtk_list_store_append (GTK_LIST_STORE (model), &iter);
 
567
        gtk_list_store_set (GTK_LIST_STORE (model), &iter,
 
568
                            0, lightdm_user_get_name (user),
 
569
                            1, lightdm_user_get_display_name (user),
 
570
                            2, lightdm_user_get_logged_in (user) ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
 
571
                            3, pixbuf,
 
572
                            -1);
 
573
    }
 
574
    if (lightdm_greeter_get_has_guest_account_hint (greeter))
 
575
    {
 
576
        gtk_list_store_append (GTK_LIST_STORE (model), &iter);
 
577
        gtk_list_store_set (GTK_LIST_STORE (model), &iter,
 
578
                            0, "*guest",
 
579
                            1, _("Guest Account"),
 
580
                            2, PANGO_WEIGHT_NORMAL,
 
581
                            3, gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), "stock_person", 64, 0, NULL),
 
582
                            -1);
 
583
    }
 
584
 
 
585
    gtk_list_store_append (GTK_LIST_STORE (model), &iter);
 
586
    gtk_list_store_set (GTK_LIST_STORE (model), &iter,
 
587
                        0, "*other",
 
588
                        1, _("Other..."),
 
589
                        2, PANGO_WEIGHT_NORMAL,
 
590
                        3, gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), "stock_person", 64, 0, NULL),
 
591
                        -1);
 
592
 
 
593
    last_user = g_key_file_get_value (state, "greeter", "last-user", NULL);
 
594
 
 
595
    if (lightdm_greeter_get_select_user_hint (greeter))
 
596
        selected_user = lightdm_greeter_get_select_user_hint (greeter);
 
597
    else if (lightdm_greeter_get_select_guest_hint (greeter))
 
598
        selected_user = "*guest";
 
599
    else if (last_user)
 
600
        selected_user = last_user;
 
601
    else
 
602
        selected_user = NULL;
 
603
 
 
604
    if (selected_user && gtk_tree_model_get_iter_first (model, &iter))
 
605
    {
 
606
        do
 
607
        {
 
608
            gchar *name;
 
609
            gboolean matched;
 
610
            gtk_tree_model_get (model, &iter, 0, &name, -1);
 
611
            matched = strcmp (name, selected_user) == 0;
 
612
            g_free (name);
 
613
            if (matched)
 
614
            {
 
615
                gtk_tree_selection_select_iter (gtk_tree_view_get_selection (user_view), &iter);
 
616
                start_authentication (selected_user);
 
617
                break;
 
618
            }
 
619
        } while (gtk_tree_model_iter_next (model, &iter));
 
620
    }
 
621
 
 
622
    g_free (last_user);
 
623
}
 
624
 
 
625
static cairo_surface_t *
 
626
create_root_surface (GdkScreen *screen)
 
627
{
 
628
    gint number, width, height;
 
629
    Display *display;
 
630
    Pixmap pixmap;
 
631
    cairo_surface_t *surface;
 
632
 
 
633
    number = gdk_screen_get_number (screen);
 
634
    width = gdk_screen_get_width (screen);
 
635
    height = gdk_screen_get_height (screen);
 
636
 
 
637
    /* Open a new connection so with Retain Permanent so the pixmap remains when the greeter quits */
 
638
    gdk_flush ();
 
639
    display = XOpenDisplay (gdk_display_get_name (gdk_screen_get_display (screen)));
 
640
    if (!display)
 
641
    {
 
642
        g_warning ("Failed to create root pixmap");
 
643
        return NULL;
 
644
    }
 
645
    XSetCloseDownMode (display, RetainPermanent);
 
646
    pixmap = XCreatePixmap (display, RootWindow (display, number), width, height, DefaultDepth (display, number));
 
647
    XCloseDisplay (display);
 
648
 
 
649
    /* Convert into a Cairo surface */
 
650
    surface = cairo_xlib_surface_create (GDK_SCREEN_XDISPLAY (screen),
 
651
                                         pixmap,
 
652
                                         GDK_VISUAL_XVISUAL (gdk_screen_get_system_visual (screen)),
 
653
                                         width, height);
 
654
 
 
655
    /* Use this pixmap for the background */
 
656
    XSetWindowBackgroundPixmap (GDK_SCREEN_XDISPLAY (screen),
 
657
                                RootWindow (GDK_SCREEN_XDISPLAY (screen), number),
 
658
                                cairo_xlib_surface_get_drawable (surface));
 
659
 
 
660
 
 
661
    return surface;  
 
662
}
 
663
 
 
664
int
 
665
main (int argc, char **argv)
 
666
{
 
667
    GKeyFile *config;
 
668
    GdkRectangle monitor_geometry;
 
669
    GtkBuilder *builder;
 
670
    GtkTreeModel *model;
 
671
    const GList *items, *item;
 
672
    GtkTreeIter iter;
 
673
    GtkCellRenderer *renderer;
 
674
    GtkWidget *menuitem, *hbox, *image;
 
675
    gchar *value, *state_dir;
 
676
    GdkPixbuf *background_pixbuf = NULL;
 
677
    GdkColor background_color;
 
678
    gint i;
 
679
    GError *error = NULL;
 
680
 
 
681
    /* Disable global menus */
 
682
    g_unsetenv ("UBUNTU_MENUPROXY");
 
683
 
 
684
    /* Initialize i18n */
 
685
    setlocale (LC_ALL, "");
 
686
    bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
 
687
    bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
 
688
    textdomain (GETTEXT_PACKAGE);
 
689
 
 
690
    signal (SIGTERM, sigterm_cb);
 
691
 
 
692
    gtk_init (&argc, &argv);
 
693
 
 
694
    config = g_key_file_new ();
 
695
    g_key_file_load_from_file (config, CONFIG_FILE, G_KEY_FILE_NONE, &error);
 
696
    if (error && !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
 
697
        g_warning ("Failed to load configuration from %s: %s\n", CONFIG_FILE, error->message);
 
698
    g_clear_error (&error);
 
699
 
 
700
    state_dir = g_build_filename (g_get_user_cache_dir (), "lightdm-gtk-greeter", NULL);
 
701
    g_mkdir_with_parents (state_dir, 0775);
 
702
    state_filename = g_build_filename (state_dir, "state", NULL);
 
703
    g_free (state_dir);
 
704
 
 
705
    state = g_key_file_new ();
 
706
    g_key_file_load_from_file (state, state_filename, G_KEY_FILE_NONE, &error);
 
707
    if (error && !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
 
708
        g_warning ("Failed to load state from %s: %s\n", state_filename, error->message);
 
709
    g_clear_error (&error);
 
710
 
 
711
    greeter = lightdm_greeter_new ();
 
712
    g_signal_connect (greeter, "show-prompt", G_CALLBACK (show_prompt_cb), NULL);  
 
713
    g_signal_connect (greeter, "show-message", G_CALLBACK (show_message_cb), NULL);
 
714
    g_signal_connect (greeter, "authentication-complete", G_CALLBACK (authentication_complete_cb), NULL);
 
715
    g_signal_connect (greeter, "autologin-timer-expired", G_CALLBACK (autologin_timer_expired_cb), NULL);
 
716
    if (!lightdm_greeter_connect_sync (greeter, NULL))
 
717
        return EXIT_FAILURE;
 
718
 
 
719
    /* Set default cursor */
 
720
    gdk_window_set_cursor (gdk_get_default_root_window (), gdk_cursor_new (GDK_LEFT_PTR));
 
721
 
 
722
    /* Load background */
 
723
    value = g_key_file_get_value (config, "greeter", "background", NULL);
 
724
    if (!value)
 
725
        value = g_strdup ("#000000");
 
726
    if (!gdk_color_parse (value, &background_color))
 
727
    {
 
728
        gchar *path;
 
729
        GError *error = NULL;
 
730
 
 
731
        if (g_path_is_absolute (value))
 
732
            path = g_strdup (value);
 
733
        else
 
734
            path = g_build_filename (GREETER_DATA_DIR, value, NULL);
 
735
 
 
736
        g_debug ("Loading background %s", path);
 
737
        background_pixbuf = gdk_pixbuf_new_from_file (path, &error);
 
738
        if (!background_pixbuf)
 
739
           g_warning ("Failed to load background: %s", error->message);
 
740
        g_clear_error (&error);
 
741
        g_free (path);
 
742
    }
 
743
    else
 
744
        g_debug ("Using background color %s", value);
 
745
    g_free (value);
 
746
 
 
747
    /* Set the background */
 
748
    for (i = 0; i < gdk_display_get_n_screens (gdk_display_get_default ()); i++)
 
749
    {
 
750
        GdkScreen *screen;
 
751
        cairo_surface_t *surface;
 
752
        cairo_t *c;
 
753
        int monitor;
 
754
 
 
755
        screen = gdk_display_get_screen (gdk_display_get_default (), i);
 
756
        surface = create_root_surface (screen);
 
757
        c = cairo_create (surface);
 
758
 
 
759
        for (monitor = 0; monitor < gdk_screen_get_n_monitors (screen); monitor++)
 
760
        {
 
761
            gdk_screen_get_monitor_geometry (screen, monitor, &monitor_geometry);
 
762
 
 
763
            if (background_pixbuf)
 
764
            {
 
765
                GdkPixbuf *pixbuf = gdk_pixbuf_scale_simple (background_pixbuf, monitor_geometry.width, monitor_geometry.height, GDK_INTERP_BILINEAR);
 
766
                gdk_cairo_set_source_pixbuf (c, pixbuf, monitor_geometry.x, monitor_geometry.y);
 
767
                g_object_unref (pixbuf);
 
768
            }
 
769
            else
 
770
                gdk_cairo_set_source_color (c, &background_color);
 
771
            cairo_paint (c);
 
772
        }
 
773
 
 
774
        cairo_destroy (c);
 
775
 
 
776
        /* Refresh background */
 
777
        gdk_flush ();
 
778
        XClearWindow (GDK_SCREEN_XDISPLAY (screen), RootWindow (GDK_SCREEN_XDISPLAY (screen), i));
 
779
    }
 
780
    if (background_pixbuf)
 
781
        g_object_unref (background_pixbuf);
 
782
 
 
783
    /* Set GTK+ settings */
 
784
    value = g_key_file_get_value (config, "greeter", "theme-name", NULL);
 
785
    if (value)
 
786
    {
 
787
        g_debug ("Using theme %s", value);
 
788
        g_object_set (gtk_settings_get_default (), "gtk-theme-name", value, NULL);
 
789
    }
 
790
    g_free (value);
 
791
    g_object_get (gtk_settings_get_default (), "gtk-theme-name", &default_theme_name, NULL);
 
792
    g_debug ("Default theme is '%s'", default_theme_name);
 
793
 
 
794
    value = g_key_file_get_value (config, "greeter", "font-name", NULL);
 
795
    if (value)
 
796
    {
 
797
        g_debug ("Using font %s", value);
 
798
        g_object_set (gtk_settings_get_default (), "gtk-font-name", value, NULL);
 
799
    }
 
800
    g_object_get (gtk_settings_get_default (), "gtk-font-name", &default_font_name, NULL);  
 
801
    value = g_key_file_get_value (config, "greeter", "xft-dpi", NULL);
 
802
    if (value)
 
803
        g_object_set (gtk_settings_get_default (), "gtk-xft-dpi", (int) (1024 * atof (value)), NULL);
 
804
    value = g_key_file_get_value (config, "greeter", "xft-antialias", NULL);
 
805
    if (value)
 
806
        g_object_set (gtk_settings_get_default (), "gtk-xft-antialias", strcmp (value, "true") == 0, NULL);
 
807
    g_free (value);
 
808
    value = g_key_file_get_value (config, "greeter", "xft-hintstyle", NULL);
 
809
    if (value)
 
810
        g_object_set (gtk_settings_get_default (), "gtk-xft-hintstyle", value, NULL);
 
811
    g_free (value);
 
812
    value = g_key_file_get_value (config, "greeter", "xft-rgba", NULL);
 
813
    if (value)
 
814
        g_object_set (gtk_settings_get_default (), "gtk-xft-rgba", value, NULL);
 
815
    g_free (value);
 
816
 
 
817
    /* Load out installed icons */
 
818
    gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (), GREETER_DATA_DIR);
 
819
    gchar **path;
 
820
    gtk_icon_theme_get_search_path (gtk_icon_theme_get_default (), &path, NULL);
 
821
 
 
822
    builder = gtk_builder_new ();
 
823
    if (!gtk_builder_add_from_file (builder, GREETER_DATA_DIR "/greeter.ui", &error))
 
824
    {
 
825
        g_warning ("Error loading UI: %s", error->message);
 
826
        return EXIT_FAILURE;
 
827
    }
 
828
    g_clear_error (&error);
 
829
 
 
830
    login_window = GTK_WINDOW (gtk_builder_get_object (builder, "login_window"));
 
831
    login_box = GTK_WIDGET (gtk_builder_get_object (builder, "login_box"));
 
832
    prompt_box = GTK_WIDGET (gtk_builder_get_object (builder, "prompt_box"));
 
833
    prompt_label = GTK_LABEL (gtk_builder_get_object (builder, "prompt_label"));
 
834
    prompt_entry = GTK_ENTRY (gtk_builder_get_object (builder, "prompt_entry"));
 
835
    message_label = GTK_LABEL (gtk_builder_get_object (builder, "message_label"));
 
836
    session_combo = GTK_COMBO_BOX (gtk_builder_get_object (builder, "session_combobox"));
 
837
    language_combo = GTK_COMBO_BOX (gtk_builder_get_object (builder, "language_combobox"));  
 
838
    panel_window = GTK_WINDOW (gtk_builder_get_object (builder, "panel_window"));
 
839
 
 
840
    gtk_label_set_text (GTK_LABEL (gtk_builder_get_object (builder, "hostname_label")), lightdm_get_hostname ());
 
841
 
 
842
    /* Glade can't handle custom menuitems, so set them up manually */
 
843
    menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "power_menuitem"));
 
844
    hbox = gtk_hbox_new (FALSE, 0);
 
845
    gtk_widget_show (hbox);
 
846
    gtk_container_add (GTK_CONTAINER (menuitem), hbox);
 
847
    image = gtk_image_new_from_icon_name ("system-shutdown", GTK_ICON_SIZE_MENU);
 
848
    gtk_widget_show (image);
 
849
    gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0);
 
850
 
 
851
    menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "a11y_menuitem"));
 
852
    hbox = gtk_hbox_new (FALSE, 0);
 
853
    gtk_widget_show (hbox);
 
854
    gtk_container_add (GTK_CONTAINER (menuitem), hbox);
 
855
    image = gtk_image_new_from_icon_name ("accessibility", GTK_ICON_SIZE_MENU);
 
856
    gtk_widget_show (image);
 
857
    gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0);
 
858
 
 
859
    if (!lightdm_get_can_suspend ())
 
860
        gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (builder, "suspend_menuitem")));
 
861
    if (!lightdm_get_can_hibernate ())
 
862
        gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (builder, "hibernate_menuitem")));
 
863
    if (!lightdm_get_can_restart ())
 
864
        gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (builder, "restart_menuitem")));
 
865
    if (!lightdm_get_can_shutdown ())
 
866
        gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (builder, "shutdown_menuitem")));
 
867
 
 
868
    renderer = gtk_cell_renderer_text_new();
 
869
    gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (session_combo), renderer, TRUE);
 
870
    gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (session_combo), renderer, "text", 0);
 
871
    model = gtk_combo_box_get_model (session_combo);
 
872
    items = lightdm_get_sessions ();
 
873
    for (item = items; item; item = item->next)
 
874
    {
 
875
        LightDMSession *session = item->data;
 
876
 
 
877
        gtk_widget_show (GTK_WIDGET (session_combo));
 
878
        gtk_list_store_append (GTK_LIST_STORE (model), &iter);
 
879
        gtk_list_store_set (GTK_LIST_STORE (model), &iter,
 
880
                            0, lightdm_session_get_name (session),
 
881
                            1, lightdm_session_get_key (session),
 
882
                            -1);
 
883
    }
 
884
    set_session (NULL);
 
885
 
 
886
    if (g_key_file_get_boolean (config, "greeter", "show-language-selector", NULL))
 
887
    {
 
888
        gtk_widget_show (GTK_WIDGET (language_combo));
 
889
 
 
890
        renderer = gtk_cell_renderer_text_new();
 
891
        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (language_combo), renderer, TRUE);
 
892
        gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (language_combo), renderer, "text", 0);
 
893
        model = gtk_combo_box_get_model (language_combo);
 
894
        items = lightdm_get_languages ();
 
895
        for (item = items; item; item = item->next)
 
896
        {
 
897
            LightDMLanguage *language = item->data;
 
898
            gchar *label;
 
899
 
 
900
            label = g_strdup_printf ("%s - %s", lightdm_language_get_name (language), lightdm_language_get_territory (language));
 
901
 
 
902
            gtk_widget_show (GTK_WIDGET (language_combo));
 
903
            gtk_list_store_append (GTK_LIST_STORE (model), &iter);
 
904
            gtk_list_store_set (GTK_LIST_STORE (model), &iter,
 
905
                                0, label,
 
906
                                1, lightdm_language_get_code (language),
 
907
                                -1);
 
908
            g_free (label);
 
909
        }
 
910
        set_language (NULL);
 
911
    }
 
912
 
 
913
    user_view = GTK_TREE_VIEW (gtk_builder_get_object (builder, "user_treeview"));
 
914
    gtk_tree_view_insert_column_with_attributes (user_view, 0, "Face", gtk_cell_renderer_pixbuf_new(), "pixbuf", 3, NULL);
 
915
    gtk_tree_view_insert_column_with_attributes (user_view, 1, "Name", gtk_cell_renderer_text_new(), "text", 1, "weight", 2, NULL);
 
916
 
 
917
    if (lightdm_greeter_get_hide_users_hint (greeter))
 
918
        start_authentication ("*other");
 
919
    else
 
920
    {
 
921
        load_user_list ();
 
922
        gtk_widget_show (GTK_WIDGET (user_view));
 
923
    } 
 
924
 
 
925
    gtk_builder_connect_signals(builder, greeter);
 
926
 
 
927
    gtk_widget_show (GTK_WIDGET (login_window));
 
928
    center_window (login_window);
 
929
 
 
930
    gtk_widget_show (GTK_WIDGET (panel_window));
 
931
    GtkAllocation allocation;
 
932
    gtk_widget_get_allocation (GTK_WIDGET (panel_window), &allocation);
 
933
    gdk_screen_get_monitor_geometry (gdk_screen_get_default (), gdk_screen_get_primary_monitor (gdk_screen_get_default ()), &monitor_geometry);
 
934
    gtk_window_resize (panel_window, monitor_geometry.width, allocation.height);
 
935
    gtk_window_move (panel_window, monitor_geometry.x, monitor_geometry.y);
 
936
 
 
937
    gtk_widget_show (GTK_WIDGET (login_window));
 
938
    gdk_window_focus (gtk_widget_get_window (GTK_WIDGET (login_window)), GDK_CURRENT_TIME);
 
939
 
 
940
    gtk_main ();
 
941
 
 
942
    return EXIT_SUCCESS;
 
943
}