Mir

Merge lp:~cemil-azizoglu/mir/nested_lifecycle_events into lp:mir

Proposed by Cemil Azizoglu
Status: Merged
Approved by: Cemil Azizoglu
Approved revision: no longer in the source branch.
Merged at revision: 1774
Proposed branch: lp:~cemil-azizoglu/mir/nested_lifecycle_events
Merge into: lp:mir
Diff against target: 414 lines (+222/-4)
10 files modified
examples/demo-shell/demo_shell.cpp (+20/-0)
examples/demo-shell/window_manager.cpp (+11/-0)
include/server/mir/default_server_configuration.h (+4/-0)
include/server/mir/shell/host_lifecycle_event_listener.h (+44/-0)
src/server/graphics/default_configuration.cpp (+2/-1)
src/server/graphics/nested/mir_client_host_connection.cpp (+16/-2)
src/server/graphics/nested/mir_client_host_connection.h (+5/-1)
src/server/shell/default_configuration.cpp (+12/-0)
src/server/shell/null_host_lifecycle_event_listener.h (+38/-0)
tests/acceptance-tests/test_nested_mir.cpp (+70/-0)
To merge this branch: bzr merge lp:~cemil-azizoglu/mir/nested_lifecycle_events
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Alan Griffiths Needs Fixing
Alexandros Frantzis (community) Approve
Andreas Pokorny (community) Approve
Michael Terry Pending
Review via email: mp+224426@code.launchpad.net

Commit message

Listen to lifecycle events in nested server.

Description of the change

Nested server registers a callback for lifecycle events coming from the host. This is necessary for the nested server to receive lifecycle events so that its clients, in turn, can be notified.

To showcase, I have also added the ability to send lifecycle events to the focussed app upon hitting ctl-alt-L, to the example shell.

To post a comment you must log in.
Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote :

Since the nested tests don't work, I modified the demo_shell to test this MP.

https://code.launchpad.net/~cemil-azizoglu/mir/nested_lifecycle_events_test/+merge/224434

The test code needs some private headers exposed in the demo shell, and is not meant to be merged (thus, is marked as "disapprove").

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

21 + ${PROJECT_SOURCE_DIR}/include/server/mir/scene

Not needed: use the canonical include path "mir/scene/<whatever>"

22 + ${PROJECT_SOURCE_DIR}/src/server/scene

Not allowed (hence disapprove)

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

After our discussions on IRC I thought the intent was to provide a "hook" so that shells implemented using Mir could "hook" into these events and process them. As such I think that HostLifecycleEventListener should be in shell and not in scene.

~~~~

86 + mirnestedscene
...
193 +add_subdirectory(nested/)
...
203 +#include "nested/default_host_lifecycle_event_listener.h"

etc.

This new "scene/nested" library is not justified. All it contains is a default (null) implementation of an interface: scene::HostLifecycleEventListener. I see no reason not to put this in scene directly (or, in view of the above remarks: shell). (That's where you've put mir::DefaultServerConfiguration::the_host_lifecycle_event_listener() anyway).

~~~~

144 + std::static_pointer_cast<void>(host_lifecycle_event_listener).get());

No obvious need for the cast.

~~~~~

+void DefaultHostLifecycleEventListener::lifecycle_event_occured(MirLifecycleState state)
283 +{
284 + app_container->for_each(
285 + [&state](std::shared_ptr<Session> const& session)
286 + {
287 + session->set_lifecycle_state(state);
288 + });
289 +}

I think the default behavior should be to do nothing and let the implementing shell use this as a hook.

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

Getting closer. ;)

24 + /* Duplicate impl. Could move to a common library so Mir proper, and examples can share. */
25 + class NullHostLifecycleEventListener : public msh::HostLifecycleEventListener
26 + {
27 + public:
28 + virtual void lifecycle_event_occured(MirLifecycleState /*state*/) override
29 + {
30 + printf("This line must not be output\n");
31 + }
32 + };

Not needed as

57 + return host_lifecycle_event_listener(
58 + []()
59 + {
60 + return std::make_shared<NullHostLifecycleEventListener>();
61 + });
62 + }

Can be simply

  return mir::examples::ServerConfiguration::the_host_lifecycle_event_listener();

Although...

