Merge lp:~3v1n0/unity/input-monitor-menus-scrubbing-triangolation into lp:unity

Proposed by Marco Trevisan (Treviño) on 2016-08-30
Status: Merged
Approved by: Andrea Azzarone on 2016-08-30
Approved revision: no longer in the source branch.
Merged at revision: 4187
Proposed branch: lp:~3v1n0/unity/input-monitor-menus-scrubbing-triangolation
Merge into: lp:unity
Prerequisite: lp:~3v1n0/unity/input-monitor-lockscreen-panel
Diff against target: 1307 lines (+360/-246)
26 files modified
decorations/DecoratedWindow.cpp (+2/-9)
decorations/DecorationsMenuLayout.cpp (+14/-10)
decorations/DecorationsMenuLayout.h (+2/-1)
decorations/DecorationsPriv.h (+0/-1)
lockscreen/KylinLockScreenShield.cpp (+1/-1)
lockscreen/LockScreenBaseShield.cpp (+0/-2)
lockscreen/LockScreenBaseShield.h (+3/-4)
lockscreen/LockScreenController.cpp (+3/-3)
lockscreen/LockScreenController.h (+1/-2)
lockscreen/LockScreenPanel.cpp (+19/-36)
lockscreen/LockScreenPanel.h (+4/-5)
lockscreen/LockScreenShield.cpp (+7/-6)
lockscreen/LockScreenShield.h (+4/-3)
lockscreen/LockScreenShieldFactory.cpp (+2/-2)
lockscreen/LockScreenShieldFactory.h (+3/-3)
panel/PanelIndicatorEntryView.cpp (+10/-0)
panel/PanelMenuView.cpp (+1/-7)
panel/PanelMenuView.h (+0/-2)
panel/PanelView.cpp (+2/-105)
panel/PanelView.h (+2/-9)
tests/test_lockscreen_controller.cpp (+2/-2)
unity-shared/InputMonitor.cpp (+39/-5)
unity-shared/InputMonitor.h (+3/-27)
unity-shared/MenuManager.cpp (+162/-1)
unity-shared/MenuManager.h (+4/-0)
unity-shared/SigcSlotHash.h (+70/-0)
To merge this branch: bzr merge lp:~3v1n0/unity/input-monitor-menus-scrubbing-triangolation
Reviewer Review Type Date Requested Status
Andrea Azzarone (community) 2016-08-30 Approve on 2016-08-30
Review via email: mp+304353@code.launchpad.net

This proposal supersedes a proposal from 2016-08-30.

Commit message

MenuManager: add support for mouse trackers with triangle algorithm support

It allows to register pointer trackers with menu entries selection by using the triangle
technique which prevents menus items from being opened on quick menu scrubbing

Then use use menu::Manager pointer tracker for entries activation in PanelView, LockScreenPanel and DecorationsMenuLayout

To post a comment you must log in.
3827. By Marco Trevisan (Treviño) on 2016-08-30

MenuManager: update active tracker on removal

Andrea Azzarone (azzar1) wrote :

+1

review: Approve
3828. By Marco Trevisan (Treviño) on 2016-08-30

