Merge lp:~attente/unity/1291461 into lp:unity

Proposed by William Hua
Status: Merged
Approved by: Marco Trevisan (Treviño)
Approved revision: no longer in the source branch.
Merged at revision: 3795
Proposed branch: lp:~attente/unity/1291461
Merge into: lp:unity
Diff against target: 1502 lines (+896/-303)
16 files modified
lockscreen/CMakeLists.txt (+2/-0)
lockscreen/LockScreenAbstractShield.h (+5/-1)
lockscreen/LockScreenAcceleratorController.cpp (+146/-0)
lockscreen/LockScreenAcceleratorController.h (+46/-0)
lockscreen/LockScreenAccelerators.cpp (+528/-0)
lockscreen/LockScreenAccelerators.h (+92/-0)
lockscreen/LockScreenController.cpp (+14/-1)
lockscreen/LockScreenController.h (+4/-1)
lockscreen/LockScreenPanel.cpp (+4/-237)
lockscreen/LockScreenPanel.h (+2/-50)
lockscreen/LockScreenShield.cpp (+23/-6)
lockscreen/LockScreenShield.h (+2/-1)
lockscreen/LockScreenShieldFactory.cpp (+2/-2)
lockscreen/LockScreenShieldFactory.h (+2/-2)
tests/data/external.gschema.xml (+21/-0)
tests/test_lockscreen_controller.cpp (+3/-2)
To merge this branch: bzr merge lp:~attente/unity/1291461
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Marco Trevisan (Treviño) Approve
Review via email: mp+215848@code.launchpad.net

Commit message

Add proper support for modifier-only shortcuts on the lock screen.

Description of the change

Add proper support for modifier-only shortcuts on the lock screen.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

Hey, I didn't go much into the review yet, but I was wondering: what about moving the whole thing inside a LockScreenAccelerators class, that is generated just once by LockScreenController and that the relevant LockScreenShield will pass the events to?

Revision history for this message
William Hua (attente) wrote :

Thanks Marco, I ripped it out like you suggested, and made it easier for us to add new accelerators if we ever need to.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

Cool, looks nicer!

Btw, when i meant about moving to another class, I also meant all the initialization code that now is LockScreenController. Ideally the controller should just initialize the accelerators inside Controller::LockScreen (just like it does for the indicators themselves), and would pass them to the shields.

All the parsing code should be out from the controller, and done during the Accelerators construction.

So a LockScreenAccelerators(Manager) class that handles the Accelerator's (and moving there the same functionalities that the Accelerators class has now) if you prefer :)

88 +static unsigned int KeysymToModifier(unsigned int keysym)
109 +static unsigned int KeysymToPressedMask(unsigned int keysym)
134 +static unsigned int KeysymToMirrorKeysym(unsigned int keysym)

You don't need to make them static, just put them into an anonymous namespace