45 + auto nested = the_options()->is_set(options::host_socket_opt);
46 +
47 + if (nested)

Do we actually need two paths here? The function will only be called when a HostLifecycleEventListener is needed - i.e. in Nested mode. (And if it is called in other circumstances it is probably better to provide NestedLifecycleEventListener anyway.)

~~~~

362 + EXPECT_CALL(*this, lifecycle_event_occured(lifecycle_state)).Times(1);

Expectations should be set in the test body - as that should explain what is being checked. (And it would also be nice to see several notifications checked by InSequence.)

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

%s/occured/occurred/g

~~~~

347 + void TriggerLifecycleEvent(MirLifecycleState const lifecycle_state)

http://unity.ubuntu.com/mir/cppguide/index.html?showone=Function_Names#Function_Names

~~~~

387 + TriggerLifecycleEvent(mir_lifecycle_state_resumed);
388 + TriggerLifecycleEvent(mir_lifecycle_state_will_suspend);
389 +
390 + InSequence seq;
...

I'm surprised that sending the events before setting the expectations isn't racy.

~~~~

391 + EXPECT_CALL(*(static_cast<MockHostLifecycleEventListener*>(nested_config.the_host_lifecycle_event_listener().get())), lifecycle_event_occured(mir_lifecycle_state_resumed)).Times(1);
392 + EXPECT_CALL(*(static_cast<MockHostLifecycleEventListener*>(nested_config.the_host_lifecycle_event_listener().get())), lifecycle_event_occured(mir_lifecycle_state_will_suspend)).Times(1);

Excessively long lines.

I'd prefer to expose the MockHostLifecycleEventListener directly on MyServerConfiguration and use that to avoid the casts.

Something like:

TEST_F(NestedServer, receives_lifecycle_events_from_host)
{
    struct MyServerConfiguration : NestedServerConfiguration, MockHostLifecycleEventListener
    {
        using NestedServerConfiguration::NestedServerConfiguration;

        std::shared_ptr<msh::HostLifecycleEventListener> the_host_lifecycle_event_listener() override
        {
            return host_lifecycle_event_listener(
                [this]
                {
                    return mt::fake_shared<msh::HostLifecycleEventListener>(*this);
                });
        }
    };

    MyServerConfiguration nested_config{connection_string, the_graphics_platform()};

    NestedMirRunner nested_mir{nested_config};

    InSequence seq;
    EXPECT_CALL(nested_config, lifecycle_event_occured(mir_lifecycle_state_resumed)).Times(1);
    EXPECT_CALL(nested_config, lifecycle_event_occured(mir_lifecycle_state_will_suspend)).Times(1);

    trigger_lifecycle_event(mir_lifecycle_state_resumed);
    trigger_lifecycle_event(mir_lifecycle_state_will_suspend);
}

(Although that inheritance-for-convenience might earn a "Needs Fixing")

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

> 387 + TriggerLifecycleEvent(mir_lifecycle_state_resumed);
> 388 + TriggerLifecycleEvent(mir_lifecycle_state_will_suspend);
> 389 +
> 390 + InSequence seq;
> ...
>
> I'm surprised that sending the events before setting the expectations isn't
> racy.

Actually it is.

Sticking in...

    std::this_thread::sleep_for(std::chrono::seconds(1));

...shouldn't hurt but it does.

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

LGTM - although the example code sending the same event every time is a bit boring.

BTW does Jenkins not recognize you? It should be reviewing this.

review: Approve
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

toggling through life cycle would be cool.

All fine but a there is a C-Cast in 169, that should be a static_cast.

review: Needs Fixing
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

Looks good overall.

A couple of nits:

169 + msh::HostLifecycleEventListener *listener = (msh::HostLifecycleEventListener *) context;

The c-cast like mentioned by Andreas, and also '*' should go with the type (msh::HostLifecycleEventListener* listener = ...)

58 + if(app)

Space between if and '('.

review: Needs Fixing
Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote :

Iterating through an enum is a bit painful and would make the code messy. So I'll leave the example boring, but hopefully to the point. (Other comments addressed.)

Revision history for this message
Andreas Pokorny (andreas-pokorny) :
review: Approve
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

OK.

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

8 + . DefaultServerConfiguration: Lifecycle event listener for nested server.

Don't make changes to the cahngelog in "routine" MPs