SigcSlotHash: ensure it works with GCC-6

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'decorations/DecoratedWindow.cpp'
2--- decorations/DecoratedWindow.cpp 2016-08-06 16:24:45 +0000
3+++ decorations/DecoratedWindow.cpp 2016-09-01 22:11:45 +0000
4@@ -37,7 +37,6 @@
5 {
6 namespace
7 {
8-const std::string MENUS_PANEL_NAME = "WindowLIM";
9 const int SHADOW_BLUR_MARGIN_FACTOR = 2;
10 }
11
12@@ -55,7 +54,6 @@
13 , deco_elements_(cu::DecorationElement::NONE)
14 , last_mwm_decor_(win_->mwmDecor())
15 , last_actions_(win_->actions())
16- , panel_id_(MENUS_PANEL_NAME + std::to_string(win_->id()))
17 , cv_(Settings::Instance().em())
18 {
19 active.changed.connect([this] (bool active) {
20@@ -932,18 +930,13 @@
21 sliding_layout->mouse_owner = grab_edge_->mouse_owner();
22 }
23
24-inline std::string const& Window::Impl::GetMenusPanelID() const
25-{
26- return panel_id_;
27-}
28-
29 void Window::Impl::UnsetAppMenu()
30 {
31 if (!menus_)
32 return;
33
34 auto const& indicators = manager_->impl_->menu_manager_->Indicators();
35- indicators->SyncGeometries(GetMenusPanelID(), indicator::EntryLocationMap());
36+ indicators->SyncGeometries(menus_->MenubarId(), indicator::EntryLocationMap());
37 sliding_layout_->SetInputItem(nullptr);
38 grab_mouse_changed_->disconnect();
39 }
40@@ -956,7 +949,7 @@
41 auto const& indicators = manager_->impl_->menu_manager_->Indicators();
42 indicator::EntryLocationMap map;
43 menus_->ChildrenGeometries(map);
44- indicators->SyncGeometries(GetMenusPanelID(), map);
45+ indicators->SyncGeometries(menus_->MenubarId(), map);
46 }
47
48 bool Window::Impl::ActivateMenu(std::string const& entry_id)
49
50=== modified file 'decorations/DecorationsMenuLayout.cpp'
51--- decorations/DecorationsMenuLayout.cpp 2016-09-01 22:11:44 +0000
52+++ decorations/DecorationsMenuLayout.cpp 2016-09-01 22:11:45 +0000
53@@ -20,12 +20,15 @@
54 #include "DecorationsMenuLayout.h"
55 #include "DecorationsMenuEntry.h"
56 #include "DecorationsMenuDropdown.h"
57-#include "InputMonitor.h"
58
59 namespace unity
60 {
61 namespace decoration
62 {
63+namespace
64+{
65+const std::string MENUS_PANEL_NAME = "WindowLIM";
66+}
67
68 using namespace indicator;
69
70@@ -35,6 +38,7 @@
71 , menu_manager_(menu)
72 , win_(win)
73 , dropdown_(std::make_shared<MenuDropdown>(menu_manager_->Indicators(), win))
74+ , menubar_id_(MENUS_PANEL_NAME + std::to_string(win_->id()))
75 {
76 visible = false;
77 }
78@@ -91,6 +95,11 @@
79 Relayout();
80 }
81
82+std::string const& MenuLayout::MenubarId() const
83+{
84+ return menubar_id_;
85+}
86+
87 bool MenuLayout::ActivateMenu(std::string const& entry_id)
88 {
89 MenuEntry::Ptr target;
90@@ -169,21 +178,16 @@
91
92 if (active && items_.size() > 1)
93 {
94- auto const& event_cb = sigc::mem_fun(this, &MenuLayout::OnEntryInputEvent);
95- input::Monitor::Get().RegisterClient(input::Events::POINTER, event_cb);
96+ menu_manager_->RegisterTracker(menubar_id_, (sigc::track_obj([this] (int x, int y, double speed) {
97+ ActivateMenu(CompPoint(x, y));
98+ }, *this)));
99 }
100 else if (!active)
101 {
102- input::Monitor::Get().UnregisterClient(sigc::mem_fun(this, &MenuLayout::OnEntryInputEvent));
103+ menu_manager_->UnregisterTracker(menubar_id_);
104 }
105 }
106
107-void MenuLayout::OnEntryInputEvent(XEvent const& e)
108-{
109- if (e.type == MotionNotify)
110- ActivateMenu(CompPoint(e.xmotion.x_root, e.xmotion.y_root));
111-}
112-
113 void MenuLayout::ChildrenGeometries(EntryLocationMap& map) const
114 {
115 for (auto const& item : items_)
116
117=== modified file 'decorations/DecorationsMenuLayout.h'
118--- decorations/DecorationsMenuLayout.h 2016-09-01 22:11:44 +0000
119+++ decorations/DecorationsMenuLayout.h 2016-09-01 22:11:45 +0000
120@@ -44,6 +44,7 @@
121 bool ActivateMenu(std::string const& entry_id);
122 bool ActivateMenu(CompPoint const&);
123 void ChildrenGeometries(indicator::EntryLocationMap&) const;
124+ std::string const& MenubarId() const;
125
126 protected:
127 void DoRelayout() override;
128@@ -53,12 +54,12 @@
129 void OnEntryMouseOwnershipChanged(bool);
130 void OnEntryActiveChanged(bool);
131 void OnEntryShowNowChanged(bool);
132- void OnEntryInputEvent(XEvent const&);
133
134 menu::Manager::Ptr menu_manager_;
135 CompWindow* win_;
136 glib::Source::UniquePtr show_now_timeout_;
137 std::shared_ptr<MenuDropdown> dropdown_;
138+ std::string menubar_id_;
139 };
140
141 } // decoration namespace
142
143=== modified file 'decorations/DecorationsPriv.h'
144--- decorations/DecorationsPriv.h 2016-08-06 16:24:45 +0000
145+++ decorations/DecorationsPriv.h 2016-09-01 22:11:45 +0000
146@@ -162,7 +162,6 @@
147 connection::Wrapper dpi_changed_;
148 connection::Wrapper grab_mouse_changed_;
149 std::string last_title_;
150- std::string panel_id_;
151 std::vector<cu::SimpleTextureQuad> bg_textures_;
152 cu::PixmapTexture::Ptr shaped_shadow_pixmap_;
153 std::shared_ptr<ForceQuitDialog> force_quit_;
154
155=== modified file 'lockscreen/KylinLockScreenShield.cpp'
156--- lockscreen/KylinLockScreenShield.cpp 2015-12-07 03:09:28 +0000
157+++ lockscreen/KylinLockScreenShield.cpp 2016-09-01 22:11:45 +0000
158@@ -37,7 +37,7 @@
159 Accelerators::Ptr const& accelerators,
160 nux::ObjectPtr<AbstractUserPromptView> const& prompt_view,
161 int monitor_num, bool is_primary)
162- : BaseShield(session_manager, nullptr, accelerators, prompt_view, monitor_num, is_primary)
163+ : BaseShield(session_manager, accelerators, prompt_view, monitor_num, is_primary)
164 {
165 is_primary ? ShowPrimaryView() : ShowSecondaryView();
166 EnableInputWindow(true);
167
168=== modified file 'lockscreen/LockScreenBaseShield.cpp'
169--- lockscreen/LockScreenBaseShield.cpp 2015-12-03 14:13:10 +0000
170+++ lockscreen/LockScreenBaseShield.cpp 2016-09-01 22:11:45 +0000
171@@ -38,7 +38,6 @@
172 }
173
174 BaseShield::BaseShield(session::Manager::Ptr const& session,
175- indicator::Indicators::Ptr const& indicators,
176 Accelerators::Ptr const& accelerators,
177 nux::ObjectPtr<AbstractUserPromptView> const& prompt_view,
178 int monitor_num, bool is_primary)
179@@ -47,7 +46,6 @@
180 , monitor(monitor_num)
181 , scale(1.0)
182 , session_manager_(session)
183- , indicators_(indicators)
184 , accelerators_(accelerators)
185 , prompt_view_(prompt_view)
186 , bg_settings_(std::make_shared<BackgroundSettings>())
187
188=== modified file 'lockscreen/LockScreenBaseShield.h'
189--- lockscreen/LockScreenBaseShield.h 2016-03-31 09:51:33 +0000
190+++ lockscreen/LockScreenBaseShield.h 2016-09-01 22:11:45 +0000
191@@ -21,8 +21,8 @@
192 #define UNITY_LOCKSCREEN_BASE_SHIELD_H
193
194 #include <NuxCore/Property.h>
195+#include "UnityCore/ConnectionManager.h"
196 #include "UnityCore/SessionManager.h"
197-#include "UnityCore/Indicators.h"
198 #include "UnityCore/GLibSource.h"
199 #include "unity-shared/MockableBaseWindow.h"
200
201@@ -39,8 +39,8 @@
202 class BaseShield : public MockableBaseWindow
203 {
204 public:
205- BaseShield(session::Manager::Ptr const&, indicator::Indicators::Ptr const&,
206- Accelerators::Ptr const&, nux::ObjectPtr<AbstractUserPromptView> const&,
207+ BaseShield(session::Manager::Ptr const&, Accelerators::Ptr const&,
208+ nux::ObjectPtr<AbstractUserPromptView> const&,
209 int monitor_num, bool is_primary);
210
211 nux::Property<bool> primary;
212@@ -69,7 +69,6 @@
213 void UpdateScale();
214
215 session::Manager::Ptr session_manager_;
216- indicator::Indicators::Ptr indicators_;
217 Accelerators::Ptr accelerators_;
218 nux::ObjectPtr<AbstractUserPromptView> prompt_view_;
219 std::shared_ptr<BackgroundSettings> bg_settings_;
220
221=== modified file 'lockscreen/LockScreenController.cpp'
222--- lockscreen/LockScreenController.cpp 2016-07-04 12:45:06 +0000
223+++ lockscreen/LockScreenController.cpp 2016-09-01 22:11:45 +0000
224@@ -130,7 +130,7 @@
225
226 upstart_wrapper_->Emit("desktop-unlock");
227 accelerator_controller_.reset();
228- indicators_.reset();
229+ menu_manager_.reset();
230 }
231 else if (!prompt_activation_)
232 {
233@@ -252,7 +252,7 @@
234
235 if (i >= shields_size)
236 {
237- shield = shield_factory_->CreateShield(session_manager_, indicators_, accelerator_controller_->GetAccelerators(), prompt_view, i, i == primary);
238+ shield = shield_factory_->CreateShield(session_manager_, menu_manager_, accelerator_controller_->GetAccelerators(), prompt_view, i, i == primary);
239 is_new = true;
240 }
241
242@@ -462,7 +462,7 @@
243
244 void Controller::LockScreen()
245 {
246- indicators_ = std::make_shared<indicator::LockScreenDBusIndicators>();
247+ menu_manager_ = std::make_shared<menu::Manager>(std::make_shared<indicator::LockScreenDBusIndicators>(), key_grabber_);
248 upstart_wrapper_->Emit("desktop-lock");
249
250 accelerator_controller_ = std::make_shared<AcceleratorController>(key_grabber_);
251
252=== modified file 'lockscreen/LockScreenController.h'
253--- lockscreen/LockScreenController.h 2016-06-21 01:28:26 +0000
254+++ lockscreen/LockScreenController.h 2016-09-01 22:11:45 +0000
255@@ -30,7 +30,6 @@
256 #include "SuspendInhibitorManager.h"
257 #include "ScreenSaverDBusManager.h"
258 #include "unity-shared/BackgroundEffectHelper.h"
259-#include "unity-shared/KeyGrabber.h"
260 #include "unity-shared/UpstartWrapper.h"
261
262 namespace unity
263@@ -85,8 +84,8 @@
264
265 DBusManager::Ptr dbus_manager_;
266 session::Manager::Ptr session_manager_;
267+ menu::Manager::Ptr menu_manager_;
268 key::Grabber::Ptr key_grabber_;
269- indicator::Indicators::Ptr indicators_;
270 AcceleratorController::Ptr accelerator_controller_;
271 UpstartWrapper::Ptr upstart_wrapper_;
272 ShieldFactoryInterface::Ptr shield_factory_;
273
274=== modified file 'lockscreen/LockScreenPanel.cpp'
275--- lockscreen/LockScreenPanel.cpp 2016-09-01 22:11:44 +0000
276+++ lockscreen/LockScreenPanel.cpp 2016-09-01 22:11:45 +0000
277@@ -44,11 +44,11 @@
278 using namespace indicator;
279 using namespace panel;
280
281-Panel::Panel(int monitor_, Indicators::Ptr const& indicators, session::Manager::Ptr const& session_manager)
282+Panel::Panel(int monitor_, menu::Manager::Ptr const& menu_manager, session::Manager::Ptr const& session_manager)
283 : nux::View(NUX_TRACKER_LOCATION)
284 , active(false)
285 , monitor(monitor_)
286- , indicators_(indicators)
287+ , menu_manager_(menu_manager)
288 , needs_geo_sync_(true)
289 {
290 double scale = unity::Settings::Instance().em(monitor)->DPIScale();
291@@ -72,14 +72,19 @@
292 indicators_view_->on_indicator_updated.connect(sigc::mem_fun(this, &Panel::OnIndicatorViewUpdated));
293 layout->AddView(indicators_view_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL);
294
295- for (auto const& indicator : indicators_->GetIndicators())
296+ auto indicators = menu_manager_->Indicators();
297+ menu_manager_->RegisterTracker(GetPanelName(), (sigc::track_obj([this] (int x, int y, double speed) {
298+ indicators_view_->ActivateEntryAt(x, y);
299+ }, *this)));
300+
301+ for (auto const& indicator : indicators->GetIndicators())
302 AddIndicator(indicator);
303
304- indicators_->on_object_added.connect(sigc::mem_fun(this, &Panel::AddIndicator));
305- indicators_->on_object_removed.connect(sigc::mem_fun(this, &Panel::RemoveIndicator));
306- indicators_->on_entry_show_menu.connect(sigc::mem_fun(this, &Panel::OnEntryShowMenu));
307- indicators_->on_entry_activated.connect(sigc::mem_fun(this, &Panel::OnEntryActivated));
308- indicators_->on_entry_activate_request.connect(sigc::mem_fun(this, &Panel::OnEntryActivateRequest));
309+ indicators->on_object_added.connect(sigc::mem_fun(this, &Panel::AddIndicator));
310+ indicators->on_object_removed.connect(sigc::mem_fun(this, &Panel::RemoveIndicator));
311+ indicators->on_entry_show_menu.connect(sigc::mem_fun(this, &Panel::OnEntryShowMenu));
312+ indicators->on_entry_activated.connect(sigc::mem_fun(this, &Panel::OnEntryActivated));
313+ indicators->on_entry_activate_request.connect(sigc::mem_fun(this, &Panel::OnEntryActivateRequest));
314
315 monitor.changed.connect([this, hostname] (int monitor) {
316 double scale = unity::Settings::Instance().em(monitor)->DPIScale();
317@@ -159,12 +164,7 @@
318 if (!GetInputEventSensitivity())
319 return;
320
321- if (!active)
322- {
323- // This is ugly... But Nux fault!
324- WindowManager::Default().UnGrabMousePointer(CurrentTime, button, x, y);
325- active = true;
326- }
327+ active = true;
328 }
329
330 void Panel::OnEntryActivateRequest(std::string const& entry_id)
331@@ -178,33 +178,16 @@
332 if (!GetInputEventSensitivity() || (!panel.empty() && panel != GetPanelName()))
333 return;
334
335- bool active = !entry_id.empty();
336+ bool valid_entry = !entry_id.empty();
337
338- if (active && !WindowManager::Default().IsScreenGrabbed())
339+ if (valid_entry && !WindowManager::Default().IsScreenGrabbed())
340 {
341 // The menu didn't grab the keyboard, let's take it back.
342 nux::GetWindowCompositor().GrabKeyboardAdd(static_cast<nux::BaseWindow*>(GetTopLevelViewWindow()));
343 }
344
345- auto& im = input::Monitor::Get();
346- auto const& event_cb = sigc::mem_fun(this, &Panel::OnEntryEvent);
347-
348- if (active)
349- {
350- if (im.RegisterClient(input::Events::POINTER, event_cb))
351- indicators_view_->ActivateEntry(entry_id);
352- }
353- else
354- {
355- im.UnregisterClient(event_cb);
356- this->active = active;
357- }
358-}
359-
360-void Panel::OnEntryEvent(XEvent const& e)
361-{
362- if (e.type == MotionNotify && GetAbsoluteGeometry().IsPointInside(e.xmotion.x, e.xmotion.y))
363- indicators_view_->ActivateEntryAt(e.xmotion.x, e.xmotion.y);
364+ if (!valid_entry)
365+ active = valid_entry;
366 }
367
368 void Panel::Draw(nux::GraphicsEngine& graphics_engine, bool force_draw)
369@@ -228,7 +211,7 @@
370 {
371 EntryLocationMap locations;
372 indicators_view_->GetGeometryForSync(locations);
373- indicators_->SyncGeometries(GetPanelName(), locations);
374+ menu_manager_->Indicators()->SyncGeometries(GetPanelName(), locations);
375 needs_geo_sync_ = false;
376 }
377 }
378
379=== modified file 'lockscreen/LockScreenPanel.h'
380--- lockscreen/LockScreenPanel.h 2016-09-01 22:11:44 +0000
381+++ lockscreen/LockScreenPanel.h 2016-09-01 22:11:45 +0000
382@@ -22,9 +22,9 @@
383
384 #include <Nux/Nux.h>
385 #include <Nux/View.h>
386-#include "UnityCore/Indicators.h"
387 #include "UnityCore/GLibSource.h"
388 #include "UnityCore/SessionManager.h"
389+#include "unity-shared/MenuManager.h"
390
391 namespace unity
392 {
393@@ -39,7 +39,7 @@
394 class Panel : public nux::View
395 {
396 public:
397- Panel(int monitor, indicator::Indicators::Ptr const&, session::Manager::Ptr const&);
398+ Panel(int monitor, menu::Manager::Ptr const&, session::Manager::Ptr const&);
399
400 nux::Property<bool> active;
401 nux::Property<int> monitor;
402@@ -55,15 +55,14 @@
403 void AddIndicator(indicator::Indicator::Ptr const&);
404 void RemoveIndicator(indicator::Indicator::Ptr const&);
405 void OnIndicatorViewUpdated();
406- void OnEntryActivated(std::string const& panel, std::string const& entry_id, nux::Rect const& geo);
407+ void OnEntryActivated(std::string const& panel, std::string const& entry_id, nux::Rect const&);
408 void OnEntryShowMenu(std::string const& entry_id, unsigned xid, int x, int y, unsigned button);
409 void OnEntryActivateRequest(std::string const& entry_id);
410- void OnEntryEvent(XEvent const&);
411
412 void UpdateSize();
413 std::string GetPanelName() const;
414
415- indicator::Indicators::Ptr indicators_;
416+ menu::Manager::Ptr menu_manager_;
417 panel::PanelIndicatorsView* indicators_view_;
418 bool needs_geo_sync_;
419 };
420
421=== modified file 'lockscreen/LockScreenShield.cpp'
422--- lockscreen/LockScreenShield.cpp 2015-12-03 14:13:10 +0000
423+++ lockscreen/LockScreenShield.cpp 2016-09-01 22:11:45 +0000
424@@ -32,11 +32,12 @@
425 {
426
427 Shield::Shield(session::Manager::Ptr const& session_manager,
428- indicator::Indicators::Ptr const& indicators,
429+ menu::Manager::Ptr const& menu_manager,
430 Accelerators::Ptr const& accelerators,
431 nux::ObjectPtr<AbstractUserPromptView> const& prompt_view,
432 int monitor_num, bool is_primary)
433- : BaseShield(session_manager, indicators, accelerators, prompt_view, monitor_num, is_primary)
434+ : BaseShield(session_manager, accelerators, prompt_view, monitor_num, is_primary)
435+ , menu_manager_(menu_manager)
436 , panel_view_(nullptr)
437 {
438 is_primary ? ShowPrimaryView() : ShowSecondaryView();
439@@ -91,11 +92,11 @@
440
441 Panel* Shield::CreatePanel()
442 {
443- if (!indicators_ || !session_manager_)
444+ if (!menu_manager_ || !session_manager_)
445 return nullptr;
446
447- panel_view_ = new Panel(monitor, indicators_, session_manager_);
448- panel_active_conn_ = panel_view_->active.changed.connect([this] (bool active) {
449+ panel_view_ = new Panel(monitor, menu_manager_, session_manager_);
450+ panel_view_->active.changed.connect(sigc::track_obj([this] (bool active) {
451 if (primary())
452 {
453 if (active)
454@@ -109,7 +110,7 @@
455 GrabScreen(false);
456 }
457 }
458- });
459+ }, *this));
460
461 return panel_view_;
462 }
463
464=== modified file 'lockscreen/LockScreenShield.h'
465--- lockscreen/LockScreenShield.h 2015-12-03 14:13:10 +0000
466+++ lockscreen/LockScreenShield.h 2016-09-01 22:11:45 +0000
467@@ -20,8 +20,9 @@
468 #ifndef UNITY_LOCKSCREEN_SHIELD_H
469 #define UNITY_LOCKSCREEN_SHIELD_H
470
471-#include <UnityCore/ConnectionManager.h>
472 #include "LockScreenBaseShield.h"
473+#include "unity-shared/MenuManager.h"
474+
475
476 namespace unity
477 {
478@@ -35,7 +36,7 @@
479 {
480 public:
481 Shield(session::Manager::Ptr const&,
482- indicator::Indicators::Ptr const&,
483+ menu::Manager::Ptr const&,
484 Accelerators::Ptr const&,
485 nux::ObjectPtr<AbstractUserPromptView> const&,
486 int monitor, bool is_primary);
487@@ -50,7 +51,7 @@
488 void ShowPrimaryView() override;
489 Panel* CreatePanel();
490
491- connection::Wrapper panel_active_conn_;
492+ menu::Manager::Ptr menu_manager_;
493 Panel* panel_view_;
494 };
495
496
497=== modified file 'lockscreen/LockScreenShieldFactory.cpp'
498--- lockscreen/LockScreenShieldFactory.cpp 2015-12-04 08:17:46 +0000
499+++ lockscreen/LockScreenShieldFactory.cpp 2016-09-01 22:11:45 +0000
500@@ -28,7 +28,7 @@
501 {
502
503 nux::ObjectPtr<BaseShield> ShieldFactory::CreateShield(session::Manager::Ptr const& session_manager,
504- indicator::Indicators::Ptr const& indicators,
505+ menu::Manager::Ptr const& menu_manager,
506 Accelerators::Ptr const& accelerators,
507 nux::ObjectPtr<AbstractUserPromptView> const& prompt_view,
508 int monitor, bool is_primary)
509@@ -38,7 +38,7 @@
510 if (Settings::Instance().desktop_type() == DesktopType::UBUNTUKYLIN)
511 shield = new KylinShield(session_manager, accelerators, prompt_view, monitor, is_primary);
512 else
513- shield = new Shield(session_manager, indicators, accelerators, prompt_view, monitor, is_primary);
514+ shield = new Shield(session_manager, menu_manager, accelerators, prompt_view, monitor, is_primary);
515
516 return shield;
517 }
518
519=== modified file 'lockscreen/LockScreenShieldFactory.h'
520--- lockscreen/LockScreenShieldFactory.h 2016-03-31 09:51:33 +0000
521+++ lockscreen/LockScreenShieldFactory.h 2016-09-01 22:11:45 +0000
522@@ -22,7 +22,7 @@
523
524 #include <NuxCore/NuxCore.h>
525 #include "UnityCore/SessionManager.h"
526-#include "UnityCore/Indicators.h"
527+#include "unity-shared/MenuManager.h"
528 #include "LockScreenAccelerators.h"
529
530 namespace unity
531@@ -41,7 +41,7 @@
532 virtual ~ShieldFactoryInterface() = default;
533
534 virtual nux::ObjectPtr<BaseShield> CreateShield(session::Manager::Ptr const&,
535- indicator::Indicators::Ptr const&,
536+ menu::Manager::Ptr const&,
537 Accelerators::Ptr const&,
538 nux::ObjectPtr<AbstractUserPromptView> const&,
539 int monitor, bool is_primary) = 0;
540@@ -50,7 +50,7 @@
541 struct ShieldFactory : ShieldFactoryInterface
542 {
543 nux::ObjectPtr<BaseShield> CreateShield(session::Manager::Ptr const&,
544- indicator::Indicators::Ptr const&,
545+ menu::Manager::Ptr const&,
546 Accelerators::Ptr const&,
547 nux::ObjectPtr<AbstractUserPromptView> const&,
548 int monitor, bool is_primary) override;
549
550=== modified file 'panel/PanelIndicatorEntryView.cpp'
551--- panel/PanelIndicatorEntryView.cpp 2016-02-17 13:14:37 +0000
552+++ panel/PanelIndicatorEntryView.cpp 2016-09-01 22:11:45 +0000
553@@ -33,6 +33,8 @@
554 #include "unity-shared/RawPixel.h"
555 #include "unity-shared/WindowManager.h"
556 #include "unity-shared/ThemeSettings.h"
557+#include "unity-shared/UBusWrapper.h"
558+#include "unity-shared/UBusMessages.h"
559 #include "unity-shared/UnitySettings.h"
560
561 namespace unity
562@@ -117,6 +119,9 @@
563 }
564 else
565 {
566+ if (overlay_showing_)
567+ UBusManager::SendMessage(UBUS_OVERLAY_CLOSE_REQUEST);
568+
569 WindowManager& wm = WindowManager::Default();
570
571 if (wm.IsExpoActive())
572@@ -140,6 +145,11 @@
573 wm.TerminateScale();
574 }
575
576+ // This is ugly... But Nux fault!
577+ auto const& abs_geo = GetAbsoluteGeometry();
578+ guint64 timestamp = nux::GetGraphicsDisplay()->GetCurrentEvent().x11_timestamp;
579+ WindowManager::Default().UnGrabMousePointer(timestamp, button, abs_geo.x, abs_geo.y);
580+
581 Activate(button);
582 }
583 }
584
585=== modified file 'panel/PanelMenuView.cpp'
586--- panel/PanelMenuView.cpp 2015-12-16 15:12:05 +0000
587+++ panel/PanelMenuView.cpp 2016-09-01 22:11:45 +0000
588@@ -102,7 +102,6 @@
589 , ignore_menu_visibility_(false)
590 , integrated_menus_(menu_manager_->integrated_menus())
591 , always_show_menus_(menu_manager_->always_show_menus())
592- , ignore_leave_events_(false)
593 , desktop_name_(get_current_desktop())
594 {
595 if (ApplicationWindowPtr const& win = ApplicationManager::Default().GetActiveWindow())
596@@ -1814,14 +1813,9 @@
597 }
598 }
599
600-void PanelMenuView::IgnoreLeaveEvents(bool ignore)
601-{
602- ignore_leave_events_ = ignore;
603-}
604-
605 void PanelMenuView::OnPanelViewMouseLeave(int x, int y, unsigned long mouse_button_state, unsigned long special_keys_state)
606 {
607- if (always_show_menus_ || ignore_leave_events_)
608+ if (always_show_menus_)
609 return;
610
611 if (is_inside_)
612
613=== modified file 'panel/PanelMenuView.h'
614--- panel/PanelMenuView.h 2015-11-05 14:54:13 +0000
615+++ panel/PanelMenuView.h 2016-09-01 22:11:45 +0000
616@@ -56,7 +56,6 @@
617 bool HasKeyActivableMenus() const;
618
619 void NotifyAllMenusClosed();
620- void IgnoreLeaveEvents(bool);
621
622 virtual void AddIndicator(indicator::Indicator::Ptr const& indicator);
623
624@@ -192,7 +191,6 @@
625 bool ignore_menu_visibility_;
626 bool integrated_menus_;
627 bool always_show_menus_;
628- bool ignore_leave_events_;
629
630 nux::Geometry monitor_geo_;
631 const std::string desktop_name_;
632
633=== modified file 'panel/PanelView.cpp'
634--- panel/PanelView.cpp 2016-09-01 22:11:44 +0000
635+++ panel/PanelView.cpp 2016-09-01 22:11:45 +0000
636@@ -23,7 +23,6 @@
637
638 #include <UnityCore/GLibWrapper.h>
639
640-#include "unity-shared/InputMonitor.h"
641 #include "unity-shared/PanelStyle.h"
642 #include "unity-shared/RawPixel.h"
643 #include "unity-shared/TextureCache.h"
644@@ -54,7 +53,6 @@
645 : View(NUX_FILE_LINE_PARAM)
646 , parent_(parent)
647 , remote_(menus->Indicators())
648- , last_pointer_time_(0)
649 , is_dirty_(true)
650 , opacity_maximized_toggle_(false)
651 , needs_geo_sync_(false)
652@@ -116,10 +114,9 @@
653
654 remote_->on_object_added.connect(sigc::mem_fun(this, &PanelView::OnObjectAdded));
655 remote_->on_object_removed.connect(sigc::mem_fun(this, &PanelView::OnObjectRemoved));
656- remote_->on_entry_activated.connect(sigc::mem_fun(this, &PanelView::OnEntryActivated));
657- remote_->on_entry_show_menu.connect(sigc::mem_fun(this, &PanelView::OnEntryShowMenu));
658 menus->key_activate_entry.connect(sigc::mem_fun(this, &PanelView::ActivateEntry));
659 menus->open_first.connect(sigc::mem_fun(this, &PanelView::ActivateFirstSensitive));
660+ menus->RegisterTracker(GetPanelName(), sigc::mem_fun(this, &PanelView::OnMenuPointerMoved));
661
662 ubus_manager_.RegisterInterest(UBUS_OVERLAY_HIDDEN, sigc::mem_fun(this, &PanelView::OnOverlayHidden));
663 ubus_manager_.RegisterInterest(UBUS_OVERLAY_SHOWN, sigc::mem_fun(this, &PanelView::OnOverlayShown));
664@@ -630,7 +627,7 @@
665 QueueDraw();
666 }
667
668-void PanelView::OnMenuPointerMoved(int x, int y)
669+void PanelView::OnMenuPointerMoved(int x, int y, double speed)
670 {
671 nux::Geometry const& geo = GetAbsoluteGeometry();
672
673@@ -651,106 +648,6 @@
674 }
675 }
676
677-namespace
678-{
679-bool PointInTriangle(nux::Point const& p, nux::Point const& t0, nux::Point const& t1, nux::Point const& t2)
680-{
681- int s = t0.y * t2.x - t0.x * t2.y + (t2.y - t0.y) * p.x + (t0.x - t2.x) * p.y;
682- int t = t0.x * t1.y - t0.y * t1.x + (t0.y - t1.y) * p.x + (t1.x - t0.x) * p.y;
683-
684- if ((s < 0) != (t < 0))
685- return false;
686-
687- int A = -t1.y * t2.x + t0.y * (t2.x - t1.x) + t0.x * (t1.y - t2.y) + t1.x * t2.y;
688- if (A < 0)
689- {
690- s = -s;
691- t = -t;
692- A = -A;
693- }
694-
695- return s > 0 && t > 0 && (s + t) < A;
696-}
697-
698-double GetMouseVelocity(nux::Point const& p0, nux::Point const& p1, Time time_delta)
699-{
700- int dx, dy;
701- double speed;
702-
703- if (time_delta == 0)
704- return 1;
705-
706- dx = p0.x - p1.x;
707- dy = p0.y - p1.y;
708-
709- speed = sqrt(dx * dx + dy * dy) / time_delta;
710-
711- return speed;
712-}
713-} // anonymous namespace
714-
715-void PanelView::OnActiveEntryEvent(XEvent const& e)
716-{
717- if (e.type != MotionNotify)
718- return;
719-
720- double scale = Settings::Instance().em(monitor_)->DPIScale();
721- nux::Point mouse(e.xmotion.x_root, e.xmotion.y_root);
722- double speed = GetMouseVelocity(mouse, tracked_pointer_pos_, e.xmotion.time - last_pointer_time_);
723-
724- tracked_pointer_pos_ = mouse;
725- last_pointer_time_ = e.xmotion.time;
726-
727- if (speed > SCRUB_VELOCITY_THRESHOLD &&
728- PointInTriangle(mouse, {mouse.x, std::max(mouse.y - TRIANGLE_THRESHOLD.CP(scale), 0)},
729- menu_geo_.GetPosition(), {menu_geo_.x + menu_geo_.width, menu_geo_.y}))
730- {
731- return;
732- }
733-
734- OnMenuPointerMoved(mouse.x, mouse.y);
735-}
736-
737-void PanelView::OnEntryActivated(std::string const& panel, std::string const& entry_id, nux::Rect const& menu_geo)
738-{
739- if (!panel.empty() && panel != GetPanelName())
740- return;
741-
742- bool active = !entry_id.empty();
743- auto const& activation_cb = sigc::mem_fun(this, &PanelView::OnActiveEntryEvent);
744- menu_geo_ = menu_geo;
745-
746- if (active)
747- {
748- auto& im = input::Monitor::Get();
749- if (im.RegisterClient(input::Events::POINTER, activation_cb))
750- {
751- last_pointer_time_ = 0;
752- ActivateEntry(entry_id);
753- }
754-
755- if (overlay_is_open_)
756- ubus_manager_.SendMessage(UBUS_OVERLAY_CLOSE_REQUEST);
757- }
758- else
759- {
760- input::Monitor::Get().UnregisterClient(activation_cb);
761- menu_view_->NotifyAllMenusClosed();
762- }
763-}
764-
765-void PanelView::OnEntryShowMenu(std::string const& entry_id, unsigned xid,
766- int x, int y, unsigned button)
767-{
768- if (menu_geo_.IsNull())
769- {
770- // This is ugly... But Nux fault!
771- menu_view_->IgnoreLeaveEvents(true);
772- WindowManager::Default().UnGrabMousePointer(CurrentTime, button, x, y);
773- menu_view_->IgnoreLeaveEvents(false);
774- }
775-}
776-
777 bool PanelView::ActivateFirstSensitive()
778 {
779 if (!IsActive())
780
781=== modified file 'panel/PanelView.h'
782--- panel/PanelView.h 2016-09-01 22:11:44 +0000
783+++ panel/PanelView.h 2016-09-01 22:11:45 +0000
784@@ -87,8 +87,6 @@
785 void OnObjectAdded(indicator::Indicator::Ptr const& proxy);
786 void OnObjectRemoved(indicator::Indicator::Ptr const& proxy);
787 void OnIndicatorViewUpdated();
788- void OnEntryActivated(std::string const& panel, std::string const& entry_id, nux::Rect const& geo);
789- void OnEntryShowMenu(std::string const& entry_id, unsigned xid, int x, int y, unsigned button);
790
791 private:
792 std::string GetPanelName() const;
793@@ -98,7 +96,7 @@
794 void OnSpreadInitiate();
795 void OnSpreadTerminate();
796 void OnLowGfxChanged();
797- void OnMenuPointerMoved(int x, int y);
798+ void OnMenuPointerMoved(int x, int y, double speed);
799 void OnActiveEntryEvent(XEvent const&);
800 void EnableOverlayMode(bool);
801 void LoadTextures();
802@@ -132,10 +130,6 @@
803 BaseTexturePtr bg_refine_single_column_tex_;
804 std::unique_ptr<nux::AbstractPaintLayer> bg_refine_single_column_layer_;
805
806- std::string active_overlay_;
807- nux::Point tracked_pointer_pos_;
808- Time last_pointer_time_;
809-
810 bool is_dirty_;
811 bool opacity_maximized_toggle_;
812 bool needs_geo_sync_;
813@@ -143,8 +137,7 @@
814 float opacity_;
815 int monitor_;
816 int stored_dash_width_;
817-
818- nux::Geometry menu_geo_;
819+ std::string active_overlay_;
820
821 connection::Manager on_indicator_updated_connections_;
822 connection::Manager maximized_opacity_toggle_connections_;
823
824=== modified file 'tests/test_lockscreen_controller.cpp'
825--- tests/test_lockscreen_controller.cpp 2016-06-21 14:40:26 +0000
826+++ tests/test_lockscreen_controller.cpp 2016-09-01 22:11:45 +0000
827@@ -55,7 +55,7 @@
828 struct MockShield : BaseShield
829 {
830 MockShield()
831- : BaseShield(nullptr, nullptr, nullptr, nux::ObjectPtr<AbstractUserPromptView>(), 0, false)
832+ : BaseShield(nullptr, nullptr, nux::ObjectPtr<AbstractUserPromptView>(), 0, false)
833 {}
834
835 MOCK_CONST_METHOD0(IsIndicatorOpen, bool());
836@@ -67,7 +67,7 @@
837 struct ShieldFactoryMock : ShieldFactoryInterface
838 {
839 nux::ObjectPtr<BaseShield> CreateShield(session::Manager::Ptr const&,
840- indicator::Indicators::Ptr const&,
841+ menu::Manager::Ptr const&,
842 Accelerators::Ptr const&,
843 nux::ObjectPtr<AbstractUserPromptView> const&,
844 int, bool) override
845
846=== modified file 'unity-shared/InputMonitor.cpp'
847--- unity-shared/InputMonitor.cpp 2016-09-01 22:11:44 +0000
848+++ unity-shared/InputMonitor.cpp 2016-09-01 22:11:45 +0000
849@@ -18,6 +18,7 @@
850 */
851
852 #include "InputMonitor.h"
853+#include "SigcSlotHash.h"
854
855 #include <Nux/Nux.h>
856 #include <NuxCore/Logger.h>
857@@ -46,6 +47,12 @@
858 return static_cast<ut>(static_cast<ut>(l) & static_cast<ut>(r));
859 }
860
861+Events& operator|=(Events& l, Events r)
862+{
863+ typedef std::underlying_type<Events>::type ut;
864+ return l = static_cast<Events>(static_cast<ut>(l) | static_cast<ut>(r));
865+}
866+
867 template <typename EVENT>
868 void initialize_event_common(EVENT* ev, XIDeviceEvent* xiev)
869 {
870@@ -118,6 +125,12 @@
871
872 struct Monitor::Impl
873 {
874+#if __GNUC__ < 6
875+ using EventCallbackSet = std::unordered_set<EventCallback>;
876+#else
877+ using EventCallbackSet = std::unordered_set<EventCallback, std::hash<sigc::slot_base>>;
878+#endif
879+
880 Impl()
881 : xi_opcode_(0)
882 , event_filter_set_(false)
883@@ -194,6 +207,22 @@
884 return removed;
885 }
886
887+ Events RegisteredEvents(EventCallback const& cb) const
888+ {
889+ Events events = Events::NONE;
890+
891+ if (pointer_callbacks_.find(cb) != end(pointer_callbacks_))
892+ events |= Events::POINTER;
893+
894+ if (key_callbacks_.find(cb) != end(key_callbacks_))
895+ events |= Events::KEYS;
896+
897+ if (barrier_callbacks_.find(cb) != end(barrier_callbacks_))
898+ events |= Events::BARRIER;
899+
900+ return events;
901+ }
902+
903 void UpdateEventMonitor()
904 {
905 auto* dpy = nux::GetGraphicsDisplay()->GetX11Display();
906@@ -276,7 +305,7 @@
907 }
908
909 template <typename EVENT_TYPE, typename NATIVE_TYPE = XIDeviceEvent>
910- bool InvokeCallbacks(std::unordered_set<EventCallback>& callbacks, XEvent& xiev)
911+ bool InvokeCallbacks(EventCallbackSet& callbacks, XEvent& xiev)
912 {
913 XGenericEventCookie *cookie = &xiev.xcookie;
914
915@@ -332,10 +361,10 @@
916 bool event_filter_set_;
917 bool invoking_callbacks_;
918 glib::Source::UniquePtr idle_removal_;
919- std::unordered_set<EventCallback> pointer_callbacks_;
920- std::unordered_set<EventCallback> key_callbacks_;
921- std::unordered_set<EventCallback> barrier_callbacks_;
922- std::unordered_set<EventCallback> removal_queue_;
923+ EventCallbackSet pointer_callbacks_;
924+ EventCallbackSet key_callbacks_;
925+ EventCallbackSet barrier_callbacks_;
926+ EventCallbackSet removal_queue_;
927 };
928
929 Monitor::Monitor()
930@@ -376,5 +405,10 @@
931 return impl_->UnregisterClient(cb);
932 }
933
934+Events Monitor::RegisteredEvents(EventCallback const& cb) const
935+{
936+ return impl_->RegisteredEvents(cb);
937+}
938+
939 } // input namespace
940 } // unity namespace
941
942=== modified file 'unity-shared/InputMonitor.h'
943--- unity-shared/InputMonitor.h 2016-09-01 22:11:44 +0000
944+++ unity-shared/InputMonitor.h 2016-09-01 22:11:45 +0000
945@@ -30,6 +30,7 @@
946 {
947 enum class Events : unsigned
948 {
949+ NONE = 0,
950 POINTER = (1 << 0),
951 KEYS = (1 << 1),
952 BARRIER = (1 << 2),
953@@ -50,6 +51,8 @@
954 bool RegisterClient(Events, EventCallback const&);
955 bool UnregisterClient(EventCallback const&);
956
957+ Events RegisteredEvents(EventCallback const&) const;
958+
959 private:
960 Monitor(Monitor const&) = delete;
961 Monitor& operator=(Monitor const&) = delete;
962@@ -61,31 +64,4 @@
963 } // input namespace
964 } // unity namespace
965
966-namespace std
967-{
968-template<>
969-struct hash<unity::input::Monitor::EventCallback>
970-{
971- size_t operator()(unity::input::Monitor::EventCallback const& cb) const
972- {
973- if (cb.rep_)
974- return std::hash<size_t>()(reinterpret_cast<size_t>(cb.rep_->call_));
975-
976- return std::hash<size_t>()(reinterpret_cast<size_t>(cb.rep_));
977- }
978-};
979-
980-template<>
981-struct equal_to<unity::input::Monitor::EventCallback>
982-{
983- bool operator()(unity::input::Monitor::EventCallback const& lhs, unity::input::Monitor::EventCallback const& rhs) const
984- {
985- if (!lhs.rep_ || !rhs.rep_)
986- return (lhs.rep_ == rhs.rep_);
987-
988- return (lhs.rep_->call_ == rhs.rep_->call_);
989- }
990-};
991-} // std namespace
992-
993 #endif // __UNITY_INPUT_MONITOR__
994
995=== modified file 'unity-shared/MenuManager.cpp'
996--- unity-shared/MenuManager.cpp 2015-10-02 14:02:05 +0000
997+++ unity-shared/MenuManager.cpp 2016-09-01 22:11:45 +0000
998@@ -21,11 +21,17 @@
999 #include <gtk/gtk.h>
1000 #include <NuxCore/Logger.h>
1001 #include <UnityCore/GLibSignal.h>
1002+#include <UnityCore/GLibSource.h>
1003 #include <UnityCore/GLibWrapper.h>
1004 #include <UnityCore/DBusIndicators.h>
1005 #include <unordered_map>
1006
1007 #include "MenuManager.h"
1008+#include "InputMonitor.h"
1009+#include "RawPixel.h"
1010+#include "SigcSlotHash.h"
1011+#include "UnitySettings.h"
1012+#include "UScreen.h"
1013 #include "WindowManager.h"
1014
1015 namespace unity
1016@@ -40,6 +46,10 @@
1017 const std::string LIM_KEY = "integrated-menus";
1018 const std::string SHOW_MENUS_NOW_DELAY = "show-menus-now-delay";
1019 const std::string ALWAYS_SHOW_MENUS_KEY = "always-show-menus";
1020+
1021+const RawPixel TRIANGLE_THRESHOLD = 5_em;
1022+const double SCRUB_VELOCITY_THRESHOLD = 0.05;
1023+const unsigned MENU_OPEN_MOUSE_WAIT = 150;
1024 }
1025
1026 using namespace indicator;
1027@@ -51,6 +61,7 @@
1028 , indicators_(indicators)
1029 , key_grabber_(grabber)
1030 , show_now_window_(0)
1031+ , last_pointer_time_(0)
1032 , settings_(g_settings_new(SETTINGS_NAME.c_str()))
1033 {
1034 for (auto const& indicator : indicators_->GetIndicators())
1035@@ -182,9 +193,15 @@
1036 parent_->key_activate_entry.emit(entry_id);
1037 }
1038
1039- void EntryActivated(std::string const&, std::string const&, nux::Rect const& geo)
1040+ void EntryActivated(std::string const& menubar, std::string const&, nux::Rect const& geo)
1041 {
1042 parent_->menu_open = !geo.IsNull();
1043+
1044+ if (active_menubar_ != menubar)
1045+ {
1046+ active_menubar_ = menubar;
1047+ UpdateActiveTracker();
1048+ }
1049 }
1050
1051 void SetShowNowForWindow(Window xid, bool show)
1052@@ -231,15 +248,148 @@
1053 gtk_icon_theme_set_search_path(gtk_icon_theme_get_default(), gicon_paths.data(), gicon_paths.size());
1054 }
1055
1056+ bool PointInTriangle(nux::Point const& p, nux::Point const& t0, nux::Point const& t1, nux::Point const& t2)
1057+ {
1058+ int s = t0.y * t2.x - t0.x * t2.y + (t2.y - t0.y) * p.x + (t0.x - t2.x) * p.y;
1059+ int t = t0.x * t1.y - t0.y * t1.x + (t0.y - t1.y) * p.x + (t1.x - t0.x) * p.y;
1060+
1061+ if ((s < 0) != (t < 0))
1062+ return false;
1063+
1064+ int A = -t1.y * t2.x + t0.y * (t2.x - t1.x) + t0.x * (t1.y - t2.y) + t1.x * t2.y;
1065+ if (A < 0)
1066+ {
1067+ s = -s;
1068+ t = -t;
1069+ A = -A;
1070+ }
1071+
1072+ return s > 0 && t > 0 && (s + t) < A;
1073+ }
1074+
1075+ double GetMouseVelocity(nux::Point const& p0, nux::Point const& p1, Time time_delta)
1076+ {
1077+ int dx, dy;
1078+ double speed;
1079+
1080+ if (time_delta == 0)
1081+ return 1;
1082+
1083+ dx = p0.x - p1.x;
1084+ dy = p0.y - p1.y;
1085+
1086+ speed = sqrt(dx * dx + dy * dy) / time_delta;
1087+
1088+ return speed;
1089+ }
1090+
1091+ void OnActiveEntryEvent(XEvent const& e)
1092+ {
1093+ if (e.type != MotionNotify)
1094+ return;
1095+
1096+ auto const& active_entry = indicators_->GetActiveEntry();
1097+
1098+ if (!active_entry)
1099+ return;
1100+
1101+ nux::Point mouse(e.xmotion.x_root, e.xmotion.y_root);
1102+ auto monitor = UScreen::GetDefault()->GetMonitorAtPosition(mouse.x, mouse.y);
1103+ double scale = Settings::Instance().em(monitor)->DPIScale();
1104+ double speed = GetMouseVelocity(mouse, tracked_pointer_pos_, e.xmotion.time - last_pointer_time_);
1105+ auto menu_geo = active_entry->geometry();
1106+
1107+ tracked_pointer_pos_ = mouse;
1108+ last_pointer_time_ = e.xmotion.time;
1109+
1110+ if (speed > SCRUB_VELOCITY_THRESHOLD &&
1111+ PointInTriangle(mouse, {mouse.x, std::max(mouse.y - TRIANGLE_THRESHOLD.CP(scale), 0)},
1112+ menu_geo.GetPosition(), {menu_geo.x + menu_geo.width, menu_geo.y}))
1113+ {
1114+ pointer_movement_timeout_ = std::make_shared<glib::Timeout>(MENU_OPEN_MOUSE_WAIT, [this, mouse, speed] {
1115+ if (active_tracker_)
1116+ active_tracker_(mouse.x, mouse.y, speed);
1117+
1118+ return false;
1119+ });
1120+
1121+ return;
1122+ }
1123+
1124+ if (active_tracker_)
1125+ {
1126+ pointer_movement_timeout_.reset();
1127+ active_tracker_(mouse.x, mouse.y, speed);
1128+ }
1129+ }
1130+
1131+ bool RegisterTracker(std::string const& menubar, PositionTracker const& cb)
1132+ {
1133+ auto it = position_trackers_.find(menubar);
1134+
1135+ if (it != end(position_trackers_))
1136+ return false;
1137+
1138+ position_trackers_.insert({menubar, cb});
1139+
1140+ if (active_menubar_ == menubar)
1141+ UpdateActiveTracker();
1142+
1143+ return true;
1144+ }
1145+
1146+ bool UnregisterTracker(std::string const& menubar, PositionTracker const& cb)
1147+ {
1148+ auto it = position_trackers_.find(menubar);
1149+
1150+ if (it == end(position_trackers_))
1151+ return false;
1152+
1153+ if (!cb || (cb && it->second == cb))
1154+ {
1155+ position_trackers_.erase(it);
1156+ UpdateActiveTracker();
1157+ return true;
1158+ }
1159+
1160+ return false;
1161+ }
1162+
1163+ void UpdateActiveTracker()
1164+ {
1165+ auto it = position_trackers_.find(active_menubar_);
1166+ active_tracker_ = (it != end(position_trackers_)) ? it->second : PositionTracker();
1167+ pointer_movement_timeout_.reset();
1168+
1169+ if (active_tracker_)
1170+ {
1171+ if (input::Monitor::Get().RegisterClient(input::Events::POINTER, sigc::mem_fun(this, &Impl::OnActiveEntryEvent)))
1172+ last_pointer_time_ = 0;
1173+ }
1174+ else
1175+ {
1176+ input::Monitor::Get().UnregisterClient(sigc::mem_fun(this, &Impl::OnActiveEntryEvent));
1177+
1178+ if (it != end(position_trackers_))
1179+ position_trackers_.erase(it);
1180+ }
1181+ }
1182+
1183 Manager* parent_;
1184 Indicators::Ptr indicators_;
1185 AppmenuIndicator::Ptr appmenu_;
1186 key::Grabber::Ptr key_grabber_;
1187 Window show_now_window_;
1188+ std::string active_menubar_;
1189+ PositionTracker active_tracker_;
1190+ nux::Point tracked_pointer_pos_;
1191+ Time last_pointer_time_;
1192+ glib::Source::Ptr pointer_movement_timeout_;
1193 connection::Manager appmenu_connections_;
1194 connection::Wrapper active_win_conn_;
1195 glib::Object<GSettings> settings_;
1196 glib::SignalManager signals_;
1197+ std::unordered_map<std::string, PositionTracker> position_trackers_;
1198 std::unordered_map<indicator::Entry::Ptr, uint32_t> entry_actions_;
1199 };
1200
1201@@ -278,5 +428,16 @@
1202 return impl_->key_grabber_;
1203 }
1204
1205+bool Manager::RegisterTracker(std::string const& menubar, PositionTracker const& cb)
1206+{
1207+ return impl_->RegisterTracker(menubar, cb);
1208+}
1209+
1210+bool Manager::UnregisterTracker(std::string const& menubar, PositionTracker const& cb)
1211+{
1212+ return impl_->UnregisterTracker(menubar, cb);
1213+}
1214+
1215+
1216 } // menu namespace
1217 } // unity namespace
1218
1219=== modified file 'unity-shared/MenuManager.h'
1220--- unity-shared/MenuManager.h 2015-06-05 14:28:27 +0000
1221+++ unity-shared/MenuManager.h 2016-09-01 22:11:45 +0000
1222@@ -67,6 +67,10 @@
1223
1224 key::Grabber::Ptr const& KeyGrabber() const;
1225
1226+ typedef sigc::slot<void, int /*x*/, int /*y*/, double /*speed*/> PositionTracker;
1227+ bool RegisterTracker(std::string const& menubar, PositionTracker const&);
1228+ bool UnregisterTracker(std::string const& menubar, PositionTracker const& = PositionTracker());
1229+
1230 sigc::signal<void> appmenu_added;
1231 sigc::signal<void> appmenu_removed;
1232 sigc::signal<bool>::accumulated<any_true> open_first;
1233
1234=== added file 'unity-shared/SigcSlotHash.h'
1235--- unity-shared/SigcSlotHash.h 1970-01-01 00:00:00 +0000
1236+++ unity-shared/SigcSlotHash.h 2016-09-01 22:11:45 +0000
1237@@ -0,0 +1,70 @@
1238+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1239+/*
1240+ * Copyright (C) 2016 Canonical Ltd
1241+ *
1242+ * This program is free software: you can redistribute it and/or modify
1243+ * it under the terms of the GNU General Public License version 3 as
1244+ * published by the Free Software Foundation.
1245+ *
1246+ * This program is distributed in the hope that it will be useful,
1247+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1248+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1249+ * GNU General Public License for more details.
1250+ *
1251+ * You should have received a copy of the GNU General Public License
1252+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1253+ *
1254+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
1255+ */
1256+
1257+#ifndef __UNITY_SIGC_SLOT_HASHER__
1258+#define __UNITY_SIGC_SLOT_HASHER__
1259+
1260+#include <sigc++/slot.h>
1261+
1262+namespace sigc
1263+{
1264+inline bool operator==(slot_base const& lhs, slot_base const& rhs)
1265+{
1266+ if (!lhs.rep_ || !rhs.rep_)
1267+ return (lhs.rep_ == rhs.rep_);
1268+
1269+ return (lhs.rep_->call_ == rhs.rep_->call_);
1270+}
1271+
1272+inline bool operator!=(slot_base const& lhs, slot_base const& rhs)
1273+{
1274+ return !(lhs == rhs);
1275+}
1276+} // sigc namespace
1277+
1278+namespace std
1279+{
1280+
1281+template<>
1282+struct hash<sigc::slot_base>
1283+{
1284+ size_t operator()(sigc::slot_base const& cb) const
1285+ {
1286+ if (cb.rep_)
1287+ return hash<size_t>()(reinterpret_cast<size_t>(cb.rep_->call_));
1288+
1289+ return hash<size_t>()(reinterpret_cast<size_t>(cb.rep_));
1290+ }
1291+};
1292+
1293+#if __GNUC__ < 6
1294+template<class T>
1295+struct hash
1296+{
1297+ size_t operator()(T const& cb) const
1298+ {
1299+ static_assert(std::is_base_of<sigc::slot_base, T>::value, "Type is not derived from sigc::slot_base");
1300+ return hash<sigc::slot_base>()(cb);
1301+ }
1302+};
1303+#endif
1304+
1305+} // std namespace
1306+
1307+#endif // __UNITY_SIGC_SLOT_HASHER__