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
=== modified file 'src/include/server/mir/default_server_status_listener.h'
--- src/include/server/mir/default_server_status_listener.h 2015-02-22 07:46:25 +0000
+++ src/include/server/mir/default_server_status_listener.h 2016-06-10 18:31:23 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright © 2013 Canonical Ltd.2 * Copyright © 2013,2016 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,5 * under the terms of the GNU General Public License version 3,
@@ -20,23 +20,23 @@
20#define MIR_DEFAULT_SERVER_STATUS_LISTENER_H_20#define MIR_DEFAULT_SERVER_STATUS_LISTENER_H_
2121
22#include "mir/server_status_listener.h"22#include "mir/server_status_listener.h"
23#include "mir/scene/session.h"
2324
24namespace mir25namespace mir
25{26{
27namespace scene
28{
29class SessionContainer;
30}
26class DefaultServerStatusListener : public virtual ServerStatusListener31class DefaultServerStatusListener : public virtual ServerStatusListener
27{32{
28public:33public:
29 virtual void paused()34 DefaultServerStatusListener(std::shared_ptr<scene::SessionContainer> const& session_container);
30 {35 void paused() override;
31 }36 void resumed() override;
3237 void started() override;
33 virtual void resumed()38private:
34 {39 std::shared_ptr<scene::SessionContainer> const session_container;
35 }
36
37 virtual void started()
38 {
39 }
40};40};
41}41}
4242
4343
=== modified file 'src/server/CMakeLists.txt'
--- src/server/CMakeLists.txt 2016-06-02 05:33:50 +0000
+++ src/server/CMakeLists.txt 2016-06-10 18:31:23 +0000
@@ -52,6 +52,7 @@
52 terminate_with_current_exception.cpp52 terminate_with_current_exception.cpp
53 display_server.cpp53 display_server.cpp
54 default_server_configuration.cpp54 default_server_configuration.cpp
55 default_server_status_listener.cpp
55 glib_main_loop.cpp56 glib_main_loop.cpp
56 glib_main_loop_sources.cpp57 glib_main_loop_sources.cpp
57 default_emergency_cleanup.cpp58 default_emergency_cleanup.cpp
5859
=== modified file 'src/server/default_server_configuration.cpp'
--- src/server/default_server_configuration.cpp 2016-06-02 05:33:50 +0000
+++ src/server/default_server_configuration.cpp 2016-06-10 18:31:23 +0000
@@ -166,9 +166,9 @@
166std::shared_ptr<mir::ServerStatusListener> mir::DefaultServerConfiguration::the_server_status_listener()166std::shared_ptr<mir::ServerStatusListener> mir::DefaultServerConfiguration::the_server_status_listener()
167{167{
168 return server_status_listener(168 return server_status_listener(
169 []()169 [this]()
170 {170 {
171 return std::make_shared<mir::DefaultServerStatusListener>();171 return std::make_shared<mir::DefaultServerStatusListener>(the_session_container());
172 });172 });
173}173}
174174
175175
=== added file 'src/server/default_server_status_listener.cpp'
--- src/server/default_server_status_listener.cpp 1970-01-01 00:00:00 +0000
+++ src/server/default_server_status_listener.cpp 2016-06-10 18:31:23 +0000
@@ -0,0 +1,50 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Andreas Pokorny <andreas.pokorny@canonical.com>
17 */
18
19#include "mir/default_server_status_listener.h"
20#include "scene/session_container.h"
21
22#include "mir/scene/session.h"
23
24mir::DefaultServerStatusListener::DefaultServerStatusListener(
25 std::shared_ptr<scene::SessionContainer> const& session_container)
26 : session_container{session_container}
27{
28}
29
30void mir::DefaultServerStatusListener::paused()
31{
32 session_container->for_each(
33 [](std::shared_ptr<scene::Session> const& session)
34 {
35 session->set_lifecycle_state(mir_lifecycle_state_will_suspend);
36 });
37}
38
39void mir::DefaultServerStatusListener::resumed()
40{
41 session_container->for_each(
42 [](std::shared_ptr<scene::Session> const& session)
43 {
44 session->set_lifecycle_state(mir_lifecycle_state_resumed);
45 });
46}
47
48void mir::DefaultServerStatusListener::started()
49{
50}
051
=== modified file 'src/server/graphics/nested/display.cpp'
--- src/server/graphics/nested/display.cpp 2016-05-20 13:08:56 +0000
+++ src/server/graphics/nested/display.cpp 2016-06-10 18:31:23 +0000
@@ -26,6 +26,7 @@
26#include "mir/graphics/gl_context.h"26#include "mir/graphics/gl_context.h"
27#include "mir/graphics/surfaceless_egl_context.h"27#include "mir/graphics/surfaceless_egl_context.h"
28#include "mir/graphics/display_configuration_policy.h"28#include "mir/graphics/display_configuration_policy.h"
29#include "mir/graphics/event_handler_register.h"
29#include "mir/graphics/overlapping_output_grouping.h"30#include "mir/graphics/overlapping_output_grouping.h"
30#include "mir/graphics/gl_config.h"31#include "mir/graphics/gl_config.h"
31#include "mir/graphics/egl_error.h"32#include "mir/graphics/egl_error.h"
@@ -33,6 +34,7 @@
33#include "mir_toolkit/mir_connection.h"34#include "mir_toolkit/mir_connection.h"
34#include "mir/raii.h"35#include "mir/raii.h"
3536
37#include <sys/eventfd.h>
36#include <boost/throw_exception.hpp>38#include <boost/throw_exception.hpp>
37#include <stdexcept>39#include <stdexcept>
38#include <sstream>40#include <sstream>
@@ -186,8 +188,14 @@
186 display_report{display_report},188 display_report{display_report},
187 egl_display{connection->egl_native_display(), gl_config},189 egl_display{connection->egl_native_display(), gl_config},
188 outputs{},190 outputs{},
189 current_configuration(std::make_unique<NestedDisplayConfiguration>(connection->create_display_config()))191 current_configuration(std::make_unique<NestedDisplayConfiguration>(connection->create_display_config())),
192 lifecycle_trigger{eventfd(0, EFD_CLOEXEC|EFD_NONBLOCK|EFD_SEMAPHORE)}
190{193{
194 if (lifecycle_trigger < 0)
195 BOOST_THROW_EXCEPTION((std::system_error{errno,
196 std::system_category(),
197 "Failed to create event fd for nested display"}));
198
191 decltype(current_configuration) conf{dynamic_cast<NestedDisplayConfiguration*>(current_configuration->clone().release())};199 decltype(current_configuration) conf{dynamic_cast<NestedDisplayConfiguration*>(current_configuration->clone().release())};
192200
193 initial_conf_policy->apply_to(*conf);201 initial_conf_policy->apply_to(*conf);
@@ -198,11 +206,27 @@
198 swap(current_configuration, conf);206 swap(current_configuration, conf);
199 }207 }
200208
209 connection->set_lifecycle_event_callback(
210 [this](MirLifecycleState state)
211 {
212 std::lock_guard<std::mutex> lock_display_state(pause_resume_status_mutex);
213 lifecycle_state = state;
214 uint64_t dummy = 1;
215 if (write(lifecycle_trigger, &dummy, sizeof dummy) != sizeof dummy)
216 BOOST_THROW_EXCEPTION((std::system_error{errno,
217 std::system_category(),
218 "Failed to notify lifecycle event fd notification"}));
219
220 });
221
201 create_surfaces(*current_configuration);222 create_surfaces(*current_configuration);
202}223}
203224
204mgn::Display::~Display() noexcept225mgn::Display::~Display() noexcept
205{226{
227 connection->set_lifecycle_event_callback([](MirLifecycleState){});
228 if (registered)
229 registered->unregister_fd_handler(this);
206 eglBindAPI(MIR_SERVER_EGL_OPENGL_API);230 eglBindAPI(MIR_SERVER_EGL_OPENGL_API);
207 if (eglGetCurrentContext() == egl_display.egl_context())231 if (eglGetCurrentContext() == egl_display.egl_context())
208 eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);232 eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
@@ -343,21 +367,33 @@
343}367}
344368
345void mgn::Display::register_pause_resume_handlers(369void mgn::Display::register_pause_resume_handlers(
346 EventHandlerRegister& /*handlers*/,370 EventHandlerRegister& handlers,
347 DisplayPauseHandler const& /*pause_handler*/,371 DisplayPauseHandler const& pause_handler,
348 DisplayResumeHandler const& /*resume_handler*/)372 DisplayResumeHandler const& resume_handler)
349{373{
350 // No need to do anything374 registered = &handlers;
375 handlers.register_fd_handler(
376 {int(lifecycle_trigger)},
377 this,
378 [this](int)
379 {
380 update_pause_state();
381 });
382 std::lock_guard<std::mutex> lock_display_state(pause_resume_status_mutex);
383 this->pause_handler = pause_handler;
384 this->resume_handler = resume_handler;
351}385}
352386
353void mgn::Display::pause()387void mgn::Display::pause()
354{388{
355 // No need to do anything389 std::lock_guard<std::mutex> lock_display_state(pause_resume_status_mutex);
390 display_state = DisplayState::paused;
356}391}
357392
358void mgn::Display::resume()393void mgn::Display::resume()
359{394{
360 // No need to do anything395 std::lock_guard<std::mutex> lock_display_state(pause_resume_status_mutex);
396 display_state = DisplayState::running;
361}397}
362398
363auto mgn::Display::create_hardware_cursor(std::shared_ptr<mg::CursorImage> const& /*initial_image*/) -> std::shared_ptr<mg::Cursor>399auto mgn::Display::create_hardware_cursor(std::shared_ptr<mg::CursorImage> const& /*initial_image*/) -> std::shared_ptr<mg::Cursor>
@@ -375,3 +411,30 @@
375{411{
376 return nullptr;412 return nullptr;
377}413}
414
415void mgn::Display::update_pause_state()
416{
417 uint64_t dummy;
418 if (read(lifecycle_trigger, &dummy, sizeof dummy) != sizeof dummy)
419 {
420 if (errno == EAGAIN)
421 {
422 return;
423 }
424 BOOST_THROW_EXCEPTION((std::system_error{errno,
425 std::system_category(),
426 "Failed to consume nested fd notification"}));
427 }
428
429 std::unique_lock<std::mutex> lock_display_state(pause_resume_status_mutex);
430 if (display_state != DisplayState::running && lifecycle_state == mir_lifecycle_state_resumed && resume_handler)
431 {
432 lock_display_state.unlock();
433 resume_handler();
434 }
435 else if (display_state != DisplayState::paused && lifecycle_state == mir_lifecycle_state_will_suspend && pause_handler)
436 {
437 lock_display_state.unlock();
438 pause_handler();
439 }
440}
378441
=== modified file 'src/server/graphics/nested/display.h'
--- src/server/graphics/nested/display.h 2016-05-20 13:08:56 +0000
+++ src/server/graphics/nested/display.h 2016-06-10 18:31:23 +0000
@@ -23,6 +23,7 @@
23#include "mir/graphics/display_buffer.h"23#include "mir/graphics/display_buffer.h"
24#include "mir/graphics/display_configuration.h"24#include "mir/graphics/display_configuration.h"
25#include "mir/graphics/egl_resources.h"25#include "mir/graphics/egl_resources.h"
26#include "mir/fd.h"
2627
27#include "mir_toolkit/client_types.h"28#include "mir_toolkit/client_types.h"
2829
@@ -154,8 +155,22 @@
154 std::mutex mutable configuration_mutex;155 std::mutex mutable configuration_mutex;
155 std::unique_ptr<NestedDisplayConfiguration> current_configuration;156 std::unique_ptr<NestedDisplayConfiguration> current_configuration;
156157
158 std::mutex pause_resume_status_mutex;
159 mir::Fd lifecycle_trigger;
160 EventHandlerRegister* registered{nullptr};
161 enum class DisplayState
162 {
163 running,
164 paused,
165 };
166 DisplayState display_state{DisplayState::running};
167 MirLifecycleState lifecycle_state{mir_lifecycle_connection_lost};
168 DisplayPauseHandler pause_handler;
169 DisplayResumeHandler resume_handler;
170
157 void create_surfaces(mir::graphics::DisplayConfiguration const& configuration);171 void create_surfaces(mir::graphics::DisplayConfiguration const& configuration);
158 void complete_display_initialization(MirPixelFormat format);172 void complete_display_initialization(MirPixelFormat format);
173 void update_pause_state();
159};174};
160175
161}176}
162177
=== modified file 'src/server/graphics/nested/host_connection.h'
--- src/server/graphics/nested/host_connection.h 2016-06-07 16:20:53 +0000
+++ src/server/graphics/nested/host_connection.h 2016-06-10 18:31:23 +0000
@@ -56,6 +56,7 @@
56 virtual void set_cursor_image(CursorImage const& image) = 0;56 virtual void set_cursor_image(CursorImage const& image) = 0;
57 virtual void hide_cursor() = 0;57 virtual void hide_cursor() = 0;
58 virtual auto graphics_platform_library() -> std::string = 0;58 virtual auto graphics_platform_library() -> std::string = 0;
59 virtual void set_lifecycle_event_callback(std::function<void(MirLifecycleState)> const& cb) = 0;
5960
60 virtual UniqueInputConfig create_input_device_config() = 0;61 virtual UniqueInputConfig create_input_device_config() = 0;
61 virtual void set_input_device_change_callback(std::function<void(UniqueInputConfig)> const& cb) = 0;62 virtual void set_input_device_change_callback(std::function<void(UniqueInputConfig)> const& cb) = 0;
6263
=== modified file 'src/server/graphics/nested/mir_client_host_connection.cpp'
--- src/server/graphics/nested/mir_client_host_connection.cpp 2016-06-09 13:15:34 +0000
+++ src/server/graphics/nested/mir_client_host_connection.cpp 2016-06-10 18:31:23 +0000
@@ -29,6 +29,7 @@
29#include "mir/input/input_device_observer.h"29#include "mir/input/input_device_observer.h"
30#include "mir/frontend/event_sink.h"30#include "mir/frontend/event_sink.h"
31#include "mir/server_action_queue.h"31#include "mir/server_action_queue.h"
32#include "mir/report_exception.h"
3233
33#include <boost/throw_exception.hpp>34#include <boost/throw_exception.hpp>
34#include <boost/exception/errinfo_errno.hpp>35#include <boost/exception/errinfo_errno.hpp>
@@ -62,12 +63,6 @@
62 *reply_ptr = reply;63 *reply_ptr = reply;
63}64}
6465
65static void nested_lifecycle_event_callback_thunk(MirConnection* /*connection*/, MirLifecycleState state, void *context)
66{
67 msh::HostLifecycleEventListener* listener = static_cast<msh::HostLifecycleEventListener*>(context);
68 listener->lifecycle_event_occurred(state);
69}
70
71MirPixelFormat const cursor_pixel_format = mir_pixel_format_argb_8888;66MirPixelFormat const cursor_pixel_format = mir_pixel_format_argb_8888;
7267
73void copy_image(MirGraphicsRegion const& g, mg::CursorImage const& image)68void copy_image(MirGraphicsRegion const& g, mg::CursorImage const& image)
@@ -227,6 +222,7 @@
227 std::shared_ptr<msh::HostLifecycleEventListener> const& host_lifecycle_event_listener)222 std::shared_ptr<msh::HostLifecycleEventListener> const& host_lifecycle_event_listener)
228 : mir_connection{mir_connect_sync(host_socket.c_str(), name.c_str())},223 : mir_connection{mir_connect_sync(host_socket.c_str(), name.c_str())},
229 conf_change_callback{[]{}},224 conf_change_callback{[]{}},
225 lifecycle_callback{[](MirLifecycleState){}},
230 host_lifecycle_event_listener{host_lifecycle_event_listener},226 host_lifecycle_event_listener{host_lifecycle_event_listener},
231 event_callback{[](MirEvent const&, mir::geometry::Rectangle const&){}}227 event_callback{[](MirEvent const&, mir::geometry::Rectangle const&){}}
232{228{
@@ -241,8 +237,20 @@
241237
242 mir_connection_set_lifecycle_event_callback(238 mir_connection_set_lifecycle_event_callback(
243 mir_connection,239 mir_connection,
244 nested_lifecycle_event_callback_thunk,240 [](MirConnection* /*connection*/, MirLifecycleState state, void *context)
245 std::static_pointer_cast<void>(host_lifecycle_event_listener).get());241 {
242 mgn::MirClientHostConnection* obj = static_cast<mgn::MirClientHostConnection*>(context);
243 try
244 {
245 obj->handle_lifecycle_event(state);
246 }
247 catch(...)
248 {
249 report_exception();
250 abort();
251 }
252 },
253 static_cast<void*>(this));
246254
247 mir_connection_set_input_config_change_callback(255 mir_connection_set_input_config_change_callback(
248 mir_connection,256 mir_connection,
@@ -412,3 +420,14 @@
412{420{
413 event_callback(event, source_frame);421 event_callback(event, source_frame);
414}422}
423
424void mgn::MirClientHostConnection::set_lifecycle_event_callback(std::function<void(MirLifecycleState)> const& cb)
425{
426 lifecycle_callback = cb;
427}
428
429void mgn::MirClientHostConnection::handle_lifecycle_event(MirLifecycleState state)
430{
431 host_lifecycle_event_listener->lifecycle_event_occurred(state);
432 lifecycle_callback(state);
433}
415434
=== modified file 'src/server/graphics/nested/mir_client_host_connection.h'
--- src/server/graphics/nested/mir_client_host_connection.h 2016-06-07 16:20:53 +0000
+++ src/server/graphics/nested/mir_client_host_connection.h 2016-06-10 18:31:23 +0000
@@ -66,6 +66,7 @@
66 int width, int height, MirPixelFormat pf, char const* name,66 int width, int height, MirPixelFormat pf, char const* name,
67 MirBufferUsage usage, uint32_t output_id) override;67 MirBufferUsage usage, uint32_t output_id) override;
68 void set_display_config_change_callback(std::function<void()> const& cb) override;68 void set_display_config_change_callback(std::function<void()> const& cb) override;
69 void set_lifecycle_event_callback(std::function<void(MirLifecycleState)> const& cb) override;
69 void apply_display_config(MirDisplayConfiguration&) override;70 void apply_display_config(MirDisplayConfiguration&) override;
7071
71 void set_cursor_image(CursorImage const& image) override;72 void set_cursor_image(CursorImage const& image) override;
@@ -80,12 +81,14 @@
80 void set_input_event_callback(std::function<void(MirEvent const&, mir::geometry::Rectangle const&)> const& cb) override;81 void set_input_event_callback(std::function<void(MirEvent const&, mir::geometry::Rectangle const&)> const& cb) override;
81 void emit_input_event(MirEvent const& cb, mir::geometry::Rectangle const& source_frame) override;82 void emit_input_event(MirEvent const& cb, mir::geometry::Rectangle const& source_frame) override;
8283
84 void handle_lifecycle_event(MirLifecycleState state);
83private:85private:
84 void update_input_config(UniqueInputConfig input_config);86 void update_input_config(UniqueInputConfig input_config);
85 std::mutex surfaces_mutex;87 std::mutex surfaces_mutex;
8688
87 MirConnection* const mir_connection;89 MirConnection* const mir_connection;
88 std::function<void()> conf_change_callback;90 std::function<void()> conf_change_callback;
91 std::function<void(MirLifecycleState)> lifecycle_callback;
89 std::shared_ptr<msh::HostLifecycleEventListener> const host_lifecycle_event_listener;92 std::shared_ptr<msh::HostLifecycleEventListener> const host_lifecycle_event_listener;
9093
91 std::vector<HostSurface*> surfaces;94 std::vector<HostSurface*> surfaces;
9295
=== modified file 'tests/include/mir/test/doubles/stub_host_connection.h'
--- tests/include/mir/test/doubles/stub_host_connection.h 2016-06-09 13:15:34 +0000
+++ tests/include/mir/test/doubles/stub_host_connection.h 2016-06-10 18:31:23 +0000
@@ -50,6 +50,10 @@
50 {50 {
51 }51 }
5252
53 void set_lifecycle_event_callback(std::function<void(MirLifecycleState)> const&) override
54 {
55 }
56
53 void apply_display_config(MirDisplayConfiguration&) override {}57 void apply_display_config(MirDisplayConfiguration&) override {}
5458
55 std::shared_ptr<graphics::nested::HostSurface>59 std::shared_ptr<graphics::nested::HostSurface>
5660
=== modified file 'tests/unit-tests/graphics/nested/test_nested_display.cpp'
--- tests/unit-tests/graphics/nested/test_nested_display.cpp 2016-05-04 20:53:03 +0000
+++ tests/unit-tests/graphics/nested/test_nested_display.cpp 2016-06-10 18:31:23 +0000
@@ -21,8 +21,9 @@
21#include "src/server/graphics/nested/host_surface.h"21#include "src/server/graphics/nested/host_surface.h"
22#include "src/server/report/null/display_report.h"22#include "src/server/report/null/display_report.h"
23#include "mir/graphics/default_display_configuration_policy.h"23#include "mir/graphics/default_display_configuration_policy.h"
24#include "src/server/input/null_input_dispatcher.h"24#include "mir/graphics/event_handler_register.h"
25#include "mir_display_configuration_builder.h"25#include "mir_display_configuration_builder.h"
26#include "mir/events/event_builders.h"
2627
27#include "mir/test/doubles/mock_egl.h"28#include "mir/test/doubles/mock_egl.h"
28#include "mir/test/doubles/mock_gl_config.h"29#include "mir/test/doubles/mock_gl_config.h"
@@ -44,6 +45,32 @@
44namespace45namespace
45{46{
4647
48struct StubEventHandlerRegister : mg::EventHandlerRegister
49{
50public:
51 void register_signal_handler(std::initializer_list<int>, std::function<void(int)> const&) override
52 {
53 }
54
55 void register_signal_handler(std::initializer_list<int>, mir::UniqueModulePtr<std::function<void(int)>>) override
56 {
57 }
58
59 void register_fd_handler(std::initializer_list<int> fds, void const*, std::function<void(int)> const& callback) override
60 {
61 int fd = *begin(fds);
62 event_callback = [fd, callback]{callback(fd);};
63 }
64
65 void register_fd_handler(std::initializer_list<int>,
66 void const*,
67 mir::UniqueModulePtr<std::function<void(int)>>) override{};
68
69 void unregister_fd_handler(void const*) override{};
70
71 std::function<void()> event_callback;
72};
73
47class SingleDisplayHostConnection : public mtd::StubHostConnection74class SingleDisplayHostConnection : public mtd::StubHostConnection
48{75{
49public:76public:
@@ -51,6 +78,23 @@
51 {78 {
52 return mt::build_trivial_configuration();79 return mt::build_trivial_configuration();
53 }80 }
81
82 void set_lifecycle_event_callback(std::function<void(MirLifecycleState)> const& cb) override
83 {
84 lifecycle_callback = cb;
85 }
86
87 void simulate_suspend()
88 {
89 lifecycle_callback(mir_lifecycle_state_will_suspend);
90 }
91
92 void simulate_resume()
93 {
94 lifecycle_callback(mir_lifecycle_state_resumed);
95 }
96
97 std::function<void(MirLifecycleState)> lifecycle_callback;
54};98};
5599
56class MockApplyDisplayConfigHostConnection : public SingleDisplayHostConnection100class MockApplyDisplayConfigHostConnection : public SingleDisplayHostConnection
@@ -67,7 +111,7 @@
67 {111 {
68 auto nested_display_raw = new mgn::Display{112 auto nested_display_raw = new mgn::Display{
69 platform,113 platform,
70 std::make_shared<SingleDisplayHostConnection>(),114 connection,
71 mt::fake_shared(null_display_report),115 mt::fake_shared(null_display_report),
72 mt::fake_shared(default_conf_policy),116 mt::fake_shared(default_conf_policy),
73 gl_config};117 gl_config};
@@ -75,13 +119,33 @@
75 return std::unique_ptr<mgn::Display>{nested_display_raw};119 return std::unique_ptr<mgn::Display>{nested_display_raw};
76 }120 }
77121
122 std::shared_ptr<SingleDisplayHostConnection> const connection = std::make_shared<SingleDisplayHostConnection>();
78 testing::NiceMock<mtd::MockEGL> mock_egl;123 testing::NiceMock<mtd::MockEGL> mock_egl;
79 mi::NullInputDispatcher null_input_dispatcher;
80 mir::report::null::DisplayReport null_display_report;124 mir::report::null::DisplayReport null_display_report;
81 mg::CloneDisplayConfigurationPolicy default_conf_policy;125 mg::CloneDisplayConfigurationPolicy default_conf_policy;
82 mtd::StubGLConfig stub_gl_config;126 mtd::StubGLConfig stub_gl_config;
83 std::shared_ptr<mtd::NullPlatform> null_platform{127 std::shared_ptr<mtd::NullPlatform> null_platform{
84 std::make_shared<mtd::NullPlatform>()};128 std::make_shared<mtd::NullPlatform>()};
129 StubEventHandlerRegister stub_event_handler_register;
130
131 MOCK_METHOD0(pause, void());
132 MOCK_METHOD0(resume, void());
133
134 void install_pause_resume_handlers(mgn::Display& display)
135 {
136 display.register_pause_resume_handlers(
137 stub_event_handler_register,
138 [this]()
139 {
140 pause();
141 return true;
142 },
143 [this]()
144 {
145 resume();
146 return true;
147 });
148 }
85};149};
86150
87}151}
@@ -243,3 +307,40 @@
243307
244 auto dummy_context = nested_display->create_gl_context();308 auto dummy_context = nested_display->create_gl_context();
245}309}
310
311TEST_F(NestedDisplay, pauses_server_on_suspend)
312{
313 using namespace testing;
314
315 auto const nested_display = create_nested_display(
316 null_platform,
317 mt::fake_shared(stub_gl_config));
318
319 install_pause_resume_handlers(*nested_display);
320
321 EXPECT_CALL(*this, pause());
322 connection->simulate_suspend();
323 stub_event_handler_register.event_callback();
324}
325
326TEST_F(NestedDisplay, resumes_server_on_lifecycle_resume)
327{
328 using namespace testing;
329
330 auto const nested_display = create_nested_display(
331 null_platform,
332 mt::fake_shared(stub_gl_config));
333
334 install_pause_resume_handlers(*nested_display);
335
336 EXPECT_CALL(*this, pause());
337 EXPECT_CALL(*this, resume());
338
339 connection->simulate_suspend();
340 stub_event_handler_register.event_callback();
341
342 nested_display->pause();
343
344 connection->simulate_resume();
345 stub_event_handler_register.event_callback();
346}

Subscribers

People subscribed via source and target branches