Merge lp:~3v1n0/unity/launcher-filemanager-integration into lp:unity

Proposed by Marco Trevisan (Treviño) on 2015-12-07
Status: Merged
Approved by: Andrea Azzarone on 2016-01-05
Approved revision: 4113
Merged at revision: 4069
Proposed branch: lp:~3v1n0/unity/launcher-filemanager-integration
Merge into: lp:unity
Prerequisite: lp:~3v1n0/unity/switcher-dynamic-model
Diff against target: 5139 lines (+2020/-1214)
47 files modified
UnityCore/DesktopUtilities.cpp (+5/-0)
UnityCore/DesktopUtilities.h (+1/-0)
UnityCore/GLibDBusProxy.cpp (+3/-3)
debian/control (+1/-0)
launcher/AbstractLauncherIcon.h (+11/-7)
launcher/ApplicationLauncherIcon.cpp (+118/-685)
launcher/ApplicationLauncherIcon.h (+51/-94)
launcher/CMakeLists.txt (+3/-0)
launcher/DesktopLauncherIcon.cpp (+5/-0)
launcher/DesktopLauncherIcon.h (+1/-0)
launcher/DeviceLauncherSection.h (+4/-0)
launcher/FileManagerLauncherIcon.cpp (+128/-0)
launcher/FileManagerLauncherIcon.h (+52/-0)
launcher/Launcher.cpp (+2/-9)
launcher/LauncherController.cpp (+24/-7)
launcher/LauncherControllerPrivate.h (+2/-1)
launcher/LauncherIcon.cpp (+12/-2)
launcher/LauncherIcon.h (+14/-10)
launcher/MockLauncherIcon.h (+38/-28)
launcher/SoftwareCenterLauncherIcon.cpp (+2/-1)
launcher/StorageLauncherIcon.cpp (+119/-0)
launcher/StorageLauncherIcon.h (+55/-0)
launcher/SwitcherController.cpp (+4/-7)
launcher/SwitcherModel.cpp (+2/-11)
launcher/SwitcherView.cpp (+1/-1)
launcher/TrashLauncherIcon.cpp (+49/-21)
launcher/TrashLauncherIcon.h (+5/-7)
launcher/VolumeLauncherIcon.cpp (+101/-63)
launcher/VolumeLauncherIcon.h (+7/-5)
launcher/WindowedLauncherIcon.cpp (+618/-0)
launcher/WindowedLauncherIcon.h (+100/-0)
tests/CMakeLists.txt (+1/-0)
tests/mock-application.h (+12/-2)
tests/test_application_launcher_icon.cpp (+15/-30)
tests/test_launcher_controller.cpp (+53/-48)
tests/test_mock_filemanager.h (+8/-5)
tests/test_software_center_launcher_icon.cpp (+3/-2)
tests/test_switcher_controller.h (+6/-16)
tests/test_switcher_controller_class.cpp (+9/-18)
tests/test_trash_launcher_icon.cpp (+72/-2)
tests/test_volume_launcher_icon.cpp (+169/-27)
unity-shared/ApplicationManager.h (+3/-0)
unity-shared/BamfApplicationManager.cpp (+8/-4)
unity-shared/BamfApplicationManager.h (+3/-1)
unity-shared/FileManager.h (+5/-6)
unity-shared/GnomeFileManager.cpp (+113/-86)
unity-shared/GnomeFileManager.h (+2/-5)
To merge this branch: bzr merge lp:~3v1n0/unity/launcher-filemanager-integration
Reviewer Review Type Date Requested Status
Andrea Azzarone (community) 2015-12-07 Approve on 2016-01-05
PS Jenkins bot continuous-integration Approve on 2015-12-18
Review via email: mp+279812@code.launchpad.net

Commit message

Launcher: add FileManager, Trash and Volume icons integration

Now the launcher will link each nautilus window to the related volume or trash
icon, while the Nautilus launcher icon will only be active if the file manager is
browsing other locations.
It's now possible to manage sub-windows from the parent icon like it happens for
every other application (so even spreading them or select from QL)

The windows management logic has been moved to WindowedLauncherIcon which is a
base class of ApplicationLauncherIcon, and StorageLauncherIcon.
VolumeLauncherIcon and TrashLauncherIcon are now based on StorageLauncherIcon
which connects to the FileManager to get the windows for a given location.

FileManagerLauncherIcon is now special and is both an ApplicationLauncherIcon
and a StorageLauncherIcon, and uses the parent application only for some tasks.

Lots of random code cleanup included too.

To post a comment you must log in.
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
4101. By Marco Trevisan (Treviño) on 2015-12-08

StorageLauncherIcon: check visibility only for applications icons

4102. By Marco Trevisan (Treviño) on 2015-12-08

Test*LauncherIcon: remove NiceMock for Virtually inherited classes

It doesn't seem to work here because we need to re-call the base class on initialization.

PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
4103. By Marco Trevisan (Treviño) on 2015-12-08

WindowedLauncherIcon: remove unused logger

4104. By Marco Trevisan (Treviño) on 2015-12-08

WindowedLauncherIcon, ApplicationLauncherIcon: remove bamf prefixes

PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
4105. By Marco Trevisan (Treviño) on 2015-12-09

VolumeLauncherIcon: close windows on Eject or Stop

4106. By Marco Trevisan (Treviño) on 2015-12-09

FileManagerLauncherIcon: use the WindowedLauncherIcon Quit definition

PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
4107. By Marco Trevisan (Treviño) on 2015-12-11

TestSwitcherController: implement WindowsOnViewport for FakeLauncherIcon

4108. By Marco Trevisan (Treviño) on 2015-12-11

TestSwitcherController: use WindowedLauncherIcon as base for FakeLauncherIcon and MockApplicationWindow's

PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
4109. By Marco Trevisan (Treviño) on 2015-12-11

GnomeFileManager: don't break the loop when we've found the first window matching location

4110. By Marco Trevisan (Treviño) on 2015-12-11

FileManager: remove the unneeded methods from FileManager

4111. By Marco Trevisan (Treviño) on 2015-12-11

FileManager: remove support multiple locations for window

Although the fielmanager might have multiple tabs opened, we don't care
about knowing them, since we only care of the active one.

PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
4112. By Marco Trevisan (Treviño) on 2015-12-17

debian/control: add nautilus to Recommends

PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
4113. By Marco Trevisan (Treviño) on 2015-12-17

Merging with trunk

PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Andrea Azzarone (azzar1) wrote :

+1. Code looks good and I tested it in the last two weeks and everything works fine.

review: Approve
4114. By Marco Trevisan (Treviño) on 2016-01-14

Merging with trunk

4115. By Marco Trevisan (Treviño) on 2016-02-09

FileManagerLauncherIcon: ignore invisible devices and the ones with invalid URIs

4116. By Marco Trevisan (Treviño) on 2016-02-09

FileManagerLauncherIcon: ignore device icon visibility status, as it won't update promptly

