Merge lp:~3v1n0/unity/lim-everywhere into lp:unity

Proposed by Marco Trevisan (Treviño)
Status: Merged
Approved by: Andrea Azzarone
Approved revision: no longer in the source branch.
Merged at revision: 3920
Proposed branch: lp:~3v1n0/unity/lim-everywhere
Merge into: lp:unity
Diff against target: 5330 lines (+1370/-785)
70 files modified
UnityCore/AppmenuIndicator.cpp (+52/-12)
UnityCore/AppmenuIndicator.h (+4/-3)
UnityCore/CMakeLists.txt (+1/-0)
UnityCore/DBusIndicators.cpp (+52/-40)
UnityCore/GLibDBusServer.cpp (+3/-2)
UnityCore/GLibSource.h (+2/-2)
UnityCore/Indicator.cpp (+15/-30)
UnityCore/Indicator.h (+3/-4)
UnityCore/IndicatorEntry.cpp (+15/-5)
UnityCore/IndicatorEntry.h (+4/-1)
UnityCore/Indicators.cpp (+2/-1)
UnityCore/pch/unitycore_pch.hh (+1/-0)
com.canonical.Unity.gschema.xml (+7/-1)
dash/DashView.h (+1/-1)
dash/ScopeView.h (+2/-1)
debian/control (+1/-1)
decorations/DecoratedWindow.cpp (+13/-9)
decorations/DecorationsManager.cpp (+12/-15)
decorations/DecorationsMenuDropdown.cpp (+4/-3)
decorations/DecorationsMenuEntry.cpp (+12/-2)
decorations/DecorationsMenuEntry.h (+2/-1)
decorations/DecorationsMenuLayout.cpp (+25/-3)
decorations/DecorationsPriv.h (+3/-1)
decorations/DecorationsSlidingLayout.cpp (+1/-1)
decorations/DecorationsWidgets.cpp (+4/-9)
launcher/LauncherEntryRemoteModel.h (+2/-2)
lockscreen/LockScreenPanel.cpp (+1/-1)
panel/PanelIndicatorEntryDropdownView.cpp (+6/-1)
panel/PanelIndicatorEntryDropdownView.h (+1/-0)
panel/PanelIndicatorEntryView.cpp (+7/-5)
panel/PanelIndicatorEntryView.h (+2/-3)
panel/PanelIndicatorsView.cpp (+43/-13)
panel/PanelIndicatorsView.h (+6/-4)
panel/PanelMenuView.cpp (+140/-112)
panel/PanelMenuView.h (+8/-4)
panel/PanelView.cpp (+3/-3)
plugins/unityshell/src/unityshell.cpp (+34/-44)
plugins/unityshell/src/unityshell.h (+2/-1)
services/panel-main.c (+20/-20)
services/panel-service-private.h (+22/-3)
services/panel-service.c (+148/-60)
services/panel-service.h (+0/-8)
shortcuts/ShortcutModel.h (+3/-3)
tests/autopilot/unity/emulators/panel.py (+4/-0)
tests/autopilot/unity/tests/__init__.py (+12/-13)
tests/autopilot/unity/tests/test_dash.py (+2/-2)
tests/autopilot/unity/tests/test_hud.py (+2/-2)
tests/autopilot/unity/tests/test_panel.py (+258/-211)
tests/autopilot/unity/tests/test_wm_keybindings.py (+1/-6)
tests/mock-application.h (+2/-2)
tests/test_dbus_indicators.cpp (+3/-4)
tests/test_indicator.cpp (+18/-21)
tests/test_indicator_appmenu.cpp (+182/-21)
tests/test_indicator_entry.cpp (+17/-14)
tests/test_indicators.cpp (+11/-11)
tests/test_panel_menu_view.cpp (+19/-3)
tests/test_panel_service.cpp (+6/-2)
tests/test_service_panel.cpp (+18/-15)
unity-shared/IconLoader.cpp (+2/-2)
unity-shared/MenuManager.cpp (+64/-9)
unity-shared/NuxObjectPtrHash.h (+36/-0)
unity-shared/PlacesVScrollBar.cpp (+1/-1)
unity-shared/PluginAdapter.cpp (+11/-2)
unity-shared/PluginAdapter.h (+2/-2)
unity-shared/PreviewStyle.cpp (+1/-1)
unity-shared/StandaloneWindowManager.cpp (+1/-0)
unity-shared/UBusWrapper.cpp (+3/-4)
unity-shared/UBusWrapper.h (+2/-2)
unity-shared/UnitySettings.cpp (+2/-0)
unity-shared/UnitySettings.h (+1/-0)
To merge this branch: bzr merge lp:~3v1n0/unity/lim-everywhere
Reviewer Review Type Date Requested Status
Stephen M. Webb (community) Approve
Andrea Azzarone (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+248359@code.launchpad.net

Commit message

Decorations, Panel: add menus for unfocused windows as well

Now the indicator-appmenu exports the menus for all the windows,
then it's up to us to filter them based on their parent window and
show on relevant place.
Also, set LIM as default now.

Description of the change

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Andrea Azzarone (azzar1) wrote :

+1 for me as discussed over irc.

review: Approve
Revision history for this message
Stephen M. Webb (bregma) wrote :

AP tests need fixing, see inline comments.

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

fixed

Revision history for this message
Stephen M. Webb (bregma) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'UnityCore/AppmenuIndicator.cpp'
2--- UnityCore/AppmenuIndicator.cpp 2014-12-18 19:30:05 +0000
3+++ UnityCore/AppmenuIndicator.cpp 2015-02-19 19:24:14 +0000
4@@ -17,41 +17,81 @@
5 * Authored by: Marco Trevisan (Treviño) <3v1n0@ubuntu.com>
6 */
7
8-#include "GLibSource.h"
9+#include <unordered_set>
10+
11 #include "AppmenuIndicator.h"
12+#include "ConnectionManager.h"
13
14 namespace unity
15 {
16 namespace indicator
17 {
18+namespace
19+{
20+const Indicator::Entries empty_entries_;
21+}
22
23 struct AppmenuIndicator::Impl
24 {
25 Impl(AppmenuIndicator* parent)
26 {
27- // When the active window has changed we might need to emit an updated signal
28- parent->active_window.changed.connect([this, parent] (unsigned long) {
29- update_wait_.reset(new glib::Timeout(250, [parent] {
30- parent->updated.emit();
31- return false;
32- }));
33- });
34-
35- parent->updated.connect([this] { update_wait_.reset(); });
36+ connections_.Add(parent->on_entry_added.connect([this] (Entry::Ptr const& entry) {
37+ window_entries_[entry->parent_window()].push_back(entry);
38+ }));
39+
40+ connections_.Add(parent->on_entry_removed.connect([this] (Entry::Ptr const& entry) {
41+ auto it = window_entries_.find(entry->parent_window());
42+
43+ if (it != window_entries_.end())
44+ {
45+ auto& entries = it->second;
46+ entries.erase(std::remove(entries.begin(), entries.end(), entry), entries.end());
47+
48+ if (entries.empty())
49+ window_entries_.erase(it);
50+ }
51+ }));
52 }
53
54- glib::Source::UniquePtr update_wait_;
55+ connection::Manager connections_;
56+ std::unordered_map<uint32_t, Indicator::Entries> window_entries_;
57 };
58
59 AppmenuIndicator::AppmenuIndicator(std::string const& name)
60 : Indicator(name)
61- , active_window(0)
62 , impl_(new AppmenuIndicator::Impl(this))
63 {}
64
65 AppmenuIndicator::~AppmenuIndicator()
66 {}
67
68+void AppmenuIndicator::Sync(Indicator::Entries const& entries)
69+{
70+ std::unordered_set<uint32_t> changed_windows;
71+ connection::Wrapper added_conn(on_entry_added.connect([this, &changed_windows] (Entry::Ptr const& entry) {
72+ changed_windows.insert(entry->parent_window());
73+ }));
74+
75+ connection::Wrapper rm_conn(on_entry_removed.connect([this, &changed_windows] (Entry::Ptr const& entry) {
76+ changed_windows.insert(entry->parent_window());
77+ }));
78+
79+ Indicator::Sync(entries);
80+
81+ for (uint32_t win : changed_windows)
82+ updated_win.emit(win);
83+}
84+
85+Indicator::Entries const& AppmenuIndicator::GetEntriesForWindow(uint32_t parent_window) const
86+{
87+ auto it = impl_->window_entries_.find(parent_window);
88+
89+ if (it != impl_->window_entries_.end())
90+ return it->second;
91+
92+ return empty_entries_;
93+}
94+
95 void AppmenuIndicator::ShowAppmenu(unsigned int xid, int x, int y) const
96 {
97 on_show_appmenu.emit(xid, x, y);
98
99=== modified file 'UnityCore/AppmenuIndicator.h'
100--- UnityCore/AppmenuIndicator.h 2014-12-18 18:46:29 +0000
101+++ UnityCore/AppmenuIndicator.h 2015-02-19 19:24:14 +0000
102@@ -36,12 +36,13 @@
103 AppmenuIndicator(std::string const& name);
104 ~AppmenuIndicator();
105
106- nux::Property<unsigned> active_window;
107-
108- virtual bool IsAppmenu() const { return true; }
109+ bool IsAppmenu() const override { return true; }
110+ void Sync(Entries const&) override;
111+ Entries const& GetEntriesForWindow(uint32_t parent_window) const;
112
113 void ShowAppmenu(unsigned xid, int x, int y) const;
114
115+ sigc::signal<void, uint32_t> updated_win;
116 sigc::signal<void, unsigned, int, int> on_show_appmenu;
117
118 private:
119
120=== modified file 'UnityCore/CMakeLists.txt'
121--- UnityCore/CMakeLists.txt 2014-02-05 11:38:22 +0000
122+++ UnityCore/CMakeLists.txt 2015-02-19 19:24:14 +0000
123@@ -117,6 +117,7 @@
124 #
125 include_directories(${CORE_DEPS_INCLUDE_DIRS})
126 include_directories(${CMAKE_BINARY_DIR})
127+include_directories(..)
128
129 set (LIBS ${CORE_DEPS_LDFLAGS} ${PRIVATE_CORE_DEPS_LDFLAGS})
130
131
132=== modified file 'UnityCore/DBusIndicators.cpp'
133--- UnityCore/DBusIndicators.cpp 2014-09-19 18:48:04 +0000
134+++ UnityCore/DBusIndicators.cpp 2015-02-19 19:24:14 +0000
135@@ -27,19 +27,29 @@
136 #include "GLibSource.h"
137 #include "Variant.h"
138 #include "DBusIndicators.h"
139+#include "services/panel-service-private.h"
140
141 namespace unity
142 {
143 namespace indicator
144 {
145+
146+namespace
147+{
148 DECLARE_LOGGER(logger, "unity.indicator.dbus");
149
150-namespace
151+inline bool verify_variant_type(GVariant* value, const gchar* type)
152 {
153-const std::string SERVICE_NAME_DESKTOP("com.canonical.Unity.Panel.Service.Desktop");
154-const std::string SERVICE_NAME_LOCKSCREEN("com.canonical.Unity.Panel.Service.LockScreen");
155-const std::string SERVICE_PATH("/com/canonical/Unity/Panel/Service");
156-const std::string SERVICE_IFACE("com.canonical.Unity.Panel.Service");
157+ if (!g_variant_is_of_type (value, G_VARIANT_TYPE(type)))
158+ {
159+ LOG_ERROR(logger) << "Got invalid variant type: '"
160+ << g_variant_get_type_string(value) << "' ('"
161+ << type << "' was expected)";
162+ return false;
163+ }
164+
165+ return true;
166+}
167 } // anonymous namespace
168
169
170@@ -78,15 +88,15 @@
171 glib::Source::UniquePtr show_entry_idle_;
172 glib::Source::UniquePtr show_appmenu_idle_;
173 std::vector<std::string> icon_paths_;
174- std::map<std::string, EntryLocationMap> cached_locations_;
175+ std::unordered_map<std::string, EntryLocationMap> cached_locations_;
176 };
177
178
179 // Public Methods
180 DBusIndicators::Impl::Impl(std::string const& dbus_name, DBusIndicators* owner)
181 : owner_(owner)
182- , gproxy_(dbus_name, SERVICE_PATH, SERVICE_IFACE,
183- G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES)
184+ , gproxy_(dbus_name, UPS_PATH, UPS_IFACE, G_BUS_TYPE_SESSION,
185+ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES)
186 {
187 gproxy_.Connect("ReSync", sigc::mem_fun(this, &DBusIndicators::Impl::OnReSync));
188 gproxy_.Connect("IconPathsChanged", sigc::mem_fun(this, &DBusIndicators::Impl::OnIconsPathChanged));
189@@ -208,6 +218,9 @@
190
191 void DBusIndicators::Impl::OnEntryActivated(GVariant* parameters)
192 {
193+ if (!verify_variant_type(parameters, "(ss(iiuu))"))
194+ return;
195+
196 glib::String panel;
197 glib::String entry_id;
198 nux::Rect geo;
199@@ -219,6 +232,9 @@
200
201 void DBusIndicators::Impl::OnEntryActivatedRequest(GVariant* parameters)
202 {
203+ if (!verify_variant_type(parameters, "(s)"))
204+ return;
205+
206 glib::String entry_name;
207 g_variant_get(parameters, "(s)", &entry_name);
208
209@@ -228,6 +244,9 @@
210
211 void DBusIndicators::Impl::OnEntryShowNowChanged(GVariant* parameters)
212 {
213+ if (!verify_variant_type(parameters, "(sb)"))
214+ return;
215+
216 glib::String entry_name;
217 gboolean show_now;
218 g_variant_get(parameters, "(sb)", &entry_name, &show_now);
219@@ -325,9 +344,10 @@
220 return;
221
222 GVariantIter* iter = nullptr;
223- gchar* name_hint = nullptr;
224 gchar* indicator_id = nullptr;
225 gchar* entry_id = nullptr;
226+ gchar* name_hint = nullptr;
227+ guint32 parent_window = 0;
228 gchar* label = nullptr;
229 gboolean label_sensitive = false;
230 gboolean label_visible = false;
231@@ -337,15 +357,17 @@
232 gboolean image_visible = false;
233 gint32 priority = -1;
234
235- std::map<Indicator::Ptr, Indicator::Entries> indicators;
236- int wanted_idx = 0;
237- bool any_different_idx = false;
238-
239- g_variant_get(args, "(a(ssssbbusbbi))", &iter);
240- while (g_variant_iter_loop(iter, "(ssssbbusbbi)",
241+ if (!verify_variant_type(args, "(" ENTRY_ARRAY_SIGNATURE ")"))
242+ return;
243+
244+ std::unordered_map<Indicator::Ptr, Indicator::Entries> indicators;
245+
246+ g_variant_get(args, "(" ENTRY_ARRAY_SIGNATURE ")", &iter);
247+ while (g_variant_iter_loop(iter, ENTRY_SIGNATURE,
248 &indicator_id,
249 &entry_id,
250 &name_hint,
251+ &parent_window,
252 &label,
253 &label_sensitive,
254 &label_visible,
255@@ -369,27 +391,20 @@
256 // Empty entries are empty indicators.
257 if (!entry.empty())
258 {
259- Entry::Ptr e;
260- if (!any_different_idx)
261- {
262- // Indicators can only add or remove entries, so if
263- // there is a index change we can't reuse the existing ones
264- // after that index
265- if (indicator->EntryIndex(entry_id) == wanted_idx)
266- {
267- e = indicator->GetEntry(entry_id);
268- }
269- else
270- {
271- any_different_idx = true;
272- }
273- }
274+ Entry::Ptr e = indicator->GetEntry(entry_id);
275+ int old_priority = e ? e->priority() : -1;
276+
277+ // Indicators can only add or remove entries, so if
278+ // there is a priority change we can't reuse the existing ones
279+ if (old_priority != priority)
280+ e.reset();
281
282 if (!e)
283 {
284- e = std::make_shared<Entry>(entry, name_hint, label, label_sensitive,
285- label_visible, image_type, image_data,
286- image_sensitive, image_visible, priority);
287+ e = std::make_shared<Entry>(entry, name_hint, parent_window,
288+ label, label_sensitive, label_visible,
289+ image_type, image_data, image_sensitive, image_visible,
290+ priority);
291 }
292 else
293 {
294@@ -399,15 +414,12 @@
295 }
296
297 entries.push_back(e);
298- ++wanted_idx;
299 }
300 }
301 g_variant_iter_free(iter);
302
303- for (auto i = indicators.begin(), end = indicators.end(); i != end; ++i)
304- {
305- i->first->Sync(indicators[i->first]);
306- }
307+ for (auto const& i : indicators)
308+ i.first->Sync(i.second);
309 }
310
311 void DBusIndicators::Impl::SyncGeometries(std::string const& name,
312@@ -463,7 +475,7 @@
313 }
314
315 DBusIndicators::DBusIndicators()
316- : pimpl(new Impl(SERVICE_NAME_DESKTOP, this))
317+ : pimpl(new Impl(UPS_NAME_DESKTOP, this))
318 {}
319
320 DBusIndicators::DBusIndicators(std::string const& dbus_name)
321@@ -471,7 +483,7 @@
322 {}
323
324 LockScreenDBusIndicators::LockScreenDBusIndicators()
325- : DBusIndicators(SERVICE_NAME_LOCKSCREEN)
326+ : DBusIndicators(UPS_NAME_LOCKSCREEN)
327 {}
328
329 DBusIndicators::~DBusIndicators()
330
331=== modified file 'UnityCore/GLibDBusServer.cpp'
332--- UnityCore/GLibDBusServer.cpp 2014-04-09 13:19:33 +0000
333+++ UnityCore/GLibDBusServer.cpp 2015-02-19 19:24:14 +0000
334@@ -17,6 +17,7 @@
335 * Authored by: Marco Trevisan (Treviño) <marco.trevisan@canonical.com>
336 */
337
338+#include <unordered_map>
339 #include <NuxCore/Logger.h>
340
341 #include "GLibDBusServer.h"
342@@ -406,8 +407,8 @@
343
344 GDBusInterfaceVTable interface_vtable_;
345 std::shared_ptr<GDBusInterfaceInfo> interface_info_;
346- std::map<guint, std::string> registrations_;
347- std::map<std::string, glib::Object<GDBusConnection>> connection_by_path_;
348+ std::unordered_map<guint, std::string> registrations_;
349+ std::unordered_map<std::string, glib::Object<GDBusConnection>> connection_by_path_;
350 };
351
352 DBusObject::DBusObject(std::string const& introspection_xml, std::string const& interface_name)
353
354=== modified file 'UnityCore/GLibSource.h'
355--- UnityCore/GLibSource.h 2013-10-10 09:47:24 +0000
356+++ UnityCore/GLibSource.h 2015-02-19 19:24:14 +0000
357@@ -24,7 +24,7 @@
358 #include <sigc++/sigc++.h>
359 #include <glib.h>
360 #include <memory>
361-#include <map>
362+#include <unordered_map>
363
364 namespace unity
365 {
366@@ -223,7 +223,7 @@
367 Source::Ptr GetSource(unsigned int id) const;
368
369 protected: // For testing purposes
370- typedef std::map<std::string, Source::Ptr> SourcesMap;
371+ typedef std::unordered_map<std::string, Source::Ptr> SourcesMap;
372 SourcesMap sources_;
373
374 private:
375
376=== modified file 'UnityCore/Indicator.cpp'
377--- UnityCore/Indicator.cpp 2014-01-27 17:31:30 +0000
378+++ UnityCore/Indicator.cpp 2015-02-19 19:24:14 +0000
379@@ -36,7 +36,7 @@
380 Indicator::~Indicator()
381 {
382 for (auto const& entry : entries_)
383- on_entry_removed.emit(entry->id());
384+ on_entry_removed.emit(entry);
385 }
386
387 std::string const& Indicator::name() const
388@@ -51,23 +51,23 @@
389
390 void Indicator::Sync(Indicator::Entries const& new_entries)
391 {
392- bool added = false;
393- Entries to_rm;
394+ bool changed = false;
395
396- if (!entries_.empty())
397+ for (auto it = entries_.begin(); it != entries_.end();)
398 {
399- for (auto const& entry : entries_)
400+ auto entry = *it;
401+
402+ if (std::find(new_entries.begin(), new_entries.end(), entry) == new_entries.end())
403 {
404- if (std::find(new_entries.begin(), new_entries.end(), entry) == new_entries.end())
405- to_rm.push_back(entry);
406+ auto entry_id = entry->id();
407+ entries_connections_.erase(entry);
408+ it = entries_.erase(it);
409+ on_entry_removed.emit(entry);
410+ changed = true;
411+ continue;
412 }
413- }
414
415- for (auto const& entry : to_rm)
416- {
417- entries_connections_.erase(entry);
418- on_entry_removed.emit(entry->id());
419- entries_.remove(entry);
420+ ++it;
421 }
422
423 for (auto const& new_entry : new_entries)
424@@ -93,10 +93,10 @@
425 entries_.push_back(new_entry);
426 on_entry_added.emit(new_entry);
427
428- added = true;
429+ changed = true;
430 }
431
432- if (!to_rm.empty() || added)
433+ if (changed)
434 updated.emit();
435 }
436
437@@ -109,21 +109,6 @@
438 return Entry::Ptr();
439 }
440
441-int Indicator::EntryIndex(std::string const& entry_id) const
442-{
443- int i = 0;
444- for (auto const& entry : entries_)
445- {
446- if (entry->id() == entry_id)
447- {
448- return i;
449- }
450- ++i;
451- }
452-
453- return -1;
454-}
455-
456 std::ostream& operator<<(std::ostream& out, Indicator const& i)
457 {
458 out << "<Indicator " << i.name() << std::endl;
459
460=== modified file 'UnityCore/Indicator.h'
461--- UnityCore/Indicator.h 2014-02-05 17:16:41 +0000
462+++ UnityCore/Indicator.h 2015-02-19 19:24:14 +0000
463@@ -38,7 +38,7 @@
464 {
465 public:
466 typedef std::shared_ptr<Indicator> Ptr;
467- typedef std::list<Entry::Ptr> Entries;
468+ typedef std::vector<Entry::Ptr> Entries;
469
470 Indicator(std::string const& name);
471 virtual ~Indicator();
472@@ -47,15 +47,14 @@
473
474 virtual bool IsAppmenu() const { return false; }
475
476- void Sync(Entries const& new_entries);
477+ virtual void Sync(Entries const&);
478 Entry::Ptr GetEntry(std::string const& entry_id) const;
479- int EntryIndex(std::string const& entry_id) const;
480 Entries const& GetEntries() const;
481
482 // Signals
483 sigc::signal<void> updated;
484 sigc::signal<void, Entry::Ptr const&> on_entry_added;
485- sigc::signal<void, std::string const&> on_entry_removed;
486+ sigc::signal<void, Entry::Ptr const&> on_entry_removed;
487 sigc::signal<void, std::string const&, unsigned, int, int, unsigned> on_show_menu;
488 sigc::signal<void, std::string const&> on_secondary_activate;
489 sigc::signal<void, std::string const&, int> on_scroll;
490
491=== modified file 'UnityCore/IndicatorEntry.cpp'
492--- UnityCore/IndicatorEntry.cpp 2014-02-07 23:54:15 +0000
493+++ UnityCore/IndicatorEntry.cpp 2015-02-19 19:24:14 +0000
494@@ -30,6 +30,7 @@
495
496 Entry::Entry(std::string const& id,
497 std::string const& name_hint,
498+ uint32_t parent_window,
499 std::string const& label,
500 bool label_sensitive,
501 bool label_visible,
502@@ -40,6 +41,7 @@
503 int priority)
504 : id_(id)
505 , name_hint_(name_hint)
506+ , parent_window_(parent_window)
507 , label_(label)
508 , label_visible_(label_visible)
509 , label_sensitive_(label_sensitive)
510@@ -52,9 +54,10 @@
511 , active_(false)
512 {}
513
514-Entry::Entry(std::string const& id, std::string const& name_hint)
515+Entry::Entry(std::string const& id, std::string const& name_hint, uint32_t parent_window)
516 : id_(id)
517 , name_hint_(name_hint)
518+ , parent_window_(parent_window)
519 , label_visible_(false)
520 , label_sensitive_(false)
521 , image_type_(0)
522@@ -65,14 +68,19 @@
523 , active_(false)
524 {}
525
526+std::string const& Entry::id() const
527+{
528+ return id_;
529+}
530+
531 std::string const& Entry::name_hint() const
532 {
533 return name_hint_;
534 }
535
536-std::string const& Entry::id() const
537+uint32_t Entry::parent_window() const
538 {
539- return id_;
540+ return parent_window_;
541 }
542
543 std::string const& Entry::label() const
544@@ -199,6 +207,7 @@
545
546 id_ = rhs.id_;
547 name_hint_ = rhs.name_hint_;
548+ parent_window_ = rhs.parent_window_;
549 label_ = rhs.label_;
550 label_sensitive_ = rhs.label_sensitive_;
551 label_visible_ = rhs.label_visible_;
552@@ -258,7 +267,7 @@
553
554 void Entry::ShowMenu(int x, int y, unsigned button)
555 {
556- ShowMenu(0, x, y, button);
557+ ShowMenu(parent_window_, x, y, button);
558 }
559
560 void Entry::ShowMenu(unsigned int xid, int x, int y, unsigned button)
561@@ -278,7 +287,8 @@
562
563 std::ostream& operator<<(std::ostream& out, Entry const& e)
564 {
565- out << "<indicator::Entry " << e.id() << " hint: '" << e.name_hint() << "' "
566+ out << "<indicator::Entry " << e.id() << " hint: '" << e.name_hint() << "'"
567+ << " parent window: " << e.parent_window()
568 << std::boolalpha
569 << " \"" << e.label() << "\" ("
570 << e.label_sensitive() << ", " << e.label_visible() << ") image ("
571
572=== modified file 'UnityCore/IndicatorEntry.h'
573--- UnityCore/IndicatorEntry.h 2014-02-05 17:16:41 +0000
574+++ UnityCore/IndicatorEntry.h 2015-02-19 19:24:14 +0000
575@@ -44,9 +44,10 @@
576 public:
577 typedef std::shared_ptr<Entry> Ptr;
578
579- Entry(std::string const& id, std::string const& name_hint = "");
580+ Entry(std::string const& id, std::string const& name_hint = "", uint32_t parent_window = 0);
581 Entry(std::string const& id,
582 std::string const& name_hint,
583+ uint32_t parent_window,
584 std::string const& label,
585 bool label_sensitive,
586 bool label_visible,
587@@ -61,6 +62,7 @@
588
589 std::string const& id() const;
590 std::string const& name_hint() const;
591+ uint32_t parent_window() const;
592
593 void set_image(int type, std::string const& data, bool sensitive, bool visible);
594 bool image_visible() const;
595@@ -114,6 +116,7 @@
596 private:
597 std::string id_;
598 std::string name_hint_;
599+ uint32_t parent_window_;
600
601 std::string label_;
602 bool label_visible_;
603
604=== modified file 'UnityCore/Indicators.cpp'
605--- UnityCore/Indicators.cpp 2014-02-11 03:11:47 +0000
606+++ UnityCore/Indicators.cpp 2015-02-19 19:24:14 +0000
607@@ -20,6 +20,7 @@
608
609 #include "Indicators.h"
610 #include "AppmenuIndicator.h"
611+#include "services/panel-service-private.h"
612
613 namespace unity
614 {
615@@ -143,7 +144,7 @@
616 if (indicator)
617 return indicator;
618
619- if (name == "libappmenu.so")
620+ if (name == APPMENU_INDICATOR_NAME)
621 {
622 auto appmenu = std::make_shared<AppmenuIndicator>(name);
623 appmenu->on_show_appmenu.connect(sigc::mem_fun(owner_, &Indicators::OnShowAppMenu));
624
625=== modified file 'UnityCore/pch/unitycore_pch.hh'
626--- UnityCore/pch/unitycore_pch.hh 2014-01-28 15:39:57 +0000
627+++ UnityCore/pch/unitycore_pch.hh 2015-02-19 19:24:14 +0000
628@@ -29,6 +29,7 @@
629 #include <map>
630 #include <memory>
631 #include <unordered_map>
632+#include <functional>
633
634 #include <boost/utility.hpp>
635 #include <dee.h>
636
637=== modified file 'com.canonical.Unity.gschema.xml'
638--- com.canonical.Unity.gschema.xml 2014-12-19 12:43:56 +0000
639+++ com.canonical.Unity.gschema.xml 2015-02-19 19:24:14 +0000
640@@ -47,7 +47,7 @@
641 <description>This is used to enable/disable double-click result activation in the dash. Double-click to activate, single click preview</description>
642 </key>
643 <key type="b" name="integrated-menus">
644- <default>false</default>
645+ <default>true</default>
646 <summary>Enable/Disable the integrated menus in Unity.</summary>
647 <description>When this is enabled, the application menus will be shown
648 on the window decoration, otherwise they will be always shown on the
649@@ -176,5 +176,11 @@
650 a window by double-clicking on its menus if the second click happens before the
651 specified value of ms is elapsed</description>
652 </key>
653+ <key type="b" name="unfocused-windows-popup">
654+ <default>true</default>
655+ <summary>Whether to pop-up a menu when clicking over unfocused windows entries</summary>
656+ <description>By disabling this setting you can make unity to only focus a window
657+ when clicking over unfocused menu entries</description>
658+ </key>
659 </schema>
660 </schemalist>
661
662=== modified file 'dash/DashView.h'
663--- dash/DashView.h 2014-07-07 13:16:18 +0000
664+++ dash/DashView.h 2015-02-19 19:24:14 +0000
665@@ -56,7 +56,7 @@
666 class DashView : public nux::View, public unity::debug::Introspectable
667 {
668 NUX_DECLARE_OBJECT_TYPE(DashView, nux::View);
669- typedef std::map<std::string, nux::ObjectPtr<ScopeView>> ScopeViews;
670+ typedef std::unordered_map<std::string, nux::ObjectPtr<ScopeView>> ScopeViews;
671
672 public:
673 DashView(Scopes::Ptr const& scopes, ApplicationStarter::Ptr const& application_starter);
674
675=== modified file 'dash/ScopeView.h'
676--- dash/ScopeView.h 2014-07-11 20:53:25 +0000
677+++ dash/ScopeView.h 2015-02-19 19:24:14 +0000
678@@ -35,6 +35,7 @@
679 #include "unity-shared/Introspectable.h"
680 #include "PlacesGroup.h"
681 #include "ResultViewGrid.h"
682+#include "unity-shared/NuxObjectPtrHash.h"
683 #include "unity-shared/UBusWrapper.h"
684
685 namespace unity
686@@ -48,7 +49,7 @@
687 {
688 NUX_DECLARE_OBJECT_TYPE(ScopeView, nux::View);
689 typedef std::vector<PlacesGroup::Ptr> CategoryGroups;
690- typedef std::map<PlacesGroup::Ptr, unsigned int> ResultCounts;
691+ typedef std::unordered_map<PlacesGroup::Ptr, unsigned int> ResultCounts;
692
693 public:
694 ScopeView(Scope::Ptr const& scope, nux::Area* show_filters);
695
696=== modified file 'debian/control'
697--- debian/control 2014-11-04 18:57:33 +0000
698+++ debian/control 2015-02-19 19:24:14 +0000
699@@ -80,7 +80,7 @@
700 Provides: indicator-renderer
701 Recommends: unity-control-center,
702 ${unity-default-masterscopes}
703- indicator-appmenu,
704+ indicator-appmenu (>= 15.02.0),
705 indicator-application,
706 indicator-sound,
707 indicator-bluetooth,
708
709=== modified file 'decorations/DecoratedWindow.cpp'
710--- decorations/DecoratedWindow.cpp 2014-12-19 13:03:44 +0000
711+++ decorations/DecoratedWindow.cpp 2015-02-19 19:24:14 +0000
712@@ -50,17 +50,13 @@
713 , deco_elements_(cu::DecorationElement::NONE)
714 , last_mwm_decor_(win_->mwmDecor())
715 , last_actions_(win_->actions())
716+ , panel_id_(MENUS_PANEL_NAME + std::to_string(win_->id()))
717 , cv_(Settings::Instance().em())
718 {
719 active.changed.connect([this] (bool active) {
720 bg_textures_.clear();
721 if (top_layout_)
722- {
723 top_layout_->focused = active;
724-
725- if (!active)
726- UnsetAppMenu();
727- }
728 RedrawDecorations();
729 });
730
731@@ -701,7 +697,7 @@
732
733 void Window::Impl::SetupAppMenu()
734 {
735- if (!active() || !top_layout_)
736+ if (!top_layout_)
737 return;
738
739 auto const& menu_manager = manager_->impl_->menu_manager_;
740@@ -716,8 +712,11 @@
741
742 auto menus = std::make_shared<MenuLayout>(menu_manager, win_);
743 menus->Setup();
744+
745+ if (menus->Items().empty())
746+ return;
747+
748 menus_ = menus;
749-
750 auto const& grab_edge = grab_edge_.lock();
751 sliding_layout->SetInputItem(menus);
752 sliding_layout->fadein = menu_manager->fadein();
753@@ -759,13 +758,18 @@
754 sliding_layout->mouse_owner = grab_edge_->mouse_owner();
755 }
756
757+inline std::string const& Window::Impl::GetMenusPanelID() const
758+{
759+ return panel_id_;
760+}
761+
762 void Window::Impl::UnsetAppMenu()
763 {
764 if (!menus_)
765 return;
766
767 auto const& indicators = manager_->impl_->menu_manager_->Indicators();
768- indicators->SyncGeometries(MENUS_PANEL_NAME, indicator::EntryLocationMap());
769+ indicators->SyncGeometries(GetMenusPanelID(), indicator::EntryLocationMap());
770 sliding_layout_->SetInputItem(nullptr);
771 grab_mouse_changed_->disconnect();
772 }
773@@ -778,7 +782,7 @@
774 auto const& indicators = manager_->impl_->menu_manager_->Indicators();
775 indicator::EntryLocationMap map;
776 menus_->ChildrenGeometries(map);
777- indicators->SyncGeometries(MENUS_PANEL_NAME, map);
778+ indicators->SyncGeometries(GetMenusPanelID(), map);
779 }
780
781 bool Window::Impl::ActivateMenu(std::string const& entry_id)
782
783=== modified file 'decorations/DecorationsManager.cpp'
784--- decorations/DecorationsManager.cpp 2014-12-19 13:03:44 +0000
785+++ decorations/DecorationsManager.cpp 2015-02-19 19:24:14 +0000
786@@ -141,27 +141,24 @@
787 return;
788 }
789
790- appmenu->active_window = screen->activeWindow();
791-
792- auto setup_active_window = [this] {
793- if (Window::Ptr const& active_win = active_deco_win_.lock())
794- active_win->impl_->SetupAppMenu();
795- };
796+ for (auto const& win : windows_)
797+ win.second->impl_->SetupAppMenu();
798
799 menu_connections_.Remove(appmenu_connection_);
800- appmenu_connection_ = menu_connections_.Add(appmenu->updated.connect(setup_active_window));
801- setup_active_window();
802+ appmenu_connection_ = menu_connections_.Add(appmenu->updated_win.connect([this] (uint32_t xid) {
803+ if (Window::Ptr const& win = GetWindowByXid(xid))
804+ win->impl_->SetupAppMenu();
805+ }));
806 }
807
808 void Manager::Impl::UnsetAppMenu()
809 {
810 menu_connections_.Remove(appmenu_connection_);
811- auto const& active_win = active_deco_win_.lock();
812
813- if (active_win)
814+ for (auto const& win : windows_)
815 {
816- active_win->impl_->UnsetAppMenu();
817- active_win->impl_->Damage();
818+ win.second->impl_->UnsetAppMenu();
819+ win.second->impl_->Damage();
820 }
821 }
822
823@@ -265,9 +262,6 @@
824
825 if (new_active)
826 new_active->impl_->active = true;
827-
828- if (indicator::AppmenuIndicator::Ptr const& appmenu = menu_manager_->AppMenu())
829- appmenu->active_window = active_xid;
830 }
831 else if (event->xproperty.atom == Atoms::mwmHints ||
832 event->xproperty.atom == Atoms::wmAllowedActions)
833@@ -308,6 +302,9 @@
834
835 bool Manager::Impl::HandleFrameEvent(XEvent* event)
836 {
837+ if (WindowManager::Default().IsScaleActive())
838+ return false;
839+
840 auto const& win = GetWindowByFrame(event->xany.window);
841
842 // ButtonRelease events might happen also outside the frame window, in this
843
844=== modified file 'decorations/DecorationsMenuDropdown.cpp'
845--- decorations/DecorationsMenuDropdown.cpp 2014-02-24 23:53:50 +0000
846+++ decorations/DecorationsMenuDropdown.cpp 2015-02-19 19:24:14 +0000
847@@ -33,7 +33,7 @@
848 using namespace indicator;
849
850 MenuDropdown::MenuDropdown(Indicators::Ptr const& indicators, CompWindow* win)
851- : MenuEntry(std::make_shared<Entry>("LIM-dropdown"), win)
852+ : MenuEntry(std::make_shared<Entry>("LIM"+std::to_string(win->id())+"-dropdown"), win)
853 , indicators_(indicators)
854 {
855 natural_.width = ICON_SIZE;
856@@ -53,7 +53,7 @@
857 for (auto const& child : children_)
858 entries.push_back(child->GetEntry());
859
860- indicators_->ShowEntriesDropdown(entries, active_, 0, geo.x(), geo.y2());
861+ indicators_->ShowEntriesDropdown(entries, active_, grab_.Window()->id(), geo.x(), geo.y2());
862 }
863
864 bool MenuDropdown::ActivateChild(MenuEntry::Ptr const& child)
865@@ -118,7 +118,8 @@
866
867 void MenuDropdown::RenderTexture()
868 {
869- WidgetState state = active() ? WidgetState::PRELIGHT : WidgetState::NORMAL;
870+ WidgetState normal_state = focused() ? WidgetState::NORMAL : WidgetState::BACKDROP;
871+ WidgetState state = active() ? WidgetState::PRELIGHT : normal_state;
872 cu::CairoContext icon_ctx(GetNaturalWidth(), GetNaturalHeight(), scale());
873
874 if (state == WidgetState::PRELIGHT)
875
876=== modified file 'decorations/DecorationsMenuEntry.cpp'
877--- decorations/DecorationsMenuEntry.cpp 2014-03-31 18:36:33 +0000
878+++ decorations/DecorationsMenuEntry.cpp 2015-02-19 19:24:14 +0000
879@@ -37,11 +37,13 @@
880 , in_dropdown(false)
881 , entry_(entry)
882 , grab_(win, true)
883+ , show_menu_enabled_(true)
884 {
885 entry_->updated.connect(sigc::mem_fun(this, &MenuEntry::EntryUpdated));
886 horizontal_padding.changed.connect(sigc::hide(sigc::mem_fun(this, &MenuEntry::RenderTexture)));
887 vertical_padding.changed.connect(sigc::hide(sigc::mem_fun(this, &MenuEntry::RenderTexture)));
888 scale.changed.connect(sigc::hide(sigc::mem_fun(this, &MenuEntry::RenderTexture)));
889+ focused.changed.connect(sigc::hide(sigc::mem_fun(this, &MenuEntry::RenderTexture)));
890 in_dropdown.changed.connect([this] (bool in) { visible = entry_->visible() && !in; });
891 EntryUpdated();
892 }
893@@ -63,7 +65,7 @@
894
895 void MenuEntry::RenderTexture()
896 {
897- WidgetState state = WidgetState::NORMAL;
898+ WidgetState state = focused() ? WidgetState::NORMAL : WidgetState::BACKDROP;
899
900 if (show_now())
901 state = WidgetState::PRESSED;
902@@ -120,10 +122,17 @@
903 {
904 button_up_timer_.reset();
905 grab_.ButtonDownEvent(p, button, timestamp);
906+ show_menu_enabled_ = (focused() || Settings::Instance().lim_unfocused_popup());
907 }
908
909 void MenuEntry::ButtonUpEvent(CompPoint const& p, unsigned button, Time timestamp)
910 {
911+ if (!show_menu_enabled_)
912+ {
913+ grab_.ButtonUpEvent(p, button, timestamp);
914+ return;
915+ }
916+
917 if (button == 1 && !grab_.IsGrabbed())
918 {
919 unsigned double_click_wait = Settings::Instance().lim_double_click_wait();
920@@ -143,7 +152,8 @@
921
922 if (button == 2 || button == 3)
923 {
924- ShowMenu(button);
925+ if (Style::Get()->WindowManagerAction(WMEvent(button)) == WMAction::NONE)
926+ ShowMenu(button);
927 }
928
929 grab_.ButtonUpEvent(p, button, timestamp);
930
931=== modified file 'decorations/DecorationsMenuEntry.h'
932--- decorations/DecorationsMenuEntry.h 2014-02-27 07:10:31 +0000
933+++ decorations/DecorationsMenuEntry.h 2015-02-19 19:24:14 +0000
934@@ -63,10 +63,11 @@
935
936 protected:
937 indicator::Entry::Ptr entry_;
938+ GrabEdge grab_;
939
940 private:
941+ bool show_menu_enabled_;
942 glib::Source::UniquePtr button_up_timer_;
943- GrabEdge grab_;
944 };
945
946 } // decoration namespace
947
948=== modified file 'decorations/DecorationsMenuLayout.cpp'
949--- decorations/DecorationsMenuLayout.cpp 2014-02-26 00:14:46 +0000
950+++ decorations/DecorationsMenuLayout.cpp 2015-02-19 19:24:14 +0000
951@@ -35,7 +35,9 @@
952 , win_(win)
953 , last_pointer_(-1, -1)
954 , dropdown_(std::make_shared<MenuDropdown>(menu_manager_->Indicators(), win))
955-{}
956+{
957+ visible = false;
958+}
959
960 void MenuLayout::Setup()
961 {
962@@ -56,7 +58,7 @@
963 dropdown_->active.changed.connect(active_cb);
964 dropdown_->show_now.changed.connect(show_now_cb);
965
966- for (auto const& entry : menu_manager_->AppMenu()->GetEntries())
967+ for (auto const& entry : menu_manager_->AppMenu()->GetEntriesForWindow(win_->id()))
968 {
969 auto menu = std::make_shared<MenuEntry>(entry, win_);
970 menu->mouse_owner.changed.connect(ownership_cb);
971@@ -65,7 +67,24 @@
972 menu->focused = focused();
973 menu->scale = scale();
974 menu->SetParent(shared_from_this());
975- items_.push_back(menu);
976+
977+ if (items_.empty() || entry->priority() < 0)
978+ {
979+ items_.push_back(menu);
980+ }
981+ else
982+ {
983+ auto pos = items_.rbegin();
984+
985+ for (; pos != items_.rend(); ++pos)
986+ {
987+ auto menu = std::static_pointer_cast<MenuEntry>(*pos);
988+ if (entry->priority() >= menu->GetEntry()->priority())
989+ break;
990+ }
991+
992+ items_.insert(pos.base(), menu);
993+ }
994 }
995
996 if (!items_.empty())
997@@ -195,12 +214,14 @@
998 int accumolated_width = dropdown_width + left_padding + right_padding - inner_padding;
999 int max_width = max_.width;
1000 std::list<MenuEntry::Ptr> to_hide;
1001+ bool is_visible = visible();
1002
1003 for (auto const& item : items_)
1004 {
1005 if (!item->visible() || item == dropdown_)
1006 continue;
1007
1008+ is_visible = true;
1009 accumolated_width += item->GetNaturalWidth() + inner_padding;
1010
1011 if (accumolated_width > max_width)
1012@@ -235,6 +256,7 @@
1013 dropdown_->Push(hidden);
1014 }
1015
1016+ visible = is_visible;
1017 Layout::DoRelayout();
1018 }
1019
1020
1021=== modified file 'decorations/DecorationsPriv.h'
1022--- decorations/DecorationsPriv.h 2014-10-22 14:38:06 +0000
1023+++ decorations/DecorationsPriv.h 2015-02-19 19:24:14 +0000
1024@@ -111,6 +111,7 @@
1025 bool ShouldBeDecorated() const;
1026 GLTexture* ShadowTexture() const;
1027 unsigned ShadowRadius() const;
1028+ std::string const& GetMenusPanelID() const;
1029
1030 void ComputeShadowQuads();
1031 void UpdateDecorationTextures();
1032@@ -143,6 +144,7 @@
1033 connection::Wrapper dpi_changed_;
1034 connection::Wrapper grab_mouse_changed_;
1035 std::string last_title_;
1036+ std::string panel_id_;
1037 std::vector<cu::SimpleTextureQuad> bg_textures_;
1038 std::shared_ptr<ForceQuitDialog> force_quit_;
1039 InputMixer::Ptr input_mixer_;
1040@@ -194,7 +196,7 @@
1041
1042 uweak_ptr<decoration::Window> active_deco_win_;
1043 uweak_ptr<InputMixer> last_mouse_owner_;
1044- std::map<CompWindow*, decoration::Window::Ptr> windows_;
1045+ std::unordered_map<CompWindow*, decoration::Window::Ptr> windows_;
1046 std::unordered_map<::Window, std::weak_ptr<decoration::Window>> framed_windows_;
1047
1048 menu::Manager::Ptr menu_manager_;
1049
1050=== modified file 'decorations/DecorationsSlidingLayout.cpp'
1051--- decorations/DecorationsSlidingLayout.cpp 2014-12-19 12:02:34 +0000
1052+++ decorations/DecorationsSlidingLayout.cpp 2015-02-19 19:24:14 +0000
1053@@ -137,7 +137,7 @@
1054 auto& main_item_ = items_[ItemRole::MAIN];
1055 auto& input_item_ = items_[ItemRole::INPUT];
1056
1057- if (!input_item_)
1058+ if (!input_item_ || !input_item_->visible())
1059 {
1060 if (main_item_)
1061 main_item_->Draw(ctx, transformation, attrib, clip, mask);
1062
1063=== modified file 'decorations/DecorationsWidgets.cpp'
1064--- decorations/DecorationsWidgets.cpp 2014-09-24 01:40:50 +0000
1065+++ decorations/DecorationsWidgets.cpp 2015-02-19 19:24:14 +0000
1066@@ -192,15 +192,10 @@
1067
1068 BasicContainer::Ptr Item::GetTopParent() const
1069 {
1070- BasicContainer::Ptr parent = GetParent();
1071-
1072- while (parent)
1073- {
1074- if (!parent->parent_)
1075- return parent;
1076-
1077- parent = parent->GetParent();
1078- }
1079+ BasicContainer::Ptr parent = parent_;
1080+
1081+ while (parent && parent->parent_)
1082+ parent = parent->parent_;
1083
1084 return parent;
1085 }
1086
1087=== modified file 'launcher/LauncherEntryRemoteModel.h'
1088--- launcher/LauncherEntryRemoteModel.h 2012-05-07 19:52:54 +0000
1089+++ launcher/LauncherEntryRemoteModel.h 2015-02-19 19:24:14 +0000
1090@@ -22,7 +22,7 @@
1091
1092 #include <gio/gio.h>
1093 #include <sigc++/sigc++.h>
1094-#include <map>
1095+#include <unordered_map>
1096
1097 #include "LauncherEntryRemote.h"
1098
1099@@ -68,7 +68,7 @@
1100 glib::Object<GDBusConnection> _conn;
1101 unsigned int _launcher_entry_dbus_signal_id;
1102 unsigned int _dbus_name_owner_changed_signal_id;
1103- std::map<std::string, LauncherEntryRemote::Ptr> _entries_by_uri;
1104+ std::unordered_map<std::string, LauncherEntryRemote::Ptr> _entries_by_uri;
1105 };
1106
1107 } // namespace
1108
1109=== modified file 'lockscreen/LockScreenPanel.cpp'
1110--- lockscreen/LockScreenPanel.cpp 2014-09-19 18:22:14 +0000
1111+++ lockscreen/LockScreenPanel.cpp 2015-02-19 19:24:14 +0000
1112@@ -118,7 +118,7 @@
1113 if (entry->active())
1114 {
1115 active = true;
1116- indicators_view_->ActivateEntry(entry->id());
1117+ indicators_view_->ActivateEntry(entry);
1118 OnEntryActivated(GetPanelName(), entry->id(), entry->geometry());
1119 break;
1120 }
1121
1122=== modified file 'panel/PanelIndicatorEntryDropdownView.cpp'
1123--- panel/PanelIndicatorEntryDropdownView.cpp 2014-02-25 00:28:58 +0000
1124+++ panel/PanelIndicatorEntryDropdownView.cpp 2015-02-19 19:24:14 +0000
1125@@ -98,6 +98,11 @@
1126 return child;
1127 }
1128
1129+void PanelIndicatorEntryDropdownView::Clear()
1130+{
1131+ children_.clear();
1132+}
1133+
1134 std::deque<PanelIndicatorEntryView::Ptr> const& PanelIndicatorEntryDropdownView::Children() const
1135 {
1136 return children_;
1137@@ -144,7 +149,7 @@
1138 entries.push_back(entry->GetEntry());
1139
1140 auto const& geo = GetAbsoluteGeometry();
1141- indicators_->ShowEntriesDropdown(entries, active_entry_, 0, geo.x, geo.y + geo.height);
1142+ indicators_->ShowEntriesDropdown(entries, active_entry_, entries[0]->parent_window(), geo.x, geo.y + geo.height);
1143 }
1144
1145 bool PanelIndicatorEntryDropdownView::ActivateChild(PanelIndicatorEntryView::Ptr const& child)
1146
1147=== modified file 'panel/PanelIndicatorEntryDropdownView.h'
1148--- panel/PanelIndicatorEntryDropdownView.h 2014-02-07 23:29:46 +0000
1149+++ panel/PanelIndicatorEntryDropdownView.h 2015-02-19 19:24:14 +0000
1150@@ -39,6 +39,7 @@
1151 void Insert(PanelIndicatorEntryView::Ptr const&);
1152 void Remove(PanelIndicatorEntryView::Ptr const&);
1153 PanelIndicatorEntryView::Ptr Pop();
1154+ void Clear();
1155
1156 PanelIndicatorEntryView::Ptr Top() const;
1157 std::deque<PanelIndicatorEntryView::Ptr> const& Children() const;
1158
1159=== modified file 'panel/PanelIndicatorEntryView.cpp'
1160--- panel/PanelIndicatorEntryView.cpp 2014-08-07 13:15:17 +0000
1161+++ panel/PanelIndicatorEntryView.cpp 2015-02-19 19:24:14 +0000
1162@@ -59,6 +59,7 @@
1163 , cv_(unity::Settings::Instance().em(monitor_))
1164 {
1165 proxy_->active_changed.connect(sigc::mem_fun(this, &PanelIndicatorEntryView::OnActiveChanged));
1166+ proxy_->show_now_changed.connect(sigc::mem_fun(&show_now_changed, &sigc::signal<void, bool>::emit));
1167 proxy_->updated.connect(sigc::mem_fun(this, &PanelIndicatorEntryView::Refresh));
1168
1169 InputArea::mouse_down.connect(sigc::mem_fun(this, &PanelIndicatorEntryView::OnMouseDown));
1170@@ -84,11 +85,6 @@
1171 Refresh();
1172 }
1173
1174-PanelIndicatorEntryView::~PanelIndicatorEntryView()
1175-{
1176- // Nothing to do...
1177-}
1178-
1179 void PanelIndicatorEntryView::OnActiveChanged(bool is_active)
1180 {
1181 active_changed.emit(this, is_active);
1182@@ -114,10 +110,16 @@
1183 });
1184
1185 wm.TerminateExpo();
1186+ return;
1187 }
1188
1189 if (wm.IsScaleActive())
1190+ {
1191+ if (type_ == MENU)
1192+ return;
1193+
1194 wm.TerminateScale();
1195+ }
1196
1197 auto const& abs_geo = GetAbsoluteGeometry();
1198 proxy_->ShowMenu(abs_geo.x, abs_geo.y + abs_geo.height, button);
1199
1200=== modified file 'panel/PanelIndicatorEntryView.h'
1201--- panel/PanelIndicatorEntryView.h 2014-03-31 21:08:10 +0000
1202+++ panel/PanelIndicatorEntryView.h 2015-02-19 19:24:14 +0000
1203@@ -53,10 +53,8 @@
1204 PanelIndicatorEntryView(indicator::Entry::Ptr const& proxy, int padding = 5,
1205 IndicatorEntryType type = INDICATOR);
1206
1207- virtual ~PanelIndicatorEntryView();
1208-
1209 IndicatorEntryType GetType() const;
1210- indicator::Entry::Ptr GetEntry() const { return proxy_; }
1211+ indicator::Entry::Ptr const& GetEntry() const { return proxy_; }
1212 std::string GetEntryID() const;
1213 int GetEntryPriority() const;
1214
1215@@ -93,6 +91,7 @@
1216
1217 sigc::signal<void, PanelIndicatorEntryView*, bool> active_changed;
1218 sigc::signal<void, PanelIndicatorEntryView*> refreshed;
1219+ sigc::signal<void, bool> show_now_changed;
1220
1221 protected:
1222 std::string GetName() const;
1223
1224=== modified file 'panel/PanelIndicatorsView.cpp'
1225--- panel/PanelIndicatorsView.cpp 2014-03-06 09:26:03 +0000
1226+++ panel/PanelIndicatorsView.cpp 2015-02-19 19:24:14 +0000
1227@@ -71,7 +71,7 @@
1228 indicators_.push_back(indicator);
1229
1230 for (auto const& entry : indicator->GetEntries())
1231- AddEntry(entry);
1232+ OnEntryAdded(entry);
1233
1234 auto& conn_manager = indicators_connections_[indicator];
1235 conn_manager.Add(indicator->on_entry_added.connect(sigc::mem_fun(this, &PanelIndicatorsView::OnEntryAdded)));
1236@@ -83,7 +83,7 @@
1237 indicators_connections_.erase(indicator);
1238
1239 for (auto const& entry : indicator->GetEntries())
1240- RemoveEntry(entry->id());
1241+ RemoveEntry(entry);
1242
1243 for (auto i = indicators_.begin(); i != indicators_.end(); ++i)
1244 {
1245@@ -158,13 +158,13 @@
1246 }
1247 }
1248
1249-PanelIndicatorEntryView* PanelIndicatorsView::ActivateEntry(std::string const& entry_id, int button)
1250+PanelIndicatorEntryView* PanelIndicatorsView::ActivateEntry(indicator::Entry::Ptr const& entry, int button)
1251 {
1252- auto entry = entries_.find(entry_id);
1253+ auto it = entries_.find(entry);
1254
1255- if (entry != entries_.end())
1256+ if (it != entries_.end())
1257 {
1258- PanelIndicatorEntryView* view = entry->second;
1259+ PanelIndicatorEntryView* view = it->second;
1260
1261 if (view->IsSensitive() && view->IsVisible())
1262 {
1263@@ -181,6 +181,17 @@
1264 return nullptr;
1265 }
1266
1267+PanelIndicatorEntryView* PanelIndicatorsView::ActivateEntry(std::string const& entry_id, int button)
1268+{
1269+ for (auto const& it : entries_)
1270+ {
1271+ if (it.first->id() == entry_id)
1272+ return ActivateEntry(it.first, button);
1273+ }
1274+
1275+ return nullptr;
1276+}
1277+
1278 bool PanelIndicatorsView::ActivateIfSensitive()
1279 {
1280 for (auto* area : layout_->GetChildren())
1281@@ -222,7 +233,7 @@
1282 if (!view->IsVisible())
1283 continue;
1284
1285- if (!target && view->IsFocused() &&
1286+ if (!target &&
1287 view->IsSensitive() &&
1288 view->GetAbsoluteGeometry().IsPointInside(x, y))
1289 {
1290@@ -267,9 +278,8 @@
1291 if (!view)
1292 return;
1293
1294- auto const& entry_id = view->GetEntryID();
1295 bool added_to_dropdown = false;
1296- bool known_entry = (entries_.find(entry_id) != entries_.end());
1297+ bool known_entry = (entries_.find(view->GetEntry()) != entries_.end());
1298 view->SetOpacity(opacity());
1299
1300 if (!known_entry && dropdown_ && !dropdown_->Empty())
1301@@ -317,7 +327,7 @@
1302 {
1303 view->SetMonitor(monitor_);
1304 view->refreshed.connect(sigc::mem_fun(this, &PanelIndicatorsView::OnEntryRefreshed));
1305- entries_.insert({entry_id, view});
1306+ entries_.insert({view->GetEntry(), view});
1307 on_indicator_updated.emit();
1308 entry_added.emit(view);
1309 }
1310@@ -346,6 +356,23 @@
1311 on_indicator_updated.emit();
1312 }
1313
1314+void PanelIndicatorsView::ClearEntries()
1315+{
1316+ for (auto it = entries_.begin(); it != entries_.end();)
1317+ {
1318+ auto* entry = it->second;
1319+ ++it;
1320+
1321+ if (entry != dropdown_.GetPointer())
1322+ RemoveEntryView(entry);
1323+ }
1324+
1325+ on_indicator_updated.emit();
1326+
1327+ QueueRelayout();
1328+ QueueDraw();
1329+}
1330+
1331 void PanelIndicatorsView::RemoveEntryView(PanelIndicatorEntryView* view)
1332 {
1333 if (!view)
1334@@ -357,7 +384,7 @@
1335 dropdown_->Remove(PanelIndicatorEntryView::Ptr(view));
1336
1337 RemoveChild(view);
1338- entries_.erase(view->GetEntryID());
1339+ entries_.erase(view->GetEntry());
1340 layout_->RemoveChildObject(view);
1341 on_indicator_updated.emit();
1342
1343@@ -365,9 +392,12 @@
1344 QueueDraw();
1345 }
1346
1347-void PanelIndicatorsView::RemoveEntry(std::string const& entry_id)
1348+void PanelIndicatorsView::RemoveEntry(indicator::Entry::Ptr const& entry)
1349 {
1350- RemoveEntryView(entries_[entry_id]);
1351+ auto it = entries_.find(entry);
1352+
1353+ if (it != entries_.end())
1354+ RemoveEntryView(it->second);
1355 }
1356
1357 void PanelIndicatorsView::OverlayShown()
1358
1359=== modified file 'panel/PanelIndicatorsView.h'
1360--- panel/PanelIndicatorsView.h 2014-03-06 09:26:03 +0000
1361+++ panel/PanelIndicatorsView.h 2015-02-19 19:24:14 +0000
1362@@ -55,9 +55,10 @@
1363 int padding = 5,
1364 IndicatorEntryPosition pos = AUTO,
1365 IndicatorEntryType type = IndicatorEntryType::INDICATOR);
1366- void RemoveEntry(std::string const& entry_id);
1367+ void RemoveEntry(indicator::Entry::Ptr const&);
1368
1369 PanelIndicatorEntryView* ActivateEntryAt(int x, int y, int button = 1);
1370+ PanelIndicatorEntryView* ActivateEntry(indicator::Entry::Ptr const&, int button = 1);
1371 PanelIndicatorEntryView* ActivateEntry(std::string const& entry_id, int button = 1);
1372 bool ActivateIfSensitive();
1373
1374@@ -84,18 +85,19 @@
1375 typedef std::vector<indicator::Indicator::Ptr> Indicators;
1376 Indicators const& GetIndicators() const;
1377
1378+ void ClearEntries();
1379+
1380 virtual void Draw(nux::GraphicsEngine& GfxContext, bool force_draw);
1381 virtual void DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw);
1382
1383- virtual void OnEntryAdded(indicator::Entry::Ptr const& entry);
1384+ virtual void OnEntryAdded(indicator::Entry::Ptr const&);
1385 virtual void OnEntryRefreshed(PanelIndicatorEntryView* view);
1386
1387 void AddEntryView(PanelIndicatorEntryView* view, IndicatorEntryPosition pos = AUTO);
1388 void RemoveEntryView(PanelIndicatorEntryView* view);
1389
1390 nux::HLayout* layout_;
1391- typedef std::map<std::string, PanelIndicatorEntryView*> Entries;
1392- Entries entries_;
1393+ std::unordered_map<indicator::Entry::Ptr, PanelIndicatorEntryView*> entries_;
1394
1395 int monitor_;
1396 bool overlay_showing_;
1397
1398=== modified file 'panel/PanelMenuView.cpp'
1399--- panel/PanelMenuView.cpp 2014-12-19 13:03:44 +0000
1400+++ panel/PanelMenuView.cpp 2015-02-19 19:24:14 +0000
1401@@ -27,6 +27,7 @@
1402 #include "unity-shared/CairoTexture.h"
1403 #include "unity-shared/DecorationStyle.h"
1404 #include "unity-shared/PanelStyle.h"
1405+#include "unity-shared/RawPixel.h"
1406 #include "unity-shared/UnitySettings.h"
1407 #include "unity-shared/UBusMessages.h"
1408 #include "unity-shared/UScreen.h"
1409@@ -43,15 +44,14 @@
1410
1411 namespace
1412 {
1413- const int MAIN_LEFT_PADDING = 4;
1414- const int TITLE_PADDING = 2;
1415- const int MENUBAR_PADDING = 4;
1416+ const RawPixel MAIN_LEFT_PADDING = 4_em;
1417+ const RawPixel TITLE_PADDING = 2_em;
1418+ const RawPixel MENUBAR_PADDING = 4_em;
1419 const int MENU_ENTRIES_PADDING = 6;
1420
1421 const std::string NEW_APP_HIDE_TIMEOUT = "new-app-hide-timeout";
1422 const std::string NEW_APP_SHOW_TIMEOUT = "new-app-show-timeout";
1423 const std::string WINDOW_MOVED_TIMEOUT = "window-moved-timeout";
1424- const std::string WINDOW_ACTIVATED_TIMEOUT = "window-activated-timeout";
1425 const std::string UPDATE_SHOW_NOW_TIMEOUT = "update-show-now-timeout";
1426 const std::string INTEGRATED_MENUS_DOUBLE_CLICK_TIMEOUT = "integrated-menus-double-click-timeout";
1427
1428@@ -83,7 +83,10 @@
1429 }
1430
1431 PanelMenuView::PanelMenuView(menu::Manager::Ptr const& menus)
1432- : menu_manager_(menus)
1433+ : active_window(0)
1434+ , maximized_window(0)
1435+ , focused(true)
1436+ , menu_manager_(menus)
1437 , matcher_(bamf_matcher_get_default())
1438 , is_inside_(false)
1439 , is_grabbed_(false)
1440@@ -100,16 +103,15 @@
1441 , ignore_menu_visibility_(false)
1442 , integrated_menus_(menu_manager_->integrated_menus())
1443 , always_show_menus_(menu_manager_->always_show_menus())
1444- , active_xid_(0)
1445 , desktop_name_(get_current_desktop())
1446 {
1447 BamfWindow* active_win = bamf_matcher_get_active_window(matcher_);
1448 if (BAMF_IS_WINDOW(active_win))
1449- active_xid_ = bamf_window_get_xid(active_win);
1450+ active_window = bamf_window_get_xid(active_win);
1451
1452- SetupPanelMenuViewSignals();
1453 SetupWindowButtons();
1454 SetupTitlebarGrabArea();
1455+ SetupPanelMenuViewSignals();
1456 SetupWindowManagerSignals();
1457 SetupUBusManagerInterests();
1458
1459@@ -128,8 +130,10 @@
1460 void PanelMenuView::OnStyleChanged()
1461 {
1462 int height = panel::Style::Instance().PanelHeight(monitor_);
1463+ double scale = Settings::Instance().em(monitor_)->DPIScale();
1464 window_buttons_->SetMinimumHeight(height);
1465 window_buttons_->SetMaximumHeight(height);
1466+ window_buttons_->SetLeftAndRightPadding(MAIN_LEFT_PADDING.CP(scale), MENUBAR_PADDING.CP(scale));
1467 window_buttons_->UpdateDPIChanged();
1468
1469 layout_->SetLeftAndRightPadding(window_buttons_->GetContentWidth(), 0);
1470@@ -157,6 +161,20 @@
1471
1472 menu_manager_->integrated_menus.changed.connect(sigc::mem_fun(this, &PanelMenuView::OnLIMChanged));
1473 menu_manager_->always_show_menus.changed.connect(sigc::mem_fun(this, &PanelMenuView::OnAlwaysShowMenusChanged));
1474+
1475+ auto update_target_cb = sigc::hide(sigc::mem_fun(this, &PanelMenuView::UpdateTargetWindowItems));
1476+ maximized_window.changed.connect(update_target_cb);
1477+ active_window.changed.connect(update_target_cb);
1478+
1479+ focused.changed.connect([this] (bool focused) {
1480+ Refresh(true);
1481+ window_buttons_->focused = focused;
1482+
1483+ for (auto const& entry : entries_)
1484+ entry.second->SetFocusedState(focused);
1485+
1486+ FullRedraw();
1487+ });
1488 }
1489
1490 void PanelMenuView::SetupWindowButtons()
1491@@ -164,7 +182,7 @@
1492 window_buttons_ = new WindowButtons();
1493 window_buttons_->SetParentObject(this);
1494 window_buttons_->monitor = monitor_;
1495- window_buttons_->controlled_window = active_xid_;
1496+ window_buttons_->controlled_window = active_window();
1497 window_buttons_->opacity = 0.0f;
1498 window_buttons_->SetLeftAndRightPadding(MAIN_LEFT_PADDING, MENUBAR_PADDING);
1499 window_buttons_->SetMaximumHeight(panel::Style::Instance().PanelHeight(monitor_));
1500@@ -252,6 +270,27 @@
1501 PanelIndicatorsView::AddIndicator(indicator);
1502 }
1503
1504+void PanelMenuView::UpdateTargetWindowItems()
1505+{
1506+ Window old_target = window_buttons_->controlled_window;
1507+ Window target_window = integrated_menus_ ? maximized_window() : active_window();
1508+
1509+ if (old_target != target_window)
1510+ {
1511+ window_buttons_->controlled_window = target_window;
1512+ ClearEntries();
1513+
1514+ if (indicator::AppmenuIndicator::Ptr appmenu = menu_manager_->AppMenu())
1515+ {
1516+ for (auto const& entry : appmenu->GetEntriesForWindow(target_window))
1517+ OnEntryAdded(entry);
1518+ }
1519+ }
1520+
1521+ if (integrated_menus_)
1522+ focused = (target_window == active_window());
1523+}
1524+
1525 void PanelMenuView::FullRedraw()
1526 {
1527 QueueDraw();
1528@@ -266,9 +305,11 @@
1529 if (!integrated_menus_)
1530 {
1531 CheckMouseInside();
1532- window_buttons_->focused = true;
1533+ focused = true;
1534 }
1535
1536+ UpdateTargetWindowItems();
1537+
1538 Refresh(true);
1539 FullRedraw();
1540 }
1541@@ -302,7 +343,7 @@
1542 return titlebar_grab_area_.GetPointer();
1543 }
1544
1545- if (is_maximized_ || spread_showing_ || (integrated_menus_ && GetMaximizedWindow() != 0))
1546+ if (is_maximized_ || spread_showing_ || (integrated_menus_ && maximized_window() != 0))
1547 {
1548 found_area = window_buttons_->FindAreaUnderMouse(mouse_position, event_type);
1549 NUX_RETURN_VALUE_IF_NOTNULL(found_area, found_area);
1550@@ -313,7 +354,7 @@
1551 found_area = titlebar_grab_area_->FindAreaUnderMouse(mouse_position, event_type);
1552 NUX_RETURN_VALUE_IF_NOTNULL(found_area, found_area);
1553
1554- if (integrated_menus_ && GetMaximizedWindow() != 0)
1555+ if (integrated_menus_ && maximized_window() != 0)
1556 {
1557 /* When the integrated menus are enabled, that area must act both like an
1558 * indicator-entry view and like a panel-grab-area, so not to re-implement
1559@@ -382,10 +423,7 @@
1560
1561 bool PanelMenuView::ShouldDrawMenus() const
1562 {
1563- if (integrated_menus_ && !is_maximized_)
1564- return false;
1565-
1566- if (we_control_active_ && !switcher_showing_ && !launcher_keynav_ && !ignore_menu_visibility_ && !entries_.empty())
1567+ if ((we_control_active_ || integrated_menus_) && !switcher_showing_ && !launcher_keynav_ && !ignore_menu_visibility_ && HasVisibleMenus())
1568 {
1569 WindowManager& wm = WindowManager::Default();
1570
1571@@ -410,7 +448,7 @@
1572 if (integrated_menus_)
1573 {
1574 if (!WindowManager::Default().IsExpoActive())
1575- return (GetMaximizedWindow() != 0);
1576+ return (maximized_window() != 0);
1577
1578 return false;
1579 }
1580@@ -796,7 +834,7 @@
1581
1582 std::string PanelMenuView::GetMaximizedViewName(bool use_appname) const
1583 {
1584- Window maximized = GetMaximizedWindow();
1585+ Window maximized = maximized_window();
1586 BamfWindow* window = nullptr;
1587 std::string label;
1588
1589@@ -830,18 +868,18 @@
1590 auto const& style = decoration::Style::Get();
1591 auto text_size = style->TitleNaturalSize(label);
1592 auto state = WidgetState::NORMAL;
1593- float dpi_scale = Settings::Instance().em(monitor_)->DPIScale();
1594+ double dpi_scale = Settings::Instance().em(monitor_)->DPIScale();
1595
1596 if (integrated_menus_ && !is_desktop_focused_ && !WindowManager::Default().IsExpoActive())
1597 {
1598 title_geo_.x = geo.x + window_buttons_->GetBaseWidth() + (style->TitleIndent() * dpi_scale);
1599
1600- if (!window_buttons_->focused())
1601+ if (!focused())
1602 state = WidgetState::BACKDROP;
1603 }
1604 else
1605 {
1606- title_geo_.x = geo.x + (MAIN_LEFT_PADDING + TITLE_PADDING) * dpi_scale;
1607+ title_geo_.x = geo.x + MAIN_LEFT_PADDING.CP(dpi_scale) + TITLE_PADDING.CP(dpi_scale);
1608 }
1609
1610 title_geo_.y = geo.y + (geo.height - (text_size.height * dpi_scale)) / 2;
1611@@ -904,20 +942,9 @@
1612 if (geo.width > monitor_geo_.width)
1613 return false;
1614
1615- if (integrated_menus_)
1616- {
1617- Window maximized = GetMaximizedWindow();
1618- window_buttons_->controlled_window = maximized;
1619- window_buttons_->focused = (active_xid_ == maximized);
1620- }
1621- else
1622- {
1623- window_buttons_->controlled_window = active_xid_;
1624- }
1625-
1626 std::string const& new_title = GetCurrentTitle();
1627
1628- if (new_title == panel_title_ && !force && last_geo_ == geo && title_texture_)
1629+ if (!force && new_title == panel_title_ && last_geo_ == geo && title_texture_)
1630 {
1631 // No need to redraw the title, let's save some CPU time!
1632 return false;
1633@@ -956,18 +983,20 @@
1634
1635 void PanelMenuView::OnEntryAdded(indicator::Entry::Ptr const& entry)
1636 {
1637- PanelIndicatorEntryView* view;
1638+ auto parent_window = entry->parent_window();
1639+ Window target = integrated_menus_ ? maximized_window() : active_window();
1640
1641- view = new PanelIndicatorEntryView(entry, MENU_ENTRIES_PADDING, IndicatorEntryType::MENU);
1642- entry->show_now_changed.connect(sigc::mem_fun(this, &PanelMenuView::UpdateShowNow));
1643- AddEntryView(view);
1644+ if (!parent_window || parent_window == target)
1645+ AddEntryView(new PanelIndicatorEntryView(entry, MENU_ENTRIES_PADDING, IndicatorEntryType::MENU));
1646 }
1647
1648 void PanelMenuView::OnEntryViewAdded(PanelIndicatorEntryView* view)
1649 {
1650+ view->SetFocusedState(focused());
1651 view->mouse_enter.connect(sigc::mem_fun(this, &PanelMenuView::OnPanelViewMouseEnter));
1652 view->mouse_leave.connect(sigc::mem_fun(this, &PanelMenuView::OnPanelViewMouseLeave));
1653 view->active_changed.connect(sigc::mem_fun(this, &PanelMenuView::OnActiveChanged));
1654+ view->show_now_changed.connect(sigc::mem_fun(this, &PanelMenuView::UpdateShowNow));
1655 }
1656
1657 void PanelMenuView::NotifyAllMenusClosed()
1658@@ -1116,58 +1145,41 @@
1659 show_now_activated_ = false;
1660 is_maximized_ = false;
1661 is_desktop_focused_ = false;
1662- active_xid_ = 0;
1663- bool force_refresh = false;
1664+ Window active_xid = 0;
1665
1666 sources_.Remove(WINDOW_MOVED_TIMEOUT);
1667
1668 if (BAMF_IS_WINDOW(new_view))
1669 {
1670 BamfWindow* window = reinterpret_cast<BamfWindow*>(new_view);
1671- active_xid_ = bamf_window_get_xid(window);
1672+ active_xid = bamf_window_get_xid(window);
1673 is_maximized_ = (bamf_window_maximized(window) == BAMF_WINDOW_MAXIMIZED);
1674
1675 if (bamf_window_get_window_type(window) == BAMF_WINDOW_DESKTOP)
1676 {
1677- is_desktop_focused_ = !GetMaximizedWindow();
1678+ is_desktop_focused_ = !maximized_window();
1679 we_control_active_ = true;
1680 }
1681 else
1682 {
1683- we_control_active_ = IsWindowUnderOurControl(active_xid_);
1684+ we_control_active_ = IsWindowUnderOurControl(active_xid);
1685 }
1686
1687 if (is_maximized_)
1688 {
1689- maximized_wins_.erase(std::remove(maximized_wins_.begin(), maximized_wins_.end(), active_xid_), maximized_wins_.end());
1690- maximized_wins_.push_front(active_xid_);
1691+ maximized_wins_.erase(std::remove(maximized_wins_.begin(), maximized_wins_.end(), active_xid), maximized_wins_.end());
1692+ maximized_wins_.push_front(active_xid);
1693+ UpdateMaximizedWindow();
1694 }
1695
1696 // register callback for new view
1697 view_name_changed_signal_.Connect(new_view, "name-changed",
1698 sigc::mem_fun(this, &PanelMenuView::OnNameChanged));
1699-
1700- if (integrated_menus_)
1701- force_refresh = is_maximized_;
1702- }
1703-
1704- if (!force_refresh && BAMF_IS_WINDOW(old_view) && integrated_menus_)
1705- force_refresh = (bamf_window_maximized(reinterpret_cast<BamfWindow*>(old_view)) == BAMF_WINDOW_MAXIMIZED);
1706-
1707- if (ShouldDrawMenus())
1708- {
1709- // Wait 100ms before showing the menus again if we've just switched view
1710- // this is done because the menus are updated by the indicator with some
1711- // delay, and we don't want to see the previous menus and then the new ones
1712- ignore_menu_visibility_ = true;
1713- sources_.AddTimeout(100, [this] {
1714- ignore_menu_visibility_ = false;
1715- QueueDraw();
1716- return false;
1717- }, WINDOW_ACTIVATED_TIMEOUT);
1718- }
1719-
1720- if (Refresh(force_refresh))
1721+ }
1722+
1723+ active_window = active_xid;
1724+
1725+ if (Refresh())
1726 FullRedraw();
1727 }
1728
1729@@ -1198,8 +1210,9 @@
1730 void PanelMenuView::OnWindowMinimized(Window xid)
1731 {
1732 maximized_wins_.erase(std::remove(maximized_wins_.begin(), maximized_wins_.end(), xid), maximized_wins_.end());
1733+ UpdateMaximizedWindow();
1734
1735- if (xid == active_xid_)
1736+ if (xid == active_window())
1737 {
1738 if (Refresh())
1739 QueueDraw();
1740@@ -1213,10 +1226,13 @@
1741
1742 void PanelMenuView::OnWindowUnminimized(Window xid)
1743 {
1744- if (xid == active_xid_)
1745+ if (xid == active_window())
1746 {
1747 if (WindowManager::Default().IsWindowMaximized(xid))
1748+ {
1749 maximized_wins_.push_front(xid);
1750+ UpdateMaximizedWindow();
1751+ }
1752
1753 if (Refresh())
1754 QueueDraw();
1755@@ -1224,7 +1240,10 @@
1756 else
1757 {
1758 if (WindowManager::Default().IsWindowMaximized(xid))
1759+ {
1760 maximized_wins_.push_back(xid);
1761+ UpdateMaximizedWindow();
1762+ }
1763
1764 if (integrated_menus_ && IsWindowUnderOurControl(xid))
1765 {
1766@@ -1239,8 +1258,9 @@
1767 // FIXME: compiz doesn't give us a valid xid (is always 0 on unmap)
1768 // we need to do this again on BamfView closed signal.
1769 maximized_wins_.erase(std::remove(maximized_wins_.begin(), maximized_wins_.end(), xid), maximized_wins_.end());
1770+ UpdateMaximizedWindow();
1771
1772- if (xid == active_xid_)
1773+ if (xid == active_window())
1774 {
1775 if (Refresh())
1776 QueueDraw();
1777@@ -1256,9 +1276,10 @@
1778 {
1779 if (WindowManager::Default().IsWindowMaximized(xid))
1780 {
1781- if (xid == active_xid_)
1782+ if (xid == active_window())
1783 {
1784 maximized_wins_.push_front(xid);
1785+ UpdateMaximizedWindow();
1786
1787 if (Refresh())
1788 QueueDraw();
1789@@ -1266,15 +1287,17 @@
1790 else
1791 {
1792 maximized_wins_.push_back(xid);
1793+ UpdateMaximizedWindow();
1794 }
1795 }
1796 }
1797
1798 void PanelMenuView::OnWindowMaximized(Window xid)
1799 {
1800- if (xid == active_xid_)
1801+ if (xid == active_window())
1802 {
1803 maximized_wins_.push_front(xid);
1804+ UpdateMaximizedWindow();
1805
1806 // We need to update the is_inside_ state in the case of maximization by grab
1807 CheckMouseInside();
1808@@ -1286,6 +1309,7 @@
1809 else
1810 {
1811 maximized_wins_.push_back(xid);
1812+ UpdateMaximizedWindow();
1813
1814 if (integrated_menus_ && IsWindowUnderOurControl(xid))
1815 {
1816@@ -1298,8 +1322,9 @@
1817 void PanelMenuView::OnWindowRestored(Window xid)
1818 {
1819 maximized_wins_.erase(std::remove(maximized_wins_.begin(), maximized_wins_.end(), xid), maximized_wins_.end());
1820+ UpdateMaximizedWindow();
1821
1822- if (active_xid_ == xid)
1823+ if (active_window() == xid)
1824 {
1825 is_maximized_ = false;
1826 is_grabbed_ = false;
1827@@ -1316,13 +1341,13 @@
1828
1829 bool PanelMenuView::UpdateActiveWindowPosition()
1830 {
1831- bool we_control_window = IsWindowUnderOurControl(active_xid_);
1832+ bool we_control_window = IsWindowUnderOurControl(active_window);
1833
1834 if (we_control_window != we_control_active_)
1835 {
1836 we_control_active_ = we_control_window;
1837
1838- if (!entries_.empty())
1839+ if (HasVisibleMenus())
1840 on_indicator_updated.emit();
1841
1842 if (Refresh())
1843@@ -1334,21 +1359,17 @@
1844
1845 void PanelMenuView::OnWindowMoved(Window xid)
1846 {
1847- if (active_xid_ == xid)
1848+ if (!integrated_menus_ && active_window() == xid && UScreen::GetDefault()->GetMonitors().size() > 1)
1849 {
1850 /* When moving the active window, if the current panel is controlling
1851 * the active window, then we postpone the timeout function every movement
1852 * that we have, setting a longer timeout.
1853- * Otherwise, if the moved window is not controlled by the current panel
1854+ * Otherwise, if the movedPanelMenuView::OnWindowMovedPanelMenuView::OnWindowMoved window is not controlled by the current panel
1855 * every few millisecond we check the new window position */
1856
1857 unsigned int timeout_length = 250;
1858
1859- if (we_control_active_)
1860- {
1861- sources_.Remove(WINDOW_MOVED_TIMEOUT);
1862- }
1863- else
1864+ if (!we_control_active_)
1865 {
1866 if (sources_.GetSource(WINDOW_MOVED_TIMEOUT))
1867 return;
1868@@ -1359,6 +1380,9 @@
1869 auto cb_func = sigc::mem_fun(this, &PanelMenuView::UpdateActiveWindowPosition);
1870 sources_.AddTimeout(timeout_length, cb_func, WINDOW_MOVED_TIMEOUT);
1871 }
1872+
1873+ if (std::find(maximized_wins_.begin(), maximized_wins_.end(), xid) != maximized_wins_.end())
1874+ UpdateMaximizedWindow();
1875 }
1876
1877 bool PanelMenuView::IsWindowUnderOurControl(Window xid) const
1878@@ -1391,7 +1415,7 @@
1879 return false;
1880 }
1881
1882-Window PanelMenuView::GetMaximizedWindow() const
1883+void PanelMenuView::UpdateMaximizedWindow()
1884 {
1885 Window window_xid = 0;
1886
1887@@ -1406,7 +1430,7 @@
1888 }
1889 }
1890
1891- return window_xid;
1892+ maximized_window = window_xid;
1893 }
1894
1895 Window PanelMenuView::GetTopWindow() const
1896@@ -1466,11 +1490,14 @@
1897 if (!layout_->GetAbsoluteGeometry().IsInside(click))
1898 return;
1899
1900- unsigned double_click_wait = Settings::Instance().lim_double_click_wait();
1901-
1902- if (double_click_wait > 0)
1903+ auto& settings = Settings::Instance();
1904+
1905+ if (!focused && !settings.lim_unfocused_popup())
1906+ return;
1907+
1908+ if (settings.lim_double_click_wait() > 0)
1909 {
1910- sources_.AddTimeout(double_click_wait, [this, click] {
1911+ sources_.AddTimeout(settings.lim_double_click_wait(), [this, click] {
1912 ActivateEntryAt(click.x, click.y);
1913 return false;
1914 }, INTEGRATED_MENUS_DOUBLE_CLICK_TIMEOUT);
1915@@ -1489,15 +1516,18 @@
1916
1917 void PanelMenuView::OnMaximizedActivate(int x, int y)
1918 {
1919- Window maximized = GetMaximizedWindow();
1920+ Window maximized = maximized_window();
1921
1922 if (maximized != 0)
1923 {
1924- if (maximized != active_xid_)
1925+ if (maximized != active_window())
1926 {
1927- WindowManager::Default().Activate(maximized);
1928+ auto& wm = WindowManager::Default();
1929+ wm.Raise(maximized);
1930+ wm.Activate(maximized);
1931 }
1932- else if (integrated_menus_)
1933+
1934+ if (integrated_menus_)
1935 {
1936 // Adjusting the click coordinates to be absolute.
1937 auto const& grab_geo = titlebar_grab_area_->GetAbsoluteGeometry();
1938@@ -1509,7 +1539,7 @@
1939
1940 void PanelMenuView::MaximizedWindowWMAction(int x, int y, unsigned button)
1941 {
1942- Window maximized = GetMaximizedWindow();
1943+ Window maximized = maximized_window();
1944
1945 if (!maximized)
1946 return;
1947@@ -1590,7 +1620,7 @@
1948 * This is a workaround to avoid that the grid plugin would be fired
1949 * showing the window shape preview effect. See bug #838923 */
1950
1951- Window maximized = GetMaximizedWindow();
1952+ Window maximized = maximized_window();
1953
1954 if (maximized != 0)
1955 {
1956@@ -1611,7 +1641,7 @@
1957 x += titlebar_grab_area_->GetAbsoluteX();
1958 y += titlebar_grab_area_->GetAbsoluteY();
1959
1960- Window maximized = GetMaximizedWindow();
1961+ Window maximized = maximized_window();
1962
1963 /* When the drag goes out from the Panel, start the real movement.
1964 *
1965@@ -1686,6 +1716,8 @@
1966 PanelIndicatorsView::AddProperties(introspection);
1967
1968 introspection
1969+ .add("focused", focused())
1970+ .add("integrated_menus", integrated_menus_)
1971 .add("mouse_inside", is_inside_)
1972 .add("always_show_menus", always_show_menus_)
1973 .add("grabbed", is_grabbed_)
1974@@ -1694,7 +1726,8 @@
1975 .add("panel_title", panel_title_)
1976 .add("desktop_active", (panel_title_ == desktop_name_))
1977 .add("monitor", monitor_)
1978- .add("active_window", active_xid_)
1979+ .add("active_window", active_window())
1980+ .add("maximized_window", maximized_window())
1981 .add("draw_menus", ShouldDrawMenus())
1982 .add("draw_window_buttons", ShouldDrawButtons())
1983 .add("controls_active_window", we_control_active_)
1984@@ -1833,32 +1866,19 @@
1985 auto xid = bamf_window_get_xid(window);
1986
1987 if (bamf_view_is_active(view))
1988- active_xid_ = xid;
1989+ active_window = xid;
1990
1991 if (bamf_window_maximized(window) == BAMF_WINDOW_MAXIMIZED)
1992 {
1993- if (xid == active_xid_)
1994+ if (xid == active_window())
1995 maximized_wins_.push_front(xid);
1996 else
1997 maximized_wins_.push_back(xid);
1998 }
1999 }
2000
2001- Window maximized = GetMaximizedWindow();
2002- Window buttons_win = 0;
2003-
2004- if (integrated_menus_)
2005- {
2006- buttons_win = maximized;
2007- window_buttons_->focused = (maximized == active_xid_);
2008- }
2009- else
2010- {
2011- buttons_win = (maximized == active_xid_) ? maximized : 0;
2012- }
2013-
2014 window_buttons_->monitor = monitor_;
2015- window_buttons_->controlled_window = buttons_win;
2016+ UpdateMaximizedWindow();
2017
2018 OnStyleChanged();
2019 g_list_free(windows);
2020@@ -1866,7 +1886,15 @@
2021
2022 bool PanelMenuView::HasMenus() const
2023 {
2024- if (entries_.empty())
2025+ if (!HasVisibleMenus())
2026+ return false;
2027+
2028+ return integrated_menus_ || we_control_active_;
2029+}
2030+
2031+bool PanelMenuView::HasKeyActivableMenus() const
2032+{
2033+ if (!HasVisibleMenus())
2034 return false;
2035
2036 return integrated_menus_ ? is_maximized_ : we_control_active_;
2037
2038=== modified file 'panel/PanelMenuView.h'
2039--- panel/PanelMenuView.h 2014-12-19 12:09:16 +0000
2040+++ panel/PanelMenuView.h 2015-02-19 19:24:14 +0000
2041@@ -44,13 +44,17 @@
2042 PanelMenuView(menu::Manager::Ptr const&);
2043 ~PanelMenuView();
2044
2045+ nux::Property<Window> active_window;
2046+ nux::Property<Window> maximized_window;
2047+ nux::Property<bool> focused;
2048+
2049 void SetMousePosition(int x, int y);
2050 void SetMonitor(int monitor) override;
2051
2052 Window GetTopWindow() const;
2053- Window GetMaximizedWindow() const;
2054 bool GetControlsActive() const;
2055 bool HasMenus() const;
2056+ bool HasKeyActivableMenus() const;
2057
2058 void NotifyAllMenusClosed();
2059
2060@@ -120,9 +124,9 @@
2061 bool Refresh(bool force = false);
2062
2063 void UpdateTitleTexture(nux::Geometry const&, std::string const& label);
2064-
2065 void UpdateLastGeometry(nux::Geometry const& geo);
2066 void UpdateTitleGradientTexture();
2067+ void UpdateMaximizedWindow();
2068
2069 void OnPanelViewMouseEnter(int x, int y, unsigned long mouse_button_state, unsigned long special_keys_state);
2070 void OnPanelViewMouseLeave(int x, int y, unsigned long mouse_button_state, unsigned long special_keys_state);
2071@@ -134,6 +138,7 @@
2072 void OnLauncherKeyNavEnded(GVariant* data);
2073 void OnLauncherSelectionChanged(GVariant* data);
2074
2075+ void UpdateTargetWindowItems();
2076 void UpdateShowNow(bool ignore);
2077 bool CheckMouseInside();
2078
2079@@ -158,7 +163,7 @@
2080
2081 void ActivateIntegratedMenus(nux::Point const&);
2082
2083- menu::Manager::Ptr const& menu_manager_;
2084+ menu::Manager::Ptr menu_manager_;
2085 glib::Object<BamfMatcher> matcher_;
2086
2087 nux::TextureLayer* title_layer_;
2088@@ -190,7 +195,6 @@
2089 bool integrated_menus_;
2090 bool always_show_menus_;
2091
2092- Window active_xid_;
2093 nux::Geometry monitor_geo_;
2094 const std::string desktop_name_;
2095
2096
2097=== modified file 'panel/PanelView.cpp'
2098--- panel/PanelView.cpp 2014-12-12 22:33:24 +0000
2099+++ panel/PanelView.cpp 2015-02-19 19:24:14 +0000
2100@@ -516,7 +516,7 @@
2101
2102 if (opacity_maximized_toggle_)
2103 {
2104- Window maximized_win = menu_view_->GetMaximizedWindow();
2105+ Window maximized_win = menu_view_->maximized_window();
2106
2107 if (wm.IsExpoActive() || (maximized_win != 0 && !wm.IsWindowObscured(maximized_win)))
2108 opacity = 1.0f;
2109@@ -673,7 +673,7 @@
2110 if (!IsActive())
2111 return false;
2112
2113- if ((menu_view_->HasMenus() && menu_view_->ActivateIfSensitive()) ||
2114+ if ((menu_view_->HasKeyActivableMenus() && menu_view_->ActivateIfSensitive()) ||
2115 indicators_->ActivateIfSensitive())
2116 {
2117 // Since this only happens on keyboard events, we need to prevent that the
2118@@ -690,7 +690,7 @@
2119 if (!IsActive())
2120 return false;
2121
2122- if ((menu_view_->HasMenus() && menu_view_->ActivateEntry(entry_id, 0)) ||
2123+ if ((menu_view_->HasKeyActivableMenus() && menu_view_->ActivateEntry(entry_id, 0)) ||
2124 indicators_->ActivateEntry(entry_id, 0))
2125 {
2126 // Since this only happens on keyboard events, we need to prevent that the
2127
2128=== modified file 'plugins/unityshell/src/unityshell.cpp'
2129--- plugins/unityshell/src/unityshell.cpp 2015-01-22 22:37:32 +0000
2130+++ plugins/unityshell/src/unityshell.cpp 2015-02-19 19:24:14 +0000
2131@@ -157,6 +157,7 @@
2132 , cScreen(CompositeScreen::get(screen))
2133 , gScreen(GLScreen::get(screen))
2134 , sScreen(ScaleScreen::get(screen))
2135+ , WM(PluginAdapter::Initialize(screen))
2136 , menus_(std::make_shared<menu::Manager>(std::make_shared<indicator::DBusIndicators>(), std::make_shared<key::GnomeGrabber>()))
2137 , deco_manager_(std::make_shared<decoration::Manager>(menus_))
2138 , debugger_(this)
2139@@ -281,9 +282,6 @@
2140 ScaleScreenInterface::setHandler(sScreen);
2141 screen->updateSupportedWmHints();
2142
2143- PluginAdapter::Initialize(screen);
2144- AddChild(&WindowManager::Default());
2145-
2146 nux::NuxInitialize(0);
2147 #ifndef USE_GLES
2148 wt.reset(nux::CreateFromForeignWindow(cScreen->output(),
2149@@ -442,13 +440,13 @@
2150 sigc::mem_fun(this, &UnityScreen::OnMinimizeDurationChanged)
2151 );
2152
2153- WindowManager& wm = WindowManager::Default();
2154- wm.initiate_spread.connect(sigc::mem_fun(this, &UnityScreen::OnInitiateSpread));
2155- wm.terminate_spread.connect(sigc::mem_fun(this, &UnityScreen::OnTerminateSpread));
2156- wm.initiate_expo.connect(sigc::mem_fun(this, &UnityScreen::DamagePanelShadow));
2157- wm.terminate_expo.connect(sigc::mem_fun(this, &UnityScreen::DamagePanelShadow));
2158+ WM.initiate_spread.connect(sigc::mem_fun(this, &UnityScreen::OnInitiateSpread));
2159+ WM.terminate_spread.connect(sigc::mem_fun(this, &UnityScreen::OnTerminateSpread));
2160+ WM.initiate_expo.connect(sigc::mem_fun(this, &UnityScreen::DamagePanelShadow));
2161+ WM.terminate_expo.connect(sigc::mem_fun(this, &UnityScreen::DamagePanelShadow));
2162
2163- AddChild(&screen_introspection_);
2164+ Introspectable::AddChild(&WM);
2165+ Introspectable::AddChild(&screen_introspection_);
2166
2167 /* Create blur backup texture */
2168 auto gpu_device = nux::GetGraphicsDisplay()->GetGpuDevice();
2169@@ -687,7 +685,7 @@
2170 if (sources_.GetSource(local::RELAYOUT_TIMEOUT))
2171 return;
2172
2173- if (WindowManager::Default().IsExpoActive())
2174+ if (WM.IsExpoActive())
2175 return;
2176
2177 CompOutput* output = _last_output;
2178@@ -948,7 +946,7 @@
2179 nux::TexCoordXForm texxform;
2180 texxform.SetWrap(nux::TEXWRAP_REPEAT, nux::TEXWRAP_CLAMP);
2181
2182- int monitor = WindowManager::Default().MonitorGeometryIn(NuxGeometryFromCompRect(output_dev));
2183+ int monitor = WM.MonitorGeometryIn(NuxGeometryFromCompRect(output_dev));
2184 auto const& texture = panel_style_.GetBackground(monitor)->GetDeviceTexture();
2185 graphics_engine->QRP_GLSL_1Tex(0, 0, output_dev.width(), texture->GetHeight(), texture, texxform, nux::color::White);
2186 }
2187@@ -961,7 +959,7 @@
2188 hud_controller_->IsVisible() ||
2189 session_controller_->Visible() ||
2190 ((switcher_controller_->Visible() ||
2191- WindowManager::Default().IsExpoActive())
2192+ WM.IsExpoActive())
2193 && !fullscreen_windows_.empty () && (!(screen->grabbed () && !screen->otherGrabExist (NULL))));
2194 }
2195
2196@@ -2219,7 +2217,7 @@
2197 CompAction::State state,
2198 CompOption::Vector& options)
2199 {
2200- WindowManager::Default().ShowDesktop();
2201+ WM.ShowDesktop();
2202 return true;
2203 }
2204
2205@@ -2323,7 +2321,7 @@
2206 CompAction::State state,
2207 CompOption::Vector& options)
2208 {
2209- if (WindowManager::Default().IsWallActive())
2210+ if (WM.IsWallActive())
2211 return false;
2212 else if (switcher_controller_->Visible())
2213 switcher_controller_->Next();
2214@@ -2531,11 +2529,9 @@
2215 if (QuicklistManager::Default()->Current())
2216 QuicklistManager::Default()->Current()->Hide();
2217
2218- auto& wm = WindowManager::Default();
2219-
2220- if (wm.IsScreenGrabbed())
2221+ if (WM.IsScreenGrabbed())
2222 {
2223- hud_ungrab_slot_ = wm.screen_ungrabbed.connect([this] { ShowHud(); });
2224+ hud_ungrab_slot_ = WM.screen_ungrabbed.connect([this] { ShowHud(); });
2225
2226 // Let's wait ungrab event for maximum a couple of seconds...
2227 sources_.AddTimeoutSeconds(2, [this] {
2228@@ -2664,7 +2660,7 @@
2229 KeySym keysym = XkbKeycodeToKeysym(screen->dpy(), keybind.keycode(), 0, 0);
2230 unsigned modifiers = CompizModifiersToNux(keybind.modifiers());
2231
2232- WindowManager::Default().close_window_key = std::make_pair(modifiers, keysym);
2233+ WM.close_window_key = std::make_pair(modifiers, keysym);
2234 }
2235
2236 void UnityScreen::UpdateActivateIndicatorsKey()
2237@@ -2673,7 +2669,7 @@
2238 KeySym keysym = XkbKeycodeToKeysym(screen->dpy(), keybind.keycode(), 0, 0);
2239 unsigned modifiers = CompizModifiersToNux(keybind.modifiers());
2240
2241- WindowManager::Default().activate_indicators_key = std::make_pair(modifiers, keysym);
2242+ WM.activate_indicators_key = std::make_pair(modifiers, keysym);
2243 }
2244
2245 bool UnityScreen::initPluginActions()
2246@@ -2926,7 +2922,7 @@
2247 }
2248 }
2249
2250- if (WindowManager::Default().IsScaleActive() &&
2251+ if (uScreen->WM.IsScaleActive() &&
2252 uScreen->sScreen->getSelectedWindow() == window->id())
2253 {
2254 nux::Geometry const& scaled_geo = GetScaledGeometry();
2255@@ -3027,9 +3023,8 @@
2256 !(window_state & CompWindowStateFullscreenMask) &&
2257 !(window_type & CompWindowTypeFullscreenMask))
2258 {
2259- WindowManager& wm = WindowManager::Default();
2260 auto const& output = uScreen->screen->currentOutputDev();
2261- int monitor = wm.MonitorGeometryIn(NuxGeometryFromCompRect(output));
2262+ int monitor = uScreen->WM.MonitorGeometryIn(NuxGeometryFromCompRect(output));
2263
2264 if (window->y() - window->border().top < output.y() + uScreen->panel_style_.PanelHeight(monitor))
2265 {
2266@@ -3662,8 +3657,7 @@
2267 {
2268 if (strcmp(name, "hsize") == 0 || strcmp(name, "vsize") == 0)
2269 {
2270- WindowManager& wm = WindowManager::Default();
2271- wm.viewport_layout_changed.emit(screen->vpSize().width(), screen->vpSize().height());
2272+ WM.viewport_layout_changed.emit(screen->vpSize().width(), screen->vpSize().height());
2273 }
2274 else if (strcmp(name, "close_window_key") == 0)
2275 {
2276@@ -3779,13 +3773,11 @@
2277 if (QuicklistManager::Default()->Current())
2278 QuicklistManager::Default()->Current()->Hide();
2279
2280- auto& wm = WindowManager::Default();
2281-
2282- if (wm.IsScaleActive())
2283- wm.TerminateScale();
2284-
2285- if (wm.IsExpoActive())
2286- wm.TerminateExpo();
2287+ if (WM.IsScaleActive())
2288+ WM.TerminateScale();
2289+
2290+ if (WM.IsExpoActive())
2291+ WM.TerminateExpo();
2292
2293 RaiseOSK();
2294 }
2295@@ -3889,24 +3881,24 @@
2296 edge_barriers_ = std::make_shared<ui::EdgeBarrierController>();
2297
2298 launcher_controller_ = std::make_shared<launcher::Controller>(xdnd_manager, edge_barriers_);
2299- AddChild(launcher_controller_.get());
2300+ Introspectable::AddChild(launcher_controller_.get());
2301
2302 switcher_controller_ = std::make_shared<switcher::Controller>();
2303 switcher_controller_->detail.changed.connect(sigc::mem_fun(this, &UnityScreen::OnSwitcherDetailChanged));
2304- AddChild(switcher_controller_.get());
2305+ Introspectable::AddChild(switcher_controller_.get());
2306
2307 LOG_INFO(logger) << "initLauncher-Launcher " << timer.ElapsedSeconds() << "s";
2308
2309 /* Setup panel */
2310 timer.Reset();
2311 panel_controller_ = std::make_shared<panel::Controller>(menus_, edge_barriers_);
2312- AddChild(panel_controller_.get());
2313+ Introspectable::AddChild(panel_controller_.get());
2314 LOG_INFO(logger) << "initLauncher-Panel " << timer.ElapsedSeconds() << "s";
2315
2316 /* Setup Places */
2317 dash_controller_ = std::make_shared<dash::Controller>();
2318 dash_controller_->on_realize.connect(sigc::mem_fun(this, &UnityScreen::OnDashRealized));
2319- AddChild(dash_controller_.get());
2320+ Introspectable::AddChild(dash_controller_.get());
2321
2322 /* Setup Hud */
2323 hud_controller_ = std::make_shared<hud::Controller>();
2324@@ -3915,14 +3907,14 @@
2325 hud_controller_->multiple_launchers = (optionGetNumLaunchers() == 0);
2326 hud_controller_->icon_size = launcher_controller_->options()->icon_size();
2327 hud_controller_->tile_size = launcher_controller_->options()->tile_size();
2328- AddChild(hud_controller_.get());
2329+ Introspectable::AddChild(hud_controller_.get());
2330 LOG_INFO(logger) << "initLauncher-hud " << timer.ElapsedSeconds() << "s";
2331
2332 // Setup Shortcut Hint
2333 auto base_window_raiser = std::make_shared<shortcut::BaseWindowRaiserImp>();
2334 auto shortcuts_modeller = std::make_shared<shortcut::CompizModeller>();
2335 shortcut_controller_ = std::make_shared<shortcut::Controller>(base_window_raiser, shortcuts_modeller);
2336- AddChild(shortcut_controller_.get());
2337+ Introspectable::AddChild(shortcut_controller_.get());
2338 ShowFirstRunHints();
2339
2340 // Setup Session Controller
2341@@ -3933,7 +3925,7 @@
2342 manager->unlocked.connect(sigc::mem_fun(this, &UnityScreen::OnScreenUnlocked));
2343 session_dbus_manager_ = std::make_shared<session::DBusManager>(manager);
2344 session_controller_ = std::make_shared<session::Controller>(manager);
2345- AddChild(session_controller_.get());
2346+ Introspectable::AddChild(session_controller_.get());
2347
2348 // Setup Lockscreen Controller
2349 screensaver_dbus_manager_ = std::make_shared<lockscreen::DBusManager>(manager);
2350@@ -4119,7 +4111,7 @@
2351 window->minimizedSetEnabled (this, false);
2352 }
2353
2354- /* Keep this after the optionGetShowMinimizedWindows branch */
2355+ /* Keep this after the optionGetShowMIntrospectable.hinimizedWindows branch */
2356
2357 if (window->state() & CompWindowStateFullscreenMask)
2358 uScreen->fullscreen_windows_.push_back(window);
2359@@ -4136,8 +4128,8 @@
2360 {
2361 Window xid = window->id();
2362 auto const& swins = uScreen->sScreen->getWindows();
2363+ WindowManager& wm = uScreen->WM;
2364 bool scaled = std::find(swins.begin(), swins.end(), ScaleWindow::get(window)) != swins.end();
2365- WindowManager& wm = WindowManager::Default();
2366
2367 introspection
2368 .add(scaled ? GetScaledGeometry() : wm.GetWindowGeometry(xid))
2369@@ -4373,9 +4365,7 @@
2370
2371 nux::Geometry UnityWindow::GetScaledGeometry()
2372 {
2373- WindowManager& wm = WindowManager::Default();
2374-
2375- if (!wm.IsScaleActive())
2376+ if (!uScreen->WM.IsScaleActive())
2377 return nux::Geometry();
2378
2379 ScaleWindow* scale_win = ScaleWindow::get(window);
2380
2381=== modified file 'plugins/unityshell/src/unityshell.h'
2382--- plugins/unityshell/src/unityshell.h 2014-12-12 20:44:52 +0000
2383+++ plugins/unityshell/src/unityshell.h 2015-02-19 19:24:14 +0000
2384@@ -332,6 +332,7 @@
2385
2386 /* The window thread should be the last thing removed, as c++ does it in reverse order */
2387 std::unique_ptr<nux::WindowThread> wt;
2388+ WindowManager& WM;
2389
2390 menu::Manager::Ptr menus_;
2391 std::shared_ptr<decoration::Manager> deco_manager_;
2392@@ -368,7 +369,7 @@
2393 typedef std::vector<CompActionPtr> ShortcutActions;
2394 ShortcutActions _shortcut_actions;
2395 std::map<CancelActionTarget, CompActionPtr> _escape_actions;
2396- std::map<int, unsigned int> windows_for_monitor_;
2397+ std::unordered_map<int, unsigned int> windows_for_monitor_;
2398
2399 /* keyboard-nav mode */
2400 CompWindow* newFocusedWindow;
2401
2402=== modified file 'services/panel-main.c'
2403--- services/panel-main.c 2014-11-04 14:25:04 +0000
2404+++ services/panel-main.c 2015-02-19 19:24:14 +0000
2405@@ -27,20 +27,21 @@
2406 #include "config.h"
2407 #include "panel-a11y.h"
2408 #include "panel-service.h"
2409+#include "panel-service-private.h"
2410
2411 static GDBusNodeInfo *introspection_data = NULL;
2412
2413 static const gchar introspection_xml[] =
2414 "<node>"
2415- " <interface name='com.canonical.Unity.Panel.Service'>"
2416+ " <interface name='"UPS_IFACE"'>"
2417 ""
2418 " <method name='Sync'>"
2419- " <arg type='a(ssssbbusbbi)' name='state' direction='out'/>"
2420+ " <arg type='"ENTRY_ARRAY_SIGNATURE"' name='state' direction='out'/>"
2421 " </method>"
2422 ""
2423 " <method name='SyncOne'>"
2424 " <arg type='s' name='indicator_id' direction='in'/>"
2425- " <arg type='a(ssssbbusbbi)' name='state' direction='out'/>"
2426+ " <arg type='"ENTRY_ARRAY_SIGNATURE"' name='state' direction='out'/>"
2427 " </method>"
2428 ""
2429 " <method name='SyncGeometries'>"
2430@@ -110,10 +111,6 @@
2431 " </interface>"
2432 "</node>";
2433
2434-#define S_NAME_DESKTOP "com.canonical.Unity.Panel.Service.Desktop"
2435-#define S_NAME_LOCKSCREEN "com.canonical.Unity.Panel.Service.LockScreen"
2436-#define S_PATH "/com/canonical/Unity/Panel/Service"
2437-#define S_IFACE "com.canonical.Unity.Panel.Service"
2438
2439 /* Forwards */
2440 static void
2441@@ -271,8 +268,8 @@
2442 GError *error = NULL;
2443 g_dbus_connection_emit_signal (connection,
2444 NULL,
2445- S_PATH,
2446- S_IFACE,
2447+ UPS_PATH,
2448+ UPS_IFACE,
2449 "ReSync",
2450 g_variant_new ("(s)", indicator_id),
2451 &error);
2452@@ -293,10 +290,13 @@
2453 GError *error = NULL;
2454 g_dbus_connection_emit_signal (connection,
2455 NULL,
2456- S_PATH,
2457- S_IFACE,
2458+ UPS_PATH,
2459+ UPS_IFACE,
2460 "EntryActivated",
2461- g_variant_new ("(ss(iiuu))", panel_id, entry_id, x, y, w, h),
2462+ g_variant_new ("(ss(iiuu))",
2463+ panel_id ? panel_id : "",
2464+ entry_id ? entry_id : "",
2465+ x, y, w, h),
2466 &error);
2467
2468 if (error)
2469@@ -316,8 +316,8 @@
2470
2471 g_dbus_connection_emit_signal (connection,
2472 NULL,
2473- S_PATH,
2474- S_IFACE,
2475+ UPS_PATH,
2476+ UPS_IFACE,
2477 "EntryActivateRequest",
2478 g_variant_new ("(s)", entry_id),
2479 &error);
2480@@ -338,8 +338,8 @@
2481 GError *error = NULL;
2482 g_dbus_connection_emit_signal (connection,
2483 NULL,
2484- S_PATH,
2485- S_IFACE,
2486+ UPS_PATH,
2487+ UPS_IFACE,
2488 "EntryShowNowChanged",
2489 g_variant_new ("(sb)", entry_id, show_now_state),
2490 &error);
2491@@ -357,8 +357,8 @@
2492 GError *error = NULL;
2493 g_dbus_connection_emit_signal (connection,
2494 NULL,
2495- S_PATH,
2496- S_IFACE,
2497+ UPS_PATH,
2498+ UPS_IFACE,
2499 "IconPathsChanged",
2500 NULL,
2501 &error);
2502@@ -379,7 +379,7 @@
2503 guint reg_id;
2504
2505 reg_id = g_dbus_connection_register_object (connection,
2506- S_PATH,
2507+ UPS_PATH,
2508 introspection_data->interfaces[0],
2509 &interface_vtable,
2510 service,
2511@@ -485,7 +485,7 @@
2512 service = panel_service_get_default ();
2513
2514 owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
2515- !lockscreen_mode ? S_NAME_DESKTOP : S_NAME_LOCKSCREEN,
2516+ !lockscreen_mode ? UPS_NAME_DESKTOP : UPS_NAME_LOCKSCREEN,
2517 G_BUS_NAME_OWNER_FLAGS_NONE,
2518 on_bus_acquired,
2519 on_name_acquired,
2520
2521=== modified file 'services/panel-service-private.h'
2522--- services/panel-service-private.h 2013-10-03 15:15:35 +0000
2523+++ services/panel-service-private.h 2015-02-19 19:24:14 +0000
2524@@ -21,9 +21,27 @@
2525
2526 #include <X11/Xlib.h>
2527 #include <X11/keysym.h>
2528+#include <glib.h>
2529
2530 G_BEGIN_DECLS
2531
2532+#ifdef __cplusplus
2533+extern "C" {
2534+#endif
2535+
2536+#define UPS_NAME_DESKTOP "com.canonical.Unity.Panel.Service.Desktop"
2537+#define UPS_NAME_LOCKSCREEN "com.canonical.Unity.Panel.Service.LockScreen"
2538+#define UPS_PATH "/com/canonical/Unity/Panel/Service"
2539+#define UPS_IFACE "com.canonical.Unity.Panel.Service"
2540+
2541+#define APPMENU_INDICATOR_NAME "libappmenu.so"
2542+
2543+#define ENTRY_SIGNATURE "(sssusbbusbbi)"
2544+#define ENTRY_ARRAY_SIGNATURE "a" ENTRY_SIGNATURE ""
2545+
2546+#define AltMask Mod1Mask
2547+#define SuperMask Mod4Mask
2548+
2549 typedef struct _KeyBinding
2550 {
2551 KeySym key;
2552@@ -31,11 +49,12 @@
2553 guint32 modifiers;
2554 } KeyBinding;
2555
2556-#define AltMask Mod1Mask
2557-#define SuperMask Mod4Mask
2558-
2559 void parse_string_keybinding (const char *, KeyBinding *);
2560
2561+#ifdef __cplusplus
2562+}
2563+#endif
2564+
2565 G_END_DECLS
2566
2567 #endif /* _PANEL_SERVICE_PRIVATE_H_ */
2568
2569=== modified file 'services/panel-service.c'
2570--- services/panel-service.c 2014-11-28 12:55:58 +0000
2571+++ services/panel-service.c 2015-02-19 19:24:14 +0000
2572@@ -43,7 +43,7 @@
2573
2574 #define NOTIFY_TIMEOUT 80
2575 #define N_TIMEOUT_SLOTS 50
2576-#define MAX_INDICATOR_ENTRIES 100
2577+#define MAX_INDICATOR_ENTRIES 500
2578
2579 #define NUX_VERTICAL_SCROLL_DELTA 120
2580 #define NUX_HORIZONTAL_SCROLL_DELTA (NUX_VERTICAL_SCROLL_DELTA ^ 2)
2581@@ -61,10 +61,13 @@
2582 {
2583 GSList *indicators;
2584 GSList *dropdown_entries;
2585+ GSList *removed_entries;
2586 GHashTable *id2entry_hash;
2587 GHashTable *panel2entries_hash;
2588+ IndicatorObject *appmenu_indicator;
2589
2590- gint32 timeouts[N_TIMEOUT_SLOTS];
2591+ guint timeouts[N_TIMEOUT_SLOTS];
2592+ guint remove_idle;
2593
2594 IndicatorObjectEntry *last_entry;
2595 IndicatorObjectEntry *last_dropdown_entry;
2596@@ -104,14 +107,14 @@
2597
2598 enum
2599 {
2600- SYNC_WAITING = -1,
2601+ SYNC_WAITING = G_MAXUINT,
2602 SYNC_NEUTRAL = 0,
2603 };
2604
2605 static guint32 _service_signals[LAST_SIGNAL] = { 0 };
2606
2607 static const gchar * indicator_order[][2] = {
2608- {"libappmenu.so", NULL}, /* indicator-appmenu" */
2609+ {APPMENU_INDICATOR_NAME, NULL}, /* indicator-appmenu" */
2610 {"libapplication.so", NULL}, /* indicator-application" */
2611 {"floating-indicators", NULL}, /* position-less NG indicators */
2612 {"libprintersmenu.so", NULL}, /* indicator-printers */
2613@@ -136,6 +139,8 @@
2614 static void notify_object (IndicatorObject *object);
2615 static void update_keybinding (GSettings *, const gchar *, gpointer);
2616 static void emit_upstart_event (const gchar *);
2617+static gchar * get_indicator_entry_id_by_entry (IndicatorObjectEntry *entry);
2618+static IndicatorObjectEntry * get_indicator_entry_by_id (PanelService *self, const gchar *entry_id);
2619 static GdkFilterReturn event_filter (GdkXEvent *, GdkEvent *, PanelService *);
2620
2621 /*
2622@@ -164,7 +169,7 @@
2623
2624 for (i = 0; i < N_TIMEOUT_SLOTS; i++)
2625 {
2626- if (priv->timeouts[i] > 0)
2627+ if (priv->timeouts[i] > 0 && priv->timeouts[i] != SYNC_WAITING)
2628 {
2629 g_source_remove (priv->timeouts[i]);
2630 priv->timeouts[i] = 0;
2631@@ -265,9 +270,10 @@
2632 }
2633
2634 static gboolean
2635-is_point_in_rect (gint x, gint y, GdkRectangle* rect)
2636+rect_contains_point (GdkRectangle* rect, gint x, gint y)
2637 {
2638- g_return_val_if_fail (rect, FALSE);
2639+ if (!rect)
2640+ return FALSE;
2641
2642 return (x >= rect->x && x <= (rect->x + rect->width) &&
2643 y >= rect->y && y <= (rect->y + rect->height));
2644@@ -290,7 +296,7 @@
2645 IndicatorObjectEntry *entry = k;
2646 GdkRectangle *geo = v;
2647
2648- if (is_point_in_rect (x, y, geo))
2649+ if (rect_contains_point (geo, x, y))
2650 {
2651 return entry;
2652 }
2653@@ -321,8 +327,7 @@
2654 IndicatorObjectEntry *entry = key;
2655 GdkRectangle *geo = value;
2656
2657- if (x >= geo->x && x <= (geo->x + geo->width) &&
2658- y >= geo->y && y <= (geo->y + geo->height))
2659+ if (rect_contains_point (geo, x, y))
2660 {
2661 return entry;
2662 }
2663@@ -332,7 +337,7 @@
2664 }
2665
2666 static const gchar*
2667-get_panel_at (PanelService *self, gint x, gint y)
2668+get_panel_for_parent_at (PanelService *self, guint parent, gint x, gint y)
2669 {
2670 GHashTableIter panel_iter, entries_iter;
2671 gpointer key, value, k, v;
2672@@ -346,12 +351,20 @@
2673
2674 while (g_hash_table_iter_next (&entries_iter, &k, &v))
2675 {
2676+ IndicatorObjectEntry *entry = k;
2677 GdkRectangle *geo = v;
2678
2679- if (x >= geo->x && x <= (geo->x + geo->width) &&
2680- y >= geo->y && y <= (geo->y + geo->height))
2681+ /* The entry might be invalid at this point (as it could have been
2682+ * removed, but still not synced), so it's better to double check */
2683+ if (g_slist_find (self->priv->removed_entries, entry))
2684+ continue;
2685+
2686+ if (!parent || entry->parent_window == parent)
2687 {
2688- return panel_id;
2689+ if (rect_contains_point (geo, x, y))
2690+ {
2691+ return panel_id;
2692+ }
2693 }
2694 }
2695 }
2696@@ -414,7 +427,7 @@
2697 /* Unity might register some "fake" dropdown entries that it might use to
2698 * to present long menu bars (right now only for appmenu indicator) */
2699 entry = g_new0 (IndicatorObjectEntry, 1);
2700- entry->parent_object = panel_service_get_indicator (self, "libappmenu.so");
2701+ entry->parent_object = self->priv->appmenu_indicator;
2702 entry->name_hint = g_strdup (entry_id);
2703 self->priv->dropdown_entries = g_slist_append (self->priv->dropdown_entries, entry);
2704 g_hash_table_insert (self->priv->id2entry_hash, (gpointer)entry->name_hint, entry);
2705@@ -424,6 +437,21 @@
2706 }
2707
2708 static void
2709+ensure_entry_menu_is_closed (PanelService *self,
2710+ const gchar *panel_id,
2711+ IndicatorObjectEntry *entry)
2712+{
2713+ PanelServicePrivate *priv = self->priv;
2714+
2715+ /* If the entry has been removed let's make sure that its menu is closed */
2716+ if (GTK_IS_MENU (priv->last_menu) && priv->last_menu == entry->menu)
2717+ {
2718+ if (!priv->last_panel || !panel_id || g_strcmp0 (priv->last_panel, panel_id) == 0)
2719+ gtk_menu_popdown (entry->menu);
2720+ }
2721+}
2722+
2723+static void
2724 reinject_key_event_to_root_window (XIDeviceEvent *ev)
2725 {
2726 XKeyEvent kev;
2727@@ -609,9 +637,7 @@
2728 {
2729 /* Middle clicks over an appmenu entry are considered just like
2730 * all other clicks */
2731- IndicatorObject *obj = get_entry_parent_indicator (entry);
2732-
2733- if (g_strcmp0 (g_object_get_data (G_OBJECT (obj), "id"), "libappmenu.so") == 0)
2734+ if (get_entry_parent_indicator (entry) == priv->appmenu_indicator)
2735 {
2736 event_is_a_click = TRUE;
2737 }
2738@@ -677,7 +703,7 @@
2739 initial_resync (PanelService *self)
2740 {
2741 g_signal_emit (self, _service_signals[RE_SYNC], 0, "");
2742- return FALSE;
2743+ return G_SOURCE_REMOVE;
2744 }
2745
2746 static gboolean
2747@@ -686,7 +712,7 @@
2748 if (!lockscreen_mode)
2749 emit_upstart_event ("indicator-services-start");
2750
2751- return FALSE;
2752+ return G_SOURCE_REMOVE;
2753 }
2754
2755 static void
2756@@ -850,10 +876,10 @@
2757 if (self->priv->indicators == NULL)
2758 {
2759 g_signal_emit (self, _service_signals[INDICATORS_CLEARED], 0);
2760- return FALSE;
2761+ return G_SOURCE_REMOVE;
2762 }
2763
2764- return TRUE;
2765+ return G_SOURCE_CONTINUE;
2766 }
2767
2768 static void
2769@@ -931,6 +957,9 @@
2770 g_object_ref_sink (G_OBJECT (indicator));
2771 }
2772
2773+ if (self->priv->appmenu_indicator == indicator)
2774+ self->priv->appmenu_indicator = NULL;
2775+
2776 g_object_unref (G_OBJECT (indicator));
2777 }
2778
2779@@ -1145,7 +1174,7 @@
2780 g_signal_emit (self, _service_signals[RE_SYNC],
2781 0, g_object_get_data (G_OBJECT (object), "id"));
2782
2783- return FALSE;
2784+ return G_SOURCE_REMOVE;
2785 }
2786
2787 static void
2788@@ -1204,6 +1233,7 @@
2789 g_return_if_fail (PANEL_IS_SERVICE (self));
2790 g_return_if_fail (entry != NULL);
2791
2792+ self->priv->removed_entries = g_slist_remove (self->priv->removed_entries, entry);
2793 gchar *entry_id = get_indicator_entry_id_by_entry (entry);
2794 g_hash_table_insert (self->priv->id2entry_hash, entry_id, entry);
2795
2796@@ -1243,6 +1273,42 @@
2797 notify_object (object);
2798 }
2799
2800+static gboolean
2801+on_removed_idle (PanelService *self)
2802+{
2803+ GHashTableIter iter;
2804+ GHashTable *entry2geometry_hash;
2805+ IndicatorObjectEntry *entry;
2806+ gpointer value;
2807+ GSList *l;
2808+
2809+ for (l = self->priv->removed_entries; l; l = l->next)
2810+ {
2811+ entry = l->data;
2812+ ensure_entry_menu_is_closed (self, NULL, entry);
2813+
2814+ g_hash_table_iter_init (&iter, self->priv->panel2entries_hash);
2815+ while (g_hash_table_iter_next (&iter, NULL, &value))
2816+ {
2817+ if ((entry2geometry_hash = value))
2818+ {
2819+ g_hash_table_remove (entry2geometry_hash, entry);
2820+
2821+ if (g_hash_table_size (entry2geometry_hash) == 0)
2822+ {
2823+ g_hash_table_iter_remove (&iter);
2824+ }
2825+ }
2826+ }
2827+
2828+ }
2829+
2830+ g_slist_free (self->priv->removed_entries);
2831+ self->priv->removed_entries = NULL;
2832+
2833+ return G_SOURCE_REMOVE;
2834+}
2835+
2836 static void
2837 on_entry_removed (IndicatorObject *object,
2838 IndicatorObjectEntry *entry,
2839@@ -1251,11 +1317,6 @@
2840 g_return_if_fail (PANEL_IS_SERVICE (self));
2841 g_return_if_fail (entry != NULL);
2842
2843- /* Don't remove here the value from panel2entries_hash, this should be
2844- * done during the geometries sync, to avoid false positive.
2845- * FIXME this in libappmenu.so to avoid to send an "entry-removed" signal
2846- * when switching the focus from a window to one of its dialog children */
2847-
2848 gchar *entry_id = get_indicator_entry_id_by_entry (entry);
2849 g_hash_table_remove (self->priv->id2entry_hash, entry_id);
2850 g_free (entry_id);
2851@@ -1270,6 +1331,13 @@
2852 g_signal_handlers_disconnect_by_data (entry->image, object);
2853 }
2854
2855+ self->priv->removed_entries = g_slist_append (self->priv->removed_entries, entry);
2856+
2857+ if (self->priv->remove_idle)
2858+ g_source_remove (self->priv->remove_idle);
2859+
2860+ self->priv->remove_idle = g_idle_add ((GSourceFunc) on_removed_idle, self);
2861+
2862 notify_object (object);
2863 }
2864
2865@@ -1327,6 +1395,7 @@
2866 "unity",
2867 "unity-3d",
2868 "unity-panel-service",
2869+ "unity-all-menus",
2870 NULL
2871 };
2872
2873@@ -1346,6 +1415,9 @@
2874
2875 priv->indicators = g_slist_append (priv->indicators, object);
2876
2877+ if (!priv->appmenu_indicator && g_strcmp0 (name, APPMENU_INDICATOR_NAME) == 0)
2878+ priv->appmenu_indicator = object;
2879+
2880 g_object_set_data_full (G_OBJECT (object), "id", g_strdup (name), g_free);
2881
2882 g_signal_connect (object, INDICATOR_OBJECT_SIGNAL_ENTRY_ADDED,
2883@@ -1607,10 +1679,11 @@
2884 guint32 image_type = 0;
2885 gchar *image_data = gtk_image_to_data (entry->image, &image_type);
2886
2887- g_variant_builder_add (b, "(ssssbbusbbi)",
2888+ g_variant_builder_add (b, ENTRY_SIGNATURE,
2889 indicator_id,
2890 id,
2891 entry->name_hint ? entry->name_hint : "",
2892+ entry->parent_window,
2893 is_label ? gtk_label_get_label (entry->label) : "",
2894 is_label ? gtk_widget_get_sensitive (GTK_WIDGET (entry->label)) : FALSE,
2895 is_label ? gtk_widget_get_visible (GTK_WIDGET (entry->label)) : FALSE,
2896@@ -1627,14 +1700,15 @@
2897 indicator_entry_null_to_variant (const gchar *indicator_id,
2898 GVariantBuilder *b)
2899 {
2900- g_variant_builder_add (b, "(ssssbbusbbi)",
2901+ g_variant_builder_add (b, ENTRY_SIGNATURE,
2902 indicator_id,
2903 "",
2904 "",
2905+ 0,
2906 "",
2907 FALSE,
2908 FALSE,
2909- (guint32) 0,
2910+ 0,
2911 "",
2912 FALSE,
2913 FALSE,
2914@@ -1642,15 +1716,20 @@
2915 }
2916
2917 static void
2918-indicator_object_full_to_variant (IndicatorObject *object, const gchar *indicator_id, GVariantBuilder *b)
2919+indicator_object_full_to_variant (PanelService *self, IndicatorObject *object,
2920+ const gchar *indicator_id, GVariantBuilder *b)
2921 {
2922 GList *entries, *e;
2923+ GHashTable *index_hash = NULL;
2924 gint parent_prio = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (object), "priority"));
2925 entries = indicator_object_get_entries (object);
2926- gint index = 0;
2927+ guint index = 0;
2928
2929 if (entries)
2930 {
2931+ if (object == self->priv->appmenu_indicator)
2932+ index_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
2933+
2934 for (e = entries; e; e = e->next)
2935 {
2936 gint prio = -1;
2937@@ -1664,14 +1743,29 @@
2938
2939 if (prio < 0)
2940 {
2941+ if (index_hash)
2942+ {
2943+ index = GPOINTER_TO_UINT (g_hash_table_lookup (index_hash,
2944+ GUINT_TO_POINTER (entry->parent_window)));
2945+ }
2946+
2947 prio = parent_prio + index;
2948 index++;
2949+
2950+ if (index_hash)
2951+ {
2952+ g_hash_table_insert (index_hash, GUINT_TO_POINTER (entry->parent_window),
2953+ GUINT_TO_POINTER (index));
2954+ }
2955 }
2956
2957 indicator_entry_to_variant (entry, id, indicator_id, b, prio);
2958 g_free (id);
2959 }
2960
2961+ if (index_hash)
2962+ g_hash_table_destroy (index_hash);
2963+
2964 g_list_free (entries);
2965 }
2966 else
2967@@ -1682,15 +1776,15 @@
2968 }
2969
2970 static void
2971-indicator_object_to_variant (IndicatorObject *object, const gchar *indicator_id, GVariantBuilder *b)
2972+indicator_object_to_variant (PanelService *self, IndicatorObject *object,
2973+ const gchar *indicator_id, GVariantBuilder *b)
2974 {
2975 if (!GPOINTER_TO_INT (g_object_get_data (G_OBJECT (object), "remove")))
2976 {
2977- indicator_object_full_to_variant (object, indicator_id, b);
2978+ indicator_object_full_to_variant (self, object, indicator_id, b);
2979 }
2980 else
2981 {
2982- PanelService *self = panel_service_get_default ();
2983 indicator_entry_null_to_variant (indicator_id, b);
2984 panel_service_actually_remove_indicator (self, object);
2985 }
2986@@ -1718,7 +1812,7 @@
2987 rect.height *= scale;
2988 }
2989
2990- if (is_point_in_rect (x, y, &rect))
2991+ if (rect_contains_point (&rect, x, y))
2992 {
2993 return i;
2994 }
2995@@ -1790,8 +1884,8 @@
2996 GSList *i;
2997 gint position;
2998
2999- g_variant_builder_init (&b, G_VARIANT_TYPE ("(a(ssssbbusbbi))"));
3000- g_variant_builder_open (&b, G_VARIANT_TYPE ("a(ssssbbusbbi)"));
3001+ g_variant_builder_init (&b, G_VARIANT_TYPE ("("ENTRY_ARRAY_SIGNATURE")"));
3002+ g_variant_builder_open (&b, G_VARIANT_TYPE (ENTRY_ARRAY_SIGNATURE));
3003
3004 for (i = self->priv->indicators; i;)
3005 {
3006@@ -1801,7 +1895,7 @@
3007
3008 const gchar *indicator_id = g_object_get_data (G_OBJECT (indicator), "id");
3009 position = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (indicator), "position"));
3010- indicator_object_to_variant (indicator, indicator_id, &b);
3011+ indicator_object_to_variant (self, indicator, indicator_id, &b);
3012
3013 /* Set the sync back to neutral */
3014 self->priv->timeouts[position] = SYNC_NEUTRAL;
3015@@ -1817,8 +1911,8 @@
3016 GVariantBuilder b;
3017 GSList *i;
3018
3019- g_variant_builder_init (&b, G_VARIANT_TYPE ("(a(ssssbbusbbi))"));
3020- g_variant_builder_open (&b, G_VARIANT_TYPE ("a(ssssbbusbbi)"));
3021+ g_variant_builder_init (&b, G_VARIANT_TYPE ("("ENTRY_ARRAY_SIGNATURE")"));
3022+ g_variant_builder_open (&b, G_VARIANT_TYPE (ENTRY_ARRAY_SIGNATURE));
3023
3024 for (i = self->priv->indicators; i; i = i->next)
3025 {
3026@@ -1826,7 +1920,7 @@
3027 g_object_get_data (G_OBJECT (i->data), "id")) == 0)
3028 {
3029 gint position = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (i->data), "position"));
3030- indicator_object_to_variant (i->data, indicator_id, &b);
3031+ indicator_object_to_variant (self, i->data, indicator_id, &b);
3032
3033 /* Set the sync back to neutral */
3034 self->priv->timeouts[position] = SYNC_NEUTRAL;
3035@@ -1850,6 +1944,7 @@
3036 {
3037 IndicatorObject *object;
3038 IndicatorObjectEntry *entry;
3039+ GHashTable *entry2geometry_hash;
3040 gboolean valid_entry = TRUE;
3041 PanelServicePrivate *priv = self->priv;
3042
3043@@ -1870,24 +1965,18 @@
3044
3045 if (entry)
3046 {
3047- GHashTable *entry2geometry_hash = g_hash_table_lookup (priv->panel2entries_hash, panel_id);
3048+ entry2geometry_hash = g_hash_table_lookup (priv->panel2entries_hash, panel_id);
3049
3050 if (width < 0 || height < 0 || !valid_entry)
3051 {
3052- /* If the entry has been removed let's make sure that its menu is closed */
3053- if (valid_entry && GTK_IS_MENU (priv->last_menu) && priv->last_menu == entry->menu)
3054- {
3055- if (!priv->last_panel || g_strcmp0 (priv->last_panel, panel_id) == 0)
3056- gtk_menu_popdown (entry->menu);
3057- }
3058+ if (valid_entry)
3059+ ensure_entry_menu_is_closed (self, panel_id, entry);
3060
3061 if (entry2geometry_hash)
3062 {
3063- if (g_hash_table_size (entry2geometry_hash) > 1)
3064- {
3065- g_hash_table_remove (entry2geometry_hash, entry);
3066- }
3067- else
3068+ g_hash_table_remove (entry2geometry_hash, entry);
3069+
3070+ if (g_hash_table_size (entry2geometry_hash) == 0)
3071 {
3072 g_hash_table_remove (priv->panel2entries_hash, panel_id);
3073 }
3074@@ -2256,7 +2345,7 @@
3075 priv->last_x = x;
3076 priv->last_y = y;
3077 priv->last_menu_button = button;
3078- priv->last_panel = get_panel_at (self, x, y);
3079+ priv->last_panel = get_panel_for_parent_at (self, xid, x, y);
3080
3081 g_signal_connect (priv->last_menu, "hide", G_CALLBACK (on_active_menu_hidden), self);
3082 g_signal_connect_after (priv->last_menu, "move-current",
3083@@ -2462,10 +2551,9 @@
3084 GList *entries;
3085
3086 g_return_if_fail (PANEL_IS_SERVICE (self));
3087-
3088- object = panel_service_get_indicator (self, "libappmenu.so");
3089- g_return_if_fail (INDICATOR_IS_OBJECT (object));
3090-
3091+ g_return_if_fail (INDICATOR_IS_OBJECT (self->priv->appmenu_indicator));
3092+
3093+ object = self->priv->appmenu_indicator;
3094 entries = indicator_object_get_entries (object);
3095
3096 if (entries)
3097
3098=== modified file 'services/panel-service.h'
3099--- services/panel-service.h 2014-09-19 18:38:21 +0000
3100+++ services/panel-service.h 2015-02-19 19:24:14 +0000
3101@@ -56,14 +56,6 @@
3102 struct _PanelServiceClass
3103 {
3104 GObjectClass parent_class;
3105-
3106- /*< private >*/
3107- void (*_view_padding1) (void);
3108- void (*_view_padding2) (void);
3109- void (*_view_padding3) (void);
3110- void (*_view_padding4) (void);
3111- void (*_view_padding5) (void);
3112- void (*_view_padding6) (void);
3113 };
3114
3115 GType panel_service_get_type (void) G_GNUC_CONST;
3116
3117=== modified file 'shortcuts/ShortcutModel.h'
3118--- shortcuts/ShortcutModel.h 2013-01-19 00:25:07 +0000
3119+++ shortcuts/ShortcutModel.h 2015-02-19 19:24:14 +0000
3120@@ -21,7 +21,7 @@
3121 #define UNITYSHELL_SHORTCUS_MODEL_H
3122
3123 #include <boost/noncopyable.hpp>
3124-#include <map>
3125+#include <unordered_map>
3126 #include <memory>
3127 #include <list>
3128 #include <string>
3129@@ -43,7 +43,7 @@
3130
3131 nux::Property<int> categories_per_column;
3132 std::vector<std::string> const& categories() const { return categories_; }
3133- std::map<std::string, std::list<AbstractHint::Ptr>> const& hints() const { return hints_; }
3134+ std::unordered_map<std::string, std::list<AbstractHint::Ptr>> const& hints() const { return hints_; }
3135
3136 void Fill();
3137
3138@@ -51,7 +51,7 @@
3139 void AddHint(AbstractHint::Ptr const& hint);
3140
3141 std::vector<std::string> categories_;
3142- std::map<std::string, std::list<AbstractHint::Ptr>> hints_;
3143+ std::unordered_map<std::string, std::list<AbstractHint::Ptr>> hints_;
3144 };
3145
3146 }
3147
3148=== modified file 'tests/autopilot/unity/emulators/panel.py'
3149--- tests/autopilot/unity/emulators/panel.py 2013-05-10 05:16:07 +0000
3150+++ tests/autopilot/unity/emulators/panel.py 2015-02-19 19:24:14 +0000
3151@@ -159,6 +159,10 @@
3152 return self.menus.panel_title
3153
3154 @property
3155+ def focused(self):
3156+ return self.menus.focused
3157+
3158+ @property
3159 def desktop_is_active(self):
3160 return self.menus.desktop_active
3161
3162
3163=== modified file 'tests/autopilot/unity/tests/__init__.py'
3164--- tests/autopilot/unity/tests/__init__.py 2014-02-12 20:43:54 +0000
3165+++ tests/autopilot/unity/tests/__init__.py 2015-02-19 19:24:14 +0000
3166@@ -48,7 +48,7 @@
3167 from Xlib import display
3168 from Xlib import Xutil
3169
3170-from gi.repository import Gio
3171+from gi.repository import GLib, Gio
3172
3173 log = getLogger(__name__)
3174
3175@@ -256,20 +256,19 @@
3176 atom_type = display.Display().intern_atom('CARDINAL')
3177 return bamf_window.x_win.get_property(atom, atom_type, 0, 1024).value[0]
3178
3179- def call_gsettings_cmd(self, command, schema, *args):
3180+ def call_gsettings_cmd(self, command, schema, key, value=None):
3181 """Set a desktop wide gsettings option
3182-
3183- Using the gsettings command because there is a bug with importing
3184- from gobject introspection and pygtk2 simultaneously, and the Xlib
3185- keyboard layout bits are very unwieldy. This seems like the best
3186- solution, even a little bit brutish.
3187 """
3188- cmd = ['gsettings', command, schema] + list(args)
3189- # strip to remove the trailing \n.
3190- ret = check_output(cmd).strip()
3191- time.sleep(5)
3192- reset_display()
3193- return ret
3194+ settings = Gio.Settings.new(schema)
3195+
3196+ if command == "get":
3197+ return settings.get_value(key).print_(type_annotate=False)
3198+ elif command == "set":
3199+ settings.set_value(key, GLib.Variant.parse(type=None, text=value))
3200+ settings.apply()
3201+ reset_display()
3202+ elif command == "reset":
3203+ settings.reset(key)
3204
3205 def set_unity_option(self, option_name, option_value):
3206 """Set an option in the unity compiz plugin options.
3207
3208=== modified file 'tests/autopilot/unity/tests/test_dash.py'
3209--- tests/autopilot/unity/tests/test_dash.py 2014-02-28 19:53:07 +0000
3210+++ tests/autopilot/unity/tests/test_dash.py 2015-02-19 19:24:14 +0000
3211@@ -164,7 +164,7 @@
3212
3213 self.assertProperty(char_win, is_active=True)
3214
3215- def test_dash_does_not_open_when_fullscreen_window(self):
3216+ def test_dash_opens_when_fullscreen_window(self):
3217 """ The Dash must not open if a window is fullscreen. """
3218 gedit = self.process_manager.start_app("Text Editor")
3219 self.keyboard.press_and_release('F11')
3220@@ -175,7 +175,7 @@
3221 self.keybinding("dash/reveal")
3222 self.addCleanup(self.unity.dash.ensure_hidden)
3223
3224- self.assertThat(self.unity.dash.visible, Eventually(Equals(False)))
3225+ self.assertThat(self.unity.dash.visible, Eventually(Equals(True)))
3226
3227
3228 class DashRevealWithSpreadTests(DashTestCase):
3229
3230=== modified file 'tests/autopilot/unity/tests/test_hud.py'
3231--- tests/autopilot/unity/tests/test_hud.py 2014-02-28 19:53:07 +0000
3232+++ tests/autopilot/unity/tests/test_hud.py 2015-02-19 19:24:14 +0000
3233@@ -512,7 +512,7 @@
3234 self.keyboard.type("e")
3235 self.assertThat(self.unity.hud.view.selected_button, Eventually(Equals(1)))
3236
3237- def test_hud_does_not_open_when_fullscreen_window(self):
3238+ def test_hud_opens_when_fullscreen_window(self):
3239 """ The Hud must not open if a window is fullscreen. """
3240 gedit = self.process_manager.start_app("Text Editor")
3241 self.keyboard.press_and_release('F11')
3242@@ -523,7 +523,7 @@
3243 self.keybinding("hud/reveal")
3244 self.addCleanup(self.unity.hud.ensure_hidden)
3245
3246- self.assertThat(self.unity.hud.visible, Eventually(Equals(False)))
3247+ self.assertThat(self.unity.hud.visible, Eventually(Equals(True)))
3248
3249
3250 class HudLauncherInteractionsTests(HudTestsBase):
3251
3252=== modified file 'tests/autopilot/unity/tests/test_panel.py'
3253--- tests/autopilot/unity/tests/test_panel.py 2014-03-04 15:30:06 +0000
3254+++ tests/autopilot/unity/tests/test_panel.py 2015-02-19 19:24:14 +0000
3255@@ -12,6 +12,7 @@
3256 #from autopilot.emulators.bamf import BamfWindow
3257 from autopilot.process import Window
3258 from autopilot.matchers import Eventually
3259+from autopilot.testcase import multiply_scenarios
3260 import logging
3261 import os
3262 from testtools.matchers import Equals, GreaterThan, NotEquals
3263@@ -25,6 +26,13 @@
3264
3265 logger = logging.getLogger(__name__)
3266
3267+def _make_scenarios():
3268+ return multiply_scenarios(_make_monitor_scenarios(),
3269+ _make_menu_modes_scenarios())
3270+
3271+def _make_menu_modes_scenarios():
3272+ return [ ('Locally Integrated Menus', {'lim': True}),
3273+ ('Global Menus', {'lim': False}) ]
3274
3275 def _make_monitor_scenarios():
3276 num_monitors = Display.create().get_num_screens()
3277@@ -38,17 +46,41 @@
3278
3279 return scenarios
3280
3281-
3282 class PanelTestsBase(UnityTestCase):
3283
3284 panel_monitor = 0
3285+ lim = False
3286
3287 def setUp(self):
3288 super(PanelTestsBase, self).setUp()
3289 self.panel = self.unity.panels.get_panel_for_monitor(self.panel_monitor)
3290+
3291+ old_lim = self.call_gsettings_cmd('get', 'com.canonical.Unity', 'integrated-menus')
3292+ self.call_gsettings_cmd('set', 'com.canonical.Unity', 'integrated-menus', str(self.lim).lower())
3293+ self.addCleanup(self.call_gsettings_cmd, 'set', 'com.canonical.Unity', 'integrated-menus', old_lim)
3294+
3295+ old_showmenus = self.call_gsettings_cmd('get', 'com.canonical.Unity', 'always-show-menus')
3296+ self.call_gsettings_cmd('set', 'com.canonical.Unity', 'always-show-menus', 'false')
3297+ self.addCleanup(self.call_gsettings_cmd, 'set', 'com.canonical.Unity', 'always-show-menus', old_showmenus)
3298+
3299 self.panel.move_mouse_below_the_panel()
3300 self.addCleanup(self.panel.move_mouse_below_the_panel)
3301
3302+ self.assertThat(self.panel.menus.integrated_menus, Eventually(Equals(self.lim)))
3303+ if not self.lim:
3304+ self.assertThat(self.panel.focused, Eventually(Equals(True)))
3305+
3306+ def ensure_window_state(self, win, maximized=False):
3307+ if maximized and not win.is_maximized:
3308+ self.keybinding("window/maximize")
3309+ self.addCleanup(self.keybinding, "window/restore")
3310+ elif not maximized and win.is_maximized:
3311+ self.keybinding("window/restore")
3312+ self.addCleanup(self.keybinding, "window/maximize")
3313+
3314+ sleep(.25)
3315+ self.assertProperty(win, is_maximized=maximized)
3316+
3317 def open_new_application_window(self, app_name, maximized=False, move_to_monitor=True):
3318 """Opens a new instance of the requested application, ensuring that only
3319 one window is opened.
3320@@ -68,17 +100,8 @@
3321 if move_to_monitor:
3322 self.move_window_to_panel_monitor(app_win)
3323
3324- if maximized and not app_win.is_maximized:
3325- self.keybinding("window/maximize")
3326- self.addCleanup(self.keybinding, "window/restore")
3327- elif not maximized and app_win.is_maximized:
3328- self.keybinding("window/restore")
3329- self.addCleanup(self.keybinding, "window/maximize")
3330-
3331 app_win.set_focus()
3332- sleep(.25)
3333-
3334- self.assertThat(app_win.is_maximized, Equals(maximized))
3335+ self.ensure_window_state(app_win, maximized)
3336
3337 return app_win
3338
3339@@ -137,9 +160,10 @@
3340
3341 def sleep_menu_settle_period(self):
3342 """Sleep long enough for the menus to fade in and fade out again."""
3343- sleep(self.panel.menus.fadein_duration / 1000.0)
3344- sleep(self.panel.menus.discovery_duration)
3345- sleep(self.panel.menus.fadeout_duration / 1000.0)
3346+ if not self.lim:
3347+ sleep(self.panel.menus.fadein_duration / 1000.0)
3348+ sleep(self.panel.menus.discovery_duration)
3349+ sleep(self.panel.menus.fadeout_duration / 1000.0)
3350
3351 # Unable to exit SDM without any active apps, need a placeholder.
3352 # See bug LP:1079460
3353@@ -152,7 +176,7 @@
3354
3355 class PanelTitleTests(PanelTestsBase):
3356
3357- scenarios = _make_monitor_scenarios()
3358+ scenarios = _make_scenarios()
3359
3360 def setUp(self):
3361 super(PanelTitleTests, self).setUp()
3362@@ -174,13 +198,15 @@
3363 """Panel must display application name for a non-maximised application."""
3364 calc_win = self.open_new_application_window("Calculator", maximized=False)
3365
3366- self.assertThat(self.panel.title, Eventually(Equals(calc_win.application.name)))
3367+ expected = calc_win.application.name if not self.lim else ''
3368+ self.assertThat(self.panel.title, Eventually(Equals(expected)))
3369
3370 def test_panel_title_with_maximized_application(self):
3371 """Panel must display application name for a maximised application."""
3372 text_win = self.open_new_application_window("Text Editor", maximized=True)
3373
3374 self.assertThat(self.panel.title, Eventually(Equals(text_win.title)))
3375+ self.assertThat(self.panel.focused, Eventually(Equals(True)))
3376
3377 def test_panel_title_with_maximized_window_restored_child(self):
3378 """Tests the title shown in the panel when opening the restored child of
3379@@ -194,14 +220,18 @@
3380
3381 self.assertThat(lambda: len(text_win.application.get_windows()),
3382 Eventually(Equals(2)))
3383- self.assertThat(self.panel.title, Equals(text_win.application.name))
3384+ expected = text_win.application.name if not self.lim else text_win.title
3385+ self.assertThat(self.panel.title, Equals(expected))
3386+ self.assertThat(self.panel.focused, Eventually(Equals(not self.lim)))
3387
3388 def test_panel_shows_app_title_with_maximised_app(self):
3389 """Tests app titles are shown in the panel with a non-focused maximized application."""
3390- self.open_new_application_window("Text Editor", maximized=True)
3391+ text_win = self.open_new_application_window("Text Editor", maximized=True)
3392 calc_win = self.open_new_application_window("Calculator", maximized=False)
3393
3394- self.assertThat(self.panel.title, Eventually(Equals(calc_win.application.name)))
3395+ expected = calc_win.application.name if not self.lim else text_win.title
3396+ self.assertThat(self.panel.title, Eventually(Equals(expected)))
3397+ self.assertThat(self.panel.focused, Eventually(Equals(not self.lim)))
3398
3399 def test_panel_title_updates_when_switching_to_maximized_app(self):
3400 """Switching to a maximised app from a restored one must update the panel title."""
3401@@ -242,13 +272,14 @@
3402
3403 class PanelWindowButtonsTests(PanelTestsBase):
3404
3405- scenarios = _make_monitor_scenarios()
3406+ scenarios = _make_scenarios()
3407
3408 def setUp(self):
3409 super(PanelWindowButtonsTests, self).setUp()
3410 # Locked Launchers on all monitors
3411 self.set_unity_option('num_launchers', 0)
3412 self.set_unity_option('launcher_hide_mode', 0)
3413+ self.always_visible = self.lim
3414
3415 def test_window_buttons_dont_show_on_empty_desktop(self):
3416 """Tests that the window buttons are not shown on clean desktop."""
3417@@ -279,13 +310,14 @@
3418
3419 self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(False)))
3420
3421- def test_window_buttons_dont_show_for_maximized_window_on_mouse_out(self):
3422- """Window buttons must not show for a maximized window when the mouse is
3423- outside the panel.
3424+ def test_window_buttons_show_for_maximized_window_on_mouse_out(self):
3425+ """Window buttons might show for a maximized window when the mouse is
3426+ outside the panel, depending on LIM setting.
3427 """
3428 self.open_new_application_window("Text Editor", maximized=True)
3429
3430- self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(False)))
3431+ self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(self.always_visible)))
3432+ self.assertThat(self.panel.window_buttons.focused, Eventually(Equals(True)))
3433
3434 def test_window_buttons_show_for_maximized_window_on_mouse_in(self):
3435 """Window buttons must show when a maximized window is focused and the
3436@@ -296,8 +328,30 @@
3437 self.panel.move_mouse_over_window_buttons()
3438
3439 self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(True)))
3440+ self.assertThat(self.panel.window_buttons.focused, Eventually(Equals(True)))
3441 self.assertWinButtonsInOverlayMode(False)
3442
3443+ def test_window_buttons_show_for_maximized_unfocused_window_with_mouse_in_panel(self):
3444+ """Window buttons might show for an unfocused maximized window when the
3445+ mouse is over the panel, depending on LIM setting.
3446+ """
3447+ self.open_new_application_window("Text Editor", maximized=True)
3448+ self.open_new_application_window("Calculator")
3449+ self.panel.move_mouse_over_window_buttons()
3450+
3451+ self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(self.always_visible)))
3452+ self.assertThat(self.panel.window_buttons.focused, Eventually(Equals(not self.lim)))
3453+
3454+ def test_window_buttons_show_for_maximized_unfocused_window_on_mouse_out(self):
3455+ """Window buttons might show for an unfocused maximized window when the
3456+ mouse is outside the panel, depending on LIM setting.
3457+ """
3458+ self.open_new_application_window("Text Editor", maximized=True)
3459+ self.open_new_application_window("Calculator")
3460+
3461+ self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(self.always_visible)))
3462+ self.assertThat(self.panel.window_buttons.focused, Eventually(Equals(not self.lim)))
3463+
3464 def test_window_buttons_show_with_dash(self):
3465 """Window buttons must be shown when the dash is open."""
3466 self.unity.dash.ensure_visible()
3467@@ -340,122 +394,6 @@
3468 else:
3469 self.assertThat(self.unity.hud.view.overlay_window_buttons_shown[monitor], Equals(False))
3470
3471- def test_window_buttons_update_visual_state(self):
3472- """Window button must update its state in response to mouse events."""
3473- self.open_new_application_window("Text Editor", maximized=True, move_to_monitor=True)
3474- self.panel.move_mouse_over_window_buttons()
3475- button = self.panel.window_buttons.unmaximize
3476-
3477- self.assertThat(button.visual_state, Eventually(Equals("normal")))
3478-
3479- button.mouse_move_to()
3480- self.assertThat(button.visual_state, Eventually(Equals("prelight")))
3481-
3482- self.mouse.press()
3483- self.addCleanup(self.mouse.release)
3484- self.assertThat(button.visual_state, Eventually(Equals("pressed")))
3485-
3486- def test_window_buttons_cancel(self):
3487- """Window buttons must ignore clicks when the mouse released outside
3488- their area.
3489- """
3490- win = self.open_new_application_window("Text Editor", maximized=True, move_to_monitor=True)
3491- self.panel.move_mouse_over_window_buttons()
3492-
3493- button = self.panel.window_buttons.unmaximize
3494- button.mouse_move_to()
3495- self.mouse.press()
3496- self.assertThat(button.visual_state, Eventually(Equals("pressed")))
3497- self.panel.move_mouse_below_the_panel()
3498- self.mouse.release()
3499-
3500- self.assertThat(win.is_maximized, Equals(True))
3501-
3502- def test_window_buttons_close_button_works_for_window(self):
3503- """Close window button must actually closes a window."""
3504- text_win = self.open_new_application_window("Text Editor",
3505- maximized=True,
3506- move_to_monitor=True)
3507- win_xid = text_win.x_id
3508-
3509- self.panel.window_buttons.close.mouse_click()
3510- self.assertNoWindowOpenWithXid(win_xid)
3511-
3512- def test_window_buttons_close_follows_fitts_law(self):
3513- """Tests that the 'Close' button is activated when clicking at 0,0.
3514-
3515- See bug #839690
3516- """
3517- text_win = self.open_new_application_window("Text Editor",
3518- maximized=True,
3519- move_to_monitor=True)
3520- win_xid = text_win.x_id
3521-
3522- self.panel.move_mouse_over_window_buttons()
3523- screen_x, screen_y = self.display.get_screen_geometry(self.panel_monitor)[:2]
3524- self.mouse.move(screen_x, screen_y)
3525- self.mouse.click()
3526-
3527- self.assertNoWindowOpenWithXid(win_xid)
3528-
3529- def test_window_buttons_minimize_button_works_for_window(self):
3530- """Tests that the window button 'Minimize' actually minimizes a window."""
3531- text_win = self.open_new_application_window("Text Editor",
3532- maximized=True,
3533- move_to_monitor=True)
3534-
3535- self.panel.window_buttons.minimize.mouse_click()
3536-
3537- self.assertProperty(text_win, is_hidden=True)
3538-
3539- def test_window_buttons_minimize_follows_fitts_law(self):
3540- """Tests that the 'Minimize' button is conform to Fitts's Law.
3541-
3542- See bug #839690
3543- """
3544- text_win = self.open_new_application_window("Text Editor",
3545- maximized=True,
3546- move_to_monitor=True)
3547-
3548- self.panel.move_mouse_over_window_buttons()
3549- button = self.panel.window_buttons.minimize
3550- target_x = button.x + button.width / 2
3551- target_y = self.display.get_screen_geometry(self.panel_monitor)[1]
3552- self.mouse.move(target_x, target_y)
3553- self.mouse.click()
3554-
3555- self.assertProperty(text_win, is_hidden=True)
3556-
3557- def test_window_buttons_unmaximize_button_works_for_window(self):
3558- """Tests that the window button 'Unmaximize' actually unmaximizes a window."""
3559- text_win = self.open_new_application_window("Text Editor",
3560- maximized=True,
3561- move_to_monitor=True)
3562-
3563- self.panel.window_buttons.unmaximize.mouse_click()
3564-
3565- self.assertProperties(text_win, is_maximized=False, is_focused=True)
3566- self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(False)))
3567-
3568- def test_window_buttons_unmaximize_follows_fitts_law(self):
3569- """Tests that the 'Unmaximize' button is conform to Fitts's Law.
3570-
3571- See bug #839690
3572- """
3573- text_win = self.open_new_application_window("Text Editor",
3574- maximized=True,
3575- move_to_monitor=True)
3576-
3577- button = self.panel.window_buttons.unmaximize
3578- button.mouse_move_to()
3579- target_x = button.x + button.width / 2
3580- target_y = self.display.get_screen_geometry(self.panel_monitor)[1]
3581- self.mouse.move(target_x, target_y)
3582- sleep(1)
3583- self.mouse.click()
3584-
3585- self.assertProperty(text_win, is_maximized=False)
3586-
3587 def test_window_buttons_close_button_works_for_hud(self):
3588 """Tests that the window 'Close' actually closes the HUD."""
3589 self.unity.hud.ensure_visible()
3590@@ -604,9 +542,7 @@
3591
3592 def test_minimize_button_disabled_for_non_minimizable_windows(self):
3593 """Minimize button must be disabled for windows that don't support minimization."""
3594- text_win = self.open_new_application_window("Text Editor",
3595- maximized=False,
3596- move_to_monitor=True)
3597+ text_win = self.open_new_application_window("Text Editor", maximized=True)
3598
3599 self.keyboard.press_and_release("Ctrl+S")
3600 self.addCleanup(self.keyboard.press_and_release, "Escape")
3601@@ -626,28 +562,24 @@
3602 """Window buttons must be shown when mouse is over panel area with an
3603 indicator open.
3604 """
3605- self.open_new_application_window("Text Editor",
3606- maximized=True,
3607- move_to_monitor=True)
3608+ self.open_new_application_window("Text Editor", maximized=True)
3609
3610 indicator = self.panel.indicators.get_indicator_by_name_hint("indicator-session")
3611 self.mouse_open_indicator(indicator)
3612- self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(False)))
3613+ self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(self.always_visible)))
3614
3615 self.panel.move_mouse_below_the_panel()
3616- self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(False)))
3617+ self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(self.always_visible)))
3618
3619 self.panel.move_mouse_over_grab_area()
3620 self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(True)))
3621
3622 def test_window_buttons_show_when_holding_show_menu_key(self):
3623 """Window buttons must show when we press the show-menu keybinding."""
3624- self.open_new_application_window("Text Editor",
3625- maximized=True,
3626- move_to_monitor=True)
3627+ self.open_new_application_window("Text Editor", maximized=True)
3628
3629 self.sleep_menu_settle_period()
3630- self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(False)))
3631+ self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(self.always_visible)))
3632
3633 self.keybinding_hold("panel/show_menus")
3634 self.addCleanup(self.keybinding_release, "panel/show_menus")
3635@@ -657,7 +589,7 @@
3636 # Sleep a bit to avoid a race with the Hud showing
3637 sleep(0.5)
3638 self.keybinding_release("panel/show_menus")
3639- self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(False)))
3640+ self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(self.always_visible)))
3641
3642 def test_window_buttons_cant_accept_keynav_focus(self):
3643 """On a mouse down event over the window buttons
3644@@ -673,57 +605,149 @@
3645
3646 self.assertThat(self.unity.hud.search_string, Eventually(Equals("HelloWorld")))
3647
3648- def test_double_click_unmaximize_window(self):
3649- """Double clicking the grab area must unmaximize a maximized window."""
3650- gedit_win = self.open_new_application_window("Text Editor", maximized=True)
3651-
3652- self.panel.move_mouse_over_grab_area()
3653- self.mouse.click()
3654- self.mouse.click()
3655-
3656- self.assertThat(self.panel.title, Eventually(Equals(gedit_win.application.name)))
3657+
3658+class PanelWindowButtonsActionsTests(PanelTestsBase):
3659+ """Test WindowButtons actions on windows, focused or not depending on LIM"""
3660+ restored_on_top = False
3661+ scenarios = multiply_scenarios(_make_monitor_scenarios(),
3662+ (_make_menu_modes_scenarios() +
3663+ [('Locally Integrated Menus with restored on Top',
3664+ {'lim': True, 'restored_on_top': True})]))
3665+
3666+ def setUp(self):
3667+ super(PanelWindowButtonsActionsTests, self).setUp()
3668+ self.text_win = self.open_new_application_window("Text Editor", maximized=True)
3669+
3670+ if self.restored_on_top:
3671+ self.open_new_application_window("Calculator")
3672+
3673+ def test_window_buttons_update_visual_state(self):
3674+ """Window button must update its state in response to mouse events."""
3675+ self.panel.move_mouse_over_window_buttons()
3676+ button = self.panel.window_buttons.unmaximize
3677+
3678+ self.assertThat(self.panel.window_buttons.focused, Eventually(Equals(not self.restored_on_top)))
3679+ self.assertThat(button.visual_state, Eventually(Equals("normal")))
3680+
3681+ button.mouse_move_to()
3682+ self.assertThat(button.visual_state, Eventually(Equals("prelight")))
3683+
3684+ self.mouse.press()
3685+ self.addCleanup(self.mouse.release)
3686+ self.assertThat(button.visual_state, Eventually(Equals("pressed")))
3687+
3688+ def test_window_buttons_cancel(self):
3689+ """Window buttons must ignore clicks when the mouse released outside
3690+ their area.
3691+ """
3692+ self.panel.move_mouse_over_window_buttons()
3693+
3694+ button = self.panel.window_buttons.unmaximize
3695+ button.mouse_move_to()
3696+ self.mouse.press()
3697+ self.assertThat(button.visual_state, Eventually(Equals("pressed")))
3698+ self.panel.move_mouse_below_the_panel()
3699+ self.mouse.release()
3700+
3701+ self.assertThat(self.text_win.is_maximized, Equals(True))
3702+
3703+ def test_window_buttons_close_button_works_for_window(self):
3704+ """Close window button must actually closes a window."""
3705+ win_xid = self.text_win.x_id
3706+
3707+ self.panel.window_buttons.close.mouse_click()
3708+ self.assertNoWindowOpenWithXid(win_xid)
3709+
3710+ def test_window_buttons_close_follows_fitts_law(self):
3711+ """Tests that the 'Close' button is activated when clicking at 0,0.
3712+
3713+ See bug #839690
3714+ """
3715+ win_xid = self.text_win.x_id
3716+
3717+ self.panel.move_mouse_over_window_buttons()
3718+ screen_x, screen_y = self.display.get_screen_geometry(self.panel_monitor)[:2]
3719+ self.mouse.move(screen_x, screen_y)
3720+ self.mouse.click()
3721+
3722+ self.assertNoWindowOpenWithXid(win_xid)
3723+
3724+ def test_window_buttons_minimize_button_works_for_window(self):
3725+ """Tests that the window button 'Minimize' actually minimizes a window."""
3726+ self.panel.window_buttons.minimize.mouse_click()
3727+ self.assertProperty(self.text_win, is_hidden=True)
3728+
3729+ def test_window_buttons_minimize_follows_fitts_law(self):
3730+ """Tests that the 'Minimize' button is conform to Fitts's Law.
3731+
3732+ See bug #839690
3733+ """
3734+ self.panel.move_mouse_over_window_buttons()
3735+ button = self.panel.window_buttons.minimize
3736+ target_x = button.x + button.width / 2
3737+ target_y = self.display.get_screen_geometry(self.panel_monitor)[1]
3738+ self.mouse.move(target_x, target_y)
3739+ self.mouse.click()
3740+
3741+ self.assertProperty(self.text_win, is_hidden=True)
3742+
3743+ def test_window_buttons_unmaximize_button_works_for_window(self):
3744+ """Tests that the window button 'Unmaximize' actually unmaximizes a window."""
3745+ self.panel.window_buttons.unmaximize.mouse_click()
3746+
3747+ self.assertProperties(self.text_win, is_maximized=False, is_focused=True)
3748+ self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(False)))
3749+
3750+ def test_window_buttons_unmaximize_follows_fitts_law(self):
3751+ """Tests that the 'Unmaximize' button is conform to Fitts's Law.
3752+
3753+ See bug #839690
3754+ """
3755+ button = self.panel.window_buttons.unmaximize
3756+ button.mouse_move_to()
3757+ target_x = button.x + button.width / 2
3758+ target_y = self.display.get_screen_geometry(self.panel_monitor)[1]
3759+ self.mouse.move(target_x, target_y)
3760+ sleep(1)
3761+ self.mouse.click()
3762+
3763+ self.assertProperty(self.text_win, is_maximized=False)
3764
3765
3766 class PanelHoverTests(PanelTestsBase):
3767 """Tests with the mouse pointer hovering the panel area."""
3768
3769- scenarios = _make_monitor_scenarios()
3770+ scenarios = _make_scenarios()
3771
3772 def test_only_menus_show_for_restored_window_on_mouse_in_window_btn_area(self):
3773 """Restored windows should only show menus when the mouse is in the window
3774 button area.
3775 """
3776- self.open_new_application_window("Calculator",
3777- maximized=False,
3778- move_to_monitor=True)
3779+ self.open_new_application_window("Calculator")
3780 self.sleep_menu_settle_period()
3781
3782 self.panel.move_mouse_over_window_buttons()
3783
3784- self.assertThat(self.panel.menus_shown, Eventually(Equals(True)))
3785+ self.assertThat(self.panel.menus_shown, Eventually(Equals(not self.lim)))
3786 self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(False)))
3787
3788 def test_only_menus_show_for_restored_window_on_mouse_in_menu_area(self):
3789 """Restored windows should only show menus when the mouse is in the window
3790 menu area.
3791 """
3792- self.open_new_application_window("Calculator",
3793- maximized=False,
3794- move_to_monitor=True)
3795+ self.open_new_application_window("Calculator")
3796 self.sleep_menu_settle_period()
3797
3798 self.panel.move_mouse_over_menus()
3799
3800- self.assertThat(self.panel.menus_shown, Eventually(Equals(True)))
3801+ self.assertThat(self.panel.menus_shown, Eventually(Equals(not self.lim)))
3802 self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(False)))
3803
3804 def test_only_menus_show_for_restored_window_on_mouse_in_grab_area(self):
3805 """Restored windows should only show menus when the mouse is in the panel
3806 grab area.
3807 """
3808- self.open_new_application_window("Calculator",
3809- maximized=False,
3810- move_to_monitor=True)
3811+ self.open_new_application_window("Calculator")
3812 self.sleep_menu_settle_period()
3813
3814 if self.panel.grab_area.width <= 0:
3815@@ -731,14 +755,12 @@
3816
3817 self.panel.move_mouse_over_grab_area()
3818
3819- self.assertThat(self.panel.menus_shown, Eventually(Equals(True)))
3820+ self.assertThat(self.panel.menus_shown, Eventually(Equals(not self.lim)))
3821 self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(False)))
3822
3823 def test_hovering_over_indicators_does_not_show_app_menus(self):
3824 """Hovering the mouse over the indicators must not show app menus."""
3825- self.open_new_application_window("Calculator",
3826- maximized=False,
3827- move_to_monitor=True)
3828+ self.open_new_application_window("Text Editor", maximized=True)
3829 self.sleep_menu_settle_period()
3830
3831 self.panel.move_mouse_over_menus()
3832@@ -754,9 +776,7 @@
3833 """Menus and window buttons must be shown when the mouse is in the window
3834 button area for a maximised application.
3835 """
3836- self.open_new_application_window("Text Editor",
3837- maximized=True,
3838- move_to_monitor=True)
3839+ self.open_new_application_window("Text Editor", maximized=True)
3840 self.sleep_menu_settle_period()
3841
3842 self.panel.move_mouse_over_window_buttons()
3843@@ -768,9 +788,7 @@
3844 """Menus and window buttons must be shown when the mouse is in the menu
3845 area for a maximised application.
3846 """
3847- self.open_new_application_window("Text Editor",
3848- maximized=True,
3849- move_to_monitor=True)
3850+ self.open_new_application_window("Text Editor", maximized=True)
3851 self.sleep_menu_settle_period()
3852
3853 self.panel.move_mouse_over_menus()
3854@@ -785,9 +803,7 @@
3855 if self.panel.grab_area.width <= 0:
3856 self.skipTest("Grab area is too small to run this test!")
3857
3858- self.open_new_application_window("Text Editor",
3859- maximized=True,
3860- move_to_monitor=True)
3861+ self.open_new_application_window("Text Editor", maximized=True)
3862 self.sleep_menu_settle_period()
3863
3864 self.panel.move_mouse_over_grab_area()
3865@@ -799,9 +815,7 @@
3866 """Hovering the mouse over the indicators must hide the menus and window
3867 buttons.
3868 """
3869- self.open_new_application_window("Text Editor",
3870- maximized=True,
3871- move_to_monitor=True)
3872+ self.open_new_application_window("Text Editor", maximized=True)
3873 self.sleep_menu_settle_period()
3874
3875 self.panel.move_mouse_over_menus()
3876@@ -811,14 +825,14 @@
3877
3878 self.panel.move_mouse_over_indicators()
3879
3880- self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(False)))
3881+ self.assertThat(self.panel.window_buttons_shown, Eventually(Equals(self.lim)))
3882 self.assertThat(self.panel.menus_shown, Eventually(Equals(False)))
3883
3884 def test_hovering_indicators_open_menus(self):
3885 """Opening an indicator entry, and then hovering on other entries must
3886 open them.
3887 """
3888- self.open_new_application_window("Text Editor")
3889+ self.open_new_application_window("Text Editor", maximized=self.lim)
3890 entries = self.panel.get_indicator_entries(include_hidden_menus=True)
3891
3892 self.assertThat(len(entries), GreaterThan(0))
3893@@ -832,7 +846,7 @@
3894
3895 class PanelMenuTests(PanelTestsBase):
3896
3897- scenarios = _make_monitor_scenarios()
3898+ scenarios = _make_scenarios()
3899
3900 def start_test_app_with_menus(self):
3901 window_spec = {
3902@@ -846,7 +860,12 @@
3903 {"Title": "&Quit"}
3904 ]
3905 }
3906- self.launch_test_window(window_spec)
3907+ test_win = self.launch_test_window(window_spec)
3908+ test_win.set_focus()
3909+ self.move_window_to_panel_monitor(test_win)
3910+ self.ensure_window_state(test_win, maximized=self.lim)
3911+
3912+ return test_win
3913
3914 def test_menus_are_added_on_new_application(self):
3915 """Tests that menus are added when a new application is opened."""
3916@@ -872,10 +891,13 @@
3917 "Current panel entries are: %r" % self.panel.menus.get_entries())
3918
3919 self.panel.move_mouse_over_grab_area()
3920- self.assertThat(self.panel.title, Eventually(Equals(test_win.application.name)))
3921+ expected = test_win.application.name if not self.lim else ""
3922+ self.assertThat(self.panel.title, Eventually(Equals(expected)))
3923
3924 def test_menus_shows_when_new_application_is_opened(self):
3925 """When starting a new application, menus must first show, then hide."""
3926+ if self.lim:
3927+ self.skipTest("Menu discovery is disabled when LIM are enabled.")
3928
3929 # This test requires the window to be opened on the monitor that is being tested and
3930 # we cannot guarantee which monitor the window will open up on.
3931@@ -890,6 +912,9 @@
3932
3933 def test_menus_dont_show_if_a_new_application_window_is_opened(self):
3934 """This tests the menu discovery feature on new window for a know application."""
3935+ if self.lim:
3936+ self.skipTest("Menu discovery is disabled when LIM are enabled.")
3937+
3938 self.open_new_application_window("Character Map")
3939 self.sleep_menu_settle_period()
3940
3941@@ -917,7 +942,7 @@
3942
3943 self.panel.move_mouse_over_menus()
3944
3945- self.assertThat(self.panel.menus_shown, Eventually(Equals(True)))
3946+ self.assertThat(self.panel.menus_shown, Eventually(Equals(not self.lim)))
3947
3948 def test_menus_dont_show_for_maximized_window_on_mouse_out(self):
3949 """Maximized window menus must not show when the mouse is outside the
3950@@ -947,7 +972,7 @@
3951
3952 def test_menus_dont_show_with_hud(self):
3953 """Tests that menus are not showing when opening the HUD."""
3954- self.open_new_application_window("Text Editor", maximized=True)
3955+ self.open_new_application_window("Character Map", maximized=True)
3956 self.unity.hud.ensure_visible()
3957 self.addCleanup(self.unity.hud.ensure_hidden)
3958
3959@@ -957,11 +982,13 @@
3960 class PanelIndicatorEntryTests(PanelTestsBase):
3961 """Tests for the indicator entries, including both menu and indicators."""
3962
3963- scenarios = _make_monitor_scenarios()
3964+ scenarios = _make_scenarios()
3965
3966 def open_app_and_get_menu_entry(self):
3967 """Open the test app and wait for the menu entry to appear."""
3968- self.open_new_application_window("Calculator")
3969+ self.open_new_application_window("Remmina" if self.lim else "Calculator",
3970+ maximized=self.lim)
3971+
3972 refresh_fn = lambda: len(self.panel.menus.get_entries())
3973 self.assertThat(refresh_fn, Eventually(GreaterThan(0)))
3974 menu_entry = self.panel.menus.get_entries()[0]
3975@@ -1033,7 +1060,7 @@
3976
3977 class PanelKeyNavigationTests(PanelTestsBase):
3978
3979- scenarios = _make_monitor_scenarios()
3980+ scenarios = _make_scenarios()
3981
3982 def get_active_indicator(self):
3983 """Get the active indicator in a safe manner.
3984@@ -1048,17 +1075,17 @@
3985 """Pressing the open-menus keybinding must open the first indicator."""
3986 self.open_new_application_window("Calculator")
3987 refresh_fn = lambda: len(self.panel.menus.get_entries())
3988- self.assertThat(refresh_fn, Eventually(GreaterThan(0)))
3989+ self.assertThat(refresh_fn, Eventually(Equals(0) if self.lim else GreaterThan(0)))
3990 self.addCleanup(self.keyboard.press_and_release, "Escape")
3991 self.keybinding("panel/open_first_menu")
3992
3993 open_indicator = self.get_active_indicator()
3994- expected_indicator = self.panel.get_indicator_entries(include_hidden_menus=True)[0]
3995+ expected_indicator = self.panel.get_indicator_entries(include_hidden_menus=not self.lim)[0]
3996 self.assertThat(open_indicator.entry_id, Eventually(Equals(expected_indicator.entry_id)))
3997
3998 def test_panel_hold_show_menu_works(self):
3999 """Holding the show menu key must reveal the menu with mnemonics."""
4000- self.open_new_application_window("Text Editor")
4001+ self.open_new_application_window("Text Editor", maximized=self.lim)
4002 refresh_fn = lambda: len(self.panel.menus.get_entries())
4003 self.assertThat(refresh_fn, Eventually(GreaterThan(0)))
4004 self.addCleanup(self.keyboard.press_and_release, "Escape")
4005@@ -1073,7 +1100,7 @@
4006
4007 def test_panel_menu_accelerators_work(self):
4008 """Pressing a valid menu accelerator must open the correct menu item."""
4009- self.open_new_application_window("Text Editor")
4010+ self.open_new_application_window("Text Editor", maximized=self.lim)
4011 refresh_fn = lambda: len(self.panel.menus.get_entries())
4012 self.assertThat(refresh_fn, Eventually(GreaterThan(0)))
4013 self.addCleanup(self.keyboard.press_and_release, "Escape")
4014@@ -1087,7 +1114,7 @@
4015 calc_win = self.open_new_application_window("Calculator")
4016 self.assertProperty(calc_win, is_focused=True)
4017
4018- available_indicators = self.panel.get_indicator_entries(include_hidden_menus=True)
4019+ available_indicators = self.panel.get_indicator_entries(include_hidden_menus=not self.lim)
4020
4021 self.keybinding("panel/open_first_menu")
4022 self.addCleanup(self.keyboard.press_and_release, "Escape")
4023@@ -1102,7 +1129,7 @@
4024 calc_win = self.open_new_application_window("Calculator")
4025 self.assertProperty(calc_win, is_focused=True)
4026
4027- available_indicators = self.panel.get_indicator_entries(include_hidden_menus=True)
4028+ available_indicators = self.panel.get_indicator_entries(include_hidden_menus=not self.lim)
4029
4030 self.keybinding("panel/open_first_menu")
4031 self.addCleanup(self.keyboard.press_and_release, "Escape")
4032@@ -1118,14 +1145,12 @@
4033 opened with the keyboard.
4034 """
4035 self.open_new_application_window("Calculator")
4036- available_indicators = self.panel.get_indicator_entries(include_hidden_menus=True)
4037+ available_indicators = self.panel.get_indicator_entries(include_hidden_menus=not self.lim)
4038
4039 self.keybinding("panel/open_first_menu")
4040 self.addCleanup(self.keyboard.press_and_release, "Escape")
4041
4042 available_indicators[2].mouse_move_to()
4043- self.addCleanup(self.panel.move_mouse_below_the_panel)
4044-
4045 self.assertThat(available_indicators[2].active, Eventually(Equals(True)))
4046
4047 self.keybinding("panel/prev_indicator")
4048@@ -1135,11 +1160,10 @@
4049 class PanelGrabAreaTests(PanelTestsBase):
4050 """Panel grab area tests."""
4051
4052- scenarios = _make_monitor_scenarios()
4053+ scenarios = _make_scenarios()
4054
4055 def move_mouse_over_grab_area(self):
4056 self.panel.move_mouse_over_grab_area()
4057- self.addCleanup(self.panel.move_mouse_below_the_panel)
4058 sleep(.1)
4059
4060 def test_unmaximize_from_grab_area_works(self):
4061@@ -1192,6 +1216,29 @@
4062 self.assertThat(self.unity.hud.search_string, Eventually(Equals("HelloWorld")))
4063
4064
4065+class PanelLimTests(PanelTestsBase):
4066+
4067+ scenarios = _make_monitor_scenarios()
4068+
4069+ def setUp(self):
4070+ self.lim = True
4071+ super(PanelLimTests, self).setUp()
4072+
4073+ def test_title_focus_on_maximized_state_changes(self):
4074+ text_win = self.open_new_application_window("Text Editor", maximized=True)
4075+ self.assertThat(self.panel.focused, Eventually(Equals(True)))
4076+ self.assertThat(self.panel.title, Eventually(Equals(text_win.title)))
4077+
4078+ self.open_new_application_window("Calculator")
4079+ self.assertThat(self.panel.focused, Eventually(Equals(False)))
4080+ self.assertThat(self.panel.title, Eventually(Equals(text_win.title)))
4081+
4082+ text_win.set_focus()
4083+ self.assertProperty(text_win, is_focused=True)
4084+ self.assertThat(self.panel.focused, Eventually(Equals(True)))
4085+ self.assertThat(self.panel.title, Eventually(Equals(text_win.title)))
4086+
4087+
4088 class PanelCrossMonitorsTests(PanelTestsBase):
4089 """Multimonitor panel tests."""
4090
4091
4092=== modified file 'tests/autopilot/unity/tests/test_wm_keybindings.py'
4093--- tests/autopilot/unity/tests/test_wm_keybindings.py 2013-12-04 19:42:43 +0000
4094+++ tests/autopilot/unity/tests/test_wm_keybindings.py 2015-02-19 19:24:14 +0000
4095@@ -21,27 +21,24 @@
4096
4097 def open_panel_menu(self):
4098 panel = self.unity.panels.get_panel_for_monitor(0)
4099- self.assertThat(lambda: len(panel.menus.get_entries()), Eventually(GreaterThan(0)))
4100+ self.assertThat(lambda: len(panel.get_indicator_entries()), Eventually(GreaterThan(0)))
4101 self.addCleanup(self.keyboard.press_and_release, "Escape")
4102 self.keybinding("panel/open_first_menu")
4103 self.assertThat(self.unity.panels.get_active_indicator, Eventually(NotEquals(None)))
4104
4105 def test_dash_shows_on_menus_opened(self):
4106- self.process_manager.start_app_window("Calculator")
4107 self.open_panel_menu()
4108 self.addCleanup(self.unity.dash.ensure_hidden)
4109 self.unity.dash.ensure_visible()
4110 self.assertThat(self.unity.panels.get_active_indicator, Eventually(Equals(None)))
4111
4112 def test_hud_shows_on_menus_opened(self):
4113- self.process_manager.start_app_window("Calculator")
4114 self.open_panel_menu()
4115 self.addCleanup(self.unity.hud.ensure_hidden)
4116 self.unity.hud.ensure_visible()
4117 self.assertThat(self.unity.panels.get_active_indicator, Eventually(Equals(None)))
4118
4119 def test_switcher_shows_on_menus_opened(self):
4120- self.process_manager.start_app_window("Calculator")
4121 self.open_panel_menu()
4122 self.addCleanup(self.unity.switcher.terminate)
4123 self.unity.switcher.initiate()
4124@@ -49,7 +46,6 @@
4125 self.assertThat(self.unity.panels.get_active_indicator, Eventually(Equals(None)))
4126
4127 def test_shortcut_hints_shows_on_menus_opened(self):
4128- self.process_manager.start_app_window("Calculator")
4129 self.open_panel_menu()
4130 self.addCleanup(self.unity.shortcut_hint.ensure_hidden)
4131 self.unity.shortcut_hint.show()
4132@@ -57,7 +53,6 @@
4133 self.assertThat(self.unity.panels.get_active_indicator, Eventually(Equals(None)))
4134
4135 def test_spread_shows_on_menus_opened(self):
4136- self.process_manager.start_app_window("Calculator")
4137 self.open_panel_menu()
4138 self.addCleanup(self.unity.window_manager.terminate_spread)
4139 self.unity.window_manager.initiate_spread()
4140
4141=== modified file 'tests/mock-application.h'
4142--- tests/mock-application.h 2014-03-21 04:40:12 +0000
4143+++ tests/mock-application.h 2015-02-19 19:24:14 +0000
4144@@ -20,7 +20,7 @@
4145 #ifndef TESTS_MOCK_APPLICATION_H
4146 #define TESTS_MOCK_APPLICATION_H
4147
4148-#include <map>
4149+#include <unordered_map>
4150 #include <gmock/gmock.h>
4151 #include <gio/gdesktopappinfo.h>
4152 #include <UnityCore/GLibWrapper.h>
4153@@ -360,7 +360,7 @@
4154 }
4155
4156 private:
4157- typedef std::map<std::string, unity::ApplicationPtr> AppMap;
4158+ typedef std::unordered_map<std::string, unity::ApplicationPtr> AppMap;
4159 AppMap app_map_;
4160 };
4161
4162
4163=== modified file 'tests/test_dbus_indicators.cpp'
4164--- tests/test_dbus_indicators.cpp 2013-03-25 18:22:32 +0000
4165+++ tests/test_dbus_indicators.cpp 2015-02-19 19:24:14 +0000
4166@@ -5,6 +5,7 @@
4167 #include <UnityCore/GLibWrapper.h>
4168 #include <UnityCore/DBusIndicators.h>
4169
4170+#include "panel-service-private.h"
4171 #include "test_utils.h"
4172
4173 using namespace unity;
4174@@ -50,10 +51,8 @@
4175
4176 GVariant* CallPanelMethod(std::string const& name) const
4177 {
4178- return g_dbus_connection_call_sync(session,
4179- "com.canonical.Unity.Test",
4180- "/com/canonical/Unity/Panel/Service",
4181- "com.canonical.Unity.Panel.Service",
4182+ return g_dbus_connection_call_sync(session, "com.canonical.Unity.Test",
4183+ UPS_PATH, UPS_IFACE,
4184 name.c_str(),
4185 NULL,
4186 NULL,
4187
4188=== modified file 'tests/test_indicator.cpp'
4189--- tests/test_indicator.cpp 2014-01-27 17:31:30 +0000
4190+++ tests/test_indicator.cpp 2015-02-19 19:24:14 +0000
4191@@ -44,7 +44,7 @@
4192
4193 MOCK_CONST_METHOD0(Updated, void());
4194 MOCK_CONST_METHOD1(EntryAdded, void(Entry::Ptr const&));
4195- MOCK_CONST_METHOD1(EntryRemoved, void(std::string const&));
4196+ MOCK_CONST_METHOD1(EntryRemoved, void(Entry::Ptr const&));
4197 MOCK_CONST_METHOD5(ShowMenu, void(std::string const&, unsigned, int, int, unsigned));
4198 MOCK_CONST_METHOD1(SecondaryActivate, void(std::string const&));
4199 MOCK_CONST_METHOD2(Scroll, void(std::string const&, int));
4200@@ -57,7 +57,6 @@
4201 EXPECT_EQ(indicator.name(), "indicator-test");
4202 EXPECT_FALSE(indicator.IsAppmenu());
4203 EXPECT_EQ(indicator.GetEntry("test-entry"), nullptr);
4204- EXPECT_EQ(indicator.EntryIndex("test-entry"), -1);
4205 EXPECT_TRUE(indicator.GetEntries().empty());
4206 }
4207
4208@@ -69,17 +68,17 @@
4209 Indicator indicator("indicator-test");
4210 SigReceiver::Nice sig_receiver(indicator);
4211
4212- entry = new Entry("test-entry-1", "name-hint", "label", true, true, 0, "icon",
4213+ entry = new Entry("test-entry-1", "name-hint", 0, "label", true, true, 0, "icon",
4214 true, true, -1);
4215 Entry::Ptr entry1(entry);
4216 sync_data.push_back(entry1);
4217
4218- entry = new Entry("test-entry-2", "name-hint", "label", true, true, 0, "icon",
4219+ entry = new Entry("test-entry-2", "name-hint", 0, "label", true, true, 0, "icon",
4220 true, true, -1);
4221 Entry::Ptr entry2(entry);
4222 sync_data.push_back(entry2);
4223
4224- entry = new Entry("test-entry-3", "name-hint", "label", true, true, 0, "icon",
4225+ entry = new Entry("test-entry-3", "name-hint", 0, "label", true, true, 0, "icon",
4226 true, true, -1);
4227 Entry::Ptr entry3(entry);
4228 sync_data.push_back(entry3);
4229@@ -97,31 +96,29 @@
4230 indicator.Sync(sync_data);
4231 EXPECT_EQ(indicator.GetEntries().size(), 3);
4232 EXPECT_EQ(indicator.GetEntry("test-entry-2"), entry2);
4233- EXPECT_EQ(indicator.EntryIndex("test-entry-2"), 1);
4234 // Mock::VerifyAndClearExpectations(&sig_receiver);
4235
4236 // Sync the indicator removing an entry
4237- sync_data.remove(entry2);
4238+ sync_data.erase(std::remove(sync_data.begin(), sync_data.end(), entry2), sync_data.end());
4239 EXPECT_EQ(sync_data.size(), 2);
4240 EXPECT_CALL(sig_receiver, Updated());
4241 EXPECT_CALL(sig_receiver, EntryAdded(_)).Times(0);
4242- EXPECT_CALL(sig_receiver, EntryRemoved(entry2->id()));
4243+ EXPECT_CALL(sig_receiver, EntryRemoved(entry2));
4244
4245 indicator.Sync(sync_data);
4246 EXPECT_EQ(indicator.GetEntries().size(), 2);
4247 EXPECT_EQ(indicator.GetEntry("test-entry-2"), nullptr);
4248- EXPECT_EQ(indicator.EntryIndex("test-entry-2"), -1);
4249
4250 // Sync the indicator removing an entry and adding a new one
4251- entry = new Entry("test-entry-4", "name-hint", "label", true, true, 0, "icon",
4252+ entry = new Entry("test-entry-4", "name-hint", 0, "label", true, true, 0, "icon",
4253 true, true, -1);
4254 Entry::Ptr entry4(entry);
4255 sync_data.push_back(entry4);
4256- sync_data.remove(entry3);
4257+ sync_data.erase(std::remove(sync_data.begin(), sync_data.end(), entry3), sync_data.end());
4258 EXPECT_EQ(sync_data.size(), 2);
4259
4260 EXPECT_CALL(sig_receiver, EntryAdded(entry4));
4261- EXPECT_CALL(sig_receiver, EntryRemoved(entry3->id()));
4262+ EXPECT_CALL(sig_receiver, EntryRemoved(entry3));
4263 EXPECT_CALL(sig_receiver, Updated());
4264 indicator.Sync(sync_data);
4265 EXPECT_EQ(indicator.GetEntries().size(), 2);
4266@@ -129,8 +126,8 @@
4267 // Remove all the indicators
4268
4269 EXPECT_CALL(sig_receiver, EntryAdded(_)).Times(0);
4270- EXPECT_CALL(sig_receiver, EntryRemoved(entry1->id()));
4271- EXPECT_CALL(sig_receiver, EntryRemoved(entry4->id()));
4272+ EXPECT_CALL(sig_receiver, EntryRemoved(entry1));
4273+ EXPECT_CALL(sig_receiver, EntryRemoved(entry4));
4274 EXPECT_CALL(sig_receiver, Updated());
4275
4276 sync_data.clear();
4277@@ -144,13 +141,13 @@
4278 SigReceiver::Nice sig_receiver(indicator);
4279 Indicator::Entries sync_data;
4280
4281- auto entry1 = std::make_shared<Entry>("test-entry-1", "name-hint", "label", true, true, 0, "icon", true, true, -1);
4282+ auto entry1 = std::make_shared<Entry>("test-entry-1", "name-hint", 0, "label", true, true, 0, "icon", true, true, -1);
4283 sync_data.push_back(entry1);
4284
4285- auto entry2 = std::make_shared<Entry>("test-entry-2", "name-hint", "label", true, true, 0, "icon", true, true, -1);
4286+ auto entry2 = std::make_shared<Entry>("test-entry-2", "name-hint", 0, "label", true, true, 0, "icon", true, true, -1);
4287 sync_data.push_back(entry2);
4288
4289- auto entry3 = std::make_shared<Entry>("test-entry-3", "name-hint", "label", true, true, 0, "icon", true, true, -1);
4290+ auto entry3 = std::make_shared<Entry>("test-entry-3", "name-hint", 0, "label", true, true, 0, "icon", true, true, -1);
4291 sync_data.push_back(entry3);
4292
4293 EXPECT_CALL(sig_receiver, Updated());
4294@@ -162,7 +159,7 @@
4295 EXPECT_CALL(sig_receiver, Updated()).Times(0);
4296 indicator.Sync(sync_data);
4297
4298- sync_data.remove(entry3);
4299+ sync_data.erase(std::remove(sync_data.begin(), sync_data.end(), entry3), sync_data.end());
4300 EXPECT_CALL(sig_receiver, Updated());
4301 indicator.Sync(sync_data);
4302
4303@@ -176,7 +173,7 @@
4304 Indicator indicator("indicator-test");
4305 SigReceiver::Nice sig_receiver(indicator);
4306
4307- auto entry = std::make_shared<Entry>("test-entry-1", "name-hint", "label", true, true, 0, "icon", true, true, -1);
4308+ auto entry = std::make_shared<Entry>("test-entry-1", "name-hint", 0, "label", true, true, 0, "icon", true, true, -1);
4309 indicator.Sync({entry});
4310
4311 EXPECT_CALL(sig_receiver, ShowMenu(entry->id(), 123456789, 50, 100, 2));
4312@@ -194,7 +191,7 @@
4313 Indicator indicator("indicator-test");
4314 SigReceiver::Nice sig_receiver(indicator);
4315
4316- auto entry = std::make_shared<Entry>("test-entry-2", "name-hint", "label", true, true, 0, "icon", true, true, -1);
4317+ auto entry = std::make_shared<Entry>("test-entry-2", "name-hint", 0, "label", true, true, 0, "icon", true, true, -1);
4318 indicator.Sync({entry});
4319
4320 EXPECT_CALL(sig_receiver, SecondaryActivate(entry->id()));
4321@@ -206,7 +203,7 @@
4322 Indicator indicator("indicator-test");
4323 SigReceiver::Nice sig_receiver(indicator);
4324
4325- auto entry = std::make_shared<Entry>("test-entry-2", "name-hint", "label", true, true, 0, "icon", true, true, -1);
4326+ auto entry = std::make_shared<Entry>("test-entry-2", "name-hint", 0, "label", true, true, 0, "icon", true, true, -1);
4327 indicator.Sync({entry});
4328
4329 EXPECT_CALL(sig_receiver, Scroll(entry->id(), -5));
4330
4331=== modified file 'tests/test_indicator_appmenu.cpp'
4332--- tests/test_indicator_appmenu.cpp 2012-12-04 00:33:18 +0000
4333+++ tests/test_indicator_appmenu.cpp 2015-02-19 19:24:14 +0000
4334@@ -1,6 +1,6 @@
4335 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
4336 /*
4337- * Copyright (C) 2012 Canonical Ltd
4338+ * Copyright (C) 2012-2015 Canonical Ltd
4339 *
4340 * This program is free software: you can redistribute it and/or modify
4341 * it under the terms of the GNU General Public License version 3 as
4342@@ -18,15 +18,41 @@
4343 */
4344
4345 #include <UnityCore/AppmenuIndicator.h>
4346-
4347-#include <gtest/gtest.h>
4348+#include <gmock/gmock.h>
4349
4350 using namespace std;
4351 using namespace unity;
4352 using namespace indicator;
4353+using namespace testing;
4354
4355 namespace
4356 {
4357+struct SigReceiver : sigc::trackable
4358+{
4359+ typedef NiceMock<SigReceiver> Nice;
4360+
4361+ SigReceiver(AppmenuIndicator const& const_indicator)
4362+ {
4363+ auto& indicator = const_cast<AppmenuIndicator&>(const_indicator);
4364+ indicator.updated.connect(sigc::mem_fun(this, &SigReceiver::Updated));
4365+ indicator.updated_win.connect(sigc::mem_fun(this, &SigReceiver::UpdatedWin));
4366+ indicator.on_entry_added.connect(sigc::mem_fun(this, &SigReceiver::EntryAdded));
4367+ indicator.on_entry_removed.connect(sigc::mem_fun(this, &SigReceiver::EntryRemoved));
4368+ indicator.on_show_menu.connect(sigc::mem_fun(this, &SigReceiver::ShowMenu));
4369+ indicator.on_show_appmenu.connect(sigc::mem_fun(this, &SigReceiver::ShowAppmenu));
4370+ indicator.on_secondary_activate.connect(sigc::mem_fun(this, &SigReceiver::SecondaryActivate));
4371+ indicator.on_scroll.connect(sigc::mem_fun(this, &SigReceiver::Scroll));
4372+ }
4373+
4374+ MOCK_CONST_METHOD0(Updated, void());
4375+ MOCK_CONST_METHOD1(UpdatedWin, void(uint32_t));
4376+ MOCK_CONST_METHOD1(EntryAdded, void(Entry::Ptr const&));
4377+ MOCK_CONST_METHOD1(EntryRemoved, void(Entry::Ptr const&));
4378+ MOCK_CONST_METHOD5(ShowMenu, void(std::string const&, unsigned, int, int, unsigned));
4379+ MOCK_CONST_METHOD3(ShowAppmenu, void(unsigned, int, int));
4380+ MOCK_CONST_METHOD1(SecondaryActivate, void(std::string const&));
4381+ MOCK_CONST_METHOD2(Scroll, void(std::string const&, int));
4382+};
4383
4384 TEST(TestAppmenuIndicator, Construction)
4385 {
4386@@ -39,25 +65,160 @@
4387 TEST(TestAppmenuIndicator, ShowAppmenu)
4388 {
4389 AppmenuIndicator indicator("indicator-appmenu");
4390-
4391- bool signal_emitted = false;
4392- int show_x, show_y;
4393- unsigned show_xid;
4394-
4395- // Connecting to signals
4396- indicator.on_show_appmenu.connect([&] (unsigned int xid, int x, int y) {
4397- signal_emitted = true;
4398- show_xid = xid;
4399- show_x = x;
4400- show_y = y;
4401- });
4402-
4403+ SigReceiver::Nice sig_receiver(indicator);
4404+
4405+ EXPECT_CALL(sig_receiver, ShowAppmenu(123456789, 50, 100));
4406 indicator.ShowAppmenu(123456789, 50, 100);
4407- EXPECT_TRUE(signal_emitted);
4408-
4409- EXPECT_EQ(show_xid, 123456789);
4410- EXPECT_EQ(show_x, 50);
4411- EXPECT_EQ(show_y, 100);
4412+}
4413+
4414+TEST(TestAppmenuIndicator, Syncing)
4415+{
4416+ Indicator::Entries sync_data;
4417+
4418+ AppmenuIndicator indicator("indicator-appmenu");
4419+ SigReceiver::Nice sig_receiver(indicator);
4420+ const uint32_t parent_window1 = 12345;
4421+ const uint32_t parent_window2 = 54321;
4422+
4423+ auto entry1 = std::make_shared<Entry>("test-entry-1", "name-hint", parent_window1, "label", true, true, 0, "icon", true, true, -1);
4424+ sync_data.push_back(entry1);
4425+
4426+ auto entry2 = std::make_shared<Entry>("test-entry-2", "name-hint", parent_window1, "label", true, true, 0, "icon", true, true, -1);
4427+ sync_data.push_back(entry2);
4428+
4429+ auto entry3 = std::make_shared<Entry>("test-entry-3", "name-hint", parent_window2, "label", true, true, 0, "icon", true, true, -1);
4430+ sync_data.push_back(entry3);
4431+
4432+ // Sync the indicator, adding 3 entries
4433+ {
4434+ testing::InSequence s;
4435+ EXPECT_CALL(sig_receiver, EntryAdded(entry1));
4436+ EXPECT_CALL(sig_receiver, EntryAdded(entry2));
4437+ EXPECT_CALL(sig_receiver, EntryAdded(entry3));
4438+ EXPECT_CALL(sig_receiver, EntryRemoved(_)).Times(0);
4439+ EXPECT_CALL(sig_receiver, Updated());
4440+ }
4441+
4442+ EXPECT_CALL(sig_receiver, UpdatedWin(parent_window1));
4443+ EXPECT_CALL(sig_receiver, UpdatedWin(parent_window2));
4444+
4445+ indicator.Sync(sync_data);
4446+ EXPECT_EQ(indicator.GetEntriesForWindow(parent_window1), Indicator::Entries({entry1, entry2}));
4447+ EXPECT_EQ(indicator.GetEntriesForWindow(parent_window2), Indicator::Entries({entry3}));
4448+
4449+ // Sync the indicator removing an entry
4450+ sync_data.erase(std::remove(sync_data.begin(), sync_data.end(), entry2), sync_data.end());
4451+ ASSERT_EQ(sync_data.size(), 2);
4452+ EXPECT_CALL(sig_receiver, Updated());
4453+ EXPECT_CALL(sig_receiver, UpdatedWin(parent_window1));
4454+ EXPECT_CALL(sig_receiver, UpdatedWin(parent_window2)).Times(0);
4455+ EXPECT_CALL(sig_receiver, EntryAdded(_)).Times(0);
4456+ EXPECT_CALL(sig_receiver, EntryRemoved(entry2));
4457+
4458+ indicator.Sync(sync_data);
4459+ EXPECT_EQ(indicator.GetEntries().size(), 2);
4460+ EXPECT_EQ(indicator.GetEntry("test-entry-2"), nullptr);
4461+ EXPECT_EQ(indicator.GetEntriesForWindow(parent_window1), Indicator::Entries({entry1}));
4462+
4463+ // Sync the indicator removing an entry and adding a new one
4464+ auto entry4 = std::make_shared<Entry>("test-entry-4", "name-hint", parent_window2, "label", true, true, 0, "icon", true, true, -1);
4465+ sync_data.push_back(entry4);
4466+ sync_data.erase(std::remove(sync_data.begin(), sync_data.end(), entry3), sync_data.end());
4467+ EXPECT_EQ(sync_data.size(), 2);
4468+
4469+ EXPECT_CALL(sig_receiver, EntryAdded(entry4));
4470+ EXPECT_CALL(sig_receiver, EntryRemoved(entry3));
4471+ EXPECT_CALL(sig_receiver, Updated());
4472+ EXPECT_CALL(sig_receiver, UpdatedWin(parent_window1)).Times(0);
4473+ EXPECT_CALL(sig_receiver, UpdatedWin(parent_window2));
4474+ indicator.Sync(sync_data);
4475+ EXPECT_EQ(indicator.GetEntriesForWindow(parent_window1), Indicator::Entries({entry1}));
4476+ EXPECT_EQ(indicator.GetEntriesForWindow(parent_window2), Indicator::Entries({entry4}));
4477+
4478+ // Remove all the indicators
4479+ EXPECT_CALL(sig_receiver, EntryAdded(_)).Times(0);
4480+ EXPECT_CALL(sig_receiver, EntryRemoved(entry1));
4481+ EXPECT_CALL(sig_receiver, EntryRemoved(entry4));
4482+ EXPECT_CALL(sig_receiver, Updated());
4483+ EXPECT_CALL(sig_receiver, UpdatedWin(parent_window1));
4484+ EXPECT_CALL(sig_receiver, UpdatedWin(parent_window2));
4485+
4486+ sync_data.clear();
4487+ indicator.Sync(sync_data);
4488+
4489+ EXPECT_TRUE(indicator.GetEntriesForWindow(parent_window1).empty());
4490+ EXPECT_TRUE(indicator.GetEntriesForWindow(parent_window2).empty());
4491+}
4492+
4493+TEST(TestAppmenuIndicator, Updated)
4494+{
4495+ AppmenuIndicator indicator("indicator-test");
4496+ SigReceiver::Nice sig_receiver(indicator);
4497+ Indicator::Entries sync_data;
4498+ const uint32_t parent_window1 = 12345;
4499+ const uint32_t parent_window2 = 54321;
4500+
4501+ auto entry1 = std::make_shared<Entry>("test-entry-1", "name-hint", parent_window1, "label", true, true, 0, "icon", true, true, -1);
4502+ sync_data.push_back(entry1);
4503+
4504+ auto entry2 = std::make_shared<Entry>("test-entry-2", "name-hint", parent_window2, "label", true, true, 0, "icon", true, true, -1);
4505+ sync_data.push_back(entry2);
4506+
4507+ auto entry3 = std::make_shared<Entry>("test-entry-3", "name-hint", parent_window1, "label", true, true, 0, "icon", true, true, -1);
4508+ sync_data.push_back(entry3);
4509+
4510+ EXPECT_CALL(sig_receiver, Updated());
4511+
4512+ // Sync the indicator, adding 3 entries
4513+ indicator.Sync(sync_data);
4514+
4515+ // Readding the same entries, nothing is emitted
4516+ EXPECT_CALL(sig_receiver, Updated()).Times(0);
4517+ indicator.Sync(sync_data);
4518+
4519+ sync_data.erase(std::remove(sync_data.begin(), sync_data.end(), entry3), sync_data.end());
4520+ EXPECT_CALL(sig_receiver, Updated());
4521+ indicator.Sync(sync_data);
4522+
4523+ sync_data.push_back(entry3);
4524+ EXPECT_CALL(sig_receiver, Updated());
4525+ indicator.Sync(sync_data);
4526+}
4527+
4528+TEST(TestAppmenuIndicator, UpdatedWin)
4529+{
4530+ AppmenuIndicator indicator("indicator-test");
4531+ SigReceiver::Nice sig_receiver(indicator);
4532+ Indicator::Entries sync_data;
4533+ const uint32_t parent_window1 = 12345;
4534+ const uint32_t parent_window2 = 54321;
4535+
4536+ auto entry1 = std::make_shared<Entry>("test-entry-1", "name-hint", parent_window1, "label", true, true, 0, "icon", true, true, -1);
4537+ sync_data.push_back(entry1);
4538+
4539+ auto entry2 = std::make_shared<Entry>("test-entry-2", "name-hint", parent_window2, "label", true, true, 0, "icon", true, true, -1);
4540+ sync_data.push_back(entry2);
4541+
4542+ auto entry3 = std::make_shared<Entry>("test-entry-3", "name-hint", parent_window1, "label", true, true, 0, "icon", true, true, -1);
4543+ sync_data.push_back(entry3);
4544+
4545+ EXPECT_CALL(sig_receiver, UpdatedWin(parent_window1));
4546+ EXPECT_CALL(sig_receiver, UpdatedWin(parent_window2));
4547+
4548+ // Sync the indicator, adding 3 entries
4549+ indicator.Sync(sync_data);
4550+
4551+ // Readding the same entries, nothing is emitted
4552+ EXPECT_CALL(sig_receiver, UpdatedWin(_)).Times(0);
4553+ indicator.Sync(sync_data);
4554+
4555+ sync_data.erase(std::remove(sync_data.begin(), sync_data.end(), entry3), sync_data.end());
4556+ EXPECT_CALL(sig_receiver, UpdatedWin(entry3->parent_window()));
4557+ indicator.Sync(sync_data);
4558+
4559+ sync_data.push_back(entry3);
4560+ EXPECT_CALL(sig_receiver, UpdatedWin(entry3->parent_window()));
4561+ indicator.Sync(sync_data);
4562 }
4563
4564 }
4565
4566=== modified file 'tests/test_indicator_entry.cpp'
4567--- tests/test_indicator_entry.cpp 2014-02-07 23:54:15 +0000
4568+++ tests/test_indicator_entry.cpp 2015-02-19 19:24:14 +0000
4569@@ -36,11 +36,12 @@
4570 TEST(TestIndicatorEntry, TestConstruction)
4571 {
4572
4573- Entry entry("id", "name_hint", "label", true, true, 1, "some icon", false, true, -1);
4574+ Entry entry("id", "name_hint", 12345, "label", true, true, 1, "some icon", false, true, -1);
4575
4576 EXPECT_EQ(entry.id(), "id");
4577+ EXPECT_EQ(entry.name_hint(), "name_hint");
4578+ EXPECT_EQ(entry.parent_window(), 12345);
4579 EXPECT_EQ(entry.label(), "label");
4580- EXPECT_EQ(entry.name_hint(), "name_hint");
4581 EXPECT_TRUE(entry.label_sensitive());
4582 EXPECT_TRUE(entry.label_visible());
4583 EXPECT_FALSE(entry.image_sensitive());
4584@@ -55,10 +56,11 @@
4585
4586 TEST(TestIndicatorEntry, TestConstructionEmpty)
4587 {
4588- Entry entry("id", "name_hint");
4589+ Entry entry("id", "name_hint", 12345);
4590
4591 EXPECT_EQ(entry.id(), "id");
4592 EXPECT_EQ(entry.name_hint(), "name_hint");
4593+ EXPECT_EQ(entry.parent_window(), 12345);
4594 EXPECT_TRUE(entry.label().empty());
4595 EXPECT_FALSE(entry.label_sensitive());
4596 EXPECT_FALSE(entry.label_visible());
4597@@ -74,8 +76,8 @@
4598
4599 TEST(TestIndicatorEntry, TestAssignment)
4600 {
4601- Entry entry("id", "name_hint", "label", true, true, 0, "some icon", false, true, 10);
4602- Entry other_entry("other_id", "other_name_hint", "other_label", false, false, 2, "other icon", true, false, 5);
4603+ Entry entry("id", "name_hint", 12345, "label", true, true, 0, "some icon", false, true, 10);
4604+ Entry other_entry("other_id", "other_name_hint", 54321, "other_label", false, false, 2, "other icon", true, false, 5);
4605
4606 SigReceiver sig_receiver(entry);
4607 EXPECT_CALL(sig_receiver, Updated());
4608@@ -83,6 +85,7 @@
4609
4610 EXPECT_EQ(entry.id(), "other_id");
4611 EXPECT_EQ(entry.name_hint(), "other_name_hint");
4612+ EXPECT_EQ(entry.parent_window(), 54321);
4613 EXPECT_EQ(entry.label(), "other_label");
4614 EXPECT_FALSE(entry.label_sensitive());
4615 EXPECT_FALSE(entry.label_visible());
4616@@ -95,8 +98,8 @@
4617
4618 TEST(TestIndicatorEntry, TestShowNowEvents)
4619 {
4620- Entry entry("id", "name_hint", "label", true, true,
4621- 0, "some icon", false, true, -1);
4622+ Entry entry("id", "name_hint", 0, "label", true, true,
4623+ 0, "some icon", false, true, -1);
4624 SigReceiver sig_receiver(entry);
4625
4626 // Setting show_now to the same value doesn't emit any events.
4627@@ -116,7 +119,7 @@
4628
4629 TEST(TestIndicatorEntry, TestActiveEvents)
4630 {
4631- Entry entry("id", "name_hint", "label", true, true, 0, "some icon", false, true, -1);
4632+ Entry entry("id", "name_hint", 0, "label", true, true, 0, "some icon", false, true, -1);
4633
4634 SigReceiver sig_receiver(entry);
4635
4636@@ -137,7 +140,7 @@
4637
4638 TEST(TestIndicatorEntry, TestOnScroll)
4639 {
4640- Entry entry("id", "name_hint", "label", true, true, 0, "some icon", false, true, -1);
4641+ Entry entry("id", "name_hint", 0, "label", true, true, 0, "some icon", false, true, -1);
4642 SigReceiver sig_receiver(entry);
4643
4644 EXPECT_CALL(sig_receiver, OnScroll("id", 10));
4645@@ -149,16 +152,16 @@
4646
4647 TEST(TestIndicatorEntry, TestOnShowMenu)
4648 {
4649- Entry entry("id", "name_hint", "label", true, true, 0, "some icon", false, true, -1);
4650+ Entry entry("id", "name_hint", 123, "label", true, true, 0, "some icon", false, true, -1);
4651 SigReceiver sig_receiver(entry);
4652
4653- EXPECT_CALL(sig_receiver, OnShowMenu("id", 0, 10, 20, 1));
4654+ EXPECT_CALL(sig_receiver, OnShowMenu("id", 123, 10, 20, 1));
4655 entry.ShowMenu(10, 20, 1);
4656 }
4657
4658 TEST(TestIndicatorEntry, TestOnShowMenuXid)
4659 {
4660- Entry entry("xid", "name_hint", "label", true, true, 0, "some icon", false, true, -1);
4661+ Entry entry("xid", "name_hint", 0, "label", true, true, 0, "some icon", false, true, -1);
4662 SigReceiver sig_receiver(entry);
4663
4664 EXPECT_CALL(sig_receiver, OnShowMenu("xid", 88492615, 15, 25, 2));
4665@@ -167,7 +170,7 @@
4666
4667 TEST(TestIndicatorEntry, TestVisibility)
4668 {
4669- Entry entry("id", "name_hint", "label", true, true, 0, "some icon", false, false, -1);
4670+ Entry entry("id", "name_hint", 0, "label", true, true, 0, "some icon", false, false, -1);
4671
4672 EXPECT_TRUE(entry.visible());
4673
4674@@ -208,7 +211,7 @@
4675
4676 TEST(TestIndicatorEntry, TestGeometry)
4677 {
4678- Entry entry("id", "name_hint", "label", true, true, 0, "some icon", false, true, -1);
4679+ Entry entry("id", "name_hint", 0, "label", true, true, 0, "some icon", false, true, -1);
4680 SigReceiver sig_receiver(entry);
4681
4682 // Setting to the same value doesn't emit any events.
4683
4684=== modified file 'tests/test_indicators.cpp'
4685--- tests/test_indicators.cpp 2014-02-11 03:11:47 +0000
4686+++ tests/test_indicators.cpp 2015-02-19 19:24:14 +0000
4687@@ -62,15 +62,15 @@
4688
4689 Indicator::Ptr test_indicator_1 = indicators.AddIndicator("indicator-test-1");
4690
4691- entry = new Entry("indicator-test-1|entry-1", "name-hint-1", "label", true, true,
4692- 0, "icon", true, true, -1);
4693- sync_data.push_back(Entry::Ptr(entry));
4694-
4695- entry = new Entry("indicator-test-1|entry-2", "name-hint-2", "label", true, true,
4696- 0, "icon", true, true, -1);
4697- sync_data.push_back(Entry::Ptr(entry));
4698-
4699- entry = new Entry("indicator-test-1|entry-3", "name-hint-3", "label", true, true,
4700+ entry = new Entry("indicator-test-1|entry-1", "name-hint-1", 0, "label", true, true,
4701+ 0, "icon", true, true, -1);
4702+ sync_data.push_back(Entry::Ptr(entry));
4703+
4704+ entry = new Entry("indicator-test-1|entry-2", "name-hint-2", 0, "label", true, true,
4705+ 0, "icon", true, true, -1);
4706+ sync_data.push_back(Entry::Ptr(entry));
4707+
4708+ entry = new Entry("indicator-test-1|entry-3", "name-hint-3", 0, "label", true, true,
4709 0, "icon", true, true, -1);
4710 sync_data.push_back(Entry::Ptr(entry));
4711
4712@@ -83,11 +83,11 @@
4713 Indicator::Ptr test_indicator_2 = indicators.AddIndicator("indicator-test-2");
4714 sync_data.clear();
4715
4716- entry = new Entry("indicator-test-2|entry-1", "name-hint-1", "label", true, true,
4717+ entry = new Entry("indicator-test-2|entry-1", "name-hint-1", 0, "label", true, true,
4718 0, "icon", true, true, -1);
4719 sync_data.push_back(Entry::Ptr(entry));
4720
4721- entry = new Entry("indicator-test-2|entry-2", "name-hint-2", "label", true, true,
4722+ entry = new Entry("indicator-test-2|entry-2", "name-hint-2", 0, "label", true, true,
4723 0, "icon", true, true, -1);
4724 sync_data.push_back(Entry::Ptr(entry));
4725
4726
4727=== modified file 'tests/test_panel_menu_view.cpp'
4728--- tests/test_panel_menu_view.cpp 2014-03-21 04:40:12 +0000
4729+++ tests/test_panel_menu_view.cpp 2015-02-19 19:24:14 +0000
4730@@ -36,11 +36,22 @@
4731
4732 struct TestPanelMenuView : public testing::Test
4733 {
4734+ TestPanelMenuView()
4735+ : menu_manager(std::make_shared<menu::MockManager>())
4736+ , menu_view(menu_manager)
4737+ {}
4738+
4739 struct MockPanelMenuView : public PanelMenuView
4740 {
4741- MockPanelMenuView()
4742- : PanelMenuView(std::make_shared<menu::MockManager>())
4743- {}
4744+ MockPanelMenuView(menu::Manager::Ptr const& menu_manager)
4745+ : PanelMenuView(menu_manager)
4746+ {
4747+ view_opened_signal_.Disconnect();
4748+ active_win_changed_signal_.Disconnect();
4749+ active_app_changed_signal_.Disconnect();
4750+ view_closed_signal_.Disconnect();
4751+ maximized_wins_.clear();
4752+ }
4753
4754 MOCK_METHOD0(QueueDraw, void());
4755 MOCK_CONST_METHOD1(GetActiveViewName, std::string(bool));
4756@@ -53,6 +64,7 @@
4757 using PanelMenuView::titlebar_grab_area_;
4758 using PanelMenuView::we_control_active_;
4759 using PanelMenuView::spread_showing_;
4760+ using PanelMenuView::maximized_wins_;
4761 };
4762
4763 nux::ObjectPtr<nux::BaseWindow> AddPanelToWindow(int monitor)
4764@@ -69,6 +81,7 @@
4765 panel_win->ComputeContentSize();
4766
4767 menu_view.SetMonitor(monitor);
4768+ menu_view.maximized_wins_.clear();
4769
4770 return panel_win;
4771 }
4772@@ -79,6 +92,7 @@
4773 MockUScreen uscreen;
4774 panel::Style panelStyle;
4775 testwrapper::StandaloneWM WM;
4776+ menu::MockManager::Ptr menu_manager;
4777 testing::NiceMock<MockPanelMenuView> menu_view;
4778 };
4779
4780@@ -91,6 +105,7 @@
4781
4782 TEST_F(TestPanelMenuView, Escaping)
4783 {
4784+ menu_manager->integrated_menus = false;
4785 ON_CALL(menu_view, GetActiveViewName(testing::_)).WillByDefault(Return("<>'"));
4786 auto escapedText = "Panel d'Inici";
4787 ASSERT_TRUE(menu_view.GetCurrentTitle().empty());
4788@@ -136,6 +151,7 @@
4789 TEST_P(ProgressTester, RestoreOnGrabInBiggerWorkArea)
4790 {
4791 uscreen.SetupFakeMultiMonitor();
4792+ connection::Manager conn;
4793 unsigned monitor = uscreen.GetMonitors().size() - 1;
4794 auto const& monitor_geo = uscreen.GetMonitorGeometry(monitor);
4795 WM->SetWorkareaGeometry(monitor_geo);
4796
4797=== modified file 'tests/test_panel_service.cpp'
4798--- tests/test_panel_service.cpp 2013-10-03 15:16:06 +0000
4799+++ tests/test_panel_service.cpp 2015-02-19 19:24:14 +0000
4800@@ -32,8 +32,8 @@
4801 {
4802 typedef std::tuple<glib::Object<GtkLabel>, glib::Object<GtkImage>> EntryObjects;
4803
4804-const std::string SYNC_ENTRY_VARIANT_FORMAT = "(ssssbbusbbi)";
4805-const std::string SYNC_ENTRIES_VARIANT_FORMAT = "(a"+SYNC_ENTRY_VARIANT_FORMAT+")";
4806+const std::string SYNC_ENTRY_VARIANT_FORMAT = ENTRY_SIGNATURE;
4807+const std::string SYNC_ENTRIES_VARIANT_FORMAT = "(" ENTRY_ARRAY_SIGNATURE ")";
4808
4809 struct TestPanelService : Test
4810 {
4811@@ -46,6 +46,7 @@
4812 std::string indicator_id;
4813 std::string entry_id;
4814 std::string entry_name_hint;
4815+ uint32_t parent_window;
4816 std::string label;
4817 bool label_sensitive;
4818 bool label_visible;
4819@@ -63,6 +64,7 @@
4820 gchar* indicator_id;
4821 gchar* entry_id;
4822 gchar* entry_name_hint;
4823+ guint32 parent_window;
4824 gchar* label;
4825 gboolean label_sensitive;
4826 gboolean label_visible;
4827@@ -77,6 +79,7 @@
4828 &indicator_id,
4829 &entry_id,
4830 &entry_name_hint,
4831+ &parent_window,
4832 &label,
4833 &label_sensitive,
4834 &label_visible,
4835@@ -89,6 +92,7 @@
4836 results.push_back({ glib::gchar_to_string(indicator_id),
4837 glib::gchar_to_string(entry_id),
4838 glib::gchar_to_string(entry_name_hint),
4839+ parent_window,
4840 glib::gchar_to_string(label),
4841 label_sensitive != FALSE,
4842 label_visible != FALSE,
4843
4844=== modified file 'tests/test_service_panel.cpp'
4845--- tests/test_service_panel.cpp 2013-03-02 22:44:29 +0000
4846+++ tests/test_service_panel.cpp 2015-02-19 19:24:14 +0000
4847@@ -1,4 +1,5 @@
4848 #include "test_service_panel.h"
4849+#include "panel-service-private.h"
4850
4851 namespace unity
4852 {
4853@@ -9,11 +10,11 @@
4854 static const char * panel_interface =
4855 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
4856 "<node name=\"/\">\n"
4857-" <interface name=\"com.canonical.Unity.Panel.Service\">\n"
4858+" <interface name=\"" UPS_IFACE "\">\n"
4859 "\n"
4860 "<!-- Begin of real methods/signals -->\n"
4861 " <method name='Sync'>"
4862-" <arg type='a(ssssbbusbbi)' name='state' direction='out'/>"
4863+" <arg type='" ENTRY_ARRAY_SIGNATURE "' name='state' direction='out'/>"
4864 " </method>"
4865 "\n"
4866 " <signal name='ReSync'>"
4867@@ -32,12 +33,13 @@
4868 "</node>\n"
4869 ;
4870
4871-void add_entry_id(GVariantBuilder *b)
4872+void add_entry_id(GVariantBuilder *b, gint priority)
4873 {
4874- g_variant_builder_add (b, "(ssssbbusbbi)",
4875+ g_variant_builder_add (b, ENTRY_SIGNATURE,
4876 "test_indicator_id",
4877 "test_entry_id",
4878 "test_entry_name_hint",
4879+ 0, /* parent window */
4880 "test_entry_label",
4881 TRUE, /* label sensitive */
4882 TRUE, /* label visible */
4883@@ -45,15 +47,16 @@
4884 "", /* image_data */
4885 TRUE, /* image sensitive */
4886 TRUE, /* image visible */
4887- 1 /* priority */);
4888+ priority);
4889 }
4890
4891-void add_entry_id_2(GVariantBuilder *b)
4892+void add_entry_id_2(GVariantBuilder *b, gint priority)
4893 {
4894- g_variant_builder_add (b, "(ssssbbusbbi)",
4895+ g_variant_builder_add (b, ENTRY_SIGNATURE,
4896 "test_indicator_id",
4897 "test_entry_id2",
4898 "test_entry_name_hint2",
4899+ 12345, /* parent window */
4900 "test_entry_label2",
4901 TRUE, /* label sensitive */
4902 TRUE, /* label visible */
4903@@ -61,7 +64,7 @@
4904 "", /* image_data */
4905 TRUE, /* image sensitive */
4906 TRUE, /* image visible */
4907- 1 /* priority */);
4908+ priority);
4909 }
4910 }
4911
4912@@ -73,7 +76,7 @@
4913 auto object = glib::DBusObjectBuilder::GetObjectsForIntrospection(panel_interface).front();
4914 object->SetMethodsCallsHandler(sigc::mem_fun(this, &Panel::OnMethodCall));
4915
4916- server_.AddObject(object, "/com/canonical/Unity/Panel/Service");
4917+ server_.AddObject(object, UPS_PATH);
4918 }
4919
4920 GVariant* Panel::OnMethodCall(std::string const& method, GVariant *parameters)
4921@@ -82,18 +85,18 @@
4922 {
4923 GVariantBuilder b;
4924
4925- g_variant_builder_init (&b, G_VARIANT_TYPE ("(a(ssssbbusbbi))"));
4926- g_variant_builder_open (&b, G_VARIANT_TYPE ("a(ssssbbusbbi)"));
4927+ g_variant_builder_init (&b, G_VARIANT_TYPE ("(" ENTRY_ARRAY_SIGNATURE ")"));
4928+ g_variant_builder_open (&b, G_VARIANT_TYPE (ENTRY_ARRAY_SIGNATURE));
4929
4930 if (sync_return_mode_ == 0)
4931 {
4932- add_entry_id(&b);
4933- add_entry_id_2(&b);
4934+ add_entry_id(&b, 1);
4935+ add_entry_id_2(&b, 2);
4936 }
4937 else if (sync_return_mode_ == 1)
4938 {
4939- add_entry_id_2(&b);
4940- add_entry_id(&b);
4941+ add_entry_id_2(&b, 1);
4942+ add_entry_id(&b, 2);
4943 }
4944
4945 if (sync_return_mode_ == 1)
4946
4947=== modified file 'unity-shared/IconLoader.cpp'
4948--- unity-shared/IconLoader.cpp 2015-01-15 14:33:03 +0000
4949+++ unity-shared/IconLoader.cpp 2015-02-19 19:24:14 +0000
4950@@ -799,7 +799,7 @@
4951 bool CoalesceTasksCb();
4952
4953 private:
4954- std::map<std::string, glib::Object<GdkPixbuf>> cache_;
4955+ std::unordered_map<std::string, glib::Object<GdkPixbuf>> cache_;
4956 /* FIXME: the reference counting of IconLoaderTasks with shared pointers
4957 * is currently somewhat broken, and the queued_tasks_ member is what keeps
4958 * it from crashing randomly.
4959@@ -807,7 +807,7 @@
4960 * tasks, but when they are being completed in a worker thread, the thread
4961 * should own them as well (yet it doesn't), this could cause trouble
4962 * in the future... You've been warned! */
4963- std::map<std::string, IconLoaderTask::Ptr> queued_tasks_;
4964+ std::unordered_map<std::string, IconLoaderTask::Ptr> queued_tasks_;
4965 std::queue<IconLoaderTask::Ptr> tasks_;
4966 std::unordered_map<Handle, IconLoaderTask::Ptr> task_map_;
4967 std::vector<IconLoaderTask*> finished_tasks_;
4968
4969=== modified file 'unity-shared/MenuManager.cpp'
4970--- unity-shared/MenuManager.cpp 2015-02-04 11:13:04 +0000
4971+++ unity-shared/MenuManager.cpp 2015-02-19 19:24:14 +0000
4972@@ -26,6 +26,7 @@
4973 #include <unordered_map>
4974
4975 #include "MenuManager.h"
4976+#include "WindowManager.h"
4977
4978 namespace unity
4979 {
4980@@ -48,16 +49,20 @@
4981 : parent_(parent)
4982 , indicators_(indicators)
4983 , key_grabber_(grabber)
4984+ , show_now_window_(0)
4985 , settings_(g_settings_new(SETTINGS_NAME.c_str()))
4986 {
4987 for (auto const& indicator : indicators_->GetIndicators())
4988 AddIndicator(indicator);
4989
4990+ GrabMnemonicsForActiveWindow();
4991+
4992 parent_->show_menus.changed.connect(sigc::mem_fun(this, &Impl::ShowMenus));
4993 indicators_->on_object_added.connect(sigc::mem_fun(this, &Impl::AddIndicator));
4994 indicators_->on_object_removed.connect(sigc::mem_fun(this, &Impl::RemoveIndicator));
4995 indicators_->on_entry_activate_request.connect(sigc::mem_fun(this, &Impl::ActivateRequest));
4996 indicators_->icon_paths_changed.connect(sigc::mem_fun(this, &Impl::IconPathsChanged));
4997+ WindowManager::Default().window_focus_changed.connect(sigc::hide(sigc::mem_fun(this, &Impl::GrabMnemonicsForActiveWindow)));
4998
4999 signals_.Add<void, GSettings*, const gchar*>(settings_, "changed::" + LIM_KEY, [this] (GSettings*, const gchar*) {
5000 parent_->integrated_menus = g_settings_get_boolean(settings_, LIM_KEY.c_str());
The diff has been truncated for viewing.