Merge lp:~lightdm-gtk-greeter-team/lightdm-gtk-greeter/lp-1319848-states-and-orca into lp:~lightdm-gtk-greeter-team/lightdm-gtk-greeter/trunk
- lp-1319848-states-and-orca
- Merge into trunk
Proposed by
Andrew P.
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | 297 | ||||
Proposed branch: | lp:~lightdm-gtk-greeter-team/lightdm-gtk-greeter/lp-1319848-states-and-orca | ||||
Merge into: | lp:~lightdm-gtk-greeter-team/lightdm-gtk-greeter/trunk | ||||
Diff against target: |
748 lines (+345/-168) 3 files modified
data/lightdm-gtk-greeter.conf (+4/-1) src/lightdm-gtk-greeter.c (+330/-167) src/lightdm-gtk-greeter.glade (+11/-0) |
||||
To merge this branch: | bzr merge lp:~lightdm-gtk-greeter-team/lightdm-gtk-greeter/lp-1319848-states-and-orca | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Sean Davis | Approve | ||
Review via email: mp+225811@code.launchpad.net |
Commit message
Description of the change
1. New option:
reader=
Adds new item to a11y menu: Screen Reader (F4 key).
2. New option:
a11y-states=
Controls state of a11y tools at startup. Allowed items: contrast;
"name" - save state on exit and restore it at start
"-name" - always disabled at start (default value)
"+name" - always enabled at start
Start screen reader at start and use saved state of "contrast" menu item:
a11y-states=
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'data/lightdm-gtk-greeter.conf' |
2 | --- data/lightdm-gtk-greeter.conf 2014-02-09 20:03:35 +0000 |
3 | +++ data/lightdm-gtk-greeter.conf 2014-07-07 12:35:18 +0000 |
4 | @@ -10,7 +10,9 @@ |
5 | # show-indicators = semi-colon ";" separated list of allowed indicator modules. Built-in indicators include "~a11y", "~language", "~session", "~power". Unity indicators can be represented by short name (e.g. "sound", "power"), service file name, or absolute path |
6 | # show-clock (true or false) |
7 | # clock-format = strftime-format string, e.g. %H:%M |
8 | -# keyboard = command to launch on-screen keyboard |
9 | +# keyboard = command to launch on-screen keyboard (e.g. onboard) |
10 | +# reader = command to launch screen reader (e.g. orca) |
11 | +# a11y-states = states of accessibility features: "name" - save state on exit, "-name" - disabled at start (default value for unlisted), "+name" - enabled at start. Allowed names: contrast, font, keyboard. |
12 | # position = main window position: x y |
13 | # default-user-image = Image used as default user icon, path or #icon-name |
14 | # screensaver-timeout = Timeout (in seconds) until the screen blanks when the greeter is called as lockscreen |
15 | @@ -28,5 +30,6 @@ |
16 | #show-clock= |
17 | #clock-format= |
18 | #keyboard= |
19 | +#reader= |
20 | #position= |
21 | #screensaver-timeout= |
22 | |
23 | === modified file 'src/lightdm-gtk-greeter.c' |
24 | --- src/lightdm-gtk-greeter.c 2014-07-05 16:46:13 +0000 |
25 | +++ src/lightdm-gtk-greeter.c 2014-07-07 12:35:18 +0000 |
26 | @@ -64,8 +64,10 @@ |
27 | #endif |
28 | |
29 | static LightDMGreeter *greeter; |
30 | + |
31 | static GKeyFile *state; |
32 | static gchar *state_filename; |
33 | +static void save_state_file (void); |
34 | |
35 | /* Defaults */ |
36 | static gchar *default_font_name, *default_theme_name, *default_icon_theme_name; |
37 | @@ -78,7 +80,8 @@ |
38 | static GtkWidget *power_menuitem, *session_menuitem, *language_menuitem, *a11y_menuitem, |
39 | *layout_menuitem, *session_badge; |
40 | static GtkWidget *suspend_menuitem, *hibernate_menuitem, *restart_menuitem, *shutdown_menuitem; |
41 | -static GtkWidget *keyboard_menuitem, *clock_menuitem, *clock_label, *host_menuitem; |
42 | +static GtkWidget *clock_menuitem, *clock_label, *host_menuitem; |
43 | +static GtkWidget *contrast_menuitem, *font_menuitem, *keyboard_menuitem, *reader_menuitem; |
44 | static GtkMenu *session_menu, *language_menu, *layout_menu; |
45 | |
46 | /* Login Window Widgets */ |
47 | @@ -91,10 +94,52 @@ |
48 | static GtkButton *cancel_button, *login_button; |
49 | |
50 | static gchar *clock_format; |
51 | -static gchar **a11y_keyboard_command; |
52 | -static GPid a11y_kbd_pid = 0; |
53 | -static GError *a11y_keyboard_error; |
54 | -static GtkWindow *onboard_window; |
55 | + |
56 | +typedef struct |
57 | +{ |
58 | + gint value; |
59 | + /* +0 and -0 */ |
60 | + gint sign; |
61 | + /* interpret 'value' as percentage of screen width/height */ |
62 | + gboolean percentage; |
63 | + /* -1: left/top, 0: center, +1: right,bottom */ |
64 | + gint anchor; |
65 | +} DimensionPosition; |
66 | + |
67 | +typedef struct |
68 | +{ |
69 | + DimensionPosition x, y; |
70 | +} WindowPosition; |
71 | + |
72 | +/* Function translate user defined coordinates to absolute value */ |
73 | +static gint get_absolute_position (const DimensionPosition *p, gint screen, gint window); |
74 | +static const WindowPosition CENTERED_WINDOW_POS = {.x = {50, +1, TRUE, 0}, .y = {50, +1, TRUE, 0}}; |
75 | +static const WindowPosition ONBOARD_WINDOW_POS = {.x = {50, +1, TRUE, 0}, .y = { 0, -1, FALSE, +1}}; |
76 | +static const WindowPosition ONBOARD_WINDOW_SIZE = {.x = {610, 0, FALSE,0}, .y = {210, 0, FALSE, 0}}; |
77 | +static WindowPosition main_window_pos; |
78 | + |
79 | +typedef struct |
80 | +{ |
81 | + gchar **argv; |
82 | + gint argc; |
83 | + |
84 | + GPid pid; |
85 | + GtkWidget *menu_item; |
86 | + GtkWidget *widget; |
87 | +} MenuCommand; |
88 | + |
89 | +static MenuCommand *menu_command_parse (const gchar *value, GtkWidget *menu_item); |
90 | +static MenuCommand *menu_command_parse_extended (const gchar *value, GtkWidget *menu_item, |
91 | + const gchar *xid_supported, const gchar *xid_arg, |
92 | + const WindowPosition *size); |
93 | +static gboolean menu_command_run (MenuCommand *command); |
94 | +static gboolean menu_command_stop (MenuCommand *command); |
95 | +static void command_terminated_cb (GPid pid, gint status, MenuCommand *command); |
96 | + |
97 | +static MenuCommand *a11y_keyboard_command; |
98 | +static MenuCommand *a11y_reader_command; |
99 | + |
100 | +static void a11y_menuitem_toggled_cb (GtkCheckMenuItem *item, const gchar* name); |
101 | |
102 | /* Pending Questions */ |
103 | static GSList *pending_questions = NULL; |
104 | @@ -130,25 +175,6 @@ |
105 | gchar *text; |
106 | } PAMConversationMessage; |
107 | |
108 | -typedef struct |
109 | -{ |
110 | - gint value; |
111 | - /* +0 and -0 */ |
112 | - gint sign; |
113 | - /* interpret 'value' as percentage of screen width/height */ |
114 | - gboolean percentage; |
115 | - /* -1: left/top, 0: center, +1: right,bottom */ |
116 | - gint anchor; |
117 | -} DimensionPosition; |
118 | - |
119 | -typedef struct |
120 | -{ |
121 | - DimensionPosition x, y; |
122 | -} WindowPosition; |
123 | - |
124 | -static const WindowPosition CENTERED_WINDOW_POS = { .x = {50, +1, TRUE, 0}, .y = {50, +1, TRUE, 0} }; |
125 | -static WindowPosition main_window_pos; |
126 | - |
127 | static GdkPixbuf* default_user_pixbuf = NULL; |
128 | static gchar* default_user_icon = "avatar-default"; |
129 | |
130 | @@ -197,6 +223,201 @@ |
131 | static const gchar *INDICATOR_DATA_MENUITEMS = "indicator-data-menuitems"; |
132 | #endif |
133 | |
134 | + |
135 | +static void |
136 | +save_state_file (void) |
137 | +{ |
138 | + GError *error = NULL; |
139 | + gsize data_length = 0; |
140 | + gchar *data = g_key_file_to_data (state, &data_length, &error); |
141 | + |
142 | + if (error) |
143 | + { |
144 | + g_warning ("Failed to save state file: %s", error->message); |
145 | + g_clear_error (&error); |
146 | + } |
147 | + |
148 | + if (data) |
149 | + { |
150 | + g_file_set_contents (state_filename, data, data_length, &error); |
151 | + if (error) |
152 | + { |
153 | + g_warning ("Failed to save state file: %s", error->message); |
154 | + g_clear_error (&error); |
155 | + } |
156 | + g_free (data); |
157 | + } |
158 | +} |
159 | + |
160 | +/* MenuCommand */ |
161 | + |
162 | +static MenuCommand* |
163 | +menu_command_parse (const gchar *value, GtkWidget *menu_item) |
164 | +{ |
165 | + return menu_command_parse_extended (value, menu_item, NULL, NULL, NULL); |
166 | +} |
167 | + |
168 | +static MenuCommand* |
169 | +menu_command_parse_extended (const gchar *value, GtkWidget *menu_item, |
170 | + const gchar *xid_supported, const gchar *xid_arg, |
171 | + const WindowPosition *size) |
172 | +{ |
173 | + if (!value) |
174 | + return NULL; |
175 | + |
176 | + GError *error = NULL; |
177 | + gchar **argv; |
178 | + gint argc = 0; |
179 | + |
180 | + if (!g_shell_parse_argv (value, &argc, &argv, &error)) |
181 | + { |
182 | + if (error) |
183 | + g_warning ("Failed to parse command line: %s", error->message); |
184 | + g_clear_error (&error); |
185 | + return NULL; |
186 | + } |
187 | + |
188 | + MenuCommand *command = g_new0 (MenuCommand, 1); |
189 | + command->menu_item = menu_item; |
190 | + command->argc = argc; |
191 | + command->argv = argv; |
192 | + |
193 | + if (g_strcmp0 (argv[0], xid_supported) == 0) |
194 | + { |
195 | + gboolean have_xid_arg = FALSE; |
196 | + gint i; |
197 | + for (i = 1; i < argc; ++i) |
198 | + if (g_strcmp0 (argv[i], xid_arg) == 0) |
199 | + { |
200 | + have_xid_arg = TRUE; |
201 | + break; |
202 | + } |
203 | + if (!have_xid_arg) |
204 | + { |
205 | + gchar *new_value = g_strdup_printf ("%s %s", value, xid_arg); |
206 | + |
207 | + if (g_shell_parse_argv (new_value, &argc, &argv, &error)) |
208 | + { |
209 | + g_strfreev (command->argv); |
210 | + command->argc = argc; |
211 | + command->argv = argv; |
212 | + have_xid_arg = TRUE; |
213 | + } |
214 | + else |
215 | + { |
216 | + if (error) |
217 | + g_warning ("Failed to parse command line: %s", error->message); |
218 | + g_clear_error (&error); |
219 | + } |
220 | + g_free (new_value); |
221 | + } |
222 | + |
223 | + if (have_xid_arg) |
224 | + { |
225 | + GdkRectangle screen; |
226 | + command->widget = gtk_window_new (GTK_WINDOW_TOPLEVEL); |
227 | + gdk_screen_get_monitor_geometry (gdk_screen_get_default (), |
228 | + /* must be replaced with background->active_monitor */ |
229 | + gdk_screen_get_primary_monitor (gdk_screen_get_default ()), |
230 | + &screen); |
231 | + gtk_widget_set_size_request (command->widget, |
232 | + get_absolute_position (&size->x, screen.width, 0), |
233 | + get_absolute_position (&size->y, screen.height, 0)); |
234 | + } |
235 | + } |
236 | + return command; |
237 | +} |
238 | + |
239 | +static gboolean |
240 | +menu_command_run (MenuCommand *command) |
241 | +{ |
242 | + g_return_val_if_fail (command && g_strv_length (command->argv), FALSE); |
243 | + |
244 | + GError *error = NULL; |
245 | + gboolean spawned = FALSE; |
246 | + if (command->widget) |
247 | + { |
248 | + GtkSocket* socket = NULL; |
249 | + gint out_fd = 0; |
250 | + |
251 | + if (g_spawn_async_with_pipes (NULL, command->argv, NULL, G_SPAWN_SEARCH_PATH, |
252 | + NULL, NULL, &command->pid, NULL, &out_fd, NULL, &error)) |
253 | + { |
254 | + gchar* text = NULL; |
255 | + GIOChannel* out_channel = g_io_channel_unix_new (out_fd); |
256 | + if (g_io_channel_read_line (out_channel, &text, NULL, NULL, &error) == G_IO_STATUS_NORMAL) |
257 | + { |
258 | + gchar* end_ptr = NULL; |
259 | + |
260 | + text = g_strstrip (text); |
261 | + gint id = g_ascii_strtoll (text, &end_ptr, 0); |
262 | + |
263 | + if (id != 0 && end_ptr > text) |
264 | + { |
265 | + socket = GTK_SOCKET (gtk_socket_new ()); |
266 | + gtk_container_add (GTK_CONTAINER (command->widget), GTK_WIDGET (socket)); |
267 | + gtk_socket_add_id (socket, id); |
268 | + gtk_widget_show_all (GTK_WIDGET (command->widget)); |
269 | + spawned = TRUE; |
270 | + } |
271 | + else |
272 | + g_warning ("Failed to get '%s' socket: unrecognized output", command->argv[0]); |
273 | + |
274 | + g_free(text); |
275 | + } |
276 | + } |
277 | + } |
278 | + else |
279 | + { |
280 | + spawned = g_spawn_async (NULL, command->argv, NULL, |
281 | + G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, |
282 | + NULL, NULL, &command->pid, &error); |
283 | + if (spawned) |
284 | + g_child_watch_add (command->pid, (GChildWatchFunc)command_terminated_cb, command); |
285 | + } |
286 | + |
287 | + if(!spawned) |
288 | + { |
289 | + if (error) |
290 | + g_warning ("Command spawning error: '%s'", error->message); |
291 | + command->pid = 0; |
292 | + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (command->menu_item), FALSE); |
293 | + } |
294 | + g_clear_error(&error); |
295 | + return spawned; |
296 | +} |
297 | + |
298 | +static gboolean |
299 | +menu_command_stop (MenuCommand *command) |
300 | +{ |
301 | + g_return_val_if_fail (command, FALSE); |
302 | + |
303 | + if (command->pid) |
304 | + { |
305 | + kill (command->pid, SIGTERM); |
306 | + g_spawn_close_pid (command->pid); |
307 | + command->pid = 0; |
308 | + if (command->menu_item) |
309 | + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (command->menu_item), FALSE); |
310 | + if (command->widget) |
311 | + gtk_widget_hide (command->widget); |
312 | + } |
313 | + return TRUE; |
314 | +} |
315 | + |
316 | +static void |
317 | +command_terminated_cb (GPid pid, gint status, MenuCommand *command) |
318 | +{ |
319 | + menu_command_stop (command); |
320 | +} |
321 | + |
322 | +static void |
323 | +a11y_menuitem_toggled_cb (GtkCheckMenuItem *item, const gchar* name) |
324 | +{ |
325 | + g_key_file_set_boolean (state, "a11y-states", name, gtk_check_menu_item_get_active (item)); |
326 | + save_state_file (); |
327 | +} |
328 | + |
329 | static void |
330 | pam_message_finalize (PAMConversationMessage *message) |
331 | { |
332 | @@ -734,9 +955,7 @@ |
333 | for (menu_iter = menu_items; menu_iter != NULL; menu_iter = g_list_next(menu_iter)) |
334 | { |
335 | if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_iter->data))) |
336 | - { |
337 | return g_strdup(g_object_get_data (G_OBJECT (menu_iter->data), LANGUAGE_DATA_CODE)); |
338 | - } |
339 | } |
340 | |
341 | return NULL; |
342 | @@ -792,7 +1011,9 @@ |
343 | { |
344 | if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menu_iter->data))) |
345 | { |
346 | - gtk_menu_item_set_label (GTK_MENU_ITEM (language_menuitem), g_strdup (g_object_get_data (G_OBJECT (menu_iter->data), LANGUAGE_DATA_CODE))); |
347 | + gtk_menu_item_set_label (GTK_MENU_ITEM (language_menuitem), |
348 | + g_strdup (g_object_get_data (G_OBJECT (menu_iter->data), |
349 | + LANGUAGE_DATA_CODE))); |
350 | break; |
351 | } |
352 | } |
353 | @@ -870,6 +1091,7 @@ |
354 | |
355 | if (username) |
356 | user = lightdm_user_list_get_user_by_name (lightdm_user_list_get_instance (), username); |
357 | + |
358 | if (user) |
359 | { |
360 | path = lightdm_user_get_image (user); |
361 | @@ -896,7 +1118,6 @@ |
362 | gtk_image_set_from_icon_name (GTK_IMAGE (user_image), default_user_icon, GTK_ICON_SIZE_DIALOG); |
363 | } |
364 | |
365 | -/* Function translate user defined coordinates to absolute value */ |
366 | static gint |
367 | get_absolute_position (const DimensionPosition *p, gint screen, gint window) |
368 | { |
369 | @@ -987,7 +1208,7 @@ |
370 | |
371 | region = gdk_region_rectangle (&rect); |
372 | |
373 | - while(x >= y) |
374 | + while (x >= y) |
375 | { |
376 | |
377 | rect.x = -x + radius; |
378 | @@ -1002,12 +1223,12 @@ |
379 | rect.width = y - radius + width - rect.x; |
380 | rect.height = x - radius + height - rect.y; |
381 | |
382 | - gdk_region_union_with_rect(region, &rect); |
383 | + gdk_region_union_with_rect (region, &rect); |
384 | |
385 | y++; |
386 | radiusError += yChange; |
387 | yChange += 2; |
388 | - if(((radiusError << 1) + xChange) > 0) |
389 | + if (((radiusError << 1) + xChange) > 0) |
390 | { |
391 | x--; |
392 | radiusError += xChange; |
393 | @@ -1025,9 +1246,10 @@ |
394 | |
395 | GdkWindow *window = gtk_widget_get_window (widget); |
396 | if (window_region) |
397 | - gdk_region_destroy(window_region); |
398 | + gdk_region_destroy (window_region); |
399 | window_region = cairo_region_from_rectangle (allocation->width, allocation->height, radius); |
400 | - if (window) { |
401 | + if (window) |
402 | + { |
403 | gdk_window_shape_combine_region(window, window_region, 0, 0); |
404 | gdk_window_input_shape_combine_region(window, window_region, 0, 0); |
405 | } |
406 | @@ -1053,10 +1275,6 @@ |
407 | static void |
408 | start_authentication (const gchar *username) |
409 | { |
410 | - gchar *data; |
411 | - gsize data_length; |
412 | - GError *error = NULL; |
413 | - |
414 | cancelling = FALSE; |
415 | prompted = FALSE; |
416 | password_prompted = FALSE; |
417 | @@ -1069,18 +1287,7 @@ |
418 | } |
419 | |
420 | g_key_file_set_value (state, "greeter", "last-user", username); |
421 | - data = g_key_file_to_data (state, &data_length, &error); |
422 | - if (error) |
423 | - g_warning ("Failed to save state file: %s", error->message); |
424 | - g_clear_error (&error); |
425 | - if (data) |
426 | - { |
427 | - g_file_set_contents (state_filename, data, data_length, &error); |
428 | - if (error) |
429 | - g_warning ("Failed to save state file: %s", error->message); |
430 | - g_clear_error (&error); |
431 | - } |
432 | - g_free (data); |
433 | + save_state_file (); |
434 | |
435 | if (g_strcmp0 (username, "*other") == 0) |
436 | { |
437 | @@ -1163,9 +1370,6 @@ |
438 | { |
439 | gchar *language; |
440 | gchar *session; |
441 | - gchar *data; |
442 | - gsize data_length; |
443 | - GError *error = NULL; |
444 | |
445 | language = get_language (); |
446 | if (language) |
447 | @@ -1176,19 +1380,7 @@ |
448 | |
449 | /* Remember last choice */ |
450 | g_key_file_set_value (state, "greeter", "last-session", session); |
451 | - |
452 | - data = g_key_file_to_data (state, &data_length, &error); |
453 | - if (error) |
454 | - g_warning ("Failed to save state file: %s", error->message); |
455 | - g_clear_error (&error); |
456 | - if (data) |
457 | - { |
458 | - g_file_set_contents (state_filename, data, data_length, &error); |
459 | - if (error) |
460 | - g_warning ("Failed to save state file: %s", error->message); |
461 | - g_clear_error (&error); |
462 | - } |
463 | - g_free (data); |
464 | + save_state_file (); |
465 | |
466 | if (!lightdm_greeter_start_session_sync (greeter, session, NULL)) |
467 | { |
468 | @@ -1851,82 +2043,26 @@ |
469 | } |
470 | } |
471 | |
472 | -static void |
473 | -keyboard_terminated_cb (GPid pid, gint status, gpointer user_data) |
474 | +void a11y_keyboard_cb (GtkCheckMenuItem *item, gpointer user_data); |
475 | +G_MODULE_EXPORT |
476 | +void |
477 | +a11y_keyboard_cb (GtkCheckMenuItem *item, gpointer user_data) |
478 | { |
479 | - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (keyboard_menuitem), FALSE); |
480 | + if (gtk_check_menu_item_get_active (item)) |
481 | + menu_command_run (a11y_keyboard_command); |
482 | + else |
483 | + menu_command_stop (a11y_keyboard_command); |
484 | } |
485 | |
486 | -void a11y_keyboard_cb (GtkCheckMenuItem *item); |
487 | +void a11y_reader_cb (GtkCheckMenuItem *item, gpointer user_data); |
488 | G_MODULE_EXPORT |
489 | void |
490 | -a11y_keyboard_cb (GtkCheckMenuItem *item) |
491 | +a11y_reader_cb (GtkCheckMenuItem *item, gpointer user_data) |
492 | { |
493 | if (gtk_check_menu_item_get_active (item)) |
494 | - { |
495 | - gboolean spawned = FALSE; |
496 | - if (onboard_window) |
497 | - { |
498 | - GtkSocket* socket = NULL; |
499 | - gint out_fd = 0; |
500 | - |
501 | - if (g_spawn_async_with_pipes (NULL, a11y_keyboard_command, NULL, G_SPAWN_SEARCH_PATH, |
502 | - NULL, NULL, &a11y_kbd_pid, NULL, &out_fd, NULL, |
503 | - &a11y_keyboard_error)) |
504 | - { |
505 | - gchar* text = NULL; |
506 | - GIOChannel* out_channel = g_io_channel_unix_new (out_fd); |
507 | - if (g_io_channel_read_line(out_channel, &text, NULL, NULL, &a11y_keyboard_error) == G_IO_STATUS_NORMAL) |
508 | - { |
509 | - gchar* end_ptr = NULL; |
510 | - |
511 | - text = g_strstrip (text); |
512 | - gint id = g_ascii_strtoll (text, &end_ptr, 0); |
513 | - |
514 | - if (id != 0 && end_ptr > text) |
515 | - { |
516 | - socket = GTK_SOCKET (gtk_socket_new ()); |
517 | - gtk_container_add (GTK_CONTAINER (onboard_window), GTK_WIDGET (socket)); |
518 | - gtk_socket_add_id (socket, id); |
519 | - gtk_widget_show_all (GTK_WIDGET (onboard_window)); |
520 | - spawned = TRUE; |
521 | - } |
522 | - else |
523 | - g_debug ("onboard keyboard command error : 'unrecognized output'"); |
524 | - |
525 | - g_free(text); |
526 | - } |
527 | - } |
528 | - } |
529 | - else |
530 | - { |
531 | - spawned = g_spawn_async (NULL, a11y_keyboard_command, NULL, |
532 | - G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, |
533 | - NULL, NULL, &a11y_kbd_pid, &a11y_keyboard_error); |
534 | - if (spawned) |
535 | - g_child_watch_add (a11y_kbd_pid, keyboard_terminated_cb, NULL); |
536 | - } |
537 | - |
538 | - if(!spawned) |
539 | - { |
540 | - if (a11y_keyboard_error) |
541 | - g_debug ("a11y keyboard command error : '%s'", a11y_keyboard_error->message); |
542 | - a11y_kbd_pid = 0; |
543 | - g_clear_error(&a11y_keyboard_error); |
544 | - gtk_check_menu_item_set_active (item, FALSE); |
545 | - } |
546 | - } |
547 | + menu_command_run (a11y_reader_command); |
548 | else |
549 | - { |
550 | - if (a11y_kbd_pid != 0) |
551 | - { |
552 | - kill (a11y_kbd_pid, SIGTERM); |
553 | - g_spawn_close_pid (a11y_kbd_pid); |
554 | - a11y_kbd_pid = 0; |
555 | - if (onboard_window) |
556 | - gtk_widget_hide (GTK_WIDGET(onboard_window)); |
557 | - } |
558 | - } |
559 | + menu_command_stop (a11y_reader_command); |
560 | } |
561 | |
562 | static void |
563 | @@ -2320,7 +2456,8 @@ |
564 | focus_upon_map (GdkXEvent *gxevent, GdkEvent *event, gpointer data) |
565 | { |
566 | XEvent* xevent = (XEvent*)gxevent; |
567 | - GdkWindow* keyboard_win = onboard_window ? gtk_widget_get_window (GTK_WIDGET (onboard_window)) : NULL; |
568 | + GdkWindow* keyboard_win = a11y_keyboard_command && a11y_keyboard_command->widget ? |
569 | + gtk_widget_get_window (GTK_WIDGET (a11y_keyboard_command->widget)) : NULL; |
570 | if (xevent->type == MapNotify) |
571 | { |
572 | Window xwin = xevent->xmap.window; |
573 | @@ -2343,11 +2480,8 @@ |
574 | { |
575 | gdk_window_focus (win, GDK_CURRENT_TIME); |
576 | /* Make sure to keep keyboard above */ |
577 | - if (onboard_window) |
578 | - { |
579 | - if (keyboard_win) |
580 | - gdk_window_raise (keyboard_win); |
581 | - } |
582 | + if (keyboard_win) |
583 | + gdk_window_raise (keyboard_win); |
584 | } |
585 | } |
586 | else if (xevent->type == UnmapNotify) |
587 | @@ -2360,11 +2494,8 @@ |
588 | { |
589 | gdk_window_focus (gtk_widget_get_window (GTK_WIDGET (login_window)), GDK_CURRENT_TIME); |
590 | /* Make sure to keep keyboard above */ |
591 | - if (onboard_window) |
592 | - { |
593 | - if (keyboard_win) |
594 | - gdk_window_raise (keyboard_win); |
595 | - } |
596 | + if (keyboard_win) |
597 | + gdk_window_raise (keyboard_win); |
598 | } |
599 | } |
600 | return GDK_FILTER_CONTINUE; |
601 | @@ -2553,7 +2684,7 @@ |
602 | const GList *items, *item; |
603 | GtkCellRenderer *renderer; |
604 | GtkWidget *image, *infobar_compat, *content_area; |
605 | - gchar *value, *state_dir; |
606 | + gchar *value, **values, *state_dir; |
607 | #if GTK_CHECK_VERSION (3, 0, 0) |
608 | GdkRGBA background_color; |
609 | GtkIconTheme *icon_theme; |
610 | @@ -2734,15 +2865,7 @@ |
611 | if (value) |
612 | g_object_set (gtk_settings_get_default (), "gtk-xft-rgba", value, NULL); |
613 | g_free (value); |
614 | - |
615 | - /* Get a11y on screen keyboard command*/ |
616 | - gint argp; |
617 | - value = g_key_file_get_value (config, "greeter", "keyboard", NULL); |
618 | - g_debug ("a11y keyboard command is '%s'", value); |
619 | - /* Set NULL to blank to avoid warnings */ |
620 | - if (!value) { value = g_strdup(""); } |
621 | - g_shell_parse_argv (value, &argp, &a11y_keyboard_command, NULL); |
622 | - g_free (value); |
623 | + |
624 | |
625 | builder = gtk_builder_new (); |
626 | if (!gtk_builder_add_from_string (builder, lightdm_gtk_greeter_ui, |
627 | @@ -2816,16 +2939,20 @@ |
628 | language_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "language_menuitem")); |
629 | language_menu = GTK_MENU(gtk_builder_get_object (builder, "language_menu")); |
630 | a11y_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "a11y_menuitem")); |
631 | + contrast_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "high_contrast_menuitem")); |
632 | + font_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "large_font_menuitem")); |
633 | + keyboard_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "keyboard_menuitem")); |
634 | + reader_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "reader_menuitem")); |
635 | power_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "power_menuitem")); |
636 | layout_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "layout_menuitem")); |
637 | layout_menu = GTK_MENU(gtk_builder_get_object (builder, "layout_menu")); |
638 | - keyboard_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "keyboard_menuitem")); |
639 | clock_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "clock_menuitem")); |
640 | host_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "host_menuitem")); |
641 | |
642 | gtk_accel_map_add_entry ("<Login>/a11y/font", GDK_KEY_F1, 0); |
643 | gtk_accel_map_add_entry ("<Login>/a11y/contrast", GDK_KEY_F2, 0); |
644 | gtk_accel_map_add_entry ("<Login>/a11y/keyboard", GDK_KEY_F3, 0); |
645 | + gtk_accel_map_add_entry ("<Login>/a11y/reader", GDK_KEY_F4, 0); |
646 | gtk_accel_map_add_entry ("<Login>/power/shutdown", GDK_KEY_F4, GDK_MOD1_MASK); |
647 | |
648 | #ifdef START_INDICATOR_SERVICES |
649 | @@ -2934,6 +3061,20 @@ |
650 | gtk_container_add (GTK_CONTAINER (a11y_menuitem), image); |
651 | } |
652 | |
653 | + value = g_key_file_get_value (config, "greeter", "keyboard", NULL); |
654 | + a11y_keyboard_command = menu_command_parse_extended (value, keyboard_menuitem, "onboard", "--xid", |
655 | + &ONBOARD_WINDOW_SIZE); |
656 | + g_free (value); |
657 | + |
658 | + gtk_widget_set_visible (keyboard_menuitem, a11y_keyboard_command != NULL); |
659 | + if (a11y_keyboard_command) |
660 | + g_signal_connect (a11y_keyboard_command->widget, "size-allocate", G_CALLBACK (center_window), (gpointer)&ONBOARD_WINDOW_POS); |
661 | + |
662 | + value = g_key_file_get_value (config, "greeter", "reader", NULL); |
663 | + a11y_reader_command = menu_command_parse (value, reader_menuitem); |
664 | + gtk_widget_set_visible (reader_menuitem, a11y_reader_command != NULL); |
665 | + g_free (value); |
666 | + |
667 | /* Power menu */ |
668 | if (gtk_widget_get_visible (power_menuitem)) |
669 | { |
670 | @@ -3115,22 +3256,44 @@ |
671 | gtk_widget_show (GTK_WIDGET (login_window)); |
672 | gdk_window_focus (gtk_widget_get_window (GTK_WIDGET (login_window)), GDK_CURRENT_TIME); |
673 | |
674 | - if (a11y_keyboard_command) |
675 | + values = g_key_file_get_string_list (config, "greeter", "a11y-states", NULL, NULL); |
676 | + if (values && *values) |
677 | { |
678 | - /* If command is onboard, position the application at the bottom-center of the screen */ |
679 | - if (g_strcmp0(a11y_keyboard_command[0], "onboard") == 0) |
680 | + GHashTable *items = g_hash_table_new (g_str_hash, g_str_equal); |
681 | + g_hash_table_insert (items, "contrast", contrast_menuitem); |
682 | + g_hash_table_insert (items, "font", font_menuitem); |
683 | + g_hash_table_insert (items, "keyboard", keyboard_menuitem); |
684 | + g_hash_table_insert (items, "reader", reader_menuitem); |
685 | + |
686 | + gpointer item; |
687 | + gchar **values_iter; |
688 | + for (values_iter = values; *values_iter; ++values_iter) |
689 | { |
690 | - gint argp; |
691 | - value = "onboard --xid"; |
692 | - g_debug ("a11y keyboard command is now '%s'", value); |
693 | - g_shell_parse_argv (value, &argp, &a11y_keyboard_command, NULL); |
694 | - onboard_window = GTK_WINDOW (gtk_window_new(GTK_WINDOW_TOPLEVEL)); |
695 | - gtk_widget_set_size_request (GTK_WIDGET (onboard_window), 605, 205); |
696 | - gtk_window_move (onboard_window, (monitor_geometry.width - 605)/2, monitor_geometry.height - 205); |
697 | + value = *values_iter; |
698 | + switch (value[0]) |
699 | + { |
700 | + case '-': |
701 | + continue; |
702 | + case '+': |
703 | + if (g_hash_table_lookup_extended (items, &value[1], NULL, &item) && |
704 | + gtk_widget_get_visible (GTK_WIDGET (item))) |
705 | + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE); |
706 | + break; |
707 | + case '~': |
708 | + value++; |
709 | + default: |
710 | + if (g_hash_table_lookup_extended (items, value, NULL, &item) && |
711 | + gtk_widget_get_visible (GTK_WIDGET (item))) |
712 | + { |
713 | + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), |
714 | + g_key_file_get_boolean (state, "a11y-states", value, NULL)); |
715 | + g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (a11y_menuitem_toggled_cb), g_strdup (value)); |
716 | + } |
717 | + } |
718 | } |
719 | + g_hash_table_unref (items); |
720 | } |
721 | - gtk_widget_set_sensitive (keyboard_menuitem, a11y_keyboard_command != NULL); |
722 | - gtk_widget_set_visible (keyboard_menuitem, a11y_keyboard_command != NULL); |
723 | + g_strfreev (values); |
724 | |
725 | /* focus fix (source: unity-greeter) */ |
726 | GdkWindow* root_window = gdk_get_default_root_window (); |
727 | |
728 | === modified file 'src/lightdm-gtk-greeter.glade' |
729 | --- src/lightdm-gtk-greeter.glade 2014-06-09 16:14:37 +0000 |
730 | +++ src/lightdm-gtk-greeter.glade 2014-07-07 12:35:18 +0000 |
731 | @@ -108,6 +108,17 @@ |
732 | <signal name="toggled" handler="a11y_keyboard_cb" swapped="no"/> |
733 | </object> |
734 | </child> |
735 | + <child> |
736 | + <object class="GtkCheckMenuItem" id="reader_menuitem"> |
737 | + <property name="use_action_appearance">False</property> |
738 | + <property name="visible">True</property> |
739 | + <property name="can_focus">False</property> |
740 | + <property name="accel_path"><Login>/a11y/reader</property> |
741 | + <property name="label" translatable="yes">Screen Reader</property> |
742 | + <property name="use_underline">True</property> |
743 | + <signal name="toggled" handler="a11y_reader_cb" swapped="no"/> |
744 | + </object> |
745 | + </child> |
746 | </object> |
747 | </child> |
748 | </object> |
This is sane and good for accessibility. Approve.