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

« back to all changes in this revision

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