~lightdm-team/lightdm/1.4

4 by robert.ancell at gmail
Add basic greeter
1
/*
19 by robert.ancell at gmail
Change copyright
2
 * Copyright (C) 2010 Robert Ancell.
4 by robert.ancell at gmail
Add basic greeter
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
188 by robert.ancell at gmail
Cleanly exit greeter when requested by DM
12
#include <stdlib.h>
4 by robert.ancell at gmail
Add basic greeter
13
#include <gtk/gtk.h>
18 by robert.ancell at gmail
Add user icons and some more menus
14
#include <glib/gi18n.h>
249 by robert.ancell at canonical
Use a single fullscreen window for GTK+ greeter
15
#include <cairo.h>
153 by robert.ancell at gmail
Set background in GTK+ greeter
16
#include <gdk-pixbuf/gdk-pixbuf.h>
17
#include <gdk-pixbuf-xlib/gdk-pixbuf-xlib.h>
4 by robert.ancell at gmail
Add basic greeter
18
19
#include "greeter.h"
20
65 by robert.ancell at gmail
Use namespace for client library, add object properties
21
static LdmGreeter *greeter;
204 by robert.ancell at gmail
Show username entry if no user list
22
static GtkTreeModel *user_model;
249 by robert.ancell at canonical
Use a single fullscreen window for GTK+ greeter
23
static GtkWidget *window, *vbox, *login_vbox, *message_label, *user_view;
24
static GdkPixmap *background_pixmap;
204 by robert.ancell at gmail
Show username entry if no user list
25
static GtkWidget *username_entry, *password_entry;
255 by robert.ancell at canonical
Change language/layout/session when user selected in GTK+ greeter
26
static gchar *theme_name;
27
static GSList *session_radio_list = NULL, *language_radio_list = NULL, *layout_radio_list = NULL;
28
29
static gchar *
30
get_language ()
31
{
32
    GSList *iter;
33
34
    for (iter = language_radio_list; iter; iter = iter->next)
35
    {
36
        GtkCheckMenuItem *item = iter->data;
37
        if (gtk_check_menu_item_get_active (item))
38
            return g_object_get_data (G_OBJECT (item), "language");
39
    }
40
41
    return NULL;
42
}
43
44
static void
45
set_language (const gchar *language)
46
{
47
    GSList *iter;
48
49
    for (iter = language_radio_list; iter; iter = iter->next)
50
    {
51
        GtkCheckMenuItem *item = iter->data;
52
        if (strcmp (language, g_object_get_data (G_OBJECT (item), "language")) == 0)
53
            gtk_check_menu_item_set_active (item, TRUE);
54
    }
55
}
56
57
static gchar *
58
get_layout ()
59
{
60
    GSList *iter;
61
62
    for (iter = layout_radio_list; iter; iter = iter->next)
63
    {
64
        GtkCheckMenuItem *item = iter->data;
65
        if (gtk_check_menu_item_get_active (item))
66
            return g_object_get_data (G_OBJECT (item), "layout");
67
    }
68
69
    return NULL;
70
}
71
72
static void
73
set_layout (const gchar *layout)
74
{
75
    GSList *iter;
76
77
    for (iter = layout_radio_list; iter; iter = iter->next)
78
    {
79
        GtkCheckMenuItem *item = iter->data;
80
        if (strcmp (layout, g_object_get_data (G_OBJECT (item), "layout")) == 0)
81
            gtk_check_menu_item_set_active (item, TRUE);
82
    }
83
}
84
85
static gchar *
86
get_session ()
87
{
88
    GSList *iter;
89
90
    for (iter = session_radio_list; iter; iter = iter->next)
91
    {
92
        GtkCheckMenuItem *item = iter->data;
93
        if (gtk_check_menu_item_get_active (item))
94
            return g_object_get_data (G_OBJECT (item), "key");
95
    }
96
97
    return NULL;
98
}
99
100
static void
101
set_session (const gchar *session)
102
{
103
    GSList *iter;
104
105
    for (iter = session_radio_list; iter; iter = iter->next)
106
    {
107
        GtkCheckMenuItem *item = iter->data;
108
        if (strcmp (session, g_object_get_data (G_OBJECT (item), "key")) == 0)
109
            gtk_check_menu_item_set_active (item, TRUE);
110
    }
111
}
7 by robert.ancell at gmail
Improvements to greeter spawning. Add support for user detection
112
113
static void
154 by robert.ancell at gmail
Make GTK+ greeter single click selection
114
start_authentication (const gchar *username)
115
{
116
    GtkTreeIter iter;
255 by robert.ancell at canonical
Change language/layout/session when user selected in GTK+ greeter
117
    gchar *language, *layout, *session;
118
  
119
    if (ldm_greeter_get_user_defaults (greeter, username, &language, &layout, &session))
120
    {
121
        set_language (language);
122
        set_session (session);
123
        set_layout (layout);
124
        g_free (language);
125
        g_free (layout);
126
        g_free (session);
127
    }
154 by robert.ancell at gmail
Make GTK+ greeter single click selection
128
204 by robert.ancell at gmail
Show username entry if no user list
129
    if (user_model && gtk_tree_model_get_iter_first (GTK_TREE_MODEL (user_model), &iter))
154 by robert.ancell at gmail
Make GTK+ greeter single click selection
130
    {
131
        do
132
        {
133
            gchar *user;
134
            gtk_tree_model_get (GTK_TREE_MODEL (user_model), &iter, 0, &user, -1);
135
            gtk_list_store_set (GTK_LIST_STORE (user_model), &iter, 3, strcmp (user, username) == 0, -1);
136
            g_free (user);
137
        } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (user_model), &iter));
138
    }
204 by robert.ancell at gmail
Show username entry if no user list
139
    if (username_entry)
140
        gtk_widget_set_sensitive (username_entry, FALSE);
154 by robert.ancell at gmail
Make GTK+ greeter single click selection
141
142
    ldm_greeter_start_authentication (greeter, username);
143
}
144
145
static void
7 by robert.ancell at gmail
Improvements to greeter spawning. Add support for user detection
146
user_view_activate_cb (GtkWidget *widget, GtkTreePath *path, GtkTreeViewColumn *column)
147
{
148
    GtkTreeIter iter;
149
    gchar *user;
27 by robert.ancell at gmail
Get timed login working
150
7 by robert.ancell at gmail
Improvements to greeter spawning. Add support for user detection
151
    gtk_tree_model_get_iter (GTK_TREE_MODEL (user_model), &iter, path);
152
    gtk_tree_model_get (GTK_TREE_MODEL (user_model), &iter, 0, &user, -1);
154 by robert.ancell at gmail
Make GTK+ greeter single click selection
153
    start_authentication (user);
7 by robert.ancell at gmail
Improvements to greeter spawning. Add support for user detection
154
    g_free (user);
155
}
4 by robert.ancell at gmail
Add basic greeter
156
154 by robert.ancell at gmail
Make GTK+ greeter single click selection
157
static gboolean
158
idle_select_cb ()
159
{
160
    GtkTreeIter iter;
161
    gchar *user;
162
163
    if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (user_view)),
164
                                         NULL, &iter))
165
    {
166
        gtk_tree_model_get (GTK_TREE_MODEL (user_model), &iter, 0, &user, -1);
167
        start_authentication (user);
168
        g_free (user);
169
    }
170
171
    return FALSE;
172
}
173
174
static gboolean
175
user_view_click_cb (GtkWidget *widget, GdkEventButton *event)
176
{
177
    /* Do it in the idle loop so the selection is done first */
