Merge lp:~alan-griffiths/miral/mru-window-visiblity into lp:miral

Proposed by Alan Griffiths
Status: Merged
Approved by: Gerry Boland
Approved revision: 517
Merged at revision: 515
Proposed branch: lp:~alan-griffiths/miral/mru-window-visiblity
Merge into: lp:miral
Diff against target: 216 lines (+100/-21)
3 files modified
miral/basic_window_manager.cpp (+17/-14)
miral/mru_window_list.cpp (+25/-3)
test/mru_window_list.cpp (+58/-4)
To merge this branch: bzr merge lp:~alan-griffiths/miral/mru-window-visiblity
Reviewer Review Type Date Requested Status
Gerry Boland (community) Approve
Review via email: mp+317613@code.launchpad.net

Commit message

Make the MRU window list aware of visiblity, instead of faking it

Description of the change

Make the MRU window list aware of visiblity, instead of faking it

So far we "got away" with removing and re-adding windows when they became invisible. But the existing code didn't scale to more than one window. (This became painfully obvious in the workspace example branch.)

To post a comment you must log in.
515. By Alan Griffiths

Fix Xenial build

Revision history for this message
Gerry Boland (gerboland) wrote :

Is there a specific bug this is fixing?

review: Needs Information
Revision history for this message
Gerry Boland (gerboland) wrote :

It looks reasonable, am just a bit unclear on exactly the problem case this is fixing. A test case would help me understand.

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

> It looks reasonable, am just a bit unclear on exactly the problem case this is
> fixing. A test case would help me understand.

Yeah, adding a test case makes sense. I was just wanting to split this out of the "example" MP.

The issue is that when we hide a bunch of surfaces and then unhide them we don't want to lose track of their order. That's a existing problem but became very obvious when playing with workspaces.

516. By Alan Griffiths

merge :parent

517. By Alan Griffiths

Some tests

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

> It looks reasonable, am just a bit unclear on exactly the problem case this is
> fixing. A test case would help me understand.

Without this the workspaces-example gets very confused when switching back to a workspace with multiple windows. So to see the problem you'd need to extract this code from that branch.

