Merge lp:~3v1n0/unity/switcher-better-active-app-check into lp:unity

Proposed by Marco Trevisan (Treviño)
Status: Merged
Approved by: Brandon Schaefer
Approved revision: no longer in the source branch.
Merged at revision: 3124
Proposed branch: lp:~3v1n0/unity/switcher-better-active-app-check
Merge into: lp:unity
Diff against target: 400 lines (+139/-48)
9 files modified
launcher/ApplicationLauncherIcon.cpp (+25/-0)
launcher/ApplicationLauncherIcon.h (+2/-0)
launcher/SwitcherController.cpp (+3/-4)
launcher/SwitcherModel.cpp (+20/-26)
launcher/SwitcherModel.h (+13/-12)
tests/mock-application.h (+49/-4)
tests/test_application_launcher_icon.cpp (+16/-1)
tests/test_switcher_model.cpp (+11/-0)
unity-shared/BamfApplicationManager.cpp (+0/-1)
To merge this branch: bzr merge lp:~3v1n0/unity/switcher-better-active-app-check
Reviewer Review Type Date Requested Status
Brandon Schaefer (community) Approve
PS Jenkins bot continuous-integration Pending
Review via email: mp+146540@code.launchpad.net

Commit message

ApplicationLauncherIcon: add a custom implementation of GetQuirk for Quirk::ACTIVE

We need to make sure that an application is set as active also if the WindowManager active window
is contained in the application windows list.

Description of the change

Due to the dbus nature of the bamfdaemon, it can happen that when quickly switching the application focus through Alt+Tab the unity active application is updated with some delay. This can lead to a wrong Alt+Tab behavior (see screencast on attached bug).

So, we need to ensure that an application is considered active when both BAMF has marked it as active and the active Window pointed by the WindowManager is a child of the application.

Made some minor cleanup of SwitcherModel, added new tests.

To post a comment you must log in.
Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

