Mir

Merge lp:~alan-griffiths/mir/first-pass-of-surface-spec-modification into lp:mir

Proposed by Alan Griffiths
Status: Merged
Approved by: Alan Griffiths
Approved revision: no longer in the source branch.
Merged at revision: 2484
Proposed branch: lp:~alan-griffiths/mir/first-pass-of-surface-spec-modification
Merge into: lp:mir
Prerequisite: lp:~alan-griffiths/mir/some-surface-modification-infrastructure
Diff against target: 397 lines (+184/-56)
9 files modified
include/client/mir_toolkit/mir_surface.h (+23/-3)
src/client/mir_surface.cpp (+1/-2)
src/client/mir_surface.h (+1/-3)
src/client/mir_surface_api.cpp (+41/-40)
src/client/symbols.map (+2/-0)
src/server/shell/canonical_window_manager.cpp (+36/-5)
src/server/shell/canonical_window_manager.h (+7/-0)
tests/acceptance-tests/test_client_surfaces.cpp (+3/-3)
tests/acceptance-tests/test_surface_modifications.cpp (+70/-0)
To merge this branch: bzr merge lp:~alan-griffiths/mir/first-pass-of-surface-spec-modification
Reviewer Review Type Date Requested Status
Robert Carr (community) Approve
Kevin DuBois (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Thomas Voß (community) Approve
Alexandros Frantzis (community) Approve
Alberto Aguirre (community) Approve
Alan Griffiths Abstain
Chris Halse Rogers Approve
Review via email: mp+255707@code.launchpad.net

Commit message

client API, shell: start exposing the surface spec modification functionality

Description of the change

client API, shell: start exposing the surface spec modification functionality

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Chris Halse Rogers (raof) wrote :

This looks mostly sensible, but does mean that we need a separate API for introspecting the state of surfaces. IIRC the longer-term plan was to move all the surface introspection into MirSurfaceSpec accessors and deprecate things such as MirSurfaceParameters.

That said, now that I think of it some more, I think being able to get a SurfaceSpec from an existing surface and apply it would probably a misfeature, as the possibility for clients to accidentally override user changes would be high.

Hm. If we need to support morphing from different surface types - dialog to normal, for example - we'll need to have a mir_surface_spec_set_type and this will be somewhat redundant with the mir_connection_surface_spec_for_* family of functions. A client would be able to mir_create_spec_for_changes(), fill in all the same details as mir_connection_surface_spec_for_normal(), and then pass it to mir_surface_create() - whereupon they'd somewhat unexpectedly get an abort(), because the MirConnection isn't set.

I'm not sure what I think about this. On the one hand, it might be nice to not have the same type for both. On the other, that's obvious duplication. I guess I lean towards the former; one type with perhaps surprising behaviour.

17 +mir_connection_create_spec_for_changes(MirConnection* connection);
Why does this take a MirConnection? It's not used for anything, and it doesn't seem likely that it'll be used for anything in the future.

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

I guess that's “needs discussion” ☺

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

*Needs Discussion*

> This looks mostly sensible, but does mean that we need a separate API for
> introspecting the state of surfaces. IIRC the longer-term plan was to move all
> the surface introspection into MirSurfaceSpec accessors and deprecate things
> such as MirSurfaceParameters.

While I'm not strongly against it I'm not sure there is currently such a plan. The client trying to use the "existing state" with a surface specification leads to synchronization issues. Like this:

> That said, now that I think of it some more, I think being able to get a
> SurfaceSpec from an existing surface and apply it would probably a misfeature,
> as the possibility for clients to accidentally override user changes would be
> high.

~~~~

> Hm. If we need to support morphing from different surface types - dialog to
> normal, for example - we'll need to have a mir_surface_spec_set_type and this
> will be somewhat redundant with the mir_connection_surface_spec_for_* family
> of functions. A client would be able to mir_create_spec_for_changes(), fill in
> all the same details as mir_connection_surface_spec_for_normal(), and then
> pass it to mir_surface_create() - whereupon they'd somewhat unexpectedly get
> an abort(), because the MirConnection isn't set.
>
> I'm not sure what I think about this. On the one hand, it might be nice to not
> have the same type for both. On the other, that's obvious duplication. I guess
> I lean towards the former; one type with perhaps surprising behaviour.

Well, while MirSurfaceSpec isn't currently polymorphic the various mir_surface_spec_set_XXX() functions can fail (and return false). So different behavior from MirSurfaceSpec's created by different create functions is consistent with the API.

For example, mir_surface_spec_set_type() could fail if the MirSurfaceSpec was not created for change.

Alternatively, we could just constrain the state of MirSurfaceSpec in the functions that accept it and use the various mir_connection_create_spec_for_XXX functions as shortcuts.

> 17 +mir_connection_create_spec_for_changes(MirConnection* connection);
> Why does this take a MirConnection? It's not used for anything, and it doesn't
> seem likely that it'll be used for anything in the future.

Initially it was for consistency, but given the points you raise above we could use it to initialize MirSurfaceSpec::connection - that way the client could theoretically pass the MirSurfaceSpec to mir_surface_create() in the scenario you describe.

Although, if we decide on that approach this function should probably be renamed mir_connection_create_spec(MirConnection* connection) - and the existing functions are then "shortcuts" to the valid states for creation.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Kevin DuBois (kdub) wrote :

nits:
93 namespace { // Private for now. TODO: Finalize and publish later (LP: #1422522)
comment needs removal

46 +
47 +
extra whitespace

57 +MirSurfaceSpec::MirSurfaceSpec()
could we just remove this, and keep MirSurfaceSpec() = default?

review: Needs Fixing
Revision history for this message
Kevin DuBois (kdub) wrote :

As for the API changes, I'm all for publishing some sort of surface-changing functions (with a slightly different way proposed in the rfc-branch https://code.launchpad.net/~kdub/mir/RFC-surface-arrangements/+merge/254982)

My points here:
After I call mir_surface_create(), the MirSurfaceSpec seems to be associated with the surface. It makes more sense (to me at least) to query the surface, where MirSurfaceSpec "lives", for the existing specification of the surface.

This also leads to the topic of guaranteeing that the surface is in a particular state while the client decides what to do with the surface next. Like, it seems sensible that we have to lock the surface state, and then apply all the changes at once, and then 'unlock' the surface for further server-started changes.

It also seems that just rejecting change-specs the server doesn't like will lead to a somewhat frustrating back-and-forth for the clients trying to apply the change they want and then being told for non-obvious reasons that the change that was requested was rejected.

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

> nits:
> 93 namespace { // Private for now. TODO: Finalize and publish later (LP:
> #1422522)
> comment needs removal

Done

>
> 46 +
> 47 +
> extra whitespace

Done

> 57 +MirSurfaceSpec::MirSurfaceSpec()
> could we just remove this, and keep MirSurfaceSpec() = default?

We could, but there's no advantage to having it inline (and it might change as result of discussion).

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

> As for the API changes, I'm all for publishing some sort of surface-changing
> functions (with a slightly different way proposed in the rfc-branch
> https://code.launchpad.net/~kdub/mir/RFC-surface-arrangements/+merge/254982)

But isn't that now about arranging buffer streams within a surface, and not to do with modifying the surface.

> My points here:
> After I call mir_surface_create(), the MirSurfaceSpec seems to be associated
> with the surface. It makes more sense (to me at least) to query the surface,
> where MirSurfaceSpec "lives", for the existing specification of the surface.

I don't think the MirSurfaceSpec is associated with a surface. If I were to call mir_surface_create() three times and get three surfaces would you consider it associated with all of them?

> This also leads to the topic of guaranteeing that the surface is in a
> particular state while the client decides what to do with the surface next.
> Like, it seems sensible that we have to lock the surface state, and then apply
> all the changes at once, and then 'unlock' the surface for further server-
> started changes.

Clients cannot reasonably "lock" the state of the surface - the window manager needs to respond to user input, display changes etc.

> It also seems that just rejecting change-specs the server doesn't like will
> lead to a somewhat frustrating back-and-forth for the clients trying to apply
> the change they want and then being told for non-obvious reasons that the
> change that was requested was rejected.

There is no way for a client to get a meaningful response to a change spec request. It is "fire and forget". There will likely be corresponding events from the server - but even if the request is honored in full the surface may never be in the requested state because of concurrent changes by (e.g.) the user.

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

> There is no way for a client to get a meaningful response to a change spec
> request. It is "fire and forget". There will likely be corresponding events
> from the server - but even if the request is honored in full the surface may
> never be in the requested state because of concurrent changes by (e.g.) the
> user.

This was discussed to death in lp:~vanvugt/mir/wait-result/+merge/252403

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

Another thought is that we don't necessarily need mir_surface_spec_set_type().

We could, for example, do this:

void morph_to_a_dialog(MirSurface* some_existing_surface)
{
    auto const spec = mir_connection_create_spec_for_modal_dialog(...);
    mir_surface_apply_spec(some_existing_surface, spec);
    mir_surface_spec_release(spec);
}

This way we avoid the complexity of managing the required parameters for the new type.

The "con" is that it is then difficult to "inherit" parameters from the existing surface.

But this is not a problem with the current MP - we can still chose several options building upon it.

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

I think this MP is reasonable.

I don't think a mir_surface_spec_set_type is necessary, as you can create a spec for a specific type using the mir_connection_create_spec_for_xxx set of APIs and just use it in mir_surface_apply_spec.

I know that would require passing width/height/pixel_format (which could be in theory be morphed too) but I wouldn't mind a user setting -1, -1, mir_pixel_format_invalid to signal mir_surface_apply_spec to ignore those settings. I would prefer that slight ugliness in order to keep the API consistent and avoid adding type/parent setters - which was something we discussed to death and decided against.

In any case this MP looks ok to me.

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

nits fixed, unblocking while I think more about the observations in my above comment.

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

I'm conceptually happy with this.

I was thinking that we needed a surface-state-snapshot type, and that MirSurfaceSpec could be it, but on reflection I don't think we *do* need one.

For the specific case of Kevin's MirBufferStream bypass work, the introspection API is only necessary to ease testing - clients are perfectly capable of maintaining their own stacking and positioning state.

I'm in favour of doing the mir_connection_spec_for_* for surface type morphing - I'd maintain the requirement to set mir_pixel_format to the correct value, because that's entirely under the control of the client, but having a guard mir_dimension_last = -1 for width/height seems least ugly.

With that, I don't mind the useless MirConnection parameter to spec_for_changes :).

Why does mir_surface_apply_spec return a MirWaitHandle? I don't particularly mind it doing so, but as (extensively!) discussed, there's nothing useful a client can do with it.

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

*Needs Discussion*

> Why does mir_surface_apply_spec return a MirWaitHandle? I don't particularly
> mind it doing so, but as (extensively!) discussed, there's nothing useful a
> client can do with it.

I agree it is useless. But it is consistent with the other APIs we discussed. Is it better to be inconsistent and return void now? Or to plan on removing the wait handle in all similar APIs when we next break ABI compatibility?

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

I would vote for just returning void, but it's not a blocking issue.

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

> I would vote for just returning void, but it's not a blocking issue.

Let's do it then

review: Abstain
Revision history for this message
Alberto Aguirre (albaguirre) :
review: Approve
Revision history for this message
Robert Carr (robertcarr) wrote :

146 and 153
+void mir_surface_apply_spec(MirSurface* surface, MirSurfaceSpec* spec)
+...set_name...

Should catch exceptions right?

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Kevin DuBois (kdub) wrote :

So, I'm okay with this approach, as opposed to some sort of "lock" guarantee, as that seems to raise all sorts of questions about what a 'locked' surface might mean.
The wait handle seemed useless too, so also okay with its removal.

Chris's point that the nested stuff (or other clients) can maintain some of their own info is a good one. I'm not sure though that we explain well what changing a surface spec means... It makes sense to me to say that "when the title name is set to "X" on the MirSurfaceSpec, it will be presented as "X" when the server chooses to show a title", as opposed to saying "when the title name is set to "X" on the MirSurfaceSpec, it can be silently rejected"

needs-info:
1) Shouldn't this take a MirSurfaceSpec* instead of of a MirSurface*?
31 +void mir_surface_set_title(MirSurface* surface, char const* name);

2) Is it (or will it be) possible to construct a MirSurfaceSpec that's invalid? For instance, if we have a mir_surface_spec_set_size(..., int x, int y), and someone tries to morph a tooltip to a tooltip that spans multiple monitors that seems to violate the meaning of the types in the spec document. It might make sense to indicate to the client that its request was "flat-out rejected forever", instead of "accepted as something that the server will try to apply when appropriate".

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

> needs-info:
> 1) Shouldn't this take a MirSurfaceSpec* instead of of a MirSurface*?
> 31 +void mir_surface_set_title(MirSurface* surface, char const* name);

No, this is a signature change (dropping the wait handle) to an existing method that's a "convenience wrapper" around the MirSurfaceSpec calls needed to change a surface title. (C.f. lp:~vanvugt/mir/rename-api/+merge/252864/comments/628924.)

> 2) Is it (or will it be) possible to construct a MirSurfaceSpec that's
> invalid? For instance, if we have a mir_surface_spec_set_size(..., int x, int
> y), and someone tries to morph a tooltip to a tooltip that spans multiple
> monitors that seems to violate the meaning of the types in the spec document.
> It might make sense to indicate to the client that its request was "flat-out
> rejected forever", instead of "accepted as something that the server will try
> to apply when appropriate".

That's a poor example of a MirSurfaceSpec that's invalid: How is that any different from the existing scenario of a "someone" requesting a tooltip that spans multiple monitors without a modification? The server knows what monitors are attached at the time it processes the request (and what "shell space" exists on the monitors) and sizes the surface accordingly.

A better example would be creating a MirSurfaceSpec for changes and then calling mir_surface_create_sync() - which will then abort because the surface has no type.

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

> 146 and 153
> +void mir_surface_apply_spec(MirSurface* surface, MirSurfaceSpec* spec)
> +...set_name...
>
> Should catch exceptions right?

Fixed

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

Looks sensible.

31 +void mir_surface_set_title(MirSurface* surface, char const* name);

Now that we have a way to perform the same task with a more general mechanism, I am not convinced that we should keep mir_surface_set_title. If we keep it then we will be tempted to add mir_surface_set_ATTR for every new attribute that can be changed. I prefer offering a single way to do things, even if it's slightly more complex (which is not much of a problem considering that we don't expect most clients to be written with the client API itself, but rather through toolkits).

review: Approve
Revision history for this message
Thomas Voß (thomas-voss) wrote :

LGTM, two remarks inline, though.

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

@Alan, I see now that its just a convenience wrapper, so okay with the signature.
resolved the second point on IRC, my assumption that there were invalid change MirSurfaceSpecs isn't part of the intended model.

