Merge lp:~alan-griffiths/mir/fix-1522105 into lp:mir
- fix-1522105
- Merge into development-branch
Status: | Merged |
---|---|
Approved by: | Alberto Aguirre |
Approved revision: | no longer in the source branch. |
Merged at revision: | 3172 |
Proposed branch: | lp:~alan-griffiths/mir/fix-1522105 |
Merge into: | lp:mir |
Diff against target: |
348 lines (+96/-35) 3 files modified
src/server/scene/surface_stack.cpp (+27/-23) src/server/scene/surface_stack.h (+2/-1) tests/unit-tests/scene/test_surface_stack.cpp (+67/-11) |
To merge this branch: | bzr merge lp:~alan-griffiths/mir/fix-1522105 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Kevin DuBois (community) | Approve | ||
Alberto Aguirre (community) | Approve | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Review via email: mp+279418@code.launchpad.net |
Commit message
scene: fix the locking in SurfaceStack
Description of the change
scene: fix the locking in SurfaceStack
The primary motivation is add_observer() using a reference to an unlocked data structure (lp:1522105) but there were also issues with create_
Alan Griffiths (alan-griffiths) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:3168
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Alberto Aguirre (albaguirre) wrote : | # |
I vote for this one :)
Kevin DuBois (kdub) wrote : | # |
> looks good to me
At Alberto's request in standup today, will cherry-pick this fix into 0.18 once this MP lands to lp:mir
Preview Diff
1 | === modified file 'src/server/scene/surface_stack.cpp' | |||
2 | --- src/server/scene/surface_stack.cpp 2015-11-05 11:51:04 +0000 | |||
3 | +++ src/server/scene/surface_stack.cpp 2015-12-03 10:31:29 +0000 | |||
4 | @@ -127,7 +127,7 @@ | |||
5 | 127 | 127 | ||
6 | 128 | mc::SceneElementSequence ms::SurfaceStack::scene_elements_for(mc::CompositorID id) | 128 | mc::SceneElementSequence ms::SurfaceStack::scene_elements_for(mc::CompositorID id) |
7 | 129 | { | 129 | { |
9 | 130 | std::lock_guard<decltype(guard)> lg(guard); | 130 | RecursiveReadLock lg(guard); |
10 | 131 | 131 | ||
11 | 132 | scene_changed = false; | 132 | scene_changed = false; |
12 | 133 | mc::SceneElementSequence elements; | 133 | mc::SceneElementSequence elements; |
13 | @@ -155,7 +155,7 @@ | |||
14 | 155 | 155 | ||
15 | 156 | int ms::SurfaceStack::frames_pending(mc::CompositorID id) const | 156 | int ms::SurfaceStack::frames_pending(mc::CompositorID id) const |
16 | 157 | { | 157 | { |
18 | 158 | std::lock_guard<decltype(guard)> lg(guard); | 158 | RecursiveReadLock lg(guard); |
19 | 159 | 159 | ||
20 | 160 | int result = scene_changed ? 1 : 0; | 160 | int result = scene_changed ? 1 : 0; |
21 | 161 | for (auto const& surface : surfaces) | 161 | for (auto const& surface : surfaces) |
22 | @@ -182,7 +182,7 @@ | |||
23 | 182 | 182 | ||
24 | 183 | void ms::SurfaceStack::register_compositor(mc::CompositorID cid) | 183 | void ms::SurfaceStack::register_compositor(mc::CompositorID cid) |
25 | 184 | { | 184 | { |
27 | 185 | std::lock_guard<decltype(guard)> lg(guard); | 185 | RecursiveWriteLock lg(guard); |
28 | 186 | 186 | ||
29 | 187 | registered_compositors.insert(cid); | 187 | registered_compositors.insert(cid); |
30 | 188 | 188 | ||
31 | @@ -191,7 +191,7 @@ | |||
32 | 191 | 191 | ||
33 | 192 | void ms::SurfaceStack::unregister_compositor(mc::CompositorID cid) | 192 | void ms::SurfaceStack::unregister_compositor(mc::CompositorID cid) |
34 | 193 | { | 193 | { |
36 | 194 | std::lock_guard<decltype(guard)> lg(guard); | 194 | RecursiveWriteLock lg(guard); |
37 | 195 | 195 | ||
38 | 196 | registered_compositors.erase(cid); | 196 | registered_compositors.erase(cid); |
39 | 197 | 197 | ||
40 | @@ -202,7 +202,7 @@ | |||
41 | 202 | std::shared_ptr<mg::Renderable> const& overlay) | 202 | std::shared_ptr<mg::Renderable> const& overlay) |
42 | 203 | { | 203 | { |
43 | 204 | { | 204 | { |
45 | 205 | std::lock_guard<decltype(guard)> lg(guard); | 205 | RecursiveWriteLock lg(guard); |
46 | 206 | overlays.push_back(overlay); | 206 | overlays.push_back(overlay); |
47 | 207 | } | 207 | } |
48 | 208 | emit_scene_changed(); | 208 | emit_scene_changed(); |
49 | @@ -213,7 +213,7 @@ | |||
50 | 213 | { | 213 | { |
51 | 214 | auto overlay = weak_overlay.lock(); | 214 | auto overlay = weak_overlay.lock(); |
52 | 215 | { | 215 | { |
54 | 216 | std::lock_guard<decltype(guard)> lg(guard); | 216 | RecursiveWriteLock lg(guard); |
55 | 217 | auto const p = std::find(overlays.begin(), overlays.end(), overlay); | 217 | auto const p = std::find(overlays.begin(), overlays.end(), overlay); |
56 | 218 | if (p == overlays.end()) | 218 | if (p == overlays.end()) |
57 | 219 | { | 219 | { |
58 | @@ -228,7 +228,7 @@ | |||
59 | 228 | void ms::SurfaceStack::emit_scene_changed() | 228 | void ms::SurfaceStack::emit_scene_changed() |
60 | 229 | { | 229 | { |
61 | 230 | { | 230 | { |
63 | 231 | std::lock_guard<decltype(guard)> lg(guard); | 231 | RecursiveWriteLock lg(guard); |
64 | 232 | scene_changed = true; | 232 | scene_changed = true; |
65 | 233 | } | 233 | } |
66 | 234 | observers.scene_changed(); | 234 | observers.scene_changed(); |
67 | @@ -239,7 +239,7 @@ | |||
68 | 239 | mi::InputReceptionMode input_mode) | 239 | mi::InputReceptionMode input_mode) |
69 | 240 | { | 240 | { |
70 | 241 | { | 241 | { |
72 | 242 | std::lock_guard<decltype(guard)> lg(guard); | 242 | RecursiveWriteLock lg(guard); |
73 | 243 | surfaces.push_back(surface); | 243 | surfaces.push_back(surface); |
74 | 244 | create_rendering_tracker_for(surface); | 244 | create_rendering_tracker_for(surface); |
75 | 245 | } | 245 | } |
76 | @@ -255,7 +255,7 @@ | |||
77 | 255 | 255 | ||
78 | 256 | bool found_surface = false; | 256 | bool found_surface = false; |
79 | 257 | { | 257 | { |
81 | 258 | std::lock_guard<decltype(guard)> lg(guard); | 258 | RecursiveWriteLock lg(guard); |
82 | 259 | 259 | ||
83 | 260 | auto const surface = std::find(surfaces.begin(), surfaces.end(), keep_alive); | 260 | auto const surface = std::find(surfaces.begin(), surfaces.end(), keep_alive); |
84 | 261 | 261 | ||
85 | @@ -292,7 +292,7 @@ | |||
86 | 292 | auto ms::SurfaceStack::surface_at(geometry::Point cursor) const | 292 | auto ms::SurfaceStack::surface_at(geometry::Point cursor) const |
87 | 293 | -> std::shared_ptr<Surface> | 293 | -> std::shared_ptr<Surface> |
88 | 294 | { | 294 | { |
90 | 295 | std::lock_guard<decltype(guard)> lg(guard); | 295 | RecursiveReadLock lg(guard); |
91 | 296 | for (auto const& surface : in_reverse(surfaces)) | 296 | for (auto const& surface : in_reverse(surfaces)) |
92 | 297 | { | 297 | { |
93 | 298 | // TODO There's a lack of clarity about how the input area will | 298 | // TODO There's a lack of clarity about how the input area will |
94 | @@ -308,7 +308,7 @@ | |||
95 | 308 | 308 | ||
96 | 309 | void ms::SurfaceStack::for_each(std::function<void(std::shared_ptr<mi::Surface> const&)> const& callback) | 309 | void ms::SurfaceStack::for_each(std::function<void(std::shared_ptr<mi::Surface> const&)> const& callback) |
97 | 310 | { | 310 | { |
99 | 311 | std::lock_guard<decltype(guard)> lg(guard); | 311 | RecursiveReadLock lg(guard); |
100 | 312 | for (auto &surface : surfaces) | 312 | for (auto &surface : surfaces) |
101 | 313 | { | 313 | { |
102 | 314 | if (surface->query(mir_surface_attrib_visibility) == | 314 | if (surface->query(mir_surface_attrib_visibility) == |
103 | @@ -321,32 +321,34 @@ | |||
104 | 321 | 321 | ||
105 | 322 | void ms::SurfaceStack::raise(std::weak_ptr<Surface> const& s) | 322 | void ms::SurfaceStack::raise(std::weak_ptr<Surface> const& s) |
106 | 323 | { | 323 | { |
108 | 324 | auto surface = s.lock(); | 324 | bool surfaces_reordered{false}; |
109 | 325 | 325 | ||
110 | 326 | { | 326 | { |
112 | 327 | std::unique_lock<decltype(guard)> ul(guard); | 327 | auto const surface = s.lock(); |
113 | 328 | |||
114 | 329 | RecursiveWriteLock ul(guard); | ||
115 | 328 | auto const p = std::find(surfaces.begin(), surfaces.end(), surface); | 330 | auto const p = std::find(surfaces.begin(), surfaces.end(), surface); |
116 | 329 | 331 | ||
117 | 330 | if (p != surfaces.end()) | 332 | if (p != surfaces.end()) |
118 | 331 | { | 333 | { |
119 | 332 | surfaces.erase(p); | 334 | surfaces.erase(p); |
120 | 333 | surfaces.push_back(surface); | 335 | surfaces.push_back(surface); |
126 | 334 | 336 | surfaces_reordered = true; | |
122 | 335 | ul.unlock(); | ||
123 | 336 | observers.surfaces_reordered(); | ||
124 | 337 | |||
125 | 338 | return; | ||
127 | 339 | } | 337 | } |
128 | 340 | } | 338 | } |
129 | 341 | 339 | ||
131 | 342 | BOOST_THROW_EXCEPTION(std::runtime_error("Invalid surface")); | 340 | if (!surfaces_reordered) |
132 | 341 | BOOST_THROW_EXCEPTION(std::runtime_error("Invalid surface")); | ||
133 | 342 | |||
134 | 343 | observers.surfaces_reordered(); | ||
135 | 344 | return; | ||
136 | 343 | } | 345 | } |
137 | 344 | 346 | ||
138 | 345 | void ms::SurfaceStack::raise(SurfaceSet const& ss) | 347 | void ms::SurfaceStack::raise(SurfaceSet const& ss) |
139 | 346 | { | 348 | { |
140 | 347 | bool surfaces_reordered{false}; | 349 | bool surfaces_reordered{false}; |
141 | 348 | { | 350 | { |
143 | 349 | std::lock_guard<decltype(guard)> ul(guard); | 351 | RecursiveWriteLock ul(guard); |
144 | 350 | 352 | ||
145 | 351 | auto const old_surfaces = surfaces; | 353 | auto const old_surfaces = surfaces; |
146 | 352 | std::stable_partition( | 354 | std::stable_partition( |
147 | @@ -364,12 +366,16 @@ | |||
148 | 364 | void ms::SurfaceStack::create_rendering_tracker_for(std::shared_ptr<Surface> const& surface) | 366 | void ms::SurfaceStack::create_rendering_tracker_for(std::shared_ptr<Surface> const& surface) |
149 | 365 | { | 367 | { |
150 | 366 | auto const tracker = std::make_shared<RenderingTracker>(surface); | 368 | auto const tracker = std::make_shared<RenderingTracker>(surface); |
151 | 369 | |||
152 | 370 | RecursiveWriteLock ul(guard); | ||
153 | 367 | tracker->active_compositors(registered_compositors); | 371 | tracker->active_compositors(registered_compositors); |
154 | 368 | rendering_trackers[surface.get()] = tracker; | 372 | rendering_trackers[surface.get()] = tracker; |
155 | 369 | } | 373 | } |
156 | 370 | 374 | ||
157 | 371 | void ms::SurfaceStack::update_rendering_tracker_compositors() | 375 | void ms::SurfaceStack::update_rendering_tracker_compositors() |
158 | 372 | { | 376 | { |
159 | 377 | RecursiveReadLock ul(guard); | ||
160 | 378 | |||
161 | 373 | for (auto const& pair : rendering_trackers) | 379 | for (auto const& pair : rendering_trackers) |
162 | 374 | pair.second->active_compositors(registered_compositors); | 380 | pair.second->active_compositors(registered_compositors); |
163 | 375 | } | 381 | } |
164 | @@ -379,12 +385,10 @@ | |||
165 | 379 | observers.add(observer); | 385 | observers.add(observer); |
166 | 380 | 386 | ||
167 | 381 | // Notify observer of existing surfaces | 387 | // Notify observer of existing surfaces |
169 | 382 | std::unique_lock<decltype(guard)> lk(guard); | 388 | RecursiveReadLock lk(guard); |
170 | 383 | for (auto &surface : surfaces) | 389 | for (auto &surface : surfaces) |
171 | 384 | { | 390 | { |
172 | 385 | lk.unlock(); | ||
173 | 386 | observer->surface_exists(surface.get()); | 391 | observer->surface_exists(surface.get()); |
174 | 387 | lk.lock(); | ||
175 | 388 | } | 392 | } |
176 | 389 | } | 393 | } |
177 | 390 | 394 | ||
178 | 391 | 395 | ||
179 | === modified file 'src/server/scene/surface_stack.h' | |||
180 | --- src/server/scene/surface_stack.h 2015-11-25 16:32:07 +0000 | |||
181 | +++ src/server/scene/surface_stack.h 2015-12-03 10:31:29 +0000 | |||
182 | @@ -24,6 +24,7 @@ | |||
183 | 24 | #include "mir/compositor/scene.h" | 24 | #include "mir/compositor/scene.h" |
184 | 25 | #include "mir/scene/observer.h" | 25 | #include "mir/scene/observer.h" |
185 | 26 | #include "mir/input/scene.h" | 26 | #include "mir/input/scene.h" |
186 | 27 | #include "mir/recursive_read_write_mutex.h" | ||
187 | 27 | 28 | ||
188 | 28 | #include "mir/basic_observers.h" | 29 | #include "mir/basic_observers.h" |
189 | 29 | 30 | ||
190 | @@ -106,7 +107,7 @@ | |||
191 | 106 | void create_rendering_tracker_for(std::shared_ptr<Surface> const&); | 107 | void create_rendering_tracker_for(std::shared_ptr<Surface> const&); |
192 | 107 | void update_rendering_tracker_compositors(); | 108 | void update_rendering_tracker_compositors(); |
193 | 108 | 109 | ||
195 | 109 | std::mutex mutable guard; | 110 | RecursiveReadWriteMutex mutable guard; |
196 | 110 | 111 | ||
197 | 111 | std::shared_ptr<InputRegistrar> const input_registrar; | 112 | std::shared_ptr<InputRegistrar> const input_registrar; |
198 | 112 | std::shared_ptr<SceneReport> const report; | 113 | std::shared_ptr<SceneReport> const report; |
199 | 113 | 114 | ||
200 | === modified file 'tests/unit-tests/scene/test_surface_stack.cpp' | |||
201 | --- tests/unit-tests/scene/test_surface_stack.cpp 2015-11-05 11:51:04 +0000 | |||
202 | +++ tests/unit-tests/scene/test_surface_stack.cpp 2015-12-03 10:31:29 +0000 | |||
203 | @@ -349,7 +349,7 @@ | |||
204 | 349 | .WillByDefault(InvokeWithoutArgs([&]{ready++;})); | 349 | .WillByDefault(InvokeWithoutArgs([&]{ready++;})); |
205 | 350 | ON_CALL(*mock_queue, compositor_acquire(_)) | 350 | ON_CALL(*mock_queue, compositor_acquire(_)) |
206 | 351 | .WillByDefault(InvokeWithoutArgs([&]{ready--; return mt::fake_shared(stub_buffer); })); | 351 | .WillByDefault(InvokeWithoutArgs([&]{ready--; return mt::fake_shared(stub_buffer); })); |
208 | 352 | 352 | ||
209 | 353 | auto surface = std::make_shared<ms::BasicSurface>( | 353 | auto surface = std::make_shared<ms::BasicSurface>( |
210 | 354 | std::string("stub"), | 354 | std::string("stub"), |
211 | 355 | geom::Rectangle{{},{}}, | 355 | geom::Rectangle{{},{}}, |
212 | @@ -620,20 +620,76 @@ | |||
213 | 620 | { | 620 | { |
214 | 621 | using namespace ::testing; | 621 | using namespace ::testing; |
215 | 622 | 622 | ||
216 | 623 | using namespace ::testing; | ||
217 | 624 | |||
218 | 625 | MockSceneObserver observer; | 623 | MockSceneObserver observer; |
219 | 626 | 624 | ||
220 | 627 | InSequence seq; | 625 | InSequence seq; |
221 | 628 | EXPECT_CALL(observer, surface_exists(stub_surface1.get())).Times(1); | 626 | EXPECT_CALL(observer, surface_exists(stub_surface1.get())).Times(1); |
222 | 629 | EXPECT_CALL(observer, surface_exists(stub_surface2.get())).Times(1); | 627 | EXPECT_CALL(observer, surface_exists(stub_surface2.get())).Times(1); |
224 | 630 | 628 | ||
225 | 631 | stack.add_surface(stub_surface1, default_params.input_mode); | 629 | stack.add_surface(stub_surface1, default_params.input_mode); |
226 | 632 | stack.add_surface(stub_surface2, default_params.input_mode); | 630 | stack.add_surface(stub_surface2, default_params.input_mode); |
227 | 633 | 631 | ||
228 | 634 | stack.add_observer(mt::fake_shared(observer)); | 632 | stack.add_observer(mt::fake_shared(observer)); |
229 | 635 | } | 633 | } |
230 | 636 | 634 | ||
231 | 635 | TEST_F(SurfaceStack, scene_observer_can_query_scene_within_surface_exists_notification) | ||
232 | 636 | { | ||
233 | 637 | using namespace ::testing; | ||
234 | 638 | |||
235 | 639 | MockSceneObserver observer; | ||
236 | 640 | |||
237 | 641 | auto const scene_query = [&]{ | ||
238 | 642 | stack.for_each([&](std::shared_ptr<mi::Surface> const& surface){ | ||
239 | 643 | EXPECT_THAT(surface.get(), Eq(stub_surface1.get())); | ||
240 | 644 | }); | ||
241 | 645 | }; | ||
242 | 646 | EXPECT_CALL(observer, surface_exists(stub_surface1.get())).Times(1) | ||
243 | 647 | .WillOnce(InvokeWithoutArgs(scene_query)); | ||
244 | 648 | |||
245 | 649 | stack.add_surface(stub_surface1, default_params.input_mode); | ||
246 | 650 | stack.add_observer(mt::fake_shared(observer)); | ||
247 | 651 | } | ||
248 | 652 | |||
249 | 653 | TEST_F(SurfaceStack, scene_observer_can_async_query_scene_within_surface_exists_notification) | ||
250 | 654 | { | ||
251 | 655 | using namespace ::testing; | ||
252 | 656 | |||
253 | 657 | MockSceneObserver observer; | ||
254 | 658 | |||
255 | 659 | auto const scene_query = [&]{ | ||
256 | 660 | stack.for_each([&](std::shared_ptr<mi::Surface> const& surface){ | ||
257 | 661 | EXPECT_THAT(surface.get(), Eq(stub_surface1.get())); | ||
258 | 662 | }); | ||
259 | 663 | }; | ||
260 | 664 | |||
261 | 665 | auto const async_scene_query = [&]{ | ||
262 | 666 | std::async(std::launch::async, scene_query); | ||
263 | 667 | }; | ||
264 | 668 | |||
265 | 669 | EXPECT_CALL(observer, surface_exists(stub_surface1.get())).Times(1) | ||
266 | 670 | .WillOnce(InvokeWithoutArgs(async_scene_query)); | ||
267 | 671 | |||
268 | 672 | stack.add_surface(stub_surface1, default_params.input_mode); | ||
269 | 673 | stack.add_observer(mt::fake_shared(observer)); | ||
270 | 674 | } | ||
271 | 675 | |||
272 | 676 | |||
273 | 677 | TEST_F(SurfaceStack, scene_observer_can_remove_surface_from_scene_within_surface_exists_notification) | ||
274 | 678 | { | ||
275 | 679 | using namespace ::testing; | ||
276 | 680 | |||
277 | 681 | MockSceneObserver observer; | ||
278 | 682 | |||
279 | 683 | auto const surface_removal = [&]{ | ||
280 | 684 | stack.remove_surface(stub_surface1); | ||
281 | 685 | }; | ||
282 | 686 | EXPECT_CALL(observer, surface_exists(stub_surface1.get())).Times(1) | ||
283 | 687 | .WillOnce(InvokeWithoutArgs(surface_removal)); | ||
284 | 688 | |||
285 | 689 | stack.add_surface(stub_surface1, default_params.input_mode); | ||
286 | 690 | stack.add_observer(mt::fake_shared(observer)); | ||
287 | 691 | } | ||
288 | 692 | |||
289 | 637 | TEST_F(SurfaceStack, surfaces_reordered) | 693 | TEST_F(SurfaceStack, surfaces_reordered) |
290 | 638 | { | 694 | { |
291 | 639 | using namespace ::testing; | 695 | using namespace ::testing; |
292 | @@ -923,7 +979,7 @@ | |||
293 | 923 | TEST_F(SurfaceStack, overlays_do_not_appear_in_input_enumeration) | 979 | TEST_F(SurfaceStack, overlays_do_not_appear_in_input_enumeration) |
294 | 924 | { | 980 | { |
295 | 925 | mtd::StubRenderable r; | 981 | mtd::StubRenderable r; |
297 | 926 | 982 | ||
298 | 927 | stack.add_surface(stub_surface1, default_params.input_mode); | 983 | stack.add_surface(stub_surface1, default_params.input_mode); |
299 | 928 | stack.add_surface(stub_surface2, default_params.input_mode); | 984 | stack.add_surface(stub_surface2, default_params.input_mode); |
300 | 929 | 985 | ||
301 | @@ -946,7 +1002,7 @@ | |||
302 | 946 | using namespace ::testing; | 1002 | using namespace ::testing; |
303 | 947 | 1003 | ||
304 | 948 | mtd::StubRenderable r; | 1004 | mtd::StubRenderable r; |
306 | 949 | 1005 | ||
307 | 950 | stack.add_surface(stub_surface1, default_params.input_mode); | 1006 | stack.add_surface(stub_surface1, default_params.input_mode); |
308 | 951 | stack.add_input_visualization(mt::fake_shared(r)); | 1007 | stack.add_input_visualization(mt::fake_shared(r)); |
309 | 952 | stack.add_surface(stub_surface2, default_params.input_mode); | 1008 | stack.add_surface(stub_surface2, default_params.input_mode); |
310 | @@ -956,7 +1012,7 @@ | |||
311 | 956 | ElementsAre( | 1012 | ElementsAre( |
312 | 957 | SceneElementForSurface(stub_surface1), | 1013 | SceneElementForSurface(stub_surface1), |
313 | 958 | SceneElementForSurface(stub_surface2), | 1014 | SceneElementForSurface(stub_surface2), |
315 | 959 | SceneElementForStream(mt::fake_shared(r)))); | 1015 | SceneElementForStream(mt::fake_shared(r)))); |
316 | 960 | } | 1016 | } |
317 | 961 | 1017 | ||
318 | 962 | TEST_F(SurfaceStack, removed_overlays_are_removed) | 1018 | TEST_F(SurfaceStack, removed_overlays_are_removed) |
319 | @@ -964,7 +1020,7 @@ | |||
320 | 964 | using namespace ::testing; | 1020 | using namespace ::testing; |
321 | 965 | 1021 | ||
322 | 966 | mtd::StubRenderable r; | 1022 | mtd::StubRenderable r; |
324 | 967 | 1023 | ||
325 | 968 | stack.add_surface(stub_surface1, default_params.input_mode); | 1024 | stack.add_surface(stub_surface1, default_params.input_mode); |
326 | 969 | stack.add_input_visualization(mt::fake_shared(r)); | 1025 | stack.add_input_visualization(mt::fake_shared(r)); |
327 | 970 | stack.add_surface(stub_surface2, default_params.input_mode); | 1026 | stack.add_surface(stub_surface2, default_params.input_mode); |
328 | @@ -975,7 +1031,7 @@ | |||
329 | 975 | SceneElementForSurface(stub_surface1), | 1031 | SceneElementForSurface(stub_surface1), |
330 | 976 | SceneElementForSurface(stub_surface2), | 1032 | SceneElementForSurface(stub_surface2), |
331 | 977 | SceneElementForStream(mt::fake_shared(r)))); | 1033 | SceneElementForStream(mt::fake_shared(r)))); |
333 | 978 | 1034 | ||
334 | 979 | stack.remove_input_visualization(mt::fake_shared(r)); | 1035 | stack.remove_input_visualization(mt::fake_shared(r)); |
335 | 980 | 1036 | ||
336 | 981 | EXPECT_THAT( | 1037 | EXPECT_THAT( |
337 | @@ -991,10 +1047,10 @@ | |||
338 | 991 | 1047 | ||
339 | 992 | EXPECT_CALL(o1, scene_changed()).Times(1); | 1048 | EXPECT_CALL(o1, scene_changed()).Times(1); |
340 | 993 | EXPECT_CALL(o2, scene_changed()).Times(1); | 1049 | EXPECT_CALL(o2, scene_changed()).Times(1); |
342 | 994 | 1050 | ||
343 | 995 | stack.add_observer(mt::fake_shared(o1)); | 1051 | stack.add_observer(mt::fake_shared(o1)); |
344 | 996 | stack.add_observer(mt::fake_shared(o2)); | 1052 | stack.add_observer(mt::fake_shared(o2)); |
346 | 997 | 1053 | ||
347 | 998 | stack.emit_scene_changed(); | 1054 | stack.emit_scene_changed(); |
348 | 999 | } | 1055 | } |
349 | 1000 | 1056 |
An alternative solution to ~albaguirre/ mir/fix- 1522105/ +merge/ 279393