Mir

Merge lp:~andreas-pokorny/mir/use-lifecycleevent-in-mirserver into lp:mir

Proposed by Andreas Pokorny
Status: Rejected
Rejected by: Andreas Pokorny
Proposed branch: lp:~andreas-pokorny/mir/use-lifecycleevent-in-mirserver
Merge into: lp:mir
Diff against target: 580 lines (+289/-32)
11 files modified
src/include/server/mir/default_server_status_listener.h (+12/-12)
src/server/CMakeLists.txt (+1/-0)
src/server/default_server_configuration.cpp (+2/-2)
src/server/default_server_status_listener.cpp (+50/-0)
src/server/graphics/nested/display.cpp (+70/-7)
src/server/graphics/nested/display.h (+15/-0)
src/server/graphics/nested/host_connection.h (+1/-0)
src/server/graphics/nested/mir_client_host_connection.cpp (+27/-8)
src/server/graphics/nested/mir_client_host_connection.h (+3/-0)
tests/include/mir/test/doubles/stub_host_connection.h (+4/-0)
tests/unit-tests/graphics/nested/test_nested_display.cpp (+104/-3)
To merge this branch: bzr merge lp:~andreas-pokorny/mir/use-lifecycleevent-in-mirserver
Reviewer Review Type Date Requested Status
Mir CI Bot continuous-integration Approve
Alan Griffiths Approve
Chris Halse Rogers Needs Fixing
Alberto Aguirre (community) Needs Information
Brandon Schaefer (community) Approve
Cemil Azizoglu (community) Approve
Review via email: mp+292375@code.launchpad.net

Commit message

Use the builtin lifecycle event as an indication of lifecycle changes of the server

With this change all sessions will receive lifecycle events when the server pauses or resumes. The nested display will use this event to feed the registered pause/resume handlers. Thus a nested server will pause when the hosting server pauses due to a vt switch.

This is a preparation step to use resume events and focus changes as a trigger for informing clients about missed key state changes.

Description of the change

This is a first step towards the sticky-alt-key problem that may happen after vt switches.
With this change the nested session is aware that the system compositor is paused, and gets paused to.

I also spiked using focus events as an indication, but that leads to several problematic scenarios during display configuration changes.

The proposed server status handling in DefaultServerStatusListener is identical to what unity-system-compositor already does. Note that also qtmir overrides this class since it has its own life cycle management that depends on the current shell mode.

To post a comment you must log in.
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3467
https://mir-jenkins.ubuntu.com/job/mir-ci/871/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/892
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/929
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/920
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/920
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/902
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/902/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/902
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/902/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/902
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/902/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/902
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/902/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/902
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/902/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/871/rebuild

