Merge lp:~davidmhewitt/switchboard-plug-keyboard/fix-1650986-load-xml-config into lp:~elementary-pantheon/switchboard-plug-keyboard/trunk

Proposed by David Hewitt
Status: Merged
Approved by: Danielle Foré
Approved revision: 519
Merged at revision: 523
Proposed branch: lp:~davidmhewitt/switchboard-plug-keyboard/fix-1650986-load-xml-config
Merge into: lp:~elementary-pantheon/switchboard-plug-keyboard/trunk
Diff against target: 176 lines (+81/-53)
2 files modified
src/CMakeLists.txt (+2/-1)
src/Layout/Handler.vala (+79/-52)
To merge this branch: bzr merge lp:~davidmhewitt/switchboard-plug-keyboard/fix-1650986-load-xml-config
Reviewer Review Type Date Requested Status
Santiago (community) code Approve
elementary Pantheon team Pending
Leonardo Lemos Pending
Review via email: mp+317412@code.launchpad.net

Commit message

Load XKB keymaps from evdev.xml instead of evdev.lst

Description of the change

The list of keyboard configurations was being read from evdev.lst. All documentation online about how to create keyboard maps refers to creating them in the XML files.

I checked and both files contain the exact same base configurations for every language and keymap. But, it's likely that any custom or new keyboard maps will be added to the XML files.

To post a comment you must log in.
517. By David Hewitt

Fixed double-free crash?

518. By David Hewitt

Improved code based on Santiago's suggestions

519. By David Hewitt

Ooops, missed some improvements from last commit

Revision history for this message
Santiago (santileortiz) wrote :

