Merge lp:~gandalfn/gala/add-dbus-accelerator-and-input-sources into lp:gala

Proposed by gandalfn
Status: Work in progress
Proposed branch: lp:~gandalfn/gala/add-dbus-accelerator-and-input-sources
Merge into: lp:gala
Diff against target: 590 lines (+497/-1)
6 files modified
configure.ac (+7/-0)
src/DBusAccelerator.vala (+116/-0)
src/Keyboard/KeyboardManager.vala (+46/-0)
src/Keyboard/KeyboardSettings.vala (+284/-0)
src/Makefile.am (+17/-0)
src/WindowManager.vala (+27/-1)
To merge this branch: bzr merge lp:~gandalfn/gala/add-dbus-accelerator-and-input-sources
Reviewer Review Type Date Requested Status
Rico Tzschichholz Needs Fixing
Review via email: mp+274821@code.launchpad.net

Description of the change

this a merge of https://code.launchpad.net/~gandalfn/gala/add-dbus-accelerator-interface and lp:~gandalfn/gala/add-input-sources-management branches

this branch provides:

- Add check for gnome-settings-daemon >= 3.14, this needs a new dependency under gnome-settings-daemon-dev for deb packaging

- Add multimedia key grab management under gala:

Multimedia keys has been managed by gnome-settings-deamon, which forward
accelerators trought org.gnome.shell grab/ungrab interface.

Add fake dbus accelerator interface which add registered multimedia keys
in gnome-settings-deamon to gala.

See in pantheon debian port

This patch is perhaps debian specific and perhaps needs a define to enable
or not on which distribution gala is been compiled

- Add keyboard layout management in gala:

Under debian since gnome 3.14 keyboard layout management has been managed by mutter
and gnome-shell instead of gnome-settings-daemon.

This patch provide the management of keyboard layout configuration in
gala, to allow the keyboard layout configuration under pantheon desktop.
But this patch still incomplete since it is not manage ibus input sources.

To post a comment you must log in.
489. By gandalfn

Enable keyboard switch with manager only if we have mutter >= 3.14 and
gsd >= 3.14

Revision history for this message
Rico Tzschichholz (ricotz) wrote :

JFYI, putting these merges together won't make the review easier.

* Please make sure to follow gala's codestyle.
* Watch out for nested conditionals. e.g. "HAS_MUTTER_310" inside of "HAS_GSD314"
* Did you intent to ignored support for GSD 3.10/3.12?
* Do not make things public if not needed
* Use a more lightweight structure for KeyboardLayout*?
* Don't ignore existing code which could be replaced or incorporated with these changes.

There are a bunch of things to think about and I might make some adjustments myself.

E.g. Can this really be null? "unowned KeyboardManager? manager = KeyboardManager.get_instance ();

review: Needs Fixing
Revision history for this message
gandalfn (gandalfn) wrote :

Sorry for merging, it was easier for me and debian packaging.

for unowned has nullable it was a bad habit I have, for me an unowned always can be nullable since it does not transfer its ownership, not really accurate in fact

I'll watch all you remarks, but I think at term pantheon-desktop needs a gnome-settings-daemon/gnome-session programs which manage this kind of stuff

Revision history for this message
Rico Tzschichholz (ricotz) wrote :

> for unowned has nullable it was a bad habit I have, for me an unowned always
> can be nullable since it does not transfer its ownership, not really accurate
> in fact

Let me rephrase that to be more clear "Can KeyboardManager.get_instance() really be null?"

Revision history for this message
gandalfn (gandalfn) wrote :

> > for unowned has nullable it was a bad habit I have, for me an unowned always
> > can be nullable since it does not transfer its ownership, not really
> accurate
> > in fact
>
> Let me rephrase that to be more clear "Can KeyboardManager.get_instance()
> really be null?"

No it can not be null :)

Revision history for this message
Corentin Noël (tintou) wrote :

I added a few comments to your merge request

Unmerged revisions

489. By gandalfn

Enable keyboard switch with manager only if we have mutter >= 3.14 and
gsd >= 3.14

488. By gandalfn

