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 | #ifdef HAVE_CONFIG_H |
---|
13 | #include <config.h> |
---|
14 | #endif |
---|
15 | |
---|
16 | #ifdef HAVE_STDLIB_H |
---|
17 | #include <stdlib.h> |
---|
18 | #endif |
---|
19 | |
---|
20 | #include <glib-unix.h> |
---|
21 | |
---|
22 | #include <locale.h> |
---|
23 | #include <gdk/gdkx.h> |
---|
24 | #include <gtk/gtk.h> |
---|
25 | #include <glib/gi18n.h> |
---|
26 | #include <sys/mman.h> |
---|
27 | #include <sys/wait.h> |
---|
28 | #include <glib.h> |
---|
29 | #include <gtk/gtkx.h> |
---|
30 | #include <glib/gslist.h> |
---|
31 | |
---|
32 | #ifdef HAVE_LIBINDICATOR |
---|
33 | #include <libindicator/indicator-object.h> |
---|
34 | #ifdef HAVE_LIBINDICATOR_NG |
---|
35 | #include <libindicator/indicator-ng.h> |
---|
36 | #endif |
---|
37 | #endif |
---|
38 | |
---|
39 | #ifdef HAVE_LIBIDO |
---|
40 | /* Some indicators need ido library */ |
---|
41 | #include <libido/libido.h> |
---|
42 | #endif |
---|
43 | |
---|
44 | #ifdef HAVE_LIBXKLAVIER |
---|
45 | #include <libxklavier/xklavier.h> |
---|
46 | #endif |
---|
47 | |
---|
48 | #include <lightdm.h> |
---|
49 | |
---|
50 | #include "src/greeterconfiguration.h" |
---|
51 | #include "src/greetermenubar.h" |
---|
52 | #include "src/greeterbackground.h" |
---|
53 | #include "src/lightdm-gtk-greeter-ui.h" |
---|
54 | #include "src/lightdm-gtk-greeter-css-fallback.h" |
---|
55 | #include "src/lightdm-gtk-greeter-css-application.h" |
---|
56 | |
---|
57 | |
---|
58 | static LightDMGreeter *greeter; |
---|
59 | |
---|
60 | /* List of spawned processes */ |
---|
61 | static GSList *pids_to_close = NULL; |
---|
62 | static GPid spawn_argv_pid (gchar **argv, GSpawnFlags flags, gint *pfd, GError **perror); |
---|
63 | #if defined(AT_SPI_COMMAND) || defined(INDICATOR_SERVICES_COMMAND) |
---|
64 | static GPid spawn_line_pid (const gchar *line, GSpawnFlags flags, GError **perror); |
---|
65 | #endif |
---|
66 | static void close_pid (GPid pid, gboolean remove); |
---|
67 | static void sigterm_cb (gpointer user_data); |
---|
68 | |
---|
69 | /* Screen window */ |
---|
70 | static GtkOverlay *screen_overlay; |
---|
71 | static GtkWidget *screen_overlay_child; |
---|
72 | |
---|
73 | /* Login window */ |
---|
74 | static GtkWidget *login_window; |
---|
75 | static GtkImage *user_image; |
---|
76 | static GtkComboBox *user_combo; |
---|
77 | static GtkEntry *username_entry, *password_entry; |
---|
78 | static GtkLabel *message_label; |
---|
79 | static GtkInfoBar *info_bar; |
---|
80 | static GtkButton *cancel_button, *login_button; |
---|
81 | |
---|
82 | /* Panel */ |
---|
83 | static GtkWidget *panel_window, *menubar; |
---|
84 | static GtkWidget *power_menuitem, *session_menuitem, *language_menuitem, *a11y_menuitem, |
---|
85 | *layout_menuitem, *clock_menuitem, *host_menuitem; |
---|
86 | static GtkWidget *suspend_menuitem, *hibernate_menuitem, *restart_menuitem, *shutdown_menuitem; |
---|
87 | static GtkWidget *contrast_menuitem, *font_menuitem, *keyboard_menuitem, *reader_menuitem; |
---|
88 | static GtkWidget *clock_label, *session_badge; |
---|
89 | static GtkMenu *session_menu, *language_menu, *layout_menu; |
---|
90 | |
---|
91 | /* Power window */ |
---|
92 | static GtkWidget *power_window; |
---|
93 | static GtkButton *power_ok_button, *power_cancel_button; |
---|
94 | static GtkLabel *power_title, *power_text; |
---|
95 | static GtkImage *power_icon; |
---|
96 | |
---|
97 | static const gchar *POWER_WINDOW_DATA_LOOP = "power-window-loop"; /* <GMainLoop*> */ |
---|
98 | static const gchar *POWER_WINDOW_DATA_RESPONSE = "power-window-response"; /* <GtkResponseType> */ |
---|
99 | |
---|
100 | static gboolean show_power_prompt (const gchar *action, const gchar* icon, const gchar* title, const gchar* message); |
---|
101 | void power_button_clicked_cb (GtkButton *button, gpointer user_data); |
---|
102 | gboolean power_window_key_press_event_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data); |
---|
103 | |
---|
104 | /* Handling window position */ |
---|
105 | typedef struct |
---|
106 | { |
---|
107 | gint value; |
---|
108 | /* +0 and -0 */ |
---|
109 | gint sign; |
---|
110 | /* interpret 'value' as percentage of screen width/height */ |
---|
111 | gboolean percentage; |
---|
112 | /* -1: left/top, 0: center, +1: right,bottom */ |
---|
113 | gint anchor; |
---|
114 | } DimensionPosition; |
---|
115 | |
---|
116 | typedef struct |
---|
117 | { |
---|
118 | DimensionPosition x, y; |
---|
119 | /* Flag to use width and height fileds */ |
---|
120 | gboolean use_size; |
---|
121 | DimensionPosition width, height; |
---|
122 | } WindowPosition; |
---|
123 | |
---|
124 | static WindowPosition* str_to_position (const gchar *str, const WindowPosition *default_value); |
---|
125 | /* Function translate user defined coordinates to absolute value */ |
---|
126 | static gint get_absolute_position (const DimensionPosition *p, gint screen, gint window); |
---|
127 | gboolean screen_overlay_get_child_position_cb (GtkWidget *overlay, GtkWidget *widget, GdkRectangle *allocation, gpointer user_data); |
---|
128 | |
---|
129 | static const gchar *WINDOW_DATA_POSITION = "window-position"; /* <WindowPosition*> */ |
---|
130 | |
---|
131 | /* Some default positions */ |
---|
132 | static const WindowPosition WINDOW_POS_CENTER = {.x = { 50, +1, TRUE, 0}, .y = { 50, +1, TRUE, 0}, .use_size = FALSE}; |
---|
133 | static const WindowPosition KEYBOARD_POSITION = {.x = { 50, +1, TRUE, 0}, .y = { 0, -1, FALSE, +1}, .use_size = TRUE, |
---|
134 | .width = {50, 0, TRUE, 0}, .height = {25, 0, TRUE, 0}}; |
---|
135 | |
---|
136 | /* Clock */ |
---|
137 | static gchar *clock_format; |
---|
138 | static gboolean clock_timeout_thread (void); |
---|
139 | |
---|
140 | /* Message label */ |
---|
141 | static gboolean message_label_is_empty (void); |
---|
142 | static void set_message_label (LightDMMessageType type, const gchar *text); |
---|
143 | |
---|
144 | /* User image */ |
---|
145 | static GdkPixbuf *default_user_pixbuf = NULL; |
---|
146 | static gchar *default_user_icon = "avatar-default"; |
---|
147 | static void set_user_image (const gchar *username); |
---|
148 | |
---|
149 | /* External command (keyboard, reader) */ |
---|
150 | typedef struct |
---|
151 | { |
---|
152 | const gchar *name; |
---|
153 | |
---|
154 | gchar **argv; |
---|
155 | gint argc; |
---|
156 | |
---|
157 | GPid pid; |
---|
158 | GtkWidget *menu_item; |
---|
159 | GtkWidget *widget; |
---|
160 | } MenuCommand; |
---|
161 | |
---|
162 | static MenuCommand *menu_command_parse (const gchar *name, const gchar *value, GtkWidget *menu_item); |
---|
163 | static MenuCommand *menu_command_parse_extended (const gchar *name, |
---|
164 | const gchar *value, GtkWidget *menu_item, |
---|
165 | const gchar *xid_app, const gchar *xid_arg); |
---|
166 | static gboolean menu_command_run (MenuCommand *command); |
---|
167 | static gboolean menu_command_stop (MenuCommand *command); |
---|
168 | static void menu_command_terminated_cb (GPid pid, gint status, MenuCommand *command); |
---|
169 | |
---|
170 | static MenuCommand *a11y_keyboard_command; |
---|
171 | static MenuCommand *a11y_reader_command; |
---|
172 | |
---|
173 | static void a11y_menuitem_toggled_cb (GtkCheckMenuItem *item, const gchar* name); |
---|
174 | |
---|
175 | /* Session */ |
---|
176 | static gchar *current_session; |
---|
177 | static gboolean is_valid_session (GList* items, const gchar* session); |
---|
178 | static gchar* get_session (void); |
---|
179 | static void set_session (const gchar *session); |
---|
180 | void session_selected_cb (GtkMenuItem *menuitem, gpointer user_data); |
---|
181 | |
---|
182 | /* Sesion language */ |
---|
183 | static gchar *current_language; |
---|
184 | static gchar* get_language (void); |
---|
185 | static void set_language (const gchar *language); |
---|
186 | void language_selected_cb (GtkMenuItem *menuitem, gpointer user_data); |
---|
187 | |
---|
188 | /* Screensaver values */ |
---|
189 | static int timeout, interval, prefer_blanking, allow_exposures; |
---|
190 | |
---|
191 | /* Handling monitors backgrounds */ |
---|
192 | static const gint USER_BACKGROUND_DELAY = 250; |
---|
193 | static GreeterBackground *greeter_background; |
---|
194 | |
---|
195 | /* Authentication state */ |
---|
196 | static gboolean cancelling = FALSE, prompted = FALSE; |
---|
197 | static gboolean prompt_active = FALSE, password_prompted = FALSE; |
---|
198 | |
---|
199 | /* Pending questions */ |
---|
200 | static GSList *pending_questions = NULL; |
---|
201 | |
---|
202 | typedef struct |
---|
203 | { |
---|
204 | gboolean is_prompt; |
---|
205 | union |
---|
206 | { |
---|
207 | LightDMMessageType message; |
---|
208 | LightDMPromptType prompt; |
---|
209 | } type; |
---|
210 | gchar *text; |
---|
211 | } PAMConversationMessage; |
---|
212 | |
---|
213 | static void pam_message_finalize (PAMConversationMessage *message); |
---|
214 | static void process_prompts (LightDMGreeter *greeter); |
---|
215 | static void show_prompt_cb (LightDMGreeter *greeter, const gchar *text, LightDMPromptType type); |
---|
216 | |
---|
217 | /* Panel and indicators */ |
---|
218 | |
---|
219 | typedef enum |
---|
220 | { |
---|
221 | PANEL_ITEM_INDICATOR, |
---|
222 | PANEL_ITEM_SPACER, |
---|
223 | PANEL_ITEM_SEPARATOR, |
---|
224 | PANEL_ITEM_TEXT |
---|
225 | } GreeterPanelItemType; |
---|
226 | |
---|
227 | static const gchar *PANEL_ITEM_STYLE = "panel-item"; |
---|
228 | static const gchar *PANEL_ITEM_STYLE_HOVERED = "panel-item-hovered"; |
---|
229 | static const gchar *PANEL_ITEM_STYLES[] = |
---|
230 | { |
---|
231 | "panel-item-indicator", |
---|
232 | "panel-item-spacer", |
---|
233 | "panel-item-separator", |
---|
234 | "panel-item-text" |
---|
235 | }; |
---|
236 | |
---|
237 | static const gchar *PANEL_ITEM_DATA_INDEX = "panel-item-data-index"; |
---|
238 | |
---|
239 | #ifdef HAVE_LIBINDICATOR |
---|
240 | static const gchar *INDICATOR_ITEM_DATA_OBJECT = "indicator-item-data-object"; /* <IndicatorObject*> */ |
---|
241 | static const gchar *INDICATOR_ITEM_DATA_ENTRY = "indicator-item-data-entry"; /* <IndicatorObjectEntry*> */ |
---|
242 | static const gchar *INDICATOR_ITEM_DATA_BOX = "indicator-item-data-box"; /* <GtkBox*> */ |
---|
243 | static const gchar *INDICATOR_DATA_MENUITEMS = "indicator-data-menuitems"; /* <GHashTable*> */ |
---|
244 | #endif |
---|
245 | |
---|
246 | static const gchar *LANGUAGE_DATA_CODE = "language-code"; /* <gchar*> e.g. "de_DE.UTF-8" */ |
---|
247 | static const gchar *SESSION_DATA_KEY = "session-key"; /* <gchar*> session name */ |
---|
248 | |
---|
249 | /* Layout indicator */ |
---|
250 | #ifdef HAVE_LIBXKLAVIER |
---|
251 | static XklEngine *xkl_engine; |
---|
252 | static const gchar *LAYOUT_DATA_GROUP = "layout-group"; /* <gchar*> */ |
---|
253 | #else |
---|
254 | static const gchar *LAYOUT_DATA_NAME = "layout-name"; /* <gchar*> */ |
---|
255 | #endif |
---|
256 | static const gchar *LAYOUT_DATA_LABEL = "layout-label"; /* <gchar*> e.g. "English (US)" */ |
---|
257 | |
---|
258 | static gboolean panel_item_enter_notify_cb (GtkWidget *widget, GdkEvent *event, gpointer enter); |
---|
259 | static void panel_add_item (GtkWidget *widget, gint index, GreeterPanelItemType item_type); |
---|
260 | static gboolean menu_item_accel_closure_cb (GtkAccelGroup *accel_group, GObject *acceleratable, guint keyval, GdkModifierType modifier, gpointer data); |
---|
261 | /* Maybe unnecessary (in future) trick to enable accelerators for hidden/detached menu items */ |
---|
262 | static void reassign_menu_item_accel (GtkWidget *item); |
---|
263 | |
---|
264 | static void init_indicators (void); |
---|
265 | |
---|
266 | static void layout_selected_cb (GtkCheckMenuItem *menuitem, gpointer user_data); |
---|
267 | static void update_layouts_menu (void); |
---|
268 | static void update_layouts_menu_state (void); |
---|
269 | #ifdef HAVE_LIBXKLAVIER |
---|
270 | static void xkl_state_changed_cb (XklEngine *engine, XklEngineStateChange change, gint group, gboolean restore, gpointer user_data); |
---|
271 | static void xkl_config_changed_cb (XklEngine *engine, gpointer user_data); |
---|
272 | static GdkFilterReturn xkl_xevent_filter (GdkXEvent *xev, GdkEvent *event, gpointer data); |
---|
273 | #endif |
---|
274 | |
---|
275 | /* a11y indicator */ |
---|
276 | static gchar *default_font_name, |
---|
277 | *default_theme_name, |
---|
278 | *default_icon_theme_name; |
---|
279 | void a11y_font_cb (GtkCheckMenuItem *item); |
---|
280 | void a11y_contrast_cb (GtkCheckMenuItem *item); |
---|
281 | void a11y_keyboard_cb (GtkCheckMenuItem *item, gpointer user_data); |
---|
282 | void a11y_reader_cb (GtkCheckMenuItem *item, gpointer user_data); |
---|
283 | |
---|
284 | /* Power indicator */ |
---|
285 | static void power_menu_cb (GtkWidget *menuitem, gpointer userdata); |
---|
286 | void suspend_cb (GtkWidget *widget, LightDMGreeter *greeter); |
---|
287 | void hibernate_cb (GtkWidget *widget, LightDMGreeter *greeter); |
---|
288 | void restart_cb (GtkWidget *widget, LightDMGreeter *greeter); |
---|
289 | void shutdown_cb (GtkWidget *widget, LightDMGreeter *greeter); |
---|
290 | |
---|
291 | static void read_monitor_configuration (const gchar *group, const gchar *name); |
---|
292 | |
---|
293 | struct SavedFocusData |
---|
294 | { |
---|
295 | GtkWidget *widget; |
---|
296 | gint editable_pos; |
---|
297 | }; |
---|
298 | |
---|
299 | gpointer greeter_save_focus(GtkWidget* widget); |
---|
300 | void greeter_restore_focus(const gpointer saved_data); |
---|
301 | |
---|
302 | |
---|
303 | static void |
---|
304 | read_monitor_configuration (const gchar *group, const gchar *name) |
---|
305 | { |
---|
306 | g_debug ("[Configuration] Monitor configuration found: '%s'", name); |
---|
307 | |
---|
308 | gchar *background = config_get_string (group, CONFIG_KEY_BACKGROUND, NULL); |
---|
309 | greeter_background_set_monitor_config (greeter_background, name, background, |
---|
310 | config_get_bool (group, CONFIG_KEY_USER_BACKGROUND, -1), |
---|
311 | config_get_bool (group, CONFIG_KEY_LAPTOP, -1), |
---|
312 | config_get_int (group, CONFIG_KEY_T_DURATION, -1), |
---|
313 | config_get_enum (group, CONFIG_KEY_T_TYPE, |
---|
314 | TRANSITION_TYPE_FALLBACK, |
---|
315 | "none", TRANSITION_TYPE_NONE, |
---|
316 | "linear", TRANSITION_TYPE_LINEAR, |
---|
317 | "ease-in-out", TRANSITION_TYPE_EASE_IN_OUT, NULL)); |
---|
318 | g_free (background); |
---|
319 | } |
---|
320 | |
---|
321 | gpointer |
---|
322 | greeter_save_focus(GtkWidget* widget) |
---|
323 | { |
---|
324 | GtkWidget *window = gtk_widget_get_toplevel(widget); |
---|
325 | if (!GTK_IS_WINDOW (window)) |
---|
326 | return NULL; |
---|
327 | |
---|
328 | struct SavedFocusData *data = g_new0 (struct SavedFocusData, 1); |
---|
329 | data->widget = gtk_window_get_focus (GTK_WINDOW (window)); |
---|
330 | data->editable_pos = GTK_IS_EDITABLE(data->widget) ? gtk_editable_get_position (GTK_EDITABLE (data->widget)) : -1; |
---|
331 | |
---|
332 | return data; |
---|
333 | } |
---|
334 | |
---|
335 | void |
---|
336 | greeter_restore_focus(const gpointer saved_data) |
---|
337 | { |
---|
338 | struct SavedFocusData *data = saved_data; |
---|
339 | |
---|
340 | if (!saved_data || !GTK_IS_WIDGET (data->widget)) |
---|
341 | return; |
---|
342 | |
---|
343 | gtk_widget_grab_focus (data->widget); |
---|
344 | if (GTK_IS_EDITABLE(data->widget) && data->editable_pos > -1) |
---|
345 | gtk_editable_set_position(GTK_EDITABLE(data->widget), data->editable_pos); |
---|
346 | } |
---|
347 | |
---|
348 | static void |
---|
349 | infobar_revealed_cb_710888 (GObject *gobject, GParamSpec *pspec, gpointer user_data) |
---|
350 | { |
---|
351 | gtk_widget_set_visible (GTK_WIDGET (info_bar), !message_label_is_empty ()); |
---|
352 | } |
---|
353 | |
---|
354 | /* Terminating */ |
---|
355 | |
---|
356 | static GPid |
---|
357 | spawn_argv_pid (gchar **argv, GSpawnFlags flags, gint *pfd, GError **perror) |
---|
358 | { |
---|
359 | GPid pid = 0; |
---|
360 | GError *error = NULL; |
---|
361 | gboolean spawned = FALSE; |
---|
362 | |
---|
363 | if (pfd) |
---|
364 | spawned = g_spawn_async_with_pipes (NULL, argv, NULL, flags, NULL, NULL, &pid, NULL, pfd, NULL, perror); |
---|
365 | else |
---|
366 | spawned = g_spawn_async (NULL, argv, NULL, flags, NULL, NULL, &pid, &error); |
---|
367 | |
---|
368 | if (spawned) |
---|
369 | { |
---|
370 | pids_to_close = g_slist_prepend (pids_to_close, GINT_TO_POINTER (pid)); |
---|
371 | g_debug ("[PIDs] Command executed (#%d): %s", pid, argv[0]); |
---|
372 | } |
---|
373 | else if (perror) |
---|
374 | { |
---|
375 | *perror = error; |
---|
376 | } |
---|
377 | else |
---|
378 | { |
---|
379 | g_warning ("[PIDs] Failed to execute command: %s", argv[0]); |
---|
380 | g_clear_error (&error); |
---|
381 | } |
---|
382 | |
---|
383 | return pid; |
---|
384 | } |
---|
385 | |
---|
386 | #if defined(AT_SPI_COMMAND) || defined(INDICATOR_SERVICES_COMMAND) |
---|
387 | static GPid |
---|
388 | spawn_line_pid (const gchar *line, GSpawnFlags flags, GError **perror) |
---|
389 | { |
---|
390 | gint argc = 0; |
---|
391 | gchar **argv = NULL; |
---|
392 | GError *error = NULL; |
---|
393 | |
---|
394 | if (g_shell_parse_argv (line, &argc, &argv, &error)) |
---|
395 | { |
---|
396 | GPid pid = spawn_argv_pid (argv, flags, NULL, perror); |
---|
397 | g_strfreev (argv); |
---|
398 | return pid; |
---|
399 | } |
---|
400 | else if (!perror && error) |
---|
401 | { |
---|
402 | g_warning ("[PIDs] Failed to parse command line: %s, %s", error->message, line); |
---|
403 | g_clear_error (&error); |
---|
404 | } |
---|
405 | else if (error) |
---|
406 | *perror = error; |
---|
407 | |
---|
408 | return 0; |
---|
409 | } |
---|
410 | #endif |
---|
411 | |
---|
412 | static void |
---|
413 | close_pid (GPid pid, gboolean remove) |
---|
414 | { |
---|
415 | if (!pid) |
---|
416 | return; |
---|
417 | |
---|
418 | if (remove) |
---|
419 | pids_to_close = g_slist_remove (pids_to_close, GINT_TO_POINTER (pid)); |
---|
420 | |
---|
421 | if (kill (pid, SIGTERM) == 0) |
---|
422 | g_debug ("[PIDs] Process terminated: #%d", pid); |
---|
423 | else |
---|
424 | g_warning ("[PIDs] Failed to terminate process #%d: %s", pid, g_strerror (errno)); |
---|
425 | |
---|
426 | waitpid (pid, NULL, 0); |
---|
427 | } |
---|
428 | |
---|
429 | static void |
---|
430 | sigterm_cb (gpointer user_data) |
---|
431 | { |
---|
432 | gboolean is_callback = GPOINTER_TO_INT (user_data); |
---|
433 | |
---|
434 | if (is_callback) |
---|
435 | g_debug ("SIGTERM received"); |
---|
436 | |
---|
437 | if (pids_to_close) |
---|
438 | { |
---|
439 | g_slist_foreach (pids_to_close, (GFunc)close_pid, GINT_TO_POINTER (FALSE)); |
---|
440 | g_slist_free (pids_to_close); |
---|
441 | pids_to_close = NULL; |
---|
442 | } |
---|
443 | |
---|
444 | if (is_callback) |
---|
445 | { |
---|
446 | gtk_main_quit (); |
---|
447 | #ifdef KILL_ON_SIGTERM |
---|
448 | /* LP: #1445461 */ |
---|
449 | g_debug ("Killing greeter with exit()..."); |
---|
450 | exit (EXIT_SUCCESS); |
---|
451 | #endif |
---|
452 | } |
---|
453 | } |
---|
454 | |
---|
455 | /* Power window */ |
---|
456 | |
---|
457 | static gboolean |
---|
458 | show_power_prompt (const gchar *action, const gchar* icon, const gchar* title, const gchar* message) |
---|
459 | { |
---|
460 | gchar *new_message = NULL; |
---|
461 | |
---|
462 | /* Check if there are still users logged in, count them and if so, display a warning */ |
---|
463 | gint logged_in_users = 0; |
---|
464 | GList *items = lightdm_user_list_get_users (lightdm_user_list_get_instance ()); |
---|
465 | GList *item; |
---|
466 | for (item = items; item; item = item->next) |
---|
467 | { |
---|
468 | LightDMUser *user = item->data; |
---|
469 | if (lightdm_user_get_logged_in (user)) |
---|
470 | logged_in_users++; |
---|
471 | } |
---|
472 | |
---|
473 | if (logged_in_users > 0) |
---|
474 | { |
---|
475 | gchar *warning = g_strdup_printf (ngettext ("Warning: There is still %d user logged in.", |
---|
476 | "Warning: There are still %d users logged in.", |
---|
477 | logged_in_users), |
---|
478 | logged_in_users); |
---|
479 | message = new_message = g_markup_printf_escaped ("<b>%s</b>\n%s", warning, message); |
---|
480 | g_free (warning); |
---|
481 | } |
---|
482 | |
---|
483 | gchar *dialog_name = g_strconcat (action, "_dialog", NULL); |
---|
484 | gchar *button_name = g_strconcat (action, "_button", NULL); |
---|
485 | |
---|
486 | gtk_widget_set_name (power_window, dialog_name); |
---|
487 | gtk_widget_set_name (GTK_WIDGET (power_ok_button), button_name); |
---|
488 | gtk_button_set_label (power_ok_button, title); |
---|
489 | gtk_label_set_label (power_title, title); |
---|
490 | gtk_label_set_markup (power_text, message); |
---|
491 | gtk_image_set_from_icon_name (power_icon, icon, GTK_ICON_SIZE_DIALOG); |
---|
492 | |
---|
493 | g_free (button_name); |
---|
494 | g_free (dialog_name); |
---|
495 | g_free (new_message); |
---|
496 | |
---|
497 | GMainLoop *loop = g_main_loop_new (NULL, FALSE); |
---|
498 | g_object_set_data (G_OBJECT (power_window), POWER_WINDOW_DATA_LOOP, loop); |
---|
499 | g_object_set_data (G_OBJECT (power_window), POWER_WINDOW_DATA_RESPONSE, GINT_TO_POINTER (GTK_RESPONSE_CANCEL)); |
---|
500 | |
---|
501 | GtkWidget *focused = gtk_window_get_focus (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (screen_overlay)))); |
---|
502 | gboolean session_enabled = gtk_widget_get_sensitive (session_menuitem); |
---|
503 | gboolean language_enabled = gtk_widget_get_sensitive (language_menuitem); |
---|
504 | |
---|
505 | gtk_widget_set_sensitive (power_menuitem, FALSE); |
---|
506 | gtk_widget_set_sensitive (session_menuitem, FALSE); |
---|
507 | gtk_widget_set_sensitive (language_menuitem, FALSE); |
---|
508 | gtk_widget_hide (login_window); |
---|
509 | gtk_widget_show (power_window); |
---|
510 | gtk_widget_grab_focus (GTK_WIDGET (power_ok_button)); |
---|
511 | |
---|
512 | g_main_loop_run (loop); |
---|
513 | GtkResponseType response = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (power_window), POWER_WINDOW_DATA_RESPONSE)); |
---|
514 | g_main_loop_unref (loop); |
---|
515 | |
---|
516 | gtk_widget_hide (power_window); |
---|
517 | gtk_widget_show (login_window); |
---|
518 | gtk_widget_set_sensitive (power_menuitem, TRUE); |
---|
519 | gtk_widget_set_sensitive (session_menuitem, session_enabled); |
---|
520 | gtk_widget_set_sensitive (language_menuitem, language_enabled); |
---|
521 | |
---|
522 | if (focused) |
---|
523 | gtk_widget_grab_focus (focused); |
---|
524 | |
---|
525 | return response == GTK_RESPONSE_YES; |
---|
526 | } |
---|
527 | |
---|
528 | void |
---|
529 | power_button_clicked_cb (GtkButton *button, gpointer user_data) |
---|
530 | { |
---|
531 | GMainLoop *loop = g_object_get_data (G_OBJECT (power_window), POWER_WINDOW_DATA_LOOP); |
---|
532 | if (g_main_loop_is_running (loop)) |
---|
533 | g_main_loop_quit (loop); |
---|
534 | |
---|
535 | g_object_set_data (G_OBJECT (power_window), POWER_WINDOW_DATA_RESPONSE, |
---|
536 | GINT_TO_POINTER (button == power_ok_button ? GTK_RESPONSE_YES : GTK_RESPONSE_CANCEL)); |
---|
537 | } |
---|
538 | |
---|
539 | gboolean |
---|
540 | power_window_key_press_event_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data) |
---|
541 | { |
---|
542 | if (event->keyval == GDK_KEY_Escape) |
---|
543 | { |
---|
544 | power_button_clicked_cb (power_cancel_button, NULL); |
---|
545 | return TRUE; |
---|
546 | } |
---|
547 | return FALSE; |
---|
548 | } |
---|
549 | |
---|
550 | /* Handling window position */ |
---|
551 | |
---|
552 | static gboolean |
---|
553 | read_position_from_str (const gchar *s, DimensionPosition *x) |
---|
554 | { |
---|
555 | DimensionPosition p; |
---|
556 | gchar *end = NULL; |
---|
557 | gchar **parts = g_strsplit (s, ",", 2); |
---|
558 | if (parts[0]) |
---|
559 | { |
---|
560 | p.value = g_ascii_strtoll (parts[0], &end, 10); |
---|
561 | p.percentage = end && end[0] == '%'; |
---|
562 | p.sign = (p.value < 0 || (p.value == 0 && parts[0][0] == '-')) ? -1 : +1; |
---|
563 | if (p.value < 0) |
---|
564 | p.value *= -1; |
---|
565 | if (g_strcmp0(parts[1], "start") == 0) |
---|
566 | p.anchor = -1; |
---|
567 | else if (g_strcmp0(parts[1], "center") == 0) |
---|
568 | p.anchor = 0; |
---|
569 | else if (g_strcmp0(parts[1], "end") == 0) |
---|
570 | p.anchor = +1; |
---|
571 | else |
---|
572 | p.anchor = p.sign > 0 ? -1 : +1; |
---|
573 | *x = p; |
---|
574 | } |
---|
575 | else |
---|
576 | x = NULL; |
---|
577 | g_strfreev (parts); |
---|
578 | return x != NULL; |
---|
579 | } |
---|
580 | |
---|
581 | static WindowPosition* |
---|
582 | str_to_position (const gchar *str, const WindowPosition *default_value) |
---|
583 | { |
---|
584 | WindowPosition* pos = g_new0 (WindowPosition, 1); |
---|
585 | *pos = *default_value; |
---|
586 | |
---|
587 | if (str) |
---|
588 | { |
---|
589 | gchar *value = g_strdup (str); |
---|
590 | gchar *x = value; |
---|
591 | gchar *y = strchr (value, ' '); |
---|
592 | if (y) |
---|
593 | (y++)[0] = '\0'; |
---|
594 | |
---|
595 | if (read_position_from_str (x, &pos->x)) |
---|
596 | /* If there is no y-part then y = x */ |
---|
597 | if (!y || !read_position_from_str (y, &pos->y)) |
---|
598 | pos->y = pos->x; |
---|
599 | |
---|
600 | gchar *size_delim = strchr (y ? y : x, ';'); |
---|
601 | if (size_delim) |
---|
602 | { |
---|
603 | gchar *x = size_delim + 1; |
---|
604 | if (read_position_from_str (x, &pos->width)) |
---|
605 | { |
---|
606 | y = strchr (x, ' '); |
---|
607 | if (y) |
---|
608 | (y++)[0] = '\0'; |
---|
609 | if (!y || !read_position_from_str (y, &pos->height)) |
---|
610 | if (!default_value->use_size) |
---|
611 | pos->height = pos->width; |
---|
612 | pos->use_size = TRUE; |
---|
613 | } |
---|
614 | } |
---|
615 | |
---|
616 | g_free (value); |
---|
617 | } |
---|
618 | |
---|
619 | return pos; |
---|
620 | } |
---|
621 | |
---|
622 | static gint |
---|
623 | get_absolute_position (const DimensionPosition *p, gint screen, gint window) |
---|
624 | { |
---|
625 | gint x = p->percentage ? (screen*p->value)/100 : p->value; |
---|
626 | x = p->sign < 0 ? screen - x : x; |
---|
627 | if (p->anchor > 0) |
---|
628 | x -= window; |
---|
629 | else if (p->anchor == 0) |
---|
630 | x -= window/2; |
---|
631 | |
---|
632 | if (x < 0) /* Offscreen: left/top */ |
---|
633 | return 0; |
---|
634 | else if (x + window > screen) /* Offscreen: right/bottom */ |
---|
635 | return screen - window; |
---|
636 | else |
---|
637 | return x; |
---|
638 | } |
---|
639 | |
---|
640 | gboolean |
---|
641 | screen_overlay_get_child_position_cb (GtkWidget *overlay, GtkWidget *widget, GdkRectangle *allocation, gpointer user_data) |
---|
642 | { |
---|
643 | const WindowPosition *pos = g_object_get_data (G_OBJECT (widget), WINDOW_DATA_POSITION); |
---|
644 | if (!pos) |
---|
645 | return FALSE; |
---|
646 | |
---|
647 | gint screen_width = gtk_widget_get_allocated_width (overlay); |
---|
648 | gint screen_height = gtk_widget_get_allocated_height (overlay); |
---|
649 | |
---|
650 | if (pos->use_size) |
---|
651 | { |
---|
652 | allocation->width = get_absolute_position (&pos->width, screen_width, 0); |
---|
653 | allocation->height = get_absolute_position (&pos->height, screen_height, 0); |
---|
654 | } |
---|
655 | else |
---|
656 | { |
---|
657 | gtk_widget_get_preferred_width (widget, NULL, &allocation->width); |
---|
658 | gtk_widget_get_preferred_height (widget, NULL, &allocation->height); |
---|
659 | } |
---|
660 | |
---|
661 | allocation->x = get_absolute_position (&pos->x, screen_width, allocation->width); |
---|
662 | allocation->y = get_absolute_position (&pos->y, screen_height, allocation->height); |
---|
663 | |
---|
664 | /* Do not overlap panel window */ |
---|
665 | gint panel_height = gtk_widget_get_allocated_height (panel_window); |
---|
666 | if (panel_height && gtk_widget_get_visible (panel_window)) |
---|
667 | { |
---|
668 | GtkAlign valign = gtk_widget_get_valign (panel_window); |
---|
669 | if (valign == GTK_ALIGN_START && allocation->y < panel_height) |
---|
670 | allocation->y = panel_height; |
---|
671 | else if (valign == GTK_ALIGN_END && screen_height - allocation->y - allocation->height < panel_height) |
---|
672 | allocation->y = screen_height - allocation->height - panel_height; |
---|
673 | } |
---|
674 | |
---|
675 | return TRUE; |
---|
676 | } |
---|
677 | |
---|
678 | /* Clock */ |
---|
679 | |
---|
680 | static gboolean |
---|
681 | clock_timeout_thread (void) |
---|
682 | { |
---|
683 | time_t rawtime; |
---|
684 | struct tm * timeinfo; |
---|
685 | gchar time_str[50]; |
---|
686 | gchar *markup; |
---|
687 | |
---|
688 | time (&rawtime); |
---|
689 | timeinfo = localtime (&rawtime); |
---|
690 | |
---|
691 | strftime (time_str, 50, clock_format, timeinfo); |
---|
692 | markup = g_markup_printf_escaped ("<b>%s</b>", time_str); |
---|
693 | if (g_strcmp0 (markup, gtk_label_get_label (GTK_LABEL (clock_label))) != 0) |
---|
694 | gtk_label_set_markup (GTK_LABEL (clock_label), markup); |
---|
695 | g_free (markup); |
---|
696 | |
---|
697 | return TRUE; |
---|
698 | } |
---|
699 | |
---|
700 | /* Message label */ |
---|
701 | |
---|
702 | static gboolean |
---|
703 | message_label_is_empty (void) |
---|
704 | { |
---|
705 | return gtk_label_get_text (message_label)[0] == '\0'; |
---|
706 | } |
---|
707 | |
---|
708 | static void |
---|
709 | set_message_label (LightDMMessageType type, const gchar *text) |
---|
710 | { |
---|
711 | if (type == LIGHTDM_MESSAGE_TYPE_INFO) |
---|
712 | gtk_info_bar_set_message_type (info_bar, GTK_MESSAGE_INFO); |
---|
713 | else |
---|
714 | gtk_info_bar_set_message_type (info_bar, GTK_MESSAGE_ERROR); |
---|
715 | gtk_label_set_text (message_label, text); |
---|
716 | gtk_widget_set_visible (GTK_WIDGET (info_bar), text && text[0]); |
---|
717 | } |
---|
718 | |
---|
719 | /* User image */ |
---|
720 | |
---|
721 | static void |
---|
722 | set_user_image (const gchar *username) |
---|
723 | { |
---|
724 | const gchar *path; |
---|
725 | LightDMUser *user = NULL; |
---|
726 | GdkPixbuf *image = NULL; |
---|
727 | GError *error = NULL; |
---|
728 | |
---|
729 | if (!gtk_widget_get_visible (GTK_WIDGET (user_image))) |
---|
730 | return; |
---|
731 | |
---|
732 | if (username) |
---|
733 | user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username); |
---|
734 | |
---|
735 | if (user) |
---|
736 | { |
---|
737 | path = lightdm_user_get_image (user); |
---|
738 | if (path) |
---|
739 | { |
---|
740 | image = gdk_pixbuf_new_from_file_at_scale (path, 80, 80, FALSE, &error); |
---|
741 | if (image) |
---|
742 | { |
---|
743 | gtk_image_set_from_pixbuf (GTK_IMAGE (user_image), image); |
---|
744 | g_object_unref (image); |
---|
745 | return; |
---|
746 | } |
---|
747 | else |
---|
748 | { |
---|
749 | g_debug ("Failed to load user image: %s", error->message); |
---|
750 | g_clear_error (&error); |
---|
751 | } |
---|
752 | } |
---|
753 | } |
---|
754 | |
---|
755 | if (default_user_pixbuf) |
---|
756 | gtk_image_set_from_pixbuf (GTK_IMAGE (user_image), default_user_pixbuf); |
---|
757 | else |
---|
758 | gtk_image_set_from_icon_name (GTK_IMAGE (user_image), default_user_icon, GTK_ICON_SIZE_DIALOG); |
---|
759 | } |
---|
760 | |
---|
761 | /* MenuCommand */ |
---|
762 | |
---|
763 | static MenuCommand* |
---|
764 | menu_command_parse (const gchar *name, const gchar *value, GtkWidget *menu_item) |
---|
765 | { |
---|
766 | return menu_command_parse_extended (name, value, menu_item, NULL, NULL); |
---|
767 | } |
---|
768 | |
---|
769 | static MenuCommand* |
---|
770 | menu_command_parse_extended (const gchar *name, |
---|
771 | const gchar *value, /* String to parse */ |
---|
772 | GtkWidget *menu_item, /* Menu item to connect */ |
---|
773 | const gchar *xid_app, /* Program that have "xembed" mode support */ |
---|
774 | const gchar *xid_arg) /* Argument that must be added to command line */ |
---|
775 | { |
---|
776 | if (!value) |
---|
777 | return NULL; |
---|
778 | |
---|
779 | GError *error = NULL; |
---|
780 | gchar **argv; |
---|
781 | gint argc = 0; |
---|
782 | |
---|
783 | if (!g_shell_parse_argv (value, &argc, &argv, &error)) |
---|
784 | { |
---|
785 | if (error) |
---|
786 | g_warning ("[Command/%s] Failed to parse command line: %s", name, error->message); |
---|
787 | g_clear_error (&error); |
---|
788 | return NULL; |
---|
789 | } |
---|
790 | |
---|
791 | MenuCommand *command = g_new0 (MenuCommand, 1); |
---|
792 | command->menu_item = menu_item; |
---|
793 | command->argc = argc; |
---|
794 | command->argv = argv; |
---|
795 | |
---|
796 | if (g_strcmp0 (argv[0], xid_app) == 0) |
---|
797 | { |
---|
798 | gboolean have_xid_arg = FALSE; |
---|
799 | gint i; |
---|
800 | for (i = 1; i < argc; ++i) |
---|
801 | if (g_strcmp0 (argv[i], xid_arg) == 0) |
---|
802 | { |
---|
803 | have_xid_arg = TRUE; |
---|
804 | break; |
---|
805 | } |
---|
806 | if (!have_xid_arg) |
---|
807 | { |
---|
808 | gchar *new_value = g_strdup_printf ("%s %s", value, xid_arg); |
---|
809 | |
---|
810 | if (g_shell_parse_argv (new_value, &argc, &argv, &error)) |
---|
811 | { |
---|
812 | g_strfreev (command->argv); |
---|
813 | command->argc = argc; |
---|
814 | command->argv = argv; |
---|
815 | have_xid_arg = TRUE; |
---|
816 | } |
---|
817 | else |
---|
818 | { |
---|
819 | if (error) |
---|
820 | g_warning ("[Command/%s] Failed to parse command line: %s", name, error->message); |
---|
821 | g_clear_error (&error); |
---|
822 | } |
---|
823 | g_free (new_value); |
---|
824 | } |
---|
825 | |
---|
826 | if (have_xid_arg) |
---|
827 | { |
---|
828 | command->widget = gtk_event_box_new (); |
---|
829 | gtk_overlay_add_overlay (screen_overlay, command->widget); |
---|
830 | } |
---|
831 | } |
---|
832 | command->name = name; |
---|
833 | return command; |
---|
834 | } |
---|
835 | |
---|
836 | static gboolean |
---|
837 | menu_command_run (MenuCommand *command) |
---|
838 | { |
---|
839 | g_return_val_if_fail (command && g_strv_length (command->argv), FALSE); |
---|
840 | |
---|
841 | GError *error = NULL; |
---|
842 | command->pid = 0; |
---|
843 | |
---|
844 | g_debug ("[Command/%s] Running command", command->name); |
---|
845 | |
---|
846 | if (command->widget) |
---|
847 | { |
---|
848 | GtkSocket* socket = NULL; |
---|
849 | gint out_fd = 0; |
---|
850 | GPid pid = spawn_argv_pid (command->argv, G_SPAWN_SEARCH_PATH, &out_fd, &error); |
---|
851 | |
---|
852 | if (pid && out_fd) |
---|
853 | { |
---|
854 | gchar* text = NULL; |
---|
855 | GIOChannel* out_channel = g_io_channel_unix_new (out_fd); |
---|
856 | if (g_io_channel_read_line (out_channel, &text, NULL, NULL, &error) == G_IO_STATUS_NORMAL) |
---|
857 | { |
---|
858 | gchar* end_ptr = NULL; |
---|
859 | |
---|
860 | text = g_strstrip (text); |
---|
861 | gint id = g_ascii_strtoll (text, &end_ptr, 0); |
---|
862 | |
---|
863 | if (id != 0 && end_ptr > text) |
---|
864 | { |
---|
865 | socket = GTK_SOCKET (gtk_socket_new ()); |
---|
866 | gtk_container_foreach (GTK_CONTAINER (command->widget), (GtkCallback)gtk_widget_destroy, NULL); |
---|
867 | gtk_container_add (GTK_CONTAINER (command->widget), GTK_WIDGET (socket)); |
---|
868 | gtk_socket_add_id (socket, id); |
---|
869 | gtk_widget_show_all (GTK_WIDGET (command->widget)); |
---|
870 | |
---|
871 | command->pid = pid; |
---|
872 | } |
---|
873 | else |
---|
874 | g_warning ("[Command/%s] Failed to get '%s' socket for: unrecognized output", |
---|
875 | command->name, command->argv[0]); |
---|
876 | |
---|
877 | g_free (text); |
---|
878 | } |
---|
879 | } |
---|
880 | |
---|
881 | if (!command->pid && pid) |
---|
882 | close_pid (pid, TRUE); |
---|
883 | } |
---|
884 | else |
---|
885 | { |
---|
886 | command->pid = spawn_argv_pid (command->argv, G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, NULL, &error); |
---|
887 | if (command->pid) |
---|
888 | g_child_watch_add (command->pid, (GChildWatchFunc)menu_command_terminated_cb, command); |
---|
889 | } |
---|
890 | |
---|
891 | if (!command->pid) |
---|
892 | { |
---|
893 | if (error) |
---|
894 | g_warning ("[Command/%s] Failed to run: %s", command->name, error->message); |
---|
895 | gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (command->menu_item), FALSE); |
---|
896 | } |
---|
897 | |
---|
898 | g_clear_error (&error); |
---|
899 | |
---|
900 | return command->pid; |
---|
901 | } |
---|
902 | |
---|
903 | static gboolean |
---|
904 | menu_command_stop (MenuCommand *command) |
---|
905 | { |
---|
906 | g_return_val_if_fail (command, FALSE); |
---|
907 | |
---|
908 | if (command->pid) |
---|
909 | { |
---|
910 | g_debug ("[Command/%s] Stopping command", command->name); |
---|
911 | close_pid (command->pid, TRUE); |
---|
912 | command->pid = 0; |
---|
913 | if (command->menu_item) |
---|
914 | gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (command->menu_item), FALSE); |
---|
915 | if (command->widget) |
---|
916 | gtk_widget_hide (command->widget); |
---|
917 | } |
---|
918 | return TRUE; |
---|
919 | } |
---|
920 | |
---|
921 | static void |
---|
922 | menu_command_terminated_cb (GPid pid, gint status, MenuCommand *command) |
---|
923 | { |
---|
924 | menu_command_stop (command); |
---|
925 | } |
---|
926 | |
---|
927 | static void |
---|
928 | a11y_menuitem_toggled_cb (GtkCheckMenuItem *item, const gchar* name) |
---|
929 | { |
---|
930 | config_set_bool (STATE_SECTION_A11Y, name, gtk_check_menu_item_get_active (item)); |
---|
931 | } |
---|
932 | |
---|
933 | /* Session */ |
---|
934 | |
---|
935 | static gboolean |
---|
936 | is_valid_session (GList* items, const gchar* session) |
---|
937 | { |
---|
938 | for (; items; items = g_list_next (items)) |
---|
939 | if (g_strcmp0 (session, lightdm_session_get_key (items->data)) == 0) |
---|
940 | return TRUE; |
---|
941 | return FALSE; |
---|
942 | } |
---|
943 | |
---|
944 | static gchar* |
---|
945 | get_session (void) |
---|
946 | { |
---|
947 | return g_strdup (current_session); |
---|
948 | } |
---|
949 | |
---|
950 | static void |
---|
951 | set_session (const gchar *session) |
---|
952 | { |
---|
953 | gchar *last_session = NULL; |
---|
954 | GList *sessions = lightdm_get_sessions (); |
---|
955 | |
---|
956 | /* Validation */ |
---|
957 | if (!session || !is_valid_session (sessions, session)) |
---|
958 | { |
---|
959 | /* previous session */ |
---|
960 | last_session = config_get_string (STATE_SECTION_GREETER, STATE_KEY_LAST_SESSION, NULL); |
---|
961 | if (last_session && g_strcmp0 (session, last_session) != 0 && |
---|
962 | is_valid_session (sessions, last_session)) |
---|
963 | session = last_session; |
---|
964 | else |
---|
965 | { |
---|
966 | /* default */ |
---|
967 | const gchar* default_session = lightdm_greeter_get_default_session_hint (greeter); |
---|
968 | if (g_strcmp0 (session, default_session) != 0 && |
---|
969 | is_valid_session (sessions, default_session)) |
---|
970 | session = default_session; |
---|
971 | /* first in the sessions list */ |
---|
972 | else if (sessions) |
---|
973 | session = lightdm_session_get_key (sessions->data); |
---|
974 | /* give up */ |
---|
975 | else |
---|
976 | session = NULL; |
---|
977 | } |
---|
978 | } |
---|
979 | |
---|
980 | if (gtk_widget_get_visible (session_menuitem)) |
---|
981 | { |
---|
982 | GList *menu_iter = NULL; |
---|
983 | GList *menu_items = gtk_container_get_children (GTK_CONTAINER (session_menu)); |
---|
984 | if (session) |
---|
985 | { |
---|
986 | for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next (menu_iter)) |
---|
987 | if (g_strcmp0 (session, g_object_get_data (G_OBJECT (menu_iter->data), SESSION_DATA_KEY)) == 0) |
---|
988 | { |
---|
989 | /* Set menuitem-image to session-badge */ |
---|
990 | GtkIconTheme *icon_theme = gtk_icon_theme_get_default (); |
---|
991 | gchar* session_name = g_ascii_strdown (session, -1); |
---|
992 | gchar* icon_name = g_strdup_printf ("%s_badge-symbolic", session_name); |
---|
993 | g_free (session_name); |
---|
994 | if (gtk_icon_theme_has_icon (icon_theme, icon_name)) |
---|
995 | gtk_image_set_from_icon_name (GTK_IMAGE (session_badge), icon_name, GTK_ICON_SIZE_MENU); |
---|
996 | else |
---|
997 | gtk_image_set_from_icon_name (GTK_IMAGE (session_badge), "document-properties-symbolic", GTK_ICON_SIZE_MENU); |
---|
998 | g_free (icon_name); |
---|
999 | break; |
---|
1000 | } |
---|
1001 | } |
---|
1002 | if (!menu_iter) |
---|
1003 | menu_iter = menu_items; |
---|
1004 | |
---|
1005 | if (menu_iter) |
---|
1006 | gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_iter->data), TRUE); |
---|
1007 | } |
---|
1008 | |
---|
1009 | g_free (current_session); |
---|
1010 | current_session = g_strdup (session); |
---|
1011 | g_free (last_session); |
---|
1012 | } |
---|
1013 | |
---|
1014 | void |
---|
1015 | session_selected_cb (GtkMenuItem *menuitem, gpointer user_data) |
---|
1016 | { |
---|
1017 | if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem))) |
---|
1018 | set_session (g_object_get_data (G_OBJECT (menuitem), SESSION_DATA_KEY)); |
---|
1019 | } |
---|
1020 | |
---|
1021 | |
---|
1022 | /* Session language */ |
---|
1023 | |
---|
1024 | static gchar* |
---|
1025 | get_language (void) |
---|
1026 | { |
---|
1027 | GList *menu_items, *menu_iter; |
---|
1028 | |
---|
1029 | /* if the user manually selected a language, use it */ |
---|
1030 | if (current_language) |
---|
1031 | return g_strdup (current_language); |
---|
1032 | |
---|
1033 | menu_items = gtk_container_get_children (GTK_CONTAINER (language_menu)); |
---|
1034 | for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next (menu_iter)) |
---|
1035 | { |
---|
1036 | if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menu_iter->data))) |
---|
1037 | return g_strdup (g_object_get_data (G_OBJECT (menu_iter->data), LANGUAGE_DATA_CODE)); |
---|
1038 | } |
---|
1039 | |
---|
1040 | return NULL; |
---|
1041 | } |
---|
1042 | |
---|
1043 | static void |
---|
1044 | set_language (const gchar *language) |
---|
1045 | { |
---|
1046 | const gchar *default_language = NULL; |
---|
1047 | GList *menu_items, *menu_iter; |
---|
1048 | |
---|
1049 | if (!gtk_widget_get_visible (language_menuitem)) |
---|
1050 | { |
---|
1051 | g_free (current_language); |
---|
1052 | current_language = g_strdup (language); |
---|
1053 | return; |
---|
1054 | } |
---|
1055 | |
---|
1056 | menu_items = gtk_container_get_children (GTK_CONTAINER (language_menu)); |
---|
1057 | |
---|
1058 | if (language) |
---|
1059 | { |
---|
1060 | for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next (menu_iter)) |
---|
1061 | { |
---|
1062 | gchar *s; |
---|
1063 | gboolean matched; |
---|
1064 | s = g_strdup (g_object_get_data (G_OBJECT (menu_iter->data), LANGUAGE_DATA_CODE)); |
---|
1065 | matched = g_strcmp0 (s, language) == 0; |
---|
1066 | g_free (s); |
---|
1067 | if (matched) |
---|
1068 | { |
---|
1069 | gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_iter->data), TRUE); |
---|
1070 | g_free (current_language); |
---|
1071 | current_language = g_strdup (language); |
---|
1072 | gtk_menu_item_set_label (GTK_MENU_ITEM (language_menuitem),language); |
---|
1073 | return; |
---|
1074 | } |
---|
1075 | } |
---|
1076 | } |
---|
1077 | |
---|
1078 | /* If failed to find this language, then try the default */ |
---|
1079 | if (lightdm_get_language ()) |
---|
1080 | { |
---|
1081 | default_language = lightdm_language_get_code (lightdm_get_language ()); |
---|
1082 | gtk_menu_item_set_label (GTK_MENU_ITEM (language_menuitem), default_language); |
---|
1083 | } |
---|
1084 | if (default_language && g_strcmp0 (default_language, language) != 0) |
---|
1085 | set_language (default_language); |
---|
1086 | /* If all else fails, just use the first language from the menu */ |
---|
1087 | else |
---|
1088 | { |
---|
1089 | for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next (menu_iter)) |
---|
1090 | { |
---|
1091 | if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menu_iter->data))) |
---|
1092 | { |
---|
1093 | gtk_menu_item_set_label (GTK_MENU_ITEM (language_menuitem), g_strdup (g_object_get_data (G_OBJECT (menu_iter->data), LANGUAGE_DATA_CODE))); |
---|
1094 | break; |
---|
1095 | } |
---|
1096 | } |
---|
1097 | } |
---|
1098 | } |
---|
1099 | |
---|
1100 | void |
---|
1101 | language_selected_cb (GtkMenuItem *menuitem, gpointer user_data) |
---|
1102 | { |
---|
1103 | if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem))) |
---|
1104 | { |
---|
1105 | gchar *language = g_object_get_data (G_OBJECT (menuitem), LANGUAGE_DATA_CODE); |
---|
1106 | set_language (language); |
---|
1107 | } |
---|
1108 | } |
---|
1109 | |
---|
1110 | /* Pending questions */ |
---|
1111 | |
---|
1112 | static void |
---|
1113 | pam_message_finalize (PAMConversationMessage *message) |
---|
1114 | { |
---|
1115 | g_free (message->text); |
---|
1116 | g_free (message); |
---|
1117 | } |
---|
1118 | |
---|
1119 | static void |
---|
1120 | process_prompts (LightDMGreeter *greeter) |
---|
1121 | { |
---|
1122 | if (!pending_questions) |
---|
1123 | return; |
---|
1124 | |
---|
1125 | /* always allow the user to change username again */ |
---|
1126 | gtk_widget_set_sensitive (GTK_WIDGET (username_entry), TRUE); |
---|
1127 | gtk_widget_set_sensitive (GTK_WIDGET (password_entry), TRUE); |
---|
1128 | |
---|
1129 | /* Special case: no user selected from list, so PAM asks us for the user |
---|
1130 | * via a prompt. For that case, use the username field */ |
---|
1131 | if (!prompted && pending_questions && !pending_questions->next && |
---|
1132 | ((PAMConversationMessage *) pending_questions->data)->is_prompt && |
---|
1133 | ((PAMConversationMessage *) pending_questions->data)->type.prompt != LIGHTDM_PROMPT_TYPE_SECRET && |
---|
1134 | gtk_widget_get_visible ((GTK_WIDGET (username_entry))) && |
---|
1135 | lightdm_greeter_get_authentication_user (greeter) == NULL) |
---|
1136 | { |
---|
1137 | prompted = TRUE; |
---|
1138 | prompt_active = TRUE; |
---|
1139 | gtk_widget_grab_focus (GTK_WIDGET (username_entry)); |
---|
1140 | gtk_widget_show (GTK_WIDGET (password_entry)); |
---|
1141 | return; |
---|
1142 | } |
---|
1143 | |
---|
1144 | while (pending_questions) |
---|
1145 | { |
---|
1146 | PAMConversationMessage *message = (PAMConversationMessage *) pending_questions->data; |
---|
1147 | pending_questions = g_slist_remove (pending_questions, (gconstpointer) message); |
---|
1148 | |
---|
1149 | if (!message->is_prompt) |
---|
1150 | { |
---|
1151 | /* FIXME: this doesn't show multiple messages, but that was |
---|
1152 | * already the case before. */ |
---|
1153 | set_message_label (message->type.message, message->text); |
---|
1154 | continue; |
---|
1155 | } |
---|
1156 | |
---|
1157 | gtk_widget_show (GTK_WIDGET (password_entry)); |
---|
1158 | gtk_widget_grab_focus (GTK_WIDGET (password_entry)); |
---|
1159 | gtk_entry_set_text (password_entry, ""); |
---|
1160 | gtk_entry_set_visibility (password_entry, message->type.prompt != LIGHTDM_PROMPT_TYPE_SECRET); |
---|
1161 | if (message_label_is_empty () && password_prompted) |
---|
1162 | { |
---|
1163 | /* No message was provided beforehand and this is not the |
---|
1164 | * first password prompt, so use the prompt as label, |
---|
1165 | * otherwise the user will be completely unclear of what |
---|
1166 | * is going on. Actually, the fact that prompt messages are |
---|
1167 | * not shown is problematic in general, especially if |
---|
1168 | * somebody uses a custom PAM module that wants to ask |
---|
1169 | * something different. */ |
---|
1170 | gchar *str = message->text; |
---|
1171 | if (g_str_has_suffix (str, ": ")) |
---|
1172 | str = g_strndup (str, strlen (str) - 2); |
---|
1173 | else if (g_str_has_suffix (str, ":")) |
---|
1174 | str = g_strndup (str, strlen (str) - 1); |
---|
1175 | set_message_label (LIGHTDM_MESSAGE_TYPE_INFO, str); |
---|
1176 | if (str != message->text) |
---|
1177 | g_free (str); |
---|
1178 | } |
---|
1179 | gtk_widget_grab_focus (GTK_WIDGET (password_entry)); |
---|
1180 | prompted = TRUE; |
---|
1181 | password_prompted = TRUE; |
---|
1182 | prompt_active = TRUE; |
---|
1183 | |
---|
1184 | /* If we have more stuff after a prompt, assume that other prompts are pending, |
---|
1185 | * so stop here. */ |
---|
1186 | break; |
---|
1187 | } |
---|
1188 | } |
---|
1189 | |
---|
1190 | /* Panel and indicators */ |
---|
1191 | |
---|
1192 | static gboolean |
---|
1193 | panel_item_enter_notify_cb (GtkWidget *widget, GdkEvent *event, gpointer enter) |
---|
1194 | { |
---|
1195 | GtkStyleContext *context = gtk_widget_get_style_context (widget); |
---|
1196 | if (GPOINTER_TO_INT (enter)) |
---|
1197 | gtk_style_context_add_class (context, PANEL_ITEM_STYLE_HOVERED); |
---|
1198 | else |
---|
1199 | gtk_style_context_remove_class (context, PANEL_ITEM_STYLE_HOVERED); |
---|
1200 | return FALSE; |
---|
1201 | } |
---|
1202 | |
---|
1203 | static void |
---|
1204 | panel_add_item (GtkWidget *widget, gint index, GreeterPanelItemType item_type) |
---|
1205 | { |
---|
1206 | gint insert_pos = 0; |
---|
1207 | GList* items = gtk_container_get_children (GTK_CONTAINER (menubar)); |
---|
1208 | GList* item; |
---|
1209 | for (item = items; item; item = item->next) |
---|
1210 | { |
---|
1211 | if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item->data), PANEL_ITEM_DATA_INDEX)) < index) |
---|
1212 | break; |
---|
1213 | insert_pos++; |
---|
1214 | } |
---|
1215 | g_list_free (items); |
---|
1216 | |
---|
1217 | gtk_style_context_add_class (gtk_widget_get_style_context (widget), PANEL_ITEM_STYLE); |
---|
1218 | gtk_style_context_add_class (gtk_widget_get_style_context (widget), PANEL_ITEM_STYLES[item_type]); |
---|
1219 | if (item_type == PANEL_ITEM_INDICATOR) |
---|
1220 | { |
---|
1221 | g_signal_connect (G_OBJECT (widget), "enter-notify-event", |
---|
1222 | G_CALLBACK (panel_item_enter_notify_cb), GINT_TO_POINTER (TRUE)); |
---|
1223 | g_signal_connect (G_OBJECT (widget), "leave-notify-event", |
---|
1224 | G_CALLBACK (panel_item_enter_notify_cb), GINT_TO_POINTER (FALSE)); |
---|
1225 | } |
---|
1226 | |
---|
1227 | gtk_widget_show (widget); |
---|
1228 | gtk_menu_shell_insert (GTK_MENU_SHELL (menubar), widget, insert_pos); |
---|
1229 | } |
---|
1230 | |
---|
1231 | #ifdef HAVE_LIBINDICATOR |
---|
1232 | static gboolean |
---|
1233 | indicator_entry_scrolled_cb (GtkWidget *menuitem, GdkEventScroll *event, gpointer data) |
---|
1234 | { |
---|
1235 | IndicatorObject *io; |
---|
1236 | IndicatorObjectEntry *entry; |
---|
1237 | |
---|
1238 | g_return_val_if_fail (GTK_IS_WIDGET (menuitem), FALSE); |
---|
1239 | |
---|
1240 | io = g_object_get_data (G_OBJECT (menuitem), INDICATOR_ITEM_DATA_OBJECT); |
---|
1241 | entry = g_object_get_data (G_OBJECT (menuitem), INDICATOR_ITEM_DATA_ENTRY); |
---|
1242 | |
---|
1243 | g_return_val_if_fail (INDICATOR_IS_OBJECT (io), FALSE); |
---|
1244 | |
---|
1245 | g_signal_emit_by_name(io, INDICATOR_OBJECT_SIGNAL_ENTRY_SCROLLED, entry, 1, event->direction); |
---|
1246 | |
---|
1247 | return FALSE; |
---|
1248 | } |
---|
1249 | |
---|
1250 | static void |
---|
1251 | indicator_entry_activated_cb (GtkWidget *widget, gpointer user_data) |
---|
1252 | { |
---|
1253 | IndicatorObject *io; |
---|
1254 | IndicatorObjectEntry *entry; |
---|
1255 | |
---|
1256 | g_return_if_fail (GTK_IS_WIDGET (widget)); |
---|
1257 | |
---|
1258 | io = g_object_get_data (G_OBJECT (widget), INDICATOR_ITEM_DATA_OBJECT); |
---|
1259 | entry = g_object_get_data (G_OBJECT (widget), INDICATOR_ITEM_DATA_ENTRY); |
---|
1260 | |
---|
1261 | g_return_if_fail (INDICATOR_IS_OBJECT (io)); |
---|
1262 | |
---|
1263 | return indicator_object_entry_activate (io, entry, gtk_get_current_event_time ()); |
---|
1264 | } |
---|
1265 | |
---|
1266 | static GtkWidget* |
---|
1267 | indicator_entry_create_menuitem (IndicatorObject *io, IndicatorObjectEntry *entry, GtkWidget *menubar) |
---|
1268 | { |
---|
1269 | GtkWidget *box, *menuitem; |
---|
1270 | gint index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (io), PANEL_ITEM_DATA_INDEX)); |
---|
1271 | box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3); |
---|
1272 | menuitem = gtk_menu_item_new (); |
---|
1273 | |
---|
1274 | gtk_widget_add_events (GTK_WIDGET (menuitem), GDK_SCROLL_MASK); |
---|
1275 | |
---|
1276 | g_object_set_data (G_OBJECT (menuitem), INDICATOR_ITEM_DATA_BOX, box); |
---|
1277 | g_object_set_data (G_OBJECT (menuitem), INDICATOR_ITEM_DATA_OBJECT, io); |
---|
1278 | g_object_set_data (G_OBJECT (menuitem), INDICATOR_ITEM_DATA_ENTRY, entry); |
---|
1279 | g_object_set_data (G_OBJECT (menuitem), PANEL_ITEM_DATA_INDEX, GINT_TO_POINTER (index)); |
---|
1280 | |
---|
1281 | g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (indicator_entry_activated_cb), NULL); |
---|
1282 | g_signal_connect (G_OBJECT (menuitem), "scroll-event", G_CALLBACK (indicator_entry_scrolled_cb), NULL); |
---|
1283 | |
---|
1284 | if (entry->image) |
---|
1285 | gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (entry->image), FALSE, FALSE, 1); |
---|
1286 | |
---|
1287 | if (entry->label) |
---|
1288 | gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (entry->label), FALSE, FALSE, 1); |
---|
1289 | |
---|
1290 | if (entry->menu) |
---|
1291 | gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), GTK_WIDGET (entry->menu)); |
---|
1292 | |
---|
1293 | gtk_container_add (GTK_CONTAINER (menuitem), box); |
---|
1294 | gtk_widget_show (box); |
---|
1295 | panel_add_item (menuitem, index, PANEL_ITEM_INDICATOR); |
---|
1296 | |
---|
1297 | return menuitem; |
---|
1298 | } |
---|
1299 | |
---|
1300 | static void |
---|
1301 | indicator_entry_added_cb (IndicatorObject *io, IndicatorObjectEntry *entry, gpointer user_data) |
---|
1302 | { |
---|
1303 | GHashTable *menuitem_lookup; |
---|
1304 | GtkWidget *menuitem; |
---|
1305 | |
---|
1306 | /* if the menuitem doesn't already exist, create it now */ |
---|
1307 | menuitem_lookup = g_object_get_data (G_OBJECT (io), INDICATOR_DATA_MENUITEMS); |
---|
1308 | g_return_if_fail (menuitem_lookup); |
---|
1309 | menuitem = g_hash_table_lookup (menuitem_lookup, entry); |
---|
1310 | if (!GTK_IS_WIDGET (menuitem)) |
---|
1311 | { |
---|
1312 | menuitem = indicator_entry_create_menuitem (io, entry, GTK_WIDGET (user_data)); |
---|
1313 | g_hash_table_insert (menuitem_lookup, entry, menuitem); |
---|
1314 | } |
---|
1315 | |
---|
1316 | gtk_widget_show (menuitem); |
---|
1317 | } |
---|
1318 | |
---|
1319 | static void |
---|
1320 | remove_indicator_entry_cb (GtkWidget *widget, gpointer userdata) |
---|
1321 | { |
---|
1322 | IndicatorObject *io; |
---|
1323 | GHashTable *menuitem_lookup; |
---|
1324 | GtkWidget *menuitem; |
---|
1325 | gpointer entry; |
---|
1326 | |
---|
1327 | io = g_object_get_data (G_OBJECT (widget), INDICATOR_ITEM_DATA_OBJECT); |
---|
1328 | if (!INDICATOR_IS_OBJECT (io)) |
---|
1329 | return; |
---|
1330 | |
---|
1331 | entry = g_object_get_data (G_OBJECT (widget), INDICATOR_ITEM_DATA_ENTRY); |
---|
1332 | if (entry != userdata) |
---|
1333 | return; |
---|
1334 | |
---|
1335 | menuitem_lookup = g_object_get_data (G_OBJECT (io), INDICATOR_DATA_MENUITEMS); |
---|
1336 | g_return_if_fail (menuitem_lookup); |
---|
1337 | menuitem = g_hash_table_lookup (menuitem_lookup, entry); |
---|
1338 | if (GTK_IS_WIDGET (menuitem)) |
---|
1339 | gtk_widget_hide (menuitem); |
---|
1340 | |
---|
1341 | gtk_widget_destroy (widget); |
---|
1342 | } |
---|
1343 | |
---|
1344 | static void |
---|
1345 | indicator_entry_removed_cb (IndicatorObject *io, IndicatorObjectEntry *entry, gpointer user_data) |
---|
1346 | { |
---|
1347 | gtk_container_foreach (GTK_CONTAINER (user_data), remove_indicator_entry_cb, entry); |
---|
1348 | } |
---|
1349 | |
---|
1350 | static void |
---|
1351 | indicator_menu_show_cb (IndicatorObject *io, IndicatorObjectEntry *entry, guint32 timestamp, gpointer user_data) |
---|
1352 | { |
---|
1353 | IndicatorObjectEntry *entrydata; |
---|
1354 | GtkWidget *menuitem; |
---|
1355 | GList *entries, *lp; |
---|
1356 | |
---|
1357 | menuitem = GTK_WIDGET (user_data); |
---|
1358 | |
---|
1359 | if (!entry) |
---|
1360 | { |
---|
1361 | /* Close any open menus instead of opening one */ |
---|
1362 | entries = indicator_object_get_entries (io); |
---|
1363 | for (lp = entries; lp; lp = g_list_next (lp)) |
---|
1364 | { |
---|
1365 | entrydata = lp->data; |
---|
1366 | gtk_menu_popdown (entrydata->menu); |
---|
1367 | } |
---|
1368 | g_list_free (entries); |
---|
1369 | |
---|
1370 | /* And tell the menuitem to exit activation mode too */ |
---|
1371 | gtk_menu_shell_cancel (GTK_MENU_SHELL (menuitem)); |
---|
1372 | } |
---|
1373 | } |
---|
1374 | |
---|
1375 | static void |
---|
1376 | greeter_set_env (const gchar* key, const gchar* value) |
---|
1377 | { |
---|
1378 | g_setenv (key, value, TRUE); |
---|
1379 | |
---|
1380 | GDBusProxy* proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, |
---|
1381 | G_DBUS_PROXY_FLAGS_NONE, |
---|
1382 | NULL, |
---|
1383 | "org.freedesktop.DBus", |
---|
1384 | "/org/freedesktop/DBus", |
---|
1385 | "org.freedesktop.DBus", |
---|
1386 | NULL, NULL); |
---|
1387 | GVariant *result; |
---|
1388 | GVariantBuilder *builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY); |
---|
1389 | g_variant_builder_add (builder, "{ss}", key, value); |
---|
1390 | result = g_dbus_proxy_call_sync (proxy, "UpdateActivationEnvironment", g_variant_new ("(a{ss})", builder), |
---|
1391 | G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL); |
---|
1392 | g_variant_unref (result); |
---|
1393 | g_variant_builder_unref (builder); |
---|
1394 | g_object_unref (proxy); |
---|
1395 | } |
---|
1396 | #endif |
---|
1397 | |
---|
1398 | static gboolean |
---|
1399 | menu_item_accel_closure_cb (GtkAccelGroup *accel_group, |
---|
1400 | GObject *acceleratable, guint keyval, |
---|
1401 | GdkModifierType modifier, gpointer data) |
---|
1402 | { |
---|
1403 | gtk_menu_item_activate (data); |
---|
1404 | return FALSE; |
---|
1405 | } |
---|
1406 | |
---|
1407 | /* Maybe unnecessary (in future) trick to enable accelerators for hidden/detached menu items */ |
---|
1408 | static void |
---|
1409 | reassign_menu_item_accel (GtkWidget *item) |
---|
1410 | { |
---|
1411 | GtkAccelKey key; |
---|
1412 | const gchar *accel_path = gtk_menu_item_get_accel_path (GTK_MENU_ITEM (item)); |
---|
1413 | |
---|
1414 | if (accel_path && gtk_accel_map_lookup_entry (accel_path, &key)) |
---|
1415 | { |
---|
1416 | GClosure *closure = g_cclosure_new (G_CALLBACK (menu_item_accel_closure_cb), item, NULL); |
---|
1417 | gtk_accel_group_connect (gtk_menu_get_accel_group (GTK_MENU (gtk_widget_get_parent (item))), |
---|
1418 | key.accel_key, key.accel_mods, key.accel_flags, closure); |
---|
1419 | g_closure_unref (closure); |
---|
1420 | } |
---|
1421 | |
---|
1422 | GtkWidget* submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (item)); |
---|
1423 | if (submenu) |
---|
1424 | gtk_container_foreach (GTK_CONTAINER (submenu), (GtkCallback)reassign_menu_item_accel, NULL); |
---|
1425 | } |
---|
1426 | |
---|
1427 | static void |
---|
1428 | init_indicators (void) |
---|
1429 | { |
---|
1430 | gsize length = 0; |
---|
1431 | guint i; |
---|
1432 | GHashTable *builtin_items = NULL; |
---|
1433 | GHashTableIter iter; |
---|
1434 | gpointer iter_value; |
---|
1435 | #ifdef HAVE_LIBINDICATOR |
---|
1436 | gboolean inited = FALSE; |
---|
1437 | #endif |
---|
1438 | |
---|
1439 | const gchar *DEFAULT_LAYOUT[] = {"~host", "~spacer", "~clock", "~spacer", |
---|
1440 | "~session", "~language", "~a11y", "~power", NULL}; |
---|
1441 | |
---|
1442 | gchar **names = config_get_string_list (NULL, CONFIG_KEY_INDICATORS, NULL); |
---|
1443 | if (!names) |
---|
1444 | names = (gchar**)DEFAULT_LAYOUT; |
---|
1445 | length = g_strv_length (names); |
---|
1446 | |
---|
1447 | builtin_items = g_hash_table_new (g_str_hash, g_str_equal); |
---|
1448 | |
---|
1449 | g_hash_table_insert (builtin_items, "~power", power_menuitem); |
---|
1450 | g_hash_table_insert (builtin_items, "~session", session_menuitem); |
---|
1451 | g_hash_table_insert (builtin_items, "~language", language_menuitem); |
---|
1452 | g_hash_table_insert (builtin_items, "~a11y", a11y_menuitem); |
---|
1453 | g_hash_table_insert (builtin_items, "~layout", layout_menuitem); |
---|
1454 | g_hash_table_insert (builtin_items, "~host", host_menuitem); |
---|
1455 | g_hash_table_insert (builtin_items, "~clock", clock_menuitem); |
---|
1456 | |
---|
1457 | g_hash_table_iter_init (&iter, builtin_items); |
---|
1458 | while (g_hash_table_iter_next (&iter, NULL, &iter_value)) |
---|
1459 | gtk_container_remove (GTK_CONTAINER (menubar), iter_value); |
---|
1460 | |
---|
1461 | for (i = 0; i < length; ++i) |
---|
1462 | { |
---|
1463 | if (names[i][0] == '~') |
---|
1464 | { /* Built-in indicators */ |
---|
1465 | GreeterPanelItemType item_type = PANEL_ITEM_INDICATOR; |
---|
1466 | if (g_hash_table_lookup_extended (builtin_items, names[i], NULL, &iter_value)) |
---|
1467 | g_hash_table_remove (builtin_items, (gconstpointer)names[i]); |
---|
1468 | else if (g_strcmp0 (names[i], "~separator") == 0) |
---|
1469 | { |
---|
1470 | GtkWidget *separator = gtk_separator_new (GTK_ORIENTATION_VERTICAL); |
---|
1471 | item_type = PANEL_ITEM_SEPARATOR; |
---|
1472 | iter_value = gtk_separator_menu_item_new (); |
---|
1473 | gtk_widget_show (separator); |
---|
1474 | gtk_container_add (iter_value, separator); |
---|
1475 | } |
---|
1476 | else if (g_strcmp0 (names[i], "~spacer") == 0) |
---|
1477 | { |
---|
1478 | item_type = PANEL_ITEM_SPACER; |
---|
1479 | iter_value = gtk_separator_menu_item_new (); |
---|
1480 | gtk_menu_item_set_label (iter_value, ""); |
---|
1481 | gtk_widget_set_hexpand (iter_value, TRUE); |
---|
1482 | } |
---|
1483 | else if (names[i][1] == '~') |
---|
1484 | { |
---|
1485 | item_type = PANEL_ITEM_TEXT; |
---|
1486 | iter_value = gtk_separator_menu_item_new (); |
---|
1487 | gtk_menu_item_set_label (iter_value, &names[i][2]); |
---|
1488 | } |
---|
1489 | else |
---|
1490 | continue; |
---|
1491 | |
---|
1492 | g_object_set_data (G_OBJECT (iter_value), PANEL_ITEM_DATA_INDEX, GINT_TO_POINTER (i)); |
---|
1493 | panel_add_item (iter_value, i, item_type); |
---|
1494 | continue; |
---|
1495 | } |
---|
1496 | |
---|
1497 | #ifdef HAVE_LIBINDICATOR |
---|
1498 | gchar* path = NULL; |
---|
1499 | IndicatorObject* io = NULL; |
---|
1500 | |
---|
1501 | if (!inited) |
---|
1502 | { |
---|
1503 | /* Set indicators to run with reduced functionality */ |
---|
1504 | greeter_set_env ("INDICATOR_GREETER_MODE", "1"); |
---|
1505 | /* Don't allow virtual file systems? */ |
---|
1506 | greeter_set_env ("GIO_USE_VFS", "local"); |
---|
1507 | greeter_set_env ("GVFS_DISABLE_FUSE", "1"); |
---|
1508 | inited = TRUE; |
---|
1509 | } |
---|
1510 | |
---|
1511 | if (g_path_is_absolute (names[i])) |
---|
1512 | { /* library with absolute path */ |
---|
1513 | io = indicator_object_new_from_file (names[i]); |
---|
1514 | } |
---|
1515 | else if (g_str_has_suffix (names[i], G_MODULE_SUFFIX)) |
---|
1516 | { /* library */ |
---|
1517 | path = g_build_filename (INDICATOR_DIR, names[i], NULL); |
---|
1518 | io = indicator_object_new_from_file (path); |
---|
1519 | } |
---|
1520 | #ifdef HAVE_LIBINDICATOR_NG |
---|
1521 | else |
---|
1522 | { /* service file */ |
---|
1523 | if (strchr (names[i], '.')) |
---|
1524 | path = g_strdup_printf ("%s/%s", UNITY_INDICATOR_DIR, names[i]); |
---|
1525 | else |
---|
1526 | path = g_strdup_printf ("%s/com.canonical.indicator.%s", UNITY_INDICATOR_DIR, names[i]); |
---|
1527 | io = INDICATOR_OBJECT (indicator_ng_new_for_profile (path, "desktop_greeter", NULL)); |
---|
1528 | } |
---|
1529 | #endif |
---|
1530 | |
---|
1531 | if (io) |
---|
1532 | { |
---|
1533 | GList *entries, *lp; |
---|
1534 | |
---|
1535 | /* used to store/fetch menu entries */ |
---|
1536 | g_object_set_data_full (G_OBJECT (io), INDICATOR_DATA_MENUITEMS, |
---|
1537 | g_hash_table_new (g_direct_hash, g_direct_equal), |
---|
1538 | (GDestroyNotify) g_hash_table_destroy); |
---|
1539 | g_object_set_data (G_OBJECT (io), PANEL_ITEM_DATA_INDEX, GINT_TO_POINTER (i)); |
---|
1540 | |
---|
1541 | g_signal_connect (G_OBJECT (io), INDICATOR_OBJECT_SIGNAL_ENTRY_ADDED, |
---|
1542 | G_CALLBACK (indicator_entry_added_cb), menubar); |
---|
1543 | g_signal_connect (G_OBJECT (io), INDICATOR_OBJECT_SIGNAL_ENTRY_REMOVED, |
---|
1544 | G_CALLBACK (indicator_entry_removed_cb), menubar); |
---|
1545 | g_signal_connect (G_OBJECT (io), INDICATOR_OBJECT_SIGNAL_MENU_SHOW, |
---|
1546 | G_CALLBACK (indicator_menu_show_cb), menubar); |
---|
1547 | |
---|
1548 | entries = indicator_object_get_entries (io); |
---|
1549 | for (lp = entries; lp; lp = g_list_next (lp)) |
---|
1550 | indicator_entry_added_cb (io, lp->data, menubar); |
---|
1551 | g_list_free (entries); |
---|
1552 | } |
---|
1553 | else |
---|
1554 | { |
---|
1555 | g_warning ("Indicator \"%s\": failed to load", names[i]); |
---|
1556 | } |
---|
1557 | |
---|
1558 | g_free (path); |
---|
1559 | #endif |
---|
1560 | } |
---|
1561 | if (names && names != (gchar**)DEFAULT_LAYOUT) |
---|
1562 | g_strfreev (names); |
---|
1563 | |
---|
1564 | if (builtin_items) |
---|
1565 | { |
---|
1566 | g_hash_table_iter_init (&iter, builtin_items); |
---|
1567 | while (g_hash_table_iter_next (&iter, NULL, &iter_value)) |
---|
1568 | { |
---|
1569 | reassign_menu_item_accel (iter_value); |
---|
1570 | gtk_widget_hide (iter_value); |
---|
1571 | } |
---|
1572 | |
---|
1573 | g_hash_table_unref (builtin_items); |
---|
1574 | } |
---|
1575 | } |
---|
1576 | |
---|
1577 | /* Layout indicator */ |
---|
1578 | |
---|
1579 | static void |
---|
1580 | layout_selected_cb (GtkCheckMenuItem *menuitem, gpointer user_data) |
---|
1581 | { |
---|
1582 | if (gtk_check_menu_item_get_active (menuitem)) |
---|
1583 | { |
---|
1584 | #ifdef HAVE_LIBXKLAVIER |
---|
1585 | gint group = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menuitem), LAYOUT_DATA_GROUP)); |
---|
1586 | xkl_engine_lock_group (xkl_engine, group); |
---|
1587 | #else |
---|
1588 | const gchar *name = g_object_get_data (G_OBJECT (menuitem), LAYOUT_DATA_NAME); |
---|
1589 | GList *item; |
---|
1590 | for (item = lightdm_get_layouts (); item; item = g_list_next (item)) |
---|
1591 | { |
---|
1592 | if (g_strcmp0 (name, lightdm_layout_get_name (item->data)) == 0) |
---|
1593 | { |
---|
1594 | lightdm_set_layout (item->data); |
---|
1595 | gtk_menu_item_set_label (GTK_MENU_ITEM (layout_menuitem), |
---|
1596 | g_object_get_data (G_OBJECT (menuitem), LAYOUT_DATA_LABEL)); |
---|
1597 | break; |
---|
1598 | } |
---|
1599 | } |
---|
1600 | #endif |
---|
1601 | } |
---|
1602 | } |
---|
1603 | |
---|
1604 | static void |
---|
1605 | update_layouts_menu (void) |
---|
1606 | { |
---|
1607 | #ifdef HAVE_LIBXKLAVIER |
---|
1608 | XklConfigRegistry *registry; |
---|
1609 | XklConfigRec *config; |
---|
1610 | XklConfigItem *config_item; |
---|
1611 | GSList *menu_group = NULL; |
---|
1612 | gint i; |
---|
1613 | |
---|
1614 | g_list_free_full (gtk_container_get_children (GTK_CONTAINER (layout_menu)), |
---|
1615 | (GDestroyNotify)gtk_widget_destroy); |
---|
1616 | |
---|
1617 | config = xkl_config_rec_new (); |
---|
1618 | if (!xkl_config_rec_get_from_server (config, xkl_engine)) |
---|
1619 | { |
---|
1620 | g_object_unref (config); |
---|
1621 | g_warning ("Failed to get Xkl configuration from server"); |
---|
1622 | return; |
---|
1623 | } |
---|
1624 | |
---|
1625 | config_item = xkl_config_item_new (); |
---|
1626 | registry = xkl_config_registry_get_instance (xkl_engine); |
---|
1627 | xkl_config_registry_load (registry, FALSE); |
---|
1628 | |
---|
1629 | for (i = 0; config->layouts[i] != NULL; ++i) |
---|
1630 | { |
---|
1631 | const gchar *layout = config->layouts[i] ? config->layouts[i] : ""; |
---|
1632 | const gchar *variant = config->variants[i] ? config->variants[i] : ""; |
---|
1633 | gchar *label = strlen (variant) > 0 ? g_strdup_printf ("%s_%s", layout, variant) : g_strdup (layout); |
---|
1634 | |
---|
1635 | GtkWidget *menuitem = gtk_radio_menu_item_new (menu_group); |
---|
1636 | menu_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (menuitem)); |
---|
1637 | |
---|
1638 | g_snprintf (config_item->name, sizeof (config_item->name), "%s", variant); |
---|
1639 | if (xkl_config_registry_find_variant (registry, layout, config_item)) |
---|
1640 | gtk_menu_item_set_label (GTK_MENU_ITEM (menuitem), config_item->description); |
---|
1641 | else |
---|
1642 | { |
---|
1643 | g_snprintf (config_item->name, sizeof (config_item->name), "%s", layout); |
---|
1644 | if (xkl_config_registry_find_layout (registry, config_item)) |
---|
1645 | gtk_menu_item_set_label (GTK_MENU_ITEM (menuitem), config_item->description); |
---|
1646 | else |
---|
1647 | gtk_menu_item_set_label (GTK_MENU_ITEM (menuitem), label); |
---|
1648 | } |
---|
1649 | |
---|
1650 | g_object_set_data_full (G_OBJECT (menuitem), LAYOUT_DATA_LABEL, label, g_free); |
---|
1651 | g_object_set_data (G_OBJECT (menuitem), LAYOUT_DATA_GROUP, GINT_TO_POINTER (i)); |
---|
1652 | |
---|
1653 | g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (layout_selected_cb), NULL); |
---|
1654 | gtk_menu_shell_append (GTK_MENU_SHELL (layout_menu), menuitem); |
---|
1655 | gtk_widget_show (GTK_WIDGET (menuitem)); |
---|
1656 | } |
---|
1657 | |
---|
1658 | g_object_unref (registry); |
---|
1659 | g_object_unref (config_item); |
---|
1660 | g_object_unref (config); |
---|
1661 | #else |
---|
1662 | GSList *menu_group = NULL; |
---|
1663 | GList *item; |
---|
1664 | |
---|
1665 | g_list_free_full (gtk_container_get_children (GTK_CONTAINER (layout_menu)), |
---|
1666 | (GDestroyNotify)gtk_widget_destroy); |
---|
1667 | |
---|
1668 | for (item = lightdm_get_layouts (); item; item = g_list_next (item)) |
---|
1669 | { |
---|
1670 | LightDMLayout *layout = item->data; |
---|
1671 | GtkWidget *menuitem = gtk_radio_menu_item_new (menu_group); |
---|
1672 | menu_group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (menuitem)); |
---|
1673 | |
---|
1674 | g_object_set_data_full (G_OBJECT (menuitem), LAYOUT_DATA_LABEL, |
---|
1675 | g_strdelimit (g_strdup (lightdm_layout_get_name (layout)), "\t ", '_'), g_free); |
---|
1676 | g_object_set_data_full (G_OBJECT (menuitem), LAYOUT_DATA_NAME, |
---|
1677 | g_strdup (lightdm_layout_get_name (layout)), g_free); |
---|
1678 | |
---|
1679 | g_signal_connect (G_OBJECT (menuitem), "activate", G_CALLBACK (layout_selected_cb), NULL); |
---|
1680 | gtk_menu_item_set_label (GTK_MENU_ITEM (menuitem), lightdm_layout_get_description (layout)); |
---|
1681 | gtk_menu_shell_append (GTK_MENU_SHELL (layout_menu), menuitem); |
---|
1682 | gtk_widget_show (GTK_WIDGET (menuitem)); |
---|
1683 | } |
---|
1684 | #endif |
---|
1685 | } |
---|
1686 | |
---|
1687 | static void |
---|
1688 | update_layouts_menu_state (void) |
---|
1689 | { |
---|
1690 | #ifdef HAVE_LIBXKLAVIER |
---|
1691 | XklState *state = xkl_engine_get_current_state (xkl_engine); |
---|
1692 | GList *menu_items = gtk_container_get_children (GTK_CONTAINER (layout_menu)); |
---|
1693 | GtkCheckMenuItem *menu_item = g_list_nth_data (menu_items, state->group); |
---|
1694 | |
---|
1695 | if (menu_item) |
---|
1696 | { |
---|
1697 | gtk_menu_item_set_label (GTK_MENU_ITEM (layout_menuitem), |
---|
1698 | g_object_get_data (G_OBJECT (menu_item), LAYOUT_DATA_LABEL)); |
---|
1699 | gtk_check_menu_item_set_active (menu_item, TRUE); |
---|
1700 | } |
---|
1701 | else |
---|
1702 | gtk_menu_item_set_label (GTK_MENU_ITEM (layout_menuitem), "??"); |
---|
1703 | g_list_free (menu_items); |
---|
1704 | #else |
---|
1705 | LightDMLayout *layout = lightdm_get_layout (); |
---|
1706 | g_return_if_fail (layout != NULL); |
---|
1707 | |
---|
1708 | const gchar *name = lightdm_layout_get_name (layout); |
---|
1709 | GList *menu_items = gtk_container_get_children (GTK_CONTAINER (layout_menu)); |
---|
1710 | GList *menu_iter; |
---|
1711 | for (menu_iter = menu_items; menu_iter; menu_iter = g_list_next (menu_iter)) |
---|
1712 | { |
---|
1713 | if (g_strcmp0 (name, g_object_get_data (G_OBJECT (menu_iter->data), LAYOUT_DATA_NAME)) == 0) |
---|
1714 | { |
---|
1715 | gtk_check_menu_item_set_active (menu_iter->data, TRUE); |
---|
1716 | gtk_menu_item_set_label (GTK_MENU_ITEM (layout_menuitem), |
---|
1717 | g_object_get_data (G_OBJECT (menu_iter->data), LAYOUT_DATA_LABEL)); |
---|
1718 | break; |
---|
1719 | } |
---|
1720 | } |
---|
1721 | g_list_free (menu_items); |
---|
1722 | #endif |
---|
1723 | } |
---|
1724 | |
---|
1725 | #ifdef HAVE_LIBXKLAVIER |
---|
1726 | static void |
---|
1727 | xkl_state_changed_cb (XklEngine *engine, XklEngineStateChange change, gint group, |
---|
1728 | gboolean restore, gpointer user_data) |
---|
1729 | { |
---|
1730 | if (change == GROUP_CHANGED) |
---|
1731 | update_layouts_menu_state (); |
---|
1732 | } |
---|
1733 | |
---|
1734 | static void |
---|
1735 | xkl_config_changed_cb (XklEngine *engine, gpointer user_data) |
---|
1736 | { |
---|
1737 | /* tip: xkl_config_rec_get_from_server() return old settings */ |
---|
1738 | update_layouts_menu (); |
---|
1739 | update_layouts_menu_state (); |
---|
1740 | } |
---|
1741 | |
---|
1742 | static GdkFilterReturn |
---|
1743 | xkl_xevent_filter (GdkXEvent *xev, GdkEvent *event, gpointer data) |
---|
1744 | { |
---|
1745 | XEvent *xevent = (XEvent *) xev; |
---|
1746 | xkl_engine_filter_events (xkl_engine, xevent); |
---|
1747 | return GDK_FILTER_CONTINUE; |
---|
1748 | } |
---|
1749 | #endif |
---|
1750 | |
---|
1751 | /* a11y indciator */ |
---|
1752 | |
---|
1753 | void |
---|
1754 | a11y_font_cb (GtkCheckMenuItem *item) |
---|
1755 | { |
---|
1756 | if (gtk_check_menu_item_get_active (item)) |
---|
1757 | { |
---|
1758 | gchar *font_name, **tokens; |
---|
1759 | guint length; |
---|
1760 | |
---|
1761 | g_object_get (gtk_settings_get_default (), "gtk-font-name", &font_name, NULL); |
---|
1762 | tokens = g_strsplit (font_name, " ", -1); |
---|
1763 | length = g_strv_length (tokens); |
---|
1764 | if (length > 1) |
---|
1765 | { |
---|
1766 | gint size = atoi (tokens[length - 1]); |
---|
1767 | if (size > 0) |
---|
1768 | { |
---|
1769 | g_free (tokens[length - 1]); |
---|
1770 | tokens[length - 1] = g_strdup_printf ("%d", size + 10); |
---|
1771 | g_free (font_name); |
---|
1772 | font_name = g_strjoinv (" ", tokens); |
---|
1773 | } |
---|
1774 | } |
---|
1775 | g_strfreev (tokens); |
---|
1776 | |
---|
1777 | g_object_set (gtk_settings_get_default (), "gtk-font-name", font_name, NULL); |
---|
1778 | } |
---|
1779 | else |
---|
1780 | { |
---|
1781 | g_object_set (gtk_settings_get_default (), "gtk-font-name", default_font_name, NULL); |
---|
1782 | } |
---|
1783 | } |
---|
1784 | |
---|
1785 | void |
---|
1786 | a11y_contrast_cb (GtkCheckMenuItem *item) |
---|
1787 | { |
---|
1788 | if (gtk_check_menu_item_get_active (item)) |
---|
1789 | { |
---|
1790 | g_object_set (gtk_settings_get_default (), "gtk-theme-name", "HighContrast", NULL); |
---|
1791 | g_object_set (gtk_settings_get_default (), "gtk-icon-theme-name", "HighContrast", NULL); |
---|
1792 | } |
---|
1793 | else |
---|
1794 | { |
---|
1795 | g_object_set (gtk_settings_get_default (), "gtk-theme-name", default_theme_name, NULL); |
---|
1796 | g_object_set (gtk_settings_get_default (), "gtk-icon-theme-name", default_icon_theme_name, NULL); |
---|
1797 | } |
---|
1798 | } |
---|
1799 | |
---|
1800 | void |
---|
1801 | a11y_keyboard_cb (GtkCheckMenuItem *item, gpointer user_data) |
---|
1802 | { |
---|
1803 | if (gtk_check_menu_item_get_active (item)) |
---|
1804 | menu_command_run (a11y_keyboard_command); |
---|
1805 | else |
---|
1806 | menu_command_stop (a11y_keyboard_command); |
---|
1807 | } |
---|
1808 | |
---|
1809 | void |
---|
1810 | a11y_reader_cb (GtkCheckMenuItem *item, gpointer user_data) |
---|
1811 | { |
---|
1812 | if (gtk_check_menu_item_get_active (item)) |
---|
1813 | menu_command_run (a11y_reader_command); |
---|
1814 | else |
---|
1815 | menu_command_stop (a11y_reader_command); |
---|
1816 | } |
---|
1817 | |
---|
1818 | /* Power indicator */ |
---|
1819 | |
---|
1820 | static void |
---|
1821 | power_menu_cb (GtkWidget *menuitem, gpointer userdata) |
---|
1822 | { |
---|
1823 | gtk_widget_set_sensitive (suspend_menuitem, lightdm_get_can_suspend ()); |
---|
1824 | gtk_widget_set_sensitive (hibernate_menuitem, lightdm_get_can_hibernate ()); |
---|
1825 | gtk_widget_set_sensitive (restart_menuitem, lightdm_get_can_restart ()); |
---|
1826 | gtk_widget_set_sensitive (shutdown_menuitem, lightdm_get_can_shutdown ()); |
---|
1827 | } |
---|
1828 | |
---|
1829 | void |
---|
1830 | suspend_cb (GtkWidget *widget, LightDMGreeter *greeter) |
---|
1831 | { |
---|
1832 | lightdm_suspend (NULL); |
---|
1833 | } |
---|
1834 | |
---|
1835 | void |
---|
1836 | hibernate_cb (GtkWidget *widget, LightDMGreeter *greeter) |
---|
1837 | { |
---|
1838 | lightdm_hibernate (NULL); |
---|
1839 | } |
---|
1840 | |
---|
1841 | void |
---|
1842 | restart_cb (GtkWidget *widget, LightDMGreeter *greeter) |
---|
1843 | { |
---|
1844 | if (show_power_prompt ("restart", "view-refresh-symbolic", |
---|
1845 | _("Restart"), |
---|
1846 | _("Are you sure you want to close all programs and restart the computer?"))) |
---|
1847 | lightdm_restart (NULL); |
---|
1848 | } |
---|
1849 | |
---|
1850 | void |
---|
1851 | shutdown_cb (GtkWidget *widget, LightDMGreeter *greeter) |
---|
1852 | { |
---|
1853 | if (show_power_prompt ("shutdown", "system-shutdown-symbolic", |
---|
1854 | _("Shut Down"), |
---|
1855 | _("Are you sure you want to close all programs and shut down the computer?"))) |
---|
1856 | lightdm_shutdown (NULL); |
---|
1857 | } |
---|
1858 | |
---|
1859 | static void |
---|
1860 | set_login_button_label (LightDMGreeter *greeter, const gchar *username) |
---|
1861 | { |
---|
1862 | LightDMUser *user; |
---|
1863 | gboolean logged_in = FALSE; |
---|
1864 | |
---|
1865 | user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username); |
---|
1866 | if (user) |
---|
1867 | logged_in = lightdm_user_get_logged_in (user); |
---|
1868 | if (logged_in) |
---|
1869 | gtk_button_set_label (login_button, _("Unlock")); |
---|
1870 | else |
---|
1871 | gtk_button_set_label (login_button, _("Log In")); |
---|
1872 | /* and disable the session and language widgets */ |
---|
1873 | gtk_widget_set_sensitive (GTK_WIDGET (session_menuitem), !logged_in); |
---|
1874 | gtk_widget_set_sensitive (GTK_WIDGET (language_menuitem), !logged_in); |
---|
1875 | } |
---|
1876 | |
---|
1877 | static guint set_user_background_delayed_id = 0; |
---|
1878 | |
---|
1879 | static gboolean |
---|
1880 | set_user_background_delayed_cb (const gchar *value) |
---|
1881 | { |
---|
1882 | greeter_background_set_custom_background (greeter_background, value); |
---|
1883 | set_user_background_delayed_id = 0; |
---|
1884 | return G_SOURCE_REMOVE; |
---|
1885 | } |
---|
1886 | |
---|
1887 | static void |
---|
1888 | set_user_background (const gchar *user_name) |
---|
1889 | { |
---|
1890 | const gchar *value = NULL; |
---|
1891 | if (user_name) |
---|
1892 | { |
---|
1893 | LightDMUser *user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), user_name); |
---|
1894 | if (user) |
---|
1895 | value = lightdm_user_get_background (user); |
---|
1896 | } |
---|
1897 | |
---|
1898 | if (set_user_background_delayed_id) |
---|
1899 | { |
---|
1900 | g_source_remove (set_user_background_delayed_id); |
---|
1901 | set_user_background_delayed_id = 0; |
---|
1902 | } |
---|
1903 | |
---|
1904 | if (!value) |
---|
1905 | greeter_background_set_custom_background (greeter_background, NULL); |
---|
1906 | else |
---|
1907 | { |
---|
1908 | /* Small delay before changing background */ |
---|
1909 | set_user_background_delayed_id = g_timeout_add_full (G_PRIORITY_DEFAULT, USER_BACKGROUND_DELAY, |
---|
1910 | (GSourceFunc)set_user_background_delayed_cb, |
---|
1911 | g_strdup (value), g_free); |
---|
1912 | } |
---|
1913 | } |
---|
1914 | |
---|
1915 | static void |
---|
1916 | start_authentication (const gchar *username) |
---|
1917 | { |
---|
1918 | cancelling = FALSE; |
---|
1919 | prompted = FALSE; |
---|
1920 | password_prompted = FALSE; |
---|
1921 | prompt_active = FALSE; |
---|
1922 | |
---|
1923 | if (pending_questions) |
---|
1924 | { |
---|
1925 | g_slist_free_full (pending_questions, (GDestroyNotify) pam_message_finalize); |
---|
1926 | pending_questions = NULL; |
---|
1927 | } |
---|
1928 | |
---|
1929 | config_set_string (STATE_SECTION_GREETER, STATE_KEY_LAST_USER, username); |
---|
1930 | |
---|
1931 | if (g_strcmp0 (username, "*other") == 0) |
---|
1932 | { |
---|
1933 | gtk_widget_show (GTK_WIDGET (username_entry)); |
---|
1934 | gtk_widget_show (GTK_WIDGET (cancel_button)); |
---|
1935 | lightdm_greeter_authenticate (greeter, NULL); |
---|
1936 | } |
---|
1937 | else if (g_strcmp0 (username, "*guest") == 0) |
---|
1938 | { |
---|
1939 | lightdm_greeter_authenticate_as_guest (greeter); |
---|
1940 | } |
---|
1941 | else |
---|
1942 | { |
---|
1943 | LightDMUser *user; |
---|
1944 | |
---|
1945 | user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username); |
---|
1946 | if (user) |
---|
1947 | { |
---|
1948 | if (!current_session) |
---|
1949 | set_session (lightdm_user_get_session (user)); |
---|
1950 | if (!current_language) |
---|
1951 | set_language (lightdm_user_get_language (user)); |
---|
1952 | } |
---|
1953 | else |
---|
1954 | { |
---|
1955 | set_session (NULL); |
---|
1956 | set_language (NULL); |
---|
1957 | } |
---|
1958 | |
---|
1959 | lightdm_greeter_authenticate (greeter, username); |
---|
1960 | } |
---|
1961 | } |
---|
1962 | |
---|
1963 | static void |
---|
1964 | cancel_authentication (void) |
---|
1965 | { |
---|
1966 | GtkTreeModel *model; |
---|
1967 | GtkTreeIter iter; |
---|
1968 | gboolean other = FALSE; |
---|
1969 | |
---|
1970 | if (pending_questions) |
---|
1971 | { |
---|
1972 | g_slist_free_full (pending_questions, (GDestroyNotify) pam_message_finalize); |
---|
1973 | pending_questions = NULL; |
---|
1974 | } |
---|
1975 | |
---|
1976 | /* If in authentication then stop that first */ |
---|
1977 | cancelling = FALSE; |
---|
1978 | if (lightdm_greeter_get_in_authentication (greeter)) |
---|
1979 | { |
---|
1980 | cancelling = TRUE; |
---|
1981 | lightdm_greeter_cancel_authentication (greeter); |
---|
1982 | set_message_label (LIGHTDM_MESSAGE_TYPE_INFO, NULL); |
---|
1983 | } |
---|
1984 | |
---|
1985 | /* Make sure password entry is back to normal */ |
---|
1986 | gtk_entry_set_visibility (password_entry, FALSE); |
---|
1987 | |
---|
1988 | /* Force refreshing the prompt_box for "Other" */ |
---|
1989 | model = gtk_combo_box_get_model (user_combo); |
---|
1990 | |
---|
1991 | if (gtk_combo_box_get_active_iter (user_combo, &iter)) |
---|
1992 | { |
---|
1993 | gchar *user; |
---|
1994 | |
---|
1995 | gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 0, &user, -1); |
---|
1996 | other = (g_strcmp0 (user, "*other") == 0); |
---|
1997 | g_free (user); |
---|
1998 | } |
---|
1999 | |
---|
2000 | /* Start a new login or return to the user list */ |
---|
2001 | if (other || lightdm_greeter_get_hide_users_hint (greeter)) |
---|
2002 | start_authentication ("*other"); |
---|
2003 | else |
---|
2004 | gtk_widget_grab_focus (GTK_WIDGET (user_combo)); |
---|
2005 | } |
---|
2006 | |
---|
2007 | static void |
---|
2008 | start_session (void) |
---|
2009 | { |
---|
2010 | gchar *language; |
---|
2011 | gchar *session; |
---|
2012 | |
---|
2013 | language = get_language (); |
---|
2014 | if (language) |
---|
2015 | lightdm_greeter_set_language (greeter, language); |
---|
2016 | g_free (language); |
---|
2017 | |
---|
2018 | session = get_session (); |
---|
2019 | |
---|
2020 | /* Remember last choice */ |
---|
2021 | config_set_string (STATE_SECTION_GREETER, STATE_KEY_LAST_SESSION, session); |
---|
2022 | |
---|
2023 | greeter_background_save_xroot (greeter_background); |
---|
2024 | |
---|
2025 | if (!lightdm_greeter_start_session_sync (greeter, session, NULL)) |
---|
2026 | { |
---|
2027 | set_message_label (LIGHTDM_MESSAGE_TYPE_ERROR, _("Failed to start session")); |
---|
2028 | start_authentication (lightdm_greeter_get_authentication_user (greeter)); |
---|
2029 | } |
---|
2030 | g_free (session); |
---|
2031 | } |
---|
2032 | |
---|
2033 | gboolean |
---|
2034 | password_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data); |
---|
2035 | G_MODULE_EXPORT |
---|
2036 | gboolean |
---|
2037 | password_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data) |
---|
2038 | { |
---|
2039 | if ((event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_Down) && |
---|
2040 | gtk_widget_get_visible (GTK_WIDGET (user_combo))) |
---|
2041 | { |
---|
2042 | gboolean available; |
---|
2043 | GtkTreeIter iter; |
---|
2044 | GtkTreeModel *model = gtk_combo_box_get_model (user_combo); |
---|
2045 | |
---|
2046 | /* Back to username_entry if it is available */ |
---|
2047 | if (event->keyval == GDK_KEY_Up && |
---|
2048 | gtk_widget_get_visible (GTK_WIDGET (username_entry)) && widget == GTK_WIDGET (password_entry)) |
---|
2049 | { |
---|
2050 | gtk_widget_grab_focus (GTK_WIDGET (username_entry)); |
---|
2051 | return TRUE; |
---|
2052 | } |
---|
2053 | |
---|
2054 | if (!gtk_combo_box_get_active_iter (user_combo, &iter)) |
---|
2055 | return FALSE; |
---|
2056 | |
---|
2057 | if (event->keyval == GDK_KEY_Up) |
---|
2058 | available = gtk_tree_model_iter_previous (model, &iter); |
---|
2059 | else |
---|
2060 | available = gtk_tree_model_iter_next (model, &iter); |
---|
2061 | |
---|
2062 | if (available) |
---|
2063 | gtk_combo_box_set_active_iter (user_combo, &iter); |
---|
2064 | |
---|
2065 | return TRUE; |
---|
2066 | } |
---|
2067 | return FALSE; |
---|
2068 | } |
---|
2069 | |
---|
2070 | gboolean |
---|
2071 | username_focus_out_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data); |
---|
2072 | G_MODULE_EXPORT |
---|
2073 | gboolean |
---|
2074 | username_focus_out_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data) |
---|
2075 | { |
---|
2076 | if (!g_strcmp0(gtk_entry_get_text (username_entry), "") == 0) |
---|
2077 | start_authentication (gtk_entry_get_text (username_entry)); |
---|
2078 | return FALSE; |
---|
2079 | } |
---|
2080 | |
---|
2081 | gboolean |
---|
2082 | username_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data); |
---|
2083 | G_MODULE_EXPORT |
---|
2084 | gboolean |
---|
2085 | username_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data) |
---|
2086 | { |
---|
2087 | /* Acts as password_entry */ |
---|
2088 | if (event->keyval == GDK_KEY_Up) |
---|
2089 | return password_key_press_cb (widget, event, user_data); |
---|
2090 | /* Enter activates the password entry */ |
---|
2091 | else if (event->keyval == GDK_KEY_Return && gtk_widget_get_visible (GTK_WIDGET (password_entry))) |
---|
2092 | { |
---|
2093 | gtk_widget_grab_focus (GTK_WIDGET (password_entry)); |
---|
2094 | return TRUE; |
---|
2095 | } |
---|
2096 | else |
---|
2097 | return FALSE; |
---|
2098 | } |
---|
2099 | |
---|
2100 | gboolean |
---|
2101 | menubar_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data); |
---|
2102 | G_MODULE_EXPORT |
---|
2103 | gboolean |
---|
2104 | menubar_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data) |
---|
2105 | { |
---|
2106 | switch (event->keyval) |
---|
2107 | { |
---|
2108 | case GDK_KEY_Tab: case GDK_KEY_Escape: |
---|
2109 | case GDK_KEY_Super_L: case GDK_KEY_Super_R: |
---|
2110 | case GDK_KEY_F9: case GDK_KEY_F10: |
---|
2111 | case GDK_KEY_F11: case GDK_KEY_F12: |
---|
2112 | gtk_menu_shell_cancel (GTK_MENU_SHELL (menubar)); |
---|
2113 | return TRUE; |
---|
2114 | default: |
---|
2115 | return FALSE; |
---|
2116 | }; |
---|
2117 | } |
---|
2118 | |
---|
2119 | gboolean |
---|
2120 | login_window_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data); |
---|
2121 | G_MODULE_EXPORT |
---|
2122 | gboolean |
---|
2123 | login_window_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data) |
---|
2124 | { |
---|
2125 | GtkWidget *item = NULL; |
---|
2126 | |
---|
2127 | if (event->keyval == GDK_KEY_F9) |
---|
2128 | item = session_menuitem; |
---|
2129 | else if (event->keyval == GDK_KEY_F10) |
---|
2130 | item = language_menuitem; |
---|
2131 | else if (event->keyval == GDK_KEY_F11) |
---|
2132 | item = a11y_menuitem; |
---|
2133 | else if (event->keyval == GDK_KEY_F12) |
---|
2134 | item = power_menuitem; |
---|
2135 | else if (event->keyval != GDK_KEY_Escape && |
---|
2136 | event->keyval != GDK_KEY_Super_L && |
---|
2137 | event->keyval != GDK_KEY_Super_R) |
---|
2138 | return FALSE; |
---|
2139 | |
---|
2140 | if (GTK_IS_MENU_ITEM (item) && gtk_widget_is_sensitive (item) && gtk_widget_get_visible (item)) |
---|
2141 | gtk_menu_shell_select_item (GTK_MENU_SHELL (menubar), item); |
---|
2142 | else |
---|
2143 | gtk_menu_shell_select_first (GTK_MENU_SHELL (menubar), TRUE); |
---|
2144 | return TRUE; |
---|
2145 | } |
---|
2146 | |
---|
2147 | static void |
---|
2148 | set_displayed_user (LightDMGreeter *greeter, const gchar *username) |
---|
2149 | { |
---|
2150 | gchar *user_tooltip; |
---|
2151 | LightDMUser *user; |
---|
2152 | |
---|
2153 | if (g_strcmp0 (username, "*other") == 0) |
---|
2154 | { |
---|
2155 | gtk_widget_show (GTK_WIDGET (username_entry)); |
---|
2156 | gtk_widget_show (GTK_WIDGET (cancel_button)); |
---|
2157 | user_tooltip = g_strdup (_("Other")); |
---|
2158 | } |
---|
2159 | else |
---|
2160 | { |
---|
2161 | gtk_widget_hide (GTK_WIDGET (username_entry)); |
---|
2162 | gtk_widget_hide (GTK_WIDGET (cancel_button)); |
---|
2163 | user_tooltip = g_strdup (username); |
---|
2164 | } |
---|
2165 | |
---|
2166 | /* At this moment we do not have information about possible prompts |
---|
2167 | * for current user (except *guest). So, password_entry.visible changed in: |
---|
2168 | * auth_complete_cb |
---|
2169 | * process_prompts |
---|
2170 | * and here - for *guest */ |
---|
2171 | |
---|
2172 | if (g_strcmp0 (username, "*guest") == 0) |
---|
2173 | { |
---|
2174 | user_tooltip = g_strdup (_("Guest Session")); |
---|
2175 | gtk_widget_hide (GTK_WIDGET (password_entry)); |
---|
2176 | gtk_widget_grab_focus (GTK_WIDGET (user_combo)); |
---|
2177 | } |
---|
2178 | |
---|
2179 | set_login_button_label (greeter, username); |
---|
2180 | set_user_background (username); |
---|
2181 | set_user_image (username); |
---|
2182 | user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username); |
---|
2183 | if (user) |
---|
2184 | { |
---|
2185 | set_language (lightdm_user_get_language (user)); |
---|
2186 | set_session (lightdm_user_get_session (user)); |
---|
2187 | } |
---|
2188 | else |
---|
2189 | set_language (lightdm_language_get_code (lightdm_get_language ())); |
---|
2190 | gtk_widget_set_tooltip_text (GTK_WIDGET (user_combo), user_tooltip); |
---|
2191 | start_authentication (username); |
---|
2192 | g_free (user_tooltip); |
---|
2193 | } |
---|
2194 | |
---|
2195 | void user_combobox_active_changed_cb (GtkComboBox *widget, LightDMGreeter *greeter); |
---|
2196 | G_MODULE_EXPORT |
---|
2197 | void |
---|
2198 | user_combobox_active_changed_cb (GtkComboBox *widget, LightDMGreeter *greeter) |
---|
2199 | { |
---|
2200 | GtkTreeModel *model; |
---|
2201 | GtkTreeIter iter; |
---|
2202 | |
---|
2203 | model = gtk_combo_box_get_model (user_combo); |
---|
2204 | |
---|
2205 | if (gtk_combo_box_get_active_iter (user_combo, &iter)) |
---|
2206 | { |
---|
2207 | gchar *user; |
---|
2208 | |
---|
2209 | gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 0, &user, -1); |
---|
2210 | |
---|
2211 | set_displayed_user (greeter, user); |
---|
2212 | |
---|
2213 | g_free (user); |
---|
2214 | } |
---|
2215 | set_message_label (LIGHTDM_MESSAGE_TYPE_INFO, NULL); |
---|
2216 | } |
---|
2217 | |
---|
2218 | void login_cb (GtkWidget *widget); |
---|
2219 | G_MODULE_EXPORT |
---|
2220 | void |
---|
2221 | login_cb (GtkWidget *widget) |
---|
2222 | { |
---|
2223 | /* Reset to default screensaver values */ |
---|
2224 | if (lightdm_greeter_get_lock_hint (greeter)) |
---|
2225 | XSetScreenSaver (gdk_x11_display_get_xdisplay (gdk_display_get_default ()), timeout, interval, prefer_blanking, allow_exposures); |
---|
2226 | |
---|
2227 | gtk_widget_set_sensitive (GTK_WIDGET (username_entry), FALSE); |
---|
2228 | gtk_widget_set_sensitive (GTK_WIDGET (password_entry), FALSE); |
---|
2229 | set_message_label (LIGHTDM_MESSAGE_TYPE_INFO, NULL); |
---|
2230 | prompt_active = FALSE; |
---|
2231 | |
---|
2232 | if (lightdm_greeter_get_is_authenticated (greeter)) |
---|
2233 | start_session (); |
---|
2234 | else if (lightdm_greeter_get_in_authentication (greeter)) |
---|
2235 | { |
---|
2236 | lightdm_greeter_respond (greeter, gtk_entry_get_text (password_entry)); |
---|
2237 | /* If we have questions pending, then we continue processing |
---|
2238 | * those, until we are done. (Otherwise, authentication will |
---|
2239 | * not complete.) */ |
---|
2240 | if (pending_questions) |
---|
2241 | process_prompts (greeter); |
---|
2242 | } |
---|
2243 | else |
---|
2244 | start_authentication (lightdm_greeter_get_authentication_user (greeter)); |
---|
2245 | } |
---|
2246 | |
---|
2247 | void cancel_cb (GtkWidget *widget); |
---|
2248 | G_MODULE_EXPORT |
---|
2249 | void |
---|
2250 | cancel_cb (GtkWidget *widget) |
---|
2251 | { |
---|
2252 | cancel_authentication (); |
---|
2253 | } |
---|
2254 | |
---|
2255 | gboolean |
---|
2256 | user_combo_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data); |
---|
2257 | G_MODULE_EXPORT |
---|
2258 | gboolean |
---|
2259 | user_combo_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data) |
---|
2260 | { |
---|
2261 | if (event->keyval == GDK_KEY_Return) |
---|
2262 | { |
---|
2263 | if (gtk_widget_get_visible (GTK_WIDGET (username_entry))) |
---|
2264 | gtk_widget_grab_focus (GTK_WIDGET (username_entry)); |
---|
2265 | else if (gtk_widget_get_visible (GTK_WIDGET (password_entry))) |
---|
2266 | gtk_widget_grab_focus (GTK_WIDGET (password_entry)); |
---|
2267 | else |
---|
2268 | login_cb (GTK_WIDGET (login_button)); |
---|
2269 | return TRUE; |
---|
2270 | } |
---|
2271 | return FALSE; |
---|
2272 | } |
---|
2273 | |
---|
2274 | static void |
---|
2275 | show_prompt_cb (LightDMGreeter *greeter, const gchar *text, LightDMPromptType type) |
---|
2276 | { |
---|
2277 | PAMConversationMessage *message_obj = g_new (PAMConversationMessage, 1); |
---|
2278 | if (message_obj) |
---|
2279 | { |
---|
2280 | message_obj->is_prompt = TRUE; |
---|
2281 | message_obj->type.prompt = type; |
---|
2282 | message_obj->text = g_strdup (text); |
---|
2283 | pending_questions = g_slist_append (pending_questions, message_obj); |
---|
2284 | } |
---|
2285 | |
---|
2286 | if (!prompt_active) |
---|
2287 | process_prompts (greeter); |
---|
2288 | } |
---|
2289 | |
---|
2290 | static void |
---|
2291 | show_message_cb (LightDMGreeter *greeter, const gchar *text, LightDMMessageType type) |
---|
2292 | { |
---|
2293 | PAMConversationMessage *message_obj = g_new (PAMConversationMessage, 1); |
---|
2294 | if (message_obj) |
---|
2295 | { |
---|
2296 | message_obj->is_prompt = FALSE; |
---|
2297 | message_obj->type.message = type; |
---|
2298 | message_obj->text = g_strdup (text); |
---|
2299 | pending_questions = g_slist_append (pending_questions, message_obj); |
---|
2300 | } |
---|
2301 | |
---|
2302 | if (!prompt_active) |
---|
2303 | process_prompts (greeter); |
---|
2304 | } |
---|
2305 | |
---|
2306 | static void |
---|
2307 | timed_autologin_cb (LightDMGreeter *greeter) |
---|
2308 | { |
---|
2309 | /* Don't trigger autologin if user locks screen with light-locker (thanks to Andrew P.). */ |
---|
2310 | if (!lightdm_greeter_get_lock_hint (greeter)) |
---|
2311 | { |
---|
2312 | if (lightdm_greeter_get_is_authenticated (greeter)) |
---|
2313 | { |
---|
2314 | /* Configured autologin user may be already selected in user list. */ |
---|
2315 | if (lightdm_greeter_get_authentication_user (greeter)) |
---|
2316 | /* Selected user matches configured autologin-user option. */ |
---|
2317 | start_session (); |
---|
2318 | else if (lightdm_greeter_get_autologin_guest_hint (greeter)) |
---|
2319 | /* "Guest session" is selected and autologin-guest is enabled. */ |
---|
2320 | start_session (); |
---|
2321 | else if (lightdm_greeter_get_autologin_user_hint (greeter)) |
---|
2322 | { |
---|
2323 | /* "Guest session" is selected, but autologin-user is configured. */ |
---|
2324 | start_authentication (lightdm_greeter_get_autologin_user_hint (greeter)); |
---|
2325 | prompted = TRUE; |
---|
2326 | } |
---|
2327 | } |
---|
2328 | else |
---|
2329 | lightdm_greeter_authenticate_autologin (greeter); |
---|
2330 | } |
---|
2331 | } |
---|
2332 | |
---|
2333 | static void |
---|
2334 | authentication_complete_cb (LightDMGreeter *greeter) |
---|
2335 | { |
---|
2336 | prompt_active = FALSE; |
---|
2337 | gtk_entry_set_text (password_entry, ""); |
---|
2338 | |
---|
2339 | if (cancelling) |
---|
2340 | { |
---|
2341 | cancel_authentication (); |
---|
2342 | return; |
---|
2343 | } |
---|
2344 | |
---|
2345 | if (pending_questions) |
---|
2346 | { |
---|
2347 | g_slist_free_full (pending_questions, (GDestroyNotify) pam_message_finalize); |
---|
2348 | pending_questions = NULL; |
---|
2349 | } |
---|
2350 | |
---|
2351 | if (lightdm_greeter_get_is_authenticated (greeter)) |
---|
2352 | { |
---|
2353 | if (prompted) |
---|
2354 | start_session (); |
---|
2355 | else |
---|
2356 | { |
---|
2357 | gtk_widget_hide (GTK_WIDGET (password_entry)); |
---|
2358 | gtk_widget_grab_focus (GTK_WIDGET (user_combo)); |
---|
2359 | } |
---|
2360 | } |
---|
2361 | else |
---|
2362 | { |
---|
2363 | /* If an error message is already printed we do not print it this statement |
---|
2364 | * The error message probably comes from the PAM module that has a better knowledge |
---|
2365 | * of the failure. */ |
---|
2366 | gboolean have_pam_error = !message_label_is_empty () && |
---|
2367 | gtk_info_bar_get_message_type (info_bar) != GTK_MESSAGE_ERROR; |
---|
2368 | if (prompted) |
---|
2369 | { |
---|
2370 | if (!have_pam_error) |
---|
2371 | set_message_label (LIGHTDM_MESSAGE_TYPE_ERROR, _("Incorrect password, please try again")); |
---|
2372 | start_authentication (lightdm_greeter_get_authentication_user (greeter)); |
---|
2373 | } |
---|
2374 | else |
---|
2375 | { |
---|
2376 | g_warning ("Failed to authenticate"); |
---|
2377 | if (!have_pam_error) |
---|
2378 | set_message_label (LIGHTDM_MESSAGE_TYPE_ERROR, _("Failed to authenticate")); |
---|
2379 | } |
---|
2380 | } |
---|
2381 | } |
---|
2382 | |
---|
2383 | static void |
---|
2384 | user_added_cb (LightDMUserList *user_list, LightDMUser *user, LightDMGreeter *greeter) |
---|
2385 | { |
---|
2386 | GtkTreeModel *model; |
---|
2387 | GtkTreeIter iter; |
---|
2388 | gboolean logged_in = FALSE; |
---|
2389 | |
---|
2390 | model = gtk_combo_box_get_model (user_combo); |
---|
2391 | |
---|
2392 | logged_in = lightdm_user_get_logged_in (user); |
---|
2393 | |
---|
2394 | gtk_list_store_append (GTK_LIST_STORE (model), &iter); |
---|
2395 | gtk_list_store_set (GTK_LIST_STORE (model), &iter, |
---|
2396 | 0, lightdm_user_get_name (user), |
---|
2397 | 1, lightdm_user_get_display_name (user), |
---|
2398 | 2, logged_in ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, |
---|
2399 | -1); |
---|
2400 | } |
---|
2401 | |
---|
2402 | static gboolean |
---|
2403 | get_user_iter (const gchar *username, GtkTreeIter *iter) |
---|
2404 | { |
---|
2405 | GtkTreeModel *model; |
---|
2406 | |
---|
2407 | model = gtk_combo_box_get_model (user_combo); |
---|
2408 | |
---|
2409 | if (!gtk_tree_model_get_iter_first (model, iter)) |
---|
2410 | return FALSE; |
---|
2411 | do |
---|
2412 | { |
---|
2413 | gchar *name; |
---|
2414 | gboolean matched; |
---|
2415 | |
---|
2416 | gtk_tree_model_get (model, iter, 0, &name, -1); |
---|
2417 | matched = g_strcmp0 (name, username) == 0; |
---|
2418 | g_free (name); |
---|
2419 | if (matched) |
---|
2420 | return TRUE; |
---|
2421 | } while (gtk_tree_model_iter_next (model, iter)); |
---|
2422 | |
---|
2423 | return FALSE; |
---|
2424 | } |
---|
2425 | |
---|
2426 | static void |
---|
2427 | user_changed_cb (LightDMUserList *user_list, LightDMUser *user, LightDMGreeter *greeter) |
---|
2428 | { |
---|
2429 | GtkTreeModel *model; |
---|
2430 | GtkTreeIter iter; |
---|
2431 | gboolean logged_in = FALSE; |
---|
2432 | |
---|
2433 | if (!get_user_iter (lightdm_user_get_name (user), &iter)) |
---|
2434 | return; |
---|
2435 | logged_in = lightdm_user_get_logged_in (user); |
---|
2436 | |
---|
2437 | model = gtk_combo_box_get_model (user_combo); |
---|
2438 | |
---|
2439 | gtk_list_store_set (GTK_LIST_STORE (model), &iter, |
---|
2440 | 0, lightdm_user_get_name (user), |
---|
2441 | 1, lightdm_user_get_display_name (user), |
---|
2442 | 2, logged_in ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, |
---|
2443 | -1); |
---|
2444 | } |
---|
2445 | |
---|
2446 | static void |
---|
2447 | user_removed_cb (LightDMUserList *user_list, LightDMUser *user) |
---|
2448 | { |
---|
2449 | GtkTreeModel *model; |
---|
2450 | GtkTreeIter iter; |
---|
2451 | |
---|
2452 | if (!get_user_iter (lightdm_user_get_name (user), &iter)) |
---|
2453 | return; |
---|
2454 | |
---|
2455 | model = gtk_combo_box_get_model (user_combo); |
---|
2456 | gtk_list_store_remove (GTK_LIST_STORE (model), &iter); |
---|
2457 | } |
---|
2458 | |
---|
2459 | static void |
---|
2460 | load_user_list (void) |
---|
2461 | { |
---|
2462 | const GList *items, *item; |
---|
2463 | GtkTreeModel *model; |
---|
2464 | GtkTreeIter iter; |
---|
2465 | const gchar *selected_user; |
---|
2466 | gboolean logged_in = FALSE; |
---|
2467 | |
---|
2468 | g_signal_connect (lightdm_user_list_get_instance (), "user-added", G_CALLBACK (user_added_cb), greeter); |
---|
2469 | g_signal_connect (lightdm_user_list_get_instance (), "user-changed", G_CALLBACK (user_changed_cb), greeter); |
---|
2470 | g_signal_connect (lightdm_user_list_get_instance (), "user-removed", G_CALLBACK (user_removed_cb), NULL); |
---|
2471 | model = gtk_combo_box_get_model (user_combo); |
---|
2472 | items = lightdm_user_list_get_users (lightdm_user_list_get_instance ()); |
---|
2473 | for (item = items; item; item = item->next) |
---|
2474 | { |
---|
2475 | LightDMUser *user = item->data; |
---|
2476 | logged_in = lightdm_user_get_logged_in (user); |
---|
2477 | |
---|
2478 | gtk_list_store_append (GTK_LIST_STORE (model), &iter); |
---|
2479 | gtk_list_store_set (GTK_LIST_STORE (model), &iter, |
---|
2480 | 0, lightdm_user_get_name (user), |
---|
2481 | 1, lightdm_user_get_display_name (user), |
---|
2482 | 2, logged_in ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL, |
---|
2483 | -1); |
---|
2484 | } |
---|
2485 | if (lightdm_greeter_get_has_guest_account_hint (greeter)) |
---|
2486 | { |
---|
2487 | gtk_list_store_append (GTK_LIST_STORE (model), &iter); |
---|
2488 | gtk_list_store_set (GTK_LIST_STORE (model), &iter, |
---|
2489 | 0, "*guest", |
---|
2490 | 1, _("Guest Session"), |
---|
2491 | 2, PANGO_WEIGHT_NORMAL, |
---|
2492 | -1); |
---|
2493 | } |
---|
2494 | |
---|
2495 | gtk_list_store_append (GTK_LIST_STORE (model), &iter); |
---|
2496 | gtk_list_store_set (GTK_LIST_STORE (model), &iter, |
---|
2497 | 0, "*other", |
---|
2498 | 1, _("Other..."), |
---|
2499 | 2, PANGO_WEIGHT_NORMAL, |
---|
2500 | -1); |
---|
2501 | |
---|
2502 | gchar *last_user = config_get_string (STATE_SECTION_GREETER, STATE_KEY_LAST_USER, NULL); |
---|
2503 | |
---|
2504 | if (lightdm_greeter_get_select_user_hint (greeter)) |
---|
2505 | selected_user = lightdm_greeter_get_select_user_hint (greeter); |
---|
2506 | else if (lightdm_greeter_get_select_guest_hint (greeter)) |
---|
2507 | selected_user = "*guest"; |
---|
2508 | else if (last_user) |
---|
2509 | selected_user = last_user; |
---|
2510 | else |
---|
2511 | selected_user = NULL; |
---|
2512 | |
---|
2513 | if (gtk_tree_model_get_iter_first (model, &iter)) |
---|
2514 | { |
---|
2515 | gchar *name; |
---|
2516 | gboolean matched = FALSE; |
---|
2517 | |
---|
2518 | if (selected_user) |
---|
2519 | { |
---|
2520 | do |
---|
2521 | { |
---|
2522 | gtk_tree_model_get (model, &iter, 0, &name, -1); |
---|
2523 | matched = g_strcmp0 (name, selected_user) == 0; |
---|
2524 | g_free (name); |
---|
2525 | if (matched) |
---|
2526 | { |
---|
2527 | gtk_combo_box_set_active_iter (user_combo, &iter); |
---|
2528 | set_displayed_user (greeter, selected_user); |
---|
2529 | break; |
---|
2530 | } |
---|
2531 | } while (gtk_tree_model_iter_next (model, &iter)); |
---|
2532 | } |
---|
2533 | if (!matched) |
---|
2534 | { |
---|
2535 | gtk_tree_model_get_iter_first (model, &iter); |
---|
2536 | gtk_tree_model_get (model, &iter, 0, &name, -1); |
---|
2537 | gtk_combo_box_set_active_iter (user_combo, &iter); |
---|
2538 | set_displayed_user (greeter, name); |
---|
2539 | g_free (name); |
---|
2540 | } |
---|
2541 | } |
---|
2542 | |
---|
2543 | g_free (last_user); |
---|
2544 | } |
---|
2545 | |
---|
2546 | static GdkFilterReturn |
---|
2547 | wm_window_filter (GdkXEvent *gxevent, GdkEvent *event, gpointer data) |
---|
2548 | { |
---|
2549 | XEvent *xevent = (XEvent*)gxevent; |
---|
2550 | if (xevent->type == MapNotify) |
---|
2551 | { |
---|
2552 | GdkDisplay *display = gdk_x11_lookup_xdisplay (xevent->xmap.display); |
---|
2553 | GdkWindow *win = gdk_x11_window_foreign_new_for_display (display, xevent->xmap.window); |
---|
2554 | GdkWindowTypeHint win_type = gdk_window_get_type_hint (win); |
---|
2555 | |
---|
2556 | if (win_type != GDK_WINDOW_TYPE_HINT_COMBO && |
---|
2557 | win_type != GDK_WINDOW_TYPE_HINT_TOOLTIP && |
---|
2558 | win_type != GDK_WINDOW_TYPE_HINT_NOTIFICATION) |
---|
2559 | /* |
---|
2560 | if (win_type == GDK_WINDOW_TYPE_HINT_DESKTOP || |
---|
2561 | win_type == GDK_WINDOW_TYPE_HINT_DIALOG) |
---|
2562 | */ |
---|
2563 | gdk_window_focus (win, GDK_CURRENT_TIME); |
---|
2564 | } |
---|
2565 | else if (xevent->type == UnmapNotify) |
---|
2566 | { |
---|
2567 | Window xwin; |
---|
2568 | int revert_to = RevertToNone; |
---|
2569 | |
---|
2570 | XGetInputFocus (xevent->xunmap.display, &xwin, &revert_to); |
---|
2571 | if (revert_to == RevertToNone) |
---|
2572 | gdk_window_lower (gtk_widget_get_window (gtk_widget_get_toplevel (GTK_WIDGET (screen_overlay)))); |
---|
2573 | } |
---|
2574 | |
---|
2575 | return GDK_FILTER_CONTINUE; |
---|
2576 | } |
---|
2577 | |
---|
2578 | static void |
---|
2579 | debug_log_handler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) |
---|
2580 | { |
---|
2581 | gchar *new_domain = NULL; |
---|
2582 | if (log_level == G_LOG_LEVEL_DEBUG) |
---|
2583 | { |
---|
2584 | log_level = G_LOG_LEVEL_MESSAGE; |
---|
2585 | if (log_domain) |
---|
2586 | log_domain = new_domain = g_strdup_printf ("DEBUG/%s", log_domain); |
---|
2587 | else |
---|
2588 | log_domain = "DEBUG"; |
---|
2589 | } |
---|
2590 | g_log_default_handler (log_domain, log_level, message, user_data); |
---|
2591 | g_free (new_domain); |
---|
2592 | } |
---|
2593 | |
---|
2594 | int |
---|
2595 | main (int argc, char **argv) |
---|
2596 | { |
---|
2597 | GtkBuilder *builder; |
---|
2598 | const GList *items, *item; |
---|
2599 | GtkWidget *image; |
---|
2600 | gchar *value; |
---|
2601 | GtkIconTheme *icon_theme; |
---|
2602 | GtkCssProvider *css_provider; |
---|
2603 | GError *error = NULL; |
---|
2604 | |
---|
2605 | /* Prevent memory from being swapped out, as we are dealing with passwords */ |
---|
2606 | mlockall (MCL_CURRENT | MCL_FUTURE); |
---|
2607 | |
---|
2608 | g_message ("Starting %s (%s, %s)", PACKAGE_STRING, __DATE__, __TIME__); |
---|
2609 | |
---|
2610 | /* Disable global menus */ |
---|
2611 | g_unsetenv ("UBUNTU_MENUPROXY"); |
---|
2612 | |
---|
2613 | /* LP: #1024482 */ |
---|
2614 | g_setenv ("GDK_CORE_DEVICE_EVENTS", "1", TRUE); |
---|
2615 | |
---|
2616 | /* LP: #1366534 */ |
---|
2617 | g_setenv ("NO_AT_BRIDGE", "1", TRUE); |
---|
2618 | |
---|
2619 | /* Initialize i18n */ |
---|
2620 | setlocale (LC_ALL, ""); |
---|
2621 | bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); |
---|
2622 | bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); |
---|
2623 | textdomain (GETTEXT_PACKAGE); |
---|
2624 | |
---|
2625 | g_unix_signal_add (SIGTERM, (GSourceFunc)sigterm_cb, /* is_callback */ GINT_TO_POINTER (TRUE)); |
---|
2626 | |
---|
2627 | config_init (); |
---|
2628 | |
---|
2629 | if (config_get_bool (NULL, CONFIG_KEY_DEBUGGING, FALSE)) |
---|
2630 | g_log_set_default_handler (debug_log_handler, NULL); |
---|
2631 | |
---|
2632 | /* init gtk */ |
---|
2633 | gtk_init (&argc, &argv); |
---|
2634 | |
---|
2635 | /* Disabling GtkInspector shortcuts. |
---|
2636 | It is still possible to run GtkInspector with GTK_DEBUG=interactive. |
---|
2637 | Assume that user knows what he's doing. */ |
---|
2638 | if (!config_get_bool (NULL, CONFIG_KEY_DEBUGGING, FALSE)) |
---|
2639 | { |
---|
2640 | GtkWidget *fake_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); |
---|
2641 | GtkBindingSet *set = gtk_binding_set_by_class (G_OBJECT_GET_CLASS (fake_window)); |
---|
2642 | GtkBindingEntry *entry = NULL; |
---|
2643 | GtkBindingSignal *signals = NULL; |
---|
2644 | GSList *bindings = NULL; |
---|
2645 | GSList *iter; |
---|
2646 | |
---|
2647 | for (entry = set->entries; entry; entry = entry->set_next) |
---|
2648 | { |
---|
2649 | for (signals = entry->signals; signals; signals = signals->next) |
---|
2650 | { |
---|
2651 | if (g_strcmp0 (signals->signal_name, "enable-debugging") == 0) |
---|
2652 | { |
---|
2653 | bindings = g_slist_prepend (bindings, entry); |
---|
2654 | break; |
---|
2655 | } |
---|
2656 | } |
---|
2657 | } |
---|
2658 | |
---|
2659 | for (iter = bindings; iter; iter = g_slist_next (iter)) |
---|
2660 | { |
---|
2661 | entry = iter->data; |
---|
2662 | gtk_binding_entry_remove (set, entry->keyval, entry->modifiers); |
---|
2663 | } |
---|
2664 | |
---|
2665 | g_slist_free (bindings); |
---|
2666 | gtk_widget_destroy (fake_window); |
---|
2667 | } |
---|
2668 | |
---|
2669 | #ifdef HAVE_LIBIDO |
---|
2670 | g_debug ("Initializing IDO library"); |
---|
2671 | ido_init (); |
---|
2672 | #endif |
---|
2673 | |
---|
2674 | greeter = lightdm_greeter_new (); |
---|
2675 | g_signal_connect (greeter, "show-prompt", G_CALLBACK (show_prompt_cb), NULL); |
---|
2676 | g_signal_connect (greeter, "show-message", G_CALLBACK (show_message_cb), NULL); |
---|
2677 | g_signal_connect (greeter, "authentication-complete", G_CALLBACK (authentication_complete_cb), NULL); |
---|
2678 | g_signal_connect (greeter, "autologin-timer-expired", G_CALLBACK (timed_autologin_cb), NULL); |
---|
2679 | if (!lightdm_greeter_connect_sync (greeter, NULL)) |
---|
2680 | return EXIT_FAILURE; |
---|
2681 | |
---|
2682 | /* Set default cursor */ |
---|
2683 | gdk_window_set_cursor (gdk_get_default_root_window (), gdk_cursor_new (GDK_LEFT_PTR)); |
---|
2684 | |
---|
2685 | /* Make the greeter behave a bit more like a screensaver if used as un/lock-screen by blanking the screen */ |
---|
2686 | if (lightdm_greeter_get_lock_hint (greeter)) |
---|
2687 | { |
---|
2688 | Display *display = gdk_x11_display_get_xdisplay (gdk_display_get_default ()); |
---|
2689 | XGetScreenSaver (display, &timeout, &interval, &prefer_blanking, &allow_exposures); |
---|
2690 | XForceScreenSaver (display, ScreenSaverActive); |
---|
2691 | XSetScreenSaver (display, config_get_int (NULL, CONFIG_KEY_SCREENSAVER_TIMEOUT, 60), 0, |
---|
2692 | ScreenSaverActive, DefaultExposures); |
---|
2693 | } |
---|
2694 | |
---|
2695 | /* Set GTK+ settings */ |
---|
2696 | value = config_get_string (NULL, CONFIG_KEY_THEME, NULL); |
---|
2697 | if (value) |
---|
2698 | { |
---|
2699 | g_debug ("[Configuration] Changing GTK+ theme to '%s'", value); |
---|
2700 | g_object_set (gtk_settings_get_default (), "gtk-theme-name", value, NULL); |
---|
2701 | g_free (value); |
---|
2702 | } |
---|
2703 | g_object_get (gtk_settings_get_default (), "gtk-theme-name", &default_theme_name, NULL); |
---|
2704 | g_debug ("[Configuration] GTK+ theme: '%s'", default_theme_name); |
---|
2705 | |
---|
2706 | value = config_get_string (NULL, CONFIG_KEY_ICON_THEME, NULL); |
---|
2707 | if (value) |
---|
2708 | { |
---|
2709 | g_debug ("[Configuration] Changing icons theme to '%s'", value); |
---|
2710 | g_object_set (gtk_settings_get_default (), "gtk-icon-theme-name", value, NULL); |
---|
2711 | g_free (value); |
---|
2712 | } |
---|
2713 | g_object_get (gtk_settings_get_default (), "gtk-icon-theme-name", &default_icon_theme_name, NULL); |
---|
2714 | g_debug ("[Configuration] Icons theme: '%s'", default_icon_theme_name); |
---|
2715 | |
---|
2716 | value = config_get_string (NULL, CONFIG_KEY_FONT, "Sans 10"); |
---|
2717 | if (value) |
---|
2718 | { |
---|
2719 | g_debug ("[Configuration] Changing font to '%s'", value); |
---|
2720 | g_object_set (gtk_settings_get_default (), "gtk-font-name", value, NULL); |
---|
2721 | g_free (value); |
---|
2722 | } |
---|
2723 | g_object_get (gtk_settings_get_default (), "gtk-font-name", &default_font_name, NULL); |
---|
2724 | g_debug ("[Configuration] Font: '%s'", default_font_name); |
---|
2725 | |
---|
2726 | if (config_has_key (NULL, CONFIG_KEY_DPI)) |
---|
2727 | g_object_set (gtk_settings_get_default (), "gtk-xft-dpi", 1024*config_get_int (NULL, CONFIG_KEY_DPI, 96), NULL); |
---|
2728 | |
---|
2729 | if (config_has_key (NULL, CONFIG_KEY_ANTIALIAS)) |
---|
2730 | g_object_set (gtk_settings_get_default (), "gtk-xft-antialias", config_get_bool (NULL, CONFIG_KEY_ANTIALIAS, FALSE), NULL); |
---|
2731 | |
---|
2732 | value = config_get_string (NULL, CONFIG_KEY_HINT_STYLE, NULL); |
---|
2733 | if (value) |
---|
2734 | { |
---|
2735 | g_object_set (gtk_settings_get_default (), "gtk-xft-hintstyle", value, NULL); |
---|
2736 | g_free (value); |
---|
2737 | } |
---|
2738 | |
---|
2739 | value = config_get_string (NULL, CONFIG_KEY_RGBA, NULL); |
---|
2740 | if (value) |
---|
2741 | { |
---|
2742 | g_object_set (gtk_settings_get_default (), "gtk-xft-rgba", value, NULL); |
---|
2743 | g_free (value); |
---|
2744 | } |
---|
2745 | |
---|
2746 | #ifdef AT_SPI_COMMAND |
---|
2747 | spawn_line_pid (AT_SPI_COMMAND, G_SPAWN_SEARCH_PATH, NULL); |
---|
2748 | #endif |
---|
2749 | |
---|
2750 | #ifdef INDICATOR_SERVICES_COMMAND |
---|
2751 | spawn_line_pid (INDICATOR_SERVICES_COMMAND, G_SPAWN_SEARCH_PATH, NULL); |
---|
2752 | #endif |
---|
2753 | |
---|
2754 | builder = gtk_builder_new (); |
---|
2755 | if (!gtk_builder_add_from_string (builder, lightdm_gtk_greeter_ui, |
---|
2756 | lightdm_gtk_greeter_ui_length, &error)) |
---|
2757 | { |
---|
2758 | g_warning ("Error loading UI: %s", error->message); |
---|
2759 | return EXIT_FAILURE; |
---|
2760 | } |
---|
2761 | g_clear_error (&error); |
---|
2762 | |
---|
2763 | /* Screen window */ |
---|
2764 | screen_overlay = GTK_OVERLAY (gtk_builder_get_object (builder, "screen_overlay")); |
---|
2765 | screen_overlay_child = GTK_WIDGET (gtk_builder_get_object (builder, "screen_overlay_child")); |
---|
2766 | |
---|
2767 | /* Login window */ |
---|
2768 | login_window = GTK_WIDGET (gtk_builder_get_object (builder, "login_window")); |
---|
2769 | user_image = GTK_IMAGE (gtk_builder_get_object (builder, "user_image")); |
---|
2770 | user_combo = GTK_COMBO_BOX (gtk_builder_get_object (builder, "user_combobox")); |
---|
2771 | username_entry = GTK_ENTRY (gtk_builder_get_object (builder, "username_entry")); |
---|
2772 | password_entry = GTK_ENTRY (gtk_builder_get_object (builder, "password_entry")); |
---|
2773 | info_bar = GTK_INFO_BAR (gtk_builder_get_object (builder, "greeter_infobar")); |
---|
2774 | message_label = GTK_LABEL (gtk_builder_get_object (builder, "message_label")); |
---|
2775 | cancel_button = GTK_BUTTON (gtk_builder_get_object (builder, "cancel_button")); |
---|
2776 | login_button = GTK_BUTTON (gtk_builder_get_object (builder, "login_button")); |
---|
2777 | |
---|
2778 | /* Panel window*/ |
---|
2779 | panel_window = GTK_WIDGET (gtk_builder_get_object (builder, "panel_window")); |
---|
2780 | menubar = GTK_WIDGET (gtk_builder_get_object (builder, "menubar")); |
---|
2781 | session_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "session_menuitem")); |
---|
2782 | session_menu = GTK_MENU (gtk_builder_get_object (builder, "session_menu")); |
---|
2783 | language_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "language_menuitem")); |
---|
2784 | language_menu = GTK_MENU (gtk_builder_get_object (builder, "language_menu")); |
---|
2785 | a11y_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "a11y_menuitem")); |
---|
2786 | contrast_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "high_contrast_menuitem")); |
---|
2787 | font_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "large_font_menuitem")); |
---|
2788 | keyboard_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "keyboard_menuitem")); |
---|
2789 | reader_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "reader_menuitem")); |
---|
2790 | power_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "power_menuitem")); |
---|
2791 | layout_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "layout_menuitem")); |
---|
2792 | layout_menu = GTK_MENU (gtk_builder_get_object (builder, "layout_menu")); |
---|
2793 | clock_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "clock_menuitem")); |
---|
2794 | host_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "host_menuitem")); |
---|
2795 | |
---|
2796 | /* Power dialog */ |
---|
2797 | power_window = GTK_WIDGET (gtk_builder_get_object (builder, "power_window")); |
---|
2798 | power_ok_button = GTK_BUTTON (gtk_builder_get_object (builder, "power_ok_button")); |
---|
2799 | power_cancel_button = GTK_BUTTON (gtk_builder_get_object (builder, "power_cancel_button")); |
---|
2800 | power_title = GTK_LABEL (gtk_builder_get_object (builder, "power_title")); |
---|
2801 | power_text = GTK_LABEL (gtk_builder_get_object (builder, "power_text")); |
---|
2802 | power_icon = GTK_IMAGE (gtk_builder_get_object (builder, "power_icon")); |
---|
2803 | |
---|
2804 | gtk_overlay_add_overlay (screen_overlay, login_window); |
---|
2805 | gtk_overlay_add_overlay (screen_overlay, panel_window); |
---|
2806 | gtk_overlay_add_overlay (screen_overlay, power_window); |
---|
2807 | |
---|
2808 | gtk_accel_map_add_entry ("<Login>/a11y/font", GDK_KEY_F1, 0); |
---|
2809 | gtk_accel_map_add_entry ("<Login>/a11y/contrast", GDK_KEY_F2, 0); |
---|
2810 | gtk_accel_map_add_entry ("<Login>/a11y/keyboard", GDK_KEY_F3, 0); |
---|
2811 | gtk_accel_map_add_entry ("<Login>/a11y/reader", GDK_KEY_F4, 0); |
---|
2812 | gtk_accel_map_add_entry ("<Login>/power/shutdown", GDK_KEY_F4, GDK_MOD1_MASK); |
---|
2813 | |
---|
2814 | init_indicators (); |
---|
2815 | |
---|
2816 | /* https://bugzilla.gnome.org/show_bug.cgi?id=710888 |
---|
2817 | > GtkInfoBar not shown after calling gtk_widget_show |
---|
2818 | Assume they will fix it someday. */ |
---|
2819 | if (gtk_get_major_version () == 3 && gtk_get_minor_version () < 18) |
---|
2820 | { |
---|
2821 | GList *children = gtk_container_get_children (GTK_CONTAINER (info_bar)); |
---|
2822 | if (g_list_length (children) == 1 && GTK_IS_REVEALER (children->data)) |
---|
2823 | g_signal_connect_after(children->data, "notify::child-revealed", (GCallback)infobar_revealed_cb_710888, NULL); |
---|
2824 | g_list_free (children); |
---|
2825 | } |
---|
2826 | |
---|
2827 | /* Hide empty panel */ |
---|
2828 | GList *menubar_items = gtk_container_get_children (GTK_CONTAINER (menubar)); |
---|
2829 | if (!menubar_items) |
---|
2830 | gtk_widget_hide (GTK_WIDGET (panel_window)); |
---|
2831 | else |
---|
2832 | g_list_free (menubar_items); |
---|
2833 | |
---|
2834 | if (config_get_bool (NULL, CONFIG_KEY_HIDE_USER_IMAGE, FALSE)) |
---|
2835 | { |
---|
2836 | gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (builder, "user_image_border"))); |
---|
2837 | gtk_widget_hide (GTK_WIDGET (user_image)); /* Hide to mark image is disabled */ |
---|
2838 | gtk_widget_set_size_request (GTK_WIDGET (user_combo), 250, -1); |
---|
2839 | } |
---|
2840 | else |
---|
2841 | { |
---|
2842 | value = config_get_string (NULL, CONFIG_KEY_DEFAULT_USER_IMAGE, NULL); |
---|
2843 | if (value) |
---|
2844 | { |
---|
2845 | if (value[0] == '#') |
---|
2846 | default_user_icon = g_strdup (value + 1); |
---|
2847 | else |
---|
2848 | { |
---|
2849 | default_user_pixbuf = gdk_pixbuf_new_from_file (value, &error); |
---|
2850 | if (!default_user_pixbuf) |
---|
2851 | { |
---|
2852 | g_warning ("Failed to load default user image: %s", error->message); |
---|
2853 | g_clear_error (&error); |
---|
2854 | } |
---|
2855 | } |
---|
2856 | g_free (value); |
---|
2857 | } |
---|
2858 | } |
---|
2859 | |
---|
2860 | icon_theme = gtk_icon_theme_get_default (); |
---|
2861 | |
---|
2862 | /* Session menu */ |
---|
2863 | if (gtk_widget_get_visible (session_menuitem)) |
---|
2864 | { |
---|
2865 | if (gtk_icon_theme_has_icon (icon_theme, "document-properties-symbolic")) |
---|
2866 | session_badge = gtk_image_new_from_icon_name ("document-properties-symbolic", GTK_ICON_SIZE_MENU); |
---|
2867 | else |
---|
2868 | session_badge = gtk_image_new_from_icon_name ("document-properties", GTK_ICON_SIZE_MENU); |
---|
2869 | gtk_widget_show (session_badge); |
---|
2870 | gtk_container_add (GTK_CONTAINER (session_menuitem), session_badge); |
---|
2871 | |
---|
2872 | items = lightdm_get_sessions (); |
---|
2873 | GSList *sessions = NULL; |
---|
2874 | for (item = items; item; item = item->next) |
---|
2875 | { |
---|
2876 | LightDMSession *session = item->data; |
---|
2877 | GtkWidget *radiomenuitem; |
---|
2878 | |
---|
2879 | radiomenuitem = gtk_radio_menu_item_new_with_label (sessions, lightdm_session_get_name (session)); |
---|
2880 | g_object_set_data (G_OBJECT (radiomenuitem), SESSION_DATA_KEY, (gpointer) lightdm_session_get_key (session)); |
---|
2881 | sessions = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (radiomenuitem)); |
---|
2882 | g_signal_connect (G_OBJECT (radiomenuitem), "activate", G_CALLBACK (session_selected_cb), NULL); |
---|
2883 | gtk_menu_shell_append (GTK_MENU_SHELL (session_menu), radiomenuitem); |
---|
2884 | gtk_widget_show (GTK_WIDGET (radiomenuitem)); |
---|
2885 | } |
---|
2886 | set_session (NULL); |
---|
2887 | } |
---|
2888 | |
---|
2889 | /* Language menu */ |
---|
2890 | if (gtk_widget_get_visible (language_menuitem)) |
---|
2891 | { |
---|
2892 | items = lightdm_get_languages (); |
---|
2893 | GSList *languages = NULL; |
---|
2894 | for (item = items; item; item = item->next) |
---|
2895 | { |
---|
2896 | LightDMLanguage *language = item->data; |
---|
2897 | const gchar *country, *code; |
---|
2898 | gchar *label; |
---|
2899 | GtkWidget *radiomenuitem; |
---|
2900 | |
---|
2901 | country = lightdm_language_get_territory (language); |
---|
2902 | if (country) |
---|
2903 | label = g_strdup_printf ("%s - %s", lightdm_language_get_name (language), country); |
---|
2904 | else |
---|
2905 | label = g_strdup (lightdm_language_get_name (language)); |
---|
2906 | |
---|
2907 | code = lightdm_language_get_code (language); |
---|
2908 | gchar *modifier = strchr (code, '@'); |
---|
2909 | if (modifier != NULL) |
---|
2910 | { |
---|
2911 | gchar *label_new = g_strdup_printf ("%s [%s]", label, modifier+1); |
---|
2912 | g_free (label); |
---|
2913 | label = label_new; |
---|
2914 | } |
---|
2915 | |
---|
2916 | radiomenuitem = gtk_radio_menu_item_new_with_label (languages, label); |
---|
2917 | g_object_set_data (G_OBJECT (radiomenuitem), LANGUAGE_DATA_CODE, (gpointer) code); |
---|
2918 | languages = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (radiomenuitem)); |
---|
2919 | g_signal_connect (G_OBJECT (radiomenuitem), "activate", G_CALLBACK (language_selected_cb), NULL); |
---|
2920 | gtk_menu_shell_append (GTK_MENU_SHELL (language_menu), radiomenuitem); |
---|
2921 | gtk_widget_show (GTK_WIDGET (radiomenuitem)); |
---|
2922 | } |
---|
2923 | set_language (NULL); |
---|
2924 | } |
---|
2925 | |
---|
2926 | /* a11y menu */ |
---|
2927 | if (gtk_widget_get_visible (a11y_menuitem)) |
---|
2928 | { |
---|
2929 | if (gtk_icon_theme_has_icon (icon_theme, "preferences-desktop-accessibility-symbolic")) |
---|
2930 | image = gtk_image_new_from_icon_name ("preferences-desktop-accessibility-symbolic", GTK_ICON_SIZE_MENU); |
---|
2931 | else |
---|
2932 | image = gtk_image_new_from_icon_name ("preferences-desktop-accessibility", GTK_ICON_SIZE_MENU); |
---|
2933 | gtk_widget_show (image); |
---|
2934 | gtk_container_add (GTK_CONTAINER (a11y_menuitem), image); |
---|
2935 | } |
---|
2936 | |
---|
2937 | value = config_get_string (NULL, CONFIG_KEY_KEYBOARD, NULL); |
---|
2938 | if (value) |
---|
2939 | { |
---|
2940 | a11y_keyboard_command = menu_command_parse_extended ("keyboard", value, keyboard_menuitem, "onboard", "--xid"); |
---|
2941 | g_free (value); |
---|
2942 | } |
---|
2943 | gtk_widget_set_visible (keyboard_menuitem, a11y_keyboard_command != NULL); |
---|
2944 | |
---|
2945 | |
---|
2946 | |
---|
2947 | value = config_get_string (NULL, CONFIG_KEY_READER, NULL); |
---|
2948 | if (value) |
---|
2949 | { |
---|
2950 | a11y_reader_command = menu_command_parse ("reader", value, reader_menuitem); |
---|
2951 | g_free (value); |
---|
2952 | } |
---|
2953 | gtk_widget_set_visible (reader_menuitem, a11y_reader_command != NULL); |
---|
2954 | |
---|
2955 | /* Power menu */ |
---|
2956 | if (gtk_widget_get_visible (power_menuitem)) |
---|
2957 | { |
---|
2958 | if (gtk_icon_theme_has_icon (icon_theme, "system-shutdown-symbolic")) |
---|
2959 | image = gtk_image_new_from_icon_name ("system-shutdown-symbolic", GTK_ICON_SIZE_MENU); |
---|
2960 | else |
---|
2961 | image = gtk_image_new_from_icon_name ("system-shutdown", GTK_ICON_SIZE_MENU); |
---|
2962 | gtk_widget_show (image); |
---|
2963 | gtk_container_add (GTK_CONTAINER (power_menuitem), image); |
---|
2964 | |
---|
2965 | suspend_menuitem = (GTK_WIDGET (gtk_builder_get_object (builder, "suspend_menuitem"))); |
---|
2966 | hibernate_menuitem = (GTK_WIDGET (gtk_builder_get_object (builder, "hibernate_menuitem"))); |
---|
2967 | restart_menuitem = (GTK_WIDGET (gtk_builder_get_object (builder, "restart_menuitem"))); |
---|
2968 | shutdown_menuitem = (GTK_WIDGET (gtk_builder_get_object (builder, "shutdown_menuitem"))); |
---|
2969 | |
---|
2970 | g_signal_connect (G_OBJECT (power_menuitem),"activate", G_CALLBACK (power_menu_cb), NULL); |
---|
2971 | } |
---|
2972 | |
---|
2973 | /* Layout menu */ |
---|
2974 | if (gtk_widget_get_visible (layout_menuitem)) |
---|
2975 | { |
---|
2976 | #ifdef HAVE_LIBXKLAVIER |
---|
2977 | xkl_engine = xkl_engine_get_instance (XOpenDisplay (NULL)); |
---|
2978 | if (xkl_engine) |
---|
2979 | { |
---|
2980 | xkl_engine_start_listen (xkl_engine, XKLL_TRACK_KEYBOARD_STATE); |
---|
2981 | g_signal_connect (xkl_engine, "X-state-changed", |
---|
2982 | G_CALLBACK (xkl_state_changed_cb), NULL); |
---|
2983 | g_signal_connect (xkl_engine, "X-config-changed", |
---|
2984 | G_CALLBACK (xkl_config_changed_cb), NULL); |
---|
2985 | gdk_window_add_filter (NULL, (GdkFilterFunc) xkl_xevent_filter, NULL); |
---|
2986 | |
---|
2987 | /* refresh */ |
---|
2988 | XklConfigRec *config_rec = xkl_config_rec_new (); |
---|
2989 | if (xkl_config_rec_get_from_server (config_rec, xkl_engine)) |
---|
2990 | xkl_config_rec_activate (config_rec, xkl_engine); |
---|
2991 | g_object_unref (config_rec); |
---|
2992 | } |
---|
2993 | else |
---|
2994 | { |
---|
2995 | g_warning ("Failed to get XklEngine instance"); |
---|
2996 | gtk_widget_hide (layout_menuitem); |
---|
2997 | } |
---|
2998 | #endif |
---|
2999 | update_layouts_menu (); |
---|
3000 | update_layouts_menu_state (); |
---|
3001 | } |
---|
3002 | |
---|
3003 | /* Host label */ |
---|
3004 | if (gtk_widget_get_visible (host_menuitem)) |
---|
3005 | gtk_menu_item_set_label (GTK_MENU_ITEM (host_menuitem), lightdm_get_hostname ()); |
---|
3006 | |
---|
3007 | /* Clock label */ |
---|
3008 | if (gtk_widget_get_visible (clock_menuitem)) |
---|
3009 | { |
---|
3010 | gtk_menu_item_set_label (GTK_MENU_ITEM (clock_menuitem), ""); |
---|
3011 | clock_label = gtk_bin_get_child (GTK_BIN (clock_menuitem)); |
---|
3012 | clock_format = config_get_string (NULL, CONFIG_KEY_CLOCK_FORMAT, "%a, %H:%M"); |
---|
3013 | clock_timeout_thread (); |
---|
3014 | gdk_threads_add_timeout (1000, (GSourceFunc) clock_timeout_thread, NULL); |
---|
3015 | } |
---|
3016 | |
---|
3017 | /* A bit of CSS */ |
---|
3018 | GdkRGBA lightdm_gtk_greeter_override_defaults; |
---|
3019 | css_provider = gtk_css_provider_new (); |
---|
3020 | gtk_css_provider_load_from_data (css_provider, lightdm_gtk_greeter_css_application, lightdm_gtk_greeter_css_application_length, NULL); |
---|
3021 | gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), GTK_STYLE_PROVIDER (css_provider), |
---|
3022 | GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); |
---|
3023 | css_provider = gtk_css_provider_new (); |
---|
3024 | guint fallback_css_priority = GTK_STYLE_PROVIDER_PRIORITY_APPLICATION; |
---|
3025 | if (gtk_style_context_lookup_color (gtk_widget_get_style_context (GTK_WIDGET (login_window)), |
---|
3026 | "lightdm-gtk-greeter-override-defaults", |
---|
3027 | &lightdm_gtk_greeter_override_defaults)) |
---|
3028 | fallback_css_priority = GTK_STYLE_PROVIDER_PRIORITY_FALLBACK; |
---|
3029 | gtk_css_provider_load_from_data (css_provider, lightdm_gtk_greeter_css_fallback, lightdm_gtk_greeter_css_fallback_length, NULL); |
---|
3030 | gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), GTK_STYLE_PROVIDER (css_provider), |
---|
3031 | fallback_css_priority); |
---|
3032 | |
---|
3033 | /* Background */ |
---|
3034 | greeter_background = greeter_background_new (GTK_WIDGET (screen_overlay)); |
---|
3035 | |
---|
3036 | value = config_get_string (NULL, CONFIG_KEY_ACTIVE_MONITOR, NULL); |
---|
3037 | greeter_background_set_active_monitor_config (greeter_background, value ? value : "#cursor"); |
---|
3038 | g_free (value); |
---|
3039 | |
---|
3040 | read_monitor_configuration (CONFIG_GROUP_DEFAULT, GREETER_BACKGROUND_DEFAULT); |
---|
3041 | |
---|
3042 | gchar **config_group; |
---|
3043 | gchar **config_groups = config_get_groups (CONFIG_GROUP_MONITOR); |
---|
3044 | for (config_group = config_groups; *config_group; ++config_group) |
---|
3045 | { |
---|
3046 | const gchar *name = *config_group + sizeof (CONFIG_GROUP_MONITOR); |
---|
3047 | while (*name && g_ascii_isspace (*name)) |
---|
3048 | ++name; |
---|
3049 | |
---|
3050 | read_monitor_configuration (*config_group, name); |
---|
3051 | } |
---|
3052 | g_strfreev (config_groups); |
---|
3053 | |
---|
3054 | greeter_background_add_accel_group (greeter_background, GTK_ACCEL_GROUP (gtk_builder_get_object (builder, "a11y_accelgroup"))); |
---|
3055 | greeter_background_add_accel_group (greeter_background, GTK_ACCEL_GROUP (gtk_builder_get_object (builder, "power_accelgroup"))); |
---|
3056 | |
---|
3057 | greeter_background_connect (greeter_background, gdk_screen_get_default ()); |
---|
3058 | |
---|
3059 | if (lightdm_greeter_get_hide_users_hint (greeter)) |
---|
3060 | { |
---|
3061 | set_user_image (NULL); |
---|
3062 | start_authentication ("*other"); |
---|
3063 | } |
---|
3064 | else |
---|
3065 | { |
---|
3066 | load_user_list (); |
---|
3067 | gtk_widget_hide (GTK_WIDGET (cancel_button)); |
---|
3068 | gtk_widget_show (GTK_WIDGET (user_combo)); |
---|
3069 | } |
---|
3070 | |
---|
3071 | /* Windows positions */ |
---|
3072 | value = config_get_string (NULL, CONFIG_KEY_POSITION, NULL); |
---|
3073 | g_object_set_data_full (G_OBJECT (login_window), WINDOW_DATA_POSITION, str_to_position (value, &WINDOW_POS_CENTER), g_free); |
---|
3074 | g_free (value); |
---|
3075 | |
---|
3076 | |
---|
3077 | gtk_widget_set_valign (panel_window, config_get_enum (NULL, CONFIG_KEY_PANEL_POSITION, GTK_ALIGN_START, |
---|
3078 | "bottom", GTK_ALIGN_END, |
---|
3079 | "top", GTK_ALIGN_START, NULL)); |
---|
3080 | |
---|
3081 | if (a11y_keyboard_command) |
---|
3082 | { |
---|
3083 | value = config_get_string (NULL, CONFIG_KEY_KEYBOARD_POSITION, NULL); |
---|
3084 | g_object_set_data_full (G_OBJECT (a11y_keyboard_command->widget), WINDOW_DATA_POSITION, str_to_position (value, &KEYBOARD_POSITION), g_free); |
---|
3085 | g_free (value); |
---|
3086 | } |
---|
3087 | |
---|
3088 | gtk_builder_connect_signals (builder, greeter); |
---|
3089 | |
---|
3090 | gchar **a11y_states = config_get_string_list (NULL, CONFIG_KEY_A11Y_STATES, NULL); |
---|
3091 | if (a11y_states && *a11y_states) |
---|
3092 | { |
---|
3093 | GHashTable *items = g_hash_table_new (g_str_hash, g_str_equal); |
---|
3094 | g_hash_table_insert (items, "contrast", contrast_menuitem); |
---|
3095 | g_hash_table_insert (items, "font", font_menuitem); |
---|
3096 | g_hash_table_insert (items, "keyboard", keyboard_menuitem); |
---|
3097 | g_hash_table_insert (items, "reader", reader_menuitem); |
---|
3098 | |
---|
3099 | gpointer item; |
---|
3100 | gchar **values_iter; |
---|
3101 | for (values_iter = a11y_states; *values_iter; ++values_iter) |
---|
3102 | { |
---|
3103 | value = *values_iter; |
---|
3104 | switch (value[0]) |
---|
3105 | { |
---|
3106 | case '-': |
---|
3107 | continue; |
---|
3108 | case '+': |
---|
3109 | if (g_hash_table_lookup_extended (items, &value[1], NULL, &item) && |
---|
3110 | gtk_widget_get_visible (GTK_WIDGET (item))) |
---|
3111 | gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); |
---|
3112 | break; |
---|
3113 | case '~': |
---|
3114 | value++; |
---|
3115 | default: |
---|
3116 | if (g_hash_table_lookup_extended (items, value, NULL, &item) && |
---|
3117 | gtk_widget_get_visible (GTK_WIDGET (item))) |
---|
3118 | { |
---|
3119 | gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), |
---|
3120 | config_get_bool (STATE_SECTION_A11Y, value, FALSE)); |
---|
3121 | g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (a11y_menuitem_toggled_cb), g_strdup (value)); |
---|
3122 | } |
---|
3123 | } |
---|
3124 | } |
---|
3125 | g_hash_table_unref (items); |
---|
3126 | } |
---|
3127 | g_strfreev (a11y_states); |
---|
3128 | |
---|
3129 | /* There is no window manager, so we need to implement some of its functionality */ |
---|
3130 | GdkWindow* root_window = gdk_get_default_root_window (); |
---|
3131 | gdk_window_set_events (root_window, gdk_window_get_events (root_window) | GDK_SUBSTRUCTURE_MASK); |
---|
3132 | gdk_window_add_filter (root_window, wm_window_filter, NULL); |
---|
3133 | |
---|
3134 | gtk_widget_show (GTK_WIDGET (screen_overlay)); |
---|
3135 | |
---|
3136 | g_debug ("Run Gtk loop..."); |
---|
3137 | gtk_main (); |
---|
3138 | g_debug ("Gtk loop exits"); |
---|
3139 | |
---|
3140 | sigterm_cb (/* is_callback */ GINT_TO_POINTER (FALSE)); |
---|
3141 | |
---|
3142 | return EXIT_SUCCESS; |
---|
3143 | } |
---|