178
    g_idle_add (idle_select_cb, NULL);
179
    return FALSE;
4 by robert.ancell at gmail
Add basic greeter
180
}
181
182
static void
204 by robert.ancell at gmail
Show username entry if no user list
183
username_activate_cb (GtkWidget *widget)
184
{
185
    start_authentication (gtk_entry_get_text (GTK_ENTRY (username_entry)));
186
}
187
188
static void
4 by robert.ancell at gmail
Add basic greeter
189
password_activate_cb (GtkWidget *widget)
190
{
7 by robert.ancell at gmail
Improvements to greeter spawning. Add support for user detection
191
    gtk_widget_set_sensitive (widget, FALSE);
65 by robert.ancell at gmail
Use namespace for client library, add object properties
192
    ldm_greeter_provide_secret (greeter, gtk_entry_get_text (GTK_ENTRY (widget)));
4 by robert.ancell at gmail
Add basic greeter
193
}
194
195
static void
65 by robert.ancell at gmail
Use namespace for client library, add object properties
196
show_prompt_cb (LdmGreeter *greeter, const gchar *text)
4 by robert.ancell at gmail
Add basic greeter
197
{
34 by robert.ancell at gmail
Move session combo into the menu, hide widgets until needed
198
    gtk_widget_show (password_entry);
4 by robert.ancell at gmail
Add basic greeter
199
    gtk_widget_set_sensitive (password_entry, TRUE);
200
    gtk_widget_grab_focus (password_entry);
201
}
202
203
static void
65 by robert.ancell at gmail
Use namespace for client library, add object properties
204
show_message_cb (LdmGreeter *greeter, const gchar *text)
4 by robert.ancell at gmail
Add basic greeter
205
{
144 by robert.ancell at gmail
import gtk greeter
206
    gtk_widget_show (message_label);
207
    gtk_label_set_text (GTK_LABEL (message_label), text);
4 by robert.ancell at gmail
Add basic greeter
208
}
209
210
static void
65 by robert.ancell at gmail
Use namespace for client library, add object properties
211
authentication_complete_cb (LdmGreeter *greeter)
4 by robert.ancell at gmail
Add basic greeter
212
{
154 by robert.ancell at gmail
Make GTK+ greeter single click selection
213
    GtkTreeIter iter;
214
215
    gtk_widget_hide (password_entry);
216
    gtk_entry_set_text (GTK_ENTRY (password_entry), "");
217
173 by robert.ancell at gmail
Use better login API
218
    /* Clear row shading */
204 by robert.ancell at gmail
Show username entry if no user list
219
    if (user_model && gtk_tree_model_get_iter_first (GTK_TREE_MODEL (user_model), &iter))
154 by robert.ancell at gmail
Make GTK+ greeter single click selection
220
    {
221
        do
222
        {
223
            gtk_list_store_set (GTK_LIST_STORE (user_model), &iter, 3, TRUE, -1);
224
        } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (user_model), &iter));
225
    }
204 by robert.ancell at gmail
Show username entry if no user list
226
    if (username_entry)
227
    {
228
        gtk_entry_set_text (GTK_ENTRY (username_entry), "");
229
        gtk_widget_set_sensitive (username_entry, TRUE);
230
    }
231
232
    if (user_view)
233
        gtk_widget_grab_focus (user_view);
234
    else
235
        gtk_widget_grab_focus (username_entry);
173 by robert.ancell at gmail
Use better login API
236
  
65 by robert.ancell at gmail
Use namespace for client library, add object properties
237
    if (ldm_greeter_get_is_authenticated (greeter))
84 by robert.ancell at gmail
Fix up documentation and tweak UI
238
    {
255 by robert.ancell at canonical
Change language/layout/session when user selected in GTK+ greeter
239
        ldm_greeter_login (greeter, ldm_greeter_get_authentication_user (greeter), get_session (), get_language ());
84 by robert.ancell at gmail
Fix up documentation and tweak UI
240
    }
241
    else
242
    {
144 by robert.ancell at gmail
import gtk greeter
243
        gtk_widget_show (message_label);
244
        gtk_label_set_text (GTK_LABEL (message_label), "Failed to authenticate");
84 by robert.ancell at gmail
Fix up documentation and tweak UI
245
    }
4 by robert.ancell at gmail
Add basic greeter
246
}
247
27 by robert.ancell at gmail
Get timed login working
248
static void
65 by robert.ancell at gmail
Use namespace for client library, add object properties
249
timed_login_cb (LdmGreeter *greeter, const gchar *username)
27 by robert.ancell at gmail
Get timed login working
250
{
237 by robert.ancell at canonical
support language changes
251
    ldm_greeter_login (greeter, ldm_greeter_get_timed_login_user (greeter), NULL, NULL);
84 by robert.ancell at gmail
Fix up documentation and tweak UI
252
}
253
254
static void
195 by robert.ancell at gmail
Make shutdown buttons work in GTK+ greeter
255
suspend_cb (GtkWidget *widget, LdmGreeter *greeter)
256
{
257
    ldm_greeter_suspend (greeter);
258
}
259
260
static void
261
hibernate_cb (GtkWidget *widget, LdmGreeter *greeter)
262
{
263
    ldm_greeter_hibernate (greeter);
264
}
265
266
static void
267
center_window (GtkWindow *window)
268
{
269
    GtkAllocation allocation;
270
    GdkDisplay *display;
271
    GdkScreen *screen;
272
    gint screen_width, screen_height;
273
274
    gtk_widget_get_allocation (GTK_WIDGET (window), &allocation);
275
    display = gdk_display_get_default ();
276
    screen = gdk_display_get_default_screen (display);
277
    screen_width = gdk_screen_get_width (screen);
278
    screen_height = gdk_screen_get_height (screen);
279
    gtk_window_move (GTK_WINDOW (window),
280
                     (screen_width - allocation.width) / 2,
281
                     (screen_height - allocation.height) / 2);
282
}
283
284
static void
285
restart_cb (GtkWidget *widget, LdmGreeter *greeter)
286
{
287
    GtkWidget *dialog;
288
289
    dialog = gtk_message_dialog_new (NULL,
290
                                     GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR,
291
                                     GTK_MESSAGE_OTHER,
292
                                     GTK_BUTTONS_NONE,
293
                                     "%s", _("Are you sure you want to close all programs and restart the computer?"));
294
    gtk_message_dialog_set_image (GTK_MESSAGE_DIALOG (dialog), gtk_image_new_from_icon_name ("system-restart", GTK_ICON_SIZE_DIALOG));
295
    gtk_dialog_add_buttons (GTK_DIALOG (dialog), _("Cancel"), FALSE, _("Restart"), TRUE, NULL);
296
    gtk_widget_show_all (dialog);
297
    center_window (GTK_WINDOW (dialog));
298
299
    if (gtk_dialog_run (GTK_DIALOG (dialog)))
300
        ldm_greeter_restart (greeter);
301
    gtk_widget_destroy (dialog);
302
}
303
304
static void
305
shutdown_cb (GtkWidget *widget, LdmGreeter *greeter)
306
{
307
    GtkWidget *dialog;
308
309
    dialog = gtk_message_dialog_new (NULL,
310
                                     GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR,
311
                                     GTK_MESSAGE_OTHER,
312
                                     GTK_BUTTONS_NONE,
313
                                     "%s", _("Are you sure you want to close all programs and shutdown the computer?"));
314
    gtk_message_dialog_set_image (GTK_MESSAGE_DIALOG (dialog), gtk_image_new_from_icon_name ("system-shutdown", GTK_ICON_SIZE_DIALOG));
315
    gtk_dialog_add_buttons (GTK_DIALOG (dialog), _("Cancel"), FALSE, _("Shutdown"), TRUE, NULL);
316
    gtk_widget_show_all (dialog);
317
    center_window (GTK_WINDOW (dialog));
318
319
    if (gtk_dialog_run (GTK_DIALOG (dialog)))
320
        ldm_greeter_shutdown (greeter);
321
    gtk_widget_destroy (dialog);
322
}
323
248 by robert.ancell at canonical
Start to support transitions
324
static gboolean
325
fade_timer_cb (gpointer data)
326
{
327
    gdouble opacity;
328
249 by robert.ancell at canonical
Use a single fullscreen window for GTK+ greeter
329
    opacity = gtk_window_get_opacity (GTK_WINDOW (window));
248 by robert.ancell at canonical
Start to support transitions
330
    opacity -= 0.1;
331
    if (opacity <= 0)
332
    {
333
        gtk_main_quit ();
334
        return FALSE;
335
    }
249 by robert.ancell at canonical
Use a single fullscreen window for GTK+ greeter
336
    gtk_window_set_opacity (GTK_WINDOW (window), opacity);
248 by robert.ancell at canonical
Start to support transitions
337
338
    return TRUE;
339
}
340
195 by robert.ancell at gmail
Make shutdown buttons work in GTK+ greeter
341
static void
84 by robert.ancell at gmail
Fix up documentation and tweak UI
342
quit_cb (LdmGreeter *greeter, const gchar *username)
343
{
248 by robert.ancell at canonical
Start to support transitions
344
    /* Fade out the greeter */
345
    g_timeout_add (40, (GSourceFunc) fade_timer_cb, NULL);
27 by robert.ancell at gmail
Get timed login working
346
}
347
32 by robert.ancell at gmail
Able to configure and change sessions
348
static void
107 by robert.ancell at gmail
Implement keyboard layout in GTK+ greeter
349
layout_changed_cb (GtkWidget *widget)
350
{
351
    if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
352
        ldm_greeter_set_layout (greeter, g_object_get_data (G_OBJECT (widget), "layout"));
353
}
354
355
static void
144 by robert.ancell at gmail
import gtk greeter
356
a11y_font_cb (GtkWidget *widget)
357
{
358
    if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
359
        g_object_set (gtk_settings_get_default (), "gtk-font-name", "UbuntuBeta 20", NULL);
360
    else
361
        g_object_set (gtk_settings_get_default (), "gtk-font-name", "UbuntuBeta 10", NULL);
362
}
363
364
static void
365
a11y_contrast_cb (GtkWidget *widget)
366
{
367
    if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
368
        g_object_set (gtk_settings_get_default (), "gtk-theme-name", "HighContrastInverse", NULL);
369
    else
156 by robert.ancell at gmail
Re-enable desensitizing images, revert to correct theme after high contrast
370
        g_object_set (gtk_settings_get_default (), "gtk-theme-name", theme_name, NULL);
144 by robert.ancell at gmail
import gtk greeter
371
}
372
188 by robert.ancell at gmail
Cleanly exit greeter when requested by DM
373
static void
374
sigterm_cb (int signum)
375
{
376
    exit (0);
377
}
378
204 by robert.ancell at gmail
Show username entry if no user list
379
static GtkWidget *
380
make_user_view (void)
381
{
382
    GtkListStore *model;
383
    GtkWidget *view;
384
    GtkCellRenderer *renderer;
385
    const GList *items, *item;
386
    GtkTreeIter iter;
387
388
    items = ldm_greeter_get_users (greeter);
389
    if (!items)
390
        return NULL;
391
  
392
    model = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_BOOLEAN);
