2
* Copyright (C) 2012 Red Hat, Inc.
4
* Written by: Rui Matos <rmatos@redhat.com>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2, or (at your option)
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28
#include <X11/XKBlib.h>
29
#include <X11/extensions/XKBrules.h>
33
#include <glib/gi18n-lib.h>
34
#define XKEYBOARD_CONFIG_(String) ((char *) g_dgettext ("xkeyboard-config", String))
36
#define GNOME_DESKTOP_USE_UNSTABLE_API
37
#include "gnome-languages.h"
38
#include "gnome-xkb-info.h"
40
#ifndef XKB_RULES_FILE
41
#define XKB_RULES_FILE "evdev"
44
#define XKB_LAYOUT "us"
47
#define XKB_MODEL "pc105+inet"
50
typedef struct _Layout Layout;
58
const Layout *main_layout;
61
typedef struct _XkbOption XkbOption;
68
typedef struct _XkbOptionGroup XkbOptionGroup;
69
struct _XkbOptionGroup
73
gboolean allow_multiple_selection;
74
GHashTable *options_table;
77
struct _GnomeXkbInfoPrivate
79
GHashTable *option_groups_table;
80
GHashTable *layouts_by_country;
81
GHashTable *layouts_by_language;
82
GHashTable *layouts_table;
84
/* Only used while parsing */
85
XkbOptionGroup *current_parser_group;
86
XkbOption *current_parser_option;
87
Layout *current_parser_layout;
88
Layout *current_parser_variant;
89
gchar *current_parser_iso639Id;
90
gchar *current_parser_iso3166Id;
91
gchar **current_parser_text;
94
G_DEFINE_TYPE (GnomeXkbInfo, gnome_xkb_info, G_TYPE_OBJECT);
97
free_layout (gpointer data)
99
Layout *layout = data;
101
g_return_if_fail (layout != NULL);
104
g_free (layout->xkb_name);
105
g_free (layout->short_desc);
106
g_free (layout->description);
107
g_slice_free (Layout, layout);
111
free_option (gpointer data)
113
XkbOption *option = data;
115
g_return_if_fail (option != NULL);
118
g_free (option->description);
119
g_slice_free (XkbOption, option);
123
free_option_group (gpointer data)
125
XkbOptionGroup *group = data;
127
g_return_if_fail (group != NULL);
130
g_free (group->description);
131
g_hash_table_destroy (group->options_table);
132
g_slice_free (XkbOptionGroup, group);
136
* gnome_xkb_info_get_var_defs: (skip)
137
* @rules: (out) (transfer full): location to store the rules file
138
* path. Use g_free() when it's no longer needed
139
* @var_defs: (out) (transfer full): location to store a
140
* #XkbRF_VarDefsRec pointer. Use gnome_xkb_info_free_var_defs() to
143
* Gets both the XKB rules file path and the current XKB parameters in
144
* use by the X server.
149
gnome_xkb_info_get_var_defs (gchar **rules,
150
XkbRF_VarDefsRec **var_defs)
152
Display *display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
155
g_return_if_fail (rules != NULL);
156
g_return_if_fail (var_defs != NULL);
159
*var_defs = g_new0 (XkbRF_VarDefsRec, 1);
161
gdk_error_trap_push ();
163
/* Get it from the X property or fallback on defaults */
164
if (!XkbRF_GetNamesProp (display, rules, *var_defs) || !*rules)
166
*rules = strdup (XKB_RULES_FILE);
167
(*var_defs)->model = strdup (XKB_MODEL);
168
(*var_defs)->layout = strdup (XKB_LAYOUT);
169
(*var_defs)->variant = NULL;
170
(*var_defs)->options = NULL;
173
gdk_error_trap_pop_ignored ();
177
if (*rules[0] == '/')
178
*rules = g_strdup (*rules);
180
*rules = g_build_filename (XKB_BASE, "rules", *rules, NULL);
186
* gnome_xkb_info_free_var_defs: (skip)
187
* @var_defs: #XkbRF_VarDefsRec instance to free
189
* Frees an #XkbRF_VarDefsRec instance allocated by
190
* gnome_xkb_info_get_var_defs().
195
gnome_xkb_info_free_var_defs (XkbRF_VarDefsRec *var_defs)
197
g_return_if_fail (var_defs != NULL);
199
free (var_defs->model);
200
free (var_defs->layout);
201
free (var_defs->variant);
202
free (var_defs->options);
208
get_xml_rules_file_path (const gchar *suffix)
210
XkbRF_VarDefsRec *xkb_var_defs;
212
gchar *xml_rules_file;
214
gnome_xkb_info_get_var_defs (&rules_file, &xkb_var_defs);
215
gnome_xkb_info_free_var_defs (xkb_var_defs);
217
xml_rules_file = g_strdup_printf ("%s%s", rules_file, suffix);
220
return xml_rules_file;
224
parse_start_element (GMarkupParseContext *context,
225
const gchar *element_name,
226
const gchar **attribute_names,
227
const gchar **attribute_values,
231
GnomeXkbInfoPrivate *priv = GNOME_XKB_INFO (data)->priv;
233
if (priv->current_parser_text)
235
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
236
"Expected character data but got element '%s'", element_name);
240
if (strcmp (element_name, "name") == 0)
242
if (priv->current_parser_variant)
243
priv->current_parser_text = &priv->current_parser_variant->xkb_name;
244
else if (priv->current_parser_layout)
245
priv->current_parser_text = &priv->current_parser_layout->xkb_name;
246
else if (priv->current_parser_option)
247
priv->current_parser_text = &priv->current_parser_option->id;
248
else if (priv->current_parser_group)
249
priv->current_parser_text = &priv->current_parser_group->id;
251
else if (strcmp (element_name, "description") == 0)
253
if (priv->current_parser_variant)
254
priv->current_parser_text = &priv->current_parser_variant->description;
255
else if (priv->current_parser_layout)
256
priv->current_parser_text = &priv->current_parser_layout->description;
257
else if (priv->current_parser_option)
258
priv->current_parser_text = &priv->current_parser_option->description;
259
else if (priv->current_parser_group)
260
priv->current_parser_text = &priv->current_parser_group->description;
262
else if (strcmp (element_name, "shortDescription") == 0)
264
if (priv->current_parser_variant)
265
priv->current_parser_text = &priv->current_parser_variant->short_desc;
266
else if (priv->current_parser_layout)
267
priv->current_parser_text = &priv->current_parser_layout->short_desc;
269
else if (strcmp (element_name, "iso639Id") == 0)
271
priv->current_parser_text = &priv->current_parser_iso639Id;
273
else if (strcmp (element_name, "iso3166Id") == 0)
275
priv->current_parser_text = &priv->current_parser_iso3166Id;
277
else if (strcmp (element_name, "layout") == 0)
279
if (priv->current_parser_layout)
281
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
282
"'layout' elements can't be nested");
286
priv->current_parser_layout = g_slice_new0 (Layout);
288
else if (strcmp (element_name, "variant") == 0)
292
if (priv->current_parser_variant)
294
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
295
"'variant' elements can't be nested");
299
if (!priv->current_parser_layout)
301
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
302
"'variant' elements must be inside 'layout' elements");
306
if (!priv->current_parser_layout->xkb_name)
308
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
309
"'variant' elements must be inside named 'layout' elements");
313
layout = g_hash_table_lookup (priv->layouts_table, priv->current_parser_layout->xkb_name);
315
layout = priv->current_parser_layout;
317
priv->current_parser_variant = g_slice_new0 (Layout);
318
priv->current_parser_variant->is_variant = TRUE;
319
priv->current_parser_variant->main_layout = layout;
321
else if (strcmp (element_name, "group") == 0)
323
if (priv->current_parser_group)
325
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
326
"'group' elements can't be nested");
330
priv->current_parser_group = g_slice_new0 (XkbOptionGroup);
331
/* Maps option ids to XkbOption structs. Owns the XkbOption structs. */
332
priv->current_parser_group->options_table = g_hash_table_new_full (g_str_hash, g_str_equal,
334
g_markup_collect_attributes (element_name,
338
G_MARKUP_COLLECT_BOOLEAN | G_MARKUP_COLLECT_OPTIONAL,
339
"allowMultipleSelection",
340
&priv->current_parser_group->allow_multiple_selection,
341
G_MARKUP_COLLECT_INVALID);
343
else if (strcmp (element_name, "option") == 0)
345
if (priv->current_parser_option)
347
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
348
"'option' elements can't be nested");
352
if (!priv->current_parser_group)
354
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
355
"'option' elements must be inside 'group' elements");
359
priv->current_parser_option = g_slice_new0 (XkbOption);
364
add_layout_to_table (GHashTable *table,
370
if (!layout->xkb_name)
373
set = g_hash_table_lookup (table, key);
376
set = g_hash_table_new (g_str_hash, g_str_equal);
377
g_hash_table_replace (table, g_strdup (key), set);
381
if (g_hash_table_contains (set, layout->xkb_name))
384
g_hash_table_replace (set, layout->xkb_name, layout);
388
parse_end_element (GMarkupParseContext *context,
389
const gchar *element_name,
393
GnomeXkbInfoPrivate *priv = GNOME_XKB_INFO (data)->priv;
395
if (strcmp (element_name, "layout") == 0)
397
if (!priv->current_parser_layout->description || !priv->current_parser_layout->xkb_name)
399
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
400
"'layout' elements must enclose 'description' and 'name' elements");
404
priv->current_parser_layout->id = g_strdup (priv->current_parser_layout->xkb_name);
406
if (g_hash_table_contains (priv->layouts_table, priv->current_parser_layout->id))
408
g_clear_pointer (&priv->current_parser_layout, free_layout);
412
g_hash_table_replace (priv->layouts_table,
413
priv->current_parser_layout->id,
414
priv->current_parser_layout);
415
priv->current_parser_layout = NULL;
417
else if (strcmp (element_name, "variant") == 0)
419
if (!priv->current_parser_variant->description || !priv->current_parser_variant->xkb_name)
421
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
422
"'variant' elements must enclose 'description' and 'name' elements");
426
priv->current_parser_variant->id = g_strjoin ("+",
427
priv->current_parser_layout->xkb_name,
428
priv->current_parser_variant->xkb_name,
431
g_hash_table_replace (priv->layouts_table,
432
priv->current_parser_variant->id,
433
priv->current_parser_variant);
434
priv->current_parser_variant = NULL;
436
else if (strcmp (element_name, "iso639Id") == 0)
440
if (!priv->current_parser_iso639Id)
442
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
443
"'iso639Id' elements must enclose text");
447
language = gnome_get_language_from_code (priv->current_parser_iso639Id, NULL);
450
if (priv->current_parser_variant)
451
add_layout_to_table (priv->layouts_by_language, language, priv->current_parser_variant);
452
else if (priv->current_parser_layout)
453
add_layout_to_table (priv->layouts_by_language, language, priv->current_parser_layout);
458
g_clear_pointer (&priv->current_parser_iso639Id, g_free);
460
else if (strcmp (element_name, "iso3166Id") == 0)
464
if (!priv->current_parser_iso3166Id)
466
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
467
"'iso3166Id' elements must enclose text");
471
country = gnome_get_country_from_code (priv->current_parser_iso3166Id, NULL);
474
if (priv->current_parser_variant)
475
add_layout_to_table (priv->layouts_by_country, country, priv->current_parser_variant);
476
else if (priv->current_parser_layout)
477
add_layout_to_table (priv->layouts_by_country, country, priv->current_parser_layout);
482
g_clear_pointer (&priv->current_parser_iso3166Id, g_free);
484
else if (strcmp (element_name, "group") == 0)
486
if (!priv->current_parser_group->description || !priv->current_parser_group->id)
488
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
489
"'group' elements must enclose 'description' and 'name' elements");
493
g_hash_table_replace (priv->option_groups_table,
494
priv->current_parser_group->id,
495
priv->current_parser_group);
496
priv->current_parser_group = NULL;
498
else if (strcmp (element_name, "option") == 0)
500
if (!priv->current_parser_option->description || !priv->current_parser_option->id)
502
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
503
"'option' elements must enclose 'description' and 'name' elements");
507
g_hash_table_replace (priv->current_parser_group->options_table,
508
priv->current_parser_option->id,
509
priv->current_parser_option);
510
priv->current_parser_option = NULL;
515
parse_text (GMarkupParseContext *context,
521
GnomeXkbInfoPrivate *priv = GNOME_XKB_INFO (data)->priv;
523
if (priv->current_parser_text)
525
*priv->current_parser_text = g_strndup (text, text_len);
526
priv->current_parser_text = NULL;
531
parse_error (GMarkupParseContext *context,
535
GnomeXkbInfoPrivate *priv = GNOME_XKB_INFO (data)->priv;
537
free_option_group (priv->current_parser_group);
538
free_option (priv->current_parser_option);
539
free_layout (priv->current_parser_layout);
540
free_layout (priv->current_parser_variant);
541
g_free (priv->current_parser_iso639Id);
542
g_free (priv->current_parser_iso3166Id);
545
static const GMarkupParser markup_parser = {
554
parse_rules_file (GnomeXkbInfo *self,
560
GMarkupParseContext *context;
561
GError *sub_error = NULL;
563
g_file_get_contents (path, &buffer, &length, &sub_error);
566
g_propagate_error (error, sub_error);
570
context = g_markup_parse_context_new (&markup_parser, 0, self, NULL);
571
g_markup_parse_context_parse (context, buffer, length, &sub_error);
572
g_markup_parse_context_free (context);
575
g_propagate_error (error, sub_error);
579
parse_rules (GnomeXkbInfo *self)
581
GnomeXkbInfoPrivate *priv = self->priv;
583
gboolean show_all_sources;
585
GError *error = NULL;
587
/* Maps option group ids to XkbOptionGroup structs. Owns the
588
XkbOptionGroup structs. */
589
priv->option_groups_table = g_hash_table_new_full (g_str_hash, g_str_equal,
590
NULL, free_option_group);
591
/* Maps country strings to a GHashTable which is a set of Layout
592
struct pointers into the Layout structs stored in
594
priv->layouts_by_country = g_hash_table_new_full (g_str_hash, g_str_equal,
595
g_free, (GDestroyNotify) g_hash_table_destroy);
596
/* Maps language strings to a GHashTable which is a set of Layout
597
struct pointers into the Layout structs stored in
599
priv->layouts_by_language = g_hash_table_new_full (g_str_hash, g_str_equal,
600
g_free, (GDestroyNotify) g_hash_table_destroy);
601
/* Maps layout ids to Layout structs. Owns the Layout structs. */
602
priv->layouts_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, free_layout);
604
file_path = get_xml_rules_file_path (".xml");
605
parse_rules_file (self, file_path, &error);
610
settings = g_settings_new ("org.gnome.desktop.input-sources");
611
show_all_sources = g_settings_get_boolean (settings, "show-all-sources");
612
g_object_unref (settings);
614
if (!show_all_sources)
617
file_path = get_xml_rules_file_path (".extras.xml");
618
parse_rules_file (self, file_path, &error);
626
g_warning ("Failed to load XKB rules file %s: %s", file_path, error->message);
627
g_clear_pointer (&error, g_error_free);
628
g_clear_pointer (&file_path, g_free);
629
g_clear_pointer (&priv->option_groups_table, g_hash_table_destroy);
630
g_clear_pointer (&priv->layouts_by_country, g_hash_table_destroy);
631
g_clear_pointer (&priv->layouts_by_language, g_hash_table_destroy);
632
g_clear_pointer (&priv->layouts_table, g_hash_table_destroy);
636
ensure_rules_are_parsed (GnomeXkbInfo *self)
638
GnomeXkbInfoPrivate *priv = self->priv;
640
if (!priv->layouts_table)
643
return !!priv->layouts_table;
647
gnome_xkb_info_init (GnomeXkbInfo *self)
649
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GNOME_TYPE_XKB_INFO, GnomeXkbInfoPrivate);
653
gnome_xkb_info_finalize (GObject *self)
655
GnomeXkbInfoPrivate *priv = GNOME_XKB_INFO (self)->priv;
657
if (priv->option_groups_table)
658
g_hash_table_destroy (priv->option_groups_table);
659
if (priv->layouts_by_country)
660
g_hash_table_destroy (priv->layouts_by_country);
661
if (priv->layouts_by_language)
662
g_hash_table_destroy (priv->layouts_by_language);
663
if (priv->layouts_table)
664
g_hash_table_destroy (priv->layouts_table);
666
G_OBJECT_CLASS (gnome_xkb_info_parent_class)->finalize (self);
670
gnome_xkb_info_class_init (GnomeXkbInfoClass *klass)
672
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
674
gobject_class->finalize = gnome_xkb_info_finalize;
676
g_type_class_add_private (gobject_class, sizeof (GnomeXkbInfoPrivate));
680
* gnome_xkb_info_new:
682
* Returns: (transfer full): a new #GnomeXkbInfo instance.
685
gnome_xkb_info_new (void)
687
return g_object_new (GNOME_TYPE_XKB_INFO, NULL);
691
* gnome_xkb_info_get_all_layouts:
692
* @self: a #GnomeXkbInfo
694
* Returns a list of all layout identifiers we know about.
696
* Return value: (transfer container) (element-type utf8): the list
697
* of layout names. The caller takes ownership of the #GList but not
698
* of the strings themselves, those are internally allocated and must
704
gnome_xkb_info_get_all_layouts (GnomeXkbInfo *self)
706
GnomeXkbInfoPrivate *priv;
708
g_return_val_if_fail (GNOME_IS_XKB_INFO (self), NULL);
712
if (!ensure_rules_are_parsed (self))
715
return g_hash_table_get_keys (priv->layouts_table);
719
* gnome_xkb_info_get_all_option_groups:
720
* @self: a #GnomeXkbInfo
722
* Returns a list of all option group identifiers we know about.
724
* Return value: (transfer container) (element-type utf8): the list
725
* of option group ids. The caller takes ownership of the #GList but
726
* not of the strings themselves, those are internally allocated and
727
* must not be modified.
732
gnome_xkb_info_get_all_option_groups (GnomeXkbInfo *self)
734
GnomeXkbInfoPrivate *priv;
736
g_return_val_if_fail (GNOME_IS_XKB_INFO (self), NULL);
740
if (!ensure_rules_are_parsed (self))
743
return g_hash_table_get_keys (priv->option_groups_table);
747
* gnome_xkb_info_description_for_group:
748
* @self: a #GnomeXkbInfo
749
* @group_id: identifier for group
751
* Return value: the translated description for the group @group_id.
756
gnome_xkb_info_description_for_group (GnomeXkbInfo *self,
757
const gchar *group_id)
759
GnomeXkbInfoPrivate *priv;
760
const XkbOptionGroup *group;
762
g_return_val_if_fail (GNOME_IS_XKB_INFO (self), NULL);
766
if (!ensure_rules_are_parsed (self))
769
group = g_hash_table_lookup (priv->option_groups_table, group_id);
773
return XKEYBOARD_CONFIG_(group->description);
777
* gnome_xkb_info_get_options_for_group:
778
* @self: a #GnomeXkbInfo
779
* @group_id: group's identifier about which to retrieve the options
781
* Returns a list of all option identifiers we know about for group
784
* Return value: (transfer container) (element-type utf8): the list
785
* of option ids. The caller takes ownership of the #GList but not of
786
* the strings themselves, those are internally allocated and must not
792
gnome_xkb_info_get_options_for_group (GnomeXkbInfo *self,
793
const gchar *group_id)
795
GnomeXkbInfoPrivate *priv;
796
const XkbOptionGroup *group;
798
g_return_val_if_fail (GNOME_IS_XKB_INFO (self), NULL);
802
if (!ensure_rules_are_parsed (self))
805
group = g_hash_table_lookup (priv->option_groups_table, group_id);
809
return g_hash_table_get_keys (group->options_table);
813
* gnome_xkb_info_description_for_option:
814
* @self: a #GnomeXkbInfo
815
* @group_id: identifier for group containing the option
816
* @id: option identifier
818
* Return value: the translated description for the option @id.
823
gnome_xkb_info_description_for_option (GnomeXkbInfo *self,
824
const gchar *group_id,
827
GnomeXkbInfoPrivate *priv;
828
const XkbOptionGroup *group;
829
const XkbOption *option;
831
g_return_val_if_fail (GNOME_IS_XKB_INFO (self), NULL);
835
if (!ensure_rules_are_parsed (self))
838
group = g_hash_table_lookup (priv->option_groups_table, group_id);
842
option = g_hash_table_lookup (group->options_table, id);
846
return XKEYBOARD_CONFIG_(option->description);
850
* gnome_xkb_info_get_layout_info:
851
* @self: a #GnomeXkbInfo
852
* @id: layout's identifier about which to retrieve the info
853
* @display_name: (out) (allow-none) (transfer none): location to store
854
* the layout's display name, or %NULL
855
* @short_name: (out) (allow-none) (transfer none): location to store
856
* the layout's short name, or %NULL
857
* @xkb_layout: (out) (allow-none) (transfer none): location to store
858
* the layout's XKB name, or %NULL
859
* @xkb_variant: (out) (allow-none) (transfer none): location to store
860
* the layout's XKB variant, or %NULL
862
* Retrieves information about a layout. Both @display_name and
863
* @short_name are suitable to show in UIs and might be localized if
864
* translations are available.
866
* Some layouts don't provide a short name (2 or 3 letters) or don't
867
* specify a XKB variant, in those cases @short_name or @xkb_variant
868
* are empty strings, i.e. "".
870
* If the given layout doesn't exist the return value is %FALSE and
871
* all the (out) parameters are set to %NULL.
873
* Return value: %TRUE if the layout exists or %FALSE otherwise.
878
gnome_xkb_info_get_layout_info (GnomeXkbInfo *self,
880
const gchar **display_name,
881
const gchar **short_name,
882
const gchar **xkb_layout,
883
const gchar **xkb_variant)
885
GnomeXkbInfoPrivate *priv;
886
const Layout *layout;
889
*display_name = NULL;
897
g_return_val_if_fail (GNOME_IS_XKB_INFO (self), FALSE);
901
if (!ensure_rules_are_parsed (self))
904
if (!g_hash_table_lookup_extended (priv->layouts_table, id, NULL, (gpointer *)&layout))
908
*display_name = XKEYBOARD_CONFIG_(layout->description);
910
if (!layout->is_variant)
913
*short_name = XKEYBOARD_CONFIG_(layout->short_desc ? layout->short_desc : "");
915
*xkb_layout = layout->xkb_name;
922
*short_name = XKEYBOARD_CONFIG_(layout->short_desc ? layout->short_desc :
923
layout->main_layout->short_desc ? layout->main_layout->short_desc : "");
925
*xkb_layout = layout->main_layout->xkb_name;
927
*xkb_variant = layout->xkb_name;
934
collect_layout_ids (gpointer key,
938
Layout *layout = value;
941
*list = g_list_prepend (*list, layout->id);
945
* gnome_xkb_info_get_layouts_for_language:
946
* @self: a #GnomeXkbInfo
947
* @language_code: an ISO 639 code string
949
* Returns a list of all layout identifiers we know about for
952
* Return value: (transfer container) (element-type utf8): the list
953
* of layout ids. The caller takes ownership of the #GList but not of
954
* the strings themselves, those are internally allocated and must not
960
gnome_xkb_info_get_layouts_for_language (GnomeXkbInfo *self,
961
const gchar *language_code)
963
GnomeXkbInfoPrivate *priv;
964
GHashTable *layouts_for_language;
968
g_return_val_if_fail (GNOME_IS_XKB_INFO (self), NULL);
972
if (!ensure_rules_are_parsed (self))
975
language = gnome_get_language_from_code (language_code, NULL);
977
layouts_for_language = g_hash_table_lookup (priv->layouts_by_language, language);
978
if (!layouts_for_language)
982
g_hash_table_foreach (layouts_for_language, collect_layout_ids, &list);
988
* gnome_xkb_info_get_layouts_for_country:
989
* @self: a #GnomeXkbInfo
990
* @country_code: an ISO 3166 code string
992
* Returns a list of all layout identifiers we know about for
995
* Return value: (transfer container) (element-type utf8): the list
996
* of layout ids. The caller takes ownership of the #GList but not of
997
* the strings themselves, those are internally allocated and must not
1003
gnome_xkb_info_get_layouts_for_country (GnomeXkbInfo *self,
1004
const gchar *country_code)
1006
GnomeXkbInfoPrivate *priv;
1007
GHashTable *layouts_for_country;
1011
g_return_val_if_fail (GNOME_IS_XKB_INFO (self), NULL);
1015
if (!ensure_rules_are_parsed (self))
1018
country = gnome_get_country_from_code (country_code, NULL);
1020
layouts_for_country = g_hash_table_lookup (priv->layouts_by_country, country);
1021
if (!layouts_for_country)
1025
g_hash_table_foreach (layouts_for_country, collect_layout_ids, &list);