Under the hood, the mru list gets out of step with the Z order in the Mir "model" (as we don't guarantee to make windows visible in that order).

Medium term I think this logic needs to be better integrated with the Mir "model", but this papers over the cracks.

We need a lot more tests around the focus logic, I'm tempted to suggest leaving that for a follow-up branch.

Revision history for this message
Gerry Boland (gerboland) wrote :

Ok, I think I understand the issue & where you're going, so IMO you've added enough tests to cover this bit. Agreed deeper integration with Mir's model would be desirable in future.

review: Approve
Revision history for this message
Gerry Boland (gerboland) wrote :

"visiblity" or visibility?

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'miral/basic_window_manager.cpp'
2--- miral/basic_window_manager.cpp 2017-02-13 16:23:29 +0000
3+++ miral/basic_window_manager.cpp 2017-02-20 18:05:53 +0000
4@@ -1041,16 +1041,11 @@
5 window_info.state() == mir_window_state_minimized;
6
7 policy->advise_state_change(window_info, value);
8- window_info.state(value);
9-
10- mir_surface->configure(mir_window_attrib_state, value);
11
12 switch (value)
13 {
14 case mir_window_state_hidden:
15 case mir_window_state_minimized:
16- mir_surface->hide();
17-
18 if (window == active_window())
19 {
20 auto const workspaces_containing_window = workspaces_containing(window);
21@@ -1087,15 +1082,23 @@
22
23 if (window == active_window())
24 select_active_window({});
25-
26- mru_active_windows.erase(window);
27 }
28+
29+ window_info.state(value);
30+ mir_surface->configure(mir_window_attrib_state, value);
31+ mir_surface->hide();
32+
33 break;
34
35 default:
36+ auto const none_active = !active_window();
37+ window_info.state(value);
38+ mir_surface->configure(mir_window_attrib_state, value);
39 mir_surface->show();
40- if (was_hidden && !active_window())
41+ if (was_hidden && none_active)
42+ {
43 select_active_window(window);
44+ }
45 }
46 }
47
48@@ -1920,13 +1923,13 @@
49
50 std::function<void(WindowInfo const& info)> const add_children =
51 [&,this](WindowInfo const& info)
52+ {
53+ for (auto const& child : info.children())
54 {
55- for (auto const& child : info.children())
56- {
57- windows.push_back(child);
58- add_children(info_for(child));
59- }
60- };
61+ windows.push_back(child);
62+ add_children(info_for(child));
63+ }
64+ };
65
66 windows.push_back(root);
67 add_children(*info);
68
69=== modified file 'miral/mru_window_list.cpp'
70--- miral/mru_window_list.cpp 2017-02-02 11:31:52 +0000
71+++ miral/mru_window_list.cpp 2017-02-20 18:05:53 +0000
72@@ -18,8 +18,28 @@
73
74 #include "mru_window_list.h"
75
76+#include <mir/client/detail/mir_forward_compatibility.h>
77+#include <mir/scene/surface.h>
78+
79 #include <algorithm>
80
81+namespace
82+{
83+bool visible(miral::Window const& window)
84+{
85+ std::shared_ptr<mir::scene::Surface> const& surface{window};
86+
87+ switch (surface->state())
88+ {
89+ case mir_window_state_hidden:
90+ case mir_window_state_minimized:
91+ return false;
92+ default:
93+ return surface->visible();
94+ }
95+}
96+}
97+
98 void miral::MRUWindowList::push(Window const& window)
99 {
100 windows.erase(remove(begin(windows), end(windows), window), end(windows));
101@@ -33,12 +53,14 @@
102
103 auto miral::MRUWindowList::top() const -> Window
104 {
105- return (!windows.empty()) ? windows.back() : Window{};
106+ auto const& found = std::find_if(rbegin(windows), rend(windows), visible);
107+ return (found != rend(windows)) ? *found: Window{};
108 }
109
110 void miral::MRUWindowList::enumerate(Enumerator const& enumerator) const
111 {
112 for (auto i = windows.rbegin(); i != windows.rend(); ++i)
113- if (!enumerator(const_cast<Window&>(*i)))
114- break;
115+ if (visible(*i))
116+ if (!enumerator(const_cast<Window&>(*i)))
117+ break;
118 }
119
120=== modified file 'test/mru_window_list.cpp'
121--- test/mru_window_list.cpp 2016-08-05 08:53:45 +0000
122+++ test/mru_window_list.cpp 2017-02-20 18:05:53 +0000
123@@ -24,17 +24,23 @@
124 #include <gtest/gtest.h>
125 #include <gmock/gmock.h>
126
127-using StubSurface = mir::test::doubles::StubSurface;
128 using namespace testing;
129
130 namespace
131 {
132+struct StubSurface : mir::test::doubles::StubSurface
133+{
134+ bool visible() const override { return visible_; }
135+
136+ bool visible_ = true;
137+};
138+
139 struct StubSession : mir::test::doubles::StubSession
140 {
141 StubSession(int number_of_surfaces)
142 {
143 for (auto i = 0; i != number_of_surfaces; ++i)
144- surfaces.push_back(std::make_shared<mir::test::doubles::StubSurface>());
145+ surfaces.push_back(std::make_shared<StubSurface>());
146 }
147
148 std::shared_ptr<mir::scene::Surface> surface(mir::frontend::SurfaceId surface) const override
149@@ -53,13 +59,26 @@
150
151 struct MRUWindowList : testing::Test
152 {
153+ static auto const window_a_id = 0;
154+ static auto const window_b_id = 1;
155+
156 miral::MRUWindowList mru_list;
157
158 std::shared_ptr<StubSession> const stub_session{std::make_shared<StubSession>(3)};
159 miral::Application app{stub_session};
160- miral::Window window_a{app, stub_session->surface(mir::frontend::SurfaceId{0})};
161- miral::Window window_b{app, stub_session->surface(mir::frontend::SurfaceId{1})};
162+ miral::Window window_a{app, stub_session->surface(mir::frontend::SurfaceId{window_a_id})};
163+ miral::Window window_b{app, stub_session->surface(mir::frontend::SurfaceId{window_b_id})};
164 miral::Window window_c{app, stub_session->surface(mir::frontend::SurfaceId{2})};
165+
166+ void hide_window(int window_id)
167+ {
168+ stub_session->surfaces[window_id]->visible_ = false;
169+ }
170+
171+ void show_window(int window_id)
172+ {
173+ stub_session->surfaces[window_id]->visible_ = true;
174+ }
175 };
176
177 TEST_F(MRUWindowList, when_created_is_empty)
178@@ -137,3 +156,38 @@
179
180 EXPECT_THAT(count, Eq(1));
181 }
182+
183+TEST_F(MRUWindowList, a_hidden_window_is_not_enumerated)
184+{
185+ mru_list.push(window_a);
186+ mru_list.push(window_b);
187+ mru_list.push(window_c);
188+
189+ int count{0};
190+
191+ hide_window(window_a_id);
192+ mru_list.enumerate([&](miral::Window& window)
193+ { if (window == window_a) ++count; return true; });
194+
195+ EXPECT_THAT(count, Eq(0));
196+}
197+
198+TEST_F(MRUWindowList, hiding_then_showing_windows_retains_order)
199+{
200+ mru_list.push(window_a);
201+ mru_list.push(window_b);
202+ mru_list.push(window_c);
203+
204+ hide_window(window_a_id);
205+ hide_window(window_b_id);
206+ show_window(window_a_id);
207+ show_window(window_b_id);
208+
209+ std::vector<miral::Window> as_enumerated;
210+
211+ mru_list.enumerate([&](miral::Window& window)
212+ { as_enumerated.push_back(window); return true; });
213+
214+ EXPECT_THAT(as_enumerated, ElementsAre(window_c, window_b, window_a));
215+}
216+

Subscribers

People subscribed via source and target branches