393
    for (item = items; item; item = item->next)
394
    {
395
        LdmUser *user = item->data;
396
        const gchar *image;
397
        GdkPixbuf *pixbuf = NULL;
398
399
        image = ldm_user_get_image (user);
400
        if (image[0] != '\0')
401
        {
402
            gchar *path;
403
404
            path = g_filename_from_uri (image, NULL, NULL);
405
            if (path)
406
                pixbuf = gdk_pixbuf_new_from_file_at_scale (path, 64, 64, TRUE, NULL);
407
            g_free (path);
408
        }
409
        if (!pixbuf)
410
            pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
411
                                               "stock_person",
412
                                               64,
413
                                               0,
414
                                               NULL);
415
416
        gtk_list_store_append (GTK_LIST_STORE (model), &iter);
417
        gtk_list_store_set (GTK_LIST_STORE (model), &iter,
418
                            0, ldm_user_get_name (user),
419
                            1, ldm_user_get_display_name (user),
420
                            2, pixbuf,
421
                            3, TRUE,
422
                            -1);
423
    }
424
425
    view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
426
    gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view), FALSE);
427
    gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view), GTK_TREE_VIEW_GRID_LINES_NONE);
428
429
    renderer = gtk_cell_renderer_pixbuf_new();
430
    gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view), 0, "Face", renderer, "pixbuf", 2, "sensitive", 3, NULL);
431
432
    renderer = gtk_cell_renderer_text_new();
433
    gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view), 1, "Name", renderer, "text", 1, NULL);
434
435
    g_signal_connect (view, "row-activated", G_CALLBACK (user_view_activate_cb), NULL);
436
    g_signal_connect (view, "button-press-event", G_CALLBACK (user_view_click_cb), NULL);
437
438
    if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter))
439
        gtk_tree_selection_select_iter (gtk_tree_view_get_selection (GTK_TREE_VIEW (view)), &iter);
440
441
    return view;
442
}
443
249 by robert.ancell at canonical
Use a single fullscreen window for GTK+ greeter
444
static gboolean
445
draw_background_cb (GtkWidget *widget, GdkEventExpose *event)
446
{
447
    cairo_t *context;
448
    GtkAllocation allocation;
449
450
    context = gdk_cairo_create (GDK_DRAWABLE (gtk_widget_get_window (widget)));
451
452
    gtk_widget_get_allocation (GTK_WIDGET (window), &allocation);
453
    gdk_cairo_set_source_pixmap (context, background_pixmap, 0.0, 0.0);
454
    cairo_rectangle (context, 0, 0, allocation.width, allocation.height);
455
    cairo_fill (context);
456
457
    cairo_destroy (context);
458
459
    return FALSE;
460
}
461
4 by robert.ancell at gmail
Add basic greeter
462
int
463
main(int argc, char **argv)
464
{
153 by robert.ancell at gmail
Set background in GTK+ greeter
465
    gchar *theme_dir, *rc_file, *background_image;
35 by robert.ancell at gmail
Set background
466
    GdkWindow *root;
107 by robert.ancell at gmail
Implement keyboard layout in GTK+ greeter
467
    const GList *items, *item;
17 by robert.ancell at gmail
Make a greeter panel
468
    GdkDisplay *display;
469
    GdkScreen *screen;
470
    gint screen_width, screen_height;
249 by robert.ancell at canonical
Use a single fullscreen window for GTK+ greeter
471
    GtkWidget *login_align, *logo_image;
107 by robert.ancell at gmail
Implement keyboard layout in GTK+ greeter
472
    GtkWidget *option_menu, *power_menu;
473
    GtkWidget *menu_bar, *menu, *menu_item;
40 by robert.ancell at gmail
Check if can do power options and implement power d-bus calls
474
    gint n_power_items = 0;
7 by robert.ancell at gmail
Improvements to greeter spawning. Add support for user detection
475
188 by robert.ancell at gmail
Cleanly exit greeter when requested by DM
476
    signal (SIGTERM, sigterm_cb);
477
145 by robert.ancell at gmail
More theme stuff
478
    g_type_init ();
144 by robert.ancell at gmail
import gtk greeter
479
65 by robert.ancell at gmail
Use namespace for client library, add object properties
480
    greeter = ldm_greeter_new ();
17 by robert.ancell at gmail
Make a greeter panel
481
32 by robert.ancell at gmail
Able to configure and change sessions
482
    g_signal_connect (G_OBJECT (greeter), "show-prompt", G_CALLBACK (show_prompt_cb), NULL);  
483
    g_signal_connect (G_OBJECT (greeter), "show-message", G_CALLBACK (show_message_cb), NULL);
484
    g_signal_connect (G_OBJECT (greeter), "show-error", G_CALLBACK (show_message_cb), NULL);
485
    g_signal_connect (G_OBJECT (greeter), "authentication-complete", G_CALLBACK (authentication_complete_cb), NULL);
486
    g_signal_connect (G_OBJECT (greeter), "timed-login", G_CALLBACK (timed_login_cb), NULL);
84 by robert.ancell at gmail
Fix up documentation and tweak UI
487
    g_signal_connect (G_OBJECT (greeter), "quit", G_CALLBACK (quit_cb), NULL);
32 by robert.ancell at gmail
Able to configure and change sessions
488
65 by robert.ancell at gmail
Use namespace for client library, add object properties
489
    ldm_greeter_connect (greeter);
32 by robert.ancell at gmail
Able to configure and change sessions
490
146 by robert.ancell at gmail
Support theme properties, use this to find the gtkrc in GNOME theme
491
    theme_dir = g_path_get_dirname (ldm_greeter_get_theme (greeter));
492
    rc_file = ldm_greeter_get_string_property (greeter, "gtkrc");
493
    if (rc_file)
494
    {
153 by robert.ancell at gmail
Set background in GTK+ greeter
495
        gchar *path = g_build_filename (theme_dir, rc_file, NULL);
146 by robert.ancell at gmail
Support theme properties, use this to find the gtkrc in GNOME theme
496
        g_free (rc_file);
153 by robert.ancell at gmail
Set background in GTK+ greeter
497
        gtk_rc_add_default_file (path);
498
        g_free (path);
146 by robert.ancell at gmail
Support theme properties, use this to find the gtkrc in GNOME theme
499
    }
145 by robert.ancell at gmail
More theme stuff
500
501
    gtk_init (&argc, &argv);
502
156 by robert.ancell at gmail
Re-enable desensitizing images, revert to correct theme after high contrast
503
    g_object_get (gtk_settings_get_default (), "gtk-theme-name", &theme_name, NULL);
504
17 by robert.ancell at gmail
Make a greeter panel
505
    display = gdk_display_get_default ();
506
    screen = gdk_display_get_default_screen (display);
507
    screen_width = gdk_screen_get_width (screen);
35 by robert.ancell at gmail
Set background
508
    screen_height = gdk_screen_get_height (screen);
248 by robert.ancell at canonical
Start to support transitions
509
35 by robert.ancell at gmail
Set background
510
    root = gdk_get_default_root_window ();
511
    gdk_window_set_cursor (root, gdk_cursor_new (GDK_LEFT_PTR));
248 by robert.ancell at canonical
Start to support transitions
512
249 by robert.ancell at canonical
Use a single fullscreen window for GTK+ greeter
513
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
514
    gtk_widget_set_app_paintable (window, TRUE);
515
    g_signal_connect (G_OBJECT (window), "expose-event", G_CALLBACK (draw_background_cb), NULL);
516
    gtk_window_set_default_size (GTK_WINDOW (window), screen_width, screen_height);
517
    gtk_window_fullscreen (GTK_WINDOW (window));
518
    gtk_widget_realize (window);
153 by robert.ancell at gmail
Set background in GTK+ greeter
519
520
    background_image = ldm_greeter_get_string_property (greeter, "background-image");
521
    if (background_image)
522
    {
523
        gchar *path;
524
        GdkPixbuf *pixbuf;
525
        GError *error = NULL;
526
527
        path = g_build_filename (theme_dir, background_image, NULL);
528
        g_free (background_image);
529
        pixbuf = gdk_pixbuf_new_from_file (path, &error);
530
        if (!pixbuf)
531
           g_warning ("Failed to load background: %s", error->message);
532
        g_clear_error (&error);
533
        g_free (path);
534
535
        if (pixbuf)
536
        {
537
            GdkPixbuf *scaled;
249 by robert.ancell at canonical
Use a single fullscreen window for GTK+ greeter
538
            GdkWindow *w;
153 by robert.ancell at gmail
Set background in GTK+ greeter
539
540
            scaled = gdk_pixbuf_scale_simple (pixbuf, screen_width, screen_height, GDK_INTERP_BILINEAR);
541
            g_object_unref (pixbuf);
542
249 by robert.ancell at canonical
Use a single fullscreen window for GTK+ greeter
543
            w = gtk_widget_get_window (GTK_WIDGET (window));
544
545
            gdk_pixbuf_render_pixmap_and_mask_for_colormap (scaled, gdk_window_get_colormap (w), &background_pixmap, NULL, 0);
153 by robert.ancell at gmail
Set background in GTK+ greeter
546
            g_object_unref (scaled);
547
        }
548
    }
17 by robert.ancell at gmail
Make a greeter panel
549
249 by robert.ancell at canonical
Use a single fullscreen window for GTK+ greeter
550
    vbox = gtk_vbox_new (FALSE, 0);
551
    gtk_container_add (GTK_CONTAINER (window), vbox);
552
553
    login_align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
554
    gtk_box_pack_start (GTK_BOX (vbox), login_align, TRUE, TRUE, 0);
555
556
    GtkWidget *notebook;
557
    notebook = gtk_notebook_new ();
558
    gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), FALSE);