This and the branch on the keyboard indicator should allow users to more easily use custom keyboard layouts, I've been running them both for several days and they seem fine. Code looks good to me too.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/CMakeLists.txt'
2--- src/CMakeLists.txt 2017-02-12 02:46:10 +0000
3+++ src/CMakeLists.txt 2017-02-25 18:17:51 +0000
4@@ -1,7 +1,7 @@
5 find_package (PkgConfig)
6
7 # Add all your dependencies to the list below
8-pkg_check_modules (DEPS REQUIRED gthread-2.0 gtk+-3.0>=3.10 switchboard-2.0 granite)
9+pkg_check_modules (DEPS REQUIRED gthread-2.0 gtk+-3.0>=3.10 switchboard-2.0 granite libxml-2.0)
10
11 add_definitions (${DEPS_CFLAGS})
12 link_directories (${DEPS_LIBRARY_DIRS})
13@@ -47,6 +47,7 @@
14 gtk+-3.0
15 switchboard-2.0
16 granite
17+ libxml-2.0
18 OPTIONS
19 --thread
20 )
21
22=== modified file 'src/Layout/Handler.vala'
23--- src/Layout/Handler.vala 2017-02-12 02:46:10 +0000
24+++ src/Layout/Handler.vala 2017-02-25 18:17:51 +0000
25@@ -8,73 +8,100 @@
26 construct {
27 languages = new HashTable<string, string> (str_hash, str_equal);
28 }
29-
30+
31 private void parse_layouts () {
32- var file = File.new_for_path ("/usr/share/X11/xkb/rules/evdev.lst");
33-
34- if (!file.query_exists ()) {
35- critical ("File '%s' doesn't exist.", file.get_path ());
36- return;
37- }
38-
39- try {
40- var dis = new DataInputStream (file.read ());
41- string line;
42- bool layout_found = false;
43- while ((line = dis.read_line (null)) != null) {
44- if (layout_found) {
45- if ("!" in line || line == "") {
46- break;
47- }
48-
49- var parts = line.chug ().split (" ", 2);
50- languages.set (parts[0], dgettext ("xkeyboard-config", parts[1].chug ()));
51- } else {
52- if ("!" in line && "layout" in line) {
53- layout_found = true;
54+ Xml.Doc* doc = Xml.Parser.parse_file ("/usr/share/X11/xkb/rules/evdev.xml");
55+ if (doc == null) {
56+ critical ("'evdev.xml' not found or permissions missing\n");
57+ return;
58+ }
59+
60+ Xml.XPath.Context cntx = new Xml.XPath.Context (doc);
61+ Xml.XPath.Object* res = cntx.eval_expression ("/xkbConfigRegistry/layoutList/layout/configItem");
62+
63+ if (res == null) {
64+ delete doc;
65+ critical ("Unable to parse 'evdev.xml'");
66+ return;
67+ }
68+
69+ if (res->type != Xml.XPath.ObjectType.NODESET || res->nodesetval == null) {
70+ delete res;
71+ delete doc;
72+ critical ("No layouts found in 'evdev.xml'");
73+ return;
74+ }
75+
76+ for (int i = 0; i < res->nodesetval->length (); i++) {
77+ Xml.Node* node = res->nodesetval->item (i);
78+ string? name = null;
79+ string? description = null;
80+ for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
81+ if (iter->type == Xml.ElementType.ELEMENT_NODE) {
82+ if (iter->name == "name") {
83+ name = iter->get_content ();
84+ } else if (iter->name == "description") {
85+ description = dgettext ("xkeyboard-config", iter->get_content ());
86 }
87 }
88 }
89- } catch (Error e) {
90- error (e.message);
91+ if (name != null && description != null) {
92+ languages.set (name, description);
93+ }
94 }
95+
96+ delete res;
97+ delete doc;
98 }
99
100 public HashTable<string, string> get_variants_for_language (string language) {
101 var returned_table = new HashTable<string, string> (str_hash, str_equal);
102 returned_table.set ("", _("Default"));
103- var file = File.new_for_path ("/usr/share/X11/xkb/rules/evdev.lst");
104-
105- if (!file.query_exists ()) {
106- critical ("File '%s' doesn't exist.", file.get_path ());
107- return returned_table;
108- }
109-
110- try {
111- var dis = new DataInputStream (file.read ());
112- string line;
113- bool variant_found = false;
114- while ((line = dis.read_line (null)) != null) {
115- if (variant_found) {
116- if ("!" in line || line == "") {
117- break;
118- }
119-
120- var parts = line.chug ().split (" ", 2);
121- var subparts = parts[1].chug ().split (":", 2);
122- if (subparts[0] == language) {
123- returned_table.set (parts[0], dgettext ("xkeyboard-config", subparts[1].chug ()));
124- }
125- } else {
126- if ("!" in line && "variant" in line) {
127- variant_found = true;
128+ Xml.Doc* doc = Xml.Parser.parse_file ("/usr/share/X11/xkb/rules/evdev.xml");
129+ if (doc == null) {
130+ critical ("'evdev.xml' not found or permissions incorrect\n");
131+ return returned_table;
132+ }
133+
134+ Xml.XPath.Context cntx = new Xml.XPath.Context (doc);
135+ var xpath = @"/xkbConfigRegistry/layoutList/layout/configItem/name[text()='$language']/../../variantList/variant/configItem";
136+ Xml.XPath.Object* res = cntx.eval_expression (xpath);
137+
138+ if (res == null) {
139+ delete doc;
140+ critical ("Unable to parse 'evdev.xml'");
141+ return returned_table;
142+ }
143+
144+ if (res->type != Xml.XPath.ObjectType.NODESET || res->nodesetval == null) {
145+ delete res;
146+ delete doc;
147+ warning (@"No variants for $language found in 'evdev.xml'");
148+ return returned_table;
149+ }
150+
151+ for (int i = 0; i < res->nodesetval->length (); i++) {
152+ Xml.Node* node = res->nodesetval->item (i);
153+
154+ string? name = null;
155+ string? description = null;
156+ for (Xml.Node* iter = node->children; iter != null; iter = iter->next) {
157+ if (iter->type == Xml.ElementType.ELEMENT_NODE) {
158+ if (iter->name == "name") {
159+ name = iter->get_content ();
160+ } else if (iter->name == "description") {
161+ description = dgettext ("xkeyboard-config", iter->get_content ());
162 }
163 }
164 }
165- } catch (Error e) {
166- error (e.message);
167+ if (name != null && description != null) {
168+ returned_table.set (name, description);
169+ }
170 }
171
172+ delete res;
173+ delete doc;
174+
175 return returned_table;
176 }
177

Subscribers

People subscribed via source and target branches

to all changes: