Mir

Merge lp:~mir-team/mir/surface-output-events into lp:mir

Proposed by Chris Halse Rogers on 2015-09-29
Status: Merged
Approved by: Alexandros Frantzis on 2015-10-07
Approved revision: 3032
Merged at revision: 3000
Proposed branch: lp:~mir-team/mir/surface-output-events
Merge into: lp:mir
Prerequisite: lp:~raof/mir/display-configuration-for-the-shell
Diff against target: 2661 lines (+1280/-110)
47 files modified
include/client/mir/events/event_builders.h (+6/-0)
include/client/mir_toolkit/events/event.h (+18/-0)
include/client/mir_toolkit/events/surface_output_event.h (+61/-0)
include/common/mir_toolkit/common.h (+14/-0)
include/platform/mir/graphics/display_configuration.h (+13/-4)
include/test/mir/test/doubles/stub_display_configuration.h (+51/-9)
include/test/mir/test/empty_deleter.h (+1/-1)
src/client/CMakeLists.txt (+1/-0)
src/client/event.cpp (+27/-0)
src/client/events/event_builders.cpp (+18/-0)
src/client/rpc/mir_protobuf_rpc_channel.cpp (+3/-0)
src/client/symbols.map (+4/-0)
src/include/common/mir/events/event_private.h (+11/-0)
src/include/server/mir/scene/surface_event_source.h (+10/-0)
src/platform/graphics/display_configuration.cpp (+51/-13)
src/platforms/android/server/fb_device.cpp (+3/-1)
src/platforms/android/server/hwc_blanking_control.cpp (+7/-1)
src/platforms/mesa/server/kms/real_kms_display_configuration.cpp (+5/-4)
src/platforms/mesa/server/x11/graphics/display_configuration.cpp (+3/-1)
src/server/graphics/nested/nested_display_configuration.cpp (+6/-2)
src/server/graphics/offscreen/display_configuration.cpp (+3/-1)
src/server/scene/CMakeLists.txt (+2/-0)
src/server/scene/application_session.cpp (+31/-3)
src/server/scene/application_session.h (+9/-0)
src/server/scene/default_configuration.cpp (+4/-0)
src/server/scene/output_properties_cache.cpp (+100/-0)
src/server/scene/output_properties_cache.h (+66/-0)
src/server/scene/session_manager.cpp (+15/-5)
src/server/scene/session_manager.h (+18/-8)
src/server/scene/surface_event_source.cpp (+20/-0)
tests/acceptance-tests/test_client_focus_notification.cpp (+3/-0)
tests/acceptance-tests/test_client_surface_events.cpp (+100/-0)
tests/acceptance-tests/test_system_compositor_window_manager.cpp (+1/-3)
tests/include/mir/test/doubles/stub_surface_factory.h (+5/-2)
tests/integration-tests/session_management.cpp (+1/-1)
tests/integration-tests/test_session.cpp (+2/-0)
tests/mir_test/display_config_matchers.cpp (+6/-2)
tests/unit-tests/graphics/mesa/kms/test_cursor.cpp (+9/-3)
tests/unit-tests/graphics/mesa/kms/test_display_configuration.cpp (+34/-16)
tests/unit-tests/graphics/test_default_display_configuration_policy.cpp (+4/-2)
tests/unit-tests/graphics/test_display_configuration.cpp (+29/-1)
tests/unit-tests/graphics/test_overlapping_output_grouping.cpp (+4/-2)
tests/unit-tests/scene/test_abstract_shell.cpp (+9/-2)
tests/unit-tests/scene/test_application_session.cpp (+466/-14)
tests/unit-tests/scene/test_session_manager.cpp (+12/-3)
tests/unit-tests/scene/test_surface.cpp (+5/-2)
tests/unit-tests/scene/test_surface_impl.cpp (+9/-4)
To merge this branch: bzr merge lp:~mir-team/mir/surface-output-events
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration 2015-09-29 Approve on 2015-10-07
Alexandros Frantzis (community) Approve on 2015-10-07
Alan Griffiths 2015-09-29 Approve on 2015-10-06
Review via email: mp+272698@code.launchpad.net

This proposal supersedes a proposal from 2015-09-25.

Commit Message

send events pertaining to the output (dpi, form factor, scale) to the client, available as events.

Description of the Change

Send events pertaining to the output (dpi, form factor, scale) to the client, available as events.

To post a comment you must log in.
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

How much of this diff is the same as lp:~mir-team/mir/surface-event-ordering/+merge/270879

review: Needs Information
Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal

let me figure that out and restack accordingly...

Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal

@Alan, about half :)

Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

+ /// \return the display configuration changer
+ auto the_display_changer() const -> std::shared_ptr<mir::DisplayChanger>;

Why are we making internal wiring part of the API?

~~~~

+#include "src/include/server/mir/display_changer.h"

There's a reason src/include/server/ is not on the include path: Acceptance tests should only use the public API.

review: Needs Fixing
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

> +#include "src/include/server/mir/display_changer.h"
>
> There's a reason src/include/server/ is not on the include path: Acceptance
> tests should only use the public API.

OK, maybe it's arguable that this already happens in some acceptance tests.

Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal

still have to find the fd leak in test, please still review :)

Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

display_changer.h is not (and should not be) a public header.

That means the API should not include:

+ /// \return the display configuration changer
+ auto the_display_changer() const -> std::shared_ptr<mir::DisplayChanger>;

as that isn't of any use to library users.

review: Needs Fixing
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

-)
+ ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/events/surface_output_event.h)

Not our usual placement of parentheses.

Chris Halse Rogers (raof) wrote : Posted in a previous version of this proposal

This is *mostly* ready to review. The exposure of DisplayChanger needs to be replaced by adding a subset of that interface to something in mir::scene and then rebasing on that.

Alan Griffiths (alan-griffiths) wrote :

 MIR_CLIENT_9.2 { # New functions in Mir 0.16
   global:
     mir_surface_spec_set_event_handler;
+ mir_event_get_surface_output_event;
+ mir_surface_output_event_get_dpi;
+ mir_surface_output_event_get_form_factor;
+ mir_surface_output_event_get_scale;

0.16 has been branched. These should be in a 0.17 stanza

~~~~

+std::string as_string(MirFormFactor form_factor)
+{

Is there any good reason for std::string as opposed to char const*?

~~~~

+ out << "{" << std::endl << "\tid: " << val.id << std::endl << "\tcard_id: " << val.card_id << std::endl
+ << "\ttype: " << output_type_to_string(val.type) << std::endl
+ << "\tmodes: [ ";

We don't need all the flush() calls from the endl manipulator - "\n" would be fine.

~~~~

+ std::function<std::shared_ptr<graphics::DisplayConfiguration const>()> const& get_display_config,

I very much prefer defining an interface for the desired functionality over using std::function<>. Even when the interface has a single member function this makes the dependences across the system much clearer.

Instead of MediatingDisplayChanger implementing a DisplayConfigurationProvider interface, we have a std::function<> that wraps a call to a builder function to call a function on an interface required by frontend that coincidentally offers functionality also needed by the SessionManager.

~~~~

+ [this]() -> std::shared_ptr<mg::DisplayConfiguration>
+ {
+ return the_frontend_display_changer()->active_configuration();
+ },

I don't think this parameter should be a std::function<> (see previous note) but, given this approach, it ought to capture result of the_frontend_display_changer(), not the DefaultServerConfiguration. The reason being that the dependency is between SessionManager and a facility implemented by MediatingDisplayChanger and the latter should be kept alive, not (potentially) reconstructed for each request.

review: Needs Fixing
2981. By Chris Halse Rogers on 2015-09-30

EventSinkFactory: Delete CopyAssign

2982. By Chris Halse Rogers on 2015-09-30

Drop changes to MockEventSink

2983. By Chris Halse Rogers on 2015-09-30

Add shell::DisplayConfigurationController.

This allows a shell to correctly change the display configuration, notifying clients
as appropriate.

2984. By Chris Halse Rogers on 2015-09-30

MediatingDisplayChanger: Implement ms::DisplayConfigurationController

2985. By Chris Halse Rogers on 2015-09-30

Augment mt::DisplayConfigMatches to handle the other client/server comparison order

2986. By Chris Halse Rogers on 2015-09-30

mtd::StubDisplayConfig: Add a constructor that duplicates an existing mg::DisplayConfig

2987. By Chris Halse Rogers on 2015-09-30

Expose mir::Server::the_display_configuration_controller().

Implemented by ms::MediatingDisplayChanger by default.

2988. By Chris Halse Rogers on 2015-09-30

Acceptance test for set_default_display_configuration()

Alan Griffiths (alan-griffiths) wrote :

"Diff against target: 0 lines"

Probably not as intended

review: Needs Information
2989. By Chris Halse Rogers on 2015-10-01

DisplayConfigurationController: Delete CopyAssign

2990. By Chris Halse Rogers on 2015-10-02

First cut at mir_surface_output_event acceptance test

2991. By Chris Halse Rogers on 2015-10-02

Add DisplayConfigurationOutput unit-test for comparison with new fields

2992. By Chris Halse Rogers on 2015-10-02

StubDisplayConfig: Add a constructor taking a vector<DisplayConfigurationOutput>

2993. By Chris Halse Rogers on 2015-10-02

First go at pushing SurfaceOutputEvents from the ApplicationSession

2994. By Chris Halse Rogers on 2015-10-02

Send output properties appropriate to the display the top-left corner of a surface is on

2995. By Chris Halse Rogers on 2015-10-02

Send the details of the highest-scale output a surface is partially on

2996. By Chris Halse Rogers on 2015-10-02

Factor out an OutputPropertiesCache

2997. By Chris Halse Rogers on 2015-10-02

Make OutputPropertiesCache::properties_for resiliant under failure to set initial config

2998. By Chris Halse Rogers on 2015-10-02

Send SurfaceOutput event in response to moving a surface to a different output

2999. By Chris Halse Rogers on 2015-10-02

Give surface output events their own test fixture.

It's different enough from ApplicationSessionSender to make it worthwhile.

3000. By Chris Halse Rogers on 2015-10-02

Factor out test output configuration setup

3001. By Chris Halse Rogers on 2015-10-02

Add operator<<(ostream, DisplayConfiguration).

We've already got pretty-printers for DisplayConfigurationCard and DisplayConfigurationOutput,
let's go the whole hog.

3002. By Chris Halse Rogers on 2015-10-02

client: Dispatch mir_event_type_surface_output to the correct MirSurface

3003. By Chris Halse Rogers on 2015-10-02

Improve pretty-printing for DisplayConfigurationOutput

3004. By Chris Halse Rogers on 2015-10-02

Slighly generalise mt::EmptyDeleter.

It's fine to take a void const*, which I'll soon want to pass it.

3005. By Chris Halse Rogers on 2015-10-02

Plumb the initial display configuration through to ApplicationSession.

The next step is to have the application session use this to send a SurfaceOutputEvent
on surface creation.

3006. By Chris Halse Rogers on 2015-10-02

Pass a non-null sender in ApplicationSessionSurfaceOutput tests.

This lets them pass, rather than SEGV when they try to dereference it...

3007. By Kevin DuBois on 2015-10-02

improve the android code to return the right form factor for external displays

3008. By Kevin DuBois on 2015-10-02

get tests to compile, and pass

3009. By Kevin DuBois on 2015-10-02

correct a bit in OutputProperties cache to avoid atomics

3010. By Chris Halse Rogers on 2015-10-02

Add test for surface-output event on construction

3011. By Kevin DuBois on 2015-10-02

Ignore the new scaling event in the focus test

3012. By Kevin DuBois on 2015-10-02

correct the unit tests, which needed some mock behavior added

3013. By Kevin DuBois on 2015-10-02

correction for integration test, all tests passing

3014. By Kevin DuBois on 2015-10-02

clean up spacings where possible

3015. By Kevin DuBois on 2015-10-02

fix up clang

3016. By Chris Halse Rogers on 2015-10-02

Add mir_form_factor_unknown

3017. By Chris Halse Rogers on 2015-10-02

Fix CMakeLists.txt formatting

3018. By Chris Halse Rogers on 2015-10-02

Make SystemCompositorWindowManager.if_no_surface_posts_client_never_gets_focus resiliant to non-focus events being sent.

If a mock function has an EXPECT_CALL set for it, even if it's .Times(0), then any calls
that *don't* match that specifier become errors.

There's no reason to fail that test if the surface receives a non-focus event, and there's
no reason to add expectations for any other surface events we might choose to send now
or in the future.

3019. By Chris Halse Rogers on 2015-10-02

SessionManager: Take a reference to the_display() rather than a std::function<> to get the configuration.

3020. By Chris Halse Rogers on 2015-10-02

Add new client symbols to new version stanza; 0.17 is being released

3021. By Chris Halse Rogers on 2015-10-02

We don't need to construct a std::string to print the MirFormFactor

3022. By Chris Halse Rogers on 2015-10-02

Fewer superfluous flush() calls via std::endl

Chris Halse Rogers (raof) wrote :

> MIR_CLIENT_9.2 { # New functions in Mir 0.16
> global:
> mir_surface_spec_set_event_handler;
> + mir_event_get_surface_output_event;
> + mir_surface_output_event_get_dpi;
> + mir_surface_output_event_get_form_factor;
> + mir_surface_output_event_get_scale;
>
> 0.16 has been branched. These should be in a 0.17 stanza
>

Done.
> ~~~~
>
> +std::string as_string(MirFormFactor form_factor)
> +{
>
> Is there any good reason for std::string as opposed to char const*?
>

No; fixed.

> ~~~~
>
> + out << "{" << std::endl << "\tid: " << val.id << std::endl << "\tcard_id:
> " << val.card_id << std::endl
> + << "\ttype: " << output_type_to_string(val.type) << std::endl
> + << "\tmodes: [ ";
>
> We don't need all the flush() calls from the endl manipulator - "\n" would be
> fine.

But then we won't be portable to platforms that need \r\n! :)

Fixed.

Chris Halse Rogers (raof) wrote :

> MIR_CLIENT_9.2 { # New functions in Mir 0.16
> global:
> mir_surface_spec_set_event_handler;
> + mir_event_get_surface_output_event;
> + mir_surface_output_event_get_dpi;
> + mir_surface_output_event_get_form_factor;
> + mir_surface_output_event_get_scale;
>
> 0.16 has been branched. These should be in a 0.17 stanza
>

Done.
> ~~~~
>
> +std::string as_string(MirFormFactor form_factor)
> +{
>
> Is there any good reason for std::string as opposed to char const*?
>

No; fixed.

> ~~~~
>
> + out << "{" << std::endl << "\tid: " << val.id << std::endl << "\tcard_id:
> " << val.card_id << std::endl
> + << "\ttype: " << output_type_to_string(val.type) << std::endl
> + << "\tmodes: [ ";
>
> We don't need all the flush() calls from the endl manipulator - "\n" would be
> fine.

But then we won't be portable to platforms that need \r\n! :)

Fixed.

Alan Griffiths (alan-griffiths) wrote :

> > We don't need all the flush() calls from the endl manipulator - "\n" would
> be
> > fine.
>
> But then we won't be portable to platforms that need \r\n! :)

We'll be just as portable as with endl. (Which by definition is put(widen('\n')) followed by flush().)

Alan Griffiths (alan-griffiths) wrote :

+MIR_CLIENT_0.18 {
+ mir_event_get_surface_output_event;
+ mir_surface_output_event_get_dpi;
+ mir_surface_output_event_get_form_factor;
+ mir_surface_output_event_get_scale;
+} MIR_CLIENT_9v17;

We've not branched 0.17 yet - these should be in the 0.17 stanza.

review: Needs Fixing
3023. By Chris Halse Rogers on 2015-10-05

Add new client symbols to correct version stanza

Chris Halse Rogers (raof) wrote :

See, this is why my DSO proposal has a _unreleased stanza :)

Fixed.

3024. By Chris Halse Rogers on 2015-10-05

OutputPropertiesCache: Correctly handle output.connected == false.

Disconnected outputs have an empty output.modes vector, and some of their fields
- such as current_mode_index - are uninitialised. Don't try to index into an empty
vector by an uninitialised index.

3025. By Chris Halse Rogers on 2015-10-05

Fix up mg::DisplayConfigurationOutput::*_mode_index.

Using size_t in the server doesn't make any sense when we send them over
the wire to clients as uint32_t.

3026. By Chris Halse Rogers on 2015-10-05

OutputPropertiesCache: Even more paranoia about outputs.

Really what we care about is that the current_mode_index is valid.
Just check against the size of the mode vector directly.

Chris Halse Rogers (raof) wrote :

HOW DID THAT NOT FAIL LOCALLY?

3027. By Chris Halse Rogers on 2015-10-05

Fix two build issues that *my* gcc-5 doesn't find for some reason

3028. By Chris Halse Rogers on 2015-10-06

StubDisplayConfig: Ensure the first display is connected and used.

The Android tests assume that the first output of the StubDisplayConfig contains
sane values, which is not true for disconnected outputs.

Alan Griffiths (alan-griffiths) wrote :

There's a lot of superfluous flush() calls (from using endl).

review: Approve
Alexandros Frantzis (afrantzis) wrote :

A couple of concerns:

+ auto new_output_properties = outputs.properties_for(geom::Rectangle{top_left, {100,100}});
+ if (new_output_properties)

Unless I overlooked some logic, we will be sending unchanged output properties to the client on every move, flooding the clients unnecessarily. We shouldn't be sending output properties unless there is a change.

Is the 100x100 area we are using to decide on which output the surface belongs to based on some specification or is it completely arbitrary? In any case we should document this decision in the code (name and/or comment).

review: Needs Fixing
3029. By Chris Halse Rogers on 2015-10-07

Factor out a SurfaceOutputEventFor matcher

3030. By Chris Halse Rogers on 2015-10-07

Drop some unsatisfying mockery

3031. By Chris Halse Rogers on 2015-10-07

SurfaceEventSource: Use the surface's actual size for output calculations.

3032. By Chris Halse Rogers on 2015-10-07

SurfaceEventSource: Only send SurfaceOutputEvents when the surface moves to a different output.

Chris Halse Rogers (raof) wrote :

> A couple of concerns:
>
> + auto new_output_properties =
> outputs.properties_for(geom::Rectangle{top_left, {100,100}});
> + if (new_output_properties)
>
> Unless I overlooked some logic, we will be sending unchanged output properties
> to the client on every move, flooding the clients unnecessarily. We shouldn't
> be sending output properties unless there is a change.
>
> Is the 100x100 area we are using to decide on which output the surface belongs
> to based on some specification or is it completely arbitrary? In any case we
> should document this decision in the code (name and/or comment).

Urgh, thanks for noticing. These were both artefacts of work half-finished before I needed to go back and hack some prerequisite. Fixed.

Alexandros Frantzis (afrantzis) wrote :

Looks good.

review: Approve
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/client/mir/events/event_builders.h'
2--- include/client/mir/events/event_builders.h 2015-09-16 17:20:32 +0000
3+++ include/client/mir/events/event_builders.h 2015-10-07 06:10:46 +0000
4@@ -46,6 +46,12 @@
5 EventUPtr make_event(frontend::SurfaceId const& surface_id);
6 // Keymap event
7 EventUPtr make_event(frontend::SurfaceId const& surface_id, xkb_rule_names const& names);
8+// Surface output event
9+EventUPtr make_event(
10+ frontend::SurfaceId const& surface_id,
11+ int dpi,
12+ float scale,
13+ MirFormFactor form_factor);
14
15 // Key event
16 EventUPtr make_event(MirInputDeviceId device_id, std::chrono::nanoseconds timestamp,
17
18=== modified file 'include/client/mir_toolkit/events/event.h'
19--- include/client/mir_toolkit/events/event.h 2015-06-18 04:38:28 +0000
20+++ include/client/mir_toolkit/events/event.h 2015-10-07 06:10:46 +0000
21@@ -45,6 +45,7 @@
22 mir_event_type_input,
23 mir_event_type_keymap,
24 mir_event_type_input_configuration,
25+ mir_event_type_surface_output,
26 } MirEventType;
27
28 typedef struct MirSurfaceEvent MirSurfaceEvent;
29@@ -55,6 +56,7 @@
30 typedef struct MirInputEvent MirInputEvent;
31 typedef struct MirKeymapEvent MirKeymapEvent;
32 typedef struct MirInputConfigurationEvent MirInputConfigurationEvent;
33+typedef struct MirSurfaceOutputEvent MirSurfaceOutputEvent;
34
35 typedef union MirEvent MirEvent;
36
37@@ -70,6 +72,7 @@
38 #include "mir_toolkit/events/prompt_session_event.h"
39 #include "mir_toolkit/events/keymap_event.h"
40 #include "mir_toolkit/events/input_configuration_event.h"
41+#include "mir_toolkit/events/surface_output_event.h"
42
43 #ifdef __cplusplus
44 /**
45@@ -169,6 +172,21 @@
46 */
47 MirInputConfigurationEvent const* mir_event_get_input_configuration_event(MirEvent const* ev);
48
49+/**
50+ * Retrieve the MirSurfaceOutputEvent associated with a MirEvent of type
51+ * mir_event_type_surface_output. The event signifies that the properties
52+ * of the output the surface is displayed upon have changed.
53+ *
54+ * A MirSurfaceOutputEvent is generated either when the properties of the
55+ * output the surface is primarily on change (for example: by user configuration
56+ * of resolution) or when the output the surface is primarily on changes
57+ * (for example: when a user moves the surface from one monitor to another).
58+ *
59+ * \param [in] event The event
60+ * \return The associated MirSurfaceOutputEvent
61+ */
62+MirSurfaceOutputEvent const* mir_event_get_surface_output_event(MirEvent const* ev);
63+
64 /*
65 *
66 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
67
68=== added file 'include/client/mir_toolkit/events/surface_output_event.h'
69--- include/client/mir_toolkit/events/surface_output_event.h 1970-01-01 00:00:00 +0000
70+++ include/client/mir_toolkit/events/surface_output_event.h 2015-10-07 06:10:46 +0000
71@@ -0,0 +1,61 @@
72+/*
73+ * Copyright © 2015 Canonical Ltd.
74+ *
75+ * This program is free software: you can redistribute it and/or modify it
76+ * under the terms of the GNU Lesser General Public License version 3,
77+ * as published by the Free Software Foundation.
78+ *
79+ * This program is distributed in the hope that it will be useful,
80+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
81+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
82+ * GNU Lesser General Public License for more details.
83+ *
84+ * You should have received a copy of the GNU Lesser General Public License
85+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
86+ *
87+ * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
88+ */
89+
90+#ifndef MIR_TOOLKIT_SURFACE_OUTPUT_EVENT_H_
91+#define MIR_TOOLKIT_SURFACE_OUTPUT_EVENT_H_
92+
93+#include <mir_toolkit/events/event.h>
94+
95+#ifdef __cplusplus
96+/**
97+ * \addtogroup mir_toolkit
98+ * @{
99+ */
100+extern "C" {
101+#endif
102+
103+/**
104+ * Retrieve the DPI of the new output configuration of a MirSurfaceOutputEvent
105+ *
106+ * \param [in] ev The event
107+ * \return The new DPI value for the surface is primarily on.
108+ */
109+int mir_surface_output_event_get_dpi(MirSurfaceOutputEvent const* ev);
110+
111+/**
112+ * Retrieve the form factor of the new output configuration of a MirSurfaceOutputEvent
113+ *
114+ * \param [in] ev The event
115+ * \return The new form factor of the output the surface is primarily on.
116+ */
117+MirFormFactor mir_surface_output_event_get_form_factor(MirSurfaceOutputEvent const* ev);
118+
119+/**
120+ * Retrieve the form factor of the new output configuration of a MirSurfaceOutputEvent
121+ *
122+ * \param [in] ev The event
123+ * \return The new form factor of the output the surface is primarily on.
124+ */
125+float mir_surface_output_event_get_scale(MirSurfaceOutputEvent const* ev);
126+
127+#ifdef __cplusplus
128+}
129+/**@}*/
130+#endif
131+
132+#endif //MIR_TOOLKIT_SURFACE_OUTPUT_EVENT_H_
133
134=== modified file 'include/common/mir_toolkit/common.h'
135--- include/common/mir_toolkit/common.h 2015-09-18 12:07:07 +0000
136+++ include/common/mir_toolkit/common.h 2015-10-07 06:10:46 +0000
137@@ -190,6 +190,20 @@
138 mir_edge_attachment_any = mir_edge_attachment_vertical |
139 mir_edge_attachment_horizontal
140 } MirEdgeAttachment;
141+
142+/**
143+ * Form factor associated with a physical output
144+ */
145+typedef enum MirFormFactor
146+{
147+ mir_form_factor_unknown,
148+ mir_form_factor_phone,
149+ mir_form_factor_tablet,
150+ mir_form_factor_monitor,
151+ mir_form_factor_tv,
152+ mir_form_factor_projector,
153+} MirFormFactor;
154+
155 /**@}*/
156
157 #endif
158
159=== modified file 'include/platform/mir/graphics/display_configuration.h'
160--- include/platform/mir/graphics/display_configuration.h 2015-02-22 07:46:25 +0000
161+++ include/platform/mir/graphics/display_configuration.h 2015-10-07 06:10:46 +0000
162@@ -93,7 +93,7 @@
163 /** The modes supported by the output. */
164 std::vector<DisplayConfigurationMode> modes;
165 /** The index in the 'modes' vector of the preferred output mode. */
166- size_t preferred_mode_index;
167+ uint32_t preferred_mode_index;
168 /** The physical size of the output. */
169 geometry::Size physical_size_mm;
170 /** Whether the output is connected. */
171@@ -103,13 +103,18 @@
172 /** The top left point of this output in the virtual coordinate space. */
173 geometry::Point top_left;
174 /** The index in the 'modes' vector of the current output mode. */
175- size_t current_mode_index;
176+ uint32_t current_mode_index;
177 /** The current output pixel format. A matching entry should be found in the 'pixel_formats' vector*/
178 MirPixelFormat current_format;
179 /** Current power mode **/
180 MirPowerMode power_mode;
181 MirOrientation orientation;
182
183+ /** Requested scale factor for this output, for HiDPI support */
184+ float scale;
185+ /** Form factor of this output; phone display, tablet, monitor, TV, projector... */
186+ MirFormFactor form_factor;
187+
188 /** The logical rectangle occupied by the output, based on its position,
189 current mode and orientation (rotation) */
190 geometry::Rectangle extents() const;
191@@ -127,15 +132,17 @@
192 DisplayConfigurationOutputType const& type;
193 std::vector<MirPixelFormat> const& pixel_formats;
194 std::vector<DisplayConfigurationMode> const& modes;
195- size_t const& preferred_mode_index;
196+ uint32_t const& preferred_mode_index;
197 geometry::Size const& physical_size_mm;
198 bool const& connected;
199 bool& used;
200 geometry::Point& top_left;
201- size_t& current_mode_index;
202+ uint32_t& current_mode_index;
203 MirPixelFormat& current_format;
204 MirPowerMode& power_mode;
205 MirOrientation& orientation;
206+ float& scale;
207+ MirFormFactor& form_factor;
208
209 UserDisplayConfigurationOutput(DisplayConfigurationOutput& master);
210 geometry::Rectangle extents() const;
211@@ -174,6 +181,8 @@
212 DisplayConfiguration& operator=(DisplayConfiguration const& c) = delete;
213 };
214
215+std::ostream& operator<<(std::ostream& out, DisplayConfiguration const& val);
216+
217 }
218 }
219
220
221=== modified file 'include/test/mir/test/doubles/stub_display_configuration.h'
222--- include/test/mir/test/doubles/stub_display_configuration.h 2015-09-30 07:19:48 +0000
223+++ include/test/mir/test/doubles/stub_display_configuration.h 2015-10-07 06:10:46 +0000
224@@ -56,7 +56,9 @@
225 0,
226 format,
227 mir_power_mode_on,
228- mir_orientation_normal
229+ mir_orientation_normal,
230+ 1.0f,
231+ mir_form_factor_monitor
232 }
233 {
234 }
235@@ -119,6 +121,12 @@
236 {
237 std::vector<graphics::DisplayConfigurationMode> modes;
238
239+ // Every second output, starting with the first, is connected...
240+ // (Android tests assume the first output in a configuration is connected)
241+ auto const connected = [](int index) { return (index % 2) == 0; };
242+ // ..and every second connected output is used...
243+ auto const used = [](int index) { return (index % 4) == 0; };
244+
245 for (auto j = 0u; j <= i; j++)
246 {
247 geometry::Size sz{mode_index*4, mode_index*3};
248@@ -127,21 +135,37 @@
249 modes.push_back(mode);
250 }
251
252- size_t mode_index = modes.size() - 1;
253+ uint32_t current_mode_index;
254+ uint32_t preferred_mode_index;
255+ if (connected(i))
256+ {
257+ current_mode_index = modes.size() - 1;
258+ preferred_mode_index = i;
259+ }
260+ else
261+ {
262+ current_mode_index = std::numeric_limits<uint32_t>::max();
263+ preferred_mode_index = std::numeric_limits<uint32_t>::max();
264+ }
265+
266 geometry::Size physical_size{};
267 geometry::Point top_left{};
268 graphics::DisplayConfigurationOutput output{
269 graphics::DisplayConfigurationOutputId{static_cast<int>(i + 1)},
270 graphics::DisplayConfigurationCardId{static_cast<int>(i)},
271 graphics::DisplayConfigurationOutputType::vga,
272- pfs, modes, i,
273+ pfs,
274+ connected(i) ? modes : std::vector<graphics::DisplayConfigurationMode>{},
275+ preferred_mode_index,
276 physical_size,
277- ((i % 2) == 0), // even numbers have connected==true
278- ((i % 4) == 0), // only every second even has used==true
279+ connected(i),
280+ used(i),
281 top_left,
282- mode_index, pfs[0],
283- mir_power_mode_off,
284- mir_orientation_normal
285+ current_mode_index, pfs[0],
286+ used(i) ? mir_power_mode_on : mir_power_mode_off,
287+ mir_orientation_normal,
288+ 1.0f,
289+ mir_form_factor_monitor
290 };
291
292 outputs.push_back(output);
293@@ -170,7 +194,9 @@
294 {{rect.size, 60.0}},
295 0, geometry::Size{}, true, true, rect.top_left, 0,
296 mir_pixel_format_abgr_8888, mir_power_mode_on,
297- mir_orientation_normal
298+ mir_orientation_normal,
299+ 1.0f,
300+ mir_form_factor_monitor
301 };
302
303 outputs.push_back(output);
304@@ -185,6 +211,22 @@
305 cards.push_back(card);
306 }
307
308+ StubDisplayConfig(std::vector<graphics::DisplayConfigurationOutput> const& outputs)
309+ {
310+ graphics::DisplayConfigurationCard card{
311+ graphics::DisplayConfigurationCardId{static_cast<int>(1)},
312+ outputs.size()
313+ };
314+
315+ cards.push_back(card);
316+ this->outputs = outputs;
317+
318+ for (auto& output : this->outputs)
319+ {
320+ output.card_id = cards[0].id;
321+ }
322+ }
323+
324 void for_each_card(std::function<void(graphics::DisplayConfigurationCard const&)> f) const override
325 {
326 for (auto const& card : cards)
327
328=== modified file 'include/test/mir/test/empty_deleter.h'
329--- include/test/mir/test/empty_deleter.h 2015-06-22 03:04:56 +0000
330+++ include/test/mir/test/empty_deleter.h 2015-10-07 06:10:46 +0000
331@@ -23,7 +23,7 @@
332 {
333 struct EmptyDeleter
334 {
335- void operator()(void* )
336+ void operator()(void const* )
337 {
338 }
339 };
340
341=== modified file 'src/client/CMakeLists.txt'
342--- src/client/CMakeLists.txt 2015-09-09 13:22:49 +0000
343+++ src/client/CMakeLists.txt 2015-10-07 06:10:46 +0000
344@@ -72,6 +72,7 @@
345 mir_buffer_stream_api.cpp
346 default_client_buffer_stream_factory.cpp
347 ${MIR_CLIENT_SOURCES}
348+ ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/events/surface_output_event.h
349 )
350
351 # Ensure protobuf C++ headers have been produced before
352
353=== modified file 'src/client/event.cpp'
354--- src/client/event.cpp 2015-06-17 05:20:42 +0000
355+++ src/client/event.cpp 2015-10-07 06:10:46 +0000
356@@ -147,6 +147,13 @@
357 return &ev->input_configuration;
358 }
359
360+MirSurfaceOutputEvent const* mir_event_get_surface_output_event(MirEvent const* ev)
361+{
362+ expect_event_type(ev, mir_event_type_surface_output);
363+
364+ return &ev->surface_output;
365+}
366+
367 /* Surface event accessors */
368
369 MirSurfaceAttrib mir_surface_event_get_attribute(MirSurfaceEvent const* ev)
370@@ -221,6 +228,26 @@
371 return ev->id;
372 }
373
374+/* Surface output event accessors */
375+
376+int mir_surface_output_event_get_dpi(MirSurfaceOutputEvent const* ev)
377+{
378+ expect_event_type(ev, mir_event_type_surface_output);
379+ return ev->dpi;
380+}
381+
382+MirFormFactor mir_surface_output_event_get_form_factor(MirSurfaceOutputEvent const* ev)
383+{
384+ expect_event_type(ev, mir_event_type_surface_output);
385+ return ev->form_factor;
386+}
387+
388+float mir_surface_output_event_get_scale(MirSurfaceOutputEvent const* ev)
389+{
390+ expect_event_type(ev, mir_event_type_surface_output);
391+ return ev->scale;
392+}
393+
394 // TODO: Until we opaquify the MirEvent structure and add
395 // a ref count ref is implemented as copy.
396 MirEvent const* mir_event_ref(MirEvent const* ev)
397
398=== modified file 'src/client/events/event_builders.cpp'
399--- src/client/events/event_builders.cpp 2015-09-24 15:42:21 +0000
400+++ src/client/events/event_builders.cpp 2015-10-07 06:10:46 +0000
401@@ -95,6 +95,24 @@
402 return make_event_uptr(e);
403 }
404
405+mir::EventUPtr mev::make_event(
406+ mf::SurfaceId const& surface_id,
407+ int dpi,
408+ float scale,
409+ MirFormFactor form_factor)
410+{
411+ auto e = new MirEvent;
412+ memset(e, 0, sizeof(*e));
413+
414+ e->type = mir_event_type_surface_output;
415+ e->surface_output.surface_id = surface_id.as_value();
416+ e->surface_output.dpi = dpi;
417+ e->surface_output.scale = scale;
418+ e->surface_output.form_factor = form_factor;
419+
420+ return make_event_uptr(e);
421+}
422+
423 namespace
424 {
425 // Never exposed in old event, so lets avoid leaking it in to a header now.
426
427=== modified file 'src/client/rpc/mir_protobuf_rpc_channel.cpp'
428--- src/client/rpc/mir_protobuf_rpc_channel.cpp 2015-09-17 20:32:32 +0000
429+++ src/client/rpc/mir_protobuf_rpc_channel.cpp 2015-10-07 06:10:46 +0000
430@@ -324,6 +324,9 @@
431 case mir_event_type_keymap:
432 surface_map->with_surface_do(mf::SurfaceId(e.keymap.surface_id), send_e);
433 break;
434+ case mir_event_type_surface_output:
435+ surface_map->with_surface_do(mf::SurfaceId(e.surface_output.surface_id), send_e);
436+ break;
437 default:
438 event_sink->handle_event(e);
439 }
440
441=== modified file 'src/client/symbols.map'
442--- src/client/symbols.map 2015-09-21 11:31:49 +0000
443+++ src/client/symbols.map 2015-10-07 06:10:46 +0000
444@@ -192,6 +192,10 @@
445 mir_blob_release;
446 mir_buffer_stream_set_scale;
447 mir_buffer_stream_set_scale_sync;
448+ mir_event_get_surface_output_event;
449+ mir_surface_output_event_get_dpi;
450+ mir_surface_output_event_get_form_factor;
451+ mir_surface_output_event_get_scale;
452 } MIR_CLIENT_9.2;
453
454 MIR_CLIENT_DETAIL_9 {
455
456=== modified file 'src/include/common/mir/events/event_private.h'
457--- src/include/common/mir/events/event_private.h 2015-08-17 18:33:38 +0000
458+++ src/include/common/mir/events/event_private.h 2015-10-07 06:10:46 +0000
459@@ -164,6 +164,16 @@
460 struct xkb_rule_names rules;
461 };
462
463+struct MirSurfaceOutputEvent
464+{
465+ MirEventType type;
466+
467+ int surface_id;
468+ int dpi;
469+ float scale;
470+ MirFormFactor form_factor;
471+};
472+
473 // Access to MirEvent is deprecated
474 union MirEvent
475 {
476@@ -177,6 +187,7 @@
477 MirCloseSurfaceEvent close_surface;
478 MirKeymapEvent keymap;
479 MirInputConfigurationEvent input_configuration;
480+ MirSurfaceOutputEvent surface_output;
481 };
482
483 #ifdef __cplusplus
484
485=== modified file 'src/include/server/mir/scene/surface_event_source.h'
486--- src/include/server/mir/scene/surface_event_source.h 2015-04-28 07:54:10 +0000
487+++ src/include/server/mir/scene/surface_event_source.h 2015-10-07 06:10:46 +0000
488@@ -29,21 +29,31 @@
489 {
490 namespace scene
491 {
492+class Surface;
493+class OutputProperties;
494+class OutputPropertiesCache;
495+
496 class SurfaceEventSource : public NullSurfaceObserver
497 {
498 public:
499 SurfaceEventSource(
500 frontend::SurfaceId id,
501+ Surface const& surface,
502+ OutputPropertiesCache const& outputs,
503 std::shared_ptr<frontend::EventSink> const& event_sink);
504
505 void attrib_changed(MirSurfaceAttrib attrib, int value) override;
506 void resized_to(geometry::Size const& size) override;
507+ void moved_to(geometry::Point const& top_left) override;
508 void orientation_set_to(MirOrientation orientation) override;
509 void client_surface_close_requested() override;
510 void keymap_changed(xkb_rule_names const& names) override;
511
512 private:
513 frontend::SurfaceId const id;
514+ Surface const& surface;
515+ OutputPropertiesCache const& outputs;
516+ std::weak_ptr<OutputProperties const> last_output;
517 std::shared_ptr<frontend::EventSink> const event_sink;
518 };
519 }
520
521=== modified file 'src/platform/graphics/display_configuration.cpp'
522--- src/platform/graphics/display_configuration.cpp 2015-02-22 07:46:25 +0000
523+++ src/platform/graphics/display_configuration.cpp 2015-10-07 06:10:46 +0000
524@@ -95,11 +95,33 @@
525 return out << val.size.width << "x" << val.size.height << "@" << val.vrefresh_hz;
526 }
527
528+namespace
529+{
530+char const* as_string(MirFormFactor form_factor)
531+{
532+ switch (form_factor)
533+ {
534+ case mir_form_factor_monitor:
535+ return "monitor";
536+ case mir_form_factor_projector:
537+ return "projector";
538+ case mir_form_factor_tv:
539+ return "TV";
540+ case mir_form_factor_phone:
541+ return "phone";
542+ case mir_form_factor_tablet:
543+ return "tablet";
544+ default:
545+ return "UNKNOWN";
546+ }
547+}
548+}
549+
550 std::ostream& mg::operator<<(std::ostream& out, mg::DisplayConfigurationOutput const& val)
551 {
552- out << "{ id: " << val.id << ", card_id: " << val.card_id
553- << " type: " << output_type_to_string(val.type)
554- << " modes: [";
555+ out << "{\n\tid: " << val.id << "\n\tcard_id: " << val.card_id
556+ << "\n\ttype: " << output_type_to_string(val.type)
557+ << "\n\tmodes: [ ";
558
559 for (size_t i = 0; i < val.modes.size(); ++i)
560 {
561@@ -108,18 +130,30 @@
562 out << ", ";
563 }
564
565- out << "], preferred_mode: " << val.preferred_mode_index;
566- out << " physical_size_mm: " << val.physical_size_mm.width << "x" << val.physical_size_mm.height;
567- out << ", connected: " << (val.connected ? "true" : "false");
568- out << ", used: " << (val.used ? "true" : "false");
569- out << ", top_left: " << val.top_left;
570- out << ", current_mode: " << val.current_mode_index << " (";
571+ out << "]" << std::endl;
572+ out << "\tpreferred_mode: " << val.preferred_mode_index << std::endl;
573+ out << "\tphysical_size_mm: " << val.physical_size_mm.width << "x" << val.physical_size_mm.height << std::endl;
574+ out << "\tconnected: " << (val.connected ? "true" : "false") << std::endl;
575+ out << "\tused: " << (val.used ? "true" : "false") << std::endl;
576+ out << "\ttop_left: " << val.top_left << std::endl;
577+ out << "\tcurrent_mode: " << val.current_mode_index << " (";
578 if (val.current_mode_index < val.modes.size())
579 out << val.modes[val.current_mode_index];
580 else
581 out << "none";
582-
583- out << ") }";
584+ out << ")" << std::endl;
585+
586+ out << "\tscale: " << val.scale << std::endl;
587+ out << "\tform factor: " << as_string(val.form_factor) << std::endl;
588+ out << "}" << std::endl;
589+
590+ return out;
591+}
592+
593+std::ostream& mg::operator<<(std::ostream& out, mg::DisplayConfiguration const& val)
594+{
595+ val.for_each_card([&out](auto card) { out << card << std::endl; });
596+ val.for_each_output([&out](DisplayConfigurationOutput const& output) { out << output << std::endl; });
597
598 return out;
599 }
600@@ -163,7 +197,9 @@
601 (val1.top_left == val2.top_left) &&
602 (val1.orientation == val2.orientation) &&
603 (val1.current_mode_index == val2.current_mode_index) &&
604- (val1.modes.size() == val2.modes.size())};
605+ (val1.modes.size() == val2.modes.size()) &&
606+ (val1.scale == val2.scale) &&
607+ (val1.form_factor == val2.form_factor)};
608
609 if (equal)
610 {
611@@ -259,7 +295,9 @@
612 current_mode_index(master.current_mode_index),
613 current_format(master.current_format),
614 power_mode(master.power_mode),
615- orientation(master.orientation)
616+ orientation(master.orientation),
617+ scale(master.scale),
618+ form_factor(master.form_factor)
619 {
620 }
621
622
623=== modified file 'src/platforms/android/server/fb_device.cpp'
624--- src/platforms/android/server/fb_device.cpp 2015-09-17 20:32:32 +0000
625+++ src/platforms/android/server/fb_device.cpp 2015-10-07 06:10:46 +0000
626@@ -73,7 +73,9 @@
627 0,
628 mga::to_mir_format(fb_device->format),
629 mir_power_mode_on,
630- mir_orientation_normal
631+ mir_orientation_normal,
632+ 1.0f,
633+ mir_form_factor_phone
634 };
635 }
636
637
638=== modified file 'src/platforms/android/server/hwc_blanking_control.cpp'
639--- src/platforms/android/server/hwc_blanking_control.cpp 2015-07-21 04:30:03 +0000
640+++ src/platforms/android/server/hwc_blanking_control.cpp 2015-10-07 06:10:46 +0000
641@@ -131,8 +131,12 @@
642 external_modes.emplace_back(mg::DisplayConfigurationMode{pixel_size, vrefresh_hz});
643
644 auto type = mg::DisplayConfigurationOutputType::lvds;
645+ auto form_factor = mir_form_factor_phone;
646 if (name == mga::DisplayName::external)
647+ {
648 type = mg::DisplayConfigurationOutputType::displayport;
649+ form_factor = mir_form_factor_monitor;
650+ }
651
652 return {
653 static_cast<mg::DisplayConfigurationOutputId>(name),
654@@ -148,7 +152,9 @@
655 preferred_format_index,
656 display_format,
657 external_mode,
658- mir_orientation_normal
659+ mir_orientation_normal,
660+ 1.0f,
661+ form_factor
662 };
663 }
664
665
666=== modified file 'src/platforms/mesa/server/kms/real_kms_display_configuration.cpp'
667--- src/platforms/mesa/server/kms/real_kms_display_configuration.cpp 2015-07-23 02:39:20 +0000
668+++ src/platforms/mesa/server/kms/real_kms_display_configuration.cpp 2015-10-07 06:10:46 +0000
669@@ -171,9 +171,9 @@
670 kms_connector_type_to_output_type(connector.connector_type)};
671 geom::Size physical_size{connector.mmWidth, connector.mmHeight};
672 bool connected{connector.connection == DRM_MODE_CONNECTED};
673- size_t const invalid_mode_index = std::numeric_limits<size_t>::max();
674- size_t current_mode_index{invalid_mode_index};
675- size_t preferred_mode_index{invalid_mode_index};
676+ uint32_t const invalid_mode_index = std::numeric_limits<uint32_t>::max();
677+ uint32_t current_mode_index{invalid_mode_index};
678+ uint32_t preferred_mode_index{invalid_mode_index};
679 std::vector<DisplayConfigurationMode> modes;
680 std::vector<MirPixelFormat> formats {mir_pixel_format_argb_8888,
681 mir_pixel_format_xrgb_8888};
682@@ -215,7 +215,8 @@
683 outputs.push_back({id, card_id, type, formats, modes, preferred_mode_index,
684 physical_size, connected, false, geom::Point(),
685 current_mode_index, mir_pixel_format_xrgb_8888,
686- mir_power_mode_on, mir_orientation_normal});
687+ mir_power_mode_on, mir_orientation_normal,
688+ 1.0f, mir_form_factor_monitor});
689 }
690 else
691 {
692
693=== modified file 'src/platforms/mesa/server/x11/graphics/display_configuration.cpp'
694--- src/platforms/mesa/server/x11/graphics/display_configuration.cpp 2015-09-10 22:53:53 +0000
695+++ src/platforms/mesa/server/x11/graphics/display_configuration.cpp 2015-10-07 06:10:46 +0000
696@@ -41,7 +41,9 @@
697 0,
698 pf,
699 mir_power_mode_on,
700- orientation},
701+ orientation,
702+ 1.0f,
703+ mir_form_factor_monitor},
704 card{mg::DisplayConfigurationCardId{0}, 1}
705 {
706 }
707
708=== modified file 'src/server/graphics/nested/nested_display_configuration.cpp'
709--- src/server/graphics/nested/nested_display_configuration.cpp 2015-09-08 13:58:20 +0000
710+++ src/server/graphics/nested/nested_display_configuration.cpp 2015-10-07 06:10:46 +0000
711@@ -79,7 +79,9 @@
712 mir_output.current_mode,
713 mir_output.current_format,
714 mir_output.power_mode,
715- mir_output.orientation
716+ mir_output.orientation,
717+ 1.0f,
718+ mir_form_factor_monitor
719 };
720
721 f(output);
722@@ -133,7 +135,9 @@
723 mir_output.current_mode,
724 mir_output.current_format,
725 mir_output.power_mode,
726- mir_output.orientation
727+ mir_output.orientation,
728+ 1.0f,
729+ mir_form_factor_monitor
730 };
731 UserDisplayConfigurationOutput user(output);
732
733
734=== modified file 'src/server/graphics/offscreen/display_configuration.cpp'
735--- src/server/graphics/offscreen/display_configuration.cpp 2015-02-22 07:46:25 +0000
736+++ src/server/graphics/offscreen/display_configuration.cpp 2015-10-07 06:10:46 +0000
737@@ -34,7 +34,9 @@
738 0,
739 mir_pixel_format_xrgb_8888,
740 mir_power_mode_on,
741- mir_orientation_normal},
742+ mir_orientation_normal,
743+ 1.0f,
744+ mir_form_factor_monitor},
745 card{mg::DisplayConfigurationCardId{0}, 1}
746 {
747 }
748
749=== modified file 'src/server/scene/CMakeLists.txt'
750--- src/server/scene/CMakeLists.txt 2015-09-15 17:13:45 +0000
751+++ src/server/scene/CMakeLists.txt 2015-10-07 06:10:46 +0000
752@@ -30,4 +30,6 @@
753 rendering_tracker.cpp
754 default_coordinate_translator.cpp
755 timeout_application_not_responding_detector.cpp
756+ output_properties_cache.cpp
757+ output_properties_cache.h
758 )
759
760=== modified file 'src/server/scene/application_session.cpp'
761--- src/server/scene/application_session.cpp 2015-09-24 00:35:49 +0000
762+++ src/server/scene/application_session.cpp 2015-10-07 06:10:46 +0000
763@@ -19,6 +19,7 @@
764 #include "application_session.h"
765 #include "snapshot_strategy.h"
766 #include "default_session_container.h"
767+#include "output_properties_cache.h"
768
769 #include "mir/scene/surface.h"
770 #include "mir/scene/surface_event_source.h"
771@@ -53,6 +54,7 @@
772 std::string const& session_name,
773 std::shared_ptr<SnapshotStrategy> const& snapshot_strategy,
774 std::shared_ptr<SessionListener> const& session_listener,
775+ mg::DisplayConfiguration const& initial_config,
776 std::shared_ptr<mf::EventSink> const& sink) :
777 surface_coordinator(surface_coordinator),
778 surface_factory(surface_factory),
779@@ -65,6 +67,7 @@
780 next_surface_id(0)
781 {
782 assert(surface_coordinator);
783+ output_cache.update_from(initial_config);
784 }
785
786 ms::ApplicationSession::~ApplicationSession()
787@@ -95,8 +98,6 @@
788 if (params.parent_id.is_set())
789 params.parent = checked_find(the_params.parent_id.value())->second;
790
791- auto const observer = std::make_shared<scene::SurfaceEventSource>(id, surface_sink);
792-
793 std::shared_ptr<compositor::BufferStream> buffer_stream;
794 if (params.content_id.is_set())
795 {
796@@ -108,7 +109,7 @@
797 params.pixel_format,
798 params.buffer_usage};
799 buffer_stream = buffer_stream_factory->create_buffer_stream(
800- stream_id, event_sink, buffer_properties);
801+ stream_id, surface_sink, buffer_properties);
802 }
803 auto surface = surface_factory->create_surface(buffer_stream, params);
804 surface_coordinator->add_surface(surface, params.depth, params.input_mode, this);
805@@ -122,6 +123,11 @@
806 if (params.input_shape.is_set())
807 surface->set_input_region(params.input_shape.value());
808
809+ auto const observer = std::make_shared<scene::SurfaceEventSource>(
810+ id,
811+ *surface,
812+ output_cache,
813+ surface_sink);
814 surface->add_observer(observer);
815
816 {
817@@ -130,6 +136,8 @@
818 streams[stream_id] = buffer_stream;
819 }
820
821+ observer->moved_to(surface->top_left());
822+
823 session_listener->surface_created(*this, surface);
824 return id;
825 }
826@@ -287,6 +295,26 @@
827 void ms::ApplicationSession::send_display_config(mg::DisplayConfiguration const& info)
828 {
829 event_sink->handle_display_config_change(info);
830+
831+ output_cache.update_from(info);
832+
833+ std::lock_guard<std::mutex> lock{surfaces_and_streams_mutex};
834+ for (auto& surface : surfaces)
835+ {
836+ auto output_properties = output_cache.properties_for(geometry::Rectangle{
837+ surface.second->top_left(),
838+ surface.second->size()});
839+
840+ if (output_properties)
841+ {
842+ event_sink->handle_event(
843+ *mev::make_event(
844+ surface.first,
845+ output_properties->dpi,
846+ output_properties->scale,
847+ output_properties->form_factor));
848+ }
849+ }
850 }
851
852 void ms::ApplicationSession::set_lifecycle_state(MirLifecycleState state)
853
854=== modified file 'src/server/scene/application_session.h'
855--- src/server/scene/application_session.h 2015-09-24 00:35:49 +0000
856+++ src/server/scene/application_session.h 2015-10-07 06:10:46 +0000
857@@ -21,6 +21,8 @@
858
859 #include "mir/scene/session.h"
860
861+#include "output_properties_cache.h"
862+
863 #include <atomic>
864 #include <map>
865 #include <mutex>
866@@ -32,6 +34,10 @@
867 class EventSink;
868 }
869 namespace compositor { class BufferStream; }
870+namespace graphics
871+{
872+class DisplayConfiguration;
873+}
874 namespace scene
875 {
876 class SessionListener;
877@@ -52,6 +58,7 @@
878 std::string const& session_name,
879 std::shared_ptr<SnapshotStrategy> const& snapshot_strategy,
880 std::shared_ptr<SessionListener> const& session_listener,
881+ graphics::DisplayConfiguration const& initial_config,
882 std::shared_ptr<frontend::EventSink> const& sink);
883
884 ~ApplicationSession();
885@@ -107,6 +114,8 @@
886
887 std::atomic<int> next_surface_id;
888
889+ OutputPropertiesCache output_cache;
890+
891 typedef std::map<frontend::SurfaceId, std::shared_ptr<Surface>> Surfaces;
892 typedef std::map<frontend::BufferStreamId, std::shared_ptr<compositor::BufferStream>> Streams;
893 Surfaces::const_iterator checked_find(frontend::SurfaceId id) const;
894
895=== modified file 'src/server/scene/default_configuration.cpp'
896--- src/server/scene/default_configuration.cpp 2015-09-30 07:19:48 +0000
897+++ src/server/scene/default_configuration.cpp 2015-10-07 06:10:46 +0000
898@@ -42,11 +42,14 @@
899 #include "timeout_application_not_responding_detector.h"
900 #include "mir/options/program_option.h"
901 #include "mir/options/default_configuration.h"
902+#include "mir/graphics/display_configuration.h"
903+#include "mir/frontend/display_changer.h"
904
905 namespace mc = mir::compositor;
906 namespace mf = mir::frontend;
907 namespace mi = mir::input;
908 namespace ms = mir::scene;
909+namespace mg = mir::graphics;
910 namespace msh = mir::shell;
911
912 std::shared_ptr<ms::SurfaceStackModel>
913@@ -178,6 +181,7 @@
914 the_snapshot_strategy(),
915 the_session_event_sink(),
916 the_session_listener(),
917+ the_display(),
918 the_application_not_responding_detector());
919 });
920 }
921
922=== added file 'src/server/scene/output_properties_cache.cpp'
923--- src/server/scene/output_properties_cache.cpp 1970-01-01 00:00:00 +0000
924+++ src/server/scene/output_properties_cache.cpp 2015-10-07 06:10:46 +0000
925@@ -0,0 +1,100 @@
926+/*
927+ * Copyright © 2015 Canonical Ltd.
928+ *
929+ * This program is free software: you can redistribute it and/or modify it
930+ * under the terms of the GNU General Public License version 3,
931+ * as published by the Free Software Foundation.
932+ *
933+ * This program is distributed in the hope that it will be useful,
934+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
935+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
936+ * GNU General Public License for more details.
937+ *
938+ * You should have received a copy of the GNU General Public License
939+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
940+ *
941+ * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
942+ */
943+
944+#include "output_properties_cache.h"
945+
946+#include "mir/geometry/rectangle.h"
947+#include "mir/graphics/display_configuration.h"
948+
949+#include <atomic>
950+#include <cmath>
951+
952+namespace ms = mir::scene;
953+namespace mg = mir::graphics;
954+namespace geom = mir::geometry;
955+
956+namespace
957+{
958+int calculate_dpi(mir::geometry::Size const& resolution, mir::geometry::Size const& size)
959+{
960+ float constexpr mm_per_inch = 25.4f;
961+
962+ auto diagonal_mm = sqrt(size.height.as_int()*size.height.as_int()
963+ + size.width.as_int()*size.width.as_int());
964+ auto diagonal_px = sqrt(resolution.height.as_int() * resolution.height.as_int()
965+ + resolution.width.as_int() * resolution.width.as_int());
966+
967+ return diagonal_px / diagonal_mm * mm_per_inch;
968+}
969+}
970+
971+void ms::OutputPropertiesCache::update_from(mg::DisplayConfiguration const &config)
972+{
973+ auto new_properties = std::make_shared<std::vector<OutputProperties>>();
974+
975+ config.for_each_output(
976+ [&new_properties](auto output)
977+ {
978+ if (output.current_mode_index < output.modes.size())
979+ {
980+ auto const mode = output.modes[output.current_mode_index];
981+ new_properties->emplace_back(OutputProperties {
982+ output.extents(),
983+ calculate_dpi(mode.size, output.physical_size_mm),
984+ output.scale,
985+ output.form_factor});
986+ }
987+ });
988+
989+ std::lock_guard<std::mutex> lk(mutex);
990+ cache = new_properties;
991+}
992+
993+auto ms::OutputPropertiesCache::get_cache() const
994+ -> std::shared_ptr<std::vector<OutputProperties>>
995+{
996+ std::lock_guard<std::mutex> lk(mutex);
997+ return cache;
998+}
999+
1000+auto ms::OutputPropertiesCache::properties_for(geom::Rectangle const& extents) const
1001+ -> std::shared_ptr<OutputProperties const>
1002+{
1003+ auto temp_properties = get_cache();
1004+
1005+ std::shared_ptr<OutputProperties const> matching_output_properties{};
1006+ if (temp_properties)
1007+ {
1008+ for (auto const &output : *temp_properties)
1009+ {
1010+ if (output.extents.overlaps(extents))
1011+ {
1012+ if (!matching_output_properties ||
1013+ (output.scale > matching_output_properties->scale))
1014+ {
1015+ matching_output_properties = std::shared_ptr<OutputProperties const>(
1016+ temp_properties,
1017+ &output
1018+ );
1019+ }
1020+ }
1021+ }
1022+ }
1023+
1024+ return matching_output_properties;
1025+}
1026
1027=== added file 'src/server/scene/output_properties_cache.h'
1028--- src/server/scene/output_properties_cache.h 1970-01-01 00:00:00 +0000
1029+++ src/server/scene/output_properties_cache.h 2015-10-07 06:10:46 +0000
1030@@ -0,0 +1,66 @@
1031+/*
1032+ * Copyright © 2015 Canonical Ltd.
1033+ *
1034+ * This program is free software: you can redistribute it and/or modify it
1035+ * under the terms of the GNU General Public License version 3,
1036+ * as published by the Free Software Foundation.
1037+ *
1038+ * This program is distributed in the hope that it will be useful,
1039+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1040+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1041+ * GNU General Public License for more details.
1042+ *
1043+ * You should have received a copy of the GNU General Public License
1044+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1045+ *
1046+ * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
1047+ */
1048+
1049+#ifndef MIR_SCENE_OUTPUT_PROPERTIES_CACHE_H_
1050+#define MIR_SCENE_OUTPUT_PROPERTIES_CACHE_H_
1051+
1052+#include "mir_toolkit/common.h"
1053+#include "mir/geometry/rectangle.h"
1054+
1055+#include <vector>
1056+#include <memory>
1057+#include <mutex>
1058+
1059+namespace mir
1060+{
1061+namespace graphics
1062+{
1063+class DisplayConfiguration;
1064+}
1065+
1066+namespace scene
1067+{
1068+struct OutputProperties
1069+{
1070+ geometry::Rectangle extents;
1071+ int dpi;
1072+ float scale;
1073+ MirFormFactor form_factor;
1074+};
1075+
1076+class OutputPropertiesCache
1077+{
1078+public:
1079+
1080+ void update_from(graphics::DisplayConfiguration const& config);
1081+
1082+ std::shared_ptr<OutputProperties const> properties_for(geometry::Rectangle const& extents) const;
1083+
1084+private:
1085+ std::shared_ptr<std::vector<OutputProperties>> get_cache() const;
1086+
1087+ std::mutex mutable mutex;
1088+ std::shared_ptr<std::vector<OutputProperties>> cache;
1089+};
1090+
1091+}
1092+}
1093+
1094+
1095+
1096+#endif //MIR_SCENE_OUTPUT_PROPERTIES_CACHE_H_
1097
1098=== modified file 'src/server/scene/session_manager.cpp'
1099--- src/server/scene/session_manager.cpp 2015-06-18 04:38:28 +0000
1100+++ src/server/scene/session_manager.cpp 2015-10-07 06:10:46 +0000
1101@@ -27,6 +27,8 @@
1102 #include "mir/scene/application_not_responding_detector.h"
1103 #include "session_event_sink.h"
1104 #include "mir/frontend/event_sink.h"
1105+#include "mir/graphics/display.h"
1106+#include "mir/graphics/display_configuration.h"
1107
1108 #include <boost/throw_exception.hpp>
1109
1110@@ -37,6 +39,7 @@
1111
1112 namespace mf = mir::frontend;
1113 namespace ms = mir::scene;
1114+namespace mg = mir::graphics;
1115 namespace msh = mir::shell;
1116
1117 ms::SessionManager::SessionManager(
1118@@ -47,6 +50,7 @@
1119 std::shared_ptr<SnapshotStrategy> const& snapshot_strategy,
1120 std::shared_ptr<SessionEventSink> const& session_event_sink,
1121 std::shared_ptr<SessionListener> const& session_listener,
1122+ std::shared_ptr<graphics::Display const> const& display,
1123 std::shared_ptr<ApplicationNotRespondingDetector> const& anr_detector) :
1124 surface_coordinator(surface_coordinator),
1125 surface_factory(surface_factory),
1126@@ -55,6 +59,7 @@
1127 snapshot_strategy(snapshot_strategy),
1128 session_event_sink(session_event_sink),
1129 session_listener(session_listener),
1130+ display{display},
1131 anr_detector{anr_detector}
1132 {
1133 }
1134@@ -84,11 +89,16 @@
1135 std::string const& name,
1136 std::shared_ptr<mf::EventSink> const& sender)
1137 {
1138- std::shared_ptr<Session> new_session =
1139- std::make_shared<ApplicationSession>(
1140- surface_coordinator, surface_factory,
1141- buffer_stream_factory, client_pid, name,
1142- snapshot_strategy, session_listener, sender);
1143+ std::shared_ptr<Session> new_session = std::make_shared<ApplicationSession>(
1144+ surface_coordinator,
1145+ surface_factory,
1146+ buffer_stream_factory,
1147+ client_pid,
1148+ name,
1149+ snapshot_strategy,
1150+ session_listener,
1151+ *display->configuration(),
1152+ sender);
1153
1154 app_container->insert_session(new_session);
1155
1156
1157=== modified file 'src/server/scene/session_manager.h'
1158--- src/server/scene/session_manager.h 2015-06-18 04:38:28 +0000
1159+++ src/server/scene/session_manager.h 2015-10-07 06:10:46 +0000
1160@@ -26,6 +26,12 @@
1161
1162 namespace mir
1163 {
1164+namespace graphics
1165+{
1166+class DisplayConfiguration;
1167+class Display;
1168+}
1169+
1170 namespace scene
1171 {
1172 class SessionContainer;
1173@@ -41,14 +47,17 @@
1174 class SessionManager : public SessionCoordinator
1175 {
1176 public:
1177- explicit SessionManager(std::shared_ptr<SurfaceCoordinator> const& surface_coordinator,
1178- std::shared_ptr<SurfaceFactory> const& surface_factory,
1179- std::shared_ptr<BufferStreamFactory> const& buffer_stream_factory,
1180- std::shared_ptr<SessionContainer> const& app_container,
1181- std::shared_ptr<SnapshotStrategy> const& snapshot_strategy,
1182- std::shared_ptr<SessionEventSink> const& session_event_sink,
1183- std::shared_ptr<SessionListener> const& session_listener,
1184- std::shared_ptr<ApplicationNotRespondingDetector> const& anr_detector);
1185+ SessionManager(
1186+ std::shared_ptr<SurfaceCoordinator> const& surface_coordinator,
1187+ std::shared_ptr<SurfaceFactory> const& surface_factory,
1188+ std::shared_ptr<BufferStreamFactory> const& buffer_stream_factory,
1189+ std::shared_ptr<SessionContainer> const& app_container,
1190+ std::shared_ptr<SnapshotStrategy> const& snapshot_strategy,
1191+ std::shared_ptr<SessionEventSink> const& session_event_sink,
1192+ std::shared_ptr<SessionListener> const& session_listener,
1193+ std::shared_ptr<graphics::Display const> const& display,
1194+ std::shared_ptr<ApplicationNotRespondingDetector> const& anr_detector);
1195+
1196 virtual ~SessionManager() noexcept;
1197
1198 std::shared_ptr<Session> open_session(
1199@@ -75,6 +84,7 @@
1200 std::shared_ptr<SnapshotStrategy> const snapshot_strategy;
1201 std::shared_ptr<SessionEventSink> const session_event_sink;
1202 std::shared_ptr<SessionListener> const session_listener;
1203+ std::shared_ptr<graphics::Display const> const display;
1204 std::shared_ptr<ApplicationNotRespondingDetector> const anr_detector;
1205 };
1206
1207
1208=== modified file 'src/server/scene/surface_event_source.cpp'
1209--- src/server/scene/surface_event_source.cpp 2015-04-28 07:54:10 +0000
1210+++ src/server/scene/surface_event_source.cpp 2015-10-07 06:10:46 +0000
1211@@ -18,8 +18,11 @@
1212
1213 #include "mir/events/event_builders.h"
1214 #include "mir/scene/surface_event_source.h"
1215+#include "mir/scene/surface.h"
1216+#include "output_properties_cache.h"
1217
1218 #include "mir/geometry/size.h"
1219+#include "mir/geometry/rectangle.h"
1220
1221 #include <cstring>
1222 #include <algorithm>
1223@@ -30,8 +33,12 @@
1224
1225 ms::SurfaceEventSource::SurfaceEventSource(
1226 frontend::SurfaceId id,
1227+ Surface const& surface,
1228+ OutputPropertiesCache const& outputs,
1229 std::shared_ptr<frontend::EventSink> const& event_sink) :
1230 id(id),
1231+ surface{surface},
1232+ outputs{outputs},
1233 event_sink(event_sink)
1234 {
1235 }
1236@@ -41,6 +48,19 @@
1237 event_sink->handle_event(*mev::make_event(id, size));
1238 }
1239
1240+void ms::SurfaceEventSource::moved_to(geom::Point const& top_left)
1241+{
1242+ auto new_output_properties = outputs.properties_for(geom::Rectangle{top_left, surface.size()});
1243+ if (new_output_properties && (new_output_properties != last_output.lock()))
1244+ {
1245+ event_sink->handle_event(*mev::make_event(
1246+ id,
1247+ new_output_properties->dpi,
1248+ new_output_properties->scale,
1249+ new_output_properties->form_factor));
1250+ last_output = new_output_properties;
1251+ }
1252+}
1253
1254 void ms::SurfaceEventSource::attrib_changed(MirSurfaceAttrib attrib, int value)
1255 {
1256
1257=== modified file 'tests/acceptance-tests/test_client_focus_notification.cpp'
1258--- tests/acceptance-tests/test_client_focus_notification.cpp 2015-07-27 10:26:01 +0000
1259+++ tests/acceptance-tests/test_client_focus_notification.cpp 2015-10-07 06:10:46 +0000
1260@@ -95,6 +95,7 @@
1261 run_in_client([&]
1262 {
1263 InSequence s;
1264+ EXPECT_CALL(observer, see(_)); //ignore scaling events
1265 EXPECT_CALL(observer, see(mt::SurfaceEvent(mir_surface_attrib_focus, mir_surface_focused))).Times(1)
1266 .WillOnce(mt::WakeUp(&all_events_received));
1267 // We may not see mir_surface_unfocused before connection closes
1268@@ -123,6 +124,7 @@
1269 auto const client_one = new_client_process([&]
1270 {
1271 InSequence seq;
1272+ EXPECT_CALL(observer, see(_)); //ignore scaling events
1273 // We should receive focus as we are created
1274 EXPECT_CALL(observer, see(mt::SurfaceEvent(mir_surface_attrib_focus,
1275 mir_surface_focused))).Times(1)
1276@@ -146,6 +148,7 @@
1277 client_one->detach();
1278 ready_for_second_client.wait_for_signal_ready_for();
1279
1280+ EXPECT_CALL(observer, see(_)); //ignore scaling events
1281 EXPECT_CALL(observer, see(
1282 mt::SurfaceEvent(mir_surface_attrib_focus, mir_surface_focused)))
1283 .Times(1).WillOnce(mt::WakeUp(&all_events_received));
1284
1285=== modified file 'tests/acceptance-tests/test_client_surface_events.cpp'
1286--- tests/acceptance-tests/test_client_surface_events.cpp 2015-09-24 00:44:01 +0000
1287+++ tests/acceptance-tests/test_client_surface_events.cpp 2015-10-07 06:10:46 +0000
1288@@ -21,6 +21,10 @@
1289 #include "mir/scene/surface.h"
1290 #include "mir/scene/surface_creation_parameters.h"
1291
1292+#include "mir/graphics/display.h"
1293+
1294+#include "mir/shell/display_configuration_controller.h"
1295+
1296 #include "mir/test/event_matchers.h"
1297 #include "mir/test/doubles/wrap_shell_to_track_latest_surface.h"
1298 #include "mir_test_framework/connected_client_with_a_surface.h"
1299@@ -40,6 +44,7 @@
1300 namespace mt = mir::test;
1301 namespace mtd = mir::test::doubles;
1302 namespace mtf = mir_test_framework;
1303+namespace mg = mir::graphics;
1304
1305 using namespace testing;
1306
1307@@ -254,6 +259,39 @@
1308 }
1309 }
1310
1311+TEST_F(ClientSurfaceEvents, surface_receives_output_event_when_configuration_changes)
1312+{
1313+ using namespace std::literals::chrono_literals;
1314+
1315+ auto constexpr form_factor = mir_form_factor_tablet;
1316+ float constexpr scale = 2.15f;
1317+
1318+ auto display_configuration = server.the_display()->configuration();
1319+
1320+ display_configuration->for_each_output(
1321+ [](mg::UserDisplayConfigurationOutput& output_config)
1322+ {
1323+ output_config.scale = scale;
1324+ output_config.form_factor = form_factor;
1325+ });
1326+
1327+ set_event_filter(mir_event_type_surface_output);
1328+ reset_last_event();
1329+
1330+ auto display_controller = server.the_display_configuration_controller();
1331+ display_controller->set_default_display_configuration(std::move(display_configuration)).get();
1332+
1333+ ASSERT_TRUE(wait_for_event(1min));
1334+
1335+ std::lock_guard<decltype(last_event_mutex)> last_event_lock{last_event_mutex};
1336+
1337+ EXPECT_THAT(mir_event_get_type(last_event), Eq(mir_event_type_surface_output));
1338+ auto output_event = mir_event_get_surface_output_event(last_event);
1339+
1340+ EXPECT_THAT(mir_surface_output_event_get_form_factor(output_event), Eq(form_factor));
1341+ EXPECT_THAT(mir_surface_output_event_get_scale(output_event), FloatEq(scale));
1342+}
1343+
1344 namespace
1345 {
1346 class WrapShellGeneratingCloseEvent : public mir::shell::ShellWrapper
1347@@ -317,3 +355,65 @@
1348
1349 mir_surface_release_sync(surface);
1350 }
1351+
1352+struct EventContext
1353+{
1354+ EventContext()
1355+ : event{nullptr}
1356+ {
1357+ }
1358+
1359+ ~EventContext()
1360+ {
1361+ if (event != nullptr)
1362+ mir_event_unref(event);
1363+ }
1364+
1365+ mt::Signal captured;
1366+ MirEvent const* event;
1367+};
1368+
1369+void surface_output_capturing_callback(MirSurface*, MirEvent const* ev, void* ctx)
1370+{
1371+ if (mir_event_get_type(ev) == mir_event_type_surface_output)
1372+ {
1373+ auto out_event = reinterpret_cast<EventContext*>(ctx);
1374+ out_event->event = mir_event_ref(ev);
1375+ out_event->captured.raise();
1376+ }
1377+}
1378+
1379+TEST_F(ClientSurfaceEvents, surface_receives_output_event_on_creation)
1380+{
1381+ using namespace std::literals::chrono_literals;
1382+
1383+ auto constexpr form_factor = mir_form_factor_tablet;
1384+ float constexpr scale = 2.15f;
1385+
1386+ std::shared_ptr<mg::DisplayConfiguration> display_configuration{server.the_display()->configuration()};
1387+
1388+ display_configuration->for_each_output(
1389+ [](mg::UserDisplayConfigurationOutput& output_config)
1390+ {
1391+ output_config.scale = scale;
1392+ output_config.form_factor = form_factor;
1393+ });
1394+
1395+ auto display_controller = server.the_display_configuration_controller();
1396+ display_controller->set_default_display_configuration(std::move(display_configuration)).get();
1397+
1398+ EventContext context;
1399+
1400+ auto spec = mir_connection_create_spec_for_normal_surface(connection, 640, 480, mir_pixel_format_abgr_8888);
1401+ mir_surface_spec_set_event_handler(spec, &surface_output_capturing_callback, &context);
1402+ auto surface = mir_surface_create_sync(spec);
1403+ mir_surface_spec_release(spec);
1404+
1405+ ASSERT_TRUE(context.captured.wait_for(10s));
1406+ ASSERT_THAT(mir_event_get_type(context.event), Eq(mir_event_type_surface_output));
1407+ auto surface_event = mir_event_get_surface_output_event(context.event);
1408+ EXPECT_THAT(mir_surface_output_event_get_form_factor(surface_event), Eq(form_factor));
1409+ EXPECT_THAT(mir_surface_output_event_get_scale(surface_event), Eq(scale));
1410+
1411+ mir_surface_release_sync(surface);
1412+}
1413
1414=== modified file 'tests/acceptance-tests/test_system_compositor_window_manager.cpp'
1415--- tests/acceptance-tests/test_system_compositor_window_manager.cpp 2015-06-25 03:00:08 +0000
1416+++ tests/acceptance-tests/test_system_compositor_window_manager.cpp 2015-10-07 06:10:46 +0000
1417@@ -199,7 +199,5 @@
1418 ON_CALL(client, surface_event(_, MirFocusEvent(mir_surface_focused)))
1419 .WillByDefault(InvokeWithoutArgs([&] { signal.raise(); }));
1420
1421- EXPECT_CALL(client, surface_event(_, MirFocusEvent(mir_surface_focused))).Times(0);
1422-
1423- signal.wait_for(100ms);
1424+ EXPECT_FALSE(signal.wait_for(100ms)) << "Unexpected surface_focused event received";
1425 }
1426
1427=== modified file 'tests/include/mir/test/doubles/stub_surface_factory.h'
1428--- tests/include/mir/test/doubles/stub_surface_factory.h 2015-06-25 03:00:08 +0000
1429+++ tests/include/mir/test/doubles/stub_surface_factory.h 2015-10-07 06:10:46 +0000
1430@@ -35,9 +35,12 @@
1431 public:
1432 std::shared_ptr<scene::Surface> create_surface(
1433 std::shared_ptr<compositor::BufferStream> const&,
1434- scene::SurfaceCreationParameters const&) override
1435+ scene::SurfaceCreationParameters const& params) override
1436 {
1437- return std::make_shared<testing::NiceMock<MockSurface>>();
1438+ using namespace testing;
1439+ auto surface = std::make_shared<NiceMock<MockSurface>>();
1440+ ON_CALL(*surface, size()).WillByDefault(Return(params.size));
1441+ return surface;;
1442 }
1443 };
1444
1445
1446=== modified file 'tests/integration-tests/session_management.cpp'
1447--- tests/integration-tests/session_management.cpp 2015-09-24 00:35:49 +0000
1448+++ tests/integration-tests/session_management.cpp 2015-10-07 06:10:46 +0000
1449@@ -120,5 +120,5 @@
1450 auto const session = session_manager->open_session(0, __PRETTY_FUNCTION__, event_sink);
1451
1452 EXPECT_CALL(*test_surface_stack, add_surface(_,_,_)).Times(1);
1453- session_manager->create_surface(session, params, nullptr);
1454+ session_manager->create_surface(session, params, event_sink);
1455 }
1456
1457=== modified file 'tests/integration-tests/test_session.cpp'
1458--- tests/integration-tests/test_session.cpp 2015-09-24 00:35:49 +0000
1459+++ tests/integration-tests/test_session.cpp 2015-10-07 06:10:46 +0000
1460@@ -37,6 +37,7 @@
1461 #include "mir/test/doubles/stub_renderer.h"
1462 #include "mir/test/doubles/stub_surface_factory.h"
1463 #include "mir/test/doubles/null_pixel_buffer.h"
1464+#include "mir/test/doubles/stub_display_configuration.h"
1465 #include "mir_test_framework/stubbed_server_configuration.h"
1466
1467 #include <gtest/gtest.h>
1468@@ -122,6 +123,7 @@
1469 "stress",
1470 conf.the_snapshot_strategy(),
1471 std::make_shared<ms::NullSessionListener>(),
1472+ mtd::StubDisplayConfig{},
1473 std::make_shared<mtd::NullEventSink>()
1474 };
1475 session.create_surface(ms::a_surface(), std::make_shared<mtd::NullEventSink>());
1476
1477=== modified file 'tests/mir_test/display_config_matchers.cpp'
1478--- tests/mir_test/display_config_matchers.cpp 2015-09-30 07:19:48 +0000
1479+++ tests/mir_test/display_config_matchers.cpp 2015-10-07 06:10:46 +0000
1480@@ -69,7 +69,9 @@
1481 protobuf_output.current_mode(),
1482 static_cast<MirPixelFormat>(protobuf_output.current_format()),
1483 static_cast<MirPowerMode>(protobuf_output.power_mode()),
1484- static_cast<MirOrientation>(protobuf_output.orientation())
1485+ static_cast<MirOrientation>(protobuf_output.orientation()),
1486+ 1.0f,
1487+ mir_form_factor_monitor
1488 };
1489
1490 /* Modes */
1491@@ -135,7 +137,9 @@
1492 client_output.current_mode,
1493 client_output.current_format,
1494 static_cast<MirPowerMode>(client_output.power_mode),
1495- static_cast<MirOrientation>(client_output.orientation)
1496+ static_cast<MirOrientation>(client_output.orientation),
1497+ 1.0f,
1498+ mir_form_factor_monitor
1499 };
1500
1501 /* Modes */
1502
1503=== modified file 'tests/unit-tests/graphics/mesa/kms/test_cursor.cpp'
1504--- tests/unit-tests/graphics/mesa/kms/test_cursor.cpp 2015-07-23 02:39:20 +0000
1505+++ tests/unit-tests/graphics/mesa/kms/test_cursor.cpp 2015-10-07 06:10:46 +0000
1506@@ -98,7 +98,9 @@
1507 1,
1508 mir_pixel_format_invalid,
1509 mir_power_mode_on,
1510- mir_orientation_normal
1511+ mir_orientation_normal,
1512+ 1.0f,
1513+ mir_form_factor_monitor
1514 });
1515 outputs.push_back(
1516 {
1517@@ -118,7 +120,9 @@
1518 0,
1519 mir_pixel_format_invalid,
1520 mir_power_mode_on,
1521- mir_orientation_normal
1522+ mir_orientation_normal,
1523+ 1.0f,
1524+ mir_form_factor_monitor
1525 });
1526 outputs.push_back(
1527 {
1528@@ -138,7 +142,9 @@
1529 0,
1530 mir_pixel_format_invalid,
1531 mir_power_mode_on,
1532- mir_orientation_right
1533+ mir_orientation_right,
1534+ 1.0f,
1535+ mir_form_factor_monitor
1536 });
1537 }
1538
1539
1540=== modified file 'tests/unit-tests/graphics/mesa/kms/test_display_configuration.cpp'
1541--- tests/unit-tests/graphics/mesa/kms/test_display_configuration.cpp 2015-10-05 17:36:04 +0000
1542+++ tests/unit-tests/graphics/mesa/kms/test_display_configuration.cpp 2015-10-07 06:10:46 +0000
1543@@ -203,7 +203,9 @@
1544 1,
1545 mir_pixel_format_invalid,
1546 mir_power_mode_on,
1547- mir_orientation_normal
1548+ mir_orientation_normal,
1549+ 1.0f,
1550+ mir_form_factor_monitor
1551 },
1552 {
1553 mg::DisplayConfigurationOutputId{connector1_id},
1554@@ -211,15 +213,17 @@
1555 mg::DisplayConfigurationOutputType::unknown,
1556 {},
1557 std::vector<mg::DisplayConfigurationMode>(),
1558- std::numeric_limits<size_t>::max(),
1559+ std::numeric_limits<uint32_t>::max(),
1560 connector1_physical_size_mm,
1561 false,
1562 false,
1563 geom::Point(),
1564- std::numeric_limits<size_t>::max(),
1565+ std::numeric_limits<uint32_t>::max(),
1566 mir_pixel_format_invalid,
1567 mir_power_mode_on,
1568- mir_orientation_normal
1569+ mir_orientation_normal,
1570+ 1.0f,
1571+ mir_form_factor_monitor
1572 },
1573 {
1574 mg::DisplayConfigurationOutputId{connector2_id},
1575@@ -227,15 +231,17 @@
1576 mg::DisplayConfigurationOutputType::edp,
1577 {},
1578 std::vector<mg::DisplayConfigurationMode>(),
1579- std::numeric_limits<size_t>::max(),
1580+ std::numeric_limits<uint32_t>::max(),
1581 connector2_physical_size_mm,
1582 false,
1583 false,
1584 geom::Point(),
1585- std::numeric_limits<size_t>::max(),
1586+ std::numeric_limits<uint32_t>::max(),
1587 mir_pixel_format_invalid,
1588 mir_power_mode_on,
1589- mir_orientation_normal
1590+ mir_orientation_normal,
1591+ 1.0f,
1592+ mir_form_factor_monitor
1593 }
1594 };
1595
1596@@ -390,7 +396,9 @@
1597 1,
1598 mir_pixel_format_invalid,
1599 mir_power_mode_on,
1600- mir_orientation_normal
1601+ mir_orientation_normal,
1602+ 1.0f,
1603+ mir_form_factor_monitor
1604 },
1605 {
1606 mg::DisplayConfigurationOutputId(connector_ids[1]),
1607@@ -398,15 +406,17 @@
1608 mg::DisplayConfigurationOutputType::vga,
1609 {},
1610 std::vector<mg::DisplayConfigurationMode>(),
1611- std::numeric_limits<size_t>::max(),
1612+ std::numeric_limits<uint32_t>::max(),
1613 connector_physical_sizes_mm_before[1],
1614 false,
1615 false,
1616 geom::Point(),
1617- std::numeric_limits<size_t>::max(),
1618+ std::numeric_limits<uint32_t>::max(),
1619 mir_pixel_format_invalid,
1620 mir_power_mode_on,
1621- mir_orientation_normal
1622+ mir_orientation_normal,
1623+ 1.0f,
1624+ mir_form_factor_monitor
1625 },
1626 };
1627
1628@@ -418,7 +428,7 @@
1629 mg::DisplayConfigurationOutputType::composite,
1630 {},
1631 std::vector<mg::DisplayConfigurationMode>(),
1632- std::numeric_limits<size_t>::max(),
1633+ std::numeric_limits<uint32_t>::max(),
1634 connector_physical_sizes_mm_after[0],
1635 false,
1636 true,
1637@@ -426,7 +436,9 @@
1638 1, // Ensure current_mode_index is remembered even still
1639 mir_pixel_format_invalid,
1640 mir_power_mode_on,
1641- mir_orientation_normal
1642+ mir_orientation_normal,
1643+ 1.0f,
1644+ mir_form_factor_monitor
1645 },
1646 {
1647 mg::DisplayConfigurationOutputId(connector_ids[1]),
1648@@ -442,7 +454,9 @@
1649 1,
1650 mir_pixel_format_invalid,
1651 mir_power_mode_on,
1652- mir_orientation_normal
1653+ mir_orientation_normal,
1654+ 1.0f,
1655+ mir_form_factor_monitor
1656 },
1657 };
1658
1659@@ -562,7 +576,9 @@
1660 1,
1661 mir_pixel_format_invalid,
1662 mir_power_mode_on,
1663- mir_orientation_normal
1664+ mir_orientation_normal,
1665+ 1.0f,
1666+ mir_form_factor_monitor
1667 },
1668 };
1669
1670@@ -583,7 +599,9 @@
1671 // available modes has also changed
1672 mir_pixel_format_invalid,
1673 mir_power_mode_on,
1674- mir_orientation_normal
1675+ mir_orientation_normal,
1676+ 1.0f,
1677+ mir_form_factor_monitor
1678 },
1679 };
1680
1681
1682=== modified file 'tests/unit-tests/graphics/test_default_display_configuration_policy.cpp'
1683--- tests/unit-tests/graphics/test_default_display_configuration_policy.cpp 2015-06-25 14:21:36 +0000
1684+++ tests/unit-tests/graphics/test_default_display_configuration_policy.cpp 2015-10-07 06:10:46 +0000
1685@@ -93,7 +93,9 @@
1686 0,
1687 mir_pixel_format_abgr_8888,
1688 mir_power_mode_on,
1689- mir_orientation_normal
1690+ mir_orientation_normal,
1691+ 1.0f,
1692+ mir_form_factor_monitor
1693 };
1694 }
1695
1696@@ -116,7 +118,7 @@
1697 output.pixel_formats = {};
1698 output.modes = {};
1699 output.current_format = mir_pixel_format_invalid;
1700- output.current_mode_index = std::numeric_limits<size_t>::max();
1701+ output.current_mode_index = std::numeric_limits<uint32_t>::max();
1702 return output;
1703 }
1704
1705
1706=== modified file 'tests/unit-tests/graphics/test_display_configuration.cpp'
1707--- tests/unit-tests/graphics/test_display_configuration.cpp 2015-02-22 07:46:25 +0000
1708+++ tests/unit-tests/graphics/test_display_configuration.cpp 2015-10-07 06:10:46 +0000
1709@@ -47,7 +47,9 @@
1710 2,
1711 mir_pixel_format_abgr_8888,
1712 mir_power_mode_on,
1713- mir_orientation_normal
1714+ mir_orientation_normal,
1715+ 1.0f,
1716+ mir_form_factor_monitor
1717 };
1718
1719 }
1720@@ -244,6 +246,32 @@
1721 EXPECT_EQ(b, a);
1722 }
1723
1724+TEST(DisplayConfiguration, outputs_with_different_scaling_factors_compare_unequal)
1725+{
1726+ mg::DisplayConfigurationOutput a = tmpl_output;
1727+ mg::DisplayConfigurationOutput b = tmpl_output;
1728+
1729+ EXPECT_EQ(a, b);
1730+ EXPECT_EQ(b, a);
1731+ a.scale = 2.0f;
1732+ b.scale = 3.0f;
1733+ EXPECT_NE(a, b);
1734+ EXPECT_NE(b, a);
1735+}
1736+
1737+TEST(DisplayConfiguration, outputs_with_different_form_factors_compare_unequal)
1738+{
1739+ mg::DisplayConfigurationOutput a = tmpl_output;
1740+ mg::DisplayConfigurationOutput b = tmpl_output;
1741+
1742+ EXPECT_EQ(a, b);
1743+ EXPECT_EQ(b, a);
1744+ a.form_factor = mir_form_factor_monitor;
1745+ b.form_factor = mir_form_factor_projector;
1746+ EXPECT_NE(a, b);
1747+ EXPECT_NE(b, a);
1748+}
1749+
1750 TEST(DisplayConfiguration, output_extents_uses_current_mode)
1751 {
1752 mg::DisplayConfigurationOutput out = tmpl_output;
1753
1754=== modified file 'tests/unit-tests/graphics/test_overlapping_output_grouping.cpp'
1755--- tests/unit-tests/graphics/test_overlapping_output_grouping.cpp 2015-02-22 07:46:25 +0000
1756+++ tests/unit-tests/graphics/test_overlapping_output_grouping.cpp 2015-10-07 06:10:46 +0000
1757@@ -73,7 +73,7 @@
1758
1759 void for_each_output(std::function<void(mg::DisplayConfigurationOutput const&)> f) const
1760 {
1761- size_t i = 1;
1762+ uint32_t i = 1;
1763 for (auto const& info : outputs)
1764 {
1765 std::vector<mg::DisplayConfigurationMode> modes(i);
1766@@ -94,7 +94,9 @@
1767 i - 1,
1768 mir_pixel_format_invalid,
1769 info.power_mode,
1770- info.orientation
1771+ info.orientation,
1772+ 1.0f,
1773+ mir_form_factor_monitor
1774 };
1775
1776 f(output);
1777
1778=== modified file 'tests/unit-tests/scene/test_abstract_shell.cpp'
1779--- tests/unit-tests/scene/test_abstract_shell.cpp 2015-09-24 00:35:49 +0000
1780+++ tests/unit-tests/scene/test_abstract_shell.cpp 2015-10-07 06:10:46 +0000
1781@@ -32,11 +32,13 @@
1782 #include "mir/test/doubles/mock_surface_coordinator.h"
1783 #include "mir/test/doubles/mock_session_listener.h"
1784 #include "mir/test/doubles/mock_surface.h"
1785+#include "mir/test/doubles/null_event_sink.h"
1786 #include "mir/test/doubles/null_snapshot_strategy.h"
1787 #include "mir/test/doubles/null_prompt_session_manager.h"
1788 #include "mir/test/doubles/stub_input_targeter.h"
1789 #include "mir/test/doubles/stub_buffer_stream_factory.h"
1790 #include "mir/test/doubles/null_application_not_responding_detector.h"
1791+#include "mir/test/doubles/stub_display.h"
1792
1793 #include "mir/test/fake_shared.h"
1794
1795@@ -48,6 +50,7 @@
1796 namespace ms = mir::scene;
1797 namespace msh = mir::shell;
1798 namespace geom = mir::geometry;
1799+namespace mg = mir::graphics;
1800
1801 namespace mt = mir::test;
1802 namespace mtd = mir::test::doubles;
1803@@ -105,6 +108,7 @@
1804 NiceMock<MockSessionEventSink> session_event_sink;
1805 NiceMock<mtd::MockSessionListener> session_listener;
1806 NiceMock<MockSurfaceFactory> surface_factory;
1807+ mtd::StubDisplay display{3};
1808
1809 NiceMock<MockSessionManager> session_manager{
1810 mt::fake_shared(surface_coordinator),
1811@@ -114,6 +118,7 @@
1812 std::make_shared<mtd::NullSnapshotStrategy>(),
1813 mt::fake_shared(session_event_sink),
1814 mt::fake_shared(session_listener),
1815+ mt::fake_shared(display),
1816 std::make_shared<mtd::NullANRDetector>()};
1817
1818 mtd::StubInputTargeter input_targeter;
1819@@ -131,6 +136,8 @@
1820 ON_CALL(session_container, successor_of(_)).WillByDefault(Return((std::shared_ptr<ms::Session>())));
1821 ON_CALL(session_manager, set_focus_to(_)).
1822 WillByDefault(Invoke(&session_manager, &MockSessionManager::unmocked_set_focus_to));
1823+ ON_CALL(mock_surface, size())
1824+ .WillByDefault(Return(geom::Size{}));
1825 ON_CALL(surface_factory, create_surface(_,_))
1826 .WillByDefault(Return(mt::fake_shared(mock_surface)));
1827 }
1828@@ -390,7 +397,7 @@
1829 auto const session0 = shell.open_session(__LINE__, "XPlane", std::shared_ptr<mf::EventSink>());
1830 auto const session1 = shell.open_session(__LINE__, "Bla", std::shared_ptr<mf::EventSink>());
1831 NiceMock<mtd::MockSurface> dummy_surface;
1832-
1833+ ON_CALL(dummy_surface, size()).WillByDefault(Return(geom::Size{}));
1834 EXPECT_CALL(surface_factory, create_surface(_,_)).Times(AnyNumber())
1835 .WillOnce(Return(mt::fake_shared(dummy_surface)))
1836 .WillOnce(Return(mt::fake_shared(mock_surface)));
1837@@ -404,7 +411,7 @@
1838 auto const surface1 = session1->surface(surface1_id);
1839
1840 msh::FocusController& focus_controller = shell;
1841-;
1842+
1843 focus_controller.set_focus_to(session0, surface0);
1844 EXPECT_THAT(focus_controller.focused_surface(), Eq(surface0));
1845 focus_controller.set_focus_to(session1, surface1);
1846
1847=== modified file 'tests/unit-tests/scene/test_application_session.cpp'
1848--- tests/unit-tests/scene/test_application_session.cpp 2015-09-24 00:35:49 +0000
1849+++ tests/unit-tests/scene/test_application_session.cpp 2015-10-07 06:10:46 +0000
1850@@ -34,6 +34,7 @@
1851 #include "mir/test/doubles/null_event_sink.h"
1852 #include "mir/test/doubles/mock_event_sink.h"
1853 #include "mir/test/doubles/null_prompt_session.h"
1854+#include "mir/test/doubles/stub_display_configuration.h"
1855
1856 #include <gmock/gmock.h>
1857 #include <gtest/gtest.h>
1858@@ -51,7 +52,10 @@
1859 {
1860 static std::shared_ptr<mtd::MockSurface> make_mock_surface()
1861 {
1862- return std::make_shared<testing::NiceMock<mtd::MockSurface> >();
1863+ using namespace testing;
1864+ auto surface = std::make_shared<NiceMock<mtd::MockSurface>>();
1865+ ON_CALL(*surface, size()).WillByDefault(Return(geom::Size { 100, 100 }));
1866+ return surface;
1867 }
1868
1869 struct MockBufferStreamFactory : public ms::BufferStreamFactory
1870@@ -98,6 +102,11 @@
1871 return arg.parent.lock() == parent;
1872 }
1873
1874+MATCHER(IsSurfaceOutputEvent, "")
1875+{
1876+ return mir_event_get_type(&arg) == mir_event_type_surface_output;
1877+}
1878+
1879 struct StubSurfaceCoordinator : public ms::SurfaceCoordinator
1880 {
1881 void raise(std::weak_ptr<ms::Surface> const&) override
1882@@ -138,6 +147,7 @@
1883 pid, name,
1884 null_snapshot_strategy,
1885 stub_session_listener,
1886+ mtd::StubDisplayConfig{},
1887 event_sink);
1888 }
1889
1890@@ -150,6 +160,7 @@
1891 pid, name,
1892 null_snapshot_strategy,
1893 stub_session_listener,
1894+ mtd::StubDisplayConfig{},
1895 event_sink);
1896 }
1897
1898@@ -162,6 +173,7 @@
1899 pid, name,
1900 null_snapshot_strategy,
1901 stub_session_listener,
1902+ mtd::StubDisplayConfig{},
1903 event_sink);
1904 }
1905 std::shared_ptr<ms::ApplicationSession> make_application_session_with_coordinator(
1906@@ -172,6 +184,7 @@
1907 pid, name,
1908 null_snapshot_strategy,
1909 stub_session_listener,
1910+ mtd::StubDisplayConfig{},
1911 event_sink);
1912 }
1913
1914@@ -183,6 +196,7 @@
1915 pid, name,
1916 null_snapshot_strategy,
1917 session_listener,
1918+ mtd::StubDisplayConfig{},
1919 event_sink);
1920 }
1921
1922@@ -195,6 +209,7 @@
1923 pid, name,
1924 null_snapshot_strategy,
1925 stub_session_listener,
1926+ mtd::StubDisplayConfig{},
1927 event_sink);
1928 }
1929
1930@@ -232,7 +247,7 @@
1931 mt::fake_shared(surface_coordinator), mt::fake_shared(mock_surface_factory));
1932
1933 ms::SurfaceCreationParameters params;
1934- auto surf = session->create_surface(params, nullptr);
1935+ auto surf = session->create_surface(params, event_sink);
1936
1937 session->destroy_surface(surf);
1938 }
1939@@ -250,7 +265,7 @@
1940 auto session = make_application_session_with_listener(mt::fake_shared(listener));
1941
1942 ms::SurfaceCreationParameters params;
1943- auto surf = session->create_surface(params, nullptr);
1944+ auto surf = session->create_surface(params, event_sink);
1945
1946 session->destroy_surface(surf);
1947 }
1948@@ -269,7 +284,7 @@
1949 auto session = make_application_session_with_listener(mt::fake_shared(listener));
1950
1951 ms::SurfaceCreationParameters params;
1952- session->create_surface(params, nullptr);
1953+ session->create_surface(params, event_sink);
1954 }
1955 }
1956
1957@@ -398,7 +413,7 @@
1958 }
1959
1960 ms::SurfaceCreationParameters params;
1961- auto surf = app_session->create_surface(params, nullptr);
1962+ auto surf = app_session->create_surface(params, event_sink);
1963
1964 app_session->hide();
1965 app_session->show();
1966@@ -429,9 +444,10 @@
1967 pid, name,
1968 snapshot_strategy,
1969 std::make_shared<ms::NullSessionListener>(),
1970+ mtd::StubDisplayConfig{},
1971 event_sink);
1972
1973- auto surface = app_session.create_surface(ms::SurfaceCreationParameters{}, nullptr);
1974+ auto surface = app_session.create_surface(ms::SurfaceCreationParameters{}, event_sink);
1975 app_session.take_snapshot(ms::SnapshotCallback());
1976 app_session.destroy_surface(surface);
1977 }
1978@@ -449,6 +465,7 @@
1979 pid, name,
1980 snapshot_strategy,
1981 std::make_shared<ms::NullSessionListener>(),
1982+ mtd::StubDisplayConfig{},
1983 event_sink);
1984
1985 EXPECT_CALL(*snapshot_strategy, take_snapshot_of(_,_)).Times(0);
1986@@ -469,6 +486,7 @@
1987 session_pid, name,
1988 null_snapshot_strategy,
1989 std::make_shared<ms::NullSessionListener>(),
1990+ mtd::StubDisplayConfig{},
1991 event_sink);
1992
1993 EXPECT_THAT(app_session.process_id(), Eq(session_pid));
1994@@ -493,7 +511,7 @@
1995
1996 ms::SurfaceCreationParameters params;
1997
1998- auto id1 = session->create_surface(params, nullptr);
1999+ auto id1 = session->create_surface(params, event_sink);
2000 EXPECT_THAT(session->get_buffer_stream(mf::BufferStreamId(id1.as_value())), Eq(stub_bstream));
2001 EXPECT_THAT(session->get_surface(id1), Eq(mock_surface));
2002
2003@@ -508,7 +526,7 @@
2004 {
2005 auto session = make_application_session_with_stubs();
2006 ms::SurfaceCreationParameters params;
2007- auto id = session->create_surface(params, nullptr);
2008+ auto id = session->create_surface(params, event_sink);
2009 mf::BufferStreamId stream_id(id.as_value());
2010 session->destroy_buffer_stream(stream_id);
2011 EXPECT_THROW({
2012@@ -550,7 +568,7 @@
2013 auto stream_id0 = mf::BufferStreamId(
2014 session->create_surface(
2015 ms::a_surface().of_position({1,1}),
2016- nullptr).as_value());
2017+ event_sink).as_value());
2018
2019 auto stream_id1 = session->create_buffer_stream(stream_properties);
2020 auto stream_id2 = session->create_buffer_stream(stream_properties);
2021@@ -614,7 +632,7 @@
2022 EXPECT_CALL(mock_surface_factory, create_surface(Eq(session->get_buffer_stream(id)),_))
2023 .WillOnce(Invoke([&](auto bs, auto)
2024 {
2025- auto surface = std::make_shared<NiceMock<mtd::MockSurface>>();
2026+ auto surface = make_mock_surface();
2027 ON_CALL(*surface, primary_buffer_stream())
2028 .WillByDefault(Return(bs));
2029 return surface;
2030@@ -625,7 +643,7 @@
2031 .of_type(mir_surface_type_normal)
2032 .with_buffer_stream(id);
2033
2034- auto surface_id = session->create_surface(params, nullptr);
2035+ auto surface_id = session->create_surface(params, event_sink);
2036 auto surface = session->get_surface(surface_id);
2037
2038 EXPECT_THAT(surface->primary_buffer_stream(), Eq(session->get_buffer_stream(id)));
2039@@ -637,12 +655,19 @@
2040 {
2041 ApplicationSessionSender() :
2042 app_session(
2043- stub_surface_coordinator, stub_surface_factory, stub_buffer_stream_factory,
2044- pid, name,null_snapshot_strategy, stub_session_listener, mt::fake_shared(sender))
2045+ stub_surface_coordinator,
2046+ stub_surface_factory,
2047+ stub_buffer_stream_factory,
2048+ pid,
2049+ name,
2050+ null_snapshot_strategy,
2051+ stub_session_listener,
2052+ mtd::StubDisplayConfig{},
2053+ mt::fake_shared(sender))
2054 {
2055 }
2056
2057- mtd::MockEventSink sender;
2058+ testing::NiceMock<mtd::MockEventSink> sender;
2059 ms::ApplicationSession app_session;
2060 };
2061 }
2062@@ -683,3 +708,430 @@
2063 EXPECT_CALL(sender, handle_event(EqPromptSessionEventState(mir_prompt_session_state_stopped))).Times(1);
2064 app_session.stop_prompt_session();
2065 }
2066+
2067+namespace
2068+{
2069+class ObserverPreservingSurface : public mtd::MockSurface
2070+{
2071+public:
2072+ void add_observer(std::shared_ptr<mir::scene::SurfaceObserver> const &observer) override
2073+ {
2074+ return BasicSurface::add_observer(observer);
2075+ }
2076+
2077+ void remove_observer(std::weak_ptr<mir::scene::SurfaceObserver> const &observer) override
2078+ {
2079+ return BasicSurface::remove_observer(observer);
2080+ }
2081+};
2082+
2083+class ObserverPreservingSurfaceFactory : public ms::SurfaceFactory
2084+{
2085+public:
2086+ std::shared_ptr<ms::Surface> create_surface(
2087+ std::shared_ptr<mir::compositor::BufferStream> const&,
2088+ mir::scene::SurfaceCreationParameters const& params) override
2089+ {
2090+ using namespace testing;
2091+ auto mock = std::make_shared<NiceMock<ObserverPreservingSurface>>();
2092+ ON_CALL(*mock, size()).WillByDefault(Return(params.size));
2093+ return mock;
2094+ };
2095+};
2096+
2097+int calculate_dpi(geom::Size const& resolution, geom::Size const& size)
2098+{
2099+ float constexpr mm_per_inch = 25.4f;
2100+
2101+ auto diagonal_mm = sqrt(size.height.as_int()*size.height.as_int()
2102+ + size.width.as_int()*size.width.as_int());
2103+ auto diagonal_px = sqrt(resolution.height.as_int() * resolution.height.as_int()
2104+ + resolution.width.as_int() * resolution.width.as_int());
2105+
2106+ return diagonal_px / diagonal_mm * mm_per_inch;
2107+}
2108+
2109+struct ApplicationSessionSurfaceOutput : public ApplicationSession
2110+{
2111+ ApplicationSessionSurfaceOutput() :
2112+ high_dpi({3840, 2160}, {509, 286}, 2.5f, mir_form_factor_monitor),
2113+ projector({1280, 1024}, {800, 600}, 0.5f, mir_form_factor_projector),
2114+ stub_surface_factory{std::make_shared<ObserverPreservingSurfaceFactory>()},
2115+ sender{std::make_shared<testing::NiceMock<mtd::MockEventSink>>()},
2116+ app_session(
2117+ stub_surface_coordinator,
2118+ stub_surface_factory,
2119+ stub_buffer_stream_factory,
2120+ pid,
2121+ name,
2122+ null_snapshot_strategy,
2123+ stub_session_listener,
2124+ mtd::StubDisplayConfig{},
2125+ sender)
2126+ {
2127+ }
2128+
2129+ struct TestOutput
2130+ {
2131+ TestOutput(
2132+ geom::Size const& resolution,
2133+ geom::Size const& physical_size,
2134+ float scale,
2135+ MirFormFactor form_factor) :
2136+ output{resolution, physical_size, mir_pixel_format_argb_8888, 60.0, true},
2137+ form_factor{form_factor},
2138+ scale{scale},
2139+ dpi{calculate_dpi(resolution, physical_size)},
2140+ width{resolution.width.as_int()}
2141+ {
2142+ output.scale = scale;
2143+ output.form_factor = form_factor;
2144+ }
2145+
2146+ mtd::StubDisplayConfigurationOutput output;
2147+ MirFormFactor form_factor;
2148+ float scale;
2149+ int dpi;
2150+ int width;
2151+ };
2152+
2153+ TestOutput const high_dpi;
2154+ TestOutput const projector;
2155+ std::shared_ptr<ms::SurfaceFactory> const stub_surface_factory;
2156+ std::shared_ptr<testing::NiceMock<mtd::MockEventSink>> sender;
2157+ ms::ApplicationSession app_session;
2158+};
2159+}
2160+
2161+namespace
2162+{
2163+MATCHER_P(SurfaceOutputEventFor, output, "")
2164+{
2165+ using namespace testing;
2166+
2167+ if (mir_event_get_type(arg) != mir_event_type_surface_output)
2168+ {
2169+ *result_listener << "Event is not a MirSurfaceOutputEvent";
2170+ return 0;
2171+ }
2172+
2173+ auto const event = mir_event_get_surface_output_event(arg);
2174+ return
2175+ ExplainMatchResult(
2176+ Eq(output.dpi),
2177+ mir_surface_output_event_get_dpi(event),
2178+ result_listener) &&
2179+ ExplainMatchResult(
2180+ Eq(output.form_factor),
2181+ mir_surface_output_event_get_form_factor(event),
2182+ result_listener) &&
2183+ ExplainMatchResult(
2184+ Eq(output.scale),
2185+ mir_surface_output_event_get_scale(event),
2186+ result_listener);
2187+}
2188+}
2189+
2190+TEST_F(ApplicationSessionSurfaceOutput, sends_surface_output_events_to_surfaces)
2191+{
2192+ using namespace ::testing;
2193+
2194+ MirEvent event;
2195+ bool event_received{false};
2196+
2197+ EXPECT_CALL(*sender, handle_event(IsSurfaceOutputEvent()))
2198+ .WillOnce(Invoke([&event, &event_received](auto ev)
2199+ {
2200+ event = ev;
2201+ event_received = true;
2202+ }));
2203+
2204+ std::vector<mg::DisplayConfigurationOutput> outputs =
2205+ {
2206+ high_dpi.output
2207+ };
2208+ mtd::StubDisplayConfig config(outputs);
2209+ app_session.send_display_config(config);
2210+
2211+ ms::SurfaceCreationParameters params = ms::SurfaceCreationParameters{}
2212+ .of_size({100, 100});
2213+ auto surf_id = app_session.create_surface(params, sender);
2214+ auto surface = app_session.surface(surf_id);
2215+
2216+ ASSERT_TRUE(event_received);
2217+ EXPECT_THAT(&event, SurfaceOutputEventFor(high_dpi));
2218+}
2219+
2220+TEST_F(ApplicationSessionSurfaceOutput, sends_correct_surface_details_to_surface)
2221+{
2222+ using namespace ::testing;
2223+
2224+ std::array<TestOutput const*, 2> outputs{{ &high_dpi, &projector }};
2225+
2226+ std::array<MirEvent, 2> event;
2227+ int events_received{0};
2228+
2229+ ON_CALL(*sender, handle_event(IsSurfaceOutputEvent()))
2230+ .WillByDefault(Invoke([&event, &events_received](auto ev)
2231+ {
2232+ event[events_received] = ev;
2233+ ++events_received;
2234+ }));
2235+
2236+ ms::SurfaceCreationParameters params = ms::SurfaceCreationParameters{}
2237+ .of_size({100, 100});
2238+
2239+ mf::SurfaceId ids[2];
2240+ std::shared_ptr<ms::Surface> surfaces[2];
2241+
2242+ ids[0] = app_session.create_surface(params, sender);
2243+ ids[1] = app_session.create_surface(params, sender);
2244+
2245+ surfaces[0] = app_session.surface(ids[0]);
2246+ surfaces[1] = app_session.surface(ids[1]);
2247+
2248+ surfaces[0]->move_to({0 + 100, 100});
2249+ surfaces[1]->move_to({outputs[0]->width + 100, 100});
2250+
2251+ // Reset events recieved; we may have received events from the move.
2252+ events_received = 0;
2253+
2254+ std::vector<mg::DisplayConfigurationOutput> configuration_outputs =
2255+ {
2256+ outputs[0]->output, outputs[1]->output
2257+ };
2258+ configuration_outputs[0].top_left = {0, 0};
2259+ configuration_outputs[1].top_left = {outputs[0]->width, 0};
2260+
2261+ mtd::StubDisplayConfig config(configuration_outputs);
2262+ app_session.send_display_config(config);
2263+
2264+ ASSERT_THAT(events_received, Eq(2));
2265+
2266+ for (int i = 0; i < 2 ; ++i)
2267+ {
2268+ EXPECT_THAT(event[i].surface_output.surface_id, Eq(ids[i].as_value()));
2269+ EXPECT_THAT(&event[i], SurfaceOutputEventFor(*outputs[i]));
2270+ }
2271+}
2272+
2273+TEST_F(ApplicationSessionSurfaceOutput, sends_details_of_the_hightest_scale_factor_display_on_overlap)
2274+{
2275+ using namespace ::testing;
2276+
2277+ std::array<TestOutput const*, 2> outputs{{ &projector, &high_dpi }};
2278+
2279+ MirEvent event;
2280+ bool event_received{false};
2281+
2282+ ON_CALL(*sender, handle_event(IsSurfaceOutputEvent()))
2283+ .WillByDefault(Invoke([&event, &event_received](auto ev)
2284+ {
2285+ event = ev;
2286+ event_received = true;
2287+ }));
2288+
2289+ ms::SurfaceCreationParameters params = ms::SurfaceCreationParameters{}
2290+ .of_size({100, 100});
2291+
2292+ auto id = app_session.create_surface(params, sender);
2293+ auto surface = app_session.surface(id);
2294+
2295+ // This should overlap both outputs
2296+ surface->move_to({outputs[0]->width - 50, 100});
2297+
2298+ std::vector<mg::DisplayConfigurationOutput> configuration_outputs =
2299+ {
2300+ outputs[0]->output, outputs[1]->output
2301+ };
2302+
2303+ // Put the higher-scale output on the right, so a surface's top_left coordinate
2304+ // can be in the lower-scale output but overlap with the higher-scale output.
2305+ configuration_outputs[0].top_left = {0, 0};
2306+ configuration_outputs[1].top_left = {outputs[0]->width, 0};
2307+
2308+ mtd::StubDisplayConfig config(configuration_outputs);
2309+ app_session.send_display_config(config);
2310+
2311+ ASSERT_TRUE(event_received);
2312+
2313+ EXPECT_THAT(event.surface_output.surface_id, Eq(id.as_value()));
2314+ EXPECT_THAT(&event, SurfaceOutputEventFor(high_dpi));
2315+}
2316+
2317+TEST_F(ApplicationSessionSurfaceOutput, surfaces_on_edges_get_correct_values)
2318+{
2319+ using namespace ::testing;
2320+
2321+ std::array<TestOutput const*, 2> outputs{{ &projector, &high_dpi }};
2322+
2323+ MirEvent event;
2324+ bool event_received{false};
2325+
2326+ ON_CALL(*sender, handle_event(IsSurfaceOutputEvent()))
2327+ .WillByDefault(Invoke([&event, &event_received](auto ev)
2328+ {
2329+ event = ev;
2330+ event_received = true;
2331+ }));
2332+
2333+ std::vector<mg::DisplayConfigurationOutput> configuration_outputs =
2334+ {
2335+ outputs[0]->output, outputs[1]->output
2336+ };
2337+
2338+ // Put the higher-scale output on the right, so a surface's top_left coordinate
2339+ // can be in the lower-scale output but overlap with the higher-scale output.
2340+ configuration_outputs[0].top_left = {0, 0};
2341+ configuration_outputs[1].top_left = {outputs[0]->width, 0};
2342+
2343+ mtd::StubDisplayConfig config(configuration_outputs);
2344+ app_session.send_display_config(config);
2345+
2346+ ms::SurfaceCreationParameters params = ms::SurfaceCreationParameters{}
2347+ .of_size({640, 480});
2348+
2349+ auto id = app_session.create_surface(params, sender);
2350+ auto surface = app_session.surface(id);
2351+
2352+ // This should solidly overlap both outputs
2353+ surface->move_to({outputs[0]->width - ((surface->size().width.as_uint32_t()) / 2), 100});
2354+
2355+ ASSERT_TRUE(event_received);
2356+ EXPECT_THAT(&event, SurfaceOutputEventFor(high_dpi));
2357+
2358+ event_received = false;
2359+ // This should be *just* entirely on the projector
2360+ surface->move_to({outputs[0]->width - surface->size().width.as_uint32_t(), 100});
2361+
2362+ ASSERT_TRUE(event_received);
2363+ EXPECT_THAT(&event, SurfaceOutputEventFor(projector));
2364+
2365+ event_received = false;
2366+ // This should have a single pixel overlap on the high_dpi
2367+ surface->move_to({outputs[0]->width - (surface->size().width.as_uint32_t() - 1), 100});
2368+
2369+ ASSERT_TRUE(event_received);
2370+ EXPECT_THAT(&event, SurfaceOutputEventFor(high_dpi));
2371+}
2372+
2373+TEST_F(ApplicationSessionSurfaceOutput, sends_surface_output_event_on_move)
2374+{
2375+ using namespace ::testing;
2376+
2377+ std::array<TestOutput const*, 2> outputs {{ &projector, &high_dpi }};
2378+
2379+ MirEvent event;
2380+ int events_received{0};
2381+
2382+
2383+ ON_CALL(*sender, handle_event(IsSurfaceOutputEvent()))
2384+ .WillByDefault(Invoke([&event, &events_received](auto ev)
2385+ {
2386+ event = ev;
2387+ events_received++;
2388+ }));
2389+
2390+ std::vector<mg::DisplayConfigurationOutput> configuration_outputs =
2391+ {
2392+ outputs[0]->output, outputs[1]->output
2393+ };
2394+
2395+ // Put the higher-scale output on the right, so a surface's top_left coordinate
2396+ // can be in the lower-scale output but overlap with the higher-scale output.
2397+ configuration_outputs[0].top_left = {0, 0};
2398+ configuration_outputs[1].top_left = {outputs[0]->width, 0};
2399+
2400+ mtd::StubDisplayConfig config(configuration_outputs);
2401+ app_session.send_display_config(config);
2402+
2403+ ms::SurfaceCreationParameters params = ms::SurfaceCreationParameters{}
2404+ .of_size({100, 100});
2405+
2406+ auto id = app_session.create_surface(params, sender);
2407+ auto surface = app_session.surface(id);
2408+
2409+ // This should overlap both outputs
2410+ surface->move_to({outputs[0]->width - 50, 100});
2411+
2412+
2413+ ASSERT_THAT(events_received, Ge(1));
2414+ auto events_expected = events_received + 1;
2415+
2416+ EXPECT_THAT(event.surface_output.surface_id, Eq(id.as_value()));
2417+ EXPECT_THAT(&event, SurfaceOutputEventFor(high_dpi));
2418+
2419+ // Now solely on the left output
2420+ surface->move_to({0, 0});
2421+
2422+ ASSERT_THAT(events_received, Eq(events_expected));
2423+ events_expected++;
2424+
2425+ EXPECT_THAT(event.surface_output.surface_id, Eq(id.as_value()));
2426+ EXPECT_THAT(&event, SurfaceOutputEventFor(projector));
2427+
2428+ // Now solely on the right output
2429+ surface->move_to({outputs[0]->width + 100, 100});
2430+
2431+ ASSERT_THAT(events_received, Eq(events_expected));
2432+ events_expected++;
2433+
2434+ EXPECT_THAT(event.surface_output.surface_id, Eq(id.as_value()));
2435+ EXPECT_THAT(&event, SurfaceOutputEventFor(high_dpi));
2436+}
2437+
2438+TEST_F(ApplicationSessionSurfaceOutput, sends_surface_output_event_on_move_only_if_changed)
2439+{
2440+ using namespace ::testing;
2441+
2442+ std::array<TestOutput const*, 2> outputs {{ &projector, &high_dpi }};
2443+
2444+ MirEvent event;
2445+ int events_received{0};
2446+
2447+ ON_CALL(*sender, handle_event(IsSurfaceOutputEvent()))
2448+ .WillByDefault(Invoke([&event, &events_received](auto ev)
2449+ {
2450+ event = ev;
2451+ events_received++;
2452+ }));
2453+
2454+ std::vector<mg::DisplayConfigurationOutput> configuration_outputs =
2455+ {
2456+ outputs[0]->output, outputs[1]->output
2457+ };
2458+
2459+ // Put the higher-scale output on the right, so a surface's top_left coordinate
2460+ // can be in the lower-scale output but overlap with the higher-scale output.
2461+ configuration_outputs[0].top_left = {0, 0};
2462+ configuration_outputs[1].top_left = {outputs[0]->width, 0};
2463+
2464+ mtd::StubDisplayConfig config(configuration_outputs);
2465+ app_session.send_display_config(config);
2466+
2467+ ms::SurfaceCreationParameters params = ms::SurfaceCreationParameters{}
2468+ .of_size({100, 100});
2469+
2470+ auto id = app_session.create_surface(params, sender);
2471+ auto surface = app_session.surface(id);
2472+
2473+ // We get an event on surface creation.
2474+ EXPECT_THAT(events_received, Eq(1));
2475+
2476+ // This should move within the same output, so not generate any events
2477+ surface->move_to({outputs[0]->width - (surface->size().width.as_int() + 1), 100});
2478+
2479+ EXPECT_THAT(events_received, Eq(1));
2480+
2481+ // This should move to *exactly* touching the edge of the output; still no events
2482+ surface->move_to({outputs[0]->width - surface->size().width.as_int(), 100});
2483+ EXPECT_THAT(events_received, Eq(1));
2484+
2485+ // This should move to just overlaping the second output; should generate an event
2486+ surface->move_to({outputs[0]->width - (surface->size().width.as_int() - 1), 100});
2487+ EXPECT_THAT(events_received, Eq(2));
2488+
2489+ // Back to exactly on the original display; another event.
2490+ surface->move_to({outputs[0]->width - surface->size().width.as_int(), 100});
2491+ EXPECT_THAT(events_received, Eq(3));
2492+}
2493
2494=== modified file 'tests/unit-tests/scene/test_session_manager.cpp'
2495--- tests/unit-tests/scene/test_session_manager.cpp 2015-09-24 00:35:49 +0000
2496+++ tests/unit-tests/scene/test_session_manager.cpp 2015-10-07 06:10:46 +0000
2497@@ -33,8 +33,10 @@
2498 #include "mir/test/doubles/stub_buffer_stream_factory.h"
2499 #include "mir/test/doubles/null_snapshot_strategy.h"
2500 #include "mir/test/doubles/null_session_event_sink.h"
2501+#include "mir/test/doubles/null_event_sink.h"
2502 #include "mir/test/doubles/stub_surface_factory.h"
2503 #include "mir/test/doubles/null_application_not_responding_detector.h"
2504+#include "mir/test/doubles/stub_display.h"
2505
2506 #include "mir/test/fake_shared.h"
2507
2508@@ -91,6 +93,8 @@
2509 ms::NullSessionListener session_listener;
2510 mtd::StubBufferStreamFactory buffer_stream_factory;
2511 mtd::StubSurfaceFactory stub_surface_factory;
2512+ mtd::StubDisplay display{2};
2513+ mtd::NullEventSink event_sink;
2514
2515 ms::SessionManager session_manager{mt::fake_shared(surface_coordinator),
2516 mt::fake_shared(stub_surface_factory),
2517@@ -99,6 +103,7 @@
2518 std::make_shared<mtd::NullSnapshotStrategy>(),
2519 std::make_shared<mtd::NullSessionEventSink>(),
2520 mt::fake_shared(session_listener),
2521+ mt::fake_shared(display),
2522 std::make_shared<mtd::NullANRDetector>()};
2523 };
2524
2525@@ -111,7 +116,7 @@
2526 EXPECT_CALL(container, insert_session(_)).Times(1);
2527 EXPECT_CALL(container, remove_session(_)).Times(1);
2528
2529- auto session = session_manager.open_session(__LINE__, "Visual Basic Studio", std::shared_ptr<mf::EventSink>());
2530+ auto session = session_manager.open_session(__LINE__, "Visual Basic Studio", mt::fake_shared(event_sink));
2531 session_manager.close_session(session);
2532 }
2533
2534@@ -124,10 +129,10 @@
2535 EXPECT_CALL(container, insert_session(_)).Times(1);
2536 EXPECT_CALL(container, remove_session(_)).Times(1);
2537
2538- auto session = session_manager.open_session(__LINE__, "Visual Basic Studio", std::shared_ptr<mf::EventSink>());
2539+ auto session = session_manager.open_session(__LINE__, "Visual Basic Studio", mt::fake_shared(event_sink));
2540 session->create_surface(
2541 ms::a_surface().of_size(geom::Size{geom::Width{1024}, geom::Height{768}}),
2542- nullptr);
2543+ mt::fake_shared(event_sink));
2544
2545 session_manager.close_session(session);
2546 }
2547@@ -146,6 +151,7 @@
2548 testing::NiceMock<MockSessionContainer> container;
2549 testing::NiceMock<mtd::MockSessionListener> session_listener;
2550 mtd::StubSurfaceFactory stub_surface_factory;
2551+ mtd::StubDisplay display{2};
2552
2553 ms::SessionManager session_manager{
2554 mt::fake_shared(surface_coordinator),
2555@@ -155,6 +161,7 @@
2556 std::make_shared<mtd::NullSnapshotStrategy>(),
2557 std::make_shared<mtd::NullSessionEventSink>(),
2558 mt::fake_shared(session_listener),
2559+ mt::fake_shared(display),
2560 std::make_shared<mtd::NullANRDetector>()};
2561 };
2562 }
2563@@ -185,6 +192,7 @@
2564 MockSessionEventSink session_event_sink;
2565 testing::NiceMock<mtd::MockSessionListener> session_listener;
2566 mtd::StubSurfaceFactory stub_surface_factory;
2567+ mtd::StubDisplay display{3};
2568
2569 ms::SessionManager session_manager{
2570 mt::fake_shared(surface_coordinator),
2571@@ -194,6 +202,7 @@
2572 std::make_shared<mtd::NullSnapshotStrategy>(),
2573 mt::fake_shared(session_event_sink),
2574 mt::fake_shared(session_listener),
2575+ mt::fake_shared(display),
2576 std::make_shared<mtd::NullANRDetector>()};
2577 };
2578 }
2579
2580=== modified file 'tests/unit-tests/scene/test_surface.cpp'
2581--- tests/unit-tests/scene/test_surface.cpp 2015-08-13 21:44:58 +0000
2582+++ tests/unit-tests/scene/test_surface.cpp 2015-10-07 06:10:46 +0000
2583@@ -21,6 +21,7 @@
2584 #include "src/server/scene/basic_surface.h"
2585 #include "src/server/scene/legacy_surface_change_notification.h"
2586 #include "src/server/report/null_report_factory.h"
2587+#include "src/server/scene/output_properties_cache.h"
2588 #include "mir/frontend/event_sink.h"
2589 #include "mir/scene/surface_creation_parameters.h"
2590 #include "mir/scene/surface_event_source.h"
2591@@ -268,7 +269,8 @@
2592 .Times(1);
2593
2594 auto const mock_event_sink = std::make_shared<MockEventSink>();
2595- auto const observer = std::make_shared<ms::SurfaceEventSource>(mf::SurfaceId(), mock_event_sink);
2596+ ms::OutputPropertiesCache cache;
2597+ auto const observer = std::make_shared<ms::SurfaceEventSource>(mf::SurfaceId(), surface, cache, mock_event_sink);
2598
2599 surface.add_observer(observer);
2600
2601@@ -284,7 +286,8 @@
2602 using namespace testing;
2603 geom::Size const new_size{123, 456};
2604 auto const mock_event_sink = std::make_shared<MockEventSink>();
2605- auto const observer = std::make_shared<ms::SurfaceEventSource>(mf::SurfaceId(), mock_event_sink);
2606+ ms::OutputPropertiesCache cache;
2607+ auto const observer = std::make_shared<ms::SurfaceEventSource>(mf::SurfaceId(), surface, cache, mock_event_sink);
2608
2609 surface.add_observer(observer);
2610
2611
2612=== modified file 'tests/unit-tests/scene/test_surface_impl.cpp'
2613--- tests/unit-tests/scene/test_surface_impl.cpp 2015-06-26 08:00:59 +0000
2614+++ tests/unit-tests/scene/test_surface_impl.cpp 2015-10-07 06:10:46 +0000
2615@@ -24,6 +24,7 @@
2616 #include "src/server/report/null_report_factory.h"
2617 #include "mir/frontend/event_sink.h"
2618 #include "mir/graphics/display_configuration.h"
2619+#include "src/server/scene/output_properties_cache.h"
2620
2621 #include "mir/test/doubles/stub_buffer_stream.h"
2622 #include "mir/test/doubles/mock_buffer_stream.h"
2623@@ -173,7 +174,8 @@
2624
2625 geom::Size const new_size{123, 456};
2626 auto sink = std::make_shared<mtd::MockEventSink>();
2627- auto const observer = std::make_shared<ms::SurfaceEventSource>(stub_id, sink);
2628+ ms::OutputPropertiesCache cache;
2629+ auto const observer = std::make_shared<ms::SurfaceEventSource>(stub_id, *surface, cache, sink);
2630
2631 surface->add_observer(observer);
2632
2633@@ -192,7 +194,8 @@
2634 geom::Size const new_size{123, 456};
2635 geom::Size const new_size2{789, 1011};
2636 auto sink = std::make_shared<mtd::MockEventSink>();
2637- auto const observer = std::make_shared<ms::SurfaceEventSource>(stub_id, sink);
2638+ ms::OutputPropertiesCache cache;
2639+ auto const observer = std::make_shared<ms::SurfaceEventSource>(stub_id, *surface, cache, sink);
2640
2641 surface->add_observer(observer);
2642
2643@@ -229,7 +232,8 @@
2644 .Times(1);
2645 }
2646
2647- auto const observer = std::make_shared<ms::SurfaceEventSource>(stub_id, mt::fake_shared(sink));
2648+ ms::OutputPropertiesCache cache;
2649+ auto const observer = std::make_shared<ms::SurfaceEventSource>(stub_id, *surface, cache, mt::fake_shared(sink));
2650
2651 surface->add_observer(observer);
2652
2653@@ -242,7 +246,8 @@
2654 using namespace testing;
2655
2656 auto sink = std::make_shared<mtd::MockEventSink>();
2657- auto const observer = std::make_shared<ms::SurfaceEventSource>(stub_id, sink);
2658+ ms::OutputPropertiesCache cache;
2659+ auto const observer = std::make_shared<ms::SurfaceEventSource>(stub_id, *surface, cache, sink);
2660
2661 surface->add_observer(observer);
2662

Subscribers

People subscribed via source and target branches