559
    gtk_container_add (GTK_CONTAINER (login_align), notebook);
560
561
    login_vbox = gtk_vbox_new (FALSE, 6);
562
    gtk_container_set_border_width (GTK_CONTAINER (login_vbox), 12);
563
    gtk_container_add (GTK_CONTAINER (notebook), login_vbox);
4 by robert.ancell at gmail
Add basic greeter
564
144 by robert.ancell at gmail
import gtk greeter
565
    logo_image = gtk_image_new_from_icon_name ("computer", GTK_ICON_SIZE_DIALOG);
566
    gtk_image_set_pixel_size (GTK_IMAGE (logo_image), 64);
249 by robert.ancell at canonical
Use a single fullscreen window for GTK+ greeter
567
    gtk_box_pack_start (GTK_BOX (login_vbox), logo_image, FALSE, FALSE, 0);
568
    gtk_box_pack_start (GTK_BOX (login_vbox), gtk_label_new (ldm_greeter_get_hostname (greeter)), FALSE, FALSE, 0);
144 by robert.ancell at gmail
import gtk greeter
569
570
    message_label = gtk_label_new ("");
249 by robert.ancell at canonical
Use a single fullscreen window for GTK+ greeter
571
    gtk_box_pack_start (GTK_BOX (login_vbox), message_label, FALSE, FALSE, 0);
144 by robert.ancell at gmail
import gtk greeter
572
    gtk_widget_set_no_show_all (message_label, TRUE);
4 by robert.ancell at gmail
Add basic greeter
573
204 by robert.ancell at gmail
Show username entry if no user list
574
    user_view = make_user_view ();
575
    if (user_view)
576
    {
577
        username_entry = NULL;
578
        user_model = gtk_tree_view_get_model (GTK_TREE_VIEW (user_view));
249 by robert.ancell at canonical
Use a single fullscreen window for GTK+ greeter
579
        gtk_box_pack_start (GTK_BOX (login_vbox), user_view, FALSE, FALSE, 0);
204 by robert.ancell at gmail
Show username entry if no user list
580
    }
581
    else
582
    {
583
        username_entry = gtk_entry_new ();
249 by robert.ancell at canonical
Use a single fullscreen window for GTK+ greeter
584
        gtk_box_pack_start (GTK_BOX (login_vbox), username_entry, FALSE, FALSE, 0);
204 by robert.ancell at gmail
Show username entry if no user list
585
        g_signal_connect (username_entry, "activate", G_CALLBACK (username_activate_cb), NULL);
586
        user_model = NULL;
587
    }
155 by robert.ancell at gmail
Fix user view default focus
588
4 by robert.ancell at gmail
Add basic greeter
589
    password_entry = gtk_entry_new ();
144 by robert.ancell at gmail
import gtk greeter
590
    gtk_entry_set_visibility (GTK_ENTRY (password_entry), FALSE);
4 by robert.ancell at gmail
Add basic greeter
591
    gtk_widget_set_sensitive (password_entry, FALSE);
249 by robert.ancell at canonical
Use a single fullscreen window for GTK+ greeter
592
    gtk_box_pack_start (GTK_BOX (login_vbox), password_entry, FALSE, FALSE, 0);
17 by robert.ancell at gmail
Make a greeter panel
593
    g_signal_connect (password_entry, "activate", G_CALLBACK (password_activate_cb), NULL);