Enable keyboard manager only if we have mutter >= 3.14 and gsd >= 3.14

487. By gandalfn

Since gnome 3.14 keyboard layout management has been managed by mutter
and gnome-shell instead of gnome-settings-daemon.

This patch provide the management of keyboard layout configuration in
gala, to allow the keyboard layout configuration under pantheon desktop.
But this patch still incomplete since it is not manage ibus input sources.

486. By gandalfn

Multimedia keys has been managed by gnome-settings-deamon, which forward
accelerators trought org.gnome.shell grab/ungrab interface.
Add fake dbus accelerator interface which add registered multimedia keys
in gnome-settings-deamon to gala.

485. By gandalfn

Add check for gnome-settings-daemon >= 3.14

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'configure.ac'
2--- configure.ac 2015-09-23 14:52:12 +0000
3+++ configure.ac 2015-10-18 11:52:40 +0000
4@@ -181,6 +181,13 @@
5 MUTTER_API="3.18"
6 fi
7
8+# 3.14
9+PKG_CHECK_MODULES(GSD314, [gnome-settings-daemon >= 3.14], [have_gsd314=yes], [have_gsd314=no])
10+if test "x$have_gsd314" = "xyes" ; then
11+ VALAFLAGS="$VALAFLAGS --define HAS_GSD314"
12+fi
13+AM_CONDITIONAL([HAVE_GSD314], [test "x$have_gsd314" = "xyes"])
14+
15 # -----------------------------------------------------------
16 # Dependencies for Notifications plugin
17 # -----------------------------------------------------------
18
19=== added file 'src/DBusAccelerator.vala'
20--- src/DBusAccelerator.vala 1970-01-01 00:00:00 +0000
21+++ src/DBusAccelerator.vala 2015-10-18 11:52:40 +0000
22@@ -0,0 +1,116 @@
23+//
24+// This program is free software: you can redistribute it and/or modify
25+// it under the terms of the GNU General Public License as published by
26+// the Free Software Foundation, either version 3 of the License, or
27+// (at your option) any later version.
28+//
29+// This program is distributed in the hope that it will be useful,
30+// but WITHOUT ANY WARRANTY; without even the implied warranty of
31+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32+// GNU General Public License for more details.
33+//
34+// You should have received a copy of the GNU General Public License
35+// along with this program. If not, see <http://www.gnu.org/licenses/>.
36+//
37+
38+namespace Gala
39+{
40+ [DBus (name="org.gnome.Shell")]
41+ public class DBusAccelerator
42+ {
43+ static DBusAccelerator? instance;
44+ static WindowManager wm;
45+
46+ HashTable<string, uint?> grabbed_accelerators;
47+
48+ public struct Accelerator
49+ {
50+ public string name;
51+ public uint flags;
52+ }
53+
54+ [DBus (visibile = false)]
55+ public static void init (WindowManager _wm)
56+ {
57+ wm = _wm;
58+
59+ Bus.own_name (BusType.SESSION, "org.gnome.Shell", BusNameOwnerFlags.NONE,
60+ (connection) => {
61+ if (instance == null)
62+ instance = new DBusAccelerator ();
63+
64+ try {
65+ connection.register_object ("/org/gnome/Shell", instance);
66+ } catch (Error e) { warning (e.message); }
67+ },
68+ () => {},
69+ () => warning ("Could not acquire name\n") );
70+ }
71+
72+ public signal void AcceleratorActivated (uint action, uint device_id, uint timestamp);
73+
74+ private DBusAccelerator ()
75+ {
76+ grabbed_accelerators = new HashTable<string, uint> (str_hash, str_equal);
77+
78+ wm.get_screen ().get_display ().accelerator_activated.connect (on_accelerator_activated);
79+ }
80+
81+#if HAS_MUTTER310
82+ private void on_accelerator_activated (uint action, uint device_id, uint timestamp)
83+#else
84+ private void on_accelerator_activated (uint action, uint device_id)
85+#endif
86+ {
87+ foreach (string accelerator in grabbed_accelerators.get_keys ()) {
88+ if (grabbed_accelerators[accelerator] == action) {
89+#if HAS_MUTTER310
90+ AcceleratorActivated (action, device_id, timestamp);
91+#else
92+ AcceleratorActivated (action, device_id, 0);
93+#endif
94+ }
95+ }
96+ }
97+
98+ public uint GrabAccelerator (string accelerator, uint flags)
99+ {
100+ uint? action = grabbed_accelerators[accelerator];
101+
102+ if (action == null) {
103+ action = wm.get_screen ().get_display ().grab_accelerator (accelerator);
104+ if (action != 0) {
105+ grabbed_accelerators[accelerator] = action;
106+ }
107+ }
108+
109+ return action;
110+ }
111+
112+ public uint[] GrabAccelerators (Accelerator[] accelerators)
113+ {
114+ uint[] actions = {};
115+
116+ foreach (unowned Accelerator? accelerator in accelerators) {
117+ actions += GrabAccelerator (accelerator.name, accelerator.flags);
118+ }
119+
120+ return actions;
121+ }
122+
123+ public bool UngrabAccelerator (uint action)
124+ {
125+ bool ret = false;
126+
127+ foreach (string accelerator in grabbed_accelerators.get_keys ()) {
128+ if (grabbed_accelerators[accelerator] == action) {
129+ ret = wm.get_screen ().get_display ().ungrab_accelerator (action);
130+ grabbed_accelerators.remove (accelerator);
131+ break;
132+ }
133+ }
134+
135+ return ret;
136+ }
137+ }
138+}
139
140=== added directory 'src/Keyboard'
141=== added file 'src/Keyboard/KeyboardManager.vala'
142--- src/Keyboard/KeyboardManager.vala 1970-01-01 00:00:00 +0000
143+++ src/Keyboard/KeyboardManager.vala 2015-10-18 11:52:40 +0000
144@@ -0,0 +1,46 @@
145+//
146+// This program is free software: you can redistribute it and/or modify
147+// it under the terms of the GNU General Public License as published by
148+// the Free Software Foundation, either version 3 of the License, or
149+// (at your option) any later version.
150+//
151+// This program is distributed in the hope that it will be useful,
152+// but WITHOUT ANY WARRANTY; without even the implied warranty of
153+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
154+// GNU General Public License for more details.
155+//
156+// You should have received a copy of the GNU General Public License
157+// along with this program. If not, see <http://www.gnu.org/licenses/>.
158+//
159+
160+namespace Gala
161+{
162+ public class KeyboardManager : Object
163+ {
164+ public KeyboardLayoutSettings settings { get; private set; }
165+
166+ // singleton pattern
167+ static KeyboardManager? instance;
168+ public static unowned KeyboardManager get_instance () {
169+ if (instance == null) {
170+ instance = new KeyboardManager ();
171+ }
172+ return instance;
173+ }
174+
175+ private void update_keymap () {
176+ unowned KeyboardLayoutXKB? layout = settings.layouts[settings.layouts.active] as KeyboardLayoutXKB;
177+ if (layout != null)
178+ {
179+ Meta.Backend.get_backend ().set_keymap (layout.layout, layout.variant ?? "", settings.xkb_options);
180+ }
181+ }
182+
183+ private KeyboardManager () {
184+ settings = new KeyboardLayoutSettings ();
185+ update_keymap ();
186+
187+ settings.layouts.notify["active"].connect (update_keymap);
188+ }
189+ }
190+}
191
192=== added file 'src/Keyboard/KeyboardSettings.vala'
193--- src/Keyboard/KeyboardSettings.vala 1970-01-01 00:00:00 +0000
194+++ src/Keyboard/KeyboardSettings.vala 2015-10-18 11:52:40 +0000
195@@ -0,0 +1,284 @@
196+//
197+// This program is free software: you can redistribute it and/or modify
198+// it under the terms of the GNU General Public License as published by
199+// the Free Software Foundation, either version 3 of the License, or
200+// (at your option) any later version.
201+//
202+// This program is distributed in the hope that it will be useful,
203+// but WITHOUT ANY WARRANTY; without even the implied warranty of
204+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
205+// GNU General Public License for more details.
206+//
207+// You should have received a copy of the GNU General Public License
208+// along with this program. If not, see <http://www.gnu.org/licenses/>.
209+//
210+
211+namespace Gala
212+{
213+ public abstract class KeyboardLayout : Object {
214+ public string name { get; set; }
215+
216+ public KeyboardLayout (string name) {
217+ Object (name: name);
218+ }
219+
220+ public virtual bool equal (KeyboardLayout other) {
221+ return this.name == other.name;
222+ }
223+
224+ public static KeyboardLayout from_variant (GLib.Variant variant) {
225+ KeyboardLayout? ret = null;
226+ if (variant.is_of_type (new VariantType ("(ss)"))) {
227+ unowned string type;
228+ unowned string name;
229+
230+ variant.get ("(&s&s)", out type, out name);
231+
232+ if (type == "xkb") {
233+ ret = new KeyboardLayoutXKB (name);
234+ } else if (type == "ibus") {
235+ ret = new KeyboardLayoutIBUS (name);
236+ } else {
237+ warning ("Unkown type %s", type);
238+ }
239+
240+ } else {
241+ warning ("Variant has invalid type");
242+ }
243+
244+ return ret;
245+ }
246+ }
247+
248+ public class KeyboardLayoutIBUS : KeyboardLayout {
249+ public KeyboardLayoutIBUS (string name) {
250+ base (name);
251+ }
252+
253+ public override bool equal (KeyboardLayout other) {
254+ return (other is KeyboardLayoutIBUS) && base.equal (other);
255+ }
256+ }
257+
258+ public class KeyboardLayoutXKB : KeyboardLayout {
259+ public string? layout {
260+ owned get {
261+ string[]? split = name.split("+", 2);
262+ if (split != null)
263+ return split[0];
264+ return null;
265+ }
266+ }
267+
268+ public string? variant {
269+ owned get {
270+ string[]? split = name.split("+", 2);
271+ if (split != null && split.length >= 2)
272+ return split[1];
273+ return null;
274+ }
275+ }
276+
277+ public KeyboardLayoutXKB (string layout, string? variant = null) {
278+ string name = layout;
279+ if (variant != null && variant != "")
280+ name += "+" + variant;
281+
282+ base (name);
283+ }
284+
285+ public override bool equal (KeyboardLayout other) {
286+ return (other is KeyboardLayoutXKB) && base.equal (other);
287+ }
288+ }
289+
290+ public class KeyboardLayoutList : Object {
291+ GLib.List<KeyboardLayout> layouts = new GLib.List<KeyboardLayout> ();
292+
293+ public uint length {
294+ get {
295+ return layouts.length ();
296+ }
297+ }
298+
299+ uint _active;
300+ public uint active {
301+ get {
302+ return _active;
303+ }
304+ set {
305+ if (length == 0)
306+ return;
307+
308+ if (_active == value)
309+ return;
310+
311+ _active = value;
312+ if (_active >= length)
313+ _active = length - 1;
314+ }
315+
316+ }
317+
318+ public bool contains (KeyboardLayout given_layout) {
319+ return get_layout_index (given_layout) != -1;
320+ }
321+
322+ public int get_layout_index (KeyboardLayout given_layout) {
323+ int i = 0;
324+ foreach (KeyboardLayout l in layouts) {
325+ if (l.equal (given_layout))
326+ return i;
327+ i++;
328+ }
329+ return -1;
330+ }
331+
332+ public new unowned KeyboardLayout? @get (uint index) {
333+ if (index >= length)
334+ return null;
335+
336+ return layouts.nth_data (index);
337+ }
338+
339+ public void add (KeyboardLayout layout) {
340+ if (!(layout in this))
341+ layouts.append (layout);
342+ }
343+
344+ public void clear () {
345+ layouts = new GLib.List<KeyboardLayout> ();
346+ }
347+ }
348+
349+ public class KeyboardLayoutSettings : Object {
350+ GLib.Settings settings;
351+
352+ public KeyboardLayoutList layouts { get; private set; }
353+ public bool per_window { get; private set; }
354+ public string xkb_options {
355+ owned get {
356+ string ret = "";
357+ GLib.Variant sources = settings.get_value ("sources");
358+ if (sources.is_of_type (VariantType.ARRAY)) {
359+ for (size_t i = 0; i < sources.n_children (); i++) {
360+ GLib.Variant child = sources.get_child_value (i);
361+ if (child.is_of_type (new VariantType ("s"))) {
362+ unowned string opt;
363+ child.get ("&s", out opt);
364+ if (ret == "")
365+ ret += opt;
366+ else
367+ ret += ","+opt;
368+ }
369+ }
370+ }
371+ return ret;
372+ }
373+ }
374+
375+ void update_list_from_gsettings () {
376+ layouts.clear ();
377+ GLib.Variant sources = settings.get_value ("sources");
378+ if (sources.is_of_type (VariantType.ARRAY)) {
379+ for (size_t i = 0; i < sources.n_children (); i++) {
380+ GLib.Variant child = sources.get_child_value (i);
381+ KeyboardLayout? layout = KeyboardLayout.from_variant (child);
382+ if (layout != null)
383+ layouts.add (layout);
384+ }
385+ } else {
386+ warning ("Unkown type");
387+ }
388+ }
389+
390+ void update_active_from_gsettings () {
391+ layouts.active = settings.get_uint ("current");
392+ }
393+
394+ void parse_default () {
395+ var file = File.new_for_path ("/etc/default/keyboard");
396+
397+ if (!file.query_exists ()) {
398+ warning ("File '%s' doesn't exist.\n", file.get_path ());
399+ return;
400+ }
401+
402+ string xkb_layout = "";
403+ string xkb_variant = "";
404+
405+ try {
406+ var dis = new DataInputStream (file.read ());
407+
408+ string line;
409+
410+ while ((line = dis.read_line (null)) != null)
411+ {
412+ if (line.contains ("XKBLAYOUT="))
413+ {
414+ xkb_layout = line.replace ("XKBLAYOUT=", "").replace ("\"", "");
415+
416+ while ((line = dis.read_line (null)) != null) {
417+ if (line.contains ("XKBVARIANT=")) {
418+ xkb_variant = line.replace ("XKBVARIANT=", "").replace ("\"", "");
419+ }
420+ }
421+
422+ break;
423+ }
424+ }
425+ }
426+ catch (Error e) {
427+ warning ("%s", e.message);
428+ return;
429+ }
430+
431+ var variants = xkb_variant.split (",");
432+ var xkb_layouts = xkb_layout.split (",");
433+
434+ for (int i = 0; i < layouts.length; i++) {
435+ if (variants[i] != null && variants[i] != "")
436+ layouts.add (new KeyboardLayoutXKB (xkb_layouts[i] + "+" + variants[i]));
437+ else
438+ layouts.add (new KeyboardLayoutXKB (xkb_layouts[i]));
439+ }
440+
441+ layouts.active = 0;
442+ }
443+
444+ public KeyboardLayoutSettings ()
445+ {
446+ settings = new Settings ("org.gnome.desktop.input-sources");
447+ layouts = new KeyboardLayoutList ();
448+
449+ per_window = settings.get_boolean ("per-window");
450+ settings.changed["per-window"].connect (() => {
451+ per_window = settings.get_boolean ("per-window");
452+ });
453+
454+ update_list_from_gsettings ();
455+ update_active_from_gsettings ();
456+
457+ settings.changed["sources"].connect (() => {
458+ update_list_from_gsettings ();
459+ update_active_from_gsettings ();
460+ });
461+
462+ settings.changed["xkb-options"].connect (() => {
463+ update_active_from_gsettings ();
464+ });
465+
466+ settings.changed["current"].connect (update_active_from_gsettings);
467+
468+ layouts.notify["active"].connect (() => {
469+ settings.changed["current"].disconnect (update_active_from_gsettings);
470+ settings.set_uint ("current", layouts.active);
471+ settings.changed["current"].connect (update_active_from_gsettings);
472+ });
473+
474+ if (layouts.length == 0)
475+ parse_default ();
476+ }
477+ }
478+
479+}
480
481=== modified file 'src/Makefile.am'
482--- src/Makefile.am 2015-03-04 11:29:53 +0000
483+++ src/Makefile.am 2015-10-18 11:52:40 +0000
484@@ -69,6 +69,11 @@
485 Background/SystemBackground.vala \
486 $(NULL)
487
488+gala_keyboard = \
489+ Keyboard/KeyboardSettings.vala \
490+ Keyboard/KeyboardManager.vala \
491+ $(NULL)
492+
493 gala_background312 = \
494 Background-3.12/Background.vala \
495 Background-3.12/BackgroundCache.vala \
496@@ -79,10 +84,20 @@
497
498 if HAVE_MUTTER314
499 gala_VALASOURCES += $(gala_background)
500+if HAVE_GSD314
501+gala_VALASOURCES += $(gala_keyboard)
502+endif
503 else
504 gala_VALASOURCES += $(gala_background312)
505 endif
506
507+gala_accelerator = \
508+ DBusAccelerator.vala
509+
510+if HAVE_GSD314
511+gala_VALASOURCES += $(gala_accelerator)
512+endif
513+
514 nodist_gala_SOURCES = \
515 gala_vala.stamp \
516 $(gala_VALASOURCES:.vala=.c) \
517@@ -104,6 +119,8 @@
518 EXTRA_DIST = \
519 $(gala_background) \
520 $(gala_background312) \
521+ $(gala_accelerator) \
522+ $(gala_keyboard) \
523 $(gala_VALASOURCES) \
524 $(NULL)
525
526
527=== modified file 'src/WindowManager.vala'
528--- src/WindowManager.vala 2015-09-10 11:32:41 +0000
529+++ src/WindowManager.vala 2015-10-18 11:52:40 +0000
530@@ -93,11 +93,18 @@
531 var display = screen.get_display ();
532
533 DBus.init (this);
534+#if HAS_GSD314
535+ DBusAccelerator.init (this);
536+#endif
537 #if !HAS_MUTTER314
538 BackgroundCache.init (screen);
539 #endif
540 WindowListener.init (screen);
541
542+#if HAS_MUTTER314 && HAS_GSD314
543+ KeyboardManager.get_instance ();
544+#endif
545+
546 // Due to a bug which enables access to the stage when using multiple monitors
547 // in the screensaver, we have to listen for changes and make sure the input area
548 // is set to NONE when we are in locked mode
549@@ -325,6 +332,24 @@
550 X.Event event, Meta.KeyBinding binding)
551 #endif
552 {
553+#if HAS_MUTTER314 && HAS_GSD314
554+ unowned KeyboardManager? manager = KeyboardManager.get_instance ();
555+ if (manager != null) {
556+ var n_sources = manager.settings.layouts.length;
557+ if (n_sources < 2)
558+ return;
559+
560+ var new_index = 0U;
561+ var current_index = manager.settings.layouts.active;
562+
563+ if (binding.get_name () == "switch-input-source")
564+ new_index = (current_index + 1) % n_sources;
565+ else
566+ new_index = (current_index - 1 + n_sources) % n_sources;
567+
568+ manager.settings.layouts.active = new_index;
569+ }
570+#else
571 var keyboard_input_settings = new GLib.Settings ("org.gnome.desktop.input-sources");
572
573 var n_sources = (uint) keyboard_input_settings.get_value ("sources").n_children ();
574@@ -340,6 +365,7 @@
575 new_index = (current_index - 1 + n_sources) % n_sources;
576
577 keyboard_input_settings.set_uint ("current", new_index);
578+#endif
579 }
580
581 [CCode (instance_pos = -1)]
582@@ -746,7 +772,7 @@
583 {
584 unowned AnimationSettings animation_settings = AnimationSettings.get_default ();
585 var duration = animation_settings.minimize_duration;
586-
587+
588 if (!animation_settings.enable_animations
589 || duration == 0
590 || actor.get_meta_window ().window_type != WindowType.NORMAL) {

Subscribers

People subscribed via source and target branches