Mir

Merge lp:~mir-team/mir/multiple-change-callbacks into lp:mir

Proposed by Robert Carr
Status: Work in progress
Proposed branch: lp:~mir-team/mir/multiple-change-callbacks
Merge into: lp:mir
Diff against target: 411 lines (+172/-20)
11 files modified
include/server/mir/compositor/scene.h (+8/-2)
include/server/mir/scene/observer_id.h (+34/-0)
include/test/mir_test_doubles/mock_scene.h (+4/-1)
src/server/compositor/multi_threaded_compositor.cpp (+2/-2)
src/server/compositor/multi_threaded_compositor.h (+3/-0)
src/server/scene/surface_stack.cpp (+20/-4)
src/server/scene/surface_stack.h (+7/-3)
tests/integration-tests/test_surface_first_frame_sync.cpp (+4/-2)
tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp (+10/-2)
tests/unit-tests/compositor/test_multi_threaded_compositor.cpp (+17/-4)
tests/unit-tests/scene/test_surface_stack.cpp (+63/-0)
To merge this branch: bzr merge lp:~mir-team/mir/multiple-change-callbacks
Reviewer Review Type Date Requested Status
Alan Griffiths Abstain
Daniel van Vugt Abstain
Alberto Aguirre (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+214131@code.launchpad.net

Commit message

Rework Scene::set_change_callback to add/remove change callback in order to support multiple subscribers.

Description of the change

As part of the cursor spike support registering multiple change callbacks to the surface stack/scene. In the cursor spike these methods are added to mi::InputTargets so that the cursor controller can update the image when surfaces dissapear, etc...

Also told AlbertA needs this for some screencast stuff?

To post a comment you must log in.
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

"Also told AlbertA needs this for some screencast stuff?"

Right, I want to optionally be able to get the screencast compositor to listen to scene changes so it can capture at scene change rate.

Lines 8-15, 114, 117, 119, 131, seems like a wrong merge resolution.

Also what about testing for multiple observer notifications? Maybe this:

TEST_F(SurfaceStack, notifies_multiple_observers)
{
    using namespace ::testing;
    MockCallback mock_cb1;
    MockCallback mock_cb2;

    EXPECT_CALL(mock_cb1, call()).Times(1);
    EXPECT_CALL(mock_cb2, call()).Times(1);

    ms::SurfaceStack stack(mt::fake_shared(input_registrar), report);

    auto id1 = stack.add_change_callback(std::bind(&MockCallback::call, &mock_cb1));
    auto id2 = stack.add_change_callback(std::bind(&MockCallback::call, &mock_cb2));
    stack.add_surface(stub_surface1, default_params.depth, default_params.input_mode);
    stack.remove_change_callback(id1);
    stack.remove_change_callback(id2);

    EXPECT_CALL(mock_cb1, call()).Times(0);
    EXPECT_CALL(mock_cb2, call()).Times(0);
    stack.remove_surface(stub_surface1);
}

review: Needs Fixing
1530. By Alan Griffiths

frontend, shell: frontend doesn't need send_display_config() in the Session interface.

Approved by Alberto Aguirre, Kevin DuBois, PS Jenkins bot.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
1531. By Alan Griffiths

scene: Remove spurious BasicSurface::frame_posted() function and rework tests that used it.

Approved by PS Jenkins bot, Daniel van Vugt, Alexandros Frantzis, Kevin DuBois.

1532. By Kevin DuBois

compositor: transition bypass detection to operating on RenderableList instead of using operator/filter on mc::Scene.

Approved by Alberto Aguirre, Alan Griffiths, PS Jenkins bot.

1533. By Daniel van Vugt

Add a simple typedef Renderable::ID to make distinguishing renderables
slightly more explicit.
.

Approved by PS Jenkins bot, Alberto Aguirre, Kevin DuBois.

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

8 +set (OLD_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
9 +# Don't treat warnings as errors in 3rd_party/{gmock}
10 +string (REPLACE " -Werror " " " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
11 +
12 +
13 +# Restore -Werror for non-3rd-party code
14 +set (CMAKE_CXX_FLAGS ${OLD_CMAKE_CXX_FLAGS})
15 +

Spurious

~~~~

114 - miroptions
115 mirplatform
116 mirsharedandroid
117 - mirsharedenv
118
119 - ${Boost_PROGRAM_OPTIONS_LIBRARY}
120 ${LIBHARDWARE_LIBRARIES}
121 ${EGL_LDFLAGS} ${EGL_LIBRARIES}
122 ${GLESv2_LDFLAGS} ${GLESv2_LIBRARIES}
123
124 === modified file 'src/platform/graphics/mesa/CMakeLists.txt'
125 --- src/platform/graphics/mesa/CMakeLists.txt 2014-04-03 02:01:49 +0000
126 +++ src/platform/graphics/mesa/CMakeLists.txt 2014-04-03 22:20:09 +0000
127 @@ -47,7 +47,6 @@
128 mirplatformgraphicsmesa
129 mirplatform
130
131 - ${Boost_PROGRAM_OPTIONS_LIBRARY}

Puzzling

~~~~

87 +typedef IntWrapper<detail::ObserverIdTag> ObserverId;

I'm not convinced we need an Observer ID but other ids capitalize the "D"

review: Needs Fixing
1534. By Alberto Aguirre

Fill the mode refresh rate field for android platform display configurations.

Approved by Alan Griffiths, Alexandros Frantzis, PS Jenkins bot, Kevin DuBois.

1535. By Alan Griffiths

shell: Eliminate shell::SurfaceFactory and shell::Surface and use scene::SurfaceCoordinator and scene::Surface instead.

Approved by Andreas Pokorny, Gerry Boland, Alexandros Frantzis, PS Jenkins bot.

1536. By Kevin DuBois

Remove the RenderingOperator and VisibilityFilter classes in favor of rendering on the generated list of renderables from the scene.

Approved by Alan Griffiths, Alexandros Frantzis, PS Jenkins bot, Alberto Aguirre.

1537. By Alberto Aguirre

make current before deleting gl resources in GLPixelBuffer (LP: #1256360). Fixes: https://bugs.launchpad.net/bugs/1256360.

Approved by Alexandros Frantzis, PS Jenkins bot, Kevin DuBois.

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

(1) As Alan said, the CMakeLists.txt changes are spurious reverts of changes we want to keep.

(2) Needs Information: We potentially don't need to use ObserverId. The std::function is already unique and has operator== so could be used as the identifier itself...
   48 + virtual scene::ObserverId add_change_callback(std::function<void()> const& f) = 0;
   49 + virtual void remove_change_callback(scene::ObserverId id) = 0;
Then notify_change_by_id could become a std::set with a custom Compare template parameter. Or more simply a std::list with std::find.

(3) observer_id.h: Wrong copyright but then (2) suggests the whole file isn't required.
   59 + * Copyright © 2013 Canonical Ltd.

(4) "notify_change_by_id" is a confusing name for a map. At least the "notify_change" part. Maybe "callbacks_by_id" or "observers_by_id".

review: Needs Fixing
1538. By Robert Carr

Rework Scene::set_change_callback to add/remove change callback to support multiple subscribers

1539. By Robert Carr

ObserverId/ObserverID

1540. By Robert Carr

observer_id.h: Fix copyright

1541. By Robert Carr

notify_change_by_id->observers_by_id

1542. By Robert Carr

test_surface_stack.cpp: Add test, notifies_multiple_observers

Revision history for this message
Robert Carr (robertcarr) wrote :

Sorry about CMakeList changes...pushed wrong branch. Fixed copyright on observer_id.h. Renamed notify_change_by_id -> observers by id. ObserverId->ObserverID. Added multiple observer test.

I think utilizing std::function as the identifier is a bad idea because its convenient to just be able to pass an anonymous lambda.

Revision history for this message
Alberto Aguirre (albaguirre) wrote :

> (2) Needs Information: We potentially don't need to use ObserverId. The
> std::function is already unique and has operator== so could be used as the
> identifier itself...
> 48 + virtual scene::ObserverId
> add_change_callback(std::function<void()> const& f) = 0;
> 49 + virtual void remove_change_callback(scene::ObserverId id) = 0;
> Then notify_change_by_id could become a std::set with a custom Compare
> template parameter. Or more simply a std::list with std::find.
>

This imposes the caller to save the std::function it passed even if they are lambdas, which is probably more awkward than obtaining an id.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

Unresolved conflicts:

Text conflict in include/test/mir_test_doubles/mock_scene.h
Text conflict in src/server/scene/surface_stack.cpp
Text conflict in src/server/scene/surface_stack.h
Text conflict in tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp
Text conflict in tests/unit-tests/compositor/test_multi_threaded_compositor.cpp
Text conflict in tests/unit-tests/scene/test_surface_stack.cpp

review: Needs Fixing
Revision history for this message
Robert Carr (robertcarr) wrote :

Whoops...I got distracted in the middle of merging devel in to this during the sprint and thought I had finished it.

1543. By Robert Carr

Merge trunk

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

LGTM,

Just fyi, this will conflict with the refactoring in:
https://code.launchpad.net/~albaguirre/mir/fix-1296544/+merge/214456

review: Approve
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

I see activity but no time to re-review right now.

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

I'm still not convinced by ObserverID - other elements of the scene are managing observers by smart pointers to the observer object (Surface is close to its final state, Session still needs some work).

In all cases the legacy approach of "something changed but I won't tell you what" notification is getting reworked. So these changes will be swept away by that anyway.

review: Abstain

Unmerged revisions

1543. By Robert Carr

Merge trunk

1542. By Robert Carr

test_surface_stack.cpp: Add test, notifies_multiple_observers

1541. By Robert Carr

notify_change_by_id->observers_by_id

1540. By Robert Carr

observer_id.h: Fix copyright

1539. By Robert Carr

ObserverId/ObserverID

1538. By Robert Carr

Rework Scene::set_change_callback to add/remove change callback to support multiple subscribers

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/server/mir/compositor/scene.h'
2--- include/server/mir/compositor/scene.h 2014-04-04 17:48:23 +0000
3+++ include/server/mir/compositor/scene.h 2014-04-14 21:47:44 +0000
4@@ -21,6 +21,7 @@
5
6 #include "mir/geometry/forward.h"
7 #include "mir/graphics/renderable.h"
8+#include "mir/scene/observer_id.h"
9
10 #include <memory>
11 #include <functional>
12@@ -42,14 +43,19 @@
13 virtual graphics::RenderableList generate_renderable_list() const = 0;
14
15 /**
16- * Sets a callback to be called whenever the state of the
17+ * Registers a callback to be called whenever the state of the
18 * Scene changes.
19 *
20+ * The returned ObserverID may be passed to remove_change_callback
21+ * to unregister for change notification.
22+ *
23 * The supplied callback should not directly or indirectly (e.g.,
24 * by changing a property of a surface) change the state of
25 * the Scene, otherwise a deadlock may occur.
26+ *
27 */
28- virtual void set_change_callback(std::function<void()> const& f) = 0;
29+ virtual scene::ObserverID add_change_callback(std::function<void()> const& f) = 0;
30+ virtual void remove_change_callback(scene::ObserverID id) = 0;
31
32 protected:
33 Scene() = default;
34
35=== added file 'include/server/mir/scene/observer_id.h'
36--- include/server/mir/scene/observer_id.h 1970-01-01 00:00:00 +0000
37+++ include/server/mir/scene/observer_id.h 2014-04-14 21:47:44 +0000
38@@ -0,0 +1,34 @@
39+/*
40+ * Copyright © 2014 Canonical Ltd.
41+ *
42+ * This program is free software: you can redistribute it and/or modify it
43+ * under the terms of the GNU General Public License version 3,
44+ * as published by the Free Software Foundation.
45+ *
46+ * This program is distributed in the hope that it will be useful,
47+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
48+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
49+ * GNU General Public License for more details.
50+ *
51+ * You should have received a copy of the GNU General Public License
52+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
53+ *
54+ * Authored By: Robert Carr <racarr@canonical.com>
55+ */
56+
57+#ifndef MIR_SCENE_OBSERVER_NOTIFICATION_ID_H_
58+#define MIR_SCENE_OBSERVER_NOTIFICATION_ID_H_
59+
60+#include "mir/int_wrapper.h"
61+
62+namespace mir
63+{
64+namespace scene
65+{
66+namespace detail { struct ObserverIDTag; }
67+
68+typedef IntWrapper<detail::ObserverIDTag> ObserverID;
69+}
70+} // namespace mir
71+
72+#endif // MIR_SCENE_OBSERVER_NOTIFICATION_ID_H_
73
74=== modified file 'include/test/mir_test_doubles/mock_scene.h'
75--- include/test/mir_test_doubles/mock_scene.h 2014-04-03 00:14:45 +0000
76+++ include/test/mir_test_doubles/mock_scene.h 2014-04-14 21:47:44 +0000
77@@ -38,7 +38,10 @@
78 .WillByDefault(testing::Return(graphics::RenderableList{}));
79 }
80 MOCK_CONST_METHOD0(generate_renderable_list, graphics::RenderableList());
81- MOCK_METHOD1(set_change_callback, void(std::function<void()> const&));
82+
83+ MOCK_METHOD1(add_change_callback, scene::ObserverID(std::function<void()> const&));
84+ MOCK_METHOD1(remove_change_callback, void(scene::ObserverID));
85+
86 MOCK_METHOD0(lock, void());
87 MOCK_METHOD0(unlock, void());
88 };
89
90=== modified file 'src/server/compositor/multi_threaded_compositor.cpp'
91--- src/server/compositor/multi_threaded_compositor.cpp 2014-04-09 17:39:31 +0000
92+++ src/server/compositor/multi_threaded_compositor.cpp 2014-04-14 21:47:44 +0000
93@@ -271,7 +271,7 @@
94 }
95
96 /* Recomposite whenever the scene changes */
97- scene->set_change_callback([this]()
98+ change_registration = scene->add_change_callback([this]()
99 {
100 schedule_compositing();
101 });
102@@ -295,7 +295,7 @@
103 }
104
105 lk.unlock();
106- scene->set_change_callback([]{});
107+ scene->remove_change_callback(change_registration);
108 lk.lock();
109
110 for (auto& f : thread_functors)
111
112=== modified file 'src/server/compositor/multi_threaded_compositor.h'
113--- src/server/compositor/multi_threaded_compositor.h 2014-03-07 03:15:55 +0000
114+++ src/server/compositor/multi_threaded_compositor.h 2014-04-14 21:47:44 +0000
115@@ -20,6 +20,7 @@
116 #define MIR_COMPOSITOR_MULTI_THREADED_COMPOSITOR_H_
117
118 #include "mir/compositor/compositor.h"
119+#include "mir/scene/observer_id.h"
120
121 #include <mutex>
122 #include <memory>
123@@ -67,6 +68,8 @@
124 bool compose_on_start;
125
126 void schedule_compositing();
127+
128+ scene::ObserverID change_registration;
129 };
130
131 }
132
133=== modified file 'src/server/scene/surface_stack.cpp'
134--- src/server/scene/surface_stack.cpp 2014-04-14 11:31:04 +0000
135+++ src/server/scene/surface_stack.cpp 2014-04-14 21:47:44 +0000
136@@ -54,7 +54,7 @@
137 input_registrar{input_registrar},
138 report{report},
139 change_cb{[this]() { emit_change_notification(); }},
140- notify_change{[]{}}
141+ next_change_callback_id(0)
142 {
143 }
144
145@@ -125,11 +125,26 @@
146 return list;
147 }
148
149-void ms::SurfaceStack::set_change_callback(std::function<void()> const& f)
150+ms::ObserverID ms::SurfaceStack::add_change_callback(std::function<void()> const& f)
151 {
152 std::lock_guard<decltype(notify_change_mutex)> lg(notify_change_mutex);
153 assert(f);
154- notify_change = f;
155+
156+ auto id = ms::ObserverID{++next_change_callback_id};
157+ observers_by_id[id] = f;
158+
159+ return id;
160+}
161+
162+void ms::SurfaceStack::remove_change_callback(ms::ObserverID id)
163+{
164+ std::lock_guard<std::mutex> lg{notify_change_mutex};
165+
166+ auto it = observers_by_id.find(id);
167+ if (it == observers_by_id.end())
168+ BOOST_THROW_EXCEPTION(std::logic_error(
169+ "Invalid change notification id (not previously registered, or already unregistered)"));
170+ observers_by_id.erase(it);
171 }
172
173 void ms::SurfaceStack::add_surface(
174@@ -183,7 +198,8 @@
175 void ms::SurfaceStack::emit_change_notification()
176 {
177 std::lock_guard<decltype(notify_change_mutex)> lg(notify_change_mutex);
178- notify_change();
179+ for (auto kv : observers_by_id)
180+ kv.second();
181 }
182
183 void ms::SurfaceStack::for_each(std::function<void(std::shared_ptr<mi::InputChannel> const&)> const& callback)
184
185=== modified file 'src/server/scene/surface_stack.h'
186--- src/server/scene/surface_stack.h 2014-04-04 22:32:51 +0000
187+++ src/server/scene/surface_stack.h 2014-04-14 21:47:44 +0000
188@@ -23,6 +23,7 @@
189
190 #include "mir/compositor/scene.h"
191 #include "mir/scene/depth_id.h"
192+#include "mir/scene/observer_id.h"
193 #include "mir/input/input_targets.h"
194
195 #include <memory>
196@@ -67,8 +68,10 @@
197
198 // From Scene
199 graphics::RenderableList generate_renderable_list() const;
200- virtual void set_change_callback(std::function<void()> const& f);
201-
202+
203+ virtual scene::ObserverID add_change_callback(std::function<void()> const& f);
204+ virtual void remove_change_callback(scene::ObserverID id);
205+
206 // From InputTargets
207 void for_each(std::function<void(std::shared_ptr<input::InputChannel> const&)> const& callback);
208
209@@ -96,7 +99,8 @@
210 std::map<DepthId, Layer> layers_by_depth;
211
212 std::mutex notify_change_mutex;
213- std::function<void()> notify_change;
214+ int next_change_callback_id;
215+ std::map<ObserverID, std::function<void()>> observers_by_id;
216 };
217
218 }
219
220=== modified file 'tests/integration-tests/test_surface_first_frame_sync.cpp'
221--- tests/integration-tests/test_surface_first_frame_sync.cpp 2014-04-04 21:48:32 +0000
222+++ tests/integration-tests/test_surface_first_frame_sync.cpp 2014-04-14 21:47:44 +0000
223@@ -69,7 +69,7 @@
224
225 void start()
226 {
227- scene->set_change_callback([this]()
228+ change_id = scene->add_change_callback([this]()
229 {
230 display->for_each_display_buffer([this](mg::DisplayBuffer& display_buffer)
231 {
232@@ -80,13 +80,15 @@
233
234 void stop()
235 {
236- scene->set_change_callback([]{});
237+ scene->remove_change_callback(change_id);
238 }
239
240 private:
241 std::shared_ptr<mg::Display> const display;
242 std::shared_ptr<mc::Scene> const scene;
243 std::unordered_map<mg::DisplayBuffer*,std::unique_ptr<mc::DisplayBufferCompositor>> display_buffer_compositor_map;
244+
245+ ms::ObserverID change_id;
246 };
247
248 class StubRenderer : public mtd::StubRenderer
249
250=== modified file 'tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp'
251--- tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp 2014-04-07 16:46:16 +0000
252+++ tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp 2014-04-14 21:47:44 +0000
253@@ -38,10 +38,11 @@
254
255 namespace mg = mir::graphics;
256 namespace mc = mir::compositor;
257+namespace ms = mir::scene;
258+namespace mr = mir::report;
259 namespace geom = mir::geometry;
260 namespace mt = mir::test;
261 namespace mtd = mir::test::doubles;
262-namespace mr = mir::report;
263
264 namespace
265 {
266@@ -58,7 +59,14 @@
267 return renderlist;
268 }
269
270- void set_change_callback(std::function<void()> const&) {}
271+ ms::ObserverID add_change_callback(std::function<void()> const&) override
272+ {
273+ return ms::ObserverID{};
274+ }
275+
276+ void remove_change_callback(ms::ObserverID) override
277+ {
278+ }
279
280 void change(mg::RenderableList const& new_renderlist)
281 {
282
283=== modified file 'tests/unit-tests/compositor/test_multi_threaded_compositor.cpp'
284--- tests/unit-tests/compositor/test_multi_threaded_compositor.cpp 2014-04-09 11:40:25 +0000
285+++ tests/unit-tests/compositor/test_multi_threaded_compositor.cpp 2014-04-14 21:47:44 +0000
286@@ -42,9 +42,10 @@
287
288 namespace mc = mir::compositor;
289 namespace mg = mir::graphics;
290+namespace ms = mir::scene;
291+namespace mr = mir::report;
292 namespace geom = mir::geometry;
293 namespace mtd = mir::test::doubles;
294-namespace mr = mir::report;
295
296 namespace
297 {
298@@ -99,11 +100,20 @@
299 return renderable_list;
300 }
301
302- void set_change_callback(std::function<void()> const& f)
303+
304+ ms::ObserverID add_change_callback(std::function<void()> const& f) override
305 {
306 std::lock_guard<std::mutex> lock{callback_mutex};
307 assert(f);
308 callback = f;
309+
310+ // Test only needs a single change callback.
311+ return ms::ObserverID{0};
312+ }
313+ void remove_change_callback(ms::ObserverID id) override
314+ {
315+ assert(id == ms::ObserverID{0});
316+ callback = [](){};
317 }
318
319 void emit_change_event()
320@@ -563,12 +573,15 @@
321 auto mock_scene = std::make_shared<mtd::MockScene>();
322 auto db_compositor_factory = std::make_shared<mtd::NullDisplayBufferCompositorFactory>();
323 auto mock_report = std::make_shared<testing::NiceMock<mtd::MockCompositorReport>>();
324+
325 EXPECT_CALL(*mock_report, started())
326 .Times(1);
327 EXPECT_CALL(*mock_report, stopped())
328 .Times(1);
329- EXPECT_CALL(*mock_scene, set_change_callback(_))
330- .Times(2);
331+ EXPECT_CALL(*mock_scene, add_change_callback(_))
332+ .Times(1).WillOnce(Return(ms::ObserverID{}));
333+ EXPECT_CALL(*mock_scene, remove_change_callback(_))
334+ .Times(1);
335 EXPECT_CALL(*mock_scene, generate_renderable_list())
336 .Times(AtLeast(0))
337 .WillRepeatedly(Return(mg::RenderableList{}));
338
339=== modified file 'tests/unit-tests/scene/test_surface_stack.cpp'
340--- tests/unit-tests/scene/test_surface_stack.cpp 2014-04-14 11:31:04 +0000
341+++ tests/unit-tests/scene/test_surface_stack.cpp 2014-04-14 21:47:44 +0000
342@@ -168,6 +168,69 @@
343 EXPECT_THAT((*it)->id(), Eq(stub_surface3->id()));
344 }
345
346+TEST_F(SurfaceStack, notify_on_create_and_destroy_surface)
347+{
348+ using namespace ::testing;
349+ NiceMock<MockCallback> mock_cb;
350+ EXPECT_CALL(mock_cb, call())
351+ .Times(2);
352+
353+ ms::SurfaceStack stack(mt::fake_shared(input_registrar), report);
354+
355+ stack.add_change_callback(std::bind(&MockCallback::call, &mock_cb));
356+ stack.add_surface(stub_surface1, default_params.depth, default_params.input_mode);
357+ stack.remove_surface(stub_surface1);
358+}
359+
360+TEST_F(SurfaceStack, remove_change_callback)
361+{
362+ using namespace ::testing;
363+ MockCallback mock_cb;
364+ EXPECT_CALL(mock_cb, call())
365+ .Times(1);
366+
367+ ms::SurfaceStack stack(mt::fake_shared(input_registrar), report);
368+
369+ auto id = stack.add_change_callback(std::bind(&MockCallback::call, &mock_cb));
370+ stack.add_surface(stub_surface1, default_params.depth, default_params.input_mode);
371+ stack.remove_change_callback(id);
372+
373+ EXPECT_CALL(mock_cb, call()).Times(0);
374+ stack.remove_surface(stub_surface1);
375+}
376+
377+TEST_F(SurfaceStack, notifies_multiple_observers)
378+{
379+ using namespace ::testing;
380+ MockCallback mock_cb1;
381+ MockCallback mock_cb2;
382+
383+ EXPECT_CALL(mock_cb1, call()).Times(1);
384+ EXPECT_CALL(mock_cb2, call()).Times(1);
385+
386+ ms::SurfaceStack stack(mt::fake_shared(input_registrar), report);
387+
388+ auto id1 = stack.add_change_callback(std::bind(&MockCallback::call, &mock_cb1));
389+ auto id2 = stack.add_change_callback(std::bind(&MockCallback::call, &mock_cb2));
390+ stack.add_surface(stub_surface1, default_params.depth, default_params.input_mode);
391+ stack.remove_change_callback(id1);
392+ stack.remove_change_callback(id2);
393+
394+ EXPECT_CALL(mock_cb1, call()).Times(0);
395+ EXPECT_CALL(mock_cb2, call()).Times(0);
396+ stack.remove_surface(stub_surface1);
397+}
398+
399+TEST_F(SurfaceStack, remove_invalid_change_callback)
400+{
401+ using namespace ::testing;
402+
403+ ms::SurfaceStack stack(mt::fake_shared(input_registrar), report);
404+ EXPECT_THROW({
405+ stack.remove_change_callback(ms::ObserverID{1});
406+ }, std::logic_error);
407+}
408+
409 TEST_F(SurfaceStack, surfaces_are_emitted_by_layer)
410 {
411 using namespace testing;

Subscribers

People subscribed via source and target branches