34 by robert.ancell at gmail
Move session combo into the menu, hide widgets until needed
594
    gtk_widget_set_no_show_all (password_entry, TRUE);
24 by robert.ancell at gmail
Add session support
595
17 by robert.ancell at gmail
Make a greeter panel
596
    menu_bar = gtk_menu_bar_new ();
249 by robert.ancell at canonical
Use a single fullscreen window for GTK+ greeter
597
    gtk_box_pack_start (GTK_BOX (vbox), menu_bar, FALSE, TRUE, 0);
17 by robert.ancell at gmail
Make a greeter panel
598
107 by robert.ancell at gmail
Implement keyboard layout in GTK+ greeter
599
    menu_item = gtk_image_menu_item_new ();
153 by robert.ancell at gmail
Set background in GTK+ greeter
600
    gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), gtk_image_new_from_icon_name ("preferences-desktop-accessibility", GTK_ICON_SIZE_LARGE_TOOLBAR));
107 by robert.ancell at gmail
Implement keyboard layout in GTK+ greeter
601
    gtk_menu_item_set_label (GTK_MENU_ITEM (menu_item), ""); // NOTE: Needed to make the icon show as selected
602
    gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (menu_item), TRUE);
603
    gtk_menu_shell_append (GTK_MENU_SHELL (menu_bar), menu_item);
17 by robert.ancell at gmail
Make a greeter panel
604
    menu = gtk_menu_new ();
107 by robert.ancell at gmail
Implement keyboard layout in GTK+ greeter
605
    gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), menu);
144 by robert.ancell at gmail
import gtk greeter
606
607
    menu_item = gtk_check_menu_item_new_with_label (_("Large Font"));
608
    g_signal_connect (menu_item, "toggled", G_CALLBACK (a11y_font_cb), NULL);
609
    gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
610
611
    menu_item = gtk_check_menu_item_new_with_label (_("High Constrast"));
612
    g_signal_connect (menu_item, "toggled", G_CALLBACK (a11y_contrast_cb), NULL);
613
    gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
17 by robert.ancell at gmail
Make a greeter panel
614
107 by robert.ancell at gmail
Implement keyboard layout in GTK+ greeter
615
    menu_item = gtk_menu_item_new_with_label (_("Options"));
616
    gtk_menu_shell_append (GTK_MENU_SHELL (menu_bar), menu_item);
617
    option_menu = gtk_menu_new ();
618
    gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), option_menu);
619
620
    menu_item = gtk_menu_item_new_with_label (_("Language"));
621
    gtk_menu_shell_append (GTK_MENU_SHELL (option_menu), menu_item);
622
    menu = gtk_menu_new ();
623
    gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), menu);
237 by robert.ancell at canonical
support language changes
624
109 by robert.ancell at gmail
Add language information
625
    items = ldm_greeter_get_languages (greeter);
626
    for (item = items; item; item = item->next)
627
    {
628
        LdmLanguage *language = item->data;
629
        gchar *label;
630
      
631
        if (ldm_language_get_name (language)[0] == '\0')
632
            label = g_strdup (ldm_language_get_code (language));
633
        else
634
            label = g_strdup_printf ("%s - %s", ldm_language_get_name (language), ldm_language_get_territory (language));
635
636
        menu_item = gtk_radio_menu_item_new_with_label (language_radio_list, label);
637
        language_radio_list = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (menu_item));
638
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
639
252 by robert.ancell at canonical
Add configuration for default language/layout
640
        if (g_str_equal (ldm_language_get_code (language), ldm_greeter_get_default_language (greeter)))
109 by robert.ancell at gmail
Add language information
641
            gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), TRUE);
642
237 by robert.ancell at canonical
support language changes
643
        g_object_set_data (G_OBJECT (menu_item), "language", g_strdup (ldm_language_get_code (language)));
109 by robert.ancell at gmail
Add language information
644
    }
107 by robert.ancell at gmail
Implement keyboard layout in GTK+ greeter
645
646
    menu_item = gtk_menu_item_new_with_label (_("Keyboard Layout"));
647
    gtk_menu_shell_append (GTK_MENU_SHELL (option_menu), menu_item);
648
    menu = gtk_menu_new ();
649
    gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), menu);
650
    items = ldm_greeter_get_layouts (greeter);
651
    for (item = items; item; item = item->next)
652
    {
653
        LdmLayout *layout = item->data;
654
655
        menu_item = gtk_radio_menu_item_new_with_label (layout_radio_list, ldm_layout_get_description (layout));
656
        layout_radio_list = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (menu_item));
657
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
658
255 by robert.ancell at canonical
Change language/layout/session when user selected in GTK+ greeter
659
        if (g_str_equal (ldm_layout_get_name (layout), ldm_greeter_get_default_layout (greeter)))
107 by robert.ancell at gmail
Implement keyboard layout in GTK+ greeter
660
            gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), TRUE);
661
662
        g_object_set_data (G_OBJECT (menu_item), "layout", g_strdup (ldm_layout_get_name (layout)));
663
        g_signal_connect (menu_item, "toggled", G_CALLBACK (layout_changed_cb), NULL);
664
    }
665
257 by robert.ancell at canonical
Set the default keymap on startup
666
    ldm_greeter_set_layout (greeter, ldm_greeter_get_default_layout (greeter));
667
107 by robert.ancell at gmail
Implement keyboard layout in GTK+ greeter
668
    menu_item = gtk_menu_item_new_with_label (_("Session"));