There might be a race (if we don't connect to signals), thus there's no reason of doing this
since the volume icon already covers this case.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'UnityCore/DesktopUtilities.cpp'
2--- UnityCore/DesktopUtilities.cpp 2014-09-23 23:35:43 +0000
3+++ UnityCore/DesktopUtilities.cpp 2016-02-09 10:44:04 +0000
4@@ -90,6 +90,11 @@
5 return "";
6 }
7
8+std::string DesktopUtilities::GetUserTrashDirectory()
9+{
10+ return GetUserDataDirectory().append(G_DIR_SEPARATOR_S "Trash" G_DIR_SEPARATOR_S "files" G_DIR_SEPARATOR_S);
11+}
12+
13 std::vector<std::string> DesktopUtilities::GetSystemDataDirectories()
14 {
15 const char* const* system_dirs = g_get_system_data_dirs();
16
17=== modified file 'UnityCore/DesktopUtilities.h'
18--- UnityCore/DesktopUtilities.h 2014-08-26 22:59:57 +0000
19+++ UnityCore/DesktopUtilities.h 2016-02-09 10:44:04 +0000
20@@ -33,6 +33,7 @@
21 static std::string GetUserCacheDirectory();
22 static std::string GetUserRuntimeDirectory();
23 static std::string GetUserConfigDirectory();
24+ static std::string GetUserTrashDirectory();
25 static std::vector<std::string> GetSystemDataDirectories();
26 static std::vector<std::string> GetDataDirectories();
27
28
29=== modified file 'UnityCore/GLibDBusProxy.cpp'
30--- UnityCore/GLibDBusProxy.cpp 2015-09-30 16:32:38 +0000
31+++ UnityCore/GLibDBusProxy.cpp 2016-02-09 10:44:04 +0000
32@@ -301,7 +301,7 @@
33 }
34 }
35
36- g_variant_iter_free (iter);
37+ g_variant_iter_free(iter);
38 }
39
40 for (const gchar *property_name = *invalidated; property_name; property_name = *(++invalidated))
41@@ -624,7 +624,7 @@
42 [] (GObject *source, GAsyncResult *res, gpointer user_data) {
43 glib::Error err;
44 std::unique_ptr<ReplyCallback> callback(static_cast<ReplyCallback*>(user_data));
45- Variant result(g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &err));
46+ Variant result(g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &err), StealRef());
47
48 if (err)
49 {
50@@ -660,7 +660,7 @@
51 nullptr, G_DBUS_CALL_FLAGS_NONE, -1, pimpl->cancellable_,
52 [] (GObject *source, GAsyncResult *res, gpointer user_data) {
53 glib::Error err;
54- Variant result(g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &err));
55+ Variant result(g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &err), StealRef());
56 if (err)
57 {
58 LOG_ERROR(logger) << "Impossible to set property: " << err;
59
60=== modified file 'debian/control'
61--- debian/control 2016-02-08 20:34:08 +0000
62+++ debian/control 2016-02-09 10:44:04 +0000
63@@ -83,6 +83,7 @@
64 Provides: indicator-renderer
65 Recommends: unity-control-center,
66 ${unity-default-masterscopes}
67+ nautilus,
68 indicator-appmenu (>= 15.02.0),
69 indicator-application,
70 indicator-sound,
71
72=== modified file 'launcher/AbstractLauncherIcon.h'
73--- launcher/AbstractLauncherIcon.h 2015-11-02 18:08:08 +0000
74+++ launcher/AbstractLauncherIcon.h 2016-02-09 10:44:04 +0000
75@@ -174,13 +174,17 @@
76
77 virtual WindowList Windows() = 0;
78
79- virtual std::vector<Window> WindowsForMonitor(int monitor) = 0;
80-
81- virtual std::vector<Window> WindowsOnViewport() = 0;
82-
83- virtual const bool WindowVisibleOnMonitor(int monitor) = 0;
84-
85- virtual const bool WindowVisibleOnViewport() = 0;
86+ virtual WindowList WindowsForMonitor(int monitor) = 0;
87+
88+ virtual WindowList WindowsOnViewport() = 0;
89+
90+ virtual bool WindowVisibleOnMonitor(int monitor) const = 0;
91+
92+ virtual bool WindowVisibleOnViewport() const = 0;
93+
94+ virtual size_t WindowsVisibleOnMonitor(int monitor) const = 0;
95+
96+ virtual size_t WindowsVisibleOnViewport() const = 0;
97
98 virtual float PresentUrgency() = 0;
99
100
101=== modified file 'launcher/ApplicationLauncherIcon.cpp'
102--- launcher/ApplicationLauncherIcon.cpp 2015-12-11 12:45:28 +0000
103+++ launcher/ApplicationLauncherIcon.cpp 2016-02-09 10:44:04 +0000
104@@ -1,6 +1,6 @@
105 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
106 /*
107- * Copyright (C) 2010-2012 Canonical Ltd
108+ * Copyright (C) 2010-2015 Canonical Ltd
109 *
110 * This program is free software: you can redistribute it and/or modify
111 * it under the terms of the GNU General Public License version 3 as
112@@ -19,10 +19,8 @@
113 */
114
115 #include "config.h"
116-#include <boost/algorithm/string.hpp>
117
118 #include <Nux/Nux.h>
119-#include <Nux/BaseWindow.h>
120 #include <NuxCore/Logger.h>
121
122 #include <UnityCore/GLibWrapper.h>
123@@ -30,12 +28,7 @@
124
125 #include "ApplicationLauncherIcon.h"
126 #include "FavoriteStore.h"
127-#include "MultiMonitor.h"
128 #include "unity-shared/DesktopApplicationManager.h"
129-#include "unity-shared/GnomeFileManager.h"
130-#include "unity-shared/UBusWrapper.h"
131-#include "unity-shared/UBusMessages.h"
132-#include "unity-shared/UScreen.h"
133
134 #include <glib/gi18n-lib.h>
135 #include <gio/gdesktopappinfo.h>
136@@ -44,15 +37,13 @@
137 {
138 namespace launcher
139 {
140+namespace
141+{
142 DECLARE_LOGGER(logger, "unity.launcher.icon.application");
143-namespace
144-{
145-// We use the "bamf-" prefix since the manager is protected, to avoid name clash
146-const std::string ICON_REMOVE_TIMEOUT = "bamf-icon-remove";
147-const std::string ICON_DND_OVER_TIMEOUT = "bamf-icon-dnd-over";
148+
149+// We use the "application-" prefix since the manager is protected, to avoid name clash
150+const std::string ICON_REMOVE_TIMEOUT = "application-icon-remove";
151 const std::string DEFAULT_ICON = "application-default-icon";
152-const int MAXIMUM_QUICKLIST_WIDTH = 300;
153-const int COMPIZ_SCALE_DND_SPREAD = 1 << 7;
154
155 enum MenuItemType
156 {
157@@ -67,10 +58,8 @@
158 NUX_IMPLEMENT_OBJECT_TYPE(ApplicationLauncherIcon);
159
160 ApplicationLauncherIcon::ApplicationLauncherIcon(ApplicationPtr const& app)
161- : SimpleLauncherIcon(IconType::APPLICATION)
162- , _startup_notification_timestamp(0)
163- , _last_scroll_timestamp(0)
164- , _progressive_scroll(0)
165+ : WindowedLauncherIcon(IconType::APPLICATION)
166+ , startup_notification_timestamp_(0)
167 , use_custom_bg_color_(false)
168 , bg_color_(nux::color::White)
169 {
170@@ -83,13 +72,6 @@
171 << ", running: " << (app->running() ? "yes" : "no");
172
173 SetApplication(app);
174-
175- WindowManager& wm = WindowManager::Default();
176- wm.window_minimized.connect(sigc::mem_fun(this, &ApplicationLauncherIcon::OnWindowMinimized));
177- wm.screen_viewport_switch_ended.connect(sigc::mem_fun(this, &ApplicationLauncherIcon::EnsureWindowState));
178- wm.terminate_expo.connect(sigc::mem_fun(this, &ApplicationLauncherIcon::EnsureWindowState));
179- UScreen::GetDefault()->changed.connect(sigc::hide(sigc::hide(sigc::mem_fun(this, &ApplicationLauncherIcon::EnsureWindowsLocation))));
180-
181 EnsureWindowsLocation();
182 }
183
184@@ -157,23 +139,19 @@
185 signals_conn_.Add(app_->window_opened.connect([this](ApplicationWindowPtr const& win) {
186 signals_conn_.Add(win->monitor.changed.connect([this] (int) { EnsureWindowsLocation(); }));
187 EnsureWindowsLocation();
188-
189- if (WindowManager::Default().IsScaleActiveForGroup() && IsActive())
190- Spread(true, 0, false);
191 }));
192
193- auto ensure_win_location_cb = sigc::hide(sigc::mem_fun(this, &ApplicationLauncherIcon::EnsureWindowsLocation));
194- signals_conn_.Add(app_->window_closed.connect(ensure_win_location_cb));
195+ signals_conn_.Add(app_->window_closed.connect([this] (ApplicationWindowPtr const&) { EnsureWindowsLocation(); }));
196
197 for (auto& win : app_->GetWindows())
198- signals_conn_.Add(win->monitor.changed.connect(ensure_win_location_cb));
199+ signals_conn_.Add(win->monitor.changed.connect([this] (int) { EnsureWindowsLocation(); }));
200
201- signals_conn_.Add(app_->urgent.changed.connect([this](bool const& urgent) {
202+ signals_conn_.Add(app_->urgent.changed.connect([this](bool urgent) {
203 LOG_DEBUG(logger) << tooltip_text() << " urgent now " << (urgent ? "true" : "false");
204 SetQuirk(Quirk::URGENT, urgent);
205 }));
206
207- signals_conn_.Add(app_->active.changed.connect([this](bool const& active) {
208+ signals_conn_.Add(app_->active.changed.connect([this](bool active) {
209 LOG_DEBUG(logger) << tooltip_text() << " active now " << (active ? "true" : "false");
210 SetQuirk(Quirk::ACTIVE, active);
211 }));
212@@ -185,8 +163,8 @@
213
214 signals_conn_.Add(app_->title.changed.connect([this](std::string const& name) {
215 LOG_DEBUG(logger) << tooltip_text() << " name now " << name;
216- if (_menu_items.size() == MenuItemType::SIZE)
217- _menu_items[MenuItemType::APP_NAME] = nullptr;
218+ if (menu_items_.size() == MenuItemType::SIZE)
219+ menu_items_[MenuItemType::APP_NAME] = nullptr;
220 tooltip_text = name;
221 }));
222
223@@ -195,7 +173,7 @@
224 icon_name = (icon.empty() ? DEFAULT_ICON : icon);
225 }));
226
227- signals_conn_.Add(app_->running.changed.connect([this](bool const& running) {
228+ signals_conn_.Add(app_->running.changed.connect([this](bool running) {
229 LOG_DEBUG(logger) << tooltip_text() << " running now " << (running ? "true" : "false");
230 SetQuirk(Quirk::RUNNING, running);
231
232@@ -208,35 +186,47 @@
233 }
234 }));
235
236- signals_conn_.Add(app_->visible.changed.connect([this](bool const& visible) {
237+ signals_conn_.Add(app_->visible.changed.connect([this](bool visible) {
238 SetQuirk(Quirk::VISIBLE, IsSticky() ? true : visible);
239 }));
240
241- signals_conn_.Add(app_->closed.connect([this]() {
242- if (!IsSticky())
243- {
244- SetQuirk(Quirk::VISIBLE, false);
245- HideTooltip();
246-
247- /* Use a timeout to remove the icon, this avoids
248- * that we remove an application that is going
249- * to be reopened soon. So applications that
250- * have a splash screen won't be removed from
251- * the launcher while the splash is closed and
252- * a new window is opened. */
253- _source_manager.AddTimeoutSeconds(1, [this] {
254- Remove();
255- return false;
256- }, ICON_REMOVE_TIMEOUT);
257- }
258+ signals_conn_.Add(app_->closed.connect([this] {
259+ LOG_DEBUG(logger) << tooltip_text() << " closed";
260+ OnApplicationClosed();
261 }));
262 }
263
264+WindowList ApplicationLauncherIcon::GetManagedWindows() const
265+{
266+ return app_ ? app_->GetWindows() : WindowList();
267+}
268+
269+void ApplicationLauncherIcon::OnApplicationClosed()
270+{
271+ if (IsSticky())
272+ return;
273+
274+ SetQuirk(Quirk::VISIBLE, false);
275+ HideTooltip();
276+
277+ /* Use a timeout to remove the icon, this avoids
278+ * that we remove an application that is going
279+ * to be reopened soon. So applications that
280+ * have a splash screen won't be removed from
281+ * the launcher while the splash is closed and
282+ * a new window is opened. */
283+ _source_manager.AddTimeoutSeconds(1, [this] {
284+ Remove();
285+ return false;
286+ }, ICON_REMOVE_TIMEOUT);
287+}
288+
289+// Move to WindowedLauncherIcon?!
290 bool ApplicationLauncherIcon::GetQuirk(AbstractLauncherIcon::Quirk quirk, int monitor) const
291 {
292 if (quirk == Quirk::ACTIVE)
293 {
294- if (!SimpleLauncherIcon::GetQuirk(Quirk::ACTIVE, monitor))
295+ if (!WindowedLauncherIcon::GetQuirk(Quirk::ACTIVE, monitor))
296 return false;
297
298 if (app_->type() == AppType::WEBAPP)
299@@ -248,304 +238,35 @@
300 return app_->OwnsWindow(WindowManager::Default().GetActiveWindow());
301 }
302
303- return SimpleLauncherIcon::GetQuirk(quirk, monitor);
304+ return WindowedLauncherIcon::GetQuirk(quirk, monitor);
305 }
306
307 void ApplicationLauncherIcon::Remove()
308 {
309 LogUnityEvent(ApplicationEventType::LEAVE);
310 UnsetApplication();
311- SimpleLauncherIcon::Remove();
312+ WindowedLauncherIcon::Remove();
313 }
314
315 bool ApplicationLauncherIcon::IsSticky() const
316 {
317 if (app_)
318- return app_->sticky() && SimpleLauncherIcon::IsSticky();
319+ return app_->sticky() && WindowedLauncherIcon::IsSticky();
320
321 return false;
322 }
323
324-bool ApplicationLauncherIcon::IsActive() const
325-{
326- return GetQuirk(Quirk::ACTIVE);
327-}
328-
329-bool ApplicationLauncherIcon::IsRunning() const
330-{
331- return GetQuirk(Quirk::RUNNING);
332-}
333-
334-bool ApplicationLauncherIcon::IsUrgent() const
335-{
336- return GetQuirk(Quirk::URGENT);
337-}
338-
339-void ApplicationLauncherIcon::ActivateLauncherIcon(ActionArg arg)
340-{
341- SimpleLauncherIcon::ActivateLauncherIcon(arg);
342- WindowManager& wm = WindowManager::Default();
343-
344- // This is a little awkward as the target is only set from the switcher.
345- if (arg.target)
346- {
347- // thumper: should we Raise too? should the WM raise?
348- wm.Activate(arg.target);
349- return;
350- }
351-
352- bool scale_was_active = wm.IsScaleActive();
353- bool active = IsActive();
354- bool user_visible = IsRunning();
355- /* We should check each child to see if there is
356- * an unmapped (!= minimized) window around and
357- * if so force "Focus" behaviour */
358-
359- if (arg.source != ActionArg::Source::SWITCHER)
360- {
361- user_visible = app_->visible();
362-
363- if (active)
364- {
365- bool any_visible = false;
366- bool any_mapped = false;
367- bool any_on_top = false;
368- bool any_on_monitor = (arg.monitor < 0);
369- int active_monitor = arg.monitor;
370-
371- for (auto const& window : app_->GetWindows())
372- {
373- Window xid = window->window_id();
374-
375- if (!any_visible && wm.IsWindowOnCurrentDesktop(xid))
376- {
377- any_visible = true;
378- }
379-
380- if (!any_mapped && wm.IsWindowMapped(xid))
381- {
382- any_mapped = true;
383- }
384-
385- if (!any_on_top && wm.IsWindowOnTop(xid))
386- {
387- any_on_top = true;
388- }
389-
390- if (!any_on_monitor && window->monitor() == arg.monitor &&
391- wm.IsWindowMapped(xid) && wm.IsWindowVisible(xid))
392- {
393- any_on_monitor = true;
394- }
395-
396- if (window->active())
397- {
398- active_monitor = window->monitor();
399- }
400- }
401-
402- if (!any_visible || !any_mapped || !any_on_top)
403- active = false;
404-
405- if (any_on_monitor && arg.monitor >= 0 && active_monitor != arg.monitor)
406- active = false;
407- }
408-
409- if (user_visible && IsSticky() && IsFileManager())
410- {
411- // See bug #753938
412- unsigned minimum_windows = 0;
413- auto const& file_manager = GnomeFileManager::Get();
414-
415- if (file_manager->IsTrashOpened())
416- ++minimum_windows;
417-
418- if (file_manager->IsDeviceOpened())
419- ++minimum_windows;
420-
421- if (minimum_windows > 0)
422- {
423- if (file_manager->OpenedLocations().size() == minimum_windows &&
424- GetWindows(WindowFilter::USER_VISIBLE|WindowFilter::MAPPED).size() == minimum_windows)
425- {
426- user_visible = false;
427- }
428- }
429- }
430- }
431-
432- /* Behaviour:
433- * 1) Nothing running, or nothing visible -> launch application
434- * 2) Running and active -> spread application
435- * 3) Running and not active -> focus application
436- * 4) Spread is active and different icon pressed -> change spread
437- * 5) Spread is active -> Spread de-activated, and fall through
438- */
439-
440- if (!IsRunning() || (IsRunning() && !user_visible)) // #1 above
441- {
442- if (GetQuirk(Quirk::STARTING, arg.monitor))
443- return;
444-
445- wm.TerminateScale();
446- SetQuirk(Quirk::STARTING, true, arg.monitor);
447- OpenInstanceLauncherIcon(arg.timestamp);
448- }
449- else // app is running
450- {
451- if (active)
452- {
453- if (scale_was_active) // #5 above
454- {
455- wm.TerminateScale();
456-
457- if (minimize_window_on_click())
458- {
459- for (auto const& win : GetWindows(WindowFilter::ON_CURRENT_DESKTOP))
460- wm.Minimize(win->window_id());
461- }
462- else
463- {
464- Focus(arg);
465- }
466- }
467- else // #2 above
468- {
469- if (arg.source != ActionArg::Source::SWITCHER)
470- {
471- bool minimized = false;
472-
473- if (minimize_window_on_click())
474- {
475- WindowList const& windows = GetWindows(WindowFilter::ON_CURRENT_DESKTOP);
476-
477- if (windows.size() == 1)
478- {
479- wm.Minimize(windows[0]->window_id());
480- minimized = true;
481- }
482- }
483-
484- if (!minimized)
485- {
486- Spread(true, 0, false);
487- }
488- }
489- }
490- }
491- else
492- {
493- if (scale_was_active) // #4 above
494- {
495- if (GetWindows(WindowFilter::ON_CURRENT_DESKTOP).size() <= 1)
496- wm.TerminateScale();
497-
498- Focus(arg);
499-
500- if (arg.source != ActionArg::Source::SWITCHER)
501- Spread(true, 0, false);
502- }
503- else // #3 above
504- {
505- Focus(arg);
506- }
507- }
508- }
509-}
510-
511-WindowList ApplicationLauncherIcon::GetWindows(WindowFilterMask filter, int monitor)
512-{
513- WindowManager& wm = WindowManager::Default();
514- WindowList results;
515-
516- monitor = (filter & WindowFilter::ON_ALL_MONITORS) ? -1 : monitor;
517- bool mapped = (filter & WindowFilter::MAPPED);
518- bool user_visible = (filter & WindowFilter::USER_VISIBLE);
519- bool current_desktop = (filter & WindowFilter::ON_CURRENT_DESKTOP);
520-
521- for (auto& window : app_->GetWindows())
522- {
523- if ((monitor >= 0 && window->monitor() == monitor) || monitor < 0)
524- {
525- if ((user_visible && window->visible()) || !user_visible)
526- {
527- Window xid = window->window_id();
528-
529- if ((mapped && wm.IsWindowMapped(xid)) || !mapped)
530- {
531- if ((current_desktop && wm.IsWindowOnCurrentDesktop(xid)) || !current_desktop)
532- {
533- results.push_back(window);
534- }
535- }
536- }
537- }
538- }
539-
540- return results;
541-}
542-
543-WindowList ApplicationLauncherIcon::Windows()
544-{
545- return GetWindows(WindowFilter::MAPPED|WindowFilter::ON_ALL_MONITORS);
546-}
547-
548-std::vector<Window> ApplicationLauncherIcon::WindowsOnViewport()
549-{
550- WindowFilterMask filter = 0;
551- filter |= WindowFilter::MAPPED;
552- filter |= WindowFilter::USER_VISIBLE;
553- filter |= WindowFilter::ON_CURRENT_DESKTOP;
554- filter |= WindowFilter::ON_ALL_MONITORS;
555-
556- std::vector<Window> windows;
557- for (auto& window : GetWindows(filter))
558- {
559- windows.push_back(window->window_id());
560- }
561- return windows;
562-}
563-
564-std::vector<Window> ApplicationLauncherIcon::WindowsForMonitor(int monitor)
565-{
566- WindowFilterMask filter = 0;
567- filter |= WindowFilter::MAPPED;
568- filter |= WindowFilter::USER_VISIBLE;
569- filter |= WindowFilter::ON_CURRENT_DESKTOP;
570-
571- std::vector<Window> windows;
572- for (auto& window : GetWindows(filter, monitor))
573- {
574- windows.push_back(window->window_id());
575- }
576- return windows;
577-}
578-
579-void ApplicationLauncherIcon::OnWindowMinimized(guint32 xid)
580-{
581- for (auto const& window: app_->GetWindows())
582- {
583- if (xid == window->window_id())
584- {
585- int monitor = GetCenterForMonitor(window->monitor()).first;
586-
587- if (monitor >= 0)
588- {
589- Present(0.5f, 600, monitor);
590- FullyAnimateQuirkDelayed(300, Quirk::SHIMMER, monitor);
591- }
592-
593- break;
594- }
595- }
596+bool ApplicationLauncherIcon::IsUserVisible() const
597+{
598+ return app_ ? app_->visible() : false;
599 }
600
601 void ApplicationLauncherIcon::UpdateDesktopFile()
602 {
603 std::string const& filename = app_->desktop_file();
604
605- if (_desktop_file_monitor)
606- _gsignals.Disconnect(_desktop_file_monitor, "changed");
607+ if (desktop_file_monitor_)
608+ glib_signals_.Disconnect(desktop_file_monitor_, "changed");
609
610 auto old_uri = RemoteUri();
611 UpdateRemoteUri();
612@@ -559,11 +280,11 @@
613 // we can remove ourself from the launcher and when it's changed
614 // we can update the quicklist.
615 glib::Object<GFile> desktop_file(g_file_new_for_path(filename.c_str()));
616- _desktop_file_monitor = g_file_monitor_file(desktop_file, G_FILE_MONITOR_NONE,
617+ desktop_file_monitor_ = g_file_monitor_file(desktop_file, G_FILE_MONITOR_NONE,
618 nullptr, nullptr);
619- g_file_monitor_set_rate_limit(_desktop_file_monitor, 2000);
620+ g_file_monitor_set_rate_limit(desktop_file_monitor_, 2000);
621
622- _gsignals.Add<void, GFileMonitor*, GFile*, GFile*, GFileMonitorEvent>(_desktop_file_monitor, "changed",
623+ glib_signals_.Add<void, GFileMonitor*, GFile*, GFile*, GFileMonitorEvent>(desktop_file_monitor_, "changed",
624 [this, desktop_file] (GFileMonitor*, GFile*, GFile*, GFileMonitorEvent event_type) {
625 switch (event_type)
626 {
627@@ -600,7 +321,7 @@
628 bool update_saved_uri = (!filename.empty() && app_->sticky());
629
630 if (update_saved_uri)
631- SimpleLauncherIcon::UnStick();
632+ WindowedLauncherIcon::UnStick();
633
634 uri_changed.emit(new_uri);
635
636@@ -614,22 +335,6 @@
637 return app_->desktop_file();
638 }
639
640-void ApplicationLauncherIcon::AddProperties(debug::IntrospectionData& introspection)
641-{
642- SimpleLauncherIcon::AddProperties(introspection);
643-
644- std::vector<Window> xids;
645- for (auto const& window : GetWindows())
646- xids.push_back(window->window_id());
647-
648- introspection
649- .add("desktop_file", DesktopFile())
650- .add("desktop_id", app_->desktop_id())
651- .add("xids", glib::Variant::FromVector(xids))
652- .add("sticky", IsSticky())
653- .add("startup_notification_timestamp", _startup_notification_timestamp);
654-}
655-
656 void ApplicationLauncherIcon::OpenInstanceWithUris(std::set<std::string> const& uris, Time timestamp)
657 {
658 glib::Error error;
659@@ -639,9 +344,9 @@
660 GdkDisplay* display = gdk_display_get_default();
661 glib::Object<GdkAppLaunchContext> app_launch_context(gdk_display_get_app_launch_context(display));
662
663- _startup_notification_timestamp = timestamp;
664- if (_startup_notification_timestamp > 0)
665- gdk_app_launch_context_set_timestamp(app_launch_context, _startup_notification_timestamp);
666+ startup_notification_timestamp_ = timestamp;
667+ if (startup_notification_timestamp_ > 0)
668+ gdk_app_launch_context_set_timestamp(app_launch_context, startup_notification_timestamp_);
669
670 if (g_app_info_supports_uris(appInfo))
671 {
672@@ -705,83 +410,40 @@
673 app_->Focus(show_only_visible, arg.monitor);
674 }
675
676-bool ApplicationLauncherIcon::Spread(bool current_desktop, int state, bool force)
677-{
678- std::vector<Window> windows;
679- for (auto& window : GetWindows(current_desktop ? WindowFilter::ON_CURRENT_DESKTOP : 0))
680- windows.push_back(window->window_id());
681-
682- return WindowManager::Default().ScaleWindowGroup(windows, state, force);
683-}
684-
685-void ApplicationLauncherIcon::EnsureWindowState()
686-{
687- std::vector<int> number_of_windows_on_monitor(monitors::MAX);
688-
689- for (auto& window: app_->GetWindows())
690- {
691- int monitor = window->monitor();
692- Window window_id = window->window_id();
693-
694- if (WindowManager::Default().IsWindowOnCurrentDesktop(window_id))
695- {
696- // If monitor is -1 (or negative), show on all monitors.
697- if (monitor < 0)
698- {
699- for (unsigned j; j < monitors::MAX; ++j)
700- ++number_of_windows_on_monitor[j];
701- }
702- else
703- {
704- ++number_of_windows_on_monitor[monitor];
705- }
706- }
707- }
708-
709- for (unsigned i = 0; i < monitors::MAX; ++i)
710- SetNumberOfWindowsVisibleOnMonitor(number_of_windows_on_monitor[i], i);
711-}
712-
713-void ApplicationLauncherIcon::EnsureWindowsLocation()
714-{
715- EnsureWindowState();
716- UpdateIconGeometries(GetCenters());
717-}
718-
719 void ApplicationLauncherIcon::UpdateDesktopQuickList()
720 {
721 std::string const& desktop_file = DesktopFile();
722
723- if (_menu_desktop_shortcuts)
724+ if (menu_desktop_shortcuts_)
725 {
726- for (GList *l = dbusmenu_menuitem_get_children(_menu_desktop_shortcuts); l; l = l->next)
727+ for (GList *l = dbusmenu_menuitem_get_children(menu_desktop_shortcuts_); l; l = l->next)
728 {
729- _gsignals.Disconnect(l->data, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED);
730+ glib_signals_.Disconnect(l->data, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED);
731 }
732
733- _menu_desktop_shortcuts = nullptr;
734+ menu_desktop_shortcuts_ = nullptr;
735 }
736
737 if (desktop_file.empty())
738 return;
739
740- _menu_desktop_shortcuts = dbusmenu_menuitem_new();
741- dbusmenu_menuitem_set_root(_menu_desktop_shortcuts, TRUE);
742+ menu_desktop_shortcuts_ = dbusmenu_menuitem_new();
743+ dbusmenu_menuitem_set_root(menu_desktop_shortcuts_, TRUE);
744
745 // Build a desktop shortcuts object and tell it that our
746 // environment is Unity to handle the filtering
747- _desktop_shortcuts = indicator_desktop_shortcuts_new(desktop_file.c_str(), "Unity");
748+ desktop_shortcuts_ = indicator_desktop_shortcuts_new(desktop_file.c_str(), "Unity");
749 // This will get us a list of the nicks available, it should
750 // always be at least one entry of NULL if there either aren't
751 // any or they're filtered for the environment we're in
752- const gchar** nicks = indicator_desktop_shortcuts_get_nicks(_desktop_shortcuts);
753+ const gchar** nicks = indicator_desktop_shortcuts_get_nicks(desktop_shortcuts_);
754
755 for (int index = 0; nicks[index]; ++index)
756 {
757 // Build a dbusmenu item for each nick that is the desktop
758 // file that is built from it's name and includes a callback
759 // to the desktop shortcuts object to execute the nick
760- glib::String name(indicator_desktop_shortcuts_nick_get_name(_desktop_shortcuts,
761+ glib::String name(indicator_desktop_shortcuts_nick_get_name(desktop_shortcuts_,
762 nicks[index]));
763 glib::Object<DbusmenuMenuitem> item(dbusmenu_menuitem_new());
764 dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, name);
765@@ -789,16 +451,16 @@
766 dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
767 auto nick = glib::gchar_to_string(nicks[index]);
768
769- _gsignals.Add<void, DbusmenuMenuitem*, gint>(item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
770+ glib_signals_.Add<void, DbusmenuMenuitem*, gint>(item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
771 [this, nick] (DbusmenuMenuitem* item, unsigned timestamp) {
772 GdkDisplay* display = gdk_display_get_default();
773 glib::Object<GdkAppLaunchContext> context(gdk_display_get_app_launch_context(display));
774 gdk_app_launch_context_set_timestamp(context, timestamp);
775 auto gcontext = glib::object_cast<GAppLaunchContext>(context);
776- indicator_desktop_shortcuts_nick_exec_with_context(_desktop_shortcuts, nick.c_str(), gcontext);
777+ indicator_desktop_shortcuts_nick_exec_with_context(desktop_shortcuts_, nick.c_str(), gcontext);
778 });
779
780- dbusmenu_menuitem_child_append(_menu_desktop_shortcuts, item);
781+ dbusmenu_menuitem_child_append(menu_desktop_shortcuts_, item);
782 }
783 }
784
785@@ -821,60 +483,16 @@
786 }
787 }
788
789-void ApplicationLauncherIcon::EnsureMenuItemsWindowsReady()
790-{
791- // delete all menu items for windows
792- _menu_items_windows.clear();
793-
794- auto const& windows = Windows();
795-
796- // We only add quicklist menu-items for windows if we have more than one window
797- if (windows.size() < 2)
798- return;
799-
800- // add menu items for all open windows
801- for (auto const& w : windows)
802- {
803- auto const& title = w->title();
804-
805- if (title.empty())
806- continue;
807-
808- glib::Object<DbusmenuMenuitem> menu_item(dbusmenu_menuitem_new());
809- dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, title.c_str());
810- dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
811- dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
812- dbusmenu_menuitem_property_set_bool(menu_item, QuicklistMenuItem::MARKUP_ACCEL_DISABLED_PROPERTY, true);
813- dbusmenu_menuitem_property_set_int(menu_item, QuicklistMenuItem::MAXIMUM_LABEL_WIDTH_PROPERTY, MAXIMUM_QUICKLIST_WIDTH);
814-
815- Window xid = w->window_id();
816- _gsignals.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
817- [xid] (DbusmenuMenuitem*, unsigned) {
818- WindowManager& wm = WindowManager::Default();
819- wm.Activate(xid);
820- wm.Raise(xid);
821- });
822-
823- if (w->active())
824- {
825- dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, DBUSMENU_MENUITEM_TOGGLE_RADIO);
826- dbusmenu_menuitem_property_set_int(menu_item, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED);
827- }
828-
829- _menu_items_windows.push_back(menu_item);
830- }
831-}
832-
833 void ApplicationLauncherIcon::EnsureMenuItemsStaticQuicklist()
834 {
835 // make a client for desktop file actions
836- if (!_menu_desktop_shortcuts.IsType(DBUSMENU_TYPE_MENUITEM))
837+ if (!menu_desktop_shortcuts_.IsType(DBUSMENU_TYPE_MENUITEM))
838 {
839 UpdateDesktopQuickList();
840 }
841 }
842
843-void ApplicationLauncherIcon::Quit()
844+void ApplicationLauncherIcon::Quit() const
845 {
846 app_->Quit();
847 }
848@@ -899,7 +517,7 @@
849 }
850 else
851 {
852- SimpleLauncherIcon::Stick(save);
853+ WindowedLauncherIcon::Stick(save);
854
855 if (save)
856 LogUnityEvent(ApplicationEventType::ACCESS);
857@@ -912,11 +530,11 @@
858 return;
859
860 LogUnityEvent(ApplicationEventType::ACCESS);
861- SimpleLauncherIcon::UnStick();
862+ WindowedLauncherIcon::UnStick();
863 SetQuirk(Quirk::VISIBLE, app_->visible());
864 app_->sticky = false;
865
866- if (!app_->running())
867+ if (!IsRunning())
868 Remove();
869 }
870
871@@ -956,10 +574,10 @@
872
873 void ApplicationLauncherIcon::EnsureMenuItemsDefaultReady()
874 {
875- if (_menu_items.size() == MenuItemType::SIZE)
876+ if (menu_items_.size() == MenuItemType::SIZE)
877 return;
878
879- _menu_items.resize(MenuItemType::SIZE);
880+ menu_items_.resize(MenuItemType::SIZE);
881
882 /* (Un)Stick to Launcher */
883 glib::Object<DbusmenuMenuitem> menu_item(dbusmenu_menuitem_new());
884@@ -968,12 +586,12 @@
885 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
886 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
887
888- _gsignals.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
889+ glib_signals_.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
890 [this] (DbusmenuMenuitem*, unsigned) {
891 ToggleSticky();
892 });
893
894- _menu_items[MenuItemType::STICK] = menu_item;
895+ menu_items_[MenuItemType::STICK] = menu_item;
896
897 /* Quit */
898 menu_item = dbusmenu_menuitem_new();
899@@ -981,17 +599,17 @@
900 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
901 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
902
903- _gsignals.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
904+ glib_signals_.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
905 [this] (DbusmenuMenuitem*, unsigned) {
906 Quit();
907 });
908
909- _menu_items[MenuItemType::QUIT] = menu_item;
910+ menu_items_[MenuItemType::QUIT] = menu_item;
911
912 /* Separator */
913 menu_item = dbusmenu_menuitem_new();
914 dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
915- _menu_items[MenuItemType::SEPARATOR] = menu_item;
916+ menu_items_[MenuItemType::SEPARATOR] = menu_item;
917 }
918
919 AbstractLauncherIcon::MenuItemsVector ApplicationLauncherIcon::GetMenus()
920@@ -1003,7 +621,7 @@
921 EnsureMenuItemsDefaultReady();
922 EnsureMenuItemsStaticQuicklist();
923
924- for (auto const& menus : {GetRemoteMenus(), _menu_desktop_shortcuts})
925+ for (auto const& menus : {GetRemoteMenus(), menu_desktop_shortcuts_})
926 {
927 if (!menus.IsType(DBUSMENU_TYPE_MENUITEM))
928 continue;
929@@ -1049,11 +667,11 @@
930
931 if (separator_needed)
932 {
933- result.push_back(_menu_items[MenuItemType::SEPARATOR]);
934+ result.push_back(menu_items_[MenuItemType::SEPARATOR]);
935 separator_needed = false;
936 }
937
938- if (!_menu_items[MenuItemType::APP_NAME])
939+ if (!menu_items_[MenuItemType::APP_NAME])
940 {
941 glib::String app_name(g_markup_escape_text(app_->title().c_str(), -1));
942 std::string bold_app_name("<b>"+app_name.Str()+"</b>");
943@@ -1064,7 +682,7 @@
944 dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
945 dbusmenu_menuitem_property_set_bool(item, QuicklistMenuItem::MARKUP_ENABLED_PROPERTY, TRUE);
946
947- _gsignals.Add<void, DbusmenuMenuitem*, unsigned>(item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
948+ glib_signals_.Add<void, DbusmenuMenuitem*, unsigned>(item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
949 [this] (DbusmenuMenuitem*, unsigned timestamp) {
950 _source_manager.AddIdle([this, timestamp] {
951 ActivateLauncherIcon(ActionArg(ActionArg::Source::LAUNCHER, 0, timestamp));
952@@ -1072,25 +690,23 @@
953 });
954 });
955
956- _menu_items[MenuItemType::APP_NAME] = item;
957+ menu_items_[MenuItemType::APP_NAME] = item;
958 }
959
960- result.push_back(_menu_items[MenuItemType::APP_NAME]);
961- result.push_back(_menu_items[MenuItemType::SEPARATOR]);
962-
963- EnsureMenuItemsWindowsReady();
964-
965- if (!_menu_items_windows.empty())
966+ result.push_back(menu_items_[MenuItemType::APP_NAME]);
967+ result.push_back(menu_items_[MenuItemType::SEPARATOR]);
968+
969+ auto const& windows_menu_items = GetWindowsMenuItems();
970+
971+ if (!windows_menu_items.empty())
972 {
973- for (auto const& it : _menu_items_windows)
974- result.push_back(it);
975-
976- result.push_back(_menu_items[MenuItemType::SEPARATOR]);
977+ result.insert(end(result), begin(windows_menu_items), end(windows_menu_items));
978+ result.push_back(menu_items_[MenuItemType::SEPARATOR]);
979 }
980
981 const char* label = !IsSticky() ? _("Lock to Launcher") : _("Unlock from Launcher");
982- dbusmenu_menuitem_property_set(_menu_items[MenuItemType::STICK], DBUSMENU_MENUITEM_PROP_LABEL, label);
983- result.push_back(_menu_items[MenuItemType::STICK]);
984+ dbusmenu_menuitem_property_set(menu_items_[MenuItemType::STICK], DBUSMENU_MENUITEM_PROP_LABEL, label);
985+ result.push_back(menu_items_[MenuItemType::STICK]);
986
987 if (IsRunning())
988 {
989@@ -1102,7 +718,7 @@
990 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
991 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
992
993- _gsignals.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
994+ glib_signals_.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
995 [this] (DbusmenuMenuitem*, unsigned) {
996 app_->CreateLocalDesktopFile();
997 });
998@@ -1111,7 +727,7 @@
999 }
1000
1001 if (!quit_item)
1002- quit_item = _menu_items[MenuItemType::QUIT];
1003+ quit_item = menu_items_[MenuItemType::QUIT];
1004
1005 dbusmenu_menuitem_property_set(quit_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Quit"));
1006 result.push_back(quit_item);
1007@@ -1125,28 +741,7 @@
1008 if (app_->type() == AppType::WEBAPP)
1009 return;
1010
1011- nux::Geometry geo(0, 0, icon_size, icon_size);
1012-
1013- for (auto& window : app_->GetWindows())
1014- {
1015- Window xid = window->window_id();
1016- int monitor = GetCenterForMonitor(window->monitor()).first;
1017-
1018- if (monitor < 0)
1019- {
1020- WindowManager::Default().SetWindowIconGeometry(xid, nux::Geometry());
1021- continue;
1022- }
1023-
1024- geo.x = centers[monitor].x - icon_size / 2;
1025- geo.y = centers[monitor].y - icon_size / 2;
1026- WindowManager::Default().SetWindowIconGeometry(xid, geo);
1027- }
1028-}
1029-
1030-void ApplicationLauncherIcon::OnCenterStabilized(std::vector<nux::Point3> const& centers)
1031-{
1032- UpdateIconGeometries(centers);
1033+ return WindowedLauncherIcon::UpdateIconGeometries(centers);
1034 }
1035
1036 void ApplicationLauncherIcon::UpdateRemoteUri()
1037@@ -1155,69 +750,21 @@
1038
1039 if (!desktop_id.empty())
1040 {
1041- _remote_uri = FavoriteStore::URI_PREFIX_APP + desktop_id;
1042+ remote_uri_ = FavoriteStore::URI_PREFIX_APP + desktop_id;
1043 }
1044 else
1045 {
1046- _remote_uri.clear();
1047+ remote_uri_.clear();
1048 }
1049 }
1050
1051 std::string ApplicationLauncherIcon::GetRemoteUri() const
1052 {
1053- return _remote_uri;
1054-}
1055-
1056-void ApplicationLauncherIcon::OnDndEnter()
1057-{
1058- auto timestamp = nux::GetGraphicsDisplay()->GetCurrentEvent().x11_timestamp;
1059-
1060- _source_manager.AddTimeout(1000, [this, timestamp] {
1061- bool to_spread = GetWindows(WindowFilter::ON_CURRENT_DESKTOP).size() > 1;
1062-
1063- if (!to_spread)
1064- WindowManager::Default().TerminateScale();
1065-
1066- if (!IsRunning())
1067- return false;
1068-
1069- UBusManager::SendMessage(UBUS_OVERLAY_CLOSE_REQUEST);
1070- Focus(ActionArg(ActionArg::Source::LAUNCHER, 1, timestamp));
1071-
1072- if (to_spread)
1073- Spread(true, COMPIZ_SCALE_DND_SPREAD, false);
1074-
1075- return false;
1076- }, ICON_DND_OVER_TIMEOUT);
1077-}
1078-
1079-void ApplicationLauncherIcon::OnDndLeave()
1080-{
1081- _source_manager.Remove(ICON_DND_OVER_TIMEOUT);
1082-}
1083-
1084-bool ApplicationLauncherIcon::IsFileManager()
1085-{
1086- auto const& desktop_file = DesktopFile();
1087-
1088- return boost::algorithm::ends_with(desktop_file, "org.gnome.Nautilus.desktop") ||
1089- boost::algorithm::ends_with(desktop_file, "nautilus.desktop") ||
1090- boost::algorithm::ends_with(desktop_file, "nautilus-folder-handler.desktop") ||
1091- boost::algorithm::ends_with(desktop_file, "nautilus-home.desktop");
1092+ return remote_uri_;
1093 }
1094
1095 bool ApplicationLauncherIcon::OnShouldHighlightOnDrag(DndData const& dnd_data)
1096 {
1097- if (IsFileManager())
1098- {
1099- for (auto const& uri : dnd_data.Uris())
1100- {
1101- if (boost::algorithm::starts_with(uri, "file://"))
1102- return true;
1103- }
1104- return false;
1105- }
1106-
1107 for (auto type : dnd_data.Types())
1108 {
1109 for (auto supported_type : GetSupportedTypes())
1110@@ -1248,28 +795,6 @@
1111 OpenInstanceWithUris(dnd_data.Uris(), timestamp);
1112 }
1113
1114-bool ApplicationLauncherIcon::ShowInSwitcher(bool current)
1115-{
1116- if (!removed() && IsRunning() && IsVisible())
1117- {
1118- // If current is true, we only want to show the current workspace.
1119- if (!current)
1120- {
1121- return true;
1122- }
1123- else
1124- {
1125- for (unsigned i = 0; i < monitors::MAX; ++i)
1126- {
1127- if (WindowVisibleOnMonitor(i))
1128- return true;
1129- }
1130- }
1131- }
1132-
1133- return false;
1134-}
1135-
1136 bool ApplicationLauncherIcon::AllowDetailViewInSwitcher() const
1137 {
1138 return app_->type() != AppType::WEBAPP;
1139@@ -1277,18 +802,11 @@
1140
1141 uint64_t ApplicationLauncherIcon::SwitcherPriority()
1142 {
1143- uint64_t result = 0;
1144 // Webapps always go at the back.
1145 if (app_->type() == AppType::WEBAPP)
1146- return result;
1147-
1148- for (auto& window : app_->GetWindows())
1149- {
1150- Window xid = window->window_id();
1151- result = std::max(result, WindowManager::Default().GetWindowActiveNumber(xid));
1152- }
1153-
1154- return result;
1155+ return 0;
1156+
1157+ return WindowedLauncherIcon::SwitcherPriority();
1158 }
1159
1160 nux::Color ApplicationLauncherIcon::BackgroundColor() const
1161@@ -1296,7 +814,7 @@
1162 if (use_custom_bg_color_)
1163 return bg_color_;
1164
1165- return SimpleLauncherIcon::BackgroundColor();
1166+ return WindowedLauncherIcon::BackgroundColor();
1167 }
1168
1169 const std::set<std::string> ApplicationLauncherIcon::GetSupportedTypes()
1170@@ -1312,103 +830,18 @@
1171 return supported_types;
1172 }
1173
1174-void PerformScrollUp(WindowList const& windows, unsigned int progressive_scroll)
1175-{
1176- if (progressive_scroll == windows.size() - 1)
1177- {
1178- //RestackAbove to preserve Global Stacking Order
1179- WindowManager::Default().RestackBelow(windows.at(0)->window_id(), windows.at(1)->window_id());
1180- WindowManager::Default().RestackBelow(windows.at(1)->window_id(), windows.at(0)->window_id());
1181- windows.back()->Focus();
1182- return;
1183- }
1184-
1185- WindowManager::Default().RestackBelow(windows.at(0)->window_id(), windows.at(progressive_scroll + 1)->window_id());
1186- windows.at(progressive_scroll + 1)->Focus();
1187-}
1188-
1189-void PerformScrollDown(WindowList const& windows, unsigned int progressive_scroll)
1190-{
1191- if (!progressive_scroll)
1192- {
1193- WindowManager::Default().RestackBelow(windows.at(0)->window_id(), windows.back()->window_id());
1194- windows.at(1)->Focus();
1195- return;
1196- }
1197-
1198- WindowManager::Default().RestackBelow(windows.at(0)->window_id(), windows.at(progressive_scroll)->window_id());
1199- windows.at(progressive_scroll)->Focus();
1200-}
1201-
1202-void ApplicationLauncherIcon::PerformScroll(ScrollDirection direction, Time timestamp)
1203-{
1204- if (timestamp - _last_scroll_timestamp < 150)
1205- return;
1206- else if (timestamp - _last_scroll_timestamp > 1500)
1207- _progressive_scroll = 0;
1208-
1209- _last_scroll_timestamp = timestamp;
1210-
1211- auto const& windows = GetWindowsOnCurrentDesktopInStackingOrder();
1212-
1213- if (windows.empty())
1214- return;
1215-
1216- if (scroll_inactive_icons && !IsActive())
1217- {
1218- windows.at(0)->Focus();
1219- return;
1220- }
1221-
1222- if (!scroll_inactive_icons && !IsActive())
1223- return;
1224-
1225- if (windows.size() <= 1)
1226- return;
1227-
1228- if (direction == ScrollDirection::DOWN)
1229- ++_progressive_scroll;
1230- else
1231- //--_progressive_scroll; but roll to the top of windows
1232- _progressive_scroll += windows.size() - 1;
1233- _progressive_scroll %= windows.size();
1234-
1235- switch(direction)
1236- {
1237- case ScrollDirection::UP:
1238- PerformScrollUp(windows, _progressive_scroll);
1239- break;
1240- case ScrollDirection::DOWN:
1241- PerformScrollDown(windows, _progressive_scroll);
1242- break;
1243- }
1244-}
1245-
1246-WindowList ApplicationLauncherIcon::GetWindowsOnCurrentDesktopInStackingOrder()
1247-{
1248- auto windows = GetWindows(WindowFilter::ON_CURRENT_DESKTOP | WindowFilter::ON_ALL_MONITORS);
1249- auto sorted_windows = WindowManager::Default().GetWindowsInStackingOrder();
1250-
1251- // Order the windows
1252- std::sort(windows.begin(), windows.end(), [&sorted_windows] (ApplicationWindowPtr const& win1, ApplicationWindowPtr const& win2) {
1253- for (auto const& window : sorted_windows)
1254- {
1255- if (window == win1->window_id())
1256- return false;
1257- else if (window == win2->window_id())
1258- return true;
1259- }
1260-
1261- return true;
1262- });
1263-
1264- return windows;
1265-}
1266-
1267 std::string ApplicationLauncherIcon::GetName() const
1268 {
1269 return "ApplicationLauncherIcon";
1270 }
1271
1272+void ApplicationLauncherIcon::AddProperties(debug::IntrospectionData& introspection)
1273+{
1274+ WindowedLauncherIcon::AddProperties(introspection);
1275+
1276+ introspection.add("desktop_file", DesktopFile())
1277+ .add("desktop_id", app_->desktop_id());
1278+}
1279+
1280 } // namespace launcher
1281 } // namespace unity
1282
1283=== modified file 'launcher/ApplicationLauncherIcon.h'
1284--- launcher/ApplicationLauncherIcon.h 2015-11-18 15:25:31 +0000
1285+++ launcher/ApplicationLauncherIcon.h 2016-02-09 10:44:04 +0000
1286@@ -1,6 +1,6 @@
1287 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1288 /*
1289- * Copyright (C) 2010-2012 Canonical Ltd
1290+ * Copyright (C) 2010-2015 Canonical Ltd
1291 *
1292 * This program is free software: you can redistribute it and/or modify
1293 * it under the terms of the GNU General Public License version 3 as
1294@@ -18,17 +18,15 @@
1295 * Marco Trevisan (Treviño) <3v1n0@ubuntu.com>
1296 */
1297
1298-#ifndef APPLICATIONLAUNCHERICON_H
1299-#define APPLICATIONLAUNCHERICON_H
1300+#ifndef APPLICATION_LAUNCHER_ICON_H
1301+#define APPLICATION_LAUNCHER_ICON_H
1302
1303-#include <UnityCore/GLibSignal.h>
1304-#include <UnityCore/GLibWrapper.h>
1305 #include <UnityCore/ConnectionManager.h>
1306 #include <UnityCore/Variant.h>
1307
1308 #include <libindicator/indicator-desktop-shortcuts.h>
1309
1310-#include "SimpleLauncherIcon.h"
1311+#include "WindowedLauncherIcon.h"
1312
1313 namespace unity
1314 {
1315@@ -37,115 +35,74 @@
1316
1317 class Launcher;
1318
1319-class ApplicationLauncherIcon : public SimpleLauncherIcon
1320+class ApplicationLauncherIcon : public virtual WindowedLauncherIcon
1321 {
1322- NUX_DECLARE_OBJECT_TYPE(ApplicationLauncherIcon, SimpleLauncherIcon);
1323+ NUX_DECLARE_OBJECT_TYPE(ApplicationLauncherIcon, WindowedLauncherIcon);
1324 public:
1325- ApplicationLauncherIcon(ApplicationPtr const& app);
1326+ ApplicationLauncherIcon(ApplicationPtr const&);
1327 virtual ~ApplicationLauncherIcon();
1328
1329- virtual void ActivateLauncherIcon(ActionArg arg);
1330-
1331 std::string DesktopFile() const;
1332
1333- bool IsSticky() const;
1334- bool IsActive() const;
1335- bool IsRunning() const;
1336- bool IsUrgent() const;
1337-
1338- virtual bool GetQuirk(Quirk quirk, int monitor = 0) const override;
1339-
1340- virtual void Quit();
1341- virtual void AboutToRemove();
1342-
1343- virtual void Stick(bool save = true);
1344- virtual void UnStick();
1345-
1346- virtual bool ShowInSwitcher(bool current);
1347- virtual bool AllowDetailViewInSwitcher() const override;
1348- virtual uint64_t SwitcherPriority();
1349-
1350- virtual nux::Color BackgroundColor() const;
1351-
1352- WindowList Windows();
1353- std::vector<Window> WindowsOnViewport();
1354- std::vector<Window> WindowsForMonitor(int monitor);
1355-
1356- void PerformScroll(ScrollDirection direction, Time timestamp) override;
1357+ bool IsSticky() const override;
1358+ bool IsUserVisible() const override;
1359+ bool GetQuirk(Quirk quirk, int monitor = 0) const override;
1360+
1361+ void Quit() const override;
1362+
1363+ void Stick(bool save = true) override;
1364+ void UnStick() override;
1365
1366 protected:
1367 void SetApplication(ApplicationPtr const& app);
1368 ApplicationPtr GetApplication() const;
1369
1370+ WindowList GetManagedWindows() const override;
1371+
1372+ void LogUnityEvent(ApplicationEventType);
1373 void Remove();
1374- void UpdateIconGeometries(std::vector<nux::Point3> const& centers);
1375- void OnCenterStabilized(std::vector<nux::Point3> const& centers);
1376- void AddProperties(debug::IntrospectionData&);
1377- void OnAcceptDrop(DndData const& dnd_data);
1378- void OnDndEnter();
1379- void OnDndLeave();
1380+
1381+ void AboutToRemove() override;
1382+ bool AllowDetailViewInSwitcher() const override;
1383+ uint64_t SwitcherPriority() override;
1384+ void UpdateIconGeometries(std::vector<nux::Point3> const& centers) override;
1385+ nux::Color BackgroundColor() const override;
1386+ MenuItemsVector GetMenus() override;
1387+ std::string GetRemoteUri() const override;
1388+
1389 void OpenInstanceLauncherIcon(Time timestamp) override;
1390- void ToggleSticky();
1391- void LogUnityEvent(ApplicationEventType);
1392- bool IsFileManager();
1393-
1394- bool OnShouldHighlightOnDrag(DndData const& dnd_data);
1395- nux::DndAction OnQueryAcceptDrop(DndData const& dnd_data);
1396-
1397- MenuItemsVector GetMenus();
1398-
1399- std::string GetRemoteUri() const;
1400-
1401- bool HandlesSpread() { return true; }
1402- std::string GetName() const;
1403-
1404- void UpdateDesktopFile();
1405- void UpdateRemoteUri();
1406- std::string _desktop_file;
1407-
1408-private:
1409- typedef unsigned long int WindowFilterMask;
1410- enum WindowFilter
1411- {
1412- MAPPED = (1 << 0),
1413- USER_VISIBLE = (1 << 1),
1414- ON_CURRENT_DESKTOP = (1 << 2),
1415- ON_ALL_MONITORS = (1 << 3),
1416- };
1417+ void OpenInstanceWithUris(std::set<std::string> const& uris, Time timestamp);
1418+ void Focus(ActionArg arg) override;
1419+
1420+ void OnAcceptDrop(DndData const&) override;
1421+ bool OnShouldHighlightOnDrag(DndData const&) override;
1422+ nux::DndAction OnQueryAcceptDrop(DndData const&) override;
1423+
1424+ std::string GetName() const override;
1425+ void AddProperties(debug::IntrospectionData&) override;
1426
1427 void UnsetApplication();
1428 void SetupApplicationSignalsConnections();
1429- void EnsureWindowState();
1430- void EnsureWindowsLocation();
1431- void EnsureMenuItemsWindowsReady();
1432 void EnsureMenuItemsDefaultReady();
1433 void EnsureMenuItemsStaticQuicklist();
1434 void UpdateBackgroundColor();
1435 void UpdateDesktopQuickList();
1436-
1437- void OpenInstanceWithUris(std::set<std::string> const& uris, Time timestamp);
1438- void Focus(ActionArg arg);
1439- bool Spread(bool current_desktop, int state, bool force);
1440-
1441- void OnWindowMinimized(guint32 xid);
1442-
1443- WindowList GetWindows(WindowFilterMask filter = 0, int monitor = -1);
1444+ void UpdateDesktopFile();
1445+ void UpdateRemoteUri();
1446+ void ToggleSticky();
1447+ void OnApplicationClosed();
1448+
1449 const std::set<std::string> GetSupportedTypes();
1450- WindowList GetWindowsOnCurrentDesktopInStackingOrder();
1451 ApplicationSubjectPtr GetSubject();
1452
1453 ApplicationPtr app_;
1454- std::string _remote_uri;
1455- Time _startup_notification_timestamp;
1456- Time _last_scroll_timestamp;
1457- unsigned int _progressive_scroll;
1458- std::set<std::string> _supported_types;
1459- std::vector<glib::Object<DbusmenuMenuitem>> _menu_items;
1460- std::vector<glib::Object<DbusmenuMenuitem>> _menu_items_windows;
1461- glib::Object<IndicatorDesktopShortcuts> _desktop_shortcuts;
1462- glib::Object<DbusmenuMenuitem> _menu_desktop_shortcuts;
1463- glib::Object<GFileMonitor> _desktop_file_monitor;
1464- glib::SignalManager _gsignals;
1465+ std::string remote_uri_;
1466+ Time startup_notification_timestamp_;
1467+ std::set<std::string> supported_types_;
1468+ MenuItemsVector menu_items_;
1469+ glib::Object<IndicatorDesktopShortcuts> desktop_shortcuts_;
1470+ glib::Object<DbusmenuMenuitem> menu_desktop_shortcuts_;
1471+ glib::Object<GFileMonitor> desktop_file_monitor_;
1472
1473 bool use_custom_bg_color_;
1474 nux::Color bg_color_;
1475@@ -153,7 +110,7 @@
1476 connection::Manager signals_conn_;
1477 };
1478
1479-}
1480-}
1481+} // namespace launcher
1482+} // namespace unity
1483
1484-#endif // BAMFLAUNCHERICON_H
1485+#endif // APPLICATION_LAUNCHER_ICON_H
1486
1487=== modified file 'launcher/CMakeLists.txt'
1488--- launcher/CMakeLists.txt 2013-09-11 18:39:27 +0000
1489+++ launcher/CMakeLists.txt 2016-02-09 10:44:04 +0000
1490@@ -32,6 +32,7 @@
1491 FavoriteStore.cpp
1492 FavoriteStoreGSettings.cpp
1493 FavoriteStorePrivate.cpp
1494+ FileManagerLauncherIcon.cpp
1495 HudLauncherIcon.cpp
1496 Launcher.cpp
1497 LauncherController.cpp
1498@@ -55,12 +56,14 @@
1499 SingleMonitorLauncherIcon.cpp
1500 SoftwareCenterLauncherIcon.cpp
1501 SpacerLauncherIcon.cpp
1502+ StorageLauncherIcon.cpp
1503 Tooltip.cpp
1504 TooltipManager.cpp
1505 TrashLauncherIcon.cpp
1506 VolumeImp.cpp
1507 VolumeLauncherIcon.cpp
1508 VolumeMonitorWrapper.cpp
1509+ WindowedLauncherIcon.cpp
1510 XdndCollectionWindowImp.cpp
1511 XdndManagerImp.cpp
1512 XdndStartStopNotifier.cpp
1513
1514=== modified file 'launcher/DesktopLauncherIcon.cpp'
1515--- launcher/DesktopLauncherIcon.cpp 2014-08-13 23:32:39 +0000
1516+++ launcher/DesktopLauncherIcon.cpp 2016-02-09 10:44:04 +0000
1517@@ -77,5 +77,10 @@
1518 return show_in_switcher_;
1519 }
1520
1521+uint64_t DesktopLauncherIcon::SwitcherPriority()
1522+{
1523+ return std::numeric_limits<uint64_t>::max();
1524+}
1525+
1526 } // namespace launcher
1527 } // namespace unity
1528
1529=== modified file 'launcher/DesktopLauncherIcon.h'
1530--- launcher/DesktopLauncherIcon.h 2014-08-13 23:32:39 +0000
1531+++ launcher/DesktopLauncherIcon.h 2016-02-09 10:44:04 +0000
1532@@ -37,6 +37,7 @@
1533
1534 protected:
1535 void ActivateLauncherIcon(ActionArg arg);
1536+ uint64_t SwitcherPriority() override;
1537 std::string GetName() const;
1538 std::string GetRemoteUri() const;
1539
1540
1541=== modified file 'launcher/DeviceLauncherSection.h'
1542--- launcher/DeviceLauncherSection.h 2013-10-07 14:13:45 +0000
1543+++ launcher/DeviceLauncherSection.h 2016-02-09 10:44:04 +0000
1544@@ -37,10 +37,14 @@
1545 class DeviceLauncherSection : public sigc::trackable
1546 {
1547 public:
1548+ typedef std::shared_ptr<DeviceLauncherSection> Ptr;
1549+
1550 DeviceLauncherSection(AbstractVolumeMonitorWrapper::Ptr const& volume_monitor = nullptr,
1551 DevicesSettings::Ptr const& devices_settings = nullptr,
1552 DeviceNotificationDisplay::Ptr const& notifications = nullptr);
1553
1554+ virtual ~DeviceLauncherSection() = default;
1555+
1556 std::vector<VolumeLauncherIcon::Ptr> GetIcons() const;
1557
1558 sigc::signal<void, AbstractLauncherIcon::Ptr const&> icon_added;
1559
1560=== added file 'launcher/FileManagerLauncherIcon.cpp'
1561--- launcher/FileManagerLauncherIcon.cpp 1970-01-01 00:00:00 +0000
1562+++ launcher/FileManagerLauncherIcon.cpp 2016-02-09 10:44:04 +0000
1563@@ -0,0 +1,128 @@
1564+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1565+/*
1566+ * Copyright (C) 2015 Canonical Ltd
1567+ *
1568+ * This program is free software: you can redistribute it and/or modify
1569+ * it under the terms of the GNU General Public License version 3 as
1570+ * published by the Free Software Foundation.
1571+ *
1572+ * This program is distributed in the hope that it will be useful,
1573+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1574+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1575+ * GNU General Public License for more details.
1576+ *
1577+ * You should have received a copy of the GNU General Public License
1578+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1579+ *
1580+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
1581+ */
1582+
1583+#include "FileManagerLauncherIcon.h"
1584+
1585+#include <boost/algorithm/string.hpp>
1586+#include <NuxCore/Logger.h>
1587+#include <UnityCore/DesktopUtilities.h>
1588+
1589+#include "unity-shared/GnomeFileManager.h"
1590+
1591+namespace unity
1592+{
1593+namespace launcher
1594+{
1595+namespace
1596+{
1597+DECLARE_LOGGER(logger, "unity.launcher.icon.filemanager");
1598+const std::string TRASH_URI = "trash:";
1599+const std::string TRASH_PATH = "file://" + DesktopUtilities::GetUserTrashDirectory();
1600+const std::string DEFAULT_ICON = "system-file-manager";
1601+}
1602+
1603+FileManagerLauncherIcon::FileManagerLauncherIcon(ApplicationPtr const& app, DeviceLauncherSection::Ptr const& dev, FileManager::Ptr const& fm)
1604+ : WindowedLauncherIcon(IconType::APPLICATION)
1605+ , ApplicationLauncherIcon(app)
1606+ , StorageLauncherIcon(GetIconType(), fm ? fm : GnomeFileManager::Get())
1607+ , devices_(dev)
1608+{
1609+ // We disconnect from ApplicationLauncherIcon app signals, as we manage them manually
1610+ signals_conn_.Clear();
1611+
1612+ signals_conn_.Add(app_->desktop_file.changed.connect([this](std::string const& desktop_file) {
1613+ LOG_DEBUG(logger) << tooltip_text() << " desktop_file now " << desktop_file;
1614+ UpdateDesktopFile();
1615+ }));
1616+
1617+ signals_conn_.Add(app_->closed.connect([this] {
1618+ LOG_DEBUG(logger) << tooltip_text() << " closed";
1619+ OnApplicationClosed();
1620+ }));
1621+
1622+ signals_conn_.Add(app_->title.changed.connect([this](std::string const& name) {
1623+ LOG_DEBUG(logger) << tooltip_text() << " name now " << name;
1624+ menu_items_.clear();
1625+ tooltip_text = name;
1626+ }));
1627+
1628+ signals_conn_.Add(app_->icon.changed.connect([this](std::string const& icon) {
1629+ LOG_DEBUG(logger) << tooltip_text() << " icon now " << icon;
1630+ icon_name = (icon.empty() ? DEFAULT_ICON : icon);
1631+ }));
1632+
1633+ UpdateStorageWindows();
1634+}
1635+
1636+void FileManagerLauncherIcon::Focus(ActionArg arg)
1637+{
1638+ WindowedLauncherIcon::Focus(arg);
1639+}
1640+
1641+void FileManagerLauncherIcon::Quit() const
1642+{
1643+ WindowedLauncherIcon::Quit();
1644+}
1645+
1646+bool FileManagerLauncherIcon::IsLocationManaged(std::string const& location) const
1647+{
1648+ if (location.empty())
1649+ return true;
1650+
1651+ if (boost::algorithm::starts_with(location, TRASH_URI))
1652+ return false;
1653+
1654+ if (boost::algorithm::starts_with(location, TRASH_PATH))
1655+ return false;
1656+
1657+ for (auto const& volume_icon : devices_->GetIcons())
1658+ {
1659+ auto const& volume_uri = volume_icon->GetVolumeUri();
1660+ if (!volume_uri.empty() && boost::algorithm::starts_with(location, volume_uri))
1661+ return false;
1662+ }
1663+
1664+ return true;
1665+}
1666+
1667+WindowList FileManagerLauncherIcon::GetManagedWindows() const
1668+{
1669+ return StorageLauncherIcon::GetManagedWindows();
1670+}
1671+
1672+WindowList FileManagerLauncherIcon::GetStorageWindows() const
1673+{
1674+ WindowList fm_windows;
1675+
1676+ for (auto const& app_win : ApplicationLauncherIcon::GetManagedWindows())
1677+ {
1678+ if (IsLocationManaged(file_manager_->LocationForWindow(app_win)))
1679+ fm_windows.push_back(app_win);
1680+ }
1681+
1682+ return fm_windows;
1683+}
1684+
1685+bool FileManagerLauncherIcon::OnShouldHighlightOnDrag(DndData const& dnd_data)
1686+{
1687+ return StorageLauncherIcon::OnShouldHighlightOnDrag(dnd_data);
1688+}
1689+
1690+} // namespace launcher
1691+} // namespace unity
1692
1693=== added file 'launcher/FileManagerLauncherIcon.h'
1694--- launcher/FileManagerLauncherIcon.h 1970-01-01 00:00:00 +0000
1695+++ launcher/FileManagerLauncherIcon.h 2016-02-09 10:44:04 +0000
1696@@ -0,0 +1,52 @@
1697+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1698+/*
1699+ * Copyright (C) 2015 Canonical Ltd
1700+ *
1701+ * This program is free software: you can redistribute it and/or modify
1702+ * it under the terms of the GNU General Public License version 3 as
1703+ * published by the Free Software Foundation.
1704+ *
1705+ * This program is distributed in the hope that it will be useful,
1706+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1707+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1708+ * GNU General Public License for more details.
1709+ *
1710+ * You should have received a copy of the GNU General Public License
1711+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1712+ *
1713+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
1714+ */
1715+
1716+#ifndef FILEMANAGER_LAUNCHER_ICON_H
1717+#define FILEMANAGER_LAUNCHER_ICON_H
1718+
1719+#include "ApplicationLauncherIcon.h"
1720+#include "StorageLauncherIcon.h"
1721+#include "DeviceLauncherSection.h"
1722+
1723+namespace unity
1724+{
1725+namespace launcher
1726+{
1727+
1728+class FileManagerLauncherIcon : public ApplicationLauncherIcon, public StorageLauncherIcon
1729+{
1730+public:
1731+ FileManagerLauncherIcon(ApplicationPtr const&, DeviceLauncherSection::Ptr const&, FileManager::Ptr const& = nullptr);
1732+
1733+private:
1734+ WindowList GetManagedWindows() const override;
1735+ WindowList GetStorageWindows() const override;
1736+ void Focus(ActionArg arg) override;
1737+ void Quit() const override;
1738+ bool OnShouldHighlightOnDrag(DndData const& dnd_data) override;
1739+
1740+ bool IsLocationManaged(std::string const&) const;
1741+
1742+ DeviceLauncherSection::Ptr devices_;
1743+};
1744+
1745+} // namespace launcher
1746+} // namespace unity
1747+
1748+#endif // FILEMANAGER_LAUNCHER_ICON_H
1749
1750=== modified file 'launcher/Launcher.cpp'
1751--- launcher/Launcher.cpp 2015-07-07 16:54:46 +0000
1752+++ launcher/Launcher.cpp 2016-02-09 10:44:04 +0000
1753@@ -578,16 +578,9 @@
1754 else
1755 {
1756 if (options()->show_for_all)
1757- arg.window_indicators = std::max<int> (icon->WindowsOnViewport().size(), 1);
1758+ arg.window_indicators = std::max<int>(icon->WindowsVisibleOnViewport(), 1);
1759 else
1760- arg.window_indicators = std::max<int> (icon->WindowsForMonitor(monitor).size(), 1);
1761-
1762- if (icon->GetIconType() == AbstractLauncherIcon::IconType::TRASH ||
1763- icon->GetIconType() == AbstractLauncherIcon::IconType::DEVICE)
1764- {
1765- // TODO: also these icons should respect the actual windows they have
1766- arg.window_indicators = 0;
1767- }
1768+ arg.window_indicators = std::max<int>(icon->WindowsVisibleOnMonitor(monitor), 1);
1769 }
1770
1771 arg.backlight_intensity = IconBackgroundIntensity(icon);
1772
1773=== modified file 'launcher/LauncherController.cpp'
1774--- launcher/LauncherController.cpp 2015-12-11 12:44:27 +0000
1775+++ launcher/LauncherController.cpp 2016-02-09 10:44:04 +0000
1776@@ -21,6 +21,7 @@
1777
1778 #include "config.h"
1779 #include <glib/gi18n-lib.h>
1780+#include <boost/algorithm/string.hpp>
1781
1782 #include <Nux/Nux.h>
1783 #include <Nux/HLayout.h>
1784@@ -32,6 +33,7 @@
1785 #include "DesktopLauncherIcon.h"
1786 #include "VolumeLauncherIcon.h"
1787 #include "FavoriteStore.h"
1788+#include "FileManagerLauncherIcon.h"
1789 #include "HudLauncherIcon.h"
1790 #include "LauncherController.h"
1791 #include "LauncherControllerPrivate.h"
1792@@ -102,13 +104,13 @@
1793
1794 return FavoriteStore::URI_PREFIX_APP + DesktopUtilities::GetDesktopID(desktop_path);
1795 }
1796-
1797 }
1798
1799 Controller::Impl::Impl(Controller* parent, XdndManager::Ptr const& xdnd_manager, ui::EdgeBarrierController::Ptr const& edge_barriers)
1800 : parent_(parent)
1801 , model_(std::make_shared<LauncherModel>())
1802 , xdnd_manager_(xdnd_manager)
1803+ , device_section_(std::make_shared<DeviceLauncherSection>())
1804 , expo_icon_(new ExpoLauncherIcon())
1805 , desktop_icon_(new DesktopLauncherIcon())
1806 , edge_barriers_(edge_barriers)
1807@@ -342,6 +344,21 @@
1808 return launcher;
1809 }
1810
1811+ApplicationLauncherIcon* Controller::Impl::CreateAppLauncherIcon(ApplicationPtr const& app)
1812+{
1813+ auto const& desktop_file = app->desktop_file();
1814+
1815+ if (boost::algorithm::ends_with(desktop_file, "org.gnome.Nautilus.desktop") ||
1816+ boost::algorithm::ends_with(desktop_file, "nautilus.desktop") ||
1817+ boost::algorithm::ends_with(desktop_file, "nautilus-folder-handler.desktop") ||
1818+ boost::algorithm::ends_with(desktop_file, "nautilus-home.desktop"))
1819+ {
1820+ return new FileManagerLauncherIcon(app, device_section_);
1821+ }
1822+
1823+ return new ApplicationLauncherIcon(app);
1824+}
1825+
1826 void Controller::Impl::OnLauncherAddRequest(std::string const& icon_uri, AbstractLauncherIcon::Ptr const& icon_before)
1827 {
1828 std::string app_uri;
1829@@ -838,7 +855,7 @@
1830 if (app->sticky() || app->seen())
1831 return;
1832
1833- AbstractLauncherIcon::Ptr icon(new ApplicationLauncherIcon(app));
1834+ AbstractLauncherIcon::Ptr icon(CreateAppLauncherIcon(app));
1835 RegisterIcon(icon, GetLastIconPriority<ApplicationLauncherIcon>(local::RUNNING_APPS_URI));
1836 }
1837
1838@@ -875,11 +892,11 @@
1839 if (!app || app->seen())
1840 return result;
1841
1842- result = AbstractLauncherIcon::Ptr(new ApplicationLauncherIcon(app));
1843+ result = AbstractLauncherIcon::Ptr(CreateAppLauncherIcon(app));
1844 }
1845 else if (icon_uri.find(FavoriteStore::URI_PREFIX_DEVICE) == 0)
1846 {
1847- auto const& devices = device_section_.GetIcons();
1848+ auto const& devices = device_section_->GetIcons();
1849 auto const& icon = std::find_if(devices.begin(), devices.end(),
1850 [&icon_uri](AbstractLauncherIcon::Ptr const& i) { return (i->RemoteUri() == icon_uri); });
1851
1852@@ -954,7 +971,7 @@
1853 << (app->seen() ? "yes" : "no");
1854 if (!app->seen())
1855 {
1856- AbstractLauncherIcon::Ptr icon(new ApplicationLauncherIcon(app));
1857+ AbstractLauncherIcon::Ptr icon(CreateAppLauncherIcon(app));
1858 icon->SkipQuirkAnimation(AbstractLauncherIcon::Quirk::VISIBLE);
1859 RegisterIcon(icon, ++sort_priority_);
1860 }
1861@@ -964,7 +981,7 @@
1862 void Controller::Impl::AddDevices()
1863 {
1864 auto& fav_store = FavoriteStore::Instance();
1865- for (auto const& icon : device_section_.GetIcons())
1866+ for (auto const& icon : device_section_->GetIcons())
1867 {
1868 if (!icon->IsSticky() && !fav_store.IsFavorite(icon->RemoteUri()))
1869 {
1870@@ -1044,7 +1061,7 @@
1871 ApplicationManager::Default().application_started
1872 .connect(sigc::mem_fun(this, &Impl::OnApplicationStarted));
1873
1874- device_section_.icon_added.connect(sigc::mem_fun(this, &Impl::OnDeviceIconAdded));
1875+ device_section_->icon_added.connect(sigc::mem_fun(this, &Impl::OnDeviceIconAdded));
1876 favorite_store.favorite_added.connect(sigc::mem_fun(this, &Impl::OnFavoriteStoreFavoriteAdded));
1877 favorite_store.favorite_removed.connect(sigc::mem_fun(this, &Impl::OnFavoriteStoreFavoriteRemoved));
1878 favorite_store.reordered.connect(sigc::mem_fun(this, &Impl::ResetIconPriorities));
1879
1880=== modified file 'launcher/LauncherControllerPrivate.h'
1881--- launcher/LauncherControllerPrivate.h 2015-04-16 14:38:54 +0000
1882+++ launcher/LauncherControllerPrivate.h 2016-02-09 10:44:04 +0000
1883@@ -87,6 +87,7 @@
1884
1885 void RegisterIcon(AbstractLauncherIcon::Ptr const& icon, int priority = std::numeric_limits<int>::min());
1886
1887+ ApplicationLauncherIcon* CreateAppLauncherIcon(ApplicationPtr const&);
1888 AbstractLauncherIcon::Ptr CreateFavoriteIcon(std::string const& icon_uri, bool emit_signal = false);
1889 AbstractLauncherIcon::Ptr GetIconByUri(std::string const& icon_uri);
1890 SoftwareCenterLauncherIcon::Ptr CreateSCLauncherIcon(std::string const& file_path, std::string const& aptdaemon_trans_id, std::string const& icon_path);
1891@@ -122,7 +123,7 @@
1892 nux::ObjectPtr<Launcher> launcher_;
1893 nux::ObjectPtr<Launcher> keyboard_launcher_;
1894 XdndManager::Ptr xdnd_manager_;
1895- DeviceLauncherSection device_section_;
1896+ DeviceLauncherSection::Ptr device_section_;
1897 LauncherEntryRemoteModel remote_model_;
1898 AbstractLauncherIcon::Ptr expo_icon_;
1899 AbstractLauncherIcon::Ptr desktop_icon_;
1900
1901=== modified file 'launcher/LauncherIcon.cpp'
1902--- launcher/LauncherIcon.cpp 2015-11-02 18:08:08 +0000
1903+++ launcher/LauncherIcon.cpp 2016-02-09 10:44:04 +0000
1904@@ -150,16 +150,26 @@
1905 QuicklistManager::Default()->RegisterQuicklist(_quicklist);
1906 }
1907
1908-const bool LauncherIcon::WindowVisibleOnMonitor(int monitor)
1909+bool LauncherIcon::WindowVisibleOnMonitor(int monitor) const
1910 {
1911 return _has_visible_window[monitor];
1912 }
1913
1914-const bool LauncherIcon::WindowVisibleOnViewport()
1915+bool LauncherIcon::WindowVisibleOnViewport() const
1916 {
1917 return _has_visible_window.any();
1918 }
1919
1920+size_t LauncherIcon::WindowsVisibleOnMonitor(int monitor) const
1921+{
1922+ return _number_of_visible_windows[monitor];
1923+}
1924+
1925+size_t LauncherIcon::WindowsVisibleOnViewport() const
1926+{
1927+ return std::accumulate(begin(_number_of_visible_windows), end(_number_of_visible_windows), 0);
1928+}
1929+
1930 std::string
1931 LauncherIcon::GetName() const
1932 {
1933
1934=== modified file 'launcher/LauncherIcon.h'
1935--- launcher/LauncherIcon.h 2015-11-02 18:08:08 +0000
1936+++ launcher/LauncherIcon.h 2016-02-09 10:44:04 +0000
1937@@ -82,7 +82,7 @@
1938
1939 nux::Point3 GetCenter(int monitor);
1940
1941- virtual void Activate(ActionArg arg);
1942+ void Activate(ActionArg arg);
1943
1944 void OpenInstance(ActionArg arg);
1945
1946@@ -94,15 +94,19 @@
1947
1948 void SetOrder(int order);
1949
1950- virtual WindowList Windows() { return WindowList(); }
1951-
1952- virtual std::vector<Window> WindowsOnViewport() { return std::vector<Window> (); }
1953-
1954- virtual std::vector<Window> WindowsForMonitor(int monitor) { return std::vector<Window> (); }
1955-
1956- const bool WindowVisibleOnMonitor(int monitor);
1957-
1958- const bool WindowVisibleOnViewport();
1959+ WindowList Windows() { return WindowList(); }
1960+
1961+ WindowList WindowsOnViewport() { return WindowList(); }
1962+
1963+ WindowList WindowsForMonitor(int monitor) { return WindowList(); }
1964+
1965+ bool WindowVisibleOnMonitor(int monitor) const;
1966+
1967+ bool WindowVisibleOnViewport() const;
1968+
1969+ size_t WindowsVisibleOnMonitor(int monitor) const;
1970+
1971+ size_t WindowsVisibleOnViewport() const;
1972
1973 float PresentUrgency();
1974
1975
1976=== modified file 'launcher/MockLauncherIcon.h'
1977--- launcher/MockLauncherIcon.h 2015-10-05 16:52:24 +0000
1978+++ launcher/MockLauncherIcon.h 2016-02-09 10:44:04 +0000
1979@@ -112,34 +112,34 @@
1980 return result;
1981 }
1982
1983- std::vector<Window> WindowsOnViewport ()
1984+ WindowList WindowsOnViewport()
1985 {
1986- std::vector<Window> result;
1987+ WindowList result;
1988
1989- result.push_back ((100 << 16) + 200);
1990- result.push_back ((500 << 16) + 200);
1991- result.push_back ((300 << 16) + 200);
1992- result.push_back ((200 << 16) + 200);
1993- result.push_back ((300 << 16) + 200);
1994- result.push_back ((100 << 16) + 200);
1995- result.push_back ((300 << 16) + 200);
1996- result.push_back ((600 << 16) + 200);
1997+ result.push_back(std::make_shared<MockApplicationWindow>((100 << 16) + 200));
1998+ result.push_back(std::make_shared<MockApplicationWindow>((500 << 16) + 200));
1999+ result.push_back(std::make_shared<MockApplicationWindow>((300 << 16) + 200));
2000+ result.push_back(std::make_shared<MockApplicationWindow>((200 << 16) + 200));
2001+ result.push_back(std::make_shared<MockApplicationWindow>((300 << 16) + 200));
2002+ result.push_back(std::make_shared<MockApplicationWindow>((100 << 16) + 200));
2003+ result.push_back(std::make_shared<MockApplicationWindow>((300 << 16) + 200));
2004+ result.push_back(std::make_shared<MockApplicationWindow>((600 << 16) + 200));
2005
2006 return result;
2007 }
2008
2009- std::vector<Window> WindowsForMonitor (int monitor)
2010+ WindowList WindowsForMonitor(int monitor)
2011 {
2012- std::vector<Window> result;
2013+ WindowList result;
2014
2015- result.push_back ((100 << 16) + 200);
2016- result.push_back ((500 << 16) + 200);
2017- result.push_back ((300 << 16) + 200);
2018- result.push_back ((200 << 16) + 200);
2019- result.push_back ((300 << 16) + 200);
2020- result.push_back ((100 << 16) + 200);
2021- result.push_back ((300 << 16) + 200);
2022- result.push_back ((600 << 16) + 200);
2023+ result.push_back(std::make_shared<MockApplicationWindow>((100 << 16) + 200));
2024+ result.push_back(std::make_shared<MockApplicationWindow>((500 << 16) + 200));
2025+ result.push_back(std::make_shared<MockApplicationWindow>((300 << 16) + 200));
2026+ result.push_back(std::make_shared<MockApplicationWindow>((200 << 16) + 200));
2027+ result.push_back(std::make_shared<MockApplicationWindow>((300 << 16) + 200));
2028+ result.push_back(std::make_shared<MockApplicationWindow>((100 << 16) + 200));
2029+ result.push_back(std::make_shared<MockApplicationWindow>((300 << 16) + 200));
2030+ result.push_back(std::make_shared<MockApplicationWindow>((600 << 16) + 200));
2031
2032 return result;
2033 }
2034@@ -194,14 +194,24 @@
2035 return 7;
2036 }
2037
2038- const bool WindowVisibleOnViewport()
2039- {
2040- return false;
2041- }
2042-
2043- const bool WindowVisibleOnMonitor(int monitor)
2044- {
2045- return false;
2046+ bool WindowVisibleOnViewport() const
2047+ {
2048+ return false;
2049+ }
2050+
2051+ bool WindowVisibleOnMonitor(int monitor) const
2052+ {
2053+ return false;
2054+ }
2055+
2056+ size_t WindowsVisibleOnMonitor(int monitor) const
2057+ {
2058+ return 0;
2059+ }
2060+
2061+ size_t WindowsVisibleOnViewport() const
2062+ {
2063+ return 0;
2064 }
2065
2066 void SetVisibleOnMonitor(int monitor, bool visible) {}
2067
2068=== modified file 'launcher/SoftwareCenterLauncherIcon.cpp'
2069--- launcher/SoftwareCenterLauncherIcon.cpp 2013-10-29 22:33:02 +0000
2070+++ launcher/SoftwareCenterLauncherIcon.cpp 2016-02-09 10:44:04 +0000
2071@@ -46,7 +46,8 @@
2072 SoftwareCenterLauncherIcon::SoftwareCenterLauncherIcon(ApplicationPtr const& app,
2073 std::string const& aptdaemon_trans_id,
2074 std::string const& icon_path)
2075- : ApplicationLauncherIcon(app)
2076+ : WindowedLauncherIcon(IconType::APPLICATION)
2077+ , ApplicationLauncherIcon(app)
2078 , aptdaemon_trans_(std::make_shared<glib::DBusProxy>("org.debian.apt",
2079 aptdaemon_trans_id,
2080 "org.debian.apt.transaction",
2081
2082=== added file 'launcher/StorageLauncherIcon.cpp'
2083--- launcher/StorageLauncherIcon.cpp 1970-01-01 00:00:00 +0000
2084+++ launcher/StorageLauncherIcon.cpp 2016-02-09 10:44:04 +0000
2085@@ -0,0 +1,119 @@
2086+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
2087+/*
2088+ * Copyright (C) 2015 Canonical Ltd
2089+ *
2090+ * This program is free software: you can redistribute it and/or modify
2091+ * it under the terms of the GNU General Public License version 3 as
2092+ * published by the Free Software Foundation.
2093+ *
2094+ * This program is distributed in the hope that it will be useful,
2095+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2096+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2097+ * GNU General Public License for more details.
2098+ *
2099+ * You should have received a copy of the GNU General Public License
2100+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2101+ *
2102+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
2103+ */
2104+
2105+#include "StorageLauncherIcon.h"
2106+
2107+namespace unity
2108+{
2109+namespace launcher
2110+{
2111+
2112+StorageLauncherIcon::StorageLauncherIcon(AbstractLauncherIcon::IconType icon_type, FileManager::Ptr const& fm)
2113+ : WindowedLauncherIcon(icon_type)
2114+ , file_manager_(fm)
2115+{
2116+ file_manager_->locations_changed.connect(sigc::mem_fun(this, &StorageLauncherIcon::UpdateStorageWindows));
2117+}
2118+
2119+void StorageLauncherIcon::UpdateStorageWindows()
2120+{
2121+ bool active = false;
2122+ bool urgent = false;
2123+ bool check_visibility = (GetIconType() == IconType::APPLICATION);
2124+ bool visible = IsSticky();
2125+
2126+ managed_windows_ = GetStorageWindows();
2127+ windows_connections_.Clear();
2128+
2129+ for (auto const& win : managed_windows_)
2130+ {
2131+ windows_connections_.Add(win->monitor.changed.connect([this] (int) { EnsureWindowsLocation(); }));
2132+ windows_connections_.Add(win->urgent.changed.connect([this] (bool) { OnWindowStateChanged(); }));
2133+ windows_connections_.Add(win->active.changed.connect([this] (bool) { OnWindowStateChanged(); }));
2134+ windows_connections_.Add(win->closed.connect([this] { UpdateStorageWindows(); }));
2135+
2136+ if (!active && win->active())
2137+ active = true;
2138+
2139+ if (!urgent && win->urgent())
2140+ urgent = true;
2141+
2142+ if (check_visibility)
2143+ {
2144+ windows_connections_.Add(win->visible.changed.connect([this] (bool) { OnWindowStateChanged(); }));
2145+
2146+ if (!visible && win->visible())
2147+ visible = true;
2148+ }
2149+ }
2150+
2151+ SetQuirk(Quirk::RUNNING, !managed_windows_.empty());
2152+ SetQuirk(Quirk::ACTIVE, active);
2153+ SetQuirk(Quirk::URGENT, urgent);
2154+
2155+ if (check_visibility)
2156+ SetQuirk(Quirk::VISIBLE, visible);
2157+
2158+ EnsureWindowsLocation();
2159+}
2160+
2161+WindowList StorageLauncherIcon::GetManagedWindows() const
2162+{
2163+ return managed_windows_;
2164+}
2165+
2166+void StorageLauncherIcon::OnWindowStateChanged()
2167+{
2168+ bool active = false;
2169+ bool urgent = false;
2170+ bool check_visibility = (GetIconType() == IconType::APPLICATION);
2171+ bool visible = IsSticky();
2172+
2173+ for (auto const& win : managed_windows_)
2174+ {
2175+ if (!active && win->active())
2176+ active = true;
2177+
2178+ if (!urgent && win->urgent())
2179+ urgent = true;
2180+
2181+ if (check_visibility && !visible && win->visible())
2182+ visible = true;
2183+ }
2184+
2185+ SetQuirk(Quirk::ACTIVE, active);
2186+ SetQuirk(Quirk::URGENT, urgent);
2187+
2188+ if (check_visibility)
2189+ SetQuirk(Quirk::VISIBLE, visible);
2190+}
2191+
2192+bool StorageLauncherIcon::OnShouldHighlightOnDrag(DndData const& dnd_data)
2193+{
2194+ for (auto const& uri : dnd_data.Uris())
2195+ {
2196+ if (uri.find("file://") == 0)
2197+ return true;
2198+ }
2199+
2200+ return false;
2201+}
2202+
2203+} // namespace launcher
2204+} // namespace unity
2205
2206=== added file 'launcher/StorageLauncherIcon.h'
2207--- launcher/StorageLauncherIcon.h 1970-01-01 00:00:00 +0000
2208+++ launcher/StorageLauncherIcon.h 2016-02-09 10:44:04 +0000
2209@@ -0,0 +1,55 @@
2210+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
2211+/*
2212+ * Copyright (C) 2015 Canonical Ltd
2213+ *
2214+ * This program is free software: you can redistribute it and/or modify
2215+ * it under the terms of the GNU General Public License version 3 as
2216+ * published by the Free Software Foundation.
2217+ *
2218+ * This program is distributed in the hope that it will be useful,
2219+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2220+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2221+ * GNU General Public License for more details.
2222+ *
2223+ * You should have received a copy of the GNU General Public License
2224+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2225+ *
2226+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
2227+ */
2228+
2229+#ifndef STORAGE_LAUNCHER_ICON_H
2230+#define STORAGE_LAUNCHER_ICON_H
2231+
2232+#include "WindowedLauncherIcon.h"
2233+#include "unity-shared/FileManager.h"
2234+
2235+namespace unity
2236+{
2237+namespace launcher
2238+{
2239+
2240+class StorageLauncherIcon : public virtual WindowedLauncherIcon
2241+{
2242+public:
2243+ StorageLauncherIcon(AbstractLauncherIcon::IconType, FileManager::Ptr const&);
2244+
2245+protected:
2246+ void UpdateStorageWindows();
2247+ WindowList GetManagedWindows() const override;
2248+ virtual WindowList GetStorageWindows() const = 0;
2249+
2250+ bool OnShouldHighlightOnDrag(DndData const& dnd_data) override;
2251+
2252+private:
2253+ void OnWindowStateChanged();
2254+
2255+protected:
2256+ FileManager::Ptr file_manager_;
2257+ WindowList managed_windows_;
2258+ connection::Manager windows_connections_;
2259+};
2260+
2261+} // namespace launcher
2262+} // namespace unity
2263+
2264+#endif // STORAGE_LAUNCHER_ICON_H
2265
2266=== modified file 'launcher/SwitcherController.cpp'
2267--- launcher/SwitcherController.cpp 2015-12-16 02:16:57 +0000
2268+++ launcher/SwitcherController.cpp 2016-02-09 10:44:04 +0000
2269@@ -720,14 +720,11 @@
2270 uint64_t second_first = 0; // second icons first highest active
2271
2272 WindowManager& wm = WindowManager::Default();
2273- for (auto& window : first->Windows())
2274+ auto const& windows = (model_->only_apps_on_viewport) ? first->WindowsOnViewport() : first->Windows();
2275+
2276+ for (auto& window : windows)
2277 {
2278- Window xid = window->window_id();
2279-
2280- if (model_->only_apps_on_viewport && !wm.IsWindowOnCurrentDesktop(xid))
2281- continue;
2282-
2283- uint64_t num = wm.GetWindowActiveNumber(xid);
2284+ uint64_t num = wm.GetWindowActiveNumber(window->window_id());
2285
2286 if (num > first_highest)
2287 {
2288
2289=== modified file 'launcher/SwitcherModel.cpp'
2290--- launcher/SwitcherModel.cpp 2015-12-16 02:16:57 +0000
2291+++ launcher/SwitcherModel.cpp 2016-02-09 10:44:04 +0000
2292@@ -37,16 +37,7 @@
2293 bool CompareSwitcherItemsPriority(AbstractLauncherIcon::Ptr const& first,
2294 AbstractLauncherIcon::Ptr const& second)
2295 {
2296- if (first->GetIconType() == second->GetIconType())
2297- return first->SwitcherPriority() > second->SwitcherPriority();
2298-
2299- if (first->GetIconType() == AbstractLauncherIcon::IconType::DESKTOP)
2300- return true;
2301-
2302- if (second->GetIconType() == AbstractLauncherIcon::IconType::DESKTOP)
2303- return false;
2304-
2305- return first->GetIconType() < second->GetIconType();
2306+ return first->SwitcherPriority() > second->SwitcherPriority();
2307 }
2308 }
2309
2310@@ -174,7 +165,7 @@
2311
2312 void SwitcherModel::AddIcon(AbstractLauncherIcon::Ptr const& icon)
2313 {
2314- if (!icon || icon->GetIconType() != AbstractLauncherIcon::IconType::APPLICATION)
2315+ if (!icon)
2316 return;
2317
2318 if (icon->ShowInSwitcher(only_apps_on_viewport))
2319
2320=== modified file 'launcher/SwitcherView.cpp'
2321--- launcher/SwitcherView.cpp 2015-12-15 16:11:09 +0000
2322+++ launcher/SwitcherView.cpp 2016-02-09 10:44:04 +0000
2323@@ -538,7 +538,7 @@
2324 // tells the renderer to render arrows by number
2325 arg.running_on_viewport = true;
2326
2327- arg.window_indicators = icon->WindowsForMonitor(monitor).size();
2328+ arg.window_indicators = icon->WindowsVisibleOnMonitor(monitor);
2329 if (arg.window_indicators > 1)
2330 arg.running_arrow = true;
2331 else
2332
2333=== modified file 'launcher/TrashLauncherIcon.cpp'
2334--- launcher/TrashLauncherIcon.cpp 2014-04-16 01:24:47 +0000
2335+++ launcher/TrashLauncherIcon.cpp 2016-02-09 10:44:04 +0000
2336@@ -1,6 +1,6 @@
2337 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
2338 /*
2339- * Copyright (C) 2010-2013 Canonical Ltd
2340+ * Copyright (C) 2010-2015 Canonical Ltd
2341 *
2342 * This program is free software: you can redistribute it and/or modify
2343 * it under the terms of the GNU General Public License version 3 as
2344@@ -24,6 +24,7 @@
2345 #include "config.h"
2346 #include <glib/gi18n-lib.h>
2347 #include <NuxCore/Logger.h>
2348+#include <UnityCore/DesktopUtilities.h>
2349 #include <zeitgeist.h>
2350
2351 #include "QuicklistMenuItemLabel.h"
2352@@ -39,20 +40,19 @@
2353 DECLARE_LOGGER(logger, "unity.launcher.icon.trash");
2354 const std::string ZEITGEIST_UNITY_ACTOR = "application://compiz.desktop";
2355 const std::string TRASH_URI = "trash:";
2356+ const std::string TRASH_PATH = "file://" + DesktopUtilities::GetUserTrashDirectory();
2357 }
2358
2359-TrashLauncherIcon::TrashLauncherIcon(FileManager::Ptr const& fmo)
2360- : SimpleLauncherIcon(IconType::TRASH)
2361+TrashLauncherIcon::TrashLauncherIcon(FileManager::Ptr const& fm)
2362+ : WindowedLauncherIcon(IconType::TRASH)
2363+ , StorageLauncherIcon(GetIconType(), fm ? fm : GnomeFileManager::Get())
2364 , empty_(true)
2365- , file_manager_(fmo ? fmo : GnomeFileManager::Get())
2366 {
2367 tooltip_text = _("Trash");
2368 icon_name = "user-trash";
2369 position = Position::END;
2370 SetQuirk(Quirk::VISIBLE, true);
2371 SkipQuirkAnimation(Quirk::VISIBLE);
2372-
2373- SetQuirk(Quirk::RUNNING, file_manager_->IsTrashOpened());
2374 SetShortcut('t');
2375
2376 glib::Object<GFile> location(g_file_new_for_uri(TRASH_URI.c_str()));
2377@@ -67,20 +67,27 @@
2378 }
2379 else
2380 {
2381- trash_changed_signal_.Connect(trash_monitor_, "changed",
2382+ glib_signals_.Add<void, GFileMonitor*, GFile*, GFile*, GFileMonitorEvent>(trash_monitor_, "changed",
2383 [this] (GFileMonitor*, GFile*, GFile*, GFileMonitorEvent) {
2384 UpdateTrashIcon();
2385 });
2386 }
2387
2388- file_manager_->locations_changed.connect(sigc::mem_fun(this, &TrashLauncherIcon::OnOpenedLocationsChanged));
2389-
2390 UpdateTrashIcon();
2391-}
2392-
2393-void TrashLauncherIcon::OnOpenedLocationsChanged()
2394-{
2395- SetQuirk(Quirk::RUNNING, file_manager_->IsTrashOpened());
2396+ UpdateStorageWindows();
2397+}
2398+
2399+WindowList TrashLauncherIcon::GetStorageWindows() const
2400+{
2401+ auto windows = file_manager_->WindowsForLocation(TRASH_URI);
2402+ auto const& path_wins = file_manager_->WindowsForLocation(TRASH_PATH);
2403+ windows.insert(end(windows), begin(path_wins), end(path_wins));
2404+ return windows;
2405+}
2406+
2407+void TrashLauncherIcon::OpenInstanceLauncherIcon(Time timestamp)
2408+{
2409+ file_manager_->OpenTrash(timestamp);
2410 }
2411
2412 AbstractLauncherIcon::MenuItemsVector TrashLauncherIcon::GetMenus()
2413@@ -92,22 +99,43 @@
2414 dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Empty Trash…"));
2415 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, !empty_);
2416 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
2417- empty_activated_signal_.Connect(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
2418+ glib_signals_.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
2419 [this] (DbusmenuMenuitem*, unsigned timestamp) {
2420 file_manager_->EmptyTrash(timestamp);
2421 });
2422
2423 result.push_back(menu_item);
2424
2425+ if (IsRunning())
2426+ {
2427+ auto const& windows_items = GetWindowsMenuItems();
2428+ if (!windows_items.empty())
2429+ {
2430+ menu_item = dbusmenu_menuitem_new();
2431+ dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
2432+ result.push_back(menu_item);
2433+
2434+ result.insert(end(result), begin(windows_items), end(windows_items));
2435+ }
2436+
2437+ menu_item = dbusmenu_menuitem_new();
2438+ dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
2439+ result.push_back(menu_item);
2440+
2441+ menu_item = dbusmenu_menuitem_new();
2442+ dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Quit"));
2443+ dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
2444+ dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
2445+ result.push_back(menu_item);
2446+
2447+ glib_signals_.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) {
2448+ Quit();
2449+ });
2450+ }
2451+
2452 return result;
2453 }
2454
2455-void TrashLauncherIcon::ActivateLauncherIcon(ActionArg arg)
2456-{
2457- SimpleLauncherIcon::ActivateLauncherIcon(arg);
2458- file_manager_->OpenTrash(arg.timestamp);
2459-}
2460-
2461 void TrashLauncherIcon::UpdateTrashIcon()
2462 {
2463 glib::Object<GFile> location(g_file_new_for_uri(TRASH_URI.c_str()));
2464
2465=== modified file 'launcher/TrashLauncherIcon.h'
2466--- launcher/TrashLauncherIcon.h 2013-04-03 20:45:58 +0000
2467+++ launcher/TrashLauncherIcon.h 2016-02-09 10:44:04 +0000
2468@@ -23,9 +23,10 @@
2469 #include <gio/gio.h>
2470 #include <UnityCore/GLibWrapper.h>
2471 #include <UnityCore/GLibSignal.h>
2472+#include <UnityCore/ConnectionManager.h>
2473
2474 #include "DndData.h"
2475-#include "SimpleLauncherIcon.h"
2476+#include "StorageLauncherIcon.h"
2477 #include "unity-shared/FileManager.h"
2478
2479 namespace unity
2480@@ -33,7 +34,7 @@
2481 namespace launcher
2482 {
2483
2484-class TrashLauncherIcon : public SimpleLauncherIcon
2485+class TrashLauncherIcon : public StorageLauncherIcon
2486 {
2487 public:
2488 TrashLauncherIcon(FileManager::Ptr const& = nullptr);
2489@@ -45,21 +46,18 @@
2490 bool OnShouldHighlightOnDrag(DndData const& dnd_data);
2491 void OnAcceptDrop(DndData const& dnd_data);
2492
2493+ WindowList GetStorageWindows() const override;
2494 std::string GetName() const;
2495
2496 private:
2497- void ActivateLauncherIcon(ActionArg arg);
2498- void OnOpenedLocationsChanged();
2499+ void OpenInstanceLauncherIcon(Time timestamp) override;
2500 MenuItemsVector GetMenus();
2501
2502 static void UpdateTrashIconCb(GObject* source, GAsyncResult* res, gpointer data);
2503
2504 bool empty_;
2505- FileManager::Ptr file_manager_;
2506 glib::Cancellable cancellable_;
2507 glib::Object<GFileMonitor> trash_monitor_;
2508- glib::Signal<void, GFileMonitor*, GFile*, GFile*, GFileMonitorEvent> trash_changed_signal_;
2509- glib::Signal<void, DbusmenuMenuitem*, unsigned> empty_activated_signal_;
2510 };
2511
2512 }
2513
2514=== modified file 'launcher/VolumeLauncherIcon.cpp'
2515--- launcher/VolumeLauncherIcon.cpp 2015-01-22 15:05:34 +0000
2516+++ launcher/VolumeLauncherIcon.cpp 2016-02-09 10:44:04 +0000
2517@@ -49,7 +49,7 @@
2518 , volume_(volume)
2519 , devices_settings_(devices_settings)
2520 , notification_(notification)
2521- , file_manager_(fm)
2522+ , file_manager_(parent_->file_manager_)
2523 {
2524 UpdateIcon();
2525 UpdateVisibility();
2526@@ -60,48 +60,41 @@
2527 {
2528 parent_->tooltip_text = volume_->GetName();
2529 parent_->icon_name = volume_->GetIconName();
2530- parent_->SetQuirk(Quirk::RUNNING, file_manager_->IsPrefixOpened(volume_->GetUri()));
2531 }
2532
2533 void UpdateVisibility()
2534 {
2535- UpdateKeepInLauncher();
2536- parent_->SetQuirk(Quirk::VISIBLE, keep_in_launcher_);
2537- }
2538-
2539- void UpdateKeepInLauncher()
2540- {
2541- auto const& identifier = volume_->GetIdentifier();
2542- keep_in_launcher_ = !devices_settings_->IsABlacklistedDevice(identifier);
2543+ parent_->SetQuirk(Quirk::VISIBLE, IsVisible());
2544+ }
2545+
2546+ bool IsBlackListed()
2547+ {
2548+ return devices_settings_->IsABlacklistedDevice(volume_->GetIdentifier());
2549+ }
2550+
2551+ bool IsVisible()
2552+ {
2553+ if (IsBlackListed() && parent_->GetManagedWindows().empty())
2554+ return false;
2555+
2556+ return true;
2557 }
2558
2559 void ConnectSignals()
2560 {
2561- connections_.Add(volume_->changed.connect(sigc::mem_fun(this, &Impl::OnVolumeChanged)));
2562+ connections_.Add(volume_->changed.connect([this] { UpdateIcon(); }));
2563 connections_.Add(volume_->removed.connect(sigc::mem_fun(this, &Impl::OnVolumeRemoved)));
2564- connections_.Add(devices_settings_->changed.connect(sigc::mem_fun(this, &Impl::OnSettingsChanged)));
2565- connections_.Add(file_manager_->locations_changed.connect(sigc::mem_fun(this, &Impl::UpdateIcon)));
2566- }
2567-
2568- void OnVolumeChanged()
2569- {
2570- UpdateIcon();
2571+ connections_.Add(devices_settings_->changed.connect([this] { UpdateVisibility(); }));
2572+ connections_.Add(parent_->windows_changed.connect([this] (int) { UpdateVisibility(); }));
2573 }
2574
2575 void OnVolumeRemoved()
2576 {
2577- if (devices_settings_->IsABlacklistedDevice(volume_->GetIdentifier()))
2578- devices_settings_->TryToUnblacklist(volume_->GetIdentifier());
2579-
2580+ devices_settings_->TryToUnblacklist(volume_->GetIdentifier());
2581 parent_->UnStick();
2582 parent_->Remove();
2583 }
2584
2585- void OnSettingsChanged()
2586- {
2587- UpdateVisibility();
2588- }
2589-
2590 bool CanEject() const
2591 {
2592 return volume_->CanBeEjected();
2593@@ -152,7 +145,7 @@
2594 void OpenInFileManager(uint64_t timestamp)
2595 {
2596 DoActionWhenMounted([this, timestamp] {
2597- file_manager_->OpenActiveChild(volume_->GetUri(), timestamp);
2598+ file_manager_->Open(volume_->GetUri(), timestamp);
2599 });
2600 }
2601
2602@@ -171,29 +164,38 @@
2603 AppendSeparatorItem(result);
2604 AppendNameItem(result);
2605 AppendSeparatorItem(result);
2606- AppendUnlockFromLauncherItem(result);
2607+ AppendWindowsItems(result);
2608+ AppendToggleLockFromLauncherItem(result);
2609 AppendEjectItem(result);
2610 AppendSafelyRemoveItem(result);
2611 AppendUnmountItem(result);
2612+ AppendQuitItem(result);
2613
2614 return result;
2615 }
2616
2617- void AppendUnlockFromLauncherItem(MenuItemsVector& menu)
2618+ void AppendToggleLockFromLauncherItem(MenuItemsVector& menu)
2619 {
2620 if (volume_->GetIdentifier().empty())
2621 return;
2622
2623 glib::Object<DbusmenuMenuitem> menu_item(dbusmenu_menuitem_new());
2624
2625- dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Unlock from Launcher"));
2626+ const char* label = IsBlackListed() ? _("Lock to Launcher") : _("Unlock from Launcher");
2627+ dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, label);
2628 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
2629 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
2630
2631- gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) {
2632- auto const& identifier = volume_->GetIdentifier();
2633- parent_->UnStick();
2634- devices_settings_->TryToBlacklist(identifier);
2635+ parent_->glib_signals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) {
2636+ if (!IsBlackListed())
2637+ {
2638+ parent_->UnStick();
2639+ devices_settings_->TryToBlacklist(volume_->GetIdentifier());
2640+ }
2641+ else
2642+ {
2643+ devices_settings_->TryToUnblacklist(volume_->GetIdentifier());
2644+ }
2645 }));
2646
2647 menu.push_back(menu_item);
2648@@ -220,13 +222,26 @@
2649 dbusmenu_menuitem_property_set_bool(menu_item, QuicklistMenuItem::MARKUP_ENABLED_PROPERTY, true);
2650 dbusmenu_menuitem_property_set_bool(menu_item, QuicklistMenuItem::MARKUP_ACCEL_DISABLED_PROPERTY, true);
2651
2652- gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, unsigned timestamp) {
2653+ parent_->glib_signals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, unsigned timestamp) {
2654 OpenInFileManager(timestamp);
2655 }));
2656
2657 menu.push_back(menu_item);
2658 }
2659
2660+ void AppendWindowsItems(MenuItemsVector& menu)
2661+ {
2662+ if (!parent_->IsRunning())
2663+ return;
2664+
2665+ auto const& windows_items = parent_->GetWindowsMenuItems();
2666+ if (!windows_items.empty())
2667+ {
2668+ menu.insert(end(menu), begin(windows_items), end(windows_items));
2669+ AppendSeparatorItem(menu);
2670+ }
2671+ }
2672+
2673 void AppendOpenItem(MenuItemsVector& menu)
2674 {
2675 glib::Object<DbusmenuMenuitem> menu_item(dbusmenu_menuitem_new());
2676@@ -235,7 +250,7 @@
2677 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
2678 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
2679
2680- gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, unsigned timestamp) {
2681+ parent_->glib_signals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, unsigned timestamp) {
2682 OpenInFileManager(timestamp);
2683 }));
2684
2685@@ -253,7 +268,8 @@
2686 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
2687 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
2688
2689- gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) {
2690+ parent_->glib_signals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) {
2691+ parent_->Quit();
2692 EjectAndShowNotification();
2693 }));
2694
2695@@ -271,8 +287,9 @@
2696 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
2697 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
2698
2699- gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) {
2700- volume_->StopDrive();
2701+ parent_->glib_signals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) {
2702+ parent_->Quit();
2703+ volume_->StopDrive();
2704 }));
2705
2706 menu.push_back(menu_item);
2707@@ -289,8 +306,29 @@
2708 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
2709 dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
2710
2711- gsignals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) {
2712- volume_->Unmount();
2713+ parent_->glib_signals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) {
2714+ volume_->Unmount();
2715+ }));
2716+
2717+ menu.push_back(menu_item);
2718+ }
2719+
2720+ void AppendQuitItem(MenuItemsVector& menu)
2721+ {
2722+ if (!parent_->IsRunning())
2723+ return;
2724+
2725+ if (!menu.empty())
2726+ AppendSeparatorItem(menu);
2727+
2728+ glib::Object<DbusmenuMenuitem> menu_item(dbusmenu_menuitem_new());
2729+
2730+ dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, _("Quit"));
2731+ dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
2732+ dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
2733+
2734+ parent_->glib_signals_.Add(new ItemSignal(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, [this] (DbusmenuMenuitem*, int) {
2735+ parent_->Quit();
2736 }));
2737
2738 menu.push_back(menu_item);
2739@@ -307,13 +345,10 @@
2740 }
2741
2742 VolumeLauncherIcon* parent_;
2743- bool keep_in_launcher_;
2744 Volume::Ptr volume_;
2745 DevicesSettings::Ptr devices_settings_;
2746 DeviceNotificationDisplay::Ptr notification_;
2747 FileManager::Ptr file_manager_;
2748-
2749- glib::SignalManager gsignals_;
2750 connection::Manager connections_;
2751 };
2752
2753@@ -325,15 +360,20 @@
2754 DevicesSettings::Ptr const& devices_settings,
2755 DeviceNotificationDisplay::Ptr const& notification,
2756 FileManager::Ptr const& fm)
2757- : SimpleLauncherIcon(IconType::DEVICE)
2758+ : WindowedLauncherIcon(IconType::DEVICE)
2759+ , StorageLauncherIcon(GetIconType(), fm)
2760 , pimpl_(new Impl(volume, devices_settings, notification, fm, this))
2761-{}
2762+{
2763+ UpdateStorageWindows();
2764+}
2765
2766 VolumeLauncherIcon::~VolumeLauncherIcon()
2767 {}
2768
2769 void VolumeLauncherIcon::AboutToRemove()
2770 {
2771+ StorageLauncherIcon::AboutToRemove();
2772+
2773 if (CanEject())
2774 EjectAndShowNotification();
2775 else if (CanStop())
2776@@ -360,12 +400,6 @@
2777 return pimpl_->StopDrive();
2778 }
2779
2780-void VolumeLauncherIcon::ActivateLauncherIcon(ActionArg arg)
2781-{
2782- SimpleLauncherIcon::ActivateLauncherIcon(arg);
2783- pimpl_->OpenInFileManager(arg.timestamp);
2784-}
2785-
2786 AbstractLauncherIcon::MenuItemsVector VolumeLauncherIcon::GetMenus()
2787 {
2788 return pimpl_->GetMenus();
2789@@ -388,17 +422,6 @@
2790 SetQuirk(Quirk::VISIBLE, true);
2791 }
2792
2793-bool VolumeLauncherIcon::OnShouldHighlightOnDrag(DndData const& dnd_data)
2794-{
2795- for (auto const& uri : dnd_data.Uris())
2796- {
2797- if (uri.find("file://") == 0)
2798- return true;
2799- }
2800-
2801- return false;
2802-}
2803-
2804 nux::DndAction VolumeLauncherIcon::OnQueryAcceptDrop(DndData const& dnd_data)
2805 {
2806 return dnd_data.Uris().empty() ? nux::DNDACTION_NONE : nux::DNDACTION_COPY;
2807@@ -412,6 +435,21 @@
2808 FullyAnimateQuirkDelayed(100, LauncherIcon::Quirk::SHIMMER);
2809 }
2810
2811+std::string VolumeLauncherIcon::GetVolumeUri() const
2812+{
2813+ return pimpl_->volume_->GetUri();
2814+}
2815+
2816+WindowList VolumeLauncherIcon::GetStorageWindows() const
2817+{
2818+ return file_manager_->WindowsForLocation(GetVolumeUri());
2819+}
2820+
2821+void VolumeLauncherIcon::OpenInstanceLauncherIcon(Time timestamp)
2822+{
2823+ pimpl_->OpenInFileManager(timestamp);
2824+}
2825+
2826 //
2827 // Introspection
2828 //
2829
2830=== modified file 'launcher/VolumeLauncherIcon.h'
2831--- launcher/VolumeLauncherIcon.h 2013-10-07 18:33:47 +0000
2832+++ launcher/VolumeLauncherIcon.h 2016-02-09 10:44:04 +0000
2833@@ -24,7 +24,7 @@
2834 #include "Volume.h"
2835 #include "DevicesSettings.h"
2836 #include "DeviceNotificationDisplay.h"
2837-#include "SimpleLauncherIcon.h"
2838+#include "StorageLauncherIcon.h"
2839 #include "unity-shared/FileManager.h"
2840
2841 namespace unity
2842@@ -32,7 +32,7 @@
2843 namespace launcher
2844 {
2845
2846-class VolumeLauncherIcon : public SimpleLauncherIcon
2847+class VolumeLauncherIcon : public StorageLauncherIcon
2848 {
2849 public:
2850 typedef nux::ObjectPtr<VolumeLauncherIcon> Ptr;
2851@@ -41,7 +41,7 @@
2852 DeviceNotificationDisplay::Ptr const&, FileManager::Ptr const&);
2853 virtual ~VolumeLauncherIcon();
2854
2855- virtual void AboutToRemove();
2856+ void AboutToRemove() override;
2857
2858 bool CanEject() const; // TODO: rename to public virtual bool IsTrashable();
2859 void EjectAndShowNotification(); // TODO: rename to private virtual void DoDropToTrash();
2860@@ -49,14 +49,16 @@
2861 void StopDrive();
2862 void Stick(bool save = true);
2863 void UnStick();
2864+
2865 MenuItemsVector GetMenus();
2866 std::string GetRemoteUri() const;
2867+ std::string GetVolumeUri() const;
2868
2869 protected:
2870- void ActivateLauncherIcon(ActionArg arg);
2871- bool OnShouldHighlightOnDrag(DndData const&);
2872 void OnAcceptDrop(DndData const&);
2873 nux::DndAction OnQueryAcceptDrop(DndData const&);
2874+ WindowList GetStorageWindows() const override;
2875+ void OpenInstanceLauncherIcon(Time timestamp) override;
2876
2877 // Introspection
2878 virtual std::string GetName() const;
2879
2880=== added file 'launcher/WindowedLauncherIcon.cpp'
2881--- launcher/WindowedLauncherIcon.cpp 1970-01-01 00:00:00 +0000
2882+++ launcher/WindowedLauncherIcon.cpp 2016-02-09 10:44:04 +0000
2883@@ -0,0 +1,618 @@
2884+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
2885+/*
2886+ * Copyright (C) 2015 Canonical Ltd
2887+ *
2888+ * This program is free software: you can redistribute it and/or modify
2889+ * it under the terms of the GNU General Public License version 3 as
2890+ * published by the Free Software Foundation.
2891+ *
2892+ * This program is distributed in the hope that it will be useful,
2893+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2894+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2895+ * GNU General Public License for more details.
2896+ *
2897+ * You should have received a copy of the GNU General Public License
2898+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2899+ *
2900+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
2901+ */
2902+
2903+#include <Nux/Nux.h>
2904+
2905+#include "WindowedLauncherIcon.h"
2906+#include "MultiMonitor.h"
2907+#include "unity-shared/UBusWrapper.h"
2908+#include "unity-shared/UBusMessages.h"
2909+#include "unity-shared/UScreen.h"
2910+
2911+namespace unity
2912+{
2913+namespace launcher
2914+{
2915+namespace
2916+{
2917+const std::string ICON_DND_OVER_TIMEOUT = "windowed-icon-dnd-over";
2918+const int COMPIZ_SCALE_DND_SPREAD = 1 << 7;
2919+const int MAXIMUM_QUICKLIST_WIDTH = 300;
2920+}
2921+
2922+NUX_IMPLEMENT_OBJECT_TYPE(WindowedLauncherIcon);
2923+
2924+WindowedLauncherIcon::WindowedLauncherIcon(AbstractLauncherIcon::IconType icon_type)
2925+ : SimpleLauncherIcon(icon_type)
2926+ , last_scroll_timestamp_(0)
2927+ , progressive_scroll_(0)
2928+{
2929+ WindowManager& wm = WindowManager::Default();
2930+ wm.window_minimized.connect(sigc::mem_fun(this, &WindowedLauncherIcon::OnWindowMinimized));
2931+ wm.screen_viewport_switch_ended.connect(sigc::mem_fun(this, &WindowedLauncherIcon::EnsureWindowState));
2932+ wm.terminate_expo.connect(sigc::mem_fun(this, &WindowedLauncherIcon::EnsureWindowState));
2933+ UScreen::GetDefault()->changed.connect(sigc::hide(sigc::hide(sigc::mem_fun(this, &WindowedLauncherIcon::EnsureWindowsLocation))));
2934+
2935+ windows_changed.connect([this] (int) {
2936+ if (WindowManager::Default().IsScaleActiveForGroup() && IsActive())
2937+ Spread(true, 0, false);
2938+ });
2939+}
2940+
2941+bool WindowedLauncherIcon::IsActive() const
2942+{
2943+ return GetQuirk(Quirk::ACTIVE);
2944+}
2945+
2946+bool WindowedLauncherIcon::IsRunning() const
2947+{
2948+ return GetQuirk(Quirk::RUNNING);
2949+}
2950+
2951+bool WindowedLauncherIcon::IsUrgent() const
2952+{
2953+ return GetQuirk(Quirk::URGENT);
2954+}
2955+
2956+bool WindowedLauncherIcon::IsUserVisible() const
2957+{
2958+ return IsRunning();
2959+}
2960+
2961+void WindowedLauncherIcon::ActivateLauncherIcon(ActionArg arg)
2962+{
2963+ SimpleLauncherIcon::ActivateLauncherIcon(arg);
2964+ WindowManager& wm = WindowManager::Default();
2965+
2966+ // This is a little awkward as the target is only set from the switcher.
2967+ if (arg.target)
2968+ {
2969+ // thumper: should we Raise too? should the WM raise?
2970+ wm.Activate(arg.target);
2971+ return;
2972+ }
2973+
2974+ bool scale_was_active = wm.IsScaleActive();
2975+ bool active = IsActive();
2976+ bool user_visible = IsRunning();
2977+ /* We should check each child to see if there is
2978+ * an unmapped (!= minimized) window around and
2979+ * if so force "Focus" behaviour */
2980+
2981+ if (arg.source != ActionArg::Source::SWITCHER)
2982+ {
2983+ user_visible = IsUserVisible();
2984+
2985+ if (active)
2986+ {
2987+ bool any_visible = false;
2988+ bool any_mapped = false;
2989+ bool any_on_top = false;
2990+ bool any_on_monitor = (arg.monitor < 0);
2991+ int active_monitor = arg.monitor;
2992+
2993+ for (auto const& window : GetManagedWindows())
2994+ {
2995+ Window xid = window->window_id();
2996+
2997+ if (!any_visible && wm.IsWindowOnCurrentDesktop(xid))
2998+ {
2999+ any_visible = true;
3000+ }
3001+
3002+ if (!any_mapped && wm.IsWindowMapped(xid))
3003+ {
3004+ any_mapped = true;
3005+ }
3006+
3007+ if (!any_on_top && wm.IsWindowOnTop(xid))
3008+ {
3009+ any_on_top = true;
3010+ }
3011+
3012+ if (!any_on_monitor && window->monitor() == arg.monitor &&
3013+ wm.IsWindowMapped(xid) && wm.IsWindowVisible(xid))
3014+ {
3015+ any_on_monitor = true;
3016+ }
3017+
3018+ if (window->active())
3019+ {
3020+ active_monitor = window->monitor();
3021+ }
3022+ }
3023+
3024+ if (!any_visible || !any_mapped || !any_on_top)
3025+ active = false;
3026+
3027+ if (any_on_monitor && arg.monitor >= 0 && active_monitor != arg.monitor)
3028+ active = false;
3029+ }
3030+ }
3031+
3032+ /* Behaviour:
3033+ * 1) Nothing running, or nothing visible -> launch application
3034+ * 2) Running and active -> spread application
3035+ * 3) Running and not active -> focus application
3036+ * 4) Spread is active and different icon pressed -> change spread
3037+ * 5) Spread is active -> Spread de-activated, and fall through
3038+ */
3039+
3040+ if (!IsRunning() || (IsRunning() && !user_visible)) // #1 above
3041+ {
3042+ if (GetQuirk(Quirk::STARTING, arg.monitor))
3043+ return;
3044+
3045+ wm.TerminateScale();
3046+ SetQuirk(Quirk::STARTING, true, arg.monitor);
3047+ OpenInstanceLauncherIcon(arg.timestamp);
3048+ }
3049+ else // container is running
3050+ {
3051+ if (active)
3052+ {
3053+ if (scale_was_active) // #5 above
3054+ {
3055+ wm.TerminateScale();
3056+
3057+ if (minimize_window_on_click())
3058+ {
3059+ for (auto const& win : GetWindows(WindowFilter::ON_CURRENT_DESKTOP))
3060+ wm.Minimize(win->window_id());
3061+ }
3062+ else
3063+ {
3064+ Focus(arg);
3065+ }
3066+ }
3067+ else // #2 above
3068+ {
3069+ if (arg.source != ActionArg::Source::SWITCHER)
3070+ {
3071+ bool minimized = false;
3072+
3073+ if (minimize_window_on_click())
3074+ {
3075+ WindowList const& windows = GetWindows(WindowFilter::ON_CURRENT_DESKTOP);
3076+
3077+ if (windows.size() == 1)
3078+ {
3079+ wm.Minimize(windows[0]->window_id());
3080+ minimized = true;
3081+ }
3082+ }
3083+
3084+ if (!minimized)
3085+ {
3086+ Spread(true, 0, false);
3087+ }
3088+ }
3089+ }
3090+ }
3091+ else
3092+ {
3093+ if (scale_was_active) // #4 above
3094+ {
3095+ if (GetWindows(WindowFilter::ON_CURRENT_DESKTOP).size() <= 1)
3096+ wm.TerminateScale();
3097+
3098+ Focus(arg);
3099+
3100+ if (arg.source != ActionArg::Source::SWITCHER)
3101+ Spread(true, 0, false);
3102+ }
3103+ else // #3 above
3104+ {
3105+ Focus(arg);
3106+ }
3107+ }
3108+ }
3109+}
3110+
3111+WindowList WindowedLauncherIcon::GetWindows(WindowFilterMask filter, int monitor)
3112+{
3113+ if ((!filter && monitor < 0) || (filter == WindowFilter::ON_ALL_MONITORS))
3114+ return GetManagedWindows();
3115+
3116+ WindowManager& wm = WindowManager::Default();
3117+ WindowList results;
3118+
3119+ monitor = (filter & WindowFilter::ON_ALL_MONITORS) ? -1 : monitor;
3120+ bool mapped = (filter & WindowFilter::MAPPED);
3121+ bool user_visible = (filter & WindowFilter::USER_VISIBLE);
3122+ bool current_desktop = (filter & WindowFilter::ON_CURRENT_DESKTOP);
3123+
3124+ for (auto& window : GetManagedWindows())
3125+ {
3126+ if ((monitor >= 0 && window->monitor() == monitor) || monitor < 0)
3127+ {
3128+ if ((user_visible && window->visible()) || !user_visible)
3129+ {
3130+ Window xid = window->window_id();
3131+
3132+ if ((mapped && wm.IsWindowMapped(xid)) || !mapped)
3133+ {
3134+ if ((current_desktop && wm.IsWindowOnCurrentDesktop(xid)) || !current_desktop)
3135+ {
3136+ results.push_back(window);
3137+ }
3138+ }
3139+ }
3140+ }
3141+ }
3142+
3143+ return results;
3144+}
3145+
3146+WindowList WindowedLauncherIcon::Windows()
3147+{
3148+ return GetWindows(WindowFilter::MAPPED|WindowFilter::ON_ALL_MONITORS);
3149+}
3150+
3151+WindowList WindowedLauncherIcon::WindowsOnViewport()
3152+{
3153+ WindowFilterMask filter = 0;
3154+ filter |= WindowFilter::MAPPED;
3155+ filter |= WindowFilter::USER_VISIBLE;
3156+ filter |= WindowFilter::ON_CURRENT_DESKTOP;
3157+ filter |= WindowFilter::ON_ALL_MONITORS;
3158+
3159+ return GetWindows(filter);
3160+}
3161+
3162+WindowList WindowedLauncherIcon::WindowsForMonitor(int monitor)
3163+{
3164+ WindowFilterMask filter = 0;
3165+ filter |= WindowFilter::MAPPED;
3166+ filter |= WindowFilter::USER_VISIBLE;
3167+ filter |= WindowFilter::ON_CURRENT_DESKTOP;
3168+
3169+ return GetWindows(filter, monitor);
3170+}
3171+
3172+void WindowedLauncherIcon::OnWindowMinimized(Window xid)
3173+{
3174+ for (auto const& window : GetManagedWindows())
3175+ {
3176+ if (xid == window->window_id())
3177+ {
3178+ int monitor = GetCenterForMonitor(window->monitor()).first;
3179+
3180+ if (monitor >= 0)
3181+ {
3182+ Present(0.5f, 600, monitor);
3183+ FullyAnimateQuirkDelayed(300, Quirk::SHIMMER, monitor);
3184+ }
3185+
3186+ break;
3187+ }
3188+ }
3189+}
3190+
3191+void WindowedLauncherIcon::Focus(ActionArg arg)
3192+{
3193+ bool show_only_visible = (arg.source == ActionArg::Source::SWITCHER);
3194+ ApplicationManager::Default().FocusWindowGroup(GetManagedWindows(), show_only_visible, arg.monitor);
3195+}
3196+
3197+bool WindowedLauncherIcon::Spread(bool current_desktop, int state, bool force)
3198+{
3199+ std::vector<Window> windows;
3200+ for (auto& window : GetWindows(current_desktop ? WindowFilter::ON_CURRENT_DESKTOP : 0))
3201+ windows.push_back(window->window_id());
3202+
3203+ return WindowManager::Default().ScaleWindowGroup(windows, state, force);
3204+}
3205+
3206+void WindowedLauncherIcon::EnsureWindowState()
3207+{
3208+ std::vector<int> number_of_windows_on_monitor(monitors::MAX);
3209+
3210+ for (auto const& window : WindowsOnViewport())
3211+ {
3212+ int monitor = window->monitor();
3213+
3214+ // If monitor is -1 (or negative), show on all monitors.
3215+ if (monitor < 0)
3216+ {
3217+ for (unsigned j; j < monitors::MAX; ++j)
3218+ ++number_of_windows_on_monitor[j];
3219+ }
3220+ else
3221+ {
3222+ ++number_of_windows_on_monitor[monitor];
3223+ }
3224+ }
3225+
3226+ for (unsigned i = 0; i < monitors::MAX; ++i)
3227+ SetNumberOfWindowsVisibleOnMonitor(number_of_windows_on_monitor[i], i);
3228+}
3229+
3230+void WindowedLauncherIcon::EnsureWindowsLocation()
3231+{
3232+ EnsureWindowState();
3233+ UpdateIconGeometries(GetCenters());
3234+}
3235+
3236+void WindowedLauncherIcon::UpdateIconGeometries(std::vector<nux::Point3> const& centers)
3237+{
3238+ nux::Geometry geo(0, 0, icon_size, icon_size);
3239+
3240+ for (auto& window : GetManagedWindows())
3241+ {
3242+ Window xid = window->window_id();
3243+ int monitor = GetCenterForMonitor(window->monitor()).first;
3244+
3245+ if (monitor < 0)
3246+ {
3247+ WindowManager::Default().SetWindowIconGeometry(xid, nux::Geometry());
3248+ continue;
3249+ }
3250+
3251+ geo.x = centers[monitor].x - icon_size / 2;
3252+ geo.y = centers[monitor].y - icon_size / 2;
3253+ WindowManager::Default().SetWindowIconGeometry(xid, geo);
3254+ }
3255+}
3256+
3257+void WindowedLauncherIcon::OnCenterStabilized(std::vector<nux::Point3> const& centers)
3258+{
3259+ UpdateIconGeometries(centers);
3260+}
3261+
3262+void WindowedLauncherIcon::OnDndEnter()
3263+{
3264+ auto timestamp = nux::GetGraphicsDisplay()->GetCurrentEvent().x11_timestamp;
3265+
3266+ _source_manager.AddTimeout(1000, [this, timestamp] {
3267+ bool to_spread = GetWindows(WindowFilter::ON_CURRENT_DESKTOP).size() > 1;
3268+
3269+ if (!to_spread)
3270+ WindowManager::Default().TerminateScale();
3271+
3272+ if (!IsRunning())
3273+ return false;
3274+
3275+ UBusManager::SendMessage(UBUS_OVERLAY_CLOSE_REQUEST);
3276+ Focus(ActionArg(ActionArg::Source::LAUNCHER, 1, timestamp));
3277+
3278+ if (to_spread)
3279+ Spread(true, COMPIZ_SCALE_DND_SPREAD, false);
3280+
3281+ return false;
3282+ }, ICON_DND_OVER_TIMEOUT);
3283+}
3284+
3285+void WindowedLauncherIcon::OnDndLeave()
3286+{
3287+ _source_manager.Remove(ICON_DND_OVER_TIMEOUT);
3288+}
3289+
3290+bool WindowedLauncherIcon::HandlesSpread()
3291+{
3292+ return true;
3293+}
3294+
3295+bool WindowedLauncherIcon::ShowInSwitcher(bool current)
3296+{
3297+ if (!removed() && IsRunning() && IsVisible())
3298+ {
3299+ // If current is true, we only want to show the current workspace.
3300+ if (!current)
3301+ {
3302+ return true;
3303+ }
3304+ else
3305+ {
3306+ for (unsigned i = 0; i < monitors::MAX; ++i)
3307+ {
3308+ if (WindowVisibleOnMonitor(i))
3309+ return true;
3310+ }
3311+ }
3312+ }
3313+
3314+ return false;
3315+}
3316+
3317+bool WindowedLauncherIcon::AllowDetailViewInSwitcher() const
3318+{
3319+ return true;
3320+}
3321+
3322+uint64_t WindowedLauncherIcon::SwitcherPriority()
3323+{
3324+ uint64_t result = 0;
3325+
3326+ for (auto& window : GetManagedWindows())
3327+ {
3328+ Window xid = window->window_id();
3329+ result = std::max(result, WindowManager::Default().GetWindowActiveNumber(xid));
3330+ }
3331+
3332+ return result;
3333+}
3334+
3335+void PerformScrollUp(WindowList const& windows, unsigned int progressive_scroll)
3336+{
3337+ if (progressive_scroll == windows.size() - 1)
3338+ {
3339+ //RestackAbove to preserve Global Stacking Order
3340+ WindowManager::Default().RestackBelow(windows.at(0)->window_id(), windows.at(1)->window_id());
3341+ WindowManager::Default().RestackBelow(windows.at(1)->window_id(), windows.at(0)->window_id());
3342+ windows.back()->Focus();
3343+ return;
3344+ }
3345+
3346+ WindowManager::Default().RestackBelow(windows.at(0)->window_id(), windows.at(progressive_scroll + 1)->window_id());
3347+ windows.at(progressive_scroll + 1)->Focus();
3348+}
3349+
3350+void PerformScrollDown(WindowList const& windows, unsigned int progressive_scroll)
3351+{
3352+ if (!progressive_scroll)
3353+ {
3354+ WindowManager::Default().RestackBelow(windows.at(0)->window_id(), windows.back()->window_id());
3355+ windows.at(1)->Focus();
3356+ return;
3357+ }
3358+
3359+ WindowManager::Default().RestackBelow(windows.at(0)->window_id(), windows.at(progressive_scroll)->window_id());
3360+ windows.at(progressive_scroll)->Focus();
3361+}
3362+
3363+void WindowedLauncherIcon::PerformScroll(ScrollDirection direction, Time timestamp)
3364+{
3365+ if (timestamp - last_scroll_timestamp_ < 150)
3366+ return;
3367+ else if (timestamp - last_scroll_timestamp_ > 1500)
3368+ progressive_scroll_ = 0;
3369+
3370+ last_scroll_timestamp_ = timestamp;
3371+
3372+ auto const& windows = GetWindowsOnCurrentDesktopInStackingOrder();
3373+
3374+ if (windows.empty())
3375+ return;
3376+
3377+ if (scroll_inactive_icons && !IsActive())
3378+ {
3379+ windows.at(0)->Focus();
3380+ return;
3381+ }
3382+
3383+ if (!scroll_inactive_icons && !IsActive())
3384+ return;
3385+
3386+ if (windows.size() <= 1)
3387+ return;
3388+
3389+ if (direction == ScrollDirection::DOWN)
3390+ ++progressive_scroll_;
3391+ else
3392+ //--progressive_scroll_; but roll to the top of windows
3393+ progressive_scroll_ += windows.size() - 1;
3394+ progressive_scroll_ %= windows.size();
3395+
3396+ switch(direction)
3397+ {
3398+ case ScrollDirection::UP:
3399+ PerformScrollUp(windows, progressive_scroll_);
3400+ break;
3401+ case ScrollDirection::DOWN:
3402+ PerformScrollDown(windows, progressive_scroll_);
3403+ break;
3404+ }
3405+}
3406+
3407+WindowList WindowedLauncherIcon::GetWindowsOnCurrentDesktopInStackingOrder()
3408+{
3409+ auto windows = GetWindows(WindowFilter::ON_CURRENT_DESKTOP | WindowFilter::ON_ALL_MONITORS);
3410+ auto sorted_windows = WindowManager::Default().GetWindowsInStackingOrder();
3411+
3412+ // Order the windows
3413+ std::sort(windows.begin(), windows.end(), [&sorted_windows] (ApplicationWindowPtr const& win1, ApplicationWindowPtr const& win2) {
3414+ for (auto const& window : sorted_windows)
3415+ {
3416+ if (window == win1->window_id())
3417+ return false;
3418+ else if (window == win2->window_id())
3419+ return true;
3420+ }
3421+
3422+ return true;
3423+ });
3424+
3425+ return windows;
3426+}
3427+
3428+void WindowedLauncherIcon::Quit() const
3429+{
3430+ for (auto& window : GetManagedWindows())
3431+ window->Quit();
3432+}
3433+
3434+void WindowedLauncherIcon::AboutToRemove()
3435+{
3436+ Quit();
3437+}
3438+
3439+AbstractLauncherIcon::MenuItemsVector WindowedLauncherIcon::GetWindowsMenuItems()
3440+{
3441+ auto const& windows = Windows();
3442+ MenuItemsVector menu_items;
3443+
3444+ // We only add quicklist menu-items for windows if we have more than one window
3445+ if (windows.size() < 2)
3446+ return menu_items;
3447+
3448+ // add menu items for all open windows
3449+ for (auto const& w : windows)
3450+ {
3451+ auto const& title = w->title();
3452+
3453+ if (title.empty())
3454+ continue;
3455+
3456+ glib::Object<DbusmenuMenuitem> menu_item(dbusmenu_menuitem_new());
3457+ dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_LABEL, title.c_str());
3458+ dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_ENABLED, true);
3459+ dbusmenu_menuitem_property_set_bool(menu_item, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
3460+ dbusmenu_menuitem_property_set_bool(menu_item, QuicklistMenuItem::MARKUP_ACCEL_DISABLED_PROPERTY, true);
3461+ dbusmenu_menuitem_property_set_int(menu_item, QuicklistMenuItem::MAXIMUM_LABEL_WIDTH_PROPERTY, MAXIMUM_QUICKLIST_WIDTH);
3462+
3463+ Window xid = w->window_id();
3464+ glib_signals_.Add<void, DbusmenuMenuitem*, unsigned>(menu_item, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
3465+ [xid] (DbusmenuMenuitem*, unsigned) {
3466+ WindowManager& wm = WindowManager::Default();
3467+ wm.Activate(xid);
3468+ wm.Raise(xid);
3469+ });
3470+
3471+ if (w->active())
3472+ {
3473+ dbusmenu_menuitem_property_set(menu_item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, DBUSMENU_MENUITEM_TOGGLE_RADIO);
3474+ dbusmenu_menuitem_property_set_int(menu_item, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED);
3475+ }
3476+
3477+ menu_items.push_back(menu_item);
3478+ }
3479+
3480+ return menu_items;
3481+}
3482+
3483+std::string WindowedLauncherIcon::GetName() const
3484+{
3485+ return "WindowedLauncherIcon";
3486+}
3487+
3488+void WindowedLauncherIcon::AddProperties(debug::IntrospectionData& introspection)
3489+{
3490+ SimpleLauncherIcon::AddProperties(introspection);
3491+
3492+ std::vector<Window> xids;
3493+ for (auto const& window : GetManagedWindows())
3494+ xids.push_back(window->window_id());
3495+
3496+ introspection.add("xids", glib::Variant::FromVector(xids))
3497+ .add("sticky", IsSticky());
3498+}
3499+
3500+} // namespace launcher
3501+} // namespace unity
3502
3503=== added file 'launcher/WindowedLauncherIcon.h'
3504--- launcher/WindowedLauncherIcon.h 1970-01-01 00:00:00 +0000
3505+++ launcher/WindowedLauncherIcon.h 2016-02-09 10:44:04 +0000
3506@@ -0,0 +1,100 @@
3507+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
3508+/*
3509+ * Copyright (C) 2015 Canonical Ltd
3510+ *
3511+ * This program is free software: you can redistribute it and/or modify
3512+ * it under the terms of the GNU General Public License version 3 as
3513+ * published by the Free Software Foundation.
3514+ *
3515+ * This program is distributed in the hope that it will be useful,
3516+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3517+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3518+ * GNU General Public License for more details.
3519+ *
3520+ * You should have received a copy of the GNU General Public License
3521+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3522+ *
3523+ * Authored by: Marco Trevisan <marco.trevisan@canonical.com>
3524+ */
3525+
3526+#ifndef WINDOWED_LAUNCHER_ICON_H
3527+#define WINDOWED_LAUNCHER_ICON_H
3528+
3529+#include <UnityCore/GLibSignal.h>
3530+
3531+#include "SimpleLauncherIcon.h"
3532+
3533+namespace unity
3534+{
3535+namespace launcher
3536+{
3537+
3538+class WindowedLauncherIcon : public SimpleLauncherIcon
3539+{
3540+ NUX_DECLARE_OBJECT_TYPE(WindowedLauncherIcon, SimpleLauncherIcon);
3541+public:
3542+ WindowedLauncherIcon(AbstractLauncherIcon::IconType);
3543+
3544+ WindowList Windows() override;
3545+ WindowList WindowsOnViewport() override;
3546+ WindowList WindowsForMonitor(int monitor) override;
3547+
3548+ virtual bool IsActive() const;
3549+ virtual bool IsRunning() const;
3550+ virtual bool IsUrgent() const;
3551+ virtual bool IsUserVisible() const;
3552+
3553+ virtual void Quit() const;
3554+
3555+protected:
3556+ virtual WindowList GetManagedWindows() const = 0;
3557+ void EnsureWindowState();
3558+ void EnsureWindowsLocation();
3559+
3560+ virtual void UpdateIconGeometries(std::vector<nux::Point3> const& centers);
3561+
3562+ std::string GetName() const override;
3563+ void AddProperties(debug::IntrospectionData&) override;
3564+
3565+ bool HandlesSpread() override;
3566+ bool ShowInSwitcher(bool current) override;
3567+ bool AllowDetailViewInSwitcher() const override;
3568+ uint64_t SwitcherPriority() override;
3569+ void AboutToRemove() override;
3570+
3571+ void ActivateLauncherIcon(ActionArg arg) override;
3572+ void PerformScroll(ScrollDirection direction, Time timestamp) override;
3573+ virtual void Focus(ActionArg arg);
3574+ virtual bool Spread(bool current_desktop, int state, bool force);
3575+
3576+ typedef unsigned long int WindowFilterMask;
3577+ enum WindowFilter
3578+ {
3579+ MAPPED = (1 << 0),
3580+ USER_VISIBLE = (1 << 1),
3581+ ON_CURRENT_DESKTOP = (1 << 2),
3582+ ON_ALL_MONITORS = (1 << 3),
3583+ };
3584+
3585+ WindowList GetWindows(WindowFilterMask filter = 0, int monitor = -1);
3586+ WindowList GetWindowsOnCurrentDesktopInStackingOrder();
3587+
3588+ MenuItemsVector GetWindowsMenuItems();
3589+
3590+private:
3591+ void OnCenterStabilized(std::vector<nux::Point3> const& centers) override;
3592+ void OnWindowMinimized(Window);
3593+ void OnDndEnter();
3594+ void OnDndLeave();
3595+
3596+ Time last_scroll_timestamp_;
3597+ unsigned int progressive_scroll_;
3598+
3599+protected:
3600+ glib::SignalManager glib_signals_;
3601+};
3602+
3603+} // namespace launcher
3604+} // namespace unity
3605+
3606+#endif // WINDOWED_LAUNCHER_ICON_H
3607
3608=== modified file 'tests/CMakeLists.txt'
3609--- tests/CMakeLists.txt 2015-12-11 12:45:49 +0000
3610+++ tests/CMakeLists.txt 2016-02-09 10:44:04 +0000
3611@@ -80,6 +80,7 @@
3612 set (GTEST_SLOW_SOURCES
3613 test_main.cpp
3614 logger_helper.cpp
3615+ mock-application.cpp
3616 test_switcher_controller_slow.cpp
3617 test_switcher_controller_class.cpp
3618 test_tooltip_manager.cpp
3619
3620=== modified file 'tests/mock-application.h'
3621--- tests/mock-application.h 2015-07-09 17:11:53 +0000
3622+++ tests/mock-application.h 2016-02-09 10:44:04 +0000
3623@@ -91,7 +91,7 @@
3624 return;
3625
3626 title_ = new_title;
3627- title.changed(title_);
3628+ title.changed.emit(title_);
3629 }
3630
3631 void SetIcon(std::string const& new_icon)
3632@@ -100,7 +100,16 @@
3633 return;
3634
3635 icon_ = new_icon;
3636- icon.changed(icon_);
3637+ icon.changed.emit(icon_);
3638+ }
3639+
3640+ void SetMonitor(int new_monitor)
3641+ {
3642+ if (monitor_ == new_monitor)
3643+ return;
3644+
3645+ monitor_ = new_monitor;
3646+ monitor.changed.emit(monitor_);
3647 }
3648 };
3649
3650@@ -329,6 +338,7 @@
3651 MOCK_CONST_METHOD0(GetActiveApplication, unity::ApplicationPtr());
3652 MOCK_CONST_METHOD1(GetWindowsForMonitor, unity::WindowList(int));
3653 MOCK_CONST_METHOD1(GetWindowForId, unity::ApplicationWindowPtr(Window));
3654+ MOCK_CONST_METHOD3(FocusWindowGroup, void(unity::WindowList const&, bool, int));
3655
3656 unity::ApplicationPtr LocalGetApplicationForDesktopFile(std::string const& desktop_file)
3657 {
3658
3659=== modified file 'tests/test_application_launcher_icon.cpp'
3660--- tests/test_application_launcher_icon.cpp 2015-05-22 16:04:12 +0000
3661+++ tests/test_application_launcher_icon.cpp 2016-02-09 10:44:04 +0000
3662@@ -50,7 +50,8 @@
3663 typedef nux::ObjectPtr<MockApplicationLauncherIcon> Ptr;
3664
3665 MockApplicationLauncherIcon(ApplicationPtr const& app)
3666- : ApplicationLauncherIcon(app)
3667+ : WindowedLauncherIcon(IconType::APPLICATION)
3668+ , ApplicationLauncherIcon(app)
3669 {
3670 ON_CALL(*this, Stick(_)).WillByDefault(Invoke([this] (bool save) { ApplicationLauncherIcon::Stick(save); }));
3671 ON_CALL(*this, Stick()).WillByDefault(Invoke([this] { ApplicationLauncherIcon::Stick(); }));
3672@@ -67,11 +68,14 @@
3673 bool LauncherIconIsSticky() const { return LauncherIcon::IsSticky(); }
3674 void LocalActivate(ActionArg a) { ApplicationLauncherIcon::ActivateLauncherIcon(a); }
3675
3676- using ApplicationLauncherIcon::IsFileManager;
3677 using ApplicationLauncherIcon::LogUnityEvent;
3678 using ApplicationLauncherIcon::Remove;
3679 using ApplicationLauncherIcon::SetApplication;
3680 using ApplicationLauncherIcon::GetApplication;
3681+ using ApplicationLauncherIcon::PerformScroll;
3682+ using LauncherIcon::BackgroundColor;
3683+ using LauncherIcon::GetRemoteUri;
3684+ using LauncherIcon::AllowDetailViewInSwitcher;
3685 };
3686
3687 MATCHER_P(AreArgsEqual, a, "")
3688@@ -90,15 +94,15 @@
3689 virtual void SetUp() override
3690 {
3691 usc_app = std::make_shared<MockApplication::Nice>(USC_DESKTOP, "softwarecenter");
3692- usc_icon = new NiceMock<MockApplicationLauncherIcon>(usc_app);
3693+ usc_icon = new MockApplicationLauncherIcon(usc_app);
3694 ASSERT_EQ(usc_icon->DesktopFile(), USC_DESKTOP);
3695
3696 empty_app = std::make_shared<MockApplication::Nice>(NO_ICON_DESKTOP);
3697- empty_icon = new NiceMock<MockApplicationLauncherIcon>(empty_app);
3698+ empty_icon = new MockApplicationLauncherIcon(empty_app);
3699 ASSERT_EQ(empty_icon->DesktopFile(), NO_ICON_DESKTOP);
3700
3701 mock_app = std::make_shared<MockApplication::Nice>();
3702- mock_icon = new NiceMock<MockApplicationLauncherIcon>(mock_app);
3703+ mock_icon = new MockApplicationLauncherIcon(mock_app);
3704 ASSERT_TRUE(mock_icon->DesktopFile().empty());
3705 }
3706
3707@@ -173,7 +177,7 @@
3708 {
3709 std::shared_ptr<MockApplication> app = std::make_shared<MockApplication::Nice>(USC_DESKTOP);
3710 {
3711- MockApplicationLauncherIcon::Ptr icon(new NiceMock<MockApplicationLauncherIcon>(app));
3712+ MockApplicationLauncherIcon::Ptr icon(new MockApplicationLauncherIcon(app));
3713 EXPECT_FALSE(app->closed.empty());
3714 }
3715
3716@@ -266,7 +270,7 @@
3717 auto app = std::make_shared<MockApplication::Nice>(USC_DESKTOP);
3718 app->sticky = true;
3719 app->desktop_file_ = UM_DESKTOP;
3720- MockApplicationLauncherIcon::Ptr icon(new NiceMock<MockApplicationLauncherIcon>(app));
3721+ MockApplicationLauncherIcon::Ptr icon(new MockApplicationLauncherIcon(app));
3722 ASSERT_TRUE(icon->IsSticky());
3723 EXPECT_TRUE(icon->LauncherIconIsSticky());
3724 }
3725@@ -275,7 +279,7 @@
3726 {
3727 auto app = std::make_shared<MockApplication::Nice>();
3728 app->sticky = true;
3729- MockApplicationLauncherIcon::Ptr icon(new NiceMock<MockApplicationLauncherIcon>(app));
3730+ MockApplicationLauncherIcon::Ptr icon(new MockApplicationLauncherIcon(app));
3731 ASSERT_FALSE(icon->IsSticky());
3732 EXPECT_FALSE(icon->LauncherIconIsSticky());
3733 }
3734@@ -291,7 +295,7 @@
3735 TEST_F(TestApplicationLauncherIcon, StickAndSaveDesktopLessAppCreatesNewDesktop)
3736 {
3737 auto app = std::make_shared<MockApplication::Nice>();
3738- MockApplicationLauncherIcon::Ptr icon(new NiceMock<MockApplicationLauncherIcon>(app));
3739+ MockApplicationLauncherIcon::Ptr icon(new MockApplicationLauncherIcon(app));
3740
3741 EXPECT_CALL(*app, CreateLocalDesktopFile());
3742 icon->Stick(true);
3743@@ -354,7 +358,7 @@
3744 TEST_F(TestApplicationLauncherIcon, UnstickDesktopLessAppLogEvent)
3745 {
3746 auto app = std::make_shared<MockApplication::Nice>();
3747- MockApplicationLauncherIcon::Ptr icon(new NiceMock<MockApplicationLauncherIcon>(app));
3748+ MockApplicationLauncherIcon::Ptr icon(new MockApplicationLauncherIcon(app));
3749
3750 EXPECT_CALL(*unity_app_, LogEvent(ApplicationEventType::ACCESS, _)).Times(0);
3751 icon->UnStick();
3752@@ -1103,25 +1107,6 @@
3753 dbusmenu_menuitem_handle_event(item, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0);
3754 }
3755
3756-TEST_F(TestApplicationLauncherIcon, IsFileManager)
3757-{
3758- EXPECT_FALSE(usc_icon->IsFileManager());
3759- EXPECT_FALSE(empty_icon->IsFileManager());
3760- EXPECT_FALSE(mock_icon->IsFileManager());
3761-
3762- auto app = std::make_shared<MockApplication::Nice>("/any/path/org.gnome.Nautilus.desktop", "Nautilus");
3763- MockApplicationLauncherIcon::Ptr icon(new NiceMock<MockApplicationLauncherIcon>(app));
3764- EXPECT_TRUE(icon->IsFileManager());
3765-
3766- app = std::make_shared<MockApplication::Nice>("/any/path/nautilus-folder-handler.desktop", "Nautilus");
3767- icon = new NiceMock<MockApplicationLauncherIcon>(app);
3768- EXPECT_TRUE(icon->IsFileManager());
3769-
3770- app = std::make_shared<MockApplication::Nice>("/any/path/nautilus-home.desktop", "Nautilus");
3771- icon = new NiceMock<MockApplicationLauncherIcon>(app);
3772- EXPECT_TRUE(icon->IsFileManager());
3773-}
3774-
3775 TEST_F(TestApplicationLauncherIcon, AllowDetailViewInSwitcher)
3776 {
3777 mock_app->type_ = AppType::NORMAL;
3778@@ -1232,7 +1217,7 @@
3779 mock_icon->Remove();
3780 ASSERT_FALSE(mock_app->seen);
3781
3782- MockApplicationLauncherIcon::Ptr new_icon(new NiceMock<MockApplicationLauncherIcon>(mock_app));
3783+ MockApplicationLauncherIcon::Ptr new_icon(new MockApplicationLauncherIcon(mock_app));
3784 mock_icon = nullptr;
3785
3786 EXPECT_TRUE(mock_app->seen);
3787
3788=== modified file 'tests/test_launcher_controller.cpp'
3789--- tests/test_launcher_controller.cpp 2015-04-16 14:38:54 +0000
3790+++ tests/test_launcher_controller.cpp 2016-02-09 10:44:04 +0000
3791@@ -136,8 +136,10 @@
3792
3793 struct MockApplicationLauncherIcon : ApplicationLauncherIcon
3794 {
3795- typedef NiceMock<MockApplicationLauncherIcon> Nice;
3796- typedef nux::ObjectPtr<MockApplicationLauncherIcon::Nice> Ptr;
3797+ // NiceMock doesn't work well with Virtual Inheritance, so we need to disable it
3798+ //typedef NiceMock<MockApplicationLauncherIcon> Nice;
3799+ typedef MockApplicationLauncherIcon Nice;
3800+ typedef nux::ObjectPtr<MockApplicationLauncherIcon> Ptr;
3801 typedef bool Fake;
3802
3803 MockApplicationLauncherIcon(Fake = true, std::string const& remote_uri = "")
3804@@ -154,7 +156,8 @@
3805 }
3806
3807 explicit MockApplicationLauncherIcon(ApplicationPtr const& app)
3808- : ApplicationLauncherIcon(app)
3809+ : WindowedLauncherIcon(IconType::APPLICATION)
3810+ , ApplicationLauncherIcon(app)
3811 {
3812 ON_CALL(*this, Stick(_)).WillByDefault(Invoke([this] (bool save) { ApplicationLauncherIcon::Stick(save); }));
3813 ON_CALL(*this, UnStick()).WillByDefault(Invoke([this] { ApplicationLauncherIcon::UnStick(); }));
3814@@ -170,15 +173,18 @@
3815 MOCK_CONST_METHOD0(GetRemoteUri, std::string());
3816 MOCK_METHOD1(Stick, void(bool));
3817 MOCK_METHOD0(UnStick, void());
3818- MOCK_METHOD0(Quit, void());
3819+ MOCK_CONST_METHOD0(Quit, void());
3820 };
3821
3822 struct MockVolumeLauncherIcon : public VolumeLauncherIcon
3823 {
3824 typedef nux::ObjectPtr<MockVolumeLauncherIcon> Ptr;
3825+ // typedef NiceMock<MockVolumeLauncherIcon> Nice;
3826+ typedef MockVolumeLauncherIcon Nice;
3827
3828 MockVolumeLauncherIcon()
3829- : VolumeLauncherIcon(Volume::Ptr(volume_ = new NiceMock<MockVolume>()),
3830+ : WindowedLauncherIcon(IconType::DEVICE)
3831+ , VolumeLauncherIcon(Volume::Ptr(volume_ = new NiceMock<MockVolume>()),
3832 std::make_shared<MockDevicesSettings::Nice>(),
3833 std::make_shared<MockDeviceNotificationDisplay::Nice>(),
3834 std::make_shared<MockFileManager::Nice>())
3835@@ -269,7 +275,7 @@
3836 void DisconnectSignals()
3837 {
3838 ApplicationManager::Default().application_started.clear();
3839- Impl()->device_section_.icon_added.clear();
3840+ Impl()->device_section_->icon_added.clear();
3841 Impl()->model_->icon_removed.clear();
3842 Impl()->model_->saved.clear();
3843 Impl()->model_->order_changed.clear();
3844@@ -640,8 +646,8 @@
3845
3846 TEST_F(TestLauncherController, CreateFavoriteDevice)
3847 {
3848- lc.Impl()->device_section_ = MockDeviceLauncherSection();
3849- auto const& icons = lc.Impl()->device_section_.GetIcons();
3850+ lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>();
3851+ auto const& icons = lc.Impl()->device_section_->GetIcons();
3852 auto const& device_icon = icons.front();
3853
3854 ASSERT_TRUE(device_icon.IsValid());
3855@@ -903,8 +909,8 @@
3856 {
3857 lc.ClearModel();
3858 lc.DisconnectSignals();
3859- lc.Impl()->device_section_ = MockDeviceLauncherSection();
3860- auto const& icons = lc.Impl()->device_section_.GetIcons();
3861+ lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>();
3862+ auto const& icons = lc.Impl()->device_section_->GetIcons();
3863 auto const& device_icon1 = icons.front();
3864 auto const& device_icon2 = *(std::next(icons.begin()));
3865
3866@@ -949,7 +955,7 @@
3867 TEST_F(TestLauncherController, SetupIcons)
3868 {
3869 lc.ClearModel();
3870- lc.Impl()->device_section_ = MockDeviceLauncherSection();
3871+ lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>();
3872 lc.Impl()->expo_icon_->UnStick();
3873 lc.Impl()->desktop_icon_->UnStick();
3874 auto const& model = lc.Impl()->model_;
3875@@ -970,7 +976,7 @@
3876 fav = lc.Impl()->GetIconByUri(FavoriteStore::URI_PREFIX_APP + app::SW_CENTER);
3877 EXPECT_EQ(model->IconIndex(fav), ++icon_index);
3878
3879- for (auto const& device : lc.Impl()->device_section_.GetIcons())
3880+ for (auto const& device : lc.Impl()->device_section_->GetIcons())
3881 ASSERT_EQ(model->IconIndex(device), ++icon_index);
3882
3883 fav = lc.Impl()->GetIconByUri(FavoriteStore::URI_PREFIX_APP + app::UPDATE_MANAGER);
3884@@ -995,7 +1001,7 @@
3885 TEST_F(TestLauncherController, ResetIconPriorities)
3886 {
3887 lc.ClearModel();
3888- lc.Impl()->device_section_ = MockDeviceLauncherSection();
3889+ lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>();
3890 auto const& model = lc.Impl()->model_;
3891
3892 favorite_store.AddFavorite(places::APPS_URI, -1);
3893@@ -1012,7 +1018,7 @@
3894
3895 int icon_index = -1;
3896
3897- for (auto const& device : lc.Impl()->device_section_.GetIcons())
3898+ for (auto const& device : lc.Impl()->device_section_->GetIcons())
3899 ASSERT_EQ(model->IconIndex(device), ++icon_index);
3900
3901 auto fav = lc.Impl()->GetIconByUri(FavoriteStore::URI_PREFIX_APP + app::SW_CENTER);
3902@@ -1043,8 +1049,8 @@
3903 TEST_F(TestLauncherController, GetLastIconPriorityUnSticky)
3904 {
3905 lc.ClearModel();
3906- lc.Impl()->device_section_ = MockDeviceLauncherSection(3);
3907- auto const& device_icons = lc.Impl()->device_section_.GetIcons();
3908+ lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(3);
3909+ auto const& device_icons = lc.Impl()->device_section_->GetIcons();
3910 auto const& last_device = device_icons.back();
3911
3912 favorite_store.SetFavorites({ places::DEVICES_URI,
3913@@ -1060,8 +1066,8 @@
3914 TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithAllStickyIcons)
3915 {
3916 lc.ClearModel();
3917- lc.Impl()->device_section_ = MockDeviceLauncherSection(3);
3918- auto const& device_icons = lc.Impl()->device_section_.GetIcons();
3919+ lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(3);
3920+ auto const& device_icons = lc.Impl()->device_section_->GetIcons();
3921 auto const& last_device = device_icons.back();
3922
3923 favorite_store.SetFavorites({ places::DEVICES_URI,
3924@@ -1080,8 +1086,8 @@
3925 TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithSomeStickyIcons)
3926 {
3927 lc.ClearModel();
3928- lc.Impl()->device_section_ = MockDeviceLauncherSection(3);
3929- auto const& device_icons = lc.Impl()->device_section_.GetIcons();
3930+ lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(3);
3931+ auto const& device_icons = lc.Impl()->device_section_->GetIcons();
3932 auto const& first_device = *(std::next(device_icons.rbegin()));
3933 auto const& last_device = device_icons.back();
3934
3935@@ -1100,7 +1106,7 @@
3936 TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithNoIcons)
3937 {
3938 lc.ClearModel();
3939- lc.Impl()->device_section_ = MockDeviceLauncherSection(0);
3940+ lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(0);
3941 lc.Impl()->SetupIcons();
3942 lc.DisconnectSignals();
3943
3944@@ -1111,7 +1117,7 @@
3945 TEST_F(TestLauncherController, GetLastIconPriorityUnStickyWithNoIconsAndUri)
3946 {
3947 lc.ClearModel();
3948- lc.Impl()->device_section_ = MockDeviceLauncherSection(0);
3949+ lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(0);
3950
3951 favorite_store.SetFavorites({ places::DEVICES_URI,
3952 FavoriteStore::URI_PREFIX_APP + app::SW_CENTER });
3953@@ -1136,11 +1142,11 @@
3954 TEST_F(TestLauncherController, GetLastIconPrioritySticky)
3955 {
3956 lc.ClearModel();
3957- lc.Impl()->device_section_ = MockDeviceLauncherSection(3);
3958+ lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(3);
3959 lc.Impl()->SetupIcons();
3960 lc.DisconnectSignals();
3961
3962- auto const& device_icons = lc.Impl()->device_section_.GetIcons();
3963+ auto const& device_icons = lc.Impl()->device_section_->GetIcons();
3964 auto const& first_device = device_icons.front();
3965
3966 int last_priority = lc.Impl()->GetLastIconPriority<VolumeLauncherIcon>("", true);
3967@@ -1150,8 +1156,8 @@
3968 TEST_F(TestLauncherController, GetLastIconPriorityStickyWithAllStickyIcons)
3969 {
3970 lc.ClearModel();
3971- lc.Impl()->device_section_ = MockDeviceLauncherSection(3);
3972- auto const& device_icons = lc.Impl()->device_section_.GetIcons();
3973+ lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(3);
3974+ auto const& device_icons = lc.Impl()->device_section_->GetIcons();
3975 auto const& last_device = device_icons.back();
3976
3977 favorite_store.SetFavorites({ places::DEVICES_URI,
3978@@ -1170,8 +1176,8 @@
3979 TEST_F(TestLauncherController, GetLastIconPriorityStickyWithSomeStickyIcons)
3980 {
3981 lc.ClearModel();
3982- lc.Impl()->device_section_ = MockDeviceLauncherSection(3);
3983- auto const& device_icons = lc.Impl()->device_section_.GetIcons();
3984+ lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(3);
3985+ auto const& device_icons = lc.Impl()->device_section_->GetIcons();
3986 auto const& first_device = *(std::next(device_icons.rbegin()));
3987
3988 favorite_store.SetFavorites({ places::DEVICES_URI,
3989@@ -1189,7 +1195,7 @@
3990 TEST_F(TestLauncherController, GetLastIconPriorityStickyWithNoIcons)
3991 {
3992 lc.ClearModel();
3993- lc.Impl()->device_section_ = MockDeviceLauncherSection(0);
3994+ lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>(0);
3995 lc.Impl()->SetupIcons();
3996 lc.DisconnectSignals();
3997
3998@@ -1240,8 +1246,8 @@
3999 TEST_F(TestLauncherController, LauncherAddRequestDeviceAdd)
4000 {
4001 auto const& model = lc.Impl()->model_;
4002- lc.Impl()->device_section_ = MockDeviceLauncherSection();
4003- auto const& icons = lc.Impl()->device_section_.GetIcons();
4004+ lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>();
4005+ auto const& icons = lc.Impl()->device_section_->GetIcons();
4006 auto const& device_icon = icons.front();
4007 auto const& icon_uri = device_icon->RemoteUri();
4008
4009@@ -1262,7 +1268,7 @@
4010 TEST_F(TestLauncherController, LauncherAddRequestDeviceStick)
4011 {
4012 auto const& model = lc.Impl()->model_;
4013- MockVolumeLauncherIcon::Ptr device_icon(new NiceMock<MockVolumeLauncherIcon>());
4014+ MockVolumeLauncherIcon::Ptr device_icon(new MockVolumeLauncherIcon::Nice());
4015 lc.Impl()->RegisterIcon(device_icon, std::numeric_limits<int>::max());
4016
4017 auto app_icons = model->GetSublist<ApplicationLauncherIcon>();
4018@@ -1287,7 +1293,7 @@
4019
4020 TEST_F(TestLauncherController, LauncherRemoveRequestDeviceEjects)
4021 {
4022- MockVolumeLauncherIcon::Ptr device_icon(new NiceMock<MockVolumeLauncherIcon>());
4023+ MockVolumeLauncherIcon::Ptr device_icon(new MockVolumeLauncherIcon::Nice());
4024
4025 EXPECT_CALL(*(device_icon->volume_), CanBeEjected())
4026 .WillRepeatedly(Return(true));
4027@@ -1302,7 +1308,7 @@
4028
4029 TEST_F(TestLauncherController, LauncherRemoveRequestDeviceStops)
4030 {
4031- MockVolumeLauncherIcon::Ptr device_icon(new NiceMock<MockVolumeLauncherIcon>());
4032+ MockVolumeLauncherIcon::Ptr device_icon(new MockVolumeLauncherIcon::Nice());
4033
4034 EXPECT_CALL(*(device_icon->volume_), CanBeEjected())
4035 .WillRepeatedly(Return(false));
4036@@ -1362,7 +1368,7 @@
4037 invisible_app->SetQuirk(AbstractLauncherIcon::Quirk::VISIBLE, false);
4038 lc.Impl()->RegisterIcon(invisible_app, ++priority);
4039
4040- MockVolumeLauncherIcon::Ptr sticky_device(new NiceMock<MockVolumeLauncherIcon>());
4041+ MockVolumeLauncherIcon::Ptr sticky_device(new MockVolumeLauncherIcon::Nice());
4042 sticky_device->Stick(false);
4043 lc.Impl()->RegisterIcon(sticky_device, ++priority);
4044
4045@@ -1393,7 +1399,7 @@
4046 sticky_app->Stick(false);
4047 lc.Impl()->RegisterIcon(sticky_app, ++priority);
4048
4049- MockVolumeLauncherIcon::Ptr sticky_device(new NiceMock<MockVolumeLauncherIcon>());
4050+ MockVolumeLauncherIcon::Ptr sticky_device(new MockVolumeLauncherIcon::Nice());
4051 sticky_device->Stick(false);
4052 lc.Impl()->RegisterIcon(sticky_device, ++priority);
4053
4054@@ -1422,7 +1428,7 @@
4055 sticky_app->Stick(false);
4056 lc.Impl()->RegisterIcon(sticky_app, ++priority);
4057
4058- MockVolumeLauncherIcon::Ptr sticky_device(new NiceMock<MockVolumeLauncherIcon>());
4059+ MockVolumeLauncherIcon::Ptr sticky_device(new MockVolumeLauncherIcon::Nice());
4060 sticky_device->Stick(false);
4061 lc.Impl()->RegisterIcon(sticky_device, ++priority);
4062
4063@@ -1447,7 +1453,7 @@
4064 sticky_app->Stick(false);
4065 lc.Impl()->RegisterIcon(sticky_app, ++priority);
4066
4067- MockVolumeLauncherIcon::Ptr sticky_device(new NiceMock<MockVolumeLauncherIcon>());
4068+ MockVolumeLauncherIcon::Ptr sticky_device(new MockVolumeLauncherIcon::Nice());
4069 sticky_device->Stick(false);
4070 lc.Impl()->RegisterIcon(sticky_device, ++priority);
4071
4072@@ -1597,9 +1603,9 @@
4073 TEST_F(TestLauncherController, OnFavoriteStoreFavoriteAddedDeviceSection)
4074 {
4075 lc.ClearModel();
4076- lc.Impl()->device_section_ = MockDeviceLauncherSection();
4077+ lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>();
4078 auto const& model = lc.Impl()->model_;
4079- auto const& icons = lc.Impl()->device_section_.GetIcons();
4080+ auto const& icons = lc.Impl()->device_section_->GetIcons();
4081 auto const& device_icon1(icons.front());
4082 auto const& device_icon2(*(std::next(icons.begin())));
4083
4084@@ -1634,10 +1640,10 @@
4085 TEST_F(TestLauncherController, OnFavoriteStoreFavoriteRemovedDevice)
4086 {
4087 lc.ClearModel();
4088- lc.Impl()->device_section_ = MockDeviceLauncherSection();
4089+ lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>();
4090 auto const& model = lc.Impl()->model_;
4091
4092- auto const& icons = lc.Impl()->device_section_.GetIcons();
4093+ auto const& icons = lc.Impl()->device_section_->GetIcons();
4094 auto const& device_icon(icons.front());
4095
4096 favorite_store.SetFavorites({ lc.Impl()->expo_icon_->RemoteUri(),
4097@@ -1660,10 +1666,10 @@
4098 TEST_F(TestLauncherController, OnFavoriteStoreFavoriteRemovedDeviceSection)
4099 {
4100 lc.ClearModel();
4101- lc.Impl()->device_section_ = MockDeviceLauncherSection();
4102+ lc.Impl()->device_section_ = std::make_shared<MockDeviceLauncherSection>();
4103 auto const& model = lc.Impl()->model_;
4104
4105- auto const& icons = lc.Impl()->device_section_.GetIcons();
4106+ auto const& icons = lc.Impl()->device_section_->GetIcons();
4107 auto const& device_icon1(icons.front());
4108 auto const& device_icon2(*(std::next(icons.begin())));
4109
4110@@ -1958,10 +1964,9 @@
4111 unity::glib::Object<BamfMockApplication> bamf_mock_application(bamf_mock_application_new());
4112 ApplicationPtr app(new unity::bamf::Application(mock_manager, unity::glib::object_cast<BamfApplication>(bamf_mock_application)));
4113
4114- MockApplicationLauncherIcon::Ptr our_icon;
4115-
4116+ AbstractLauncherIcon::Ptr our_icon;
4117 mock_manager.Default().application_started.emit(app);
4118-
4119+
4120 app->title.changed.emit("Hello");
4121 auto app_icons = lc.Impl()->model_->GetSublist<ApplicationLauncherIcon>();
4122
4123@@ -1971,7 +1976,7 @@
4124 {
4125 our_icon = icon;
4126 break;
4127- }
4128+ }
4129 }
4130 ASSERT_TRUE(our_icon);
4131 EXPECT_FALSE(our_icon->removed);
4132
4133=== modified file 'tests/test_mock_filemanager.h'
4134--- tests/test_mock_filemanager.h 2013-10-07 18:10:17 +0000
4135+++ tests/test_mock_filemanager.h 2016-02-09 10:44:04 +0000
4136@@ -32,15 +32,18 @@
4137 typedef testing::NiceMock<MockFileManager> Nice;
4138
4139 MOCK_METHOD2(Open, void(std::string const& uri, uint64_t time));
4140- MOCK_METHOD2(OpenActiveChild, void(std::string const& uri, uint64_t time));
4141 MOCK_METHOD1(OpenTrash, void(uint64_t time));
4142 MOCK_METHOD1(TrashFile, bool(std::string const& uri));
4143 MOCK_METHOD1(EmptyTrash, void(uint64_t time));
4144 MOCK_METHOD3(CopyFiles, void(std::set<std::string> const& files, std::string const& dest, uint64_t time));
4145- MOCK_CONST_METHOD0(OpenedLocations, std::vector<std::string>());
4146- MOCK_CONST_METHOD1(IsPrefixOpened, bool(std::string const& uri));
4147- MOCK_CONST_METHOD0(IsTrashOpened, bool());
4148- MOCK_CONST_METHOD0(IsDeviceOpened, bool());
4149+ MOCK_CONST_METHOD1(WindowsForLocation, WindowList(std::string const&));
4150+ MOCK_CONST_METHOD1(LocationForWindow, std::string(ApplicationWindowPtr const&));
4151+
4152+ MockFileManager()
4153+ {
4154+ using namespace testing;
4155+ ON_CALL(*this, WindowsForLocation(_)).WillByDefault(Return(WindowList()));
4156+ }
4157 };
4158
4159 }
4160
4161=== modified file 'tests/test_software_center_launcher_icon.cpp'
4162--- tests/test_software_center_launcher_icon.cpp 2015-03-13 13:49:16 +0000
4163+++ tests/test_software_center_launcher_icon.cpp 2016-02-09 10:44:04 +0000
4164@@ -62,16 +62,17 @@
4165 MockSoftwareCenterLauncherIcon(ApplicationPtr const& app,
4166 std::string const& aptdaemon_trans_id,
4167 std::string const& icon_path)
4168- : SoftwareCenterLauncherIcon(app, aptdaemon_trans_id, icon_path)
4169+ : WindowedLauncherIcon(IconType::APPLICATION)
4170+ , SoftwareCenterLauncherIcon(app, aptdaemon_trans_id, icon_path)
4171 {}
4172
4173 void LauncherIconUnstick() { LauncherIcon::UnStick(); }
4174
4175 using SoftwareCenterLauncherIcon::GetActualDesktopFileAfterInstall;
4176- using SoftwareCenterLauncherIcon::GetRemoteUri;
4177 using SoftwareCenterLauncherIcon::OnFinished;
4178 using SoftwareCenterLauncherIcon::OnPropertyChanged;
4179 using SoftwareCenterLauncherIcon::drag_window_;
4180+ using LauncherIcon::GetRemoteUri;
4181 };
4182
4183 nux::ObjectPtr<Launcher> CreateLauncher()
4184
4185=== modified file 'tests/test_switcher_controller.h'
4186--- tests/test_switcher_controller.h 2015-11-04 09:42:55 +0000
4187+++ tests/test_switcher_controller.h 2016-02-09 10:44:04 +0000
4188@@ -27,10 +27,11 @@
4189
4190 #include "test_utils.h"
4191 #include "DesktopLauncherIcon.h"
4192-#include "SimpleLauncherIcon.h"
4193+#include "WindowedLauncherIcon.h"
4194 #include "SwitcherController.h"
4195 #include "SwitcherView.h"
4196 #include "TimeUtil.h"
4197+#include "mock-application.h"
4198 #include "mock-base-window.h"
4199 #include "test_standalone_wm.h"
4200
4201@@ -48,35 +49,24 @@
4202 /**
4203 * A fake ApplicationWindow for verifying selection of the switcher.
4204 */
4205-class FakeApplicationWindow : public unity::ApplicationWindow
4206+struct FakeApplicationWindow : public ::testmocks::MockApplicationWindow::Nice
4207 {
4208-public:
4209+ typedef NiceMock<FakeApplicationWindow> Nice;
4210 FakeApplicationWindow(Window xid, uint64_t active_number = 0);
4211 ~FakeApplicationWindow();
4212-
4213- virtual WindowType type() const;
4214-
4215- virtual Window window_id() const;
4216- virtual int monitor() const;
4217- virtual unity::ApplicationPtr application() const;
4218- virtual bool Focus() const;
4219- virtual void Quit() const;
4220-
4221-private:
4222- Window xid_;
4223 };
4224
4225 /**
4226 * A fake LauncherIcon for verifying selection operations of the switcher.
4227 */
4228-struct FakeLauncherIcon : unity::launcher::SimpleLauncherIcon
4229+struct FakeLauncherIcon : unity::launcher::WindowedLauncherIcon
4230 {
4231 FakeLauncherIcon(std::string const& app_name, bool allow_detail_view, uint64_t priority);
4232
4233- unity::WindowList Windows() override;
4234 bool AllowDetailViewInSwitcher() const override;
4235 bool ShowInSwitcher(bool) override;
4236 uint64_t SwitcherPriority() override;
4237+ WindowList GetManagedWindows() const override;
4238
4239 bool allow_detail_view_;
4240 uint64_t priority_;
4241
4242=== modified file 'tests/test_switcher_controller_class.cpp'
4243--- tests/test_switcher_controller_class.cpp 2015-11-04 09:42:55 +0000
4244+++ tests/test_switcher_controller_class.cpp 2016-02-09 10:44:04 +0000
4245@@ -26,14 +26,13 @@
4246 using namespace std::chrono;
4247
4248 FakeApplicationWindow::FakeApplicationWindow(Window xid, uint64_t active_number)
4249- : xid_(xid)
4250+ : MockApplicationWindow::Nice(xid)
4251 {
4252- auto standalone_window = std::make_shared<StandaloneWindow>(xid_);
4253+ SetMonitor(-1);
4254+ auto standalone_window = std::make_shared<StandaloneWindow>(window_id());
4255 standalone_window->active_number = active_number;
4256 testwrapper::StandaloneWM::Get()->AddStandaloneWindow(standalone_window);
4257-
4258- title.SetGetterFunction([this] { return "FakeApplicationWindow"; });
4259- icon.SetGetterFunction([this] { return ""; });
4260+ ON_CALL(*this, Quit()).WillByDefault(Invoke([this] { WindowManager::Default().Close(window_id()); }));
4261 }
4262
4263 FakeApplicationWindow::~FakeApplicationWindow()
4264@@ -41,25 +40,17 @@
4265 testwrapper::StandaloneWM::Get()->Close(xid_);
4266 }
4267
4268-WindowType FakeApplicationWindow::type() const { return WindowType::MOCK; }
4269-
4270-Window FakeApplicationWindow::window_id() const { return xid_; }
4271-int FakeApplicationWindow::monitor() const { return -1; }
4272-ApplicationPtr FakeApplicationWindow::application() const { return ApplicationPtr(); }
4273-bool FakeApplicationWindow::Focus() const { return false; }
4274-void FakeApplicationWindow::Quit() const { WindowManager::Default().Close(xid_); }
4275-
4276 FakeLauncherIcon::FakeLauncherIcon(std::string const& app_name, bool allow_detail_view, uint64_t priority)
4277- : launcher::SimpleLauncherIcon(IconType::APPLICATION)
4278+ : launcher::WindowedLauncherIcon(IconType::APPLICATION)
4279 , allow_detail_view_(allow_detail_view)
4280 , priority_(priority)
4281- , window_list{ std::make_shared<FakeApplicationWindow>(priority_ | 0x0001, SwitcherPriority()),
4282- std::make_shared<FakeApplicationWindow>(priority_ | 0x0002, priority_) }
4283+ , window_list{ std::make_shared<FakeApplicationWindow::Nice>(priority_ | 0x0001, SwitcherPriority()),
4284+ std::make_shared<FakeApplicationWindow::Nice>(priority_ | 0x0002, priority_) }
4285 {
4286 tooltip_text = app_name;
4287 }
4288
4289-WindowList FakeLauncherIcon::Windows()
4290+WindowList FakeLauncherIcon::GetManagedWindows() const
4291 {
4292 return window_list;
4293 }
4294@@ -85,7 +76,7 @@
4295 //class TestSwitcherController : public testing::Test
4296 TestSwitcherController::TestSwitcherController()
4297 : animation_controller_(tick_source_)
4298- , mock_window_(new NiceMock<testmocks::MockBaseWindow>())
4299+ , mock_window_(new NiceMock<unity::testmocks::MockBaseWindow>())
4300 , controller_(std::make_shared<Controller>([this] { return mock_window_; }))
4301 {
4302 controller_->timeout_length = 0;
4303
4304=== modified file 'tests/test_trash_launcher_icon.cpp'
4305--- tests/test_trash_launcher_icon.cpp 2014-02-28 05:48:21 +0000
4306+++ tests/test_trash_launcher_icon.cpp 2016-02-09 10:44:04 +0000
4307@@ -27,9 +27,11 @@
4308 using namespace unity;
4309 using namespace unity::launcher;
4310 using namespace testing;
4311+using namespace testmocks;
4312
4313 namespace
4314 {
4315+const std::string TRASH_URI = "trash:";
4316
4317 struct TestTrashLauncherIcon : testmocks::TestUnityAppBase
4318 {
4319@@ -42,6 +44,12 @@
4320 TrashLauncherIcon icon;
4321 };
4322
4323+TEST_F(TestTrashLauncherIcon, InitState)
4324+{
4325+ EXPECT_FALSE(icon.GetQuirk(AbstractLauncherIcon::Quirk::RUNNING));
4326+ EXPECT_FALSE(icon.GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE));
4327+}
4328+
4329 TEST_F(TestTrashLauncherIcon, Position)
4330 {
4331 EXPECT_EQ(icon.position(), AbstractLauncherIcon::Position::END);
4332@@ -74,15 +82,77 @@
4333
4334 TEST_F(TestTrashLauncherIcon, RunningState)
4335 {
4336- EXPECT_CALL(*fm_, IsTrashOpened()).WillRepeatedly(Return(true));
4337+ auto win1 = std::make_shared<MockApplicationWindow::Nice>(g_random_int());
4338+ auto win2 = std::make_shared<MockApplicationWindow::Nice>(g_random_int());
4339+
4340+ ON_CALL(*fm_, WindowsForLocation(TRASH_URI)).WillByDefault(Return(WindowList({win1, win2})));
4341 fm_->locations_changed.emit();
4342 EXPECT_TRUE(icon.GetQuirk(AbstractLauncherIcon::Quirk::RUNNING));
4343
4344- EXPECT_CALL(*fm_, IsTrashOpened()).WillRepeatedly(Return(false));
4345+ ON_CALL(*fm_, WindowsForLocation(TRASH_URI)).WillByDefault(Return(WindowList()));
4346 fm_->locations_changed.emit();
4347 EXPECT_FALSE(icon.GetQuirk(AbstractLauncherIcon::Quirk::RUNNING));
4348 }
4349
4350+TEST_F(TestTrashLauncherIcon, ActiveState)
4351+{
4352+ auto win1 = std::make_shared<MockApplicationWindow::Nice>(g_random_int());
4353+ auto win2 = std::make_shared<MockApplicationWindow::Nice>(g_random_int());
4354+
4355+ ON_CALL(*fm_, WindowsForLocation(TRASH_URI)).WillByDefault(Return(WindowList({win1, win2})));
4356+ fm_->locations_changed.emit();
4357+ ASSERT_FALSE(icon.GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE));
4358+
4359+ win2->LocalFocus();
4360+ EXPECT_TRUE(icon.GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE));
4361+
4362+ ON_CALL(*fm_, WindowsForLocation(TRASH_URI)).WillByDefault(Return(WindowList()));
4363+ fm_->locations_changed.emit();
4364+ EXPECT_FALSE(icon.GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE));
4365+}
4366+
4367+TEST_F(TestTrashLauncherIcon, WindowsCount)
4368+{
4369+ WindowList windows((g_random_int() % 10) + 5);
4370+ for (unsigned i = 0; i < windows.capacity(); ++i)
4371+ windows[i] = std::make_shared<MockApplicationWindow::Nice>(g_random_int());
4372+
4373+ ON_CALL(*fm_, WindowsForLocation(TRASH_URI)).WillByDefault(Return(windows));
4374+ fm_->locations_changed.emit();
4375+ EXPECT_EQ(icon.Windows().size(), windows.size());
4376+}
4377+
4378+TEST_F(TestTrashLauncherIcon, WindowsPerMonitor)
4379+{
4380+ WindowList windows((g_random_int() % 10) + 5);
4381+ for (unsigned i = 0; i < windows.capacity(); ++i)
4382+ {
4383+ auto win = std::make_shared<MockApplicationWindow::Nice>(g_random_int());
4384+ win->monitor_ = i % 2;
4385+ windows[i] = win;
4386+ }
4387+
4388+ ON_CALL(*fm_, WindowsForLocation(TRASH_URI)).WillByDefault(Return(windows));
4389+ fm_->locations_changed.emit();
4390+
4391+ EXPECT_EQ(icon.WindowsVisibleOnMonitor(0), (windows.size() / 2) + (windows.size() % 2));
4392+ EXPECT_EQ(icon.WindowsVisibleOnMonitor(1), windows.size() / 2);
4393+}
4394+
4395+TEST_F(TestTrashLauncherIcon, WindowsOnMonitorChanges)
4396+{
4397+ auto win = std::make_shared<MockApplicationWindow::Nice>(g_random_int());
4398+ ON_CALL(*fm_, WindowsForLocation(TRASH_URI)).WillByDefault(Return(WindowList({win})));
4399+ fm_->locations_changed.emit();
4400+
4401+ EXPECT_EQ(icon.WindowsVisibleOnMonitor(0), 1);
4402+ EXPECT_EQ(icon.WindowsVisibleOnMonitor(1), 0);
4403+
4404+ win->SetMonitor(1);
4405+ EXPECT_EQ(icon.WindowsVisibleOnMonitor(0), 0);
4406+ EXPECT_EQ(icon.WindowsVisibleOnMonitor(1), 1);
4407+}
4408+
4409 TEST_F(TestTrashLauncherIcon, FilemanagerSignalDisconnection)
4410 {
4411 auto file_manager = std::make_shared<NiceMock<MockFileManager>>();
4412
4413=== modified file 'tests/test_volume_launcher_icon.cpp'
4414--- tests/test_volume_launcher_icon.cpp 2015-01-22 15:05:34 +0000
4415+++ tests/test_volume_launcher_icon.cpp 2016-02-09 10:44:04 +0000
4416@@ -27,8 +27,11 @@
4417 #include "test_utils.h"
4418 #include "test_mock_devices.h"
4419 #include "test_mock_filemanager.h"
4420+#include "mock-application.h"
4421+
4422 using namespace unity;
4423 using namespace unity::launcher;
4424+using namespace testmocks;
4425
4426 namespace
4427 {
4428@@ -43,7 +46,7 @@
4429 {
4430 SetupVolumeDefaultBehavior();
4431 SetupSettingsDefaultBehavior();
4432- icon_ = new NiceMock<VolumeLauncherIcon>(volume_, settings_, notifications_, file_manager_);
4433+ icon_ = new VolumeLauncherIcon(volume_, settings_, notifications_, file_manager_);
4434 }
4435
4436 void SetupSettingsDefaultBehavior()
4437@@ -94,7 +97,7 @@
4438
4439 void CreateIcon()
4440 {
4441- icon_ = new NiceMock<VolumeLauncherIcon>(volume_, settings_, notifications_, file_manager_);
4442+ icon_ = new VolumeLauncherIcon(volume_, settings_, notifications_, file_manager_);
4443 }
4444 };
4445
4446@@ -105,7 +108,7 @@
4447
4448 TEST_F(TestVolumeLauncherIconDelayedConstruction, TestRunningOnClosed)
4449 {
4450- ON_CALL(*file_manager_, IsPrefixOpened(volume_->GetUri())).WillByDefault(Return(false));
4451+ ON_CALL(*file_manager_, WindowsForLocation(_)).WillByDefault(Return(WindowList()));
4452 CreateIcon();
4453
4454 EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::RUNNING));
4455@@ -113,7 +116,8 @@
4456
4457 TEST_F(TestVolumeLauncherIconDelayedConstruction, TestRunningOnOpened)
4458 {
4459- ON_CALL(*file_manager_, IsPrefixOpened(volume_->GetUri())).WillByDefault(Return(true));
4460+ auto win = std::make_shared<MockApplicationWindow::Nice>(g_random_int());
4461+ ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList({win})));
4462 CreateIcon();
4463
4464 EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::RUNNING));
4465@@ -128,16 +132,91 @@
4466
4467 TEST_F(TestVolumeLauncherIcon, TestRunningStateOnLocationChangedClosed)
4468 {
4469- ON_CALL(*file_manager_, IsPrefixOpened(volume_->GetUri())).WillByDefault(Return(false));
4470+ ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList()));
4471 file_manager_->locations_changed.emit();
4472 EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::RUNNING));
4473 }
4474
4475 TEST_F(TestVolumeLauncherIcon, TestRunningStateOnLocationChangedOpened)
4476 {
4477- ON_CALL(*file_manager_, IsPrefixOpened(volume_->GetUri())).WillByDefault(Return(true));
4478- file_manager_->locations_changed.emit();
4479- EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::RUNNING));
4480+ auto win1 = std::make_shared<MockApplicationWindow::Nice>(g_random_int());
4481+ auto win2 = std::make_shared<MockApplicationWindow::Nice>(g_random_int());
4482+ ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList({win1, win2})));
4483+ file_manager_->locations_changed.emit();
4484+ EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::RUNNING));
4485+}
4486+
4487+TEST_F(TestVolumeLauncherIcon, RunningState)
4488+{
4489+ auto win1 = std::make_shared<MockApplicationWindow::Nice>(g_random_int());
4490+ auto win2 = std::make_shared<MockApplicationWindow::Nice>(g_random_int());
4491+
4492+ ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList({win1, win2})));
4493+ file_manager_->locations_changed.emit();
4494+ EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::RUNNING));
4495+
4496+ ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList()));
4497+ file_manager_->locations_changed.emit();
4498+ EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::RUNNING));
4499+}
4500+
4501+TEST_F(TestVolumeLauncherIcon, ActiveState)
4502+{
4503+ auto win1 = std::make_shared<MockApplicationWindow::Nice>(g_random_int());
4504+ auto win2 = std::make_shared<MockApplicationWindow::Nice>(g_random_int());
4505+
4506+ ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList({win1, win2})));
4507+ file_manager_->locations_changed.emit();
4508+ ASSERT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE));
4509+
4510+ win2->LocalFocus();
4511+ EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE));
4512+
4513+ ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList()));
4514+ file_manager_->locations_changed.emit();
4515+ EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE));
4516+}
4517+
4518+TEST_F(TestVolumeLauncherIcon, WindowsCount)
4519+{
4520+ WindowList windows((g_random_int() % 10) + 5);
4521+ for (unsigned i = 0; i < windows.capacity(); ++i)
4522+ windows[i] = std::make_shared<MockApplicationWindow::Nice>(g_random_int());
4523+
4524+ ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(windows));
4525+ file_manager_->locations_changed.emit();
4526+ EXPECT_EQ(icon_->Windows().size(), windows.size());
4527+}
4528+
4529+TEST_F(TestVolumeLauncherIcon, WindowsPerMonitor)
4530+{
4531+ WindowList windows((g_random_int() % 10) + 5);
4532+ for (unsigned i = 0; i < windows.capacity(); ++i)
4533+ {
4534+ auto win = std::make_shared<MockApplicationWindow::Nice>(g_random_int());
4535+ win->monitor_ = i % 2;
4536+ windows[i] = win;
4537+ }
4538+
4539+ ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(windows));
4540+ file_manager_->locations_changed.emit();
4541+
4542+ EXPECT_EQ(icon_->WindowsVisibleOnMonitor(0), (windows.size() / 2) + (windows.size() % 2));
4543+ EXPECT_EQ(icon_->WindowsVisibleOnMonitor(1), windows.size() / 2);
4544+}
4545+
4546+TEST_F(TestVolumeLauncherIcon, WindowsOnMonitorChanges)
4547+{
4548+ auto win = std::make_shared<MockApplicationWindow::Nice>(g_random_int());
4549+ ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList({win})));
4550+ file_manager_->locations_changed.emit();
4551+
4552+ EXPECT_EQ(icon_->WindowsVisibleOnMonitor(0), 1);
4553+ EXPECT_EQ(icon_->WindowsVisibleOnMonitor(1), 0);
4554+
4555+ win->SetMonitor(1);
4556+ EXPECT_EQ(icon_->WindowsVisibleOnMonitor(0), 0);
4557+ EXPECT_EQ(icon_->WindowsVisibleOnMonitor(1), 1);
4558 }
4559
4560 TEST_F(TestVolumeLauncherIcon, TestPosition)
4561@@ -240,6 +319,32 @@
4562 EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
4563 }
4564
4565+TEST_F(TestVolumeLauncherIcon, TestVisibilityWithWindows)
4566+{
4567+ ON_CALL(*settings_, IsABlacklistedDevice(volume_->GetIdentifier())).WillByDefault(Return(false));
4568+ settings_->changed.emit();
4569+ ASSERT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
4570+
4571+ auto win = std::make_shared<MockApplicationWindow::Nice>(g_random_int());
4572+ ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList({win})));
4573+ file_manager_->locations_changed.emit();
4574+
4575+ EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
4576+}
4577+
4578+TEST_F(TestVolumeLauncherIcon, TestVisibilityWithWindows_Blacklisted)
4579+{
4580+ ON_CALL(*settings_, IsABlacklistedDevice(volume_->GetIdentifier())).WillByDefault(Return(true));
4581+ settings_->changed.emit();
4582+ ASSERT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
4583+
4584+ auto win = std::make_shared<MockApplicationWindow::Nice>(g_random_int());
4585+ ON_CALL(*file_manager_, WindowsForLocation(volume_->GetUri())).WillByDefault(Return(WindowList({win})));
4586+ file_manager_->locations_changed.emit();
4587+
4588+ EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
4589+}
4590+
4591 TEST_F(TestVolumeLauncherIcon, TestUnlockFromLauncherMenuItem_VolumeWithoutIdentifier)
4592 {
4593 EXPECT_CALL(*volume_, GetIdentifier())
4594@@ -251,22 +356,22 @@
4595
4596 TEST_F(TestVolumeLauncherIcon, TestUnlockFromLauncherMenuItem_Success)
4597 {
4598+ ON_CALL(*settings_, IsABlacklistedDevice(volume_->GetIdentifier())).WillByDefault(Return(false));
4599+ settings_->changed.emit();
4600+ ASSERT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
4601 auto menuitem = GetMenuItemAtIndex(4);
4602
4603 ASSERT_STREQ(dbusmenu_menuitem_property_get(menuitem, DBUSMENU_MENUITEM_PROP_LABEL), "Unlock from Launcher");
4604 EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE));
4605 EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_ENABLED));
4606
4607- EXPECT_CALL(*settings_, TryToBlacklist(_))
4608- .Times(1);
4609-
4610- EXPECT_CALL(*settings_, IsABlacklistedDevice(_))
4611- .WillRepeatedly(Return(true));
4612-
4613+ EXPECT_CALL(*settings_, TryToBlacklist(volume_->GetIdentifier())).Times(1);
4614 dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0);
4615+
4616+ EXPECT_CALL(*settings_, IsABlacklistedDevice(volume_->GetIdentifier())).WillRepeatedly(Return(true));
4617 settings_->changed.emit(); // TryToBlacklist() works if DevicesSettings emits a changed signal.
4618
4619- ASSERT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
4620+ EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
4621 }
4622
4623 TEST_F(TestVolumeLauncherIcon, TestUnlockFromLauncherMenuItem_Failure)
4624@@ -277,12 +382,49 @@
4625 EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE));
4626 EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_ENABLED));
4627
4628- EXPECT_CALL(*settings_, TryToBlacklist(_))
4629- .Times(1);
4630-
4631- dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0);
4632-
4633- ASSERT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
4634+ EXPECT_CALL(*settings_, TryToBlacklist(volume_->GetIdentifier())).Times(1);
4635+ dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0);
4636+
4637+ EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
4638+}
4639+
4640+TEST_F(TestVolumeLauncherIcon, TestLockToLauncherMenuItem_Success)
4641+{
4642+ ON_CALL(*settings_, IsABlacklistedDevice(volume_->GetIdentifier())).WillByDefault(Return(true));
4643+ settings_->changed.emit();
4644+ ASSERT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
4645+
4646+ auto menuitem = GetMenuItemAtIndex(4);
4647+
4648+ ASSERT_STREQ(dbusmenu_menuitem_property_get(menuitem, DBUSMENU_MENUITEM_PROP_LABEL), "Lock to Launcher");
4649+ EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE));
4650+ EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_ENABLED));
4651+
4652+ EXPECT_CALL(*settings_, TryToUnblacklist(volume_->GetIdentifier())).Times(1);
4653+ dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0);
4654+
4655+ EXPECT_CALL(*settings_, IsABlacklistedDevice(_)).WillRepeatedly(Return(false));
4656+ settings_->changed.emit(); // TryToBlacklist() works if DevicesSettings emits a changed signal.
4657+
4658+ EXPECT_TRUE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
4659+}
4660+
4661+TEST_F(TestVolumeLauncherIcon, TestLockToLauncherMenuItem_Failure)
4662+{
4663+ ON_CALL(*settings_, IsABlacklistedDevice(volume_->GetIdentifier())).WillByDefault(Return(true));
4664+ settings_->changed.emit();
4665+ ASSERT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
4666+
4667+ auto menuitem = GetMenuItemAtIndex(4);
4668+
4669+ ASSERT_STREQ(dbusmenu_menuitem_property_get(menuitem, DBUSMENU_MENUITEM_PROP_LABEL), "Lock to Launcher");
4670+ EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE));
4671+ EXPECT_TRUE(dbusmenu_menuitem_property_get_bool(menuitem, DBUSMENU_MENUITEM_PROP_ENABLED));
4672+
4673+ EXPECT_CALL(*settings_, TryToUnblacklist(volume_->GetIdentifier())).Times(1);
4674+ dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, 0);
4675+
4676+ EXPECT_FALSE(icon_->GetQuirk(AbstractLauncherIcon::Quirk::VISIBLE));
4677 }
4678
4679 TEST_F(TestVolumeLauncherIcon, TestOpenMenuItem)
4680@@ -298,7 +440,7 @@
4681
4682 InSequence seq;
4683 EXPECT_CALL(*volume_, Mount());
4684- EXPECT_CALL(*file_manager_, OpenActiveChild(volume_->GetUri(), time));
4685+ EXPECT_CALL(*file_manager_, Open(volume_->GetUri(), time));
4686
4687 dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, time);
4688 }
4689@@ -318,7 +460,7 @@
4690
4691 InSequence seq;
4692 EXPECT_CALL(*volume_, Mount());
4693- EXPECT_CALL(*file_manager_, OpenActiveChild(volume_->GetUri(), time));
4694+ EXPECT_CALL(*file_manager_, Open(volume_->GetUri(), time));
4695
4696 dbusmenu_menuitem_handle_event(menuitem, DBUSMENU_MENUITEM_EVENT_ACTIVATED, nullptr, time);
4697 }
4698@@ -438,7 +580,7 @@
4699 EXPECT_CALL(*settings_, TryToBlacklist(_))
4700 .Times(0);
4701 EXPECT_CALL(*settings_, TryToUnblacklist(_))
4702- .Times(0);
4703+ .Times(1);
4704
4705 volume_->removed.emit();
4706 }
4707@@ -451,7 +593,7 @@
4708 EXPECT_CALL(*settings_, TryToBlacklist(_))
4709 .Times(0);
4710 EXPECT_CALL(*settings_, TryToUnblacklist(_))
4711- .Times(0);
4712+ .Times(1);
4713
4714 volume_->removed.emit();
4715 }
4716@@ -516,7 +658,7 @@
4717 uint64_t time = g_random_int();
4718 InSequence seq;
4719 EXPECT_CALL(*volume_, Mount()).Times(0);
4720- EXPECT_CALL(*file_manager_, OpenActiveChild(volume_->GetUri(), time));
4721+ EXPECT_CALL(*file_manager_, Open(volume_->GetUri(), time));
4722 icon_->Activate(ActionArg(ActionArg::Source::LAUNCHER, 0, time));
4723 }
4724
4725@@ -526,7 +668,7 @@
4726 ON_CALL(*volume_, IsMounted()).WillByDefault(Return(false));
4727 InSequence seq;
4728 EXPECT_CALL(*volume_, Mount());
4729- EXPECT_CALL(*file_manager_, OpenActiveChild(volume_->GetUri(), time));
4730+ EXPECT_CALL(*file_manager_, Open(volume_->GetUri(), time));
4731 icon_->Activate(ActionArg(ActionArg::Source::LAUNCHER, 0, time));
4732 }
4733
4734
4735=== modified file 'unity-shared/ApplicationManager.h'
4736--- unity-shared/ApplicationManager.h 2015-07-09 16:32:54 +0000
4737+++ unity-shared/ApplicationManager.h 2016-02-09 10:44:04 +0000
4738@@ -109,6 +109,8 @@
4739 nux::ROProperty<bool> active;
4740 nux::ROProperty<bool> urgent;
4741 nux::ROProperty<bool> maximized;
4742+
4743+ sigc::signal<void> closed;
4744 };
4745
4746
4747@@ -219,6 +221,7 @@
4748 virtual WindowList GetWindowsForMonitor(int monitor = -1) const = 0;
4749 virtual ApplicationPtr GetApplicationForWindow(Window xid) const = 0;
4750 virtual ApplicationWindowPtr GetWindowForId(Window xid) const = 0;
4751+ virtual void FocusWindowGroup(WindowList const&, bool show_on_visible, int monitor) const = 0;
4752
4753 sigc::signal<void, ApplicationPtr const&> application_started;
4754 sigc::signal<void, ApplicationPtr const&> application_stopped;
4755
4756=== modified file 'unity-shared/BamfApplicationManager.cpp'
4757--- unity-shared/BamfApplicationManager.cpp 2015-10-28 15:41:17 +0000
4758+++ unity-shared/BamfApplicationManager.cpp 2016-02-09 10:44:04 +0000
4759@@ -147,6 +147,7 @@
4760 });
4761 signals_.Add<void, BamfView*>(bamf_view_, "closed",
4762 [this] (BamfView* view) {
4763+ this->closed.emit();
4764 pool::wins_.erase(view);
4765 });
4766 }
4767@@ -473,7 +474,7 @@
4768 return pool::EnsureWindow(manager_, bamf_application_get_focusable_child(bamf_app_));
4769 }
4770
4771-void Application::Focus(bool show_only_visible, int monitor) const
4772+void Manager::FocusWindowGroup(WindowList const& wins, bool show_only_visible, int monitor) const
4773 {
4774 WindowManager& wm = WindowManager::Default();
4775 std::vector<Window> urgent_windows;
4776@@ -481,7 +482,7 @@
4777 std::vector<Window> non_visible_windows;
4778 bool any_visible = false;
4779
4780- for (auto& window : GetWindows())
4781+ for (auto& window : wins)
4782 {
4783 Window window_id = window->window_id();
4784 if (window->urgent())
4785@@ -526,12 +527,15 @@
4786 }
4787 }
4788
4789+void Application::Focus(bool show_only_visible, int monitor) const
4790+{
4791+ manager_.FocusWindowGroup(GetWindows(), show_only_visible, monitor);
4792+}
4793+
4794 void Application::Quit() const
4795 {
4796 for (auto& window : GetWindows())
4797- {
4798 window->Quit();
4799- }
4800 }
4801
4802 bool Application::CreateLocalDesktopFile() const
4803
4804=== modified file 'unity-shared/BamfApplicationManager.h'
4805--- unity-shared/BamfApplicationManager.h 2015-07-09 16:32:54 +0000
4806+++ unity-shared/BamfApplicationManager.h 2016-02-09 10:44:04 +0000
4807@@ -64,7 +64,7 @@
4808
4809 bool operator==(unity::ApplicationWindow const& other) const override
4810 {
4811- return static_cast<WindowBase const*>(this)->bamf_view_ == static_cast<WindowBase const&>(other).bamf_view_;
4812+ return static_cast<WindowBase const*>(this)->bamf_view_ == static_cast<WindowBase const&>(other).bamf_view_;
4813 }
4814 bool operator!=(unity::ApplicationWindow const& other) const override { return !(operator==(other)); }
4815 };
4816@@ -175,6 +175,8 @@
4817 ApplicationPtr EnsureApplication(BamfView*) const;
4818 ApplicationWindowPtr EnsureWindow(BamfView*) const;
4819
4820+ void FocusWindowGroup(WindowList const&, bool show_on_visible, int monitor) const;
4821+
4822 private:
4823 void OnViewOpened(BamfMatcher* matcher, BamfView* view);
4824 void OnViewClosed(BamfMatcher* matcher, BamfView* view);
4825
4826=== modified file 'unity-shared/FileManager.h'
4827--- unity-shared/FileManager.h 2013-10-07 18:10:17 +0000
4828+++ unity-shared/FileManager.h 2016-02-09 10:44:04 +0000
4829@@ -27,6 +27,8 @@
4830 #include <vector>
4831 #include <set>
4832 #include <sigc++/sigc++.h>
4833+#include "ApplicationManager.h"
4834+
4835
4836 namespace unity
4837 {
4838@@ -40,15 +42,12 @@
4839 virtual ~FileManager() = default;
4840
4841 virtual void Open(std::string const& uri, uint64_t timestamp = 0) = 0;
4842- virtual void OpenActiveChild(std::string const& uri, uint64_t timestamp = 0) = 0;
4843 virtual void OpenTrash(uint64_t timestamp) = 0;
4844- virtual std::vector<std::string> OpenedLocations() const = 0;
4845- virtual bool IsPrefixOpened(std::string const& uri) const = 0;
4846- virtual bool IsTrashOpened() const = 0;
4847- virtual bool IsDeviceOpened() const = 0;
4848 virtual void CopyFiles(std::set<std::string> const& uris, std::string const& dest, uint64_t timestamp = 0) = 0;
4849 virtual bool TrashFile(std::string const& uri) = 0;
4850 virtual void EmptyTrash(uint64_t timestamp = 0) = 0;
4851+ virtual WindowList WindowsForLocation(std::string const& location) const = 0;
4852+ virtual std::string LocationForWindow(ApplicationWindowPtr const&) const = 0;
4853
4854 sigc::signal<void> locations_changed;
4855
4856@@ -57,6 +56,6 @@
4857 FileManager& operator=(FileManager const&) = delete;
4858 };
4859
4860-}
4861+} // namespace unity
4862
4863 #endif
4864
4865=== modified file 'unity-shared/GnomeFileManager.cpp'
4866--- unity-shared/GnomeFileManager.cpp 2013-10-07 22:37:34 +0000
4867+++ unity-shared/GnomeFileManager.cpp 2016-02-09 10:44:04 +0000
4868@@ -21,8 +21,9 @@
4869 #include "GnomeFileManager.h"
4870 #include <NuxCore/Logger.h>
4871 #include <UnityCore/DesktopUtilities.h>
4872+#include <UnityCore/GLibSource.h>
4873+#include <UnityCore/GLibDBusProxy.h>
4874 #include <UnityCore/GLibWrapper.h>
4875-#include <UnityCore/GLibDBusProxy.h>
4876 #include <gdk/gdk.h>
4877 #include <gio/gio.h>
4878
4879@@ -33,10 +34,8 @@
4880 {
4881 DECLARE_LOGGER(logger, "unity.filemanager.gnome");
4882
4883-const std::string TRASH_URI = "trash:";
4884+const std::string TRASH_URI = "trash:///";
4885 const std::string FILE_SCHEMA = "file://";
4886-const std::string TRASH_PATH = FILE_SCHEMA + DesktopUtilities::GetUserDataDirectory() + "/Trash/files";
4887-const std::string DEVICES_PREFIX = FILE_SCHEMA + "/media/" + std::string(g_get_user_name());
4888
4889 const std::string NAUTILUS_NAME = "org.gnome.Nautilus";
4890 const std::string NAUTILUS_PATH = "/org/gnome/Nautilus";
4891@@ -48,64 +47,83 @@
4892 : parent_(parent)
4893 , filemanager_proxy_("org.freedesktop.FileManager1", "/org/freedesktop/FileManager1", "org.freedesktop.FileManager1")
4894 {
4895- auto callback = sigc::mem_fun(this, &Impl::OnOpenLocationsUpdated);
4896- filemanager_proxy_.GetProperty("OpenLocations", callback);
4897- filemanager_proxy_.ConnectProperty("OpenLocations", callback);
4898- }
4899-
4900- void OnOpenLocationsUpdated(GVariant* value)
4901- {
4902- if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING_ARRAY))
4903+ auto callback = sigc::mem_fun(this, &Impl::OnOpenLocationsXidsUpdated);
4904+ filemanager_proxy_.GetProperty("XUbuntuOpenLocationsXids", callback);
4905+ filemanager_proxy_.ConnectProperty("XUbuntuOpenLocationsXids", callback);
4906+ }
4907+
4908+ glib::DBusProxy::Ptr NautilusOperationsProxy() const
4909+ {
4910+ return std::make_shared<glib::DBusProxy>(NAUTILUS_NAME, NAUTILUS_PATH,
4911+ "org.gnome.Nautilus.FileOperations");
4912+ }
4913+
4914+ void OnOpenLocationsXidsUpdated(GVariant* value)
4915+ {
4916+ opened_location_for_xid_.clear();
4917+
4918+ if (!value)
4919+ {
4920+ LOG_WARN(logger) << "Locations have been invalidated, maybe there's no filemanager around...";
4921+ parent_->locations_changed.emit();
4922+ return;
4923+ }
4924+
4925+ if (!g_variant_is_of_type(value, G_VARIANT_TYPE("a{uas}")))
4926 {
4927 LOG_ERROR(logger) << "Locations value type is not matching the expected one!";
4928+ parent_->locations_changed.emit();
4929 return;
4930 }
4931
4932- opened_locations_.clear();
4933-
4934 GVariantIter iter;
4935- const char *str;
4936+ GVariantIter *str_iter;
4937+ const char *loc;
4938+ guint32 xid;
4939
4940 g_variant_iter_init(&iter, value);
4941
4942- while (g_variant_iter_loop(&iter, "s", &str))
4943- {
4944- LOG_DEBUG(logger) << "Opened location " << str;
4945- opened_locations_.push_back(str);
4946- }
4947-
4948- parent_->locations_changed.emit();
4949- }
4950-
4951- std::string GetOpenedPrefix(std::string const& uri, bool allow_equal = true)
4952- {
4953- glib::Object<GFile> uri_file(g_file_new_for_uri(uri.c_str()));
4954-
4955- for (auto const& loc : opened_locations_)
4956- {
4957- bool equal = false;
4958-
4959- glib::Object<GFile> loc_file(g_file_new_for_uri(loc.c_str()));
4960-
4961- if (allow_equal && g_file_equal(loc_file, uri_file))
4962- equal = true;
4963-
4964- if (equal || g_file_has_prefix(loc_file, uri_file))
4965- return loc;
4966- }
4967-
4968- return "";
4969- }
4970-
4971- glib::DBusProxy::Ptr NautilusOperationsProxy() const
4972- {
4973- return std::make_shared<glib::DBusProxy>(NAUTILUS_NAME, NAUTILUS_PATH,
4974- "org.gnome.Nautilus.FileOperations");
4975+ while (g_variant_iter_loop(&iter, "{uas}", &xid, &str_iter))
4976+ {
4977+ while (g_variant_iter_loop(str_iter, "s", &loc))
4978+ {
4979+ /* We only care about the first mentioned location as per our "standard"
4980+ * it's the active one */
4981+ LOG_DEBUG(logger) << xid << ": Opened location " << loc;
4982+ opened_location_for_xid_[xid] = loc;
4983+ break;
4984+ }
4985+ }
4986+
4987+ // We must ensure that we emit the locations_changed signal only when all
4988+ // the parent windows have been registered on the app-manager
4989+ auto app_manager_not_synced = [this]
4990+ {
4991+ auto& app_manager = ApplicationManager::Default();
4992+ bool synced = true;
4993+
4994+ for (auto const& pair : opened_location_for_xid_)
4995+ {
4996+ synced = (app_manager.GetWindowForId(pair.first) != nullptr);
4997+
4998+ if (!synced)
4999+ break;
5000+ }
The diff has been truncated for viewing.