~ubuntu-branches/ubuntu/precise/gnome-control-center/precise-updates

« back to all changes in this revision

Viewing changes to panels/region/gnome-region-panel-xkbot.c

Tags: upstream-3.0.1.1
ImportĀ upstreamĀ versionĀ 3.0.1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* gnome-region-panel-xkbot.c
 
2
 * Copyright (C) 2003-2007 Sergey V. Udaltsov
 
3
 *
 
4
 * Written by: Sergey V. Udaltsov <svu@gnome.org>
 
5
 *             John Spray <spray_john@users.sourceforge.net>
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License as published by
 
9
 * the Free Software Foundation; either version 2, or (at your option)
 
10
 * any later version.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, write to the Free Software
 
19
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
20
 * 02111-1307, USA.
 
21
 */
 
22
 
 
23
#ifdef HAVE_CONFIG_H
 
24
#  include <config.h>
 
25
#endif
 
26
 
 
27
#include <glib/gi18n.h>
 
28
#include <string.h>
 
29
 
 
30
#include "gnome-region-panel-xkb.h"
 
31
 
 
32
static GtkBuilder *chooser_dialog = NULL;
 
33
static const char *current1st_level_id = NULL;
 
34
static GSList *option_checks_list = NULL;
 
35
static GtkWidget *current_none_radio = NULL;
 
36
static GtkWidget *current_expander = NULL;
 
37
static gboolean current_multi_select = FALSE;
 
38
static GSList *current_radio_group = NULL;
 
39
 
 
40
#define OPTION_ID_PROP "optionID"
 
41
#define SELCOUNTER_PROP "selectionCounter"
 
42
#define GCONFSTATE_PROP "gconfState"
 
43
#define EXPANDERS_PROP "expandersList"
 
44
 
 
45
gchar **
 
46
xkb_options_get_selected_list (void)
 
47
{
 
48
        gchar **retval;
 
49
 
 
50
        retval =
 
51
            g_settings_get_strv (xkb_keyboard_settings,
 
52
                                 GKBD_KEYBOARD_CONFIG_KEY_OPTIONS);
 
53
        if (retval == NULL) {
 
54
                retval = g_strdupv (initial_config.options);
 
55
        }
 
56
 
 
57
        return retval;
 
58
}
 
59
 
 
60
/* Returns the selection counter of the expander (static current_expander) */
 
61
static int
 
62
xkb_options_expander_selcounter_get (void)
 
63
{
 
64
        return
 
65
            GPOINTER_TO_INT (g_object_get_data
 
66
                             (G_OBJECT (current_expander),
 
67
                              SELCOUNTER_PROP));
 
68
}
 
69
 
 
70
/* Increments the selection counter in the expander (static current_expander) 
 
71
   using the value (can be 0)*/
 
72
static void
 
73
xkb_options_expander_selcounter_add (int value)
 
74
{
 
75
        g_object_set_data (G_OBJECT (current_expander), SELCOUNTER_PROP,
 
76
                           GINT_TO_POINTER
 
77
                           (xkb_options_expander_selcounter_get ()
 
78
                            + value));
 
79
}
 
80
 
 
81
/* Resets the seletion counter in the expander (static current_expander) */
 
82
static void
 
83
xkb_options_expander_selcounter_reset (void)
 
84
{
 
85
        g_object_set_data (G_OBJECT (current_expander), SELCOUNTER_PROP,
 
86
                           GINT_TO_POINTER (0));
 
87
}
 
88
 
 
89
/* Formats the expander (static current_expander), based on the selection counter */
 
90
static void
 
91
xkb_options_expander_highlight (void)
 
92
{
 
93
        char *utf_group_name =
 
94
            g_object_get_data (G_OBJECT (current_expander),
 
95
                               "utfGroupName");
 
96
        int counter = xkb_options_expander_selcounter_get ();
 
97
        if (utf_group_name != NULL) {
 
98
                gchar *titlemarkup =
 
99
                    g_strconcat (counter >
 
100
                                 0 ? "<span weight=\"bold\">" : "<span>",
 
101
                                 utf_group_name, "</span>", NULL);
 
102
                gtk_expander_set_label (GTK_EXPANDER (current_expander),
 
103
                                        titlemarkup);
 
104
                g_free (titlemarkup);
 
105
        }
 
106
}
 
107
 
 
108
/* Add optionname from the backend's selection list if it's not
 
109
   already in there. */
 
110
static void
 
111
xkb_options_select (gchar * optionname)
 