669
    gtk_menu_shell_append (GTK_MENU_SHELL (option_menu), menu_item);
670
    menu = gtk_menu_new ();
671
    gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), menu);
672
    items = ldm_greeter_get_sessions (greeter);
673
    for (item = items; item; item = item->next)
674
    {
675
        LdmSession *session = item->data;
676
677
        menu_item = gtk_radio_menu_item_new_with_label (session_radio_list, ldm_session_get_name (session));
678
        session_radio_list = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (menu_item));
679
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
680
173 by robert.ancell at gmail
Use better login API
681
        if (g_str_equal (ldm_session_get_key (session), ldm_greeter_get_default_session (greeter)))
107 by robert.ancell at gmail
Implement keyboard layout in GTK+ greeter
682
            gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), TRUE);
683
684
        g_object_set_data (G_OBJECT (menu_item), "key", g_strdup (ldm_session_get_key (session)));
685
    }
686
687
    power_menu = gtk_menu_new ();
65 by robert.ancell at gmail
Use namespace for client library, add object properties
688
    if (ldm_greeter_get_can_suspend (greeter))
40 by robert.ancell at gmail
Check if can do power options and implement power d-bus calls
689
    {
195 by robert.ancell at gmail
Make shutdown buttons work in GTK+ greeter
690
        menu_item = gtk_menu_item_new_with_label (_("Suspend"));
691
        gtk_menu_shell_append (GTK_MENU_SHELL (power_menu), menu_item);
692
        g_signal_connect (menu_item, "activate", G_CALLBACK (suspend_cb), greeter);
40 by robert.ancell at gmail
Check if can do power options and implement power d-bus calls
693
        n_power_items++;
694
    }
65 by robert.ancell at gmail
Use namespace for client library, add object properties
695
    if (ldm_greeter_get_can_hibernate (greeter))
40 by robert.ancell at gmail
Check if can do power options and implement power d-bus calls
696
    {
195 by robert.ancell at gmail
Make shutdown buttons work in GTK+ greeter
697
        menu_item = gtk_menu_item_new_with_label (_("Hibernate"));
698
        gtk_menu_shell_append (GTK_MENU_SHELL (power_menu), menu_item);
699
        g_signal_connect (menu_item, "activate", G_CALLBACK (hibernate_cb), greeter);
40 by robert.ancell at gmail
Check if can do power options and implement power d-bus calls
700
        n_power_items++;
701
    }
65 by robert.ancell at gmail
Use namespace for client library, add object properties
702
    if (ldm_greeter_get_can_restart (greeter))
40 by robert.ancell at gmail
Check if can do power options and implement power d-bus calls
703
    {
195 by robert.ancell at gmail
Make shutdown buttons work in GTK+ greeter
704
        menu_item = gtk_menu_item_new_with_label (_("Restart..."));
705
        gtk_menu_shell_append (GTK_MENU_SHELL (power_menu), menu_item);
706
        g_signal_connect (menu_item, "activate", G_CALLBACK (restart_cb), greeter);
40 by robert.ancell at gmail
Check if can do power options and implement power d-bus calls
707
        n_power_items++;
708
    }
65 by robert.ancell at gmail
Use namespace for client library, add object properties
709
    if (ldm_greeter_get_can_shutdown (greeter))
40 by robert.ancell at gmail
Check if can do power options and implement power d-bus calls
710
    {
195 by robert.ancell at gmail
Make shutdown buttons work in GTK+ greeter
711
        menu_item = gtk_menu_item_new_with_label (_("Shutdown..."));
712
        gtk_menu_shell_append (GTK_MENU_SHELL (power_menu), menu_item);
713
        g_signal_connect (menu_item, "activate", G_CALLBACK (shutdown_cb), greeter);
40 by robert.ancell at gmail
Check if can do power options and implement power d-bus calls
714
        n_power_items++;
715
    }
716
    if (n_power_items > 0)
717
    {
107 by robert.ancell at gmail
Implement keyboard layout in GTK+ greeter
718
        menu_item = gtk_image_menu_item_new ();
719
        gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (menu_item), TRUE);
720
        gtk_menu_item_set_right_justified (GTK_MENU_ITEM (menu_item), TRUE);
721
        gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), gtk_image_new_from_icon_name ("system-shutdown", GTK_ICON_SIZE_LARGE_TOOLBAR));
722
        gtk_menu_item_set_label (GTK_MENU_ITEM (menu_item), ""); // NOTE: Needed to make the icon show as selected
153 by robert.ancell at gmail
Set background in GTK+ greeter
723
        gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), power_menu);
107 by robert.ancell at gmail
Implement keyboard layout in GTK+ greeter
724
        gtk_menu_shell_append (GTK_MENU_SHELL (menu_bar), menu_item);
40 by robert.ancell at gmail
Check if can do power options and implement power d-bus calls
725
    }
17 by robert.ancell at gmail
Make a greeter panel
726
249 by robert.ancell at canonical
Use a single fullscreen window for GTK+ greeter
727
    gtk_widget_show_all (window);
4 by robert.ancell at gmail
Add basic greeter
728
155 by robert.ancell at gmail
Fix user view default focus
729
    gtk_widget_grab_focus (user_view);
730
4 by robert.ancell at gmail
Add basic greeter
731
    gtk_main ();
732
733
    return 0;
734
}