LGTM.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'launcher/ApplicationLauncherIcon.cpp'
2--- launcher/ApplicationLauncherIcon.cpp 2013-01-22 01:28:32 +0000
3+++ launcher/ApplicationLauncherIcon.cpp 2013-02-05 02:25:24 +0000
4@@ -173,6 +173,31 @@
5 }
6 }
7
8+bool ApplicationLauncherIcon::GetQuirk(AbstractLauncherIcon::Quirk quirk) const
9+{
10+ if (quirk == Quirk::ACTIVE)
11+ {
12+ if (!SimpleLauncherIcon::GetQuirk(Quirk::ACTIVE))
13+ return false;
14+
15+ if (app_->type() == "webapp")
16+ return true;
17+
18+ // Sometimes BAMF is not fast enough to update the active application
19+ // while quickly switching between apps, so we double check that the
20+ // real active window is part of the selection (see bug #1111620)
21+ Window active = WindowManager::Default().GetActiveWindow();
22+
23+ for (auto& window : app_->GetWindows())
24+ if (window->window_id() == active)
25+ return true;
26+
27+ return false;
28+ }
29+
30+ return SimpleLauncherIcon::GetQuirk(quirk);
31+}
32+
33 void ApplicationLauncherIcon::Remove()
34 {
35 /* Removing the unity-seen flag to the wrapped bamf application, on remove
36
37=== modified file 'launcher/ApplicationLauncherIcon.h'
38--- launcher/ApplicationLauncherIcon.h 2013-01-22 01:28:32 +0000
39+++ launcher/ApplicationLauncherIcon.h 2013-02-05 02:25:24 +0000
40@@ -51,6 +51,8 @@
41 bool IsRunning() const;
42 bool IsUrgent() const;
43
44+ virtual bool GetQuirk(Quirk quirk) const;
45+
46 virtual void Quit();
47 virtual void AboutToRemove();
48
49
50=== modified file 'launcher/SwitcherController.cpp'
51--- launcher/SwitcherController.cpp 2013-02-01 03:21:51 +0000
52+++ launcher/SwitcherController.cpp 2013-02-05 02:25:24 +0000
53@@ -547,17 +547,16 @@
54 if (model_)
55 {
56 application = model_->Selection();
57+
58 if (application)
59 {
60 if (model_->detail_selection)
61 {
62 window = model_->DetailSelectionWindow();
63 }
64- else if (application->GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE))
65+ else if (model_->SelectionIsActive())
66 {
67- auto const& xids = model_->DetailXids();
68- if (!xids.empty())
69- window = xids.front();
70+ window = model_->DetailXids().front();
71 }
72 }
73 }
74
75=== modified file 'launcher/SwitcherModel.cpp'
76--- launcher/SwitcherModel.cpp 2013-02-01 02:56:13 +0000
77+++ launcher/SwitcherModel.cpp 2013-02-05 02:25:24 +0000
78@@ -49,7 +49,7 @@
79
80 SwitcherModel::~SwitcherModel()
81 {
82- for (auto application : applications_)
83+ for (auto const& application : applications_)
84 {
85 RemoveChild(application.GetPointer());
86 }
87@@ -71,69 +71,64 @@
88 .add("last-selection-index", LastSelectionIndex());
89 }
90
91-SwitcherModel::iterator
92-SwitcherModel::begin()
93+SwitcherModel::iterator SwitcherModel::begin()
94 {
95 return applications_.begin();
96 }
97
98-SwitcherModel::iterator
99-SwitcherModel::end()
100+SwitcherModel::iterator SwitcherModel::end()
101 {
102 return applications_.end();
103 }
104
105-SwitcherModel::reverse_iterator
106-SwitcherModel::rbegin()
107+SwitcherModel::reverse_iterator SwitcherModel::rbegin()
108 {
109 return applications_.rbegin();
110 }
111
112-SwitcherModel::reverse_iterator
113-SwitcherModel::rend()
114+SwitcherModel::reverse_iterator SwitcherModel::rend()
115 {
116 return applications_.rend();
117 }
118
119-AbstractLauncherIcon::Ptr
120-SwitcherModel::at(unsigned int index)
121+AbstractLauncherIcon::Ptr SwitcherModel::at(unsigned int index) const
122 {
123 if ((int) index >= Size ())
124 return AbstractLauncherIcon::Ptr();
125 return applications_[index];
126 }
127
128-int
129-SwitcherModel::Size()
130+int SwitcherModel::Size() const
131 {
132 return applications_.size();
133 }
134
135-AbstractLauncherIcon::Ptr
136-SwitcherModel::Selection()
137+AbstractLauncherIcon::Ptr SwitcherModel::Selection() const
138 {
139 return applications_.at(index_);
140 }
141
142-int
143-SwitcherModel::SelectionIndex()
144+int SwitcherModel::SelectionIndex() const
145 {
146 return index_;
147 }
148
149-AbstractLauncherIcon::Ptr
150-SwitcherModel::LastSelection()
151+bool SwitcherModel::SelectionIsActive() const
152+{
153+ return Selection()->GetQuirk(AbstractLauncherIcon::Quirk::ACTIVE);
154+}
155+
156+AbstractLauncherIcon::Ptr SwitcherModel::LastSelection() const
157 {
158 return applications_.at(last_index_);
159 }
160
161-int SwitcherModel::LastSelectionIndex()
162+int SwitcherModel::LastSelectionIndex() const
163 {
164 return last_index_;
165 }
166
167-
168-std::vector<Window> SwitcherModel::DetailXids()
169+std::vector<Window> SwitcherModel::DetailXids() const
170 {
171 WindowManager& wm = WindowManager::Default();
172 std::vector<Window> results;
173@@ -159,7 +154,7 @@
174 return results;
175 }
176
177-Window SwitcherModel::DetailSelectionWindow()
178+Window SwitcherModel::DetailSelectionWindow() const
179 {
180 auto windows = DetailXids();
181 if (!detail_selection || windows.empty())
182@@ -209,7 +204,7 @@
183 detail_selection_index = 0;
184 }
185
186-void SwitcherModel::PrevDetail ()
187+void SwitcherModel::PrevDetail()
188 {
189 if (!detail_selection())
190 return;
191@@ -242,8 +237,7 @@
192 }
193 }
194
195-void
196-SwitcherModel::Select(unsigned int index)
197+void SwitcherModel::Select(unsigned int index)
198 {
199 unsigned int target = CLAMP(index, 0, applications_.size() - 1);
200
201
202=== modified file 'launcher/SwitcherModel.h'
203--- launcher/SwitcherModel.h 2013-01-15 22:46:58 +0000
204+++ launcher/SwitcherModel.h 2013-02-05 02:25:24 +0000
205@@ -70,18 +70,19 @@
206 reverse_iterator rbegin();
207 reverse_iterator rend();
208
209- launcher::AbstractLauncherIcon::Ptr at(unsigned int index);
210-
211- int Size();
212-
213- launcher::AbstractLauncherIcon::Ptr Selection();
214- int SelectionIndex();
215-
216- launcher::AbstractLauncherIcon::Ptr LastSelection();
217- int LastSelectionIndex();
218-
219- std::vector<Window> DetailXids ();
220- Window DetailSelectionWindow ();
221+ launcher::AbstractLauncherIcon::Ptr at(unsigned int index) const;
222+
223+ int Size() const;
224+
225+ launcher::AbstractLauncherIcon::Ptr Selection() const;
226+ int SelectionIndex() const;
227+ bool SelectionIsActive() const;
228+
229+ launcher::AbstractLauncherIcon::Ptr LastSelection() const;
230+ int LastSelectionIndex() const;
231+
232+ std::vector<Window> DetailXids() const;
233+ Window DetailSelectionWindow() const;
234
235 void Next();
236 void Prev();
237
238=== modified file 'tests/mock-application.h'
239--- tests/mock-application.h 2012-12-19 22:34:22 +0000
240+++ tests/mock-application.h 2013-02-05 02:25:24 +0000
241@@ -25,9 +25,45 @@
242
243 namespace testmocks
244 {
245-class MockApplication : public unity::Application
246-{
247-public:
248+struct MockApplicationWindow : unity::ApplicationWindow
249+{
250+ MockApplicationWindow(Window xid)
251+ : xid_(xid)
252+ , monitor_(0)
253+ , type_("window")
254+ , visible_(true)
255+ , active_(false)
256+ , urgent_(false)
257+ {
258+ visible.SetGetterFunction([this] { return visible_; });
259+ active.SetGetterFunction([this] { return active_; });
260+ urgent.SetGetterFunction([this] { return urgent_; });
261+ }
262+
263+ Window xid_;
264+ int monitor_;
265+ std::string title_;
266+ std::string icon_;
267+ std::string type_;
268+
269+ bool visible_;
270+ bool active_;
271+ bool urgent_;
272+
273+ virtual std::string title() const { return title_; }
274+ virtual std::string icon() const { return icon_; }
275+ virtual std::string type() const { return type_; }
276+
277+ virtual Window window_id() const { return xid_; }
278+ virtual int monitor() const { return monitor_; }
279+
280+ virtual unity::ApplicationPtr application() const { return unity::ApplicationPtr(); }
281+ virtual bool Focus() const { return false; }
282+ virtual void Quit() const {}
283+};
284+
285+struct MockApplication : unity::Application
286+{
287 MockApplication(std::string const& desktop_file,
288 std::string const& icon = "",
289 std::string const& title = "")
290@@ -51,6 +87,7 @@
291 urgent.SetGetterFunction(sigc::mem_fun(this, &MockApplication::GetUrgent));
292 }
293
294+ unity::WindowList window_list_;
295 std::string desktop_file_;
296 std::string icon_;
297 std::string title_;
298@@ -67,7 +104,7 @@
299 virtual std::string type() const { return "mock"; }
300 virtual std::string repr() const { return "MockApplication"; }
301
302- virtual unity::WindowList GetWindows() const { return unity::WindowList(); }
303+ virtual unity::WindowList GetWindows() const { return window_list_; }
304 virtual bool OwnsWindow(Window window_id) const { return false; }
305
306 virtual std::vector<std::string> GetSupportedMimeTypes() const { return {}; }
307@@ -98,6 +135,14 @@
308 return false;
309 }
310
311+ void SetActiveState(bool state)
312+ {
313+ if (active_ == state)
314+ return;
315+ active_ = state;
316+ active.changed.emit(state);
317+ }
318+
319 bool GetVisible() const { return visible_; }
320 bool GetActive() const { return active_; }
321 bool GetRunning() const { return running_; }
322
323=== modified file 'tests/test_application_launcher_icon.cpp'
324--- tests/test_application_launcher_icon.cpp 2012-11-23 04:05:35 +0000
325+++ tests/test_application_launcher_icon.cpp 2013-02-05 02:25:24 +0000
326@@ -28,7 +28,7 @@
327 #include "ApplicationLauncherIcon.h"
328 #include "FavoriteStore.h"
329 #include "mock-application.h"
330-
331+#include "StandaloneWindowManager.h"
332
333 using namespace unity;
334 using namespace testmocks;
335@@ -45,6 +45,7 @@
336 public:
337 virtual void SetUp()
338 {
339+ WM = dynamic_cast<StandaloneWindowManager*>(&WindowManager::Default());
340 usc_app.reset(new MockApplication(USC_DESKTOP, "softwarecenter"));
341 usc_icon = new launcher::ApplicationLauncherIcon(usc_app);
342 ASSERT_EQ(usc_icon->DesktopFile(), USC_DESKTOP);
343@@ -58,6 +59,7 @@
344 ASSERT_TRUE(mock_icon->DesktopFile().empty());
345 }
346
347+ StandaloneWindowManager* WM;
348 std::shared_ptr<MockApplication> usc_app;
349 std::shared_ptr<MockApplication> empty_app;
350 std::shared_ptr<MockApplication> mock_app;
351@@ -165,4 +167,17 @@
352 EXPECT_EQ(mock_icon->icon_name(), "icon-name");
353 }
354
355+TEST_F(TestApplicationLauncherIcon, ActiveQuirkWMCrossCheck)
356+{
357+ auto win = std::make_shared<MockApplicationWindow>(g_random_int());
358+ mock_app->window_list_ = { win };
359+ ASSERT_FALSE(mock_icon->IsActive());
360+
361+ mock_app->SetActiveState(true);
362+ ASSERT_FALSE(mock_icon->IsActive());
363+
364+ WM->AddStandaloneWindow(std::make_shared<StandaloneWindow>(win->window_id()));
365+ EXPECT_TRUE(mock_icon->IsActive());
366+}
367+
368 }
369
370=== modified file 'tests/test_switcher_model.cpp'
371--- tests/test_switcher_model.cpp 2012-12-18 00:11:20 +0000
372+++ tests/test_switcher_model.cpp 2013-02-05 02:25:24 +0000
373@@ -147,4 +147,15 @@
374 EXPECT_EQ(sorted, unsorted);
375 }
376
377+TEST_F(TestSwitcherModel, SelectionIsActive)
378+{
379+ SwitcherModel model(icons_);
380+
381+ model.Selection()->SetQuirk(AbstractLauncherIcon::Quirk::ACTIVE, false);
382+ EXPECT_FALSE(model.SelectionIsActive());
383+
384+ model.Selection()->SetQuirk(AbstractLauncherIcon::Quirk::ACTIVE, true);
385+ EXPECT_TRUE(model.SelectionIsActive());
386+}
387+
388 }
389
390=== modified file 'unity-shared/BamfApplicationManager.cpp'
391--- unity-shared/BamfApplicationManager.cpp 2013-01-09 19:41:24 +0000
392+++ unity-shared/BamfApplicationManager.cpp 2013-02-05 02:25:24 +0000
393@@ -68,7 +68,6 @@
394 bool View::GetActive() const
395 {
396 return bamf_view_is_active(bamf_view_);
397-
398 }
399
400 bool View::GetRunning() const