112
{
 
113
        gboolean already_selected = FALSE;
 
114
        gchar **options_list;
 
115
        guint i;
 
116
 
 
117
        options_list = xkb_options_get_selected_list ();
 
118
        for (i = 0; options_list != NULL && options_list[i] != NULL; i++) {
 
119
                gchar *option = options_list[i];
 
120
                if (!strcmp (option, optionname)) {
 
121
                        already_selected = TRUE;
 
122
                        break;
 
123
                }
 
124
        }
 
125
 
 
126
        if (!already_selected) {
 
127
                options_list =
 
128
                    gkbd_strv_append (options_list, g_strdup (optionname));
 
129
                xkb_options_set_selected_list (options_list);
 
130
        }
 
131
 
 
132
        g_strfreev (options_list);
 
133
}
 
134
 
 
135
/* Remove all occurences of optionname from the backend's selection list */
 
136
static void
 
137
xkb_options_deselect (gchar * optionname)
 
138
{
 
139
        gchar **options_list = xkb_options_get_selected_list ();
 
140
        if (options_list != NULL) {
 
141
                gchar **option = options_list;
 
142
                while (*option != NULL) {
 
143
                        gchar *id = *option;
 
144
                        if (!strcmp (id, optionname)) {
 
145
                                gkbd_strv_behead (option);
 
146
                        } else
 
147
                                option++;
 
148
                }
 
149
                xkb_options_set_selected_list (options_list);
 
150
        }
 
151
        g_strfreev (options_list);
 
152
}
 
153
 
 
154
/* Return true if optionname describes a string already in the backend's
 
155
   list of selected options */
 
156
static gboolean
 
157
xkb_options_is_selected (gchar * optionname)
 
158
{
 
159
        gboolean retval = FALSE;
 
160
        gchar **options_list = xkb_options_get_selected_list ();
 
161
        if (options_list != NULL) {
 
162
                gchar **option = options_list;
 
163
                while (*option != NULL) {
 
164
                        if (!strcmp (*option, optionname)) {
 
165
                                retval = TRUE;
 
166
                                break;
 
167
                        }
 
168
                        option++;
 
169
                }
 
170
        }
 
171
        g_strfreev (options_list);
 
172
        return retval;
 
173
}
 
174
 
 
175
/* Make sure selected options stay visible when navigating with the keyboard */
 
176
static gboolean
 
177
option_focused_cb (GtkWidget * widget, GdkEventFocus * event,
 
178
                   gpointer data)
 
179
{
 
180
        GtkScrolledWindow *win = GTK_SCROLLED_WINDOW (data);
 
181
        GtkAllocation alloc;
 
182
        GtkAdjustment *adj;
 
183
 
 
184
        gtk_widget_get_allocation (widget, &alloc);
 
185
        adj = gtk_scrolled_window_get_vadjustment (win);
 
186
        gtk_adjustment_clamp_page (adj, alloc.y, alloc.y + alloc.height);
 
187
 
 
188
        return FALSE;
 
189
}
 
190
 
 
191
/* Update xkb backend to reflect the new UI state */
 
192
static void
 
193
option_toggled_cb (GtkWidget * checkbutton, gpointer data)
 
194
{
 
195
        gpointer optionID =
 
196
            g_object_get_data (G_OBJECT (checkbutton), OPTION_ID_PROP);
 
197
        if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbutton)))
 
198
                xkb_options_select (optionID);
 
199
        else
 
200
                xkb_options_deselect (optionID);
 
201
}
 
202
 
 
203
/* Add a check_button or radio_button to control a particular option
 
204
   This function makes particular use of the current... variables at
 
205
   the top of this file. */
 
206
static void
 
207
xkb_options_add_option (XklConfigRegistry * config_registry,
 
208
                        XklConfigItem * config_item, GtkBuilder * dialog)
 