These will all show at the same point and lead to spurious merge conflicts.

review: Needs Fixing
Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote :

> 8 + . DefaultServerConfiguration: Lifecycle event listener for nested
> server.
>
> Don't make changes to the cahngelog in "routine" MPs
>
> These will all show at the same point and lead to spurious merge conflicts.

Fixed.

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'examples/demo-shell/demo_shell.cpp'
2--- examples/demo-shell/demo_shell.cpp 2014-06-04 22:09:06 +0000
3+++ examples/demo-shell/demo_shell.cpp 2014-07-16 15:59:57 +0000
4@@ -29,6 +29,7 @@
5 #include "mir/graphics/display.h"
6 #include "mir/input/composite_event_filter.h"
7 #include "mir/compositor/renderer_factory.h"
8+#include "mir/shell/host_lifecycle_event_listener.h"
9
10 #include <iostream>
11
12@@ -38,6 +39,7 @@
13 namespace mf = mir::frontend;
14 namespace mi = mir::input;
15 namespace mo = mir::options;
16+namespace msh = mir::shell;
17
18 namespace mir
19 {
20@@ -108,6 +110,24 @@
21 return std::make_shared<DemoRendererFactory>(the_gl_program_factory());
22 }
23
24+ class NestedLifecycleEventListener : public msh::HostLifecycleEventListener
25+ {
26+ public:
27+ virtual void lifecycle_event_occurred(MirLifecycleState state) override
28+ {
29+ printf("Lifecycle event occurred : state = %d\n", state);
30+ }
31+ };
32+
33+ std::shared_ptr<msh::HostLifecycleEventListener> the_host_lifecycle_event_listener() override
34+ {
35+ return host_lifecycle_event_listener(
36+ []()
37+ {
38+ return std::make_shared<NestedLifecycleEventListener>();
39+ });
40+ }
41+
42 private:
43 std::vector<std::shared_ptr<mi::EventFilter>> const filter_list;
44 };
45
46=== modified file 'examples/demo-shell/window_manager.cpp'
47--- examples/demo-shell/window_manager.cpp 2014-06-10 14:40:23 +0000
48+++ examples/demo-shell/window_manager.cpp 2014-07-16 15:59:57 +0000
49@@ -163,6 +163,17 @@
50 return true;
51 }
52 else if ((event.key.modifiers & mir_key_modifier_alt) &&
53+ (event.key.modifiers & mir_key_modifier_ctrl) &&
54+ (event.key.scan_code == KEY_L) &&
55+ focus_controller)
56+ {
57+ auto const app = focus_controller->focussed_application().lock();
58+ if (app)
59+ {
60+ app->set_lifecycle_state(mir_lifecycle_state_will_suspend);
61+ }
62+ }
63+ else if ((event.key.modifiers & mir_key_modifier_alt) &&
64 (event.key.modifiers & mir_key_modifier_ctrl))
65 {
66 MirOrientation orientation = mir_orientation_normal;
67
68=== modified file 'include/server/mir/default_server_configuration.h'
69--- include/server/mir/default_server_configuration.h 2014-07-09 10:48:47 +0000
70+++ include/server/mir/default_server_configuration.h 2014-07-16 15:59:57 +0000
71@@ -69,6 +69,7 @@
72 class FocusSetter;
73 class FocusController;
74 class DisplayLayout;
75+class HostLifecycleEventListener;
76 }
77 namespace time
78 {
79@@ -243,6 +244,8 @@
80 virtual std::shared_ptr<shell::DisplayLayout> the_shell_display_layout();
81 virtual std::shared_ptr<scene::PromptSessionListener> the_prompt_session_listener();
82 virtual std::shared_ptr<scene::PromptSessionManager> the_prompt_session_manager();
83+ virtual std::shared_ptr<shell::HostLifecycleEventListener> the_host_lifecycle_event_listener();
84+
85 /** @} */
86
87 /** @name internal scene configuration
88@@ -394,6 +397,7 @@
89 CachedPtr<scene::PromptSessionManager> prompt_session_manager;
90 CachedPtr<scene::SessionCoordinator> session_coordinator;
91 CachedPtr<EmergencyCleanup> emergency_cleanup;
92+ CachedPtr<shell::HostLifecycleEventListener> host_lifecycle_event_listener;
93
94 private:
95 std::shared_ptr<options::Configuration> const configuration_options;
96
97=== added file 'include/server/mir/shell/host_lifecycle_event_listener.h'
98--- include/server/mir/shell/host_lifecycle_event_listener.h 1970-01-01 00:00:00 +0000
99+++ include/server/mir/shell/host_lifecycle_event_listener.h 2014-07-16 15:59:57 +0000
100@@ -0,0 +1,44 @@
101+/*
102+ * Copyright © 2014 Canonical Ltd.
103+ *
104+ * This program is free software: you can redistribute it and/or modify it
105+ * under the terms of the GNU General Public License version 3,
106+ * as published by the Free Software Foundation.
107+ *
108+ * This program is distributed in the hope that it will be useful,
109+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
110+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
111+ * GNU General Public License for more details.
112+ *
113+ * You should have received a copy of the GNU General Public License
114+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
115+ *
116+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
117+ */
118+
119+#ifndef MIR_HOST_LIFECYCLE_EVENT_LISTENER_H_
120+#define MIR_HOST_LIFECYCLE_EVENT_LISTENER_H_
121+
122+#include "mir_toolkit/common.h"
123+
124+namespace mir
125+{
126+namespace shell
127+{
128+
129+class HostLifecycleEventListener
130+{
131+public:
132+ virtual void lifecycle_event_occurred(MirLifecycleState state) = 0;
133+
134+protected:
135+ HostLifecycleEventListener() = default;
136+ virtual ~HostLifecycleEventListener() = default;
137+ HostLifecycleEventListener(HostLifecycleEventListener const&) = delete;
138+ HostLifecycleEventListener& operator=(HostLifecycleEventListener const&) = delete;
139+};
140+
141+}
142+}
143+
144+#endif /* MIR_HOST_LIFECYCLE_EVENT_LISTENER_H_ */
145
146=== modified file 'src/server/graphics/default_configuration.cpp'
147--- src/server/graphics/default_configuration.cpp 2014-07-09 10:48:47 +0000
148+++ src/server/graphics/default_configuration.cpp 2014-07-16 15:59:57 +0000
149@@ -185,7 +185,8 @@
150
151 return std::make_shared<graphics::nested::MirClientHostConnection>(
152 host_socket,
153- my_name);
154+ my_name,
155+ the_host_lifecycle_event_listener());
156 });
157 }
158
159
160=== modified file 'src/server/graphics/nested/mir_client_host_connection.cpp'
161--- src/server/graphics/nested/mir_client_host_connection.cpp 2014-04-17 11:04:41 +0000
162+++ src/server/graphics/nested/mir_client_host_connection.cpp 2014-07-16 15:59:57 +0000
163@@ -40,6 +40,12 @@
164 (*static_cast<std::function<void()>*>(context))();
165 }
166
167+static void nested_lifecycle_event_callback_thunk(MirConnection* /*connection*/, MirLifecycleState state, void *context)
168+{
169+ msh::HostLifecycleEventListener* listener = static_cast<msh::HostLifecycleEventListener*>(context);
170+ listener->lifecycle_event_occurred(state);
171+}
172+
173 class MirClientHostSurface : public mgn::HostSurface
174 {
175 public:
176@@ -80,9 +86,12 @@
177 }
178
179 mgn::MirClientHostConnection::MirClientHostConnection(
180- std::string const& host_socket, std::string const& name)
181+ std::string const& host_socket,
182+ std::string const& name,
183+ std::shared_ptr<msh::HostLifecycleEventListener> const& host_lifecycle_event_listener)
184 : mir_connection{mir_connect_sync(host_socket.c_str(), name.c_str())},
185- conf_change_callback{[]{}}
186+ conf_change_callback{[]{}},
187+ host_lifecycle_event_listener{host_lifecycle_event_listener}
188 {
189 if (!mir_connection_is_valid(mir_connection))
190 {
191@@ -92,6 +101,11 @@
192
193 BOOST_THROW_EXCEPTION(std::runtime_error(msg));
194 }
195+
196+ mir_connection_set_lifecycle_event_callback(
197+ mir_connection,
198+ nested_lifecycle_event_callback_thunk,
199+ std::static_pointer_cast<void>(host_lifecycle_event_listener).get());
200 }
201
202 mgn::MirClientHostConnection::~MirClientHostConnection()
203
204=== modified file 'src/server/graphics/nested/mir_client_host_connection.h'
205--- src/server/graphics/nested/mir_client_host_connection.h 2014-04-17 11:04:41 +0000
206+++ src/server/graphics/nested/mir_client_host_connection.h 2014-07-16 15:59:57 +0000
207@@ -20,11 +20,14 @@
208 #define MIR_GRAPHICS_NESTED_MIR_CLIENT_HOST_CONNECTION_H_
209
210 #include "host_connection.h"
211+#include "mir/shell/host_lifecycle_event_listener.h"
212
213 #include <string>
214
215 struct MirConnection;
216
217+namespace msh = mir::shell;
218+
219 namespace mir
220 {
221 namespace graphics
222@@ -35,7 +38,7 @@
223 class MirClientHostConnection : public HostConnection
224 {
225 public:
226- MirClientHostConnection(std::string const& host_socket, std::string const& name);
227+ MirClientHostConnection(std::string const& host_socket, std::string const& name, std::shared_ptr<msh::HostLifecycleEventListener> const& host_lifecycle_event_listener);
228 ~MirClientHostConnection();
229
230 std::vector<int> platform_fd_items() override;
231@@ -51,6 +54,7 @@
232 private:
233 MirConnection* const mir_connection;
234 std::function<void()> conf_change_callback;
235+ std::shared_ptr<msh::HostLifecycleEventListener> const host_lifecycle_event_listener;
236 };
237
238 }
239
240=== modified file 'src/server/shell/default_configuration.cpp'
241--- src/server/shell/default_configuration.cpp 2014-04-15 05:31:19 +0000
242+++ src/server/shell/default_configuration.cpp 2014-07-16 15:59:57 +0000
243@@ -17,6 +17,8 @@
244 */
245
246 #include "mir/default_server_configuration.h"
247+#include "null_host_lifecycle_event_listener.h"
248+
249
250 #include "consuming_placement_strategy.h"
251 #include "default_focus_mechanism.h"
252@@ -58,3 +60,13 @@
253 return std::make_shared<msh::GraphicsDisplayLayout>(the_display());
254 });
255 }
256+
257+std::shared_ptr<msh::HostLifecycleEventListener>
258+mir::DefaultServerConfiguration::the_host_lifecycle_event_listener()
259+{
260+ return host_lifecycle_event_listener(
261+ []()
262+ {
263+ return std::make_shared<msh::NullHostLifecycleEventListener>();
264+ });
265+}
266
267=== added file 'src/server/shell/null_host_lifecycle_event_listener.h'
268--- src/server/shell/null_host_lifecycle_event_listener.h 1970-01-01 00:00:00 +0000
269+++ src/server/shell/null_host_lifecycle_event_listener.h 2014-07-16 15:59:57 +0000
270@@ -0,0 +1,38 @@
271+/*
272+ * Copyright © 2014 Canonical Ltd.
273+ *
274+ * This program is free software: you can redistribute it and/or modify it
275+ * under the terms of the GNU General Public License version 3,
276+ * as published by the Free Software Foundation.
277+ *
278+ * This program is distributed in the hope that it will be useful,
279+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
280+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
281+ * GNU General Public License for more details.
282+ *
283+ * You should have received a copy of the GNU General Public License
284+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
285+ *
286+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
287+ */
288+
289+#ifndef MIR_NULL_HOST_LIFECYCLE_EVENT_LISTENER_H_
290+#define MIR_NULL_HOST_LIFECYCLE_EVENT_LISTENER_H_
291+
292+#include "mir/shell/host_lifecycle_event_listener.h"
293+
294+namespace mir
295+{
296+namespace shell
297+{
298+
299+class NullHostLifecycleEventListener : public HostLifecycleEventListener
300+{
301+public:
302+ virtual void lifecycle_event_occurred(MirLifecycleState /*state*/) override {}
303+};
304+
305+}
306+}
307+
308+#endif /* MIR_NULL_HOST_LIFECYCLE_EVENT_LISTENER_H_ */
309
310=== modified file 'tests/acceptance-tests/test_nested_mir.cpp'
311--- tests/acceptance-tests/test_nested_mir.cpp 2014-07-09 17:04:55 +0000
312+++ tests/acceptance-tests/test_nested_mir.cpp 2014-07-16 15:59:57 +0000
313@@ -22,6 +22,9 @@
314 #include "mir/graphics/display_configuration.h"
315 #include "mir/display_server.h"
316 #include "mir/run_mir.h"
317+#include "mir/shell/focus_controller.h"
318+#include "mir/scene/session.h"
319+#include "mir/shell/host_lifecycle_event_listener.h"
320
321 #include "mir_test_framework/in_process_server.h"
322 #include "mir_test_framework/stubbed_server_configuration.h"
323@@ -39,6 +42,7 @@
324 namespace mf = mir::frontend;
325 namespace mg = mir::graphics;
326 namespace mtf = mir_test_framework;
327+namespace msh = mir::shell;
328 using namespace testing;
329
330 namespace
331@@ -137,6 +141,19 @@
332 std::shared_ptr<mg::Platform> const adaptee;
333 };
334
335+struct MockHostLifecycleEventListener : msh::HostLifecycleEventListener
336+{
337+ MockHostLifecycleEventListener(
338+ std::shared_ptr<msh::HostLifecycleEventListener> const& wrapped) :
339+ wrapped(wrapped)
340+ {
341+ }
342+
343+ MOCK_METHOD1(lifecycle_event_occurred, void (MirLifecycleState));
344+
345+ std::shared_ptr<msh::HostLifecycleEventListener> const wrapped;
346+};
347+
348 struct NestedServerConfiguration : FakeCommandLine, public mir::DefaultServerConfiguration
349 {
350 NestedServerConfiguration(
351@@ -262,6 +279,18 @@
352 connection_string = new_connection();
353 }
354
355+ void trigger_lifecycle_event(MirLifecycleState const lifecycle_state)
356+ {
357+ auto const app = the_focus_controller()->focussed_application().lock();
358+
359+ EXPECT_TRUE(app != nullptr) << "Nested server not connected";
360+
361+ if (app)
362+ {
363+ app->set_lifecycle_state(lifecycle_state);
364+ }
365+ }
366+
367 std::string connection_string;
368 };
369 }
370@@ -323,3 +352,44 @@
371
372 EXPECT_FALSE(config.my_display.lock()) << "after run_mir() exits the display should be released";
373 }
374+
375+TEST_F(NestedServer, receives_lifecycle_events_from_host)
376+{
377+ struct MyServerConfiguration : NestedServerConfiguration
378+ {
379+ using NestedServerConfiguration::NestedServerConfiguration;
380+
381+ std::shared_ptr<msh::HostLifecycleEventListener> the_host_lifecycle_event_listener() override
382+ {
383+ return host_lifecycle_event_listener([this]()
384+ -> std::shared_ptr<msh::HostLifecycleEventListener>
385+ {
386+ return the_mock_host_lifecycle_event_listener();
387+ });
388+ }
389+
390+ std::shared_ptr<MockHostLifecycleEventListener> the_mock_host_lifecycle_event_listener()
391+ {
392+ return mock_host_lifecycle_event_listener([this]
393+ {
394+ return std::make_shared<MockHostLifecycleEventListener>(
395+ NestedServerConfiguration::the_host_lifecycle_event_listener());
396+ });
397+ }
398+
399+ mir::CachedPtr<MockHostLifecycleEventListener> mock_host_lifecycle_event_listener;
400+ };
401+
402+ MyServerConfiguration nested_config{connection_string, the_graphics_platform()};
403+
404+ NestedMirRunner nested_mir{nested_config};
405+
406+ InSequence seq;
407+ EXPECT_CALL(*(nested_config.the_mock_host_lifecycle_event_listener()),
408+ lifecycle_event_occurred(mir_lifecycle_state_resumed)).Times(1);
409+ EXPECT_CALL(*(nested_config.the_mock_host_lifecycle_event_listener()),
410+ lifecycle_event_occurred(mir_lifecycle_state_will_suspend)).Times(1);
411+
412+ trigger_lifecycle_event(mir_lifecycle_state_resumed);
413+ trigger_lifecycle_event(mir_lifecycle_state_will_suspend);
414+}

Subscribers

People subscribed via source and target branches