560 +enum
561 +{
562 + LeftShiftPressed = 0x01,
563 + LeftControlPressed = 0x02,

Enum class would be nicer, but anyway put this into the unnamed namespace inside the .cpp file, we don't need to make this public

580 + sigc::signal<void> Activate;

Lower case names for signals please, and maybe "activated"?

314 + goto activate;

Please get rid the goto code from unity :P

618 + std::list<Accelerator> accelerators_;

Same is valid also for the code you'd move out from Lockscreen controller, but a dd a typedef for the Accelerator::Ptr class, and use smart pointers instead of using the copy, or you'd get the same object to be initialized multiple times (make them also not-copiable).

About the jenkins failure:
CRIT 2014-04-17 13:53:41 unity.glib-gio <unknown>:0 Settings schema 'org.gnome.settings-daemon.plugins.media-keys' is not installed

Just put the settings definition you need inside tests/data/external.gschema.xml or make an abstract Accelerators class.

review: Needs Fixing
Revision history for this message
William Hua (attente) wrote :

Thanks for the comments Marco. I made all your changes except for the goto removals. I'm hoping we can keep them because otherwise we'd end up duplicating the same code several times, and I think the label is clear enough that most people reading the code will understand what the jump does.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

Nice, awesome work...

Just one last fix, I'm not using precompiled headers here (as ccache seems to not play nicely with them), so this gives me compilation issues.

Can you just add these includes: http://paste.ubuntu.com/7362584/ ?

1095 + if (activate_panel_)
1096 + {
1097 + ActivateFirst();
1098 + activate_panel_ = false;
1099 + }

What's the reason for that?

Why not just calling ActivateFirst inside ActivatePanel (or better, replacing the content of ActivatePanel with the content of ActivateFirst, removing the latter)?
InspectKeyEvent, for the way it's used can just return always true.

From my tests I didn't notice any problem using http://pastebin.ubuntu.com/7362673/

863 + std::list<Accelerator::Ptr> accelerators_;

Really optional, but in general using std::vector works better when just iterating over elements as you do.

Revision history for this message
William Hua (attente) wrote :

Thanks Marco,

> 1095 + if (activate_panel_)
> 1096 + {
> 1097 + ActivateFirst();
> 1098 + activate_panel_ = false;
> 1099 + }
>
> What's the reason for that?
>
> Why not just calling ActivateFirst inside ActivatePanel (or better, replacing
> the content of ActivatePanel with the content of ActivateFirst, removing the
> latter)?
> InspectKeyEvent, for the way it's used can just return always true.
>
> From my tests I didn't notice any problem using
> http://pastebin.ubuntu.com/7362673/

I did it in that hacky way because I thought ActivateFirst would have no effect because we'd be activating it before unity::lockscreen::Shield::FindKeyFocusArea returns the panel_view_ that would receive the keyboard focus. But if your paste works fine, I'll add it, I guess I just misunderstood the way those functions work.

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

Lovely!

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
William Hua (attente) wrote :

Marco... sorry, I forgot to treat the Meta modifier as Alt so I just added it now.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lockscreen/CMakeLists.txt'
2--- lockscreen/CMakeLists.txt 2014-04-02 13:40:28 +0000
3+++ lockscreen/CMakeLists.txt 2014-04-30 04:35:25 +0000
4@@ -24,6 +24,8 @@
5 LockScreenShield.cpp
6 LockScreenShieldFactory.cpp
7 LockScreenPanel.cpp
8+ LockScreenAcceleratorController.cpp
9+ LockScreenAccelerators.cpp
10 ScreenSaverDBusManager.cpp
11 UserAuthenticatorPam.cpp
12 UserPromptView.cpp
13
14=== modified file 'lockscreen/LockScreenAbstractShield.h'
15--- lockscreen/LockScreenAbstractShield.h 2014-04-10 17:43:13 +0000
16+++ lockscreen/LockScreenAbstractShield.h 2014-04-30 04:35:25 +0000
17@@ -25,6 +25,7 @@
18 #include <UnityCore/Indicators.h>
19
20 #include "unity-shared/MockableBaseWindow.h"
21+#include "LockScreenAccelerators.h"
22
23 namespace unity
24 {
25@@ -34,12 +35,13 @@
26 class AbstractShield : public MockableBaseWindow
27 {
28 public:
29- AbstractShield(session::Manager::Ptr const& session, indicator::Indicators::Ptr const& indicators, int monitor_num, bool is_primary)
30+ AbstractShield(session::Manager::Ptr const& session, indicator::Indicators::Ptr const& indicators, Accelerators::Ptr const& accelerators, int monitor_num, bool is_primary)
31 : MockableBaseWindow("Unity Lockscreen")
32 , primary(is_primary)
33 , monitor(monitor_num)
34 , session_manager_(session)
35 , indicators_(indicators)
36+ , accelerators_(accelerators)
37 {}
38
39 nux::Property<bool> primary;
40@@ -48,6 +50,7 @@
41 using MockableBaseWindow::RemoveLayout;
42 virtual bool IsIndicatorOpen() const = 0;
43 virtual void CheckCapsLockPrompt() = 0;
44+ virtual void ActivatePanel() = 0;
45
46 sigc::signal<void, int, int> grab_motion;
47 sigc::signal<void, unsigned long, unsigned long> grab_key;
48@@ -55,6 +58,7 @@
49 protected:
50 session::Manager::Ptr session_manager_;
51 indicator::Indicators::Ptr indicators_;
52+ Accelerators::Ptr accelerators_;
53 };
54
55 } // lockscreen
56
57=== added file 'lockscreen/LockScreenAcceleratorController.cpp'
58--- lockscreen/LockScreenAcceleratorController.cpp 1970-01-01 00:00:00 +0000
59+++ lockscreen/LockScreenAcceleratorController.cpp 2014-04-30 04:35:25 +0000
60@@ -0,0 +1,146 @@
61+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
62+/*
63+ * Copyright (C) 2014 Canonical Ltd
64+ *
65+ * This program is free software: you can redistribute it and/or modify
66+ * it under the terms of the GNU General Public License version 3 as
67+ * published by the Free Software Foundation.
68+ *
69+ * This program is distributed in the hope that it will be useful,
70+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
71+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
72+ * GNU General Public License for more details.
73+ *
74+ * You should have received a copy of the GNU General Public License
75+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
76+ *
77+ * Authored by: William Hua <william.hua@canonical.com>
78+ */
79+
80+#include "LockScreenAcceleratorController.h"
81+
82+#include <UnityCore/GLibDBusProxy.h>
83+
84+namespace unity
85+{
86+namespace lockscreen
87+{
88+
89+namespace
90+{
91+const char* const MEDIA_KEYS_SCHEMA = "org.gnome.settings-daemon.plugins.media-keys";
92+const char* const MEDIA_KEYS_KEY_VOLUME_MUTE = "volume-mute";
93+const char* const MEDIA_KEYS_KEY_VOLUME_DOWN = "volume-down";
94+const char* const MEDIA_KEYS_KEY_VOLUME_UP = "volume-up";
95+const char* const INPUT_SWITCH_SCHEMA = "org.gnome.desktop.wm.keybindings";
96+const char* const INPUT_SWITCH_KEY_PREVIOUS_SOURCE = "switch-input-source-backward";
97+const char* const INPUT_SWITCH_KEY_NEXT_SOURCE = "switch-input-source";
98+
99+const char* const INDICATOR_INTERFACE_ACTIONS = "org.gtk.Actions";
100+const char* const INDICATOR_METHOD_ACTIVATE = "Activate";
101+const char* const INDICATOR_SOUND_BUS_NAME = "com.canonical.indicator.sound";
102+const char* const INDICATOR_SOUND_OBJECT_PATH = "/com/canonical/indicator/sound";
103+const char* const INDICATOR_SOUND_ACTION_MUTE = "mute";
104+const char* const INDICATOR_SOUND_ACTION_SCROLL = "scroll";
105+const char* const INDICATOR_KEYBOARD_BUS_NAME = "com.canonical.indicator.keyboard";
106+const char* const INDICATOR_KEYBOARD_OBJECT_PATH = "/com/canonical/indicator/keyboard";
107+const char* const INDICATOR_KEYBOARD_ACTION_SCROLL = "locked_scroll";
108+
109+void ActivateIndicator(std::string const& bus_name,
110+ std::string const& object_path,
111+ std::string const& action_name,
112+ glib::Variant const& parameters = glib::Variant())
113+{
114+ GVariantBuilder builder;
115+
116+ g_variant_builder_init(&builder, G_VARIANT_TYPE("(sava{sv})"));
117+ g_variant_builder_add(&builder, "s", action_name.c_str());
118+
119+ if (parameters)
120+ g_variant_builder_add_parsed(&builder, "[%v]", static_cast<GVariant*>(parameters));
121+ else
122+ g_variant_builder_add_parsed(&builder, "@av []");
123+
124+ g_variant_builder_add_parsed(&builder, "@a{sv} []");
125+
126+ auto proxy = std::make_shared<glib::DBusProxy>(bus_name, object_path, INDICATOR_INTERFACE_ACTIONS);
127+ proxy->CallBegin(INDICATOR_METHOD_ACTIVATE, g_variant_builder_end(&builder), [proxy] (GVariant*, glib::Error const&) {});
128+}
129+
130+void MuteIndicatorSound()
131+{
132+ ActivateIndicator(INDICATOR_SOUND_BUS_NAME,
133+ INDICATOR_SOUND_OBJECT_PATH,
134+ INDICATOR_SOUND_ACTION_MUTE);
135+}
136+
137+void ScrollIndicatorSound(int offset)
138+{
139+ ActivateIndicator(INDICATOR_SOUND_BUS_NAME,
140+ INDICATOR_SOUND_OBJECT_PATH,
141+ INDICATOR_SOUND_ACTION_SCROLL,
142+ g_variant_new_int32(offset));
143+}
144+
145+void ScrollIndicatorKeyboard(int offset)
146+{
147+ ActivateIndicator(INDICATOR_KEYBOARD_BUS_NAME,
148+ INDICATOR_KEYBOARD_OBJECT_PATH,
149+ INDICATOR_KEYBOARD_ACTION_SCROLL,
150+ g_variant_new_int32(-offset));
151+}
152+} // namespace
153+
154+AcceleratorController::AcceleratorController()
155+ : accelerators_(new Accelerators)
156+{
157+ auto settings = glib::Object<GSettings>(g_settings_new(MEDIA_KEYS_SCHEMA));
158+
159+ auto accelerator = std::make_shared<Accelerator>(glib::String(g_settings_get_string(settings, MEDIA_KEYS_KEY_VOLUME_MUTE)));
160+ accelerator->activated.connect(std::function<void ()>(MuteIndicatorSound));
161+ accelerators_->Add(accelerator);
162+
163+ accelerator = std::make_shared<Accelerator>(glib::String(g_settings_get_string(settings, MEDIA_KEYS_KEY_VOLUME_DOWN)));
164+ accelerator->activated.connect(std::bind(ScrollIndicatorSound, -1));
165+ accelerators_->Add(accelerator);
166+
167+ accelerator = std::make_shared<Accelerator>(glib::String(g_settings_get_string(settings, MEDIA_KEYS_KEY_VOLUME_UP)));
168+ accelerator->activated.connect(std::bind(ScrollIndicatorSound, +1));
169+ accelerators_->Add(accelerator);
170+
171+ settings = glib::Object<GSettings>(g_settings_new(INPUT_SWITCH_SCHEMA));
172+
173+ auto variant = glib::Variant(g_settings_get_value(settings, INPUT_SWITCH_KEY_PREVIOUS_SOURCE), glib::StealRef());
174+
175+ if (g_variant_n_children(variant) > 0)
176+ {
177+ const gchar* string;
178+
179+ g_variant_get_child(variant, 0, "&s", &string);
180+
181+ accelerator = std::make_shared<Accelerator>(string);
182+ accelerator->activated.connect(std::bind(ScrollIndicatorKeyboard, -1));
183+ accelerators_->Add(accelerator);
184+ }
185+
186+ variant = glib::Variant(g_settings_get_value(settings, INPUT_SWITCH_KEY_NEXT_SOURCE), glib::StealRef());
187+
188+ if (g_variant_n_children(variant) > 0)
189+ {
190+ const gchar* string;
191+
192+ g_variant_get_child(variant, 0, "&s", &string);
193+
194+ accelerator = std::make_shared<Accelerator>(string);
195+ accelerator->activated.connect(std::bind(ScrollIndicatorKeyboard, +1));
196+ accelerators_->Add(accelerator);
197+ }
198+}
199+
200+Accelerators::Ptr const& AcceleratorController::GetAccelerators() const
201+{
202+ return accelerators_;
203+}
204+
205+} // lockscreen namespace
206+} // unity namespace
207
208=== added file 'lockscreen/LockScreenAcceleratorController.h'
209--- lockscreen/LockScreenAcceleratorController.h 1970-01-01 00:00:00 +0000
210+++ lockscreen/LockScreenAcceleratorController.h 2014-04-30 04:35:25 +0000
211@@ -0,0 +1,46 @@
212+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
213+/*
214+ * Copyright (C) 2014 Canonical Ltd
215+ *
216+ * This program is free software: you can redistribute it and/or modify
217+ * it under the terms of the GNU General Public License version 3 as
218+ * published by the Free Software Foundation.
219+ *
220+ * This program is distributed in the hope that it will be useful,
221+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
222+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
223+ * GNU General Public License for more details.
224+ *
225+ * You should have received a copy of the GNU General Public License
226+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
227+ *
228+ * Authored by: William Hua <william.hua@canonical.com>
229+ */
230+
231+#ifndef UNITY_LOCKSCREEN_ACCELERATOR_CONTROLLER
232+#define UNITY_LOCKSCREEN_ACCELERATOR_CONTROLLER
233+
234+#include "LockScreenAccelerators.h"
235+
236+namespace unity
237+{
238+namespace lockscreen
239+{
240+
241+class AcceleratorController
242+{
243+public:
244+ typedef std::shared_ptr<AcceleratorController> Ptr;
245+
246+ AcceleratorController();
247+
248+ Accelerators::Ptr const& GetAccelerators() const;
249+
250+private:
251+ Accelerators::Ptr accelerators_;
252+};
253+
254+} // lockscreen namespace
255+} // unity namespace
256+
257+#endif // UNITY_LOCKSCREEN_ACCELERATOR_CONTROLLER
258
259=== added file 'lockscreen/LockScreenAccelerators.cpp'
260--- lockscreen/LockScreenAccelerators.cpp 1970-01-01 00:00:00 +0000
261+++ lockscreen/LockScreenAccelerators.cpp 2014-04-30 04:35:25 +0000
262@@ -0,0 +1,528 @@
263+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
264+/*
265+ * Copyright (C) 2014 Canonical Ltd
266+ *
267+ * This program is free software: you can redistribute it and/or modify
268+ * it under the terms of the GNU General Public License version 3 as
269+ * published by the Free Software Foundation.
270+ *
271+ * This program is distributed in the hope that it will be useful,
272+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
273+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
274+ * GNU General Public License for more details.
275+ *
276+ * You should have received a copy of the GNU General Public License
277+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
278+ *
279+ * Authored by: William Hua <william.hua@canonical.com>
280+ */
281+
282+#include "LockScreenAccelerators.h"
283+
284+#include <NuxGraphics/Events.h>
285+#include <gtk/gtk.h>
286+
287+namespace unity
288+{
289+namespace lockscreen
290+{
291+
292+enum class PressedState : unsigned int
293+{
294+ NothingPressed = 0x00,
295+ LeftShiftPressed = 0x01,
296+ LeftControlPressed = 0x02,
297+ LeftAltPressed = 0x04,
298+ LeftSuperPressed = 0x08,
299+ RightShiftPressed = 0x10,
300+ RightControlPressed = 0x20,
301+ RightAltPressed = 0x40,
302+ RightSuperPressed = 0x80
303+};
304+
305+PressedState operator~(PressedState const& first)
306+{
307+ return static_cast<PressedState>(~static_cast<unsigned int>(first));
308+}
309+
310+PressedState operator&(PressedState const& first, PressedState const& second)
311+{
312+ return static_cast<PressedState>(static_cast<unsigned int>(first) & static_cast<unsigned int>(second));
313+}
314+
315+PressedState operator|(PressedState const& first, PressedState const& second)
316+{
317+ return static_cast<PressedState>(static_cast<unsigned int>(first) | static_cast<unsigned int>(second));
318+}
319+
320+PressedState& operator&=(PressedState& first, PressedState const& second)
321+{
322+ return first = first & second;
323+}
324+
325+PressedState& operator|=(PressedState& first, PressedState const& second)
326+{
327+ return first = first | second;
328+}
329+
330+namespace
331+{
332+unsigned int KeysymToModifier(unsigned int keysym)
333+{
334+ switch (keysym)
335+ {
336+ case GDK_KEY_Shift_L:
337+ case GDK_KEY_Shift_R:
338+ return nux::KEY_MODIFIER_SHIFT;
339+ case GDK_KEY_Control_L:
340+ case GDK_KEY_Control_R:
341+ return nux::KEY_MODIFIER_CTRL;
342+ case GDK_KEY_Meta_L:
343+ case GDK_KEY_Meta_R:
344+ case GDK_KEY_Alt_L:
345+ case GDK_KEY_Alt_R:
346+ return nux::KEY_MODIFIER_ALT;
347+ case GDK_KEY_Super_L:
348+ case GDK_KEY_Super_R:
349+ return nux::KEY_MODIFIER_SUPER;
350+ }
351+
352+ return 0;
353+}
354+
355+PressedState KeysymToPressedState(unsigned int keysym)
356+{
357+ switch (keysym)
358+ {
359+ case GDK_KEY_Shift_L:
360+ return PressedState::LeftShiftPressed;
361+ case GDK_KEY_Shift_R:
362+ return PressedState::RightShiftPressed;
363+ case GDK_KEY_Control_L:
364+ return PressedState::LeftControlPressed;
365+ case GDK_KEY_Control_R:
366+ return PressedState::RightControlPressed;
367+ case GDK_KEY_Meta_L:
368+ case GDK_KEY_Alt_L:
369+ return PressedState::LeftAltPressed;
370+ case GDK_KEY_Meta_R:
371+ case GDK_KEY_Alt_R:
372+ return PressedState::RightAltPressed;
373+ case GDK_KEY_Super_L:
374+ return PressedState::LeftSuperPressed;
375+ case GDK_KEY_Super_R:
376+ return PressedState::RightSuperPressed;
377+ }
378+
379+ return PressedState::NothingPressed;
380+}
381+
382+unsigned int KeysymToMirrorKeysym(unsigned int keysym)
383+{
384+ switch (keysym)
385+ {
386+ case GDK_KEY_Shift_L:
387+ return GDK_KEY_Shift_R;
388+ case GDK_KEY_Shift_R:
389+ return GDK_KEY_Shift_L;
390+ case GDK_KEY_Control_L:
391+ return GDK_KEY_Control_R;
392+ case GDK_KEY_Control_R:
393+ return GDK_KEY_Control_L;
394+ case GDK_KEY_Meta_L:
395+ return GDK_KEY_Meta_R;
396+ case GDK_KEY_Meta_R:
397+ return GDK_KEY_Meta_L;
398+ case GDK_KEY_Alt_L:
399+ return GDK_KEY_Alt_R;
400+ case GDK_KEY_Alt_R:
401+ return GDK_KEY_Alt_L;
402+ case GDK_KEY_Super_L:
403+ return GDK_KEY_Super_R;
404+ case GDK_KEY_Super_R:
405+ return GDK_KEY_Super_L;
406+ }
407+
408+ return 0;
409+}
410+} // namespace
411+
412+Accelerator::Accelerator(unsigned int keysym,
413+ unsigned int keycode,
414+ unsigned int modifiers)
415+ : keysym_(keysym)
416+ , keycode_(keycode)
417+ , modifiers_(modifiers)
418+ , active_(true)
419+ , activated_(false)
420+{
421+}
422+
423+Accelerator::Accelerator(std::string const& string)
424+ : keysym_(0)
425+ , keycode_(0)
426+ , modifiers_(0)
427+ , active_(true)
428+ , activated_(false)
429+{
430+ guint keysym;
431+ guint* keycodes;
432+ GdkModifierType modifiers;
433+
434+ gtk_accelerator_parse_with_keycode(string.c_str(), &keysym, &keycodes, &modifiers);
435+
436+ /* gtk_accelerator_parse_with_keycode() might fail if the key is not in the
437+ * default key map. gtk_accelerator_parse() might succeed in this case. */
438+ if (keysym == 0 && keycodes == NULL && modifiers == 0)
439+ gtk_accelerator_parse(string.c_str(), &keysym, &modifiers);
440+
441+ keysym_ = keysym;
442+
443+ if (keycodes != NULL)
444+ {
445+ keycode_ = keycodes[0];
446+ g_free(keycodes);
447+ }
448+
449+ if (modifiers & GDK_SHIFT_MASK)
450+ modifiers_ |= nux::KEY_MODIFIER_SHIFT;
451+ if (modifiers & GDK_CONTROL_MASK)
452+ modifiers_ |= nux::KEY_MODIFIER_CTRL;
453+ if ((modifiers & GDK_MOD1_MASK) || (modifiers & GDK_META_MASK))
454+ modifiers_ |= nux::KEY_MODIFIER_ALT;
455+ if (modifiers & GDK_SUPER_MASK)
456+ modifiers_ |= nux::KEY_MODIFIER_SUPER;
457+}
458+
459+bool Accelerator::operator==(Accelerator const& accelerator) const
460+{
461+ return keysym_ == accelerator.keysym_
462+ && keycode_ == accelerator.keycode_
463+ && modifiers_ == accelerator.modifiers_;
464+}
465+
466+bool Accelerator::KeyPressActivate()
467+{
468+ activated.emit();
469+ activated_ = true;
470+
471+ return true;
472+}
473+
474+bool Accelerator::KeyReleaseActivate()
475+{
476+ activated.emit();
477+ activated_ = false;
478+
479+ return true;
480+}
481+
482+bool Accelerator::HandleKeyPress(unsigned int keysym,
483+ unsigned int modifiers,
484+ PressedState pressed_state)
485+{
486+ auto is_modifier_only = keysym_ == 0 && keycode_ == 0 && modifiers_ != 0;
487+ auto is_modifier_keysym = KeysymToModifier(keysym_);
488+ auto modifier = KeysymToModifier(keysym);
489+
490+ if (modifiers == 0)
491+ {
492+ /* We're pressing a key when no other key is pressed. We can reset this
493+ * accelerator back to its original enabled state. */
494+ active_ = true;
495+ activated_ = false;
496+ }
497+
498+ if (!active_)
499+ return false;
500+
501+ /* We need to cancel modifier-only accelerators in some cases. For example,
502+ * we should cancel a Ctrl+Alt accelerator if Ctrl+Alt+T is pressed. */
503+ if (is_modifier_only || is_modifier_keysym)
504+ {
505+ if (!modifier)
506+ {
507+ /* We pressed a non-modifier key for a modifier-only accelerator. */
508+ active_ = false;
509+ return false;
510+ }
511+ else if (keysym != keysym_ && (modifiers_ & modifier) == 0)
512+ {
513+ /* We pressed a modifier key that isn't the keysym and isn't one of the
514+ * modifiers. */
515+ active_ = false;
516+ return false;
517+ }
518+ }
519+ else if (!modifier)
520+ {
521+ /* We expect a non-modifier key to activate and one was pressed. */
522+ if (modifiers == modifiers_)
523+ {
524+ /* The modifiers match. Check if the keysyms match. */
525+ if (keysym == keysym_)
526+ return KeyPressActivate();
527+ else
528+ {
529+ /* Otherwise, check if the keycodes match. Maybe the accelerator
530+ * specifies a particular key code, or the keyboard layout changed. For
531+ * example, if the accelerator is Ctrl+A and the user switches from a
532+ * QWERTY to an AZERTY layout, we should accept Ctrl+Q so the user can
533+ * cycle through the entire list of keyboard layouts. */
534+
535+ GdkKeymapKey* key;
536+ gint keys;
537+
538+ if (gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), keysym, &key, &keys))
539+ {
540+ for (auto i = 0; i < keys; i++)
541+ {
542+ if (key[i].keycode == keycode_)
543+ {
544+ g_free(key);
545+
546+ return KeyPressActivate();
547+ }
548+ }
549+
550+ g_free(key);
551+ }
552+ }
553+ }
554+ }
555+
556+ return false;
557+}
558+
559+bool Accelerator::HandleKeyRelease(unsigned int keysym,
560+ unsigned int modifiers,
561+ PressedState pressed_state)
562+{
563+ auto is_modifier_only = keysym_ == 0 && keycode_ == 0 && modifiers_ != 0;
564+ auto is_modifier_keysym = KeysymToModifier(keysym_);
565+ auto modifier = KeysymToModifier(keysym);
566+
567+ /* Don't activate on key release if we were activated on a key press. */
568+ if (!active_ || activated_)
569+ return false;
570+
571+ /* Check if the keysyms match. */
572+ if (keysym == keysym_)
573+ {
574+ if (KeysymToModifier(keysym) == 0)
575+ {
576+ /* We released a non-modifier key. */
577+ if (modifiers == modifiers_)
578+ return KeyReleaseActivate();
579+ }
580+ else
581+ {
582+ /* We released a modifier key. */
583+ auto mirror_keysym = KeysymToMirrorKeysym(keysym);
584+ auto is_mirror_pressed = (pressed_state & KeysymToPressedState(mirror_keysym)) != PressedState::NothingPressed;
585+
586+ /* Ctrl+Shift_R is different from Ctrl+Shift+Shift_R, so we must detect
587+ * if the mirror key was pressed or not. */
588+ if (is_mirror_pressed)
589+ {
590+ /* The mirrored modifier is pressed. */
591+ if (modifiers == modifiers_)
592+ return KeyReleaseActivate();
593+ }
594+ else
595+ {
596+ /* The mirrored modifier wasn't pressed. Compare modifiers without it. */
597+ if ((modifiers & ~KeysymToModifier(mirror_keysym)) == modifiers_)
598+ return KeyReleaseActivate();
599+ }
600+ }
601+ }
602+
603+ if (is_modifier_only || is_modifier_keysym)
604+ {
605+ if (modifier)
606+ {
607+ /* We released a modifier key for a modifier-only accelerator. */
608+
609+ if (is_modifier_only)
610+ {
611+ /* The accelerator has no keysym or keycode. */
612+
613+ /* TODO: Normally we would activate here, but compiz is intercepting
614+ * this case and handling it. This is bad because now we can't do
615+ * anything here. Otherwise we'll do the same action twice. */
616+ if (modifiers == modifiers_)
617+ return false;
618+ }
619+ else
620+ {
621+ /* The accelerator has a modifier keysym. */
622+ auto is_keysym_pressed = (pressed_state & KeysymToPressedState(keysym_)) != PressedState::NothingPressed;
623+
624+ if (is_keysym_pressed)
625+ {
626+ auto mirror_keysym = KeysymToMirrorKeysym(keysym_);
627+ auto is_mirror_pressed = (pressed_state & KeysymToPressedState(mirror_keysym)) != PressedState::NothingPressed;
628+
629+ /* Ctrl+Shift_R is different from Ctrl+Shift+Shift_R, so we must detect
630+ * if the mirror key was pressed or not. */
631+ if (is_mirror_pressed)
632+ {
633+ /* The mirrored modifier is pressed. */
634+ if (modifiers == modifiers_)
635+ return KeyReleaseActivate();
636+ }
637+ else
638+ {
639+ /* The mirrored modifier wasn't pressed. Compare modifiers without it. */
640+ if ((modifiers & ~KeysymToModifier(mirror_keysym)) == modifiers_)
641+ return KeyReleaseActivate();
642+ }
643+ }
644+ }
645+ }
646+ }
647+ else if (keycode_ != 0 && modifiers == modifiers_)
648+ {
649+ /* Otherwise, check if the keycodes match. Maybe the accelerator
650+ * specifies a particular key code, or the keyboard layout changed. For
651+ * example, if the accelerator is Ctrl+A and the user switches from a
652+ * QWERTY to an AZERTY layout, we should accept Ctrl+Q so the user can
653+ * cycle through the entire list of keyboard layouts. */
654+
655+ GdkKeymapKey* key;
656+ gint keys;
657+
658+ if (gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), keysym, &key, &keys))
659+ {
660+ for (auto i = 0; i < keys; i++)
661+ {
662+ if (key[i].keycode == keycode_)
663+ {
664+ g_free(key);
665+
666+ return KeyReleaseActivate();
667+ }
668+ }
669+
670+ g_free(key);
671+ }
672+ }
673+
674+ return false;
675+}
676+
677+Accelerators::Accelerators()
678+ : pressed_state_(PressedState::NothingPressed)
679+{
680+}
681+
682+void Accelerators::Clear()
683+{
684+ accelerators_.clear();
685+}
686+
687+void Accelerators::Add(Accelerator::Ptr const& accelerator)
688+{
689+ accelerators_.push_back(accelerator);
690+}
691+
692+void Accelerators::Remove(Accelerator::Ptr const& accelerator)
693+{
694+ accelerators_.erase(std::remove(accelerators_.begin(), accelerators_.end(), accelerator), accelerators_.end());
695+}
696+
697+bool Accelerators::HandleKeyPress(unsigned int keysym,
698+ unsigned int modifiers)
699+{
700+ modifiers &= nux::KEY_MODIFIER_SHIFT
701+ | nux::KEY_MODIFIER_CTRL
702+ | nux::KEY_MODIFIER_ALT
703+ | nux::KEY_MODIFIER_SUPER;
704+
705+ switch (keysym)
706+ {
707+ case GDK_KEY_Shift_L:
708+ pressed_state_ |= PressedState::LeftShiftPressed;
709+ break;
710+ case GDK_KEY_Shift_R:
711+ pressed_state_ |= PressedState::RightShiftPressed;
712+ break;
713+ case GDK_KEY_Control_L:
714+ pressed_state_ |= PressedState::LeftControlPressed;
715+ break;
716+ case GDK_KEY_Control_R:
717+ pressed_state_ |= PressedState::RightControlPressed;
718+ break;
719+ case GDK_KEY_Meta_L:
720+ case GDK_KEY_Alt_L:
721+ pressed_state_ |= PressedState::LeftAltPressed;
722+ break;
723+ case GDK_KEY_Meta_R:
724+ case GDK_KEY_Alt_R:
725+ pressed_state_ |= PressedState::RightAltPressed;
726+ break;
727+ case GDK_KEY_Super_L:
728+ pressed_state_ |= PressedState::LeftSuperPressed;
729+ break;
730+ case GDK_KEY_Super_R:
731+ pressed_state_ |= PressedState::RightSuperPressed;
732+ break;
733+ }
734+
735+ auto handled = false;
736+
737+ for (auto& accelerator : accelerators_)
738+ handled = accelerator->HandleKeyPress(keysym, modifiers, pressed_state_) || handled;
739+
740+ return handled;
741+}
742+
743+bool Accelerators::HandleKeyRelease(unsigned int keysym,
744+ unsigned int modifiers)
745+{
746+ modifiers &= nux::KEY_MODIFIER_SHIFT
747+ | nux::KEY_MODIFIER_CTRL
748+ | nux::KEY_MODIFIER_ALT
749+ | nux::KEY_MODIFIER_SUPER;
750+
751+ auto handled = false;
752+
753+ for (auto& accelerator : accelerators_)
754+ handled = accelerator->HandleKeyRelease(keysym, modifiers, pressed_state_) || handled;
755+
756+ switch (keysym)
757+ {
758+ case GDK_KEY_Shift_L:
759+ pressed_state_ &= ~PressedState::LeftShiftPressed;
760+ break;
761+ case GDK_KEY_Shift_R:
762+ pressed_state_ &= ~PressedState::RightShiftPressed;
763+ break;
764+ case GDK_KEY_Control_L:
765+ pressed_state_ &= ~PressedState::LeftControlPressed;
766+ break;
767+ case GDK_KEY_Control_R:
768+ pressed_state_ &= ~PressedState::RightControlPressed;
769+ break;
770+ case GDK_KEY_Meta_L:
771+ case GDK_KEY_Alt_L:
772+ pressed_state_ &= ~PressedState::LeftAltPressed;
773+ break;
774+ case GDK_KEY_Meta_R:
775+ case GDK_KEY_Alt_R:
776+ pressed_state_ &= ~PressedState::RightAltPressed;
777+ break;
778+ case GDK_KEY_Super_L:
779+ pressed_state_ &= ~PressedState::LeftSuperPressed;
780+ break;
781+ case GDK_KEY_Super_R:
782+ pressed_state_ &= ~PressedState::RightSuperPressed;
783+ break;
784+ }
785+
786+ return handled;
787+}
788+
789+} // lockscreen namespace
790+} // unity namespace
791
792=== added file 'lockscreen/LockScreenAccelerators.h'
793--- lockscreen/LockScreenAccelerators.h 1970-01-01 00:00:00 +0000
794+++ lockscreen/LockScreenAccelerators.h 2014-04-30 04:35:25 +0000
795@@ -0,0 +1,92 @@
796+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
797+/*
798+ * Copyright (C) 2014 Canonical Ltd
799+ *
800+ * This program is free software: you can redistribute it and/or modify
801+ * it under the terms of the GNU General Public License version 3 as
802+ * published by the Free Software Foundation.
803+ *
804+ * This program is distributed in the hope that it will be useful,
805+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
806+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
807+ * GNU General Public License for more details.
808+ *
809+ * You should have received a copy of the GNU General Public License
810+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
811+ *
812+ * Authored by: William Hua <william.hua@canonical.com>
813+ */
814+
815+#ifndef UNITY_LOCKSCREEN_ACCELERATORS
816+#define UNITY_LOCKSCREEN_ACCELERATORS
817+
818+#include <memory>
819+#include <sigc++/signal.h>
820+
821+namespace unity
822+{
823+namespace lockscreen
824+{
825+
826+enum class PressedState : unsigned int;
827+
828+class Accelerator
829+{
830+public:
831+ typedef std::shared_ptr<Accelerator> Ptr;
832+
833+ Accelerator(unsigned int keysym, unsigned int keycode, unsigned int modifiers);
834+ explicit Accelerator(std::string const& string);
835+
836+ bool operator==(Accelerator const& accelerator) const;
837+
838+ sigc::signal<void> activated;
839+
840+private:
841+ bool KeyPressActivate();
842+ bool KeyReleaseActivate();
843+
844+ bool HandleKeyPress(unsigned int keysym,
845+ unsigned int modifiers,
846+ PressedState pressed_state);
847+ bool HandleKeyRelease(unsigned int keysym,
848+ unsigned int modifiers,
849+ PressedState pressed_state);
850+
851+ unsigned int keysym_;
852+ unsigned int keycode_;
853+ unsigned int modifiers_;
854+
855+ bool active_;
856+ bool activated_;
857+
858+ friend class Accelerators;
859+};
860+
861+class Accelerators
862+{
863+public:
864+ typedef std::shared_ptr<Accelerators> Ptr;
865+
866+ Accelerators();
867+
868+ void Clear();
869+
870+ void Add(Accelerator::Ptr const& accelerator);
871+ void Remove(Accelerator::Ptr const& accelerator);
872+
873+ bool HandleKeyPress(unsigned int keysym,
874+ unsigned int modifiers);
875+ bool HandleKeyRelease(unsigned int keysym,
876+ unsigned int modifiers);
877+
878+private:
879+ std::vector<Accelerator::Ptr> accelerators_;
880+
881+ PressedState pressed_state_;
882+};
883+
884+} // lockscreen namespace
885+} // unity namespace
886+
887+#endif // UNITY_LOCKSCREEN_ACCELERATORS
888
889=== modified file 'lockscreen/LockScreenController.cpp'
890--- lockscreen/LockScreenController.cpp 2014-04-11 07:26:11 +0000
891+++ lockscreen/LockScreenController.cpp 2014-04-30 04:35:25 +0000
892@@ -107,6 +107,7 @@
893 shields_.clear();
894
895 upstart_wrapper_->Emit("desktop-unlock");
896+ accelerator_controller_.reset();
897 indicators_.reset();
898 }
899 else if (!prompt_activation_)
900@@ -141,6 +142,12 @@
901 });
902 }
903
904+void Controller::ActivatePanel()
905+{
906+ if (primary_shield_.IsValid())
907+ primary_shield_->ActivatePanel();
908+}
909+
910 void Controller::ResetPostLockScreenSaver()
911 {
912 screensaver_post_lock_timeout_.reset();
913@@ -186,7 +193,7 @@
914
915 if (i >= shields_size)
916 {
917- shield = shield_factory_->CreateShield(session_manager_, indicators_, i, i == primary);
918+ shield = shield_factory_->CreateShield(session_manager_, indicators_, accelerator_controller_->GetAccelerators(), i, i == primary);
919 is_new = true;
920 }
921
922@@ -390,6 +397,12 @@
923 indicators_ = std::make_shared<indicator::LockScreenDBusIndicators>();
924 upstart_wrapper_->Emit("desktop-lock");
925
926+ accelerator_controller_ = std::make_shared<AcceleratorController>();
927+ auto activate_key = WindowManager::Default().activate_indicators_key();
928+ auto accelerator = std::make_shared<Accelerator>(activate_key.second, 0, activate_key.first);
929+ accelerator->activated.connect(std::bind(std::mem_fn(&Controller::ActivatePanel), this));
930+ accelerator_controller_->GetAccelerators()->Add(accelerator);
931+
932 ShowShields();
933 }
934
935
936=== modified file 'lockscreen/LockScreenController.h'
937--- lockscreen/LockScreenController.h 2014-04-10 06:36:43 +0000
938+++ lockscreen/LockScreenController.h 2014-04-30 04:35:25 +0000
939@@ -25,6 +25,7 @@
940 #include <UnityCore/GLibSource.h>
941
942 #include "LockScreenShieldFactory.h"
943+#include "LockScreenAcceleratorController.h"
944 #include "ScreenSaverDBusManager.h"
945 #include "unity-shared/BackgroundEffectHelper.h"
946 #include "unity-shared/UpstartWrapper.h"
947@@ -60,6 +61,7 @@
948 void BlankWindowGrabEnable(bool grab);
949 void SimulateActivity();
950 void ResetPostLockScreenSaver();
951+ void ActivatePanel();
952
953 void OnLockRequested(bool prompt);
954 void OnUnlockRequested();
955@@ -74,6 +76,7 @@
956 DBusManager::Ptr dbus_manager_;
957 session::Manager::Ptr session_manager_;
958 indicator::Indicators::Ptr indicators_;
959+ AcceleratorController::Ptr accelerator_controller_;
960 UpstartWrapper::Ptr upstart_wrapper_;
961 ShieldFactoryInterface::Ptr shield_factory_;
962
963@@ -98,4 +101,4 @@
964 }
965 }
966
967-#endif
968\ No newline at end of file
969+#endif
970
971=== modified file 'lockscreen/LockScreenPanel.cpp'
972--- lockscreen/LockScreenPanel.cpp 2014-04-10 16:49:05 +0000
973+++ lockscreen/LockScreenPanel.cpp 2014-04-30 04:35:25 +0000
974@@ -21,7 +21,6 @@
975
976 #include <boost/algorithm/string/trim.hpp>
977 #include <Nux/HLayout.h>
978-#include <UnityCore/Variant.h>
979
980 #include "LockScreenSettings.h"
981 #include "panel/PanelIndicatorsView.h"
982@@ -39,30 +38,6 @@
983 namespace
984 {
985 const RawPixel PADDING = 5_em;
986-
987-const std::string MEDIA_KEYS_SCHEMA = "org.gnome.settings-daemon.plugins.media-keys";
988-const std::string MEDIA_KEYS_VOLUME_MUTE = "volume-mute";
989-const std::string MEDIA_KEYS_VOLUME_DOWN = "volume-down";
990-const std::string MEDIA_KEYS_VOLUME_UP = "volume-up";
991-const std::string INPUT_SWITCH_SCHEMA = "org.gnome.desktop.wm.keybindings";
992-const std::string INPUT_SWITCH_PREVIOUS = "switch-input-source-backward";
993-const std::string INPUT_SWITCH_NEXT = "switch-input-source";
994-
995-const std::string INDICATOR_KEYBOARD_BUS_NAME = "com.canonical.indicator.keyboard";
996-const std::string INDICATOR_KEYBOARD_OBJECT_PATH = "/com/canonical/indicator/keyboard";
997-const std::string INDICATOR_SOUND_BUS_NAME = "com.canonical.indicator.sound";
998-const std::string INDICATOR_SOUND_OBJECT_PATH = "/com/canonical/indicator/sound";
999-const std::string INDICATOR_ACTION_INTERFACE = "org.gtk.Actions";
1000-
1001-const std::string INDICATOR_KEYBOARD_ACTION_SCROLL = "locked_scroll";
1002-const std::string INDICATOR_SOUND_ACTION_SCROLL = "scroll";
1003-const std::string INDICATOR_SOUND_ACTION_MUTE = "mute";
1004-
1005-const unsigned int MODIFIERS = nux::KEY_MODIFIER_SHIFT |
1006- nux::KEY_MODIFIER_CAPS_LOCK |
1007- nux::KEY_MODIFIER_CTRL |
1008- nux::KEY_MODIFIER_ALT |
1009- nux::KEY_MODIFIER_SUPER;
1010 }
1011
1012 using namespace indicator;
1013@@ -74,8 +49,6 @@
1014 , monitor(monitor_)
1015 , indicators_(indicators)
1016 , needs_geo_sync_(true)
1017- , media_key_settings_(g_settings_new(MEDIA_KEYS_SCHEMA.c_str()))
1018- , input_switch_settings_(g_settings_new(INPUT_SWITCH_SCHEMA.c_str()))
1019 {
1020 double scale = unity::Settings::Instance().em(monitor)->DPIScale();
1021 auto* layout = new nux::HLayout();
1022@@ -114,11 +87,6 @@
1023 BuildTexture();
1024 QueueRelayout();
1025 });
1026-
1027- ParseAccelerators();
1028-
1029- key_down.connect(sigc::mem_fun(this, &Panel::OnKeyDown));
1030- key_up.connect(sigc::mem_fun(this, &Panel::OnKeyUp));
1031 }
1032
1033 void Panel::BuildTexture()
1034@@ -180,12 +148,6 @@
1035 indicators_view_->ActivateEntry(entry_id, 0);
1036 }
1037
1038-void Panel::ActivateFirst()
1039-{
1040- if (GetInputEventSensitivity())
1041- indicators_view_->ActivateIfSensitive();
1042-}
1043-
1044 void Panel::OnEntryActivated(std::string const& panel, std::string const& entry_id, nux::Rect const&)
1045 {
1046 if (!GetInputEventSensitivity() || (!panel.empty() && panel != GetPanelName()))
1047@@ -247,210 +209,15 @@
1048 }
1049 }
1050
1051-Panel::Accelerator Panel::ParseAcceleratorString(std::string const& string) const
1052-{
1053- guint gtk_key;
1054- GdkModifierType gtk_modifiers;
1055- gtk_accelerator_parse(string.c_str(), &gtk_key, &gtk_modifiers);
1056-
1057- unsigned int nux_key = gtk_key;
1058- unsigned int nux_modifiers = 0;
1059-
1060- if (gtk_modifiers & GDK_SHIFT_MASK)
1061- nux_modifiers |= nux::KEY_MODIFIER_SHIFT;
1062- if (gtk_modifiers & GDK_LOCK_MASK)
1063- nux_modifiers |= nux::KEY_MODIFIER_CAPS_LOCK;
1064- if (gtk_modifiers & GDK_CONTROL_MASK)
1065- nux_modifiers |= nux::KEY_MODIFIER_CTRL;
1066- if (gtk_modifiers & GDK_MOD1_MASK)
1067- nux_modifiers |= nux::KEY_MODIFIER_ALT;
1068- if (gtk_modifiers & GDK_SUPER_MASK)
1069- nux_modifiers |= nux::KEY_MODIFIER_SUPER;
1070-
1071- return std::make_pair(nux_modifiers, nux_key);
1072-}
1073-
1074-void Panel::ParseAccelerators()
1075-{
1076- activate_indicator_ = WindowManager::Default().activate_indicators_key();
1077- volume_mute_ = ParseAcceleratorString(glib::String(g_settings_get_string(media_key_settings_, MEDIA_KEYS_VOLUME_MUTE.c_str())));
1078- volume_down_ = ParseAcceleratorString(glib::String(g_settings_get_string(media_key_settings_, MEDIA_KEYS_VOLUME_DOWN.c_str())));
1079- volume_up_ = ParseAcceleratorString(glib::String(g_settings_get_string(media_key_settings_, MEDIA_KEYS_VOLUME_UP.c_str())));
1080-
1081- auto variant = glib::Variant(g_settings_get_value(input_switch_settings_, INPUT_SWITCH_PREVIOUS.c_str()), glib::StealRef());
1082-
1083- if (g_variant_n_children(variant) > 0)
1084- {
1085- const gchar *accelerator;
1086- g_variant_get_child(variant, 0, "&s", &accelerator);
1087- previous_source_ = ParseAcceleratorString(accelerator);
1088- }
1089- else
1090- previous_source_ = std::make_pair(0, 0);
1091-
1092- variant = glib::Variant(g_settings_get_value(input_switch_settings_, INPUT_SWITCH_NEXT.c_str()), glib::StealRef());
1093-
1094- if (g_variant_n_children(variant) > 0)
1095- {
1096- const gchar *accelerator;
1097- g_variant_get_child(variant, 0, "&s", &accelerator);
1098- next_source_ = ParseAcceleratorString(accelerator);
1099- }
1100- else
1101- next_source_ = std::make_pair(0, 0);
1102-}
1103-
1104-bool Panel::WillHandleKeyEvent(unsigned int event_type, unsigned long key_sym, unsigned long modifiers)
1105-{
1106- auto is_press = event_type == nux::EVENT_KEY_DOWN;
1107-
1108- /* If we're just pressing a key, and no modifiers are pressed, then
1109- * we can start accepting new actions again. */
1110- if (is_press && (modifiers & MODIFIERS) == 0)
1111- last_action_ = std::make_pair(0, 0);
1112-
1113- return IsMatch(is_press, key_sym, modifiers, activate_indicator_) ||
1114- IsMatch(is_press, key_sym, modifiers, volume_mute_) ||
1115- IsMatch(is_press, key_sym, modifiers, volume_down_) ||
1116- IsMatch(is_press, key_sym, modifiers, volume_up_) ||
1117- IsMatch(is_press, key_sym, modifiers, previous_source_) ||
1118- IsMatch(is_press, key_sym, modifiers, next_source_);
1119-}
1120-
1121 bool Panel::InspectKeyEvent(unsigned int event_type, unsigned int keysym, const char*)
1122 {
1123 return true;
1124 }
1125
1126-bool Panel::IsMatch(bool is_press,
1127- unsigned int key_sym,
1128- unsigned int state,
1129- Accelerator const& accelerator) const
1130-{
1131- /* Do the easy check, just compare key codes and modifiers.
1132- * TODO: Check permutations of modifier-only shortcuts. */
1133- return key_sym == accelerator.second && (state & MODIFIERS) == accelerator.first;
1134-}
1135-
1136-void Panel::OnKeyDown(unsigned long event,
1137- unsigned long key_sym,
1138- unsigned long state,
1139- const char* text,
1140- unsigned short repeat)
1141-{
1142- if (IsMatch(true, key_sym, state, activate_indicator_))
1143- {
1144- ActivateFirst();
1145- last_action_ = activate_indicator_;
1146- }
1147- else if (IsMatch(true, key_sym, state, volume_mute_))
1148- {
1149- ActivateSoundAction(INDICATOR_SOUND_ACTION_MUTE);
1150- last_action_ = volume_mute_;
1151- }
1152- else if (IsMatch(true, key_sym, state, volume_down_))
1153- {
1154- ActivateSoundAction(INDICATOR_SOUND_ACTION_SCROLL, g_variant_new_int32(-1));
1155- last_action_ = volume_down_;
1156- }
1157- else if (IsMatch(true, key_sym, state, volume_up_))
1158- {
1159- ActivateSoundAction(INDICATOR_SOUND_ACTION_SCROLL, g_variant_new_int32(+1));
1160- last_action_ = volume_up_;
1161- }
1162- else if (IsMatch(true, key_sym, state, previous_source_))
1163- {
1164- ActivateKeyboardAction(INDICATOR_KEYBOARD_ACTION_SCROLL, g_variant_new_int32(-1));
1165- last_action_ = previous_source_;
1166- }
1167- else if (IsMatch(true, key_sym, state, next_source_))
1168- {
1169- ActivateKeyboardAction(INDICATOR_KEYBOARD_ACTION_SCROLL, g_variant_new_int32(+1));
1170- last_action_ = next_source_;
1171- }
1172-}
1173-
1174-void Panel::OnKeyUp(unsigned int key_sym,
1175- unsigned long key_code,
1176- unsigned long state)
1177-{
1178- /* We only want to act if we didn't activate the action on key
1179- * down. Once we see the key up, we can start accepting actions
1180- * again. */
1181-
1182- if (IsMatch(false, key_sym, state, activate_indicator_))
1183- {
1184- if (last_action_ != activate_indicator_)
1185- ActivateFirst();
1186-
1187- last_action_ = std::make_pair(0, 0);
1188- }
1189- else if (IsMatch(false, key_sym, state, volume_mute_))
1190- {
1191- if (last_action_ != volume_mute_)
1192- ActivateSoundAction(INDICATOR_SOUND_ACTION_MUTE);
1193-
1194- last_action_ = std::make_pair(0, 0);
1195- }
1196- else if (IsMatch(false, key_sym, state, volume_down_))
1197- {
1198- if (last_action_ != volume_down_)
1199- ActivateSoundAction(INDICATOR_SOUND_ACTION_SCROLL, g_variant_new_int32(-1));
1200-
1201- last_action_ = std::make_pair(0, 0);
1202- }
1203- else if (IsMatch(false, key_sym, state, volume_up_))
1204- {
1205- if (last_action_ != volume_up_)
1206- ActivateSoundAction(INDICATOR_SOUND_ACTION_SCROLL, g_variant_new_int32(+1));
1207-
1208- last_action_ = std::make_pair(0, 0);
1209- }
1210- else if (IsMatch(false, key_sym, state, previous_source_))
1211- {
1212- if (last_action_ != previous_source_)
1213- ActivateKeyboardAction(INDICATOR_KEYBOARD_ACTION_SCROLL, g_variant_new_int32(-1));
1214-
1215- last_action_ = std::make_pair(0, 0);
1216- }
1217- else if (IsMatch(false, key_sym, state, next_source_))
1218- {
1219- if (last_action_ != next_source_)
1220- ActivateKeyboardAction(INDICATOR_KEYBOARD_ACTION_SCROLL, g_variant_new_int32(+1));
1221-
1222- last_action_ = std::make_pair(0, 0);
1223- }
1224-}
1225-
1226-void Panel::ActivateIndicatorAction(std::string const& bus_name,
1227- std::string const& object_path,
1228- std::string const& action,
1229- glib::Variant const& parameter) const
1230-{
1231- GVariantBuilder builder;
1232-
1233- g_variant_builder_init(&builder, G_VARIANT_TYPE("(sava{sv})"));
1234- g_variant_builder_add(&builder, "s", action.c_str());
1235-
1236- if (parameter)
1237- g_variant_builder_add_parsed(&builder, "[%v]", (GVariant*) parameter);
1238- else
1239- g_variant_builder_add_parsed(&builder, "@av []");
1240-
1241- g_variant_builder_add_parsed(&builder, "@a{sv} []");
1242-
1243- auto proxy = std::make_shared<glib::DBusProxy>(bus_name, object_path, INDICATOR_ACTION_INTERFACE, G_BUS_TYPE_SESSION);
1244- proxy->CallBegin("Activate", g_variant_builder_end(&builder), [proxy] (GVariant*, glib::Error const&) {});
1245-}
1246-
1247-void Panel::ActivateKeyboardAction(std::string const& action, glib::Variant const& parameter) const
1248-{
1249- ActivateIndicatorAction(INDICATOR_KEYBOARD_BUS_NAME, INDICATOR_KEYBOARD_OBJECT_PATH, action, parameter);
1250-}
1251-
1252-void Panel::ActivateSoundAction(std::string const& action, glib::Variant const& parameter) const
1253-{
1254- ActivateIndicatorAction(INDICATOR_SOUND_BUS_NAME, INDICATOR_SOUND_OBJECT_PATH, action, parameter);
1255+void Panel::ActivatePanel()
1256+{
1257+ if (GetInputEventSensitivity())
1258+ indicators_view_->ActivateIfSensitive();
1259 }
1260
1261 }
1262
1263=== modified file 'lockscreen/LockScreenPanel.h'
1264--- lockscreen/LockScreenPanel.h 2014-04-10 16:23:49 +0000
1265+++ lockscreen/LockScreenPanel.h 2014-04-30 04:35:25 +0000
1266@@ -22,10 +22,8 @@
1267
1268 #include <Nux/Nux.h>
1269 #include <Nux/View.h>
1270-#include <UnityCore/GLibDBusProxy.h>
1271+#include <UnityCore/Indicators.h>
1272 #include <UnityCore/GLibSource.h>
1273-#include <UnityCore/GLibWrapper.h>
1274-#include <UnityCore/Indicators.h>
1275 #include <UnityCore/SessionManager.h>
1276
1277 namespace unity
1278@@ -46,7 +44,7 @@
1279 nux::Property<bool> active;
1280 nux::Property<int> monitor;
1281
1282- bool WillHandleKeyEvent(unsigned int event_type, unsigned long key_sym, unsigned long modifiers);
1283+ void ActivatePanel();
1284
1285 protected:
1286 void Draw(nux::GraphicsEngine& GfxContext, bool force_draw) override;
1287@@ -71,52 +69,6 @@
1288 bool needs_geo_sync_;
1289 nux::Point tracked_pointer_pos_;
1290 glib::Source::UniquePtr track_menu_pointer_timeout_;
1291-
1292- glib::Object<GSettings> media_key_settings_;
1293- glib::Object<GSettings> input_switch_settings_;
1294-
1295- typedef std::pair<unsigned int, unsigned int> Accelerator;
1296- Accelerator ParseAcceleratorString(std::string const& string) const;
1297-
1298- void ParseAccelerators();
1299-
1300- Accelerator activate_indicator_;
1301- Accelerator volume_mute_;
1302- Accelerator volume_down_;
1303- Accelerator volume_up_;
1304- Accelerator previous_source_;
1305- Accelerator next_source_;
1306-
1307- /* We only want to activate the indicator on key press OR key
1308- * release, never both, so we'll need to keep track of the last
1309- * action that occurred. However, holding the keys down should
1310- * allow multiple activations, for example, when the volume
1311- * down button is held down. */
1312- Accelerator last_action_;
1313-
1314- bool IsMatch(bool is_press,
1315- unsigned int key_sym,
1316- unsigned int modifiers,
1317- Accelerator const& accelerator) const;
1318-
1319- void OnKeyDown(unsigned long event,
1320- unsigned long key_sym,
1321- unsigned long state,
1322- const char* text,
1323- unsigned short repeat);
1324-
1325- void OnKeyUp(unsigned int key_sym,
1326- unsigned long key_code,
1327- unsigned long state);
1328-
1329- /* This is just for telling an indicator to do something. */
1330- void ActivateIndicatorAction(std::string const& bus_name,
1331- std::string const& object_path,
1332- std::string const& action,
1333- glib::Variant const& parameter = glib::Variant()) const;
1334-
1335- void ActivateKeyboardAction(std::string const& action, glib::Variant const& parameter = glib::Variant()) const;
1336- void ActivateSoundAction(std::string const& action, glib::Variant const& parameter = glib::Variant()) const;
1337 };
1338
1339 } // lockscreen namespace
1340
1341=== modified file 'lockscreen/LockScreenShield.cpp'
1342--- lockscreen/LockScreenShield.cpp 2014-04-10 17:43:34 +0000
1343+++ lockscreen/LockScreenShield.cpp 2014-04-30 04:35:25 +0000
1344@@ -36,8 +36,8 @@
1345 namespace lockscreen
1346 {
1347
1348-Shield::Shield(session::Manager::Ptr const& session_manager, indicator::Indicators::Ptr const& indicators, int monitor_num, bool is_primary)
1349- : AbstractShield(session_manager, indicators, monitor_num, is_primary)
1350+Shield::Shield(session::Manager::Ptr const& session_manager, indicator::Indicators::Ptr const& indicators, Accelerators::Ptr const& accelerators, int monitor_num, bool is_primary)
1351+ : AbstractShield(session_manager, indicators, accelerators, monitor_num, is_primary)
1352 , bg_settings_(std::make_shared<BackgroundSettings>())
1353 , prompt_view_(nullptr)
1354 , panel_view_(nullptr)
1355@@ -177,14 +177,25 @@
1356 return prompt_view;
1357 }
1358
1359-nux::Area* Shield::FindKeyFocusArea(unsigned etype, unsigned long key_sym, unsigned long modifiers)
1360+nux::Area* Shield::FindKeyFocusArea(unsigned etype, unsigned long keysym, unsigned long modifiers)
1361 {
1362 if (primary)
1363 {
1364- grab_key.emit(modifiers, key_sym);
1365+ grab_key.emit(modifiers, keysym);
1366
1367- if (panel_view_ && panel_view_->WillHandleKeyEvent(etype, key_sym, modifiers))
1368- return panel_view_;
1369+ if (accelerators_)
1370+ {
1371+ if (etype == nux::EVENT_KEY_DOWN)
1372+ {
1373+ if (accelerators_->HandleKeyPress(keysym, modifiers))
1374+ return panel_view_;
1375+ }
1376+ else if (etype == nux::EVENT_KEY_UP)
1377+ {
1378+ if (accelerators_->HandleKeyRelease(keysym, modifiers))
1379+ return panel_view_;
1380+ }
1381+ }
1382
1383 if (prompt_view_)
1384 {
1385@@ -218,5 +229,11 @@
1386 return panel_view_ ? panel_view_->active() : false;
1387 }
1388
1389+void Shield::ActivatePanel()
1390+{
1391+ if (panel_view_)
1392+ panel_view_->ActivatePanel();
1393+}
1394+
1395 }
1396 }
1397
1398=== modified file 'lockscreen/LockScreenShield.h'
1399--- lockscreen/LockScreenShield.h 2014-04-09 17:09:18 +0000
1400+++ lockscreen/LockScreenShield.h 2014-04-30 04:35:25 +0000
1401@@ -36,10 +36,11 @@
1402 class Shield : public AbstractShield
1403 {
1404 public:
1405- Shield(session::Manager::Ptr const&, indicator::Indicators::Ptr const&, int monitor, bool is_primary);
1406+ Shield(session::Manager::Ptr const&, indicator::Indicators::Ptr const&, Accelerators::Ptr const&, int monitor, bool is_primary);
1407
1408 bool IsIndicatorOpen() const override;
1409 void CheckCapsLockPrompt() override;
1410+ void ActivatePanel() override;
1411
1412 protected:
1413 bool AcceptKeyNavFocus() override;
1414
1415=== modified file 'lockscreen/LockScreenShieldFactory.cpp'
1416--- lockscreen/LockScreenShieldFactory.cpp 2014-03-07 18:35:10 +0000
1417+++ lockscreen/LockScreenShieldFactory.cpp 2014-04-30 04:35:25 +0000
1418@@ -25,9 +25,9 @@
1419 namespace lockscreen
1420 {
1421
1422-nux::ObjectPtr<AbstractShield> ShieldFactory::CreateShield(session::Manager::Ptr const& session_manager, indicator::Indicators::Ptr const& indicators, int monitor, bool is_primary)
1423+nux::ObjectPtr<AbstractShield> ShieldFactory::CreateShield(session::Manager::Ptr const& session_manager, indicator::Indicators::Ptr const& indicators, Accelerators::Ptr const& accelerators, int monitor, bool is_primary)
1424 {
1425- return nux::ObjectPtr<Shield>(new Shield(session_manager, indicators, monitor, is_primary));
1426+ return nux::ObjectPtr<Shield>(new Shield(session_manager, indicators, accelerators, monitor, is_primary));
1427 }
1428
1429 }
1430
1431=== modified file 'lockscreen/LockScreenShieldFactory.h'
1432--- lockscreen/LockScreenShieldFactory.h 2014-03-07 18:35:10 +0000
1433+++ lockscreen/LockScreenShieldFactory.h 2014-04-30 04:35:25 +0000
1434@@ -37,12 +37,12 @@
1435
1436 virtual ~ShieldFactoryInterface() = default;
1437
1438- virtual nux::ObjectPtr<AbstractShield> CreateShield(session::Manager::Ptr const&, indicator::Indicators::Ptr const&, int monitor, bool is_primary) = 0;
1439+ virtual nux::ObjectPtr<AbstractShield> CreateShield(session::Manager::Ptr const&, indicator::Indicators::Ptr const&, Accelerators::Ptr const&, int monitor, bool is_primary) = 0;
1440 };
1441
1442 struct ShieldFactory : ShieldFactoryInterface
1443 {
1444- nux::ObjectPtr<AbstractShield> CreateShield(session::Manager::Ptr const&, indicator::Indicators::Ptr const&, int monitor, bool is_primary) override;
1445+ nux::ObjectPtr<AbstractShield> CreateShield(session::Manager::Ptr const&, indicator::Indicators::Ptr const&, Accelerators::Ptr const&, int monitor, bool is_primary) override;
1446 };
1447
1448 }
1449
1450=== modified file 'tests/data/external.gschema.xml'
1451--- tests/data/external.gschema.xml 2014-04-08 22:45:07 +0000
1452+++ tests/data/external.gschema.xml 2014-04-30 04:35:25 +0000
1453@@ -121,4 +121,25 @@
1454 <default>false</default>
1455 </key>
1456 </schema>
1457+
1458+ <schema id="org.gnome.settings-daemon.plugins.media-keys" path="/org/gnome/settings-daemon/plugins/media-keys/">
1459+ <key type="s" name="volume-mute">
1460+ <default>'XF86AudioMute'</default>
1461+ </key>
1462+ <key type="s" name="volume-down">
1463+ <default>'XF86AudioLowerVolume'</default>
1464+ </key>
1465+ <key type="s" name="volume-up">
1466+ <default>'XF86AudioRaiseVolume'</default>
1467+ </key>
1468+ </schema>
1469+
1470+ <schema id="org.gnome.desktop.wm.keybindings" path="/org/gnome/desktop/wm/keybindings/">
1471+ <key type="as" name="switch-input-source-backward">
1472+ <default>["&lt;Shift&gt;&lt;Super&gt;space"]</default>
1473+ </key>
1474+ <key type="as" name="switch-input-source">
1475+ <default>["&lt;Super&gt;space"]</default>
1476+ </key>
1477+ </schema>
1478 </schemalist>
1479
1480=== modified file 'tests/test_lockscreen_controller.cpp'
1481--- tests/test_lockscreen_controller.cpp 2014-04-11 07:26:11 +0000
1482+++ tests/test_lockscreen_controller.cpp 2014-04-30 04:35:25 +0000
1483@@ -52,16 +52,17 @@
1484 struct MockShield : AbstractShield
1485 {
1486 MockShield()
1487- : AbstractShield(nullptr, nullptr, 0, false)
1488+ : AbstractShield(nullptr, nullptr, nullptr, 0, false)
1489 {}
1490
1491 MOCK_CONST_METHOD0(IsIndicatorOpen, bool());
1492 MOCK_METHOD0(CheckCapsLockPrompt, void());
1493+ MOCK_METHOD0(ActivatePanel, void());
1494 };
1495
1496 struct ShieldFactoryMock : ShieldFactoryInterface
1497 {
1498- nux::ObjectPtr<AbstractShield> CreateShield(session::Manager::Ptr const&, indicator::Indicators::Ptr const&, int, bool) override
1499+ nux::ObjectPtr<AbstractShield> CreateShield(session::Manager::Ptr const&, indicator::Indicators::Ptr const&, Accelerators::Ptr const&, int, bool) override
1500 {
1501 return nux::ObjectPtr<AbstractShield>(new MockShield());
1502 }