209
{
 
210
        GtkWidget *option_check;
 
211
        gchar *utf_option_name = xci_desc_to_utf8 (config_item);
 
212
        /* Copy this out because we'll load it into the widget with set_data */
 
213
        gchar *full_option_name =
 
214
            g_strdup (gkbd_keyboard_config_merge_items
 
215
                      (current1st_level_id, config_item->name));
 
216
        gboolean initial_state;
 
217
 
 
218
        if (current_multi_select)
 
219
                option_check =
 
220
                    gtk_check_button_new_with_label (utf_option_name);
 
221
        else {
 
222
                if (current_radio_group == NULL) {
 
223
                        /* The first radio in a group is to be "Default", meaning none of
 
224
                           the below options are to be included in the selected list.
 
225
                           This is a HIG-compliant alternative to allowing no
 
226
                           selection in the group. */
 
227
                        option_check =
 
228
                            gtk_radio_button_new_with_label
 
229
                            (current_radio_group, _("Default"));
 
230
                        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
 
231
                                                      (option_check),
 
232
                                                      TRUE);
 
233
                        /* Make option name underscore - 
 
234
                           to enforce its first position in the list */
 
235
                        g_object_set_data_full (G_OBJECT (option_check),
 
236
                                                "utfOptionName",
 
237
                                                g_strdup (" "), g_free);
 
238
                        option_checks_list =
 
239
                            g_slist_append (option_checks_list,
 
240
                                            option_check);
 
241
                        current_radio_group =
 
242
                            gtk_radio_button_get_group (GTK_RADIO_BUTTON
 
243
                                                        (option_check));
 
244
                        current_none_radio = option_check;
 
245
 
 
246
                        g_signal_connect (option_check, "focus-in-event",
 
247
                                          G_CALLBACK (option_focused_cb),
 
248
                                          WID ("options_scroll"));
 
249
                }
 
250
                option_check =
 
251
                    gtk_radio_button_new_with_label (current_radio_group,
 
252
                                                     utf_option_name);
 
253
                current_radio_group =
 
254
                    gtk_radio_button_get_group (GTK_RADIO_BUTTON
 
255
                                                (option_check));
 
256
                g_object_set_data (G_OBJECT (option_check), "NoneRadio",
 
257
                                   current_none_radio);
 
258
        }
 
259
 
 
260
        initial_state = xkb_options_is_selected (full_option_name);
 
261
 
 
262
        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (option_check),
 
263
                                      initial_state);
 
264
 
 
265
        g_object_set_data_full (G_OBJECT (option_check), OPTION_ID_PROP,
 
266
                                full_option_name, g_free);
 
267
        g_object_set_data_full (G_OBJECT (option_check), "utfOptionName",
 
268
                                utf_option_name, g_free);
 
269
 
 
270
        g_signal_connect (option_check, "toggled",
 
271
                          G_CALLBACK (option_toggled_cb), NULL);
 
272
 
 
273
        option_checks_list =
 
274
            g_slist_append (option_checks_list, option_check);
 
275
 
 
276
        g_signal_connect (option_check, "focus-in-event",
 
277
                          G_CALLBACK (option_focused_cb),
 
278
                          WID ("options_scroll"));
 
279
 
 
280
        xkb_options_expander_selcounter_add (initial_state);
 
281
        g_object_set_data (G_OBJECT (option_check), GCONFSTATE_PROP,
 
282
                           GINT_TO_POINTER (initial_state));
 
283
}
 
284
 
 
285
static gint
 
286
xkb_option_checks_compare (GtkWidget * chk1, GtkWidget * chk2)
 
287
{
 
288
        const gchar *t1 =
 
289
            g_object_get_data (G_OBJECT (chk1), "utfOptionName");
 
290
        const gchar *t2 =
 
291
            g_object_get_data (G_OBJECT (chk2), "utfOptionName");
 
292
        return g_utf8_collate (t1, t2);
 
293
}
 
294
 
 
295
/* Add a group of options: create title and layout widgets and then
 
296
   add widgets for all the options in the group. */
 
297
static void
 
298
xkb_options_add_group (XklConfigRegistry * config_registry,
 
299
                       XklConfigItem * config_item, GtkBuilder * dialog)
 
300
{
 
301
        GtkWidget *align, *vbox, *option_check;
 
302
        gboolean allow_multiple_selection =
 
303
            GPOINTER_TO_INT (g_object_get_data (G_OBJECT (config_item),
 
304
                                                XCI_PROP_ALLOW_MULTIPLE_SELECTION));
 
305
 
 
306
        GSList *expanders_list =
 
307
            g_object_get_data (G_OBJECT (dialog), EXPANDERS_PROP);
 
308
 
 
309
        gchar *utf_group_name = xci_desc_to_utf8 (config_item);
 
310
        gchar *titlemarkup =
 
311
            g_strconcat ("<span>", utf_group_name, "</span>", NULL);
 
312
 
 
313
        current_expander = gtk_expander_new (titlemarkup);
 
314
        gtk_expander_set_use_markup (GTK_EXPANDER (current_expander),
 
315
                                     TRUE);
 
316
        g_object_set_data_full (G_OBJECT (current_expander),
 
317
                                "utfGroupName", utf_group_name, g_free);
 
318
        g_object_set_data_full (G_OBJECT (current_expander), "groupId",
 
319
                                g_strdup (config_item->name), g_free);
 
320
 
 
321
        g_free (titlemarkup);
 
322
        align = gtk_alignment_new (0, 0, 1, 1);
 
323
        gtk_alignment_set_padding (GTK_ALIGNMENT (align), 6, 12, 12, 0);
 
324
        vbox = gtk_vbox_new (TRUE, 6);
 
325
        gtk_container_add (GTK_CONTAINER (align), vbox);
 
326
        gtk_container_add (GTK_CONTAINER (current_expander), align);
 
327
 
 
328
        current_multi_select = (gboolean) allow_multiple_selection;
 
329
        current_radio_group = NULL;
 
330
        current1st_level_id = config_item->name;
 
331
 
 
332
        option_checks_list = NULL;
 
333
 
 
334
        xkl_config_registry_foreach_option (config_registry,
 
335
                                            config_item->name,
 
336
                                            (ConfigItemProcessFunc)
 
337
                                            xkb_options_add_option,
 
338
                                            dialog);
 
339
        /* sort it */
 
340
        option_checks_list =
 
341
            g_slist_sort (option_checks_list,
 
342
                          (GCompareFunc) xkb_option_checks_compare);
 
343
        while (option_checks_list) {
 
344
                option_check = GTK_WIDGET (option_checks_list->data);
 
345
                gtk_box_pack_start (GTK_BOX (vbox), option_check, TRUE,
 
346
                                    TRUE, 0);
 
347
                option_checks_list = option_checks_list->next;
 
348
        }
 
349
        /* free it */
 
350
        g_slist_free (option_checks_list);
 
351
        option_checks_list = NULL;
 
352
 
 
353
        xkb_options_expander_highlight ();
 
354
 
 
355
        expanders_list = g_slist_append (expanders_list, current_expander);
 
356
        g_object_set_data (G_OBJECT (dialog), EXPANDERS_PROP,
 
357
                           expanders_list);
 
358
 
 
359
        g_signal_connect (current_expander, "focus-in-event",
 
360
                          G_CALLBACK (option_focused_cb),
 
361
                          WID ("options_scroll"));
 
362
}
 
363
 
 
364
static gint
 
365
xkb_options_expanders_compare (GtkWidget * expander1,
 
366
                               GtkWidget * expander2)
 
367
{
 
368
        const gchar *t1 =
 
369
            g_object_get_data (G_OBJECT (expander1), "utfGroupName");
 
370
        const gchar *t2 =
 
371
            g_object_get_data (G_OBJECT (expander2), "utfGroupName");
 
372
        return g_utf8_collate (t1, t2);
 
373
}
 
374
 
 
375
/* Create widgets to represent the options made available by the backend */
 
376
void
 
377
xkb_options_load_options (GtkBuilder * dialog)
 
378
{
 
379
        GtkWidget *opts_vbox = WID ("options_vbox");
 
380
        GtkWidget *dialog_vbox = WID ("dialog_vbox");
 
381
        GtkWidget *options_scroll = WID ("options_scroll");
 
382
        GtkWidget *expander;
 
383
        GSList *expanders_list;
 
384
 
 
385
        current1st_level_id = NULL;
 
386
        current_none_radio = NULL;
 
387
        current_multi_select = FALSE;
 
388
        current_radio_group = NULL;
 
389
 
 
390
        /* fill the list */
 
391
        xkl_config_registry_foreach_option_group (config_registry,
 
392
                                                  (ConfigItemProcessFunc)
 
393
                                                  xkb_options_add_group,
 
394
                                                  dialog);
 
395
        /* sort it */
 
396
        expanders_list =
 
397
            g_object_get_data (G_OBJECT (dialog), EXPANDERS_PROP);
 
398
        expanders_list =
 
399
            g_slist_sort (expanders_list,
 
400
                          (GCompareFunc) xkb_options_expanders_compare);
 
401
        g_object_set_data (G_OBJECT (dialog), EXPANDERS_PROP,
 
402
                           expanders_list);
 
403
        while (expanders_list) {
 
404
                expander = GTK_WIDGET (expanders_list->data);
 
405
                gtk_box_pack_start (GTK_BOX (opts_vbox), expander, FALSE,
 
406
                                    FALSE, 0);
 
407
                expanders_list = expanders_list->next;
 
408
        }
 
409
 
 
410
        /* Somewhere in gtk3 the top vbox in dialog is made non-expandable */
 
411
        gtk_box_set_child_packing (GTK_BOX (dialog_vbox), options_scroll,
 
412
                                   TRUE, TRUE, 0, GTK_PACK_START);
 
413
        gtk_widget_show_all (dialog_vbox);
 
414
}
 
415
 
 
416
static void
 
417
chooser_response_cb (GtkDialog * dialog, gint response, gpointer data)
 
418
{
 
419
        switch (response) {
 
420
        case GTK_RESPONSE_DELETE_EVENT:
 
421
        case GTK_RESPONSE_CLOSE: {
 
422
                        /* just cleanup */
 
423
                        GSList *expanders_list =
 
424
                            g_object_get_data (G_OBJECT (dialog),
 
425
                                               EXPANDERS_PROP);
 
426
                        g_object_set_data (G_OBJECT (dialog),
 
427
                                           EXPANDERS_PROP, NULL);
 
428
                        g_slist_free (expanders_list);
 
429
 
 
430
                        gtk_widget_destroy (GTK_WIDGET (dialog));
 
431
                        chooser_dialog = NULL;
 
432
                }
 
433
                break;
 
434
        }
 
435
}
 
436
 
 
437
/* Create popup dialog */
 
438
void
 
439
xkb_options_popup_dialog (GtkBuilder * dialog)
 
440
{
 
441
        GtkWidget *chooser;
 
442
 
 
443
        chooser_dialog = gtk_builder_new ();
 
444
        gtk_builder_add_from_file (chooser_dialog, GNOMECC_UI_DIR
 
445
                                   "/gnome-region-panel-options-dialog.ui",
 
446
                                   NULL);
 
447
 
 
448
        chooser = CWID ("xkb_options_dialog");
 
449
        gtk_window_set_transient_for (GTK_WINDOW (chooser),
 
450
                                      GTK_WINDOW (gtk_widget_get_toplevel (WID ("region_notebook"))));
 
451
        gtk_window_set_modal (GTK_WINDOW (chooser), TRUE);
 
452
        xkb_options_load_options (chooser_dialog);
 
453
 
 
454
        g_signal_connect (chooser, "response",
 
455
                          G_CALLBACK (chooser_response_cb), dialog);
 
456
        gtk_widget_show (chooser);
 
457
}
 
458
 
 
459
/* Update selected option counters for a group-bound expander */
 
460
static void
 
461
xkb_options_update_option_counters (XklConfigRegistry * config_registry,
 
462
                                    XklConfigItem * config_item)
 
463
{
 
464
        gchar *full_option_name =
 
465
            g_strdup (gkbd_keyboard_config_merge_items
 
466
                      (current1st_level_id, config_item->name));
 
467
        gboolean current_state =
 
468
            xkb_options_is_selected (full_option_name);
 
469
        xkb_options_expander_selcounter_add (current_state);
 
470
}
 
471
 
 
472
/* Respond to a change in the xkb gconf settings */
 
473
static void
 
474
xkb_options_update (GSettings * settings, gchar * key, GtkBuilder * dialog)
 
475
{
 
476
        if (!strcmp (key, GKBD_KEYBOARD_CONFIG_KEY_OPTIONS)) {
 
477
                /* Updating options is handled by gconf notifies for each widget
 
478
                   This is here to avoid calling it N_OPTIONS times for each gconf
 
479
                   change. */
 
480
                enable_disable_restoring (dialog);
 
481
 
 
482
                if (chooser_dialog != NULL) {
 
483
                        GSList *expanders_list =
 
484
                            g_object_get_data (G_OBJECT (chooser_dialog),
 
485
                                               EXPANDERS_PROP);
 
486
                        while (expanders_list) {
 
487
                                current_expander =
 
488
                                    GTK_WIDGET (expanders_list->data);
 
489
                                gchar *group_id =
 
490
                                    g_object_get_data (G_OBJECT
 
491
                                                       (current_expander),
 
492
                                                       "groupId");
 
493
                                current1st_level_id = group_id;
 
494
                                xkb_options_expander_selcounter_reset ();
 
495
                                xkl_config_registry_foreach_option
 
496
                                    (config_registry, group_id,
 
497
                                     (ConfigItemProcessFunc)
 
498
                                     xkb_options_update_option_counters,
 
499
                                     current_expander);
 
500
                                xkb_options_expander_highlight ();
 
501
                                expanders_list = expanders_list->next;
 
502
                        }
 
503
                }
 
504
        }
 
505
}
 
506
 
 
507
void
 
508
xkb_options_register_conf_listener (GtkBuilder * dialog)
 
509
{
 
510
        g_signal_connect (xkb_keyboard_settings, "changed",
 
511
                          G_CALLBACK (xkb_options_update), dialog);
 
512
}