okay by me, and can port base the rfc branch I have up on this one

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

LGTM now

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/client/mir_toolkit/mir_surface.h'
2--- include/client/mir_toolkit/mir_surface.h 2015-04-09 06:20:31 +0000
3+++ include/client/mir_toolkit/mir_surface.h 2015-04-14 08:39:35 +0000
4@@ -168,6 +168,18 @@
5 MirPixelFormat format);
6
7 /**
8+ * Create a surface specification for updating a surface.
9+ *
10+ * This can be applied to one or more target surfaces using
11+ * mir_surface_apply_spec(...).
12+ *
13+ * \param [in] connection a valid mir connection
14+ *
15+ */
16+MirSurfaceSpec*
17+mir_connection_create_spec_for_changes(MirConnection* connection);
18+
19+/**
20 * Create a surface from a given specification
21 *
22 *
23@@ -577,9 +589,17 @@
24 * Change the title (name) of a surface.
25 * \param [in] surface The surface to rename
26 * \param [in] name The new name
27- * \returns When the change has completed
28- */
29-MirWaitHandle* mir_surface_set_title(MirSurface* surf, char const* name);
30+ */
31+void mir_surface_set_title(MirSurface* surface, char const* name);
32+
33+/**
34+ * Request changes to the specification of a surface. The server will decide
35+ * whether and how the request can be honoured.
36+ *
37+ * \param [in] surface The surface to rename
38+ * \param [in] spec Spec with the requested changes applied
39+ */
40+void mir_surface_apply_spec(MirSurface* surface, MirSurfaceSpec* spec);
41
42 #ifdef __cplusplus
43 }
44
45=== modified file 'src/client/mir_surface.cpp'
46--- src/client/mir_surface.cpp 2015-04-13 12:07:15 +0000
47+++ src/client/mir_surface.cpp 2015-04-14 08:39:35 +0000
48@@ -74,9 +74,8 @@
49 }
50 }
51
52-MirSurfaceSpec::MirSurfaceSpec(MirSurface* preexisting)
53+MirSurfaceSpec::MirSurfaceSpec()
54 {
55- self = preexisting;
56 }
57
58 mir::protobuf::SurfaceParameters MirSurfaceSpec::serialize() const
59
60=== modified file 'src/client/mir_surface.h'
61--- src/client/mir_surface.h 2015-04-09 14:29:02 +0000
62+++ src/client/mir_surface.h 2015-04-14 08:39:35 +0000
63@@ -61,10 +61,9 @@
64
65 struct MirSurfaceSpec
66 {
67- MirSurfaceSpec() = default;
68+ MirSurfaceSpec();
69 MirSurfaceSpec(MirConnection* connection, int width, int height, MirPixelFormat format);
70 MirSurfaceSpec(MirConnection* connection, MirSurfaceParameters const& params);
71- MirSurfaceSpec(MirSurface* preexisting);
72
73 mir::protobuf::SurfaceParameters serialize() const;
74
75@@ -84,7 +83,6 @@
76 mir::optional_value<MirSurfaceState> state;
77 mir::optional_value<MirOrientationMode> pref_orientation;
78
79- mir::optional_value<MirSurface*> self;
80 mir::optional_value<MirSurface*> parent;
81 mir::optional_value<MirRectangle> aux_rect;
82 mir::optional_value<MirEdgeAttachment> edge_attachment;
83
84=== modified file 'src/client/mir_surface_api.cpp'
85--- src/client/mir_surface_api.cpp 2015-04-10 16:50:12 +0000
86+++ src/client/mir_surface_api.cpp 2015-04-14 08:39:35 +0000
87@@ -583,44 +583,45 @@
88 return nullptr;
89 }
90
91-namespace { // Private for now. TODO: Finalize and publish later (LP: #1422522)
92-
93-MirSurfaceSpec* mir_surface_begin_changes(MirSurface* surf)
94-{
95- mir::require(mir_surface_is_valid(surf));
96-
97- MirSurfaceSpec* spec = nullptr;
98- try
99- {
100- spec = new MirSurfaceSpec(surf);
101- }
102- catch (std::exception const& ex)
103- {
104- MIR_LOG_UNCAUGHT_EXCEPTION(ex);
105- }
106-
107- return spec;
108-}
109-
110-MirWaitHandle* mir_surface_spec_commit_changes(MirSurfaceSpec* spec)
111-{
112- if (!spec->self.is_set())
113- return nullptr;
114-
115- auto surface = spec->self.value();
116- return surface->modify(*spec);
117-}
118-
119-} // Private namespace. TODO: finalize morphing API and publish.
120-
121-MirWaitHandle* mir_surface_set_title(MirSurface* surf, char const* name)
122-{
123- MirWaitHandle* result = nullptr;
124- if (auto spec = mir_surface_begin_changes(surf))
125- {
126- mir_surface_spec_set_name(spec, name);
127- result = mir_surface_spec_commit_changes(spec);
128- mir_surface_spec_release(spec);
129- }
130- return result;
131+namespace
132+{
133+MirSurfaceSpec* create_spec_for_changes()
134+try
135+{
136+ return new MirSurfaceSpec{};
137+}
138+catch (std::exception const& ex)
139+{
140+ MIR_LOG_UNCAUGHT_EXCEPTION(ex);
141+ std::abort(); // If we just failed to allocate a MirSurfaceSpec returning isn't safe
142+}
143+}
144+
145+MirSurfaceSpec* mir_connection_create_spec_for_changes(MirConnection* connection)
146+{
147+ mir::require(mir_connection_is_valid(connection));
148+
149+ return create_spec_for_changes();
150+}
151+
152+void mir_surface_apply_spec(MirSurface* surface, MirSurfaceSpec* spec)
153+try
154+{
155+ mir::require(mir_surface_is_valid(surface));
156+ mir::require(spec);
157+
158+ surface->modify(*spec);
159+}
160+catch (std::exception const& ex)
161+{
162+ MIR_LOG_UNCAUGHT_EXCEPTION(ex);
163+ // Keep calm and carry on
164+}
165+
166+void mir_surface_set_title(MirSurface* surface, char const* name)
167+{
168+ auto const spec = create_spec_for_changes();
169+ mir_surface_spec_set_name(spec, name);
170+ mir_surface_apply_spec(surface, spec);
171+ mir_surface_spec_release(spec);
172 }
173
174=== modified file 'src/client/symbols.map'
175--- src/client/symbols.map 2015-04-09 06:20:31 +0000
176+++ src/client/symbols.map 2015-04-14 08:39:35 +0000
177@@ -113,6 +113,8 @@
178
179 MIR_CLIENT_8.4 { # New in Mir 0.13
180 global:
181+ mir_connection_create_spec_for_changes;
182+ mir_surface_apply_spec;
183 mir_surface_set_event_handler;
184 mir_surface_set_title;
185 mir_default_cursor_name;
186
187=== modified file 'src/server/shell/canonical_window_manager.cpp'
188--- src/server/shell/canonical_window_manager.cpp 2015-04-09 06:20:31 +0000
189+++ src/server/shell/canonical_window_manager.cpp 2015-04-14 08:39:35 +0000
190@@ -248,6 +248,26 @@
191 {
192 if (modifications.name.is_set())
193 surface->rename(modifications.name.value());
194+
195+ if (modifications.width.is_set() || modifications.height.is_set())
196+ {
197+ // TODO similar logic is needed in example window management policies
198+ auto new_size = surface->size();
199+
200+ if (modifications.width.is_set())
201+ new_size.width = modifications.width.value();
202+
203+ if (modifications.height.is_set())
204+ new_size.height = modifications.height.value();
205+
206+ constrained_resize(
207+ surface,
208+ surface->top_left(),
209+ new_size,
210+ false,
211+ false,
212+ display_area);
213+ }
214 }
215
216 void msh::CanonicalWindowManagerPolicy::handle_delete_surface(std::shared_ptr<ms::Session> const& session, std::weak_ptr<ms::Surface> const& surface)
217@@ -577,6 +597,17 @@
218
219 Point new_pos = top_left + left_resize*delta.dx + top_resize*delta.dy;
220
221+ return constrained_resize(surface, new_pos, new_size, left_resize, top_resize, bounds);
222+}
223+
224+bool msh::CanonicalWindowManagerPolicy::constrained_resize(
225+ std::shared_ptr<ms::Surface> const& surface,
226+ Point new_pos,
227+ Size new_size,
228+ bool const left_resize,
229+ bool const top_resize,
230+ Rectangle const& bounds)
231+{
232 if (left_resize)
233 {
234 if (new_pos.x < bounds.top_left.x)
235@@ -615,15 +646,15 @@
236 // "A vertically maximised surface is anchored to the top and bottom of
237 // the available workspace and can have any width."
238 case mir_surface_state_vertmaximized:
239- new_pos.y = old_pos.top_left.y;
240- new_size.height = old_pos.size.height;
241+ new_pos.y = surface->top_left().y;
242+ new_size.height = surface->size().height;
243 break;
244
245 // "A horizontally maximised surface is anchored to the left and right of
246 // the available workspace and can have any height"
247 case mir_surface_state_horizmaximized:
248- new_pos.x = old_pos.top_left.x;
249- new_size.width = old_pos.size.width;
250+ new_pos.x = surface->top_left().x;
251+ new_size.width = surface->size().width;
252 break;
253
254 // "A maximised surface is anchored to the top, bottom, left and right of the
255@@ -639,7 +670,7 @@
256 // TODO It is rather simplistic to move a tree WRT the top_left of the root
257 // TODO when resizing. But for more sophistication we would need to encode
258 // TODO some sensible layout rules.
259- move_tree(surface, new_pos-top_left);
260+ move_tree(surface, new_pos-surface->top_left());
261
262 return true;
263 }
264
265=== modified file 'src/server/shell/canonical_window_manager.h'
266--- src/server/shell/canonical_window_manager.h 2015-04-09 06:20:31 +0000
267+++ src/server/shell/canonical_window_manager.h 2015-04-14 08:39:35 +0000
268@@ -119,6 +119,13 @@
269 bool drag(std::shared_ptr<scene::Surface> surface, geometry::Point to, geometry::Point from, geometry::Rectangle bounds);
270 void move_tree(std::shared_ptr<scene::Surface> const& root, geometry::Displacement movement) const;
271 void raise_tree(std::shared_ptr<scene::Surface> const& root) const;
272+ bool constrained_resize(
273+ std::shared_ptr<scene::Surface> const& surface,
274+ geometry::Point new_pos,
275+ geometry::Size new_size,
276+ const bool left_resize,
277+ const bool top_resize,
278+ geometry::Rectangle const& bounds);
279
280 Tools* const tools;
281 std::shared_ptr<DisplayLayout> const display_layout;
282
283=== modified file 'tests/acceptance-tests/test_client_surfaces.cpp'
284--- tests/acceptance-tests/test_client_surfaces.cpp 2015-04-09 06:20:31 +0000
285+++ tests/acceptance-tests/test_client_surfaces.cpp 2015-04-14 08:39:35 +0000
286@@ -314,9 +314,9 @@
287 *
288 * At least verify the rename completes without blocking...
289 */
290- mir_wait_for_one(mir_surface_set_title(surf, "New Name"));
291- mir_wait_for_one(mir_surface_set_title(surf, ""));
292- mir_wait_for_one(mir_surface_set_title(surf, "Alice"));
293+ mir_surface_set_title(surf, "New Name");
294+ mir_surface_set_title(surf, "");
295+ mir_surface_set_title(surf, "Alice");
296
297 mir_surface_release_sync(surf);
298 }
299
300=== modified file 'tests/acceptance-tests/test_surface_modifications.cpp'
301--- tests/acceptance-tests/test_surface_modifications.cpp 2015-04-02 12:57:34 +0000
302+++ tests/acceptance-tests/test_surface_modifications.cpp 2015-04-14 08:39:35 +0000
303@@ -31,6 +31,7 @@
304 namespace msh = mir::shell;
305 namespace mt = mir::test;
306
307+using namespace mir::geometry;
308 using namespace testing;
309
310 namespace
311@@ -39,6 +40,7 @@
312 {
313 public:
314 MOCK_METHOD1(renamed, void(char const*));
315+ MOCK_METHOD1(resized_to, void(Size const& size));
316 };
317
318 struct StubShell : msh::ShellWrapper
319@@ -80,6 +82,17 @@
320
321 MockSurfaceObserver surface_observer;
322 };
323+
324+MATCHER_P(WidthEq, value, "")
325+{
326+ return Width(value) == arg.width;
327+}
328+
329+MATCHER_P(HeightEq, value, "")
330+{
331+ return Height(value) == arg.height;
332+}
333+
334 }
335
336 TEST_F(SurfaceModifications, rename_is_notified)
337@@ -90,3 +103,60 @@
338
339 mir_surface_set_title(surface, new_title);
340 }
341+
342+TEST_F(SurfaceModifications, surface_spec_name_is_notified)
343+{
344+ auto const new_title = __PRETTY_FUNCTION__;
345+
346+ EXPECT_CALL(surface_observer, renamed(StrEq(new_title)));
347+
348+ auto const spec = mir_connection_create_spec_for_changes(connection);
349+
350+ mir_surface_spec_set_name(spec, new_title);
351+ mir_surface_apply_spec(surface, spec);
352+ mir_surface_spec_release(spec);
353+}
354+
355+TEST_F(SurfaceModifications, surface_spec_resize_is_notified)
356+{
357+ auto const new_width = 5;
358+ auto const new_height = 7;
359+
360+ EXPECT_CALL(surface_observer, resized_to(Size{new_width, new_height}));
361+
362+ auto const spec = mir_connection_create_spec_for_changes(connection);
363+
364+ mir_surface_spec_set_width(spec, new_width);
365+ mir_surface_spec_set_height(spec, new_height);
366+
367+ mir_surface_apply_spec(surface, spec);
368+ mir_surface_spec_release(spec);
369+}
370+
371+TEST_F(SurfaceModifications, surface_spec_change_width_is_notified)
372+{
373+ auto const new_width = 11;
374+
375+ EXPECT_CALL(surface_observer, resized_to(WidthEq(new_width)));
376+
377+ auto const spec = mir_connection_create_spec_for_changes(connection);
378+
379+ mir_surface_spec_set_width(spec, new_width);
380+
381+ mir_surface_apply_spec(surface, spec);
382+ mir_surface_spec_release(spec);
383+}
384+
385+TEST_F(SurfaceModifications, surface_spec_change_height_is_notified)
386+{
387+ auto const new_height = 13;
388+
389+ EXPECT_CALL(surface_observer, resized_to(HeightEq(new_height)));
390+
391+ auto const spec = mir_connection_create_spec_for_changes(connection);
392+
393+ mir_surface_spec_set_height(spec, new_height);
394+
395+ mir_surface_apply_spec(surface, spec);
396+ mir_surface_spec_release(spec);
397+}

Subscribers

People subscribed via source and target branches