review: Approve (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3468
https://mir-jenkins.ubuntu.com/job/mir-ci/894/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/930
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/969
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/960
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/960
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/940
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/940/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/940
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/940/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/940
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/940/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/940
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/940/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/940
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/940/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/894/rebuild

review: Approve (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

-ctest -S "$TEST_DIR/steer.cmake" --output-on-failure -j8 -V $@
+ctest -S "$TEST_DIR/steer.cmake" --output-on-failure -j16 -V $@

Doesn't belong in this MP.

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

"With this change the active session will receive lifecycle events when the server pauses or resumes. The nested display will use this event to feed the registered pause/resume handlers. Thus a nested server will pause when the hosting server pauses due to a vt switch."

Don't all sessions need the lifecycle event?

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

> "With this change the active session will receive lifecycle events when the
> server pauses or resumes. The nested display will use this event to feed the
> registered pause/resume handlers. Thus a nested server will pause when the
> hosting server pauses due to a vt switch."
>
> Don't all sessions need the lifecycle event?

Good point..

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3469
https://mir-jenkins.ubuntu.com/job/mir-ci/903/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/942
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/981
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/972
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/972
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/952
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/952/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/952
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/952/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/952
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/952/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/952
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/952/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/952
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/952/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/903/rebuild

review: Approve (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

Nit:

+ enum DisplayState
+ {
+ running,
+ paused,
+ };

Our guidelines say to prefer scoped enums (i.e. "enum class")

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

LGTM

review: Approve
Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

lgtm

review: Approve
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Autolanding.
More details in the following jenkins job:
https://mir-jenkins.ubuntu.com/job/mir-autolanding/229/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/947/console
    None: https://mir-jenkins.ubuntu.com/job/generic-land-mp/245/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/986
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/977
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/977
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/957/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/957/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/957
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/957/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/957
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/957/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/957/console

review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

20:55:57 /��BUILDDIR��/mir-0.22.0+vivid977bzr3469/src/server/graphics/nested/display.cpp:217:13: error: ignoring return value of function declared with warn_unused_result attribute [-Werror,-Wunused-result]
20:55:57 write(lifecycle_trigger, &dummy, sizeof dummy);
20:55:57 ^~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Revision history for this message
Chris Halse Rogers (raof) wrote :

174 + uint64_t dummy = 1;
175 + write(lifecycle_trigger, &dummy, sizeof dummy);

This can be slightly simplified as eventfd_write(lifecycle_trigger, 1); That would also fix the build issue with ignoring the return value of write().

But you should probably be checking for error and throwing if so; otherwise we'll get unexpected strange behaviour later on in the extremely unlikely event that eventfd_write fails.

Needs-fixing based on that.

Now that I think of it, I'm somewhat concerned about us overloading the meaning of mir_lifecycle_event_will_suspend and mir_lifecycle_event_resumed. For applications these mean “serialise your state to disc, because I'm about to kill you” and “restore your state from disc, because I've started you up again after killing you” respectively.

I know that using focus events for this ran into the problem of spurious focus changes during display configuration changes; would fixing those spurious focus changes be easy enough, and allow us to just use update-keystate-on-focus-change everywhere?

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

> Now that I think of it, I'm somewhat concerned about us overloading the
> meaning of mir_lifecycle_event_will_suspend and mir_lifecycle_event_resumed.
> For applications these mean “serialise your state to disc, because I'm about
> to kill you” and “restore your state from disc, because I've started you up
> again after killing you” respectively.
>
> I know that using focus events for this ran into the problem of spurious focus
> changes during display configuration changes; would fixing those spurious
> focus changes be easy enough, and allow us to just use update-keystate-on-
> focus-change everywhere?

I will look into the second part. On the lifecycle event I thought unity8 also does that, and might not kill the application between the two events, but I might be wrong here. I had a similar concern of overloading semantics when using focus lost as an indication that the server should pause.

Revision history for this message
Chris Halse Rogers (raof) wrote :

Yeah, it'd be really nice if we actually had a separate
system-compositor protocol. unity-system-compositor isn't a normal Mir
server, and Unity8 isn't a normal Mir client, and it's been a continual
source of friction.

Revision history for this message
Chris Halse Rogers (raof) wrote :

Actually, back up. Why are we pausing the nested server on focus-lost?

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

Why overload the lifecycle semantics? Would it be too redudant to add: "mir_lifecycle_event_will_pause, mir_lifecycle_event_will_resume"?

review: Needs Information
Revision history for this message
Chris Halse Rogers (raof) wrote :

> Why overload the lifecycle semantics? Would it be too redudant to add:
> "mir_lifecycle_event_will_pause, mir_lifecycle_event_will_resume"?

What do these mean to non-system-compositor clients?

3470. By Andreas Pokorny

merge current lp:mir

3471. By Andreas Pokorny

throw on write

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

> Why overload the lifecycle semantics? Would it be too redudant to add:
> "mir_lifecycle_event_will_pause, mir_lifecycle_event_will_resume"?

They mean the server is pausing/resuming the client.

I don't think they should be used here.

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

> > Why overload the lifecycle semantics? Would it be too redudant to add:
> > "mir_lifecycle_event_will_pause, mir_lifecycle_event_will_resume"?
>
> What do these mean to non-system-compositor clients?

The same actually.. the change makes the server state transitive to the nested server. And the default nested server would decide that when paused clients are paused too. When resumed all clients are resumed to their previous state too.

I think that part of the behavior would be a shell decision. I.e. a nested servers could still also decide to send lifecycle stop to clients when paused.. and use the resume flank to restart the clients.

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

> > Why overload the lifecycle semantics? Would it be too redudant to add:
> > "mir_lifecycle_event_will_pause, mir_lifecycle_event_will_resume"?
>
> They mean the server is pausing/resuming the client.
>
> I don't think they should be used here.

Whats the need fixing?

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

> Actually, back up. Why are we pausing the nested server on focus-lost?

Because we can, but we do not have to. This has the advantage that it would stop repeat handling and application not-responding detection in a system state in which we would be happy if applications are not responding.

We could install a specific handler for either surface attribute focus, or life cycle events. And then not pause the server.

I just believe it makes sense to use that information and pause processing.
Not only for power saving reasons but also to make the nested server less different from a system compositor.

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:3471
https://mir-jenkins.ubuntu.com/job/mir-ci/916/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/964/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/1009
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/1000
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/1000
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/974
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/974/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/974
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/974/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/974
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/974/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/974/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/974
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/974/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/916/rebuild

review: Needs Fixing (continuous-integration)
3472. By Andreas Pokorny

enum class instead of enum

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:3472
https://mir-jenkins.ubuntu.com/job/mir-ci/920/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/972/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/1018
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/1009
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/1009
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/982
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/982/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/982
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/982/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/982/console
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/982/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/982
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/982/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/982/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/920/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Chris Halse Rogers (raof) wrote :

> > > Why overload the lifecycle semantics? Would it be too redudant to add:
> > > "mir_lifecycle_event_will_pause, mir_lifecycle_event_will_resume"?
> >
> > What do these mean to non-system-compositor clients?
>
> The same actually.. the change makes the server state transitive to the nested
> server. And the default nested server would decide that when paused clients
> are paused too. When resumed all clients are resumed to their previous state
> too.
>
> I think that part of the behavior would be a shell decision. I.e. a nested
> servers could still also decide to send lifecycle stop to clients when
> paused.. and use the resume flank to restart the clients.
But we already have pause/resume events for clients, but with different semantics. Do we now have two different levels of “paused” - paused-and-SIGHUP/SIGKILL-is-moments-away and paused-and-nothing-much? And two different levels of “resumed” - resume-and-reload-from-disc-because-we've-SIGKILLed-you-in-the-past, and resume-nothing-much?

It seems like forwarding on the paused lifecycle events is shell-specific, and should not be in the DefaultServerListenerThingy().

I'm not too adverse to USC sending _will_suspend and _resumed events and nested acting on them, but I don't think the former bit should be here?

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

+ if (lifecycle_callback)
+ lifecycle_callback(state);

It would be better to initialize lifecycle_callback with a null functor than rely on checking at the call site.

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

*Needs discussion*

OK, I've thought about it and read the spec.

I think the confusion comes from a mismatch between MirLifecycleState and the design.

"Event: application_about_to_suspend

"This event is triggered when the application is about to be suspended. Application authors can rely on this event to account for the situation that the UI will not be visible to the user anymore and that they will be granted at most minor CPU timeslices and no GPU timeslices. The event is accompanied by an archive that application authors can rely on to store application-specific state. In addition, an application instance is granted a limited amount of time for carrying out any preparations to go to suspend. After this time has elapsed, the system executes the transition." (Draft: Application Model)

It does makes sense to automatically propagate this to clients. But is that what mir_lifecycle_event_will_pause means? I think it has been conflated with:

"Event: application_about_to_stop

"This event is triggered when the application is about to be terminated, i.e., the process containing the application instance will be terminated. The event is accompanied by an archive that application authors can rely on to store application-specific state. In addition, an application instance is granted a limited amount of time for carrying out any preparations to go to suspend. After this time has elapsed, the system executes the transition."

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

> *Needs discussion*
>
> OK, I've thought about it and read the spec.
>
> I think the confusion comes from a mismatch between MirLifecycleState and the
> design.

After hearing more, things are not clear and this MP doesn't add any new confusion.

review: Approve
3473. By Andreas Pokorny

initialize lifecycle event callback

3474. By Andreas Pokorny

merge lp:mir and resolve if(functor) functor() complaint..

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3474
https://mir-jenkins.ubuntu.com/job/mir-ci/1156/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/1289
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/1339
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/1330
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/1330
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1299
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1299/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1299
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1299/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1299
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1299/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1299
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1299/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/1299
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/1299/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/1156/rebuild

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

After a short discussion we realized that mir needs to have a different behavior on vt switch:

https://trello.com/c/cgF8ho09/407-better-pause-state-handling-in-host-server

and in general we should not have to use mir lifecycle for that..

so rejecting this MP & branch

Unmerged revisions

3474. By Andreas Pokorny

merge lp:mir and resolve if(functor) functor() complaint..

3473. By Andreas Pokorny

initialize lifecycle event callback

3472. By Andreas Pokorny

enum class instead of enum

3471. By Andreas Pokorny

throw on write

3470. By Andreas Pokorny

merge current lp:mir

3469. By Andreas Pokorny

Emit life cycle event to all sessions and revert ctest changes

3468. By Andreas Pokorny

update lp:mir

3467. By Andreas Pokorny

Use the builtin lifecycle event as an indication of lifecycle changes of the server

With this change the active session will receive lifecycle events when the server pauses or resumes. The nested display will use this event to feed the registered pause/resume handlers. Thus a nested server will pause when the hosting server pauses due to a vt switch.

This is a preparation step to use resume events and focus events as a trigger for informing clients about missed key state changes.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/include/server/mir/default_server_status_listener.h'
2--- src/include/server/mir/default_server_status_listener.h 2015-02-22 07:46:25 +0000
3+++ src/include/server/mir/default_server_status_listener.h 2016-06-10 18:31:23 +0000
4@@ -1,5 +1,5 @@
5 /*
6- * Copyright © 2013 Canonical Ltd.
7+ * Copyright © 2013,2016 Canonical Ltd.
8 *
9 * This program is free software: you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License version 3,
11@@ -20,23 +20,23 @@
12 #define MIR_DEFAULT_SERVER_STATUS_LISTENER_H_
13
14 #include "mir/server_status_listener.h"
15+#include "mir/scene/session.h"
16
17 namespace mir
18 {
19+namespace scene
20+{
21+class SessionContainer;
22+}
23 class DefaultServerStatusListener : public virtual ServerStatusListener
24 {
25 public:
26- virtual void paused()
27- {
28- }
29-
30- virtual void resumed()
31- {
32- }
33-
34- virtual void started()
35- {
36- }
37+ DefaultServerStatusListener(std::shared_ptr<scene::SessionContainer> const& session_container);
38+ void paused() override;
39+ void resumed() override;
40+ void started() override;
41+private:
42+ std::shared_ptr<scene::SessionContainer> const session_container;
43 };
44 }
45
46
47=== modified file 'src/server/CMakeLists.txt'
48--- src/server/CMakeLists.txt 2016-06-02 05:33:50 +0000
49+++ src/server/CMakeLists.txt 2016-06-10 18:31:23 +0000
50@@ -52,6 +52,7 @@
51 terminate_with_current_exception.cpp
52 display_server.cpp
53 default_server_configuration.cpp
54+ default_server_status_listener.cpp
55 glib_main_loop.cpp
56 glib_main_loop_sources.cpp
57 default_emergency_cleanup.cpp
58
59=== modified file 'src/server/default_server_configuration.cpp'
60--- src/server/default_server_configuration.cpp 2016-06-02 05:33:50 +0000
61+++ src/server/default_server_configuration.cpp 2016-06-10 18:31:23 +0000
62@@ -166,9 +166,9 @@
63 std::shared_ptr<mir::ServerStatusListener> mir::DefaultServerConfiguration::the_server_status_listener()
64 {
65 return server_status_listener(
66- []()
67+ [this]()
68 {
69- return std::make_shared<mir::DefaultServerStatusListener>();
70+ return std::make_shared<mir::DefaultServerStatusListener>(the_session_container());
71 });
72 }
73
74
75=== added file 'src/server/default_server_status_listener.cpp'
76--- src/server/default_server_status_listener.cpp 1970-01-01 00:00:00 +0000
77+++ src/server/default_server_status_listener.cpp 2016-06-10 18:31:23 +0000
78@@ -0,0 +1,50 @@
79+/*
80+ * Copyright © 2016 Canonical Ltd.
81+ *
82+ * This program is free software: you can redistribute it and/or modify it
83+ * under the terms of the GNU General Public License version 3,
84+ * as published by the Free Software Foundation.
85+ *
86+ * This program is distributed in the hope that it will be useful,
87+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
88+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
89+ * GNU General Public License for more details.
90+ *
91+ * You should have received a copy of the GNU General Public License
92+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
93+ *
94+ * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
95+ */
96+
97+#include "mir/default_server_status_listener.h"
98+#include "scene/session_container.h"
99+
100+#include "mir/scene/session.h"
101+
102+mir::DefaultServerStatusListener::DefaultServerStatusListener(
103+ std::shared_ptr<scene::SessionContainer> const& session_container)
104+ : session_container{session_container}
105+{
106+}
107+
108+void mir::DefaultServerStatusListener::paused()
109+{
110+ session_container->for_each(
111+ [](std::shared_ptr<scene::Session> const& session)
112+ {
113+ session->set_lifecycle_state(mir_lifecycle_state_will_suspend);
114+ });
115+}
116+
117+void mir::DefaultServerStatusListener::resumed()
118+{
119+ session_container->for_each(
120+ [](std::shared_ptr<scene::Session> const& session)
121+ {
122+ session->set_lifecycle_state(mir_lifecycle_state_resumed);
123+ });
124+}
125+
126+void mir::DefaultServerStatusListener::started()
127+{
128+}
129
130=== modified file 'src/server/graphics/nested/display.cpp'
131--- src/server/graphics/nested/display.cpp 2016-05-20 13:08:56 +0000
132+++ src/server/graphics/nested/display.cpp 2016-06-10 18:31:23 +0000
133@@ -26,6 +26,7 @@
134 #include "mir/graphics/gl_context.h"
135 #include "mir/graphics/surfaceless_egl_context.h"
136 #include "mir/graphics/display_configuration_policy.h"
137+#include "mir/graphics/event_handler_register.h"
138 #include "mir/graphics/overlapping_output_grouping.h"
139 #include "mir/graphics/gl_config.h"
140 #include "mir/graphics/egl_error.h"
141@@ -33,6 +34,7 @@
142 #include "mir_toolkit/mir_connection.h"
143 #include "mir/raii.h"
144
145+#include <sys/eventfd.h>
146 #include <boost/throw_exception.hpp>
147 #include <stdexcept>
148 #include <sstream>
149@@ -186,8 +188,14 @@
150 display_report{display_report},
151 egl_display{connection->egl_native_display(), gl_config},
152 outputs{},
153- current_configuration(std::make_unique<NestedDisplayConfiguration>(connection->create_display_config()))
154+ current_configuration(std::make_unique<NestedDisplayConfiguration>(connection->create_display_config())),
155+ lifecycle_trigger{eventfd(0, EFD_CLOEXEC|EFD_NONBLOCK|EFD_SEMAPHORE)}
156 {
157+ if (lifecycle_trigger < 0)
158+ BOOST_THROW_EXCEPTION((std::system_error{errno,
159+ std::system_category(),
160+ "Failed to create event fd for nested display"}));
161+
162 decltype(current_configuration) conf{dynamic_cast<NestedDisplayConfiguration*>(current_configuration->clone().release())};
163
164 initial_conf_policy->apply_to(*conf);
165@@ -198,11 +206,27 @@
166 swap(current_configuration, conf);
167 }
168
169+ connection->set_lifecycle_event_callback(
170+ [this](MirLifecycleState state)
171+ {
172+ std::lock_guard<std::mutex> lock_display_state(pause_resume_status_mutex);
173+ lifecycle_state = state;
174+ uint64_t dummy = 1;
175+ if (write(lifecycle_trigger, &dummy, sizeof dummy) != sizeof dummy)
176+ BOOST_THROW_EXCEPTION((std::system_error{errno,
177+ std::system_category(),
178+ "Failed to notify lifecycle event fd notification"}));
179+
180+ });
181+
182 create_surfaces(*current_configuration);
183 }
184
185 mgn::Display::~Display() noexcept
186 {
187+ connection->set_lifecycle_event_callback([](MirLifecycleState){});
188+ if (registered)
189+ registered->unregister_fd_handler(this);
190 eglBindAPI(MIR_SERVER_EGL_OPENGL_API);
191 if (eglGetCurrentContext() == egl_display.egl_context())
192 eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
193@@ -343,21 +367,33 @@
194 }
195
196 void mgn::Display::register_pause_resume_handlers(
197- EventHandlerRegister& /*handlers*/,
198- DisplayPauseHandler const& /*pause_handler*/,
199- DisplayResumeHandler const& /*resume_handler*/)
200+ EventHandlerRegister& handlers,
201+ DisplayPauseHandler const& pause_handler,
202+ DisplayResumeHandler const& resume_handler)
203 {
204- // No need to do anything
205+ registered = &handlers;
206+ handlers.register_fd_handler(
207+ {int(lifecycle_trigger)},
208+ this,
209+ [this](int)
210+ {
211+ update_pause_state();
212+ });
213+ std::lock_guard<std::mutex> lock_display_state(pause_resume_status_mutex);
214+ this->pause_handler = pause_handler;
215+ this->resume_handler = resume_handler;
216 }
217
218 void mgn::Display::pause()
219 {
220- // No need to do anything
221+ std::lock_guard<std::mutex> lock_display_state(pause_resume_status_mutex);
222+ display_state = DisplayState::paused;
223 }
224
225 void mgn::Display::resume()
226 {
227- // No need to do anything
228+ std::lock_guard<std::mutex> lock_display_state(pause_resume_status_mutex);
229+ display_state = DisplayState::running;
230 }
231
232 auto mgn::Display::create_hardware_cursor(std::shared_ptr<mg::CursorImage> const& /*initial_image*/) -> std::shared_ptr<mg::Cursor>
233@@ -375,3 +411,30 @@
234 {
235 return nullptr;
236 }
237+
238+void mgn::Display::update_pause_state()
239+{
240+ uint64_t dummy;
241+ if (read(lifecycle_trigger, &dummy, sizeof dummy) != sizeof dummy)
242+ {
243+ if (errno == EAGAIN)
244+ {
245+ return;
246+ }
247+ BOOST_THROW_EXCEPTION((std::system_error{errno,
248+ std::system_category(),
249+ "Failed to consume nested fd notification"}));
250+ }
251+
252+ std::unique_lock<std::mutex> lock_display_state(pause_resume_status_mutex);
253+ if (display_state != DisplayState::running && lifecycle_state == mir_lifecycle_state_resumed && resume_handler)
254+ {
255+ lock_display_state.unlock();
256+ resume_handler();
257+ }
258+ else if (display_state != DisplayState::paused && lifecycle_state == mir_lifecycle_state_will_suspend && pause_handler)
259+ {
260+ lock_display_state.unlock();
261+ pause_handler();
262+ }
263+}
264
265=== modified file 'src/server/graphics/nested/display.h'
266--- src/server/graphics/nested/display.h 2016-05-20 13:08:56 +0000
267+++ src/server/graphics/nested/display.h 2016-06-10 18:31:23 +0000
268@@ -23,6 +23,7 @@
269 #include "mir/graphics/display_buffer.h"
270 #include "mir/graphics/display_configuration.h"
271 #include "mir/graphics/egl_resources.h"
272+#include "mir/fd.h"
273
274 #include "mir_toolkit/client_types.h"
275
276@@ -154,8 +155,22 @@
277 std::mutex mutable configuration_mutex;
278 std::unique_ptr<NestedDisplayConfiguration> current_configuration;
279
280+ std::mutex pause_resume_status_mutex;
281+ mir::Fd lifecycle_trigger;
282+ EventHandlerRegister* registered{nullptr};
283+ enum class DisplayState
284+ {
285+ running,
286+ paused,
287+ };
288+ DisplayState display_state{DisplayState::running};
289+ MirLifecycleState lifecycle_state{mir_lifecycle_connection_lost};
290+ DisplayPauseHandler pause_handler;
291+ DisplayResumeHandler resume_handler;
292+
293 void create_surfaces(mir::graphics::DisplayConfiguration const& configuration);
294 void complete_display_initialization(MirPixelFormat format);
295+ void update_pause_state();
296 };
297
298 }
299
300=== modified file 'src/server/graphics/nested/host_connection.h'
301--- src/server/graphics/nested/host_connection.h 2016-06-07 16:20:53 +0000
302+++ src/server/graphics/nested/host_connection.h 2016-06-10 18:31:23 +0000
303@@ -56,6 +56,7 @@
304 virtual void set_cursor_image(CursorImage const& image) = 0;
305 virtual void hide_cursor() = 0;
306 virtual auto graphics_platform_library() -> std::string = 0;
307+ virtual void set_lifecycle_event_callback(std::function<void(MirLifecycleState)> const& cb) = 0;
308
309 virtual UniqueInputConfig create_input_device_config() = 0;
310 virtual void set_input_device_change_callback(std::function<void(UniqueInputConfig)> const& cb) = 0;
311
312=== modified file 'src/server/graphics/nested/mir_client_host_connection.cpp'
313--- src/server/graphics/nested/mir_client_host_connection.cpp 2016-06-09 13:15:34 +0000
314+++ src/server/graphics/nested/mir_client_host_connection.cpp 2016-06-10 18:31:23 +0000
315@@ -29,6 +29,7 @@
316 #include "mir/input/input_device_observer.h"
317 #include "mir/frontend/event_sink.h"
318 #include "mir/server_action_queue.h"
319+#include "mir/report_exception.h"
320
321 #include <boost/throw_exception.hpp>
322 #include <boost/exception/errinfo_errno.hpp>
323@@ -62,12 +63,6 @@
324 *reply_ptr = reply;
325 }
326
327-static void nested_lifecycle_event_callback_thunk(MirConnection* /*connection*/, MirLifecycleState state, void *context)
328-{
329- msh::HostLifecycleEventListener* listener = static_cast<msh::HostLifecycleEventListener*>(context);
330- listener->lifecycle_event_occurred(state);
331-}
332-
333 MirPixelFormat const cursor_pixel_format = mir_pixel_format_argb_8888;
334
335 void copy_image(MirGraphicsRegion const& g, mg::CursorImage const& image)
336@@ -227,6 +222,7 @@
337 std::shared_ptr<msh::HostLifecycleEventListener> const& host_lifecycle_event_listener)
338 : mir_connection{mir_connect_sync(host_socket.c_str(), name.c_str())},
339 conf_change_callback{[]{}},
340+ lifecycle_callback{[](MirLifecycleState){}},
341 host_lifecycle_event_listener{host_lifecycle_event_listener},
342 event_callback{[](MirEvent const&, mir::geometry::Rectangle const&){}}
343 {
344@@ -241,8 +237,20 @@
345
346 mir_connection_set_lifecycle_event_callback(
347 mir_connection,
348- nested_lifecycle_event_callback_thunk,
349- std::static_pointer_cast<void>(host_lifecycle_event_listener).get());
350+ [](MirConnection* /*connection*/, MirLifecycleState state, void *context)
351+ {
352+ mgn::MirClientHostConnection* obj = static_cast<mgn::MirClientHostConnection*>(context);
353+ try
354+ {
355+ obj->handle_lifecycle_event(state);
356+ }
357+ catch(...)
358+ {
359+ report_exception();
360+ abort();
361+ }
362+ },
363+ static_cast<void*>(this));
364
365 mir_connection_set_input_config_change_callback(
366 mir_connection,
367@@ -412,3 +420,14 @@
368 {
369 event_callback(event, source_frame);
370 }
371+
372+void mgn::MirClientHostConnection::set_lifecycle_event_callback(std::function<void(MirLifecycleState)> const& cb)
373+{
374+ lifecycle_callback = cb;
375+}
376+
377+void mgn::MirClientHostConnection::handle_lifecycle_event(MirLifecycleState state)
378+{
379+ host_lifecycle_event_listener->lifecycle_event_occurred(state);
380+ lifecycle_callback(state);
381+}
382
383=== modified file 'src/server/graphics/nested/mir_client_host_connection.h'
384--- src/server/graphics/nested/mir_client_host_connection.h 2016-06-07 16:20:53 +0000
385+++ src/server/graphics/nested/mir_client_host_connection.h 2016-06-10 18:31:23 +0000
386@@ -66,6 +66,7 @@
387 int width, int height, MirPixelFormat pf, char const* name,
388 MirBufferUsage usage, uint32_t output_id) override;
389 void set_display_config_change_callback(std::function<void()> const& cb) override;
390+ void set_lifecycle_event_callback(std::function<void(MirLifecycleState)> const& cb) override;
391 void apply_display_config(MirDisplayConfiguration&) override;
392
393 void set_cursor_image(CursorImage const& image) override;
394@@ -80,12 +81,14 @@
395 void set_input_event_callback(std::function<void(MirEvent const&, mir::geometry::Rectangle const&)> const& cb) override;
396 void emit_input_event(MirEvent const& cb, mir::geometry::Rectangle const& source_frame) override;
397
398+ void handle_lifecycle_event(MirLifecycleState state);
399 private:
400 void update_input_config(UniqueInputConfig input_config);
401 std::mutex surfaces_mutex;
402
403 MirConnection* const mir_connection;
404 std::function<void()> conf_change_callback;
405+ std::function<void(MirLifecycleState)> lifecycle_callback;
406 std::shared_ptr<msh::HostLifecycleEventListener> const host_lifecycle_event_listener;
407
408 std::vector<HostSurface*> surfaces;
409
410=== modified file 'tests/include/mir/test/doubles/stub_host_connection.h'
411--- tests/include/mir/test/doubles/stub_host_connection.h 2016-06-09 13:15:34 +0000
412+++ tests/include/mir/test/doubles/stub_host_connection.h 2016-06-10 18:31:23 +0000
413@@ -50,6 +50,10 @@
414 {
415 }
416
417+ void set_lifecycle_event_callback(std::function<void(MirLifecycleState)> const&) override
418+ {
419+ }
420+
421 void apply_display_config(MirDisplayConfiguration&) override {}
422
423 std::shared_ptr<graphics::nested::HostSurface>
424
425=== modified file 'tests/unit-tests/graphics/nested/test_nested_display.cpp'
426--- tests/unit-tests/graphics/nested/test_nested_display.cpp 2016-05-04 20:53:03 +0000
427+++ tests/unit-tests/graphics/nested/test_nested_display.cpp 2016-06-10 18:31:23 +0000
428@@ -21,8 +21,9 @@
429 #include "src/server/graphics/nested/host_surface.h"
430 #include "src/server/report/null/display_report.h"
431 #include "mir/graphics/default_display_configuration_policy.h"
432-#include "src/server/input/null_input_dispatcher.h"
433+#include "mir/graphics/event_handler_register.h"
434 #include "mir_display_configuration_builder.h"
435+#include "mir/events/event_builders.h"
436
437 #include "mir/test/doubles/mock_egl.h"
438 #include "mir/test/doubles/mock_gl_config.h"
439@@ -44,6 +45,32 @@
440 namespace
441 {
442
443+struct StubEventHandlerRegister : mg::EventHandlerRegister
444+{
445+public:
446+ void register_signal_handler(std::initializer_list<int>, std::function<void(int)> const&) override
447+ {
448+ }
449+
450+ void register_signal_handler(std::initializer_list<int>, mir::UniqueModulePtr<std::function<void(int)>>) override
451+ {
452+ }
453+
454+ void register_fd_handler(std::initializer_list<int> fds, void const*, std::function<void(int)> const& callback) override
455+ {
456+ int fd = *begin(fds);
457+ event_callback = [fd, callback]{callback(fd);};
458+ }
459+
460+ void register_fd_handler(std::initializer_list<int>,
461+ void const*,
462+ mir::UniqueModulePtr<std::function<void(int)>>) override{};
463+
464+ void unregister_fd_handler(void const*) override{};
465+
466+ std::function<void()> event_callback;
467+};
468+
469 class SingleDisplayHostConnection : public mtd::StubHostConnection
470 {
471 public:
472@@ -51,6 +78,23 @@
473 {
474 return mt::build_trivial_configuration();
475 }
476+
477+ void set_lifecycle_event_callback(std::function<void(MirLifecycleState)> const& cb) override
478+ {
479+ lifecycle_callback = cb;
480+ }
481+
482+ void simulate_suspend()
483+ {
484+ lifecycle_callback(mir_lifecycle_state_will_suspend);
485+ }
486+
487+ void simulate_resume()
488+ {
489+ lifecycle_callback(mir_lifecycle_state_resumed);
490+ }
491+
492+ std::function<void(MirLifecycleState)> lifecycle_callback;
493 };
494
495 class MockApplyDisplayConfigHostConnection : public SingleDisplayHostConnection
496@@ -67,7 +111,7 @@
497 {
498 auto nested_display_raw = new mgn::Display{
499 platform,
500- std::make_shared<SingleDisplayHostConnection>(),
501+ connection,
502 mt::fake_shared(null_display_report),
503 mt::fake_shared(default_conf_policy),
504 gl_config};
505@@ -75,13 +119,33 @@
506 return std::unique_ptr<mgn::Display>{nested_display_raw};
507 }
508
509+ std::shared_ptr<SingleDisplayHostConnection> const connection = std::make_shared<SingleDisplayHostConnection>();
510 testing::NiceMock<mtd::MockEGL> mock_egl;
511- mi::NullInputDispatcher null_input_dispatcher;
512 mir::report::null::DisplayReport null_display_report;
513 mg::CloneDisplayConfigurationPolicy default_conf_policy;
514 mtd::StubGLConfig stub_gl_config;
515 std::shared_ptr<mtd::NullPlatform> null_platform{
516 std::make_shared<mtd::NullPlatform>()};
517+ StubEventHandlerRegister stub_event_handler_register;
518+
519+ MOCK_METHOD0(pause, void());
520+ MOCK_METHOD0(resume, void());
521+
522+ void install_pause_resume_handlers(mgn::Display& display)
523+ {
524+ display.register_pause_resume_handlers(
525+ stub_event_handler_register,
526+ [this]()
527+ {
528+ pause();
529+ return true;
530+ },
531+ [this]()
532+ {
533+ resume();
534+ return true;
535+ });
536+ }
537 };
538
539 }
540@@ -243,3 +307,40 @@
541
542 auto dummy_context = nested_display->create_gl_context();
543 }
544+
545+TEST_F(NestedDisplay, pauses_server_on_suspend)
546+{
547+ using namespace testing;
548+
549+ auto const nested_display = create_nested_display(
550+ null_platform,
551+ mt::fake_shared(stub_gl_config));
552+
553+ install_pause_resume_handlers(*nested_display);
554+
555+ EXPECT_CALL(*this, pause());
556+ connection->simulate_suspend();
557+ stub_event_handler_register.event_callback();
558+}
559+
560+TEST_F(NestedDisplay, resumes_server_on_lifecycle_resume)
561+{
562+ using namespace testing;
563+
564+ auto const nested_display = create_nested_display(
565+ null_platform,
566+ mt::fake_shared(stub_gl_config));
567+
568+ install_pause_resume_handlers(*nested_display);
569+
570+ EXPECT_CALL(*this, pause());
571+ EXPECT_CALL(*this, resume());
572+
573+ connection->simulate_suspend();
574+ stub_event_handler_register.event_callback();
575+
576+ nested_display->pause();
577+
578+ connection->simulate_resume();
579+ stub_event_handler_register.event_callback();
580+}

Subscribers

People subscribed via source and target branches