Mir

Merge lp:~vanvugt/mir/managed-surface into lp:mir

Proposed by Daniel van Vugt
Status: Work in progress
Proposed branch: lp:~vanvugt/mir/managed-surface
Merge into: lp:mir
Diff against target: 1248 lines (+909/-47)
17 files modified
doc/demo_shell_controls.md (+5/-0)
examples/eglapp.c (+11/-42)
playground/demo-shell/window_manager.cpp (+41/-0)
playground/demo-shell/window_manager.h (+4/-0)
src/include/server/mir/scene/surface_wrapper.h (+83/-0)
src/server/scene/CMakeLists.txt (+2/-0)
src/server/scene/basic_surface.cpp (+3/-2)
src/server/scene/default_configuration.cpp (+1/-0)
src/server/scene/managed_surface.cpp (+161/-0)
src/server/scene/managed_surface.h (+50/-0)
src/server/scene/surface_controller.cpp (+11/-1)
src/server/scene/surface_controller.h (+19/-0)
src/server/scene/surface_wrapper.cpp (+229/-0)
tests/include/mir_test_doubles/mock_surface.h (+5/-0)
tests/unit-tests/scene/CMakeLists.txt (+1/-0)
tests/unit-tests/scene/test_managed_surface.cpp (+249/-0)
tests/unit-tests/scene/test_surface_controller.cpp (+34/-2)
To merge this branch: bzr merge lp:~vanvugt/mir/managed-surface
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Alan Griffiths Disapprove
Robert Carr (community) Disapprove
Alberto Aguirre (community) Needs Fixing
Review via email: mp+244542@code.launchpad.net

Commit message

Introduce surface wrapping and ManagedSurface as a default wrapper to
implement common window management policy.

As a first example this branch implements all the surface states.
Now client calls to mir_surface_set_state actually work. And key combos
have been added to the demo shell for minimize, maximize, fullscreen,
vertmaximize and restoring.

Description of the change

For those who do manual testing, beware you will run into some pre-existing bugs:
https://bugs.launchpad.net/mir/+bugs?field.tag=fullscreen

To post a comment you must log in.
lp:~vanvugt/mir/managed-surface updated
2181. By Daniel van Vugt

Fix clang SIGILL crash by avoiding int-enum pointer casting.

2182. By Daniel van Vugt

Merge latest trunk and fix a conflict.

2183. By Daniel van Vugt

Fix conflict properly.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Robert Carr (robertcarr) wrote :

I wonder if it would be easier (avoiding "SurfaceWrapper"), to use a controller pattern,

e.g. ms::SurfaceController::configure(ms::Surface const&, ...) ms::SurfaceController::resize...etc

Eventually implementation of these methods will require access to a lot of system state. At present, the display layout is pulled in, you can see obviously how it blossoms though, e.g. choosing placement requires looking at existing surfaces.

Likewise it seems as if these managed surface instances may have to share state? for example if you wanted to implement behavior like only one surface can be fullscreen at a time.

I have the thought that it may be easier to encode all this in a centralized controller object. This would make the responsibilities more clear, surface stores the data, the controller object acts as a way to access surface which injects policy as well. What do you think?

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Robert:
I spent over a week trying out the existing controller pattern and discussed it at several team meetings. The result was something that worked, but so ugly that I decided not to propose it (lp:~vanvugt/mir/states). So I spent another week on this one which actually solves a lot more problems, more elegantly.

This branch has added advantages over SurfaceController:
 * You can't call a_scene_surface->some_method() and accidentally bypass the management policy.
 * Any surface functionality can be modified by the shell in future this way.
 * Any surface metadata can be neatly attached to a surface instance by the shell, without touching the core BasicSurface. e.g. the restore location and soon a lot more like decoration state, minimize location, animation state etc.

So this approach solves a whole bunch of problems. And admittedly even during my first prototype where everything was in SurfaceController, I was aware that these other problems would necessitate a surface wrapping approach eventually anyway.

P.S. Any number of surfaces can be full screen on normal desktops right now. While a shell can choose to restrict that, it would be unusual.

lp:~vanvugt/mir/managed-surface updated
2184. By Daniel van Vugt

Merge latest trunk

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

* You can't call a_scene_surface->some_method() and accidentally bypass the management policy.

Hmm true...

 * Any surface functionality can be modified by the shell in future this way.

Kind of a blessing and a curse on this one though right? in the sense that total flexibility means you provide nothing.

 * Any surface metadata can be neatly attached to a surface instance by the shell, without touching the core BasicSurface. e.g. the restore location and soon a lot more like decoration state, minimize location, animation state etc.

This could be solved by association...

I'll investigate your states branch though...still yet to form a full opinion.

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

This branch will conflict with lp:mir right now. But that should be resolved by:
https://code.launchpad.net/~vanvugt/mir/revert-r2165/+merge/245063

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

I'm uneasy about this approach without yet having clear ideas of whether alternatives are any better.

I'm not convinced that the scene surface should be wrapped nor that the wrapper belongs in scene. Wrapping suggests that there is more behavior to Surface than I feel is appropriate. Maybe some of the multiple "Surface" roles need splitting out.

Anyway, I'm rambling. I really don't have an opinion yet.

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

I've looked through the states branch some.

I'm still inclined to lean towards the controller approach. The biggest wart I saw in the states branch was the drag_surface method on SurfaceController. I would have chosen an approach where the shell code implements what you've put in the surface controller (the shell would then just invoke surface_controller->move)...perhaps SurfaceObservers play some role too (reactive approach).

In lack of any clear differentiator for controller v. wrapping I put the following arguments in favor of controller:

1. Easy to start with a smaller interface, e.g. no wrapper of "client_input_fd". Of course, you could call this a blessing or a curse (e.g. is the wrapper interface flexible or vague?).
2. Provides a nice level of decoupling, if shell code is using this controller interface then we gain some freedom on most of the surface interface (much of which could probably be removed...especially if we switch to something like surface->input_target() rather than surface IS a input_target)
3. I speculate (with a fair amount of confidence) that these wrapper objects will end up having to share data with eachother...however in the controller approach the data can remain as private controller state as opposed to psuedo-public data exposed through either the surface interface or the wrapper implementation class (and I guess the shell would dynamic_cast from the interface to wrapper impl).

As for the arguments in favor of surface wrapper

 * You can't call a_scene_surface->some_method() and accidentally bypass the management policy.

I think this can be solved by API if we mandate use of a controller object by the shell.

 * Any surface functionality can be modified by the shell in future this way.

This is the one which is discussed above as a "blessing/curse".

 * Any surface metadata can be neatly attached to a surface instance by the shell, without touching the core BasicSurface. e.g. the restore location and soon a lot more like decoration state, minimize location, animation state etc.

I "prefer association and non member methods".

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

This branch has additional benefits you missed, over the controller branch:

 * No inconsistent hacking of some state information (but not all) and policy into BasicSurface. The other branch required strange bespoke hacks in BasicSurface.

 * This branch solves significantly more future problems which require attaching extra variables to each surface. Oh, maybe I mentioned that.

 * This branch is dramatically cleaner in design than the other one. I've spent several weeks on both approaches and the other one was so ugly it made me depressed frankly. So I'm much more excited about this one and don't really want to think about the other branch.

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

I definitely don't want to suggest that lp:~vanvugt/mir/states is better than this. But I don't like this either.

At the moment I feel that if this really is the best approach then there's something fundamental wrong with the Mir design. I think I'm going to have to try writing some code to get a feel for why more "obvious" solutions don't actually work.

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

It may work well for WM policy affecting only a single surface (e.g. minimize, maximize, etc) but for things that involve state(s) to be applied across a number of surfaces, I imagine there will have to be an encompassing "coordinator" object to oversee the policy is enforced.

I can see the ManagedSurface class morphing into that in the future. Of course, the name would have to change and it should no longer inherit from ms::surface.

I guess my question is how would then a policy involving multiple windows/surfaces be enforced with this approach?

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Actually it's worked out happening backwards to how you describe. We already have a "coordinator" in SurfaceController. And I did start using just that in the previous "states" branch. However I found it to be inadequate for the reasons outlined above.

SurfaceController remains and is still used in this branch. But regardless of how much responsibility you want to give it, at some stage you do need to attach metadata to each surface, beyond what we call BasicSurface. And given we can't predict what every future shell will want to "attach" to each surface, it needs to be something extendible.

The absence of this feature has long been a problem for Unity8. They've had to resort to storing surface information in relatively convoluted ways. Having spoken to Gerry in the past he expressed a preference for this kind of solution. And even within Mir you can see a shell like mir_proving_server needs to attach some extra data to each surface if it wanted (for example) to implement animations (not something we want implemented in Mir but living in the shell code).

So you need to keep in mind two major goals here:
  1. libmirserver implements some sane default window management policy, so that shells don't need to reinvent the wheel each time.
  2. libmirserver needs to provide shells with a convenient mechanism of attaching their own member variables to each surface. Without the overhead of extra association containers to keep in sync.

The only reason Mir isn't yet superior to Compiz is because we haven't yet agreed on how to solve this problem (despite several solutions having been proposed). This being my third or fourth attempt at landing a solution to this problem, I believe this is by far the nicest solution yet. It addresses the main goals and is sufficiently elegant that I'm excited about building on it in future (instead of depressed as the "states" branch made me).

I'm always happy to accept a superior alternate solution. But it needs to be superior to what already exists.

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

It's not a matter of having a superior solution. I'm trying to convince myself (or be convinced) that this is a solution at all for complex use cases involving metadata affecting multiple surfaces.

I don't disagree with shells wanting to attach per-surface metadata. I am more worried about metadata that is NOT per-surface. With this approach, such data would need to be replicated in each ManagedSurface instance. Also, there would have to be a "coordinator" to get the job done, which seems to be missing in this approach (or at least I'm not seeing it).

Perhaps you can provide a concrete example (code would be nice) of how such a complex policy involving multiple surfaces would be enforced. Perhaps a carousel WM that you can slide your finger to turn it to browse various app windows you have open. The surfaces would be rendered on the sides of the carousel. As the carousel is turning, I imagine you'd need to keep track of how much it has turned so you can continue to render your windows in their respective positions around the carousel's perimeter. But how much it has turned is not a per-surface info, and it's awkward to treat it as such.

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

> I don't disagree with shells wanting to attach per-surface metadata. I am more
> worried about metadata that is NOT per-surface. With this approach, such data
> would need to be replicated in each ManagedSurface instance. Also, there would
> have to be a "coordinator" to get the job done, which seems to be missing in
> this approach (or at least I'm not seeing it).

Absolutely that kind of thing will be required for some features. The example I like to think of is snapping ("magnetic") windows that like to align and attach to each other. But I don't intend to use ManagedSurface for everything, and don't intend on any "replication"/duplication.

We do have a "coordinator" already in the pre-existing class "SurfaceController". You don't see it much in this diff though because I didn't have to use it much for the surface states. You do see it used extensively in my previous adventure:
https://code.launchpad.net/~vanvugt/mir/states/+merge/243960

I think when the time comes that we need inter-surface behaviours, some of the wiring I prototyped in the above branch will be introduced.

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

We do many effects like a "carousel" in Compiz and the Mir equivalent of that is already planned in the form of Surface/Renderable::transformation() for arbitrary 3D transformations of surfaces. But we don't really demonstrate it at all other than in mir_demo_standalone_render_surfaces.

When more people make use of Mir's 3D transformations I suspect the class design might change to make it easier to use. Although a shell might decide to ignore it completely and transform everything itself (like Unity8).

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

*Needs Discussion*

I think that my dislike of this and related branches comes from inconsistencies that have crept into the design of Mir.

We started Mir with the intent to have an MVC structure to our system with the model being the shared data representation of the system state, the views being subsystems like compositor, frontend and input and the controller being where the the shell plugs in.

But through a series of pragmatic decisions we've got to a point that is far away from there. There are items missing from the "model" we have in scene (like the output devices), there are things in the model that belong to the controller (like the surface state), there are interactions that bypass the controller and update the model (like the frontend creating surfaces on a session instead of forwarding the request to the shell).

It sort-of-works but it gets increasingly clunky and I think we can usefully rework towards the original intent.

This MP continues in this misguided direction by putting logic and data to handle surface state changes into the model (as ManagedSurface). It is like saying that because the walls of a building are not sound we'll fit a shelf by building a scaffold outside and mount the shelf on a pair of horizontals that come through the window.

I think the right approach is to fix the current architecture rather that trying to work around it. Clearly that implies we should first agree what needs fixing and how.

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

I've tried to outline in improved-tiling-window-management MR some of the ways I'd like to see the architecture improve and how we can really get the window manager as an elegant controller. In light of being convinced it's fatally flawed, I am definitely inclined to lean towards continue working on the controller based approach than add this surface wrapper.

I hate to feel like I am repeating myself a fourth or fifth time on the same topic but I will try and summarize my thoughts again for the benefit of EU/AUS time discussion:

1. Model-View-Controller is a well known and understood pattern which has several additional benefits for us: Decoupling of model object (e.g.) surface from interface used to control it, and an easier way to store intra-surface state.
2. As I've outlined in the tiling-window-management MR I think untangling the controller may be able to provide a significant simplification to our current factory interfaces and the path from session mediator to scene.

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

3. I believe all the arguments in favor of this branch are bunk. I'll outline them trying to skip repetitions of the same argument:
3a. "You can't call a_scene_surface->some_method() and accidentally bypass the management policy."

This can be solved by API.

3b * Any surface functionality can be modified by the shell in future this way.

This is a tautology as an absolutism (define a C++ interface which prevents someone from doing something), and bad interface design as an ideal (maximal flexibility = doing nothing).

3c * Any surface metadata can be neatly attached to a surface instance by the shell, without touching the core BasicSurface. e.g. the restore location and soon a lot more like decoration state, minimize location, animation state etc.

This seems to be inventing a problem to justify a design. We all know this can be trivially solved by association.

3d * So I'm much more excited about this one and don't really want to think about the other branch.

I'm very excited about the improved tiling wm branch and don't really want to think about this branch.

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Alan:
I share your concerns and agree with your statements. If there's a way for us to get to a cleaner design, then I don't mind implementing surface management logic a 4th/5th/6th time. I would like us to be able to land some small first steps, somehow.

Robert:
I think your arguments lack objective justification:

3. OK, demonstrate it in a way that does not make things more complex, again.

3b. Flexibility is a good thing. I aim for code reuse to make things easier in the future. And this has been proven successful in the code I have landed in Mir over the past 2 years.

3c. I am not "inventing a problem". The problem is real as firstly demonstrated below (ManagedSurface contains restore_rect, and in future more such data like minimize_rect). Secondly, it's been clear for a long time that one cannot implement animations for example without storing animation state somewhere. And you agree "somewhere" is required. Your suggested "somewhere" of association is a hack that is inelegant and difficult to maintain. Because a separate associative container not only needs to be kept in sync with the real list of surfaces, but also notified of all surface changes (ManagedSurface solves both these problems easily).

3d. The tiling branch shouldn't come into the discussion yet. It doesn't solve the same problems as this branch does. I remind you of the requirements I seek to fulfil:

  1. libmirserver implements some sane default window management policy, so that shells don't need to reinvent the wheel each time.
  2. libmirserver needs to provide shells with a convenient mechanism of attaching their own member variables to each surface. Without the overhead of extra association containers to keep in sync.

This branch solves both while the tiling branches solve neither (yet).

But a single branch doesn't need to solve both. If it makes people happier, I can divide this one up into smaller pieces.

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

It's worth noting that the window management logic is almost trivial in the grand scheme of things. It's 100 lines long (see 347-450), so 10% of the proposal. Everything else we're talking about here is architectural improvement and making Mir a better codebase for the future...

One can trivially implement those 100 lines of WM logic almost anywhere. The challenge is to make it elegant and reusable to solve other problems too. That's what I'm trying to do here.

lp:~vanvugt/mir/managed-surface updated
2185. By Daniel van Vugt

Merge latest trunk

2186. By Daniel van Vugt

Merge latest trunk

2187. By Daniel van Vugt

Merge latest trunk

2188. By Daniel van Vugt

Merge latest trunk

2189. By Daniel van Vugt

Merge latest trunk

2190. By Daniel van Vugt

Merge latest trunk

2191. By Daniel van Vugt

Merge latest trunk

2192. By Daniel van Vugt

Merge latest trunk

2193. By Daniel van Vugt

Merge latest trunk

2194. By Daniel van Vugt

Merge latest trunk

2195. By Daniel van Vugt

Merge latest trunk

2196. By Daniel van Vugt

Merge latest trunk

2197. By Daniel van Vugt

Merge latest trunk and fix a conflict.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
lp:~vanvugt/mir/managed-surface updated
2198. By Daniel van Vugt

Merge latest trunk

2199. By Daniel van Vugt

Merge latest trunk

2200. By Daniel van Vugt

Merge latest trunk and fix conflicts.

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

Surface wrapper looks like a convenient class to have for mir server clients (though a client could of course roll their own as it's a straightforward wrapper), though that implies the client is willing to use dynamic_cast for downcasting, instead of using other means like associative containers.

As for managed surface, I would prefer a cleaner delineation between model and window management code (which should mostly be in the controller side of things) instead of combining both controller+model data into one object.

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

I didn't choose the name SurfaceWrapper. I forget what I had before but Alan insisted on that name :)

As for pure MVC vs conventional object orientation, yeah I partially agree for some things, but not others. You can see elsewhere I'm trying to make the controller approach available too:
  https://code.launchpad.net/~vanvugt/mir/wire-up-SurfaceController/+merge/246281
which works, and pre-dates this branch. Although I don't think everything would use that.

For example, we still need SurfaceWrapper (or something like it) to attach state to each surface from a bespoke shell, without needing external containers.

I did mention above three days ago that I'm willing to split this into smaller pieces that might better satisfy people in part. The only risk with smaller branches is that people (do) complain about not seeing the bigger picture to understand the intent.

lp:~vanvugt/mir/managed-surface updated
2201. By Daniel van Vugt

Merge latest trunk

2202. By Daniel van Vugt

Add support for the newly introduced mir_surface_state_horizmaximized

2203. By Daniel van Vugt

More tests to cover the new horizmaximized semantics

2204. By Daniel van Vugt

Update docs

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

>> For example, we still need SurfaceWrapper (or something like it) to attach state to each surface
>> from a bespoke shell, without needing external containers.

I prefer this sentence backwards.

"For example, we still need a hash table (or something like it) to attach state to each surface from
 a bespoke shell, without needing surface wrappers"

review: Disapprove
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

I think all this metadata can still be pointed to by a single instance of each surface object instead. We don't need to add new containers for that.

A hash table would obviously work, but it's neither the most efficient nor elegant solution. If you delete a surface for example, you'd also need to add all the logic to ensure the hash tables/maps you're maintaining in parallel get updated. Not to mention other methods during runtime. For example, if someone does set_state(foo) and your bespoke shell has an animation for foo, you need to have some wiring to initiate that. These are the future problems the approach proposed here solves.

While this branch is one example of achieving the goal without adding any new containers, there must be other ways too...

lp:~vanvugt/mir/managed-surface updated
2205. By Daniel van Vugt

Merge latest trunk

2206. By Daniel van Vugt

Fix logical conflict between the new "hidden" state and default
minimize behaviour.

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

BTW, if you want a pure controller approach please help me to make progress on that front too:
https://code.launchpad.net/~vanvugt/mir/wire-up-SurfaceController/+merge/246281

lp:~vanvugt/mir/managed-surface updated
2207. By Daniel van Vugt

Merge latest trunk

2208. By Daniel van Vugt

Merge latest trunk

2209. By Daniel van Vugt

Merge latest trunk

2210. By Daniel van Vugt

Merge latest trunk

2211. By Daniel van Vugt

Fix a conflict from upstream changes.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~vanvugt/mir/managed-surface updated
2212. By Daniel van Vugt

Ping Jenkins

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~vanvugt/mir/managed-surface updated
2213. By Daniel van Vugt

Merge latest trunk

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Bug 1413748 again. Unrelated to the proposal -- it's happening on all branches.

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

> *Needs Discussion*
>
> I think that my dislike of this and related branches comes from
> inconsistencies that have crept into the design of Mir.
>
> We started Mir with the intent to have an MVC structure to our system with the
> model being the shared data representation of the system state, the views
> being subsystems like compositor, frontend and input and the controller being
> where the the shell plugs in.
>
> But through a series of pragmatic decisions we've got to a point that is far
> away from there. There are items missing from the "model" we have in scene
> (like the output devices), there are things in the model that belong to the
> controller (like the surface state), there are interactions that bypass the
> controller and update the model (like the frontend creating surfaces on a
> session instead of forwarding the request to the shell).
>
> It sort-of-works but it gets increasingly clunky and I think we can usefully
> rework towards the original intent.
>
> This MP continues in this misguided direction by putting logic and data to
> handle surface state changes into the model (as ManagedSurface). It is like
> saying that because the walls of a building are not sound we'll fit a shelf by
> building a scaffold outside and mount the shelf on a pair of horizontals that
> come through the window.
>
> I think the right approach is to fix the current architecture rather that
> trying to work around it. Clearly that implies we should first agree what
> needs fixing and how.

Discussions have been had and we're working ong fixing the architecture

review: Disapprove
lp:~vanvugt/mir/managed-surface updated
2214. By Daniel van Vugt

Merge latest trunk.

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

OK, well more of the team might prefer MVC (although that's not yet certain). I'm a bit disappointed this branch isn't going anywhere after being up for review for 7 weeks.

Still, parts of this branch can be easily salvaged for future proposals.

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

Unmerged revisions

2214. By Daniel van Vugt

Merge latest trunk.

2213. By Daniel van Vugt

Merge latest trunk

2212. By Daniel van Vugt

Ping Jenkins

2211. By Daniel van Vugt

Fix a conflict from upstream changes.

2210. By Daniel van Vugt

Merge latest trunk

2209. By Daniel van Vugt

Merge latest trunk

2208. By Daniel van Vugt

Merge latest trunk

2207. By Daniel van Vugt

Merge latest trunk

2206. By Daniel van Vugt

Fix logical conflict between the new "hidden" state and default
minimize behaviour.

2205. By Daniel van Vugt

Merge latest trunk

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'doc/demo_shell_controls.md'
--- doc/demo_shell_controls.md 2015-01-16 02:57:31 +0000
+++ doc/demo_shell_controls.md 2015-01-27 03:20:51 +0000
@@ -46,5 +46,10 @@
46 - Reset display mode to default, on focussed monitor: *Ctrl-Alt-0*46 - Reset display mode to default, on focussed monitor: *Ctrl-Alt-0*
47 - Adjust window opacity/alpha: *Alt-mousewheel*47 - Adjust window opacity/alpha: *Alt-mousewheel*
48 - Zoom in/out: *Super-mousewheel*48 - Zoom in/out: *Super-mousewheel*
49 - Minimize/restore the focussed window: *Alt-F9*
50 - Maximize/restore the focussed window: *Alt-F10*
51 - Fullscreen/restore the focussed window: *Alt-F11*
52 - Vertically maximize/restore the focussed window: *Alt-F12*
53 - Horizontally maximize/restore the focussed window: *Shift-Alt-F12*
4954
50Want more? Log your requests at: https://bugs.launchpad.net/mir/+filebug55Want more? Log your requests at: https://bugs.launchpad.net/mir/+filebug
5156
=== modified file 'examples/eglapp.c'
--- examples/eglapp.c 2015-01-21 00:49:28 +0000
+++ examples/eglapp.c 2015-01-27 03:20:51 +0000
@@ -155,29 +155,6 @@
155 }155 }
156}156}
157157
158static const MirDisplayOutput *find_active_output(
159 const MirDisplayConfiguration *conf)
160{
161 const MirDisplayOutput *output = NULL;
162 int d;
163
164 for (d = 0; d < (int)conf->num_outputs; d++)
165 {
166 const MirDisplayOutput *out = conf->outputs + d;
167
168 if (out->used &&
169 out->connected &&
170 out->num_modes &&
171 out->current_mode < out->num_modes)
172 {
173 output = out;
174 break;
175 }
176 }
177
178 return output;
179}
180
181mir_eglapp_bool mir_eglapp_init(int argc, char *argv[],158mir_eglapp_bool mir_eglapp_init(int argc, char *argv[],
182 unsigned int *width, unsigned int *height)159 unsigned int *width, unsigned int *height)
183{160{
@@ -199,6 +176,7 @@
199 unsigned int output_id = mir_display_output_id_invalid;176 unsigned int output_id = mir_display_output_id_invalid;
200 char *mir_socket = NULL;177 char *mir_socket = NULL;
201 char const* cursor_name = mir_default_cursor_name;178 char const* cursor_name = mir_default_cursor_name;
179 MirSurfaceState initial_state = mir_surface_state_restored;
202180
203 if (argc > 1)181 if (argc > 1)
204 {182 {
@@ -256,8 +234,7 @@
256 }234 }
257 break;235 break;
258 case 'f':236 case 'f':
259 *width = 0;237 initial_state = mir_surface_state_fullscreen;
260 *height = 0;
261 break;238 break;
262 case 's':239 case 's':
263 {240 {
@@ -329,16 +306,6 @@
329 MirDisplayConfiguration* display_config =306 MirDisplayConfiguration* display_config =
330 mir_connection_create_display_config(connection);307 mir_connection_create_display_config(connection);
331308
332 const MirDisplayOutput *output = find_active_output(display_config);
333
334 if (output == NULL)
335 {
336 printf("No active outputs found.\n");
337 return 0;
338 }
339
340 const MirDisplayMode *mode = &output->modes[output->current_mode];
341
342 unsigned int format[mir_pixel_formats];309 unsigned int format[mir_pixel_formats];
343 unsigned int nformats;310 unsigned int nformats;
344311
@@ -360,14 +327,15 @@
360 }327 }
361 }328 }
362329
363 printf("Current active output is %dx%d %+d%+d\n",330 if (*width == 0 && *height == 0)
364 mode->horizontal_resolution, mode->vertical_resolution,331 {
365 output->position_x, output->position_y);332 initial_state = mir_surface_state_fullscreen;
366333
367 if (*width == 0)334 // These should be ignored due to the initial_state, but it's
368 *width = mode->horizontal_resolution;335 // unfortunately required that they're never zero:
369 if (*height == 0)336 *width = 1;
370 *height = mode->vertical_resolution;337 *height = 1;
338 }
371339
372 mir_display_config_destroy(display_config);340 mir_display_config_destroy(display_config);
373341
@@ -397,6 +365,7 @@
397365
398 CHECK(mir_surface_is_valid(surface), "Can't create a surface");366 CHECK(mir_surface_is_valid(surface), "Can't create a surface");
399367
368 mir_surface_set_state(surface, initial_state);
400 mir_surface_set_event_handler(surface, &delegate);369 mir_surface_set_event_handler(surface, &delegate);
401 370
402 MirCursorConfiguration *conf = mir_cursor_configuration_from_name(cursor_name);371 MirCursorConfiguration *conf = mir_cursor_configuration_from_name(cursor_name);
403372
=== modified file 'playground/demo-shell/window_manager.cpp'
--- playground/demo-shell/window_manager.cpp 2015-01-21 21:08:50 +0000
+++ playground/demo-shell/window_manager.cpp 2015-01-27 03:20:51 +0000
@@ -130,6 +130,23 @@
130130
131} // namespace131} // namespace
132132
133void me::WindowManager::toggle(MirSurfaceState state)
134{
135 if (auto const app = focus_controller->focussed_application().lock())
136 {
137 if (auto const surf = app->default_surface())
138 toggle(*surf, state);
139 }
140}
141
142void me::WindowManager::toggle(scene::Surface& surface, MirSurfaceState state)
143{
144 auto new_state = state;
145 if (new_state == surface.state())
146 new_state = mir_surface_state_restored;
147
148 surface.configure(mir_surface_attrib_state, new_state);
149}
133150
134void me::WindowManager::toggle(ColourEffect which)151void me::WindowManager::toggle(ColourEffect which)
135{152{
@@ -217,6 +234,30 @@
217 return true;234 return true;
218 }235 }
219 else if (event.key.modifiers & mir_key_modifier_alt &&236 else if (event.key.modifiers & mir_key_modifier_alt &&
237 event.key.scan_code == KEY_F9)
238 {
239 toggle(mir_surface_state_minimized);
240 }
241 else if (event.key.modifiers & mir_key_modifier_alt &&
242 event.key.scan_code == KEY_F10)
243 {
244 toggle(mir_surface_state_maximized);
245 }
246 else if (event.key.modifiers & mir_key_modifier_alt &&
247 event.key.scan_code == KEY_F11)
248 {
249 toggle(mir_surface_state_fullscreen);
250 }
251 else if (event.key.modifiers & mir_key_modifier_alt &&
252 event.key.scan_code == KEY_F12)
253 {
254 MirSurfaceState state =
255 event.key.modifiers & mir_key_modifier_shift ?
256 mir_surface_state_horizmaximized :
257 mir_surface_state_vertmaximized;
258 toggle(state);
259 }
260 else if (event.key.modifiers & mir_key_modifier_alt &&
220 event.key.scan_code == KEY_F4)261 event.key.scan_code == KEY_F4)
221 {262 {
222 auto const app = focus_controller->focussed_application().lock();263 auto const app = focus_controller->focussed_application().lock();
223264
=== modified file 'playground/demo-shell/window_manager.h'
--- playground/demo-shell/window_manager.h 2015-01-20 10:07:15 +0000
+++ playground/demo-shell/window_manager.h 2015-01-27 03:20:51 +0000
@@ -23,6 +23,7 @@
23#include "mir/input/scene.h"23#include "mir/input/scene.h"
24#include "mir/geometry/displacement.h"24#include "mir/geometry/displacement.h"
25#include "mir/geometry/size.h"25#include "mir/geometry/size.h"
26#include "mir/scene/surface.h"
26#include "demo_renderer.h"27#include "demo_renderer.h"
2728
28#include <memory>29#include <memory>
@@ -66,6 +67,9 @@
66 WindowManager& operator=(const WindowManager&) = delete;67 WindowManager& operator=(const WindowManager&) = delete;
6768
68private:69private:
70 void toggle(MirSurfaceState state);
71 void toggle(scene::Surface& surface, MirSurfaceState state);
72
69 std::shared_ptr<shell::FocusController> focus_controller;73 std::shared_ptr<shell::FocusController> focus_controller;
70 std::shared_ptr<graphics::Display> display;74 std::shared_ptr<graphics::Display> display;
71 std::shared_ptr<compositor::Compositor> compositor;75 std::shared_ptr<compositor::Compositor> compositor;
7276
=== added file 'src/include/server/mir/scene/surface_wrapper.h'
--- src/include/server/mir/scene/surface_wrapper.h 1970-01-01 00:00:00 +0000
+++ src/include/server/mir/scene/surface_wrapper.h 2015-01-27 03:20:51 +0000
@@ -0,0 +1,83 @@
1/*
2 * Copyright © 2014 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com>
17 */
18
19#ifndef MIR_SCENE_SURFACE_WRAPPER_H_
20#define MIR_SCENE_SURFACE_WRAPPER_H_
21
22#include "mir/scene/surface.h"
23#include <memory>
24
25namespace mir { namespace scene {
26
27class SurfaceWrapper : public scene::Surface
28{
29public:
30 SurfaceWrapper(std::shared_ptr<Surface> const& impl);
31 virtual ~SurfaceWrapper();
32
33 // This might look like a long list, but the beauty of this is that once
34 // you inherit from SurfaceWrapper, you will never have to remember
35 // or maintain all these. Just override the function you need...
36
37 virtual std::shared_ptr<mir::input::InputChannel> input_channel() const override;
38 virtual mir::input::InputReceptionMode reception_mode() const override;
39 virtual std::string name() const override;
40 virtual geometry::Point top_left() const override;
41 virtual geometry::Size client_size() const override;
42 virtual geometry::Size size() const override;
43 virtual geometry::Rectangle input_bounds() const override;
44 virtual bool input_area_contains(mir::geometry::Point const&) const override;
45 virtual std::unique_ptr<graphics::Renderable> compositor_snapshot(void const*) const override;
46 virtual float alpha() const override;
47 virtual MirSurfaceType type() const override;
48 virtual MirSurfaceState state() const override;
49 virtual void hide() override;
50 virtual void show() override;
51 virtual bool visible() const override;
52 virtual void move_to(geometry::Point const&) override;
53 virtual void take_input_focus(std::shared_ptr<shell::InputTargeter> const&) override;
54 virtual void set_input_region(std::vector<geometry::Rectangle> const&) override;
55 virtual void allow_framedropping(bool) override;
56 virtual void resize(geometry::Size const&) override;
57 virtual void set_transformation(glm::mat4 const&) override;
58 virtual void set_alpha(float) override;
59 virtual void set_orientation(MirOrientation) override;
60 virtual void force_requests_to_complete() override;
61 virtual void add_observer(std::shared_ptr<SurfaceObserver> const&) override;
62 virtual void remove_observer(std::weak_ptr<SurfaceObserver> const&) override;
63 virtual void set_reception_mode(input::InputReceptionMode mode) override;
64 virtual void consume(MirEvent const&) override;
65 virtual void set_cursor_image(std::shared_ptr<graphics::CursorImage> const&) override;
66 virtual std::shared_ptr<graphics::CursorImage> cursor_image() const override;
67 virtual void request_client_surface_close() override;
68 virtual MirPixelFormat pixel_format() const override;
69 virtual void swap_buffers(graphics::Buffer*, std::function<void(graphics::Buffer*)>) override;
70 virtual bool supports_input() const override;
71 virtual int client_input_fd() const override;
72 virtual int configure(MirSurfaceAttrib, int) override;
73 virtual int query(MirSurfaceAttrib) override;
74 virtual void with_most_recent_buffer_do(std::function<void(graphics::Buffer&)> const& ) override;
75 virtual std::shared_ptr<Surface> parent() const override;
76
77protected:
78 std::shared_ptr<Surface> const raw_surface;
79};
80
81}} // namespace mir::scene
82
83#endif // MIR_SCENE_SURFACE_WRAPPER_H_
084
=== modified file 'src/server/scene/CMakeLists.txt'
--- src/server/scene/CMakeLists.txt 2015-01-14 06:39:13 +0000
+++ src/server/scene/CMakeLists.txt 2015-01-27 03:20:51 +0000
@@ -25,4 +25,6 @@
25 prompt_session_manager_impl.cpp25 prompt_session_manager_impl.cpp
26 rendering_tracker.cpp26 rendering_tracker.cpp
27 default_coordinate_translator.cpp27 default_coordinate_translator.cpp
28 surface_wrapper.cpp
29 managed_surface.cpp
28)30)
2931
=== modified file 'src/server/scene/basic_surface.cpp'
--- src/server/scene/basic_surface.cpp 2015-01-22 03:10:13 +0000
+++ src/server/scene/basic_surface.cpp 2015-01-27 03:20:51 +0000
@@ -367,7 +367,9 @@
367367
368bool ms::BasicSurface::visible(std::unique_lock<std::mutex>&) const368bool ms::BasicSurface::visible(std::unique_lock<std::mutex>&) const
369{369{
370 return !hidden && first_frame_posted;370 return !hidden
371 && first_frame_posted
372 && state_ != mir_surface_state_hidden; // not overridable (?)
371}373}
372374
373mi::InputReceptionMode ms::BasicSurface::reception_mode() const375mi::InputReceptionMode ms::BasicSurface::reception_mode() const
@@ -435,7 +437,6 @@
435 {437 {
436 state_ = s;438 state_ = s;
437 lg.unlock();439 lg.unlock();
438 set_hidden(s == mir_surface_state_hidden);
439 440
440 observers.attrib_changed(mir_surface_attrib_state, s);441 observers.attrib_changed(mir_surface_attrib_state, s);
441 }442 }
442443
=== modified file 'src/server/scene/default_configuration.cpp'
--- src/server/scene/default_configuration.cpp 2015-01-19 17:20:10 +0000
+++ src/server/scene/default_configuration.cpp 2015-01-27 03:20:51 +0000
@@ -90,6 +90,7 @@
90 std::make_shared<ms::SurfaceController>(90 std::make_shared<ms::SurfaceController>(
91 the_surface_factory(),91 the_surface_factory(),
92 the_placement_strategy(),92 the_placement_strategy(),
93 the_shell_display_layout(),
93 the_surface_stack_model()));94 the_surface_stack_model()));
94 });95 });
95}96}
9697
=== added file 'src/server/scene/managed_surface.cpp'
--- src/server/scene/managed_surface.cpp 1970-01-01 00:00:00 +0000
+++ src/server/scene/managed_surface.cpp 2015-01-27 03:20:51 +0000
@@ -0,0 +1,161 @@
1/*
2 * Copyright © 2014 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com>
17 */
18
19#include "managed_surface.h"
20
21namespace mir { namespace scene {
22
23ManagedSurface::ManagedSurface(std::shared_ptr<Surface> const& raw,
24 std::shared_ptr<shell::DisplayLayout> const& layout)
25 : SurfaceWrapper(raw)
26 , display_layout(layout)
27 , restore_rect{raw->top_left(), raw->size()}
28{
29}
30
31ManagedSurface::~ManagedSurface()
32{
33}
34
35int ManagedSurface::configure(MirSurfaceAttrib attrib, int value)
36{
37 int new_value = value;
38
39 if (attrib == mir_surface_attrib_state)
40 new_value = set_state(static_cast<MirSurfaceState>(value));
41
42 return SurfaceWrapper::configure(attrib, new_value);
43}
44
45MirSurfaceState ManagedSurface::set_state(MirSurfaceState desired)
46{
47 // TODO: Eventually this whole function should be atomic (LP: #1395957)
48 geometry::Rectangle old_win{top_left(), size()}, new_win = old_win;
49
50 auto fullscreen = old_win;
51 display_layout->size_to_output(fullscreen);
52
53 // TODO: Shell should define workarea to exclude panels/launchers/docks
54 auto workarea = fullscreen;
55
56 auto old_state = state();
57 if (old_state != desired)
58 {
59 switch (old_state)
60 {
61 case mir_surface_state_minimized:
62 show();
63 break;
64 case mir_surface_state_restored:
65 restore_rect = old_win;
66 break;
67 default:
68 break;
69 }
70 }
71
72 switch (desired)
73 {
74 case mir_surface_state_fullscreen:
75 new_win = fullscreen;
76 break;
77 case mir_surface_state_maximized:
78 new_win = workarea;
79 break;
80 case mir_surface_state_vertmaximized:
81 new_win.top_left.y = workarea.top_left.y;
82 new_win.size.height = workarea.size.height;
83 break;
84 case mir_surface_state_horizmaximized:
85 new_win.top_left.x = workarea.top_left.x;
86 new_win.size.width = workarea.size.width;
87 break;
88 case mir_surface_state_restored:
89 new_win = restore_rect;
90 break;
91 case mir_surface_state_minimized:
92 hide();
93 break;
94 default:
95 break;
96 }
97
98 if (new_win != old_win)
99 {
100 /*
101 * Important: Call to parent class move_to/resize functions.
102 * We don't want policy enforcement of this class getting in the way
103 * here because our own versions will switch based on current state(),
104 * which is incorrect behaviour for the 'desired' new state.
105 */
106 SurfaceWrapper::move_to(new_win.top_left);
107 SurfaceWrapper::resize(new_win.size);
108 }
109
110 // TODO: In future the desired state may be rejected based on other
111 // factors such as surface type.
112 return desired;
113}
114
115void ManagedSurface::move_to(geometry::Point const& desired)
116{
117 // TODO: Eventually this whole function should be atomic (LP: #1395957)
118 auto new_pos = desired;
119
120 switch (state())
121 {
122 case mir_surface_state_fullscreen:
123 case mir_surface_state_maximized:
124 return;
125 case mir_surface_state_vertmaximized:
126 new_pos.y = top_left().y;
127 break;
128 case mir_surface_state_horizmaximized:
129 new_pos.x = top_left().x;
130 break;
131 default:
132 break;
133 }
134
135 SurfaceWrapper::move_to(new_pos);
136}
137
138void ManagedSurface::resize(geometry::Size const& desired)
139{
140 // TODO: Eventually this whole function should be atomic (LP: #1395957)
141 auto new_size = desired;
142
143 switch (state())
144 {
145 case mir_surface_state_fullscreen:
146 case mir_surface_state_maximized:
147 return;
148 case mir_surface_state_vertmaximized:
149 new_size.height = size().height;
150 break;
151 case mir_surface_state_horizmaximized:
152 new_size.width = size().width;
153 break;
154 default:
155 break;
156 }
157
158 SurfaceWrapper::resize(new_size);
159}
160
161}} // namespace mir::scene
0162
=== added file 'src/server/scene/managed_surface.h'
--- src/server/scene/managed_surface.h 1970-01-01 00:00:00 +0000
+++ src/server/scene/managed_surface.h 2015-01-27 03:20:51 +0000
@@ -0,0 +1,50 @@
1/*
2 * Copyright © 2014 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com>
17 */
18
19#ifndef MIR_SCENE_MANAGED_SURFACE_H_
20#define MIR_SCENE_MANAGED_SURFACE_H_
21
22#include "mir/scene/surface_wrapper.h"
23#include "mir/shell/display_layout.h"
24#include "mir/geometry/rectangle.h"
25#include "mir_toolkit/common.h"
26#include <memory>
27
28namespace mir { namespace scene {
29
30class ManagedSurface : public SurfaceWrapper
31{
32public:
33 ManagedSurface(std::shared_ptr<Surface> const&,
34 std::shared_ptr<shell::DisplayLayout> const&);
35 virtual ~ManagedSurface();
36
37 int configure(MirSurfaceAttrib attrib, int value) override;
38 void move_to(geometry::Point const&) override;
39 void resize(geometry::Size const&) override;
40
41private:
42 std::shared_ptr<shell::DisplayLayout> const display_layout;
43 geometry::Rectangle restore_rect;
44
45 MirSurfaceState set_state(MirSurfaceState state);
46};
47
48}} // namespace mir::scene
49
50#endif // MIR_SCENE_MANAGED_SURFACE_H_
051
=== modified file 'src/server/scene/surface_controller.cpp'
--- src/server/scene/surface_controller.cpp 2015-01-14 06:39:13 +0000
+++ src/server/scene/surface_controller.cpp 2015-01-27 03:20:51 +0000
@@ -21,26 +21,36 @@
21#include "mir/scene/surface_factory.h"21#include "mir/scene/surface_factory.h"
22#include "mir/scene/surface.h"22#include "mir/scene/surface.h"
23#include "mir/scene/placement_strategy.h"23#include "mir/scene/placement_strategy.h"
24#include "mir/shell/display_layout.h"
25#include "managed_surface.h"
2426
25namespace ms = mir::scene;27namespace ms = mir::scene;
2628
27ms::SurfaceController::SurfaceController(29ms::SurfaceController::SurfaceController(
28 std::shared_ptr<SurfaceFactory> const& surface_factory,30 std::shared_ptr<SurfaceFactory> const& surface_factory,
29 std::shared_ptr<ms::PlacementStrategy> const& placement_strategy,31 std::shared_ptr<ms::PlacementStrategy> const& placement_strategy,
32 std::shared_ptr<shell::DisplayLayout> const& display_layout,
30 std::shared_ptr<SurfaceStackModel> const& surface_stack) :33 std::shared_ptr<SurfaceStackModel> const& surface_stack) :
31 surface_factory(surface_factory),34 surface_factory(surface_factory),
32 placement_strategy(placement_strategy),35 placement_strategy(placement_strategy),
36 display_layout(display_layout),
33 surface_stack(surface_stack)37 surface_stack(surface_stack)
34{38{
35}39}
3640
41std::shared_ptr<ms::Surface> ms::SurfaceController::wrap_surface(
42 std::shared_ptr<ms::Surface> const& raw)
43{
44 return std::make_shared<ManagedSurface>(raw, display_layout);
45}
46
37std::shared_ptr<ms::Surface> ms::SurfaceController::add_surface(47std::shared_ptr<ms::Surface> ms::SurfaceController::add_surface(
38 SurfaceCreationParameters const& params,48 SurfaceCreationParameters const& params,
39 Session* session)49 Session* session)
40{50{
41 auto placed_params = placement_strategy->place(*session, params);51 auto placed_params = placement_strategy->place(*session, params);
4252
43 auto const surface = surface_factory->create_surface(placed_params);53 auto const surface = wrap_surface(surface_factory->create_surface(placed_params));
44 surface_stack->add_surface(surface, placed_params.depth, placed_params.input_mode);54 surface_stack->add_surface(surface, placed_params.depth, placed_params.input_mode);
45 return surface;55 return surface;
46}56}
4757
=== modified file 'src/server/scene/surface_controller.h'
--- src/server/scene/surface_controller.h 2015-01-14 06:39:13 +0000
+++ src/server/scene/surface_controller.h 2015-01-27 03:20:51 +0000
@@ -24,6 +24,9 @@
2424
25namespace mir25namespace mir
26{26{
27
28namespace shell { class DisplayLayout; }
29
27namespace scene30namespace scene
28{31{
29class PlacementStrategy;32class PlacementStrategy;
@@ -37,6 +40,7 @@
37 SurfaceController(40 SurfaceController(
38 std::shared_ptr<SurfaceFactory> const& surface_factory,41 std::shared_ptr<SurfaceFactory> const& surface_factory,
39 std::shared_ptr<PlacementStrategy> const& placement_strategy,42 std::shared_ptr<PlacementStrategy> const& placement_strategy,
43 std::shared_ptr<shell::DisplayLayout> const& display_layout,
40 std::shared_ptr<SurfaceStackModel> const& surface_stack);44 std::shared_ptr<SurfaceStackModel> const& surface_stack);
4145
42 std::shared_ptr<Surface> add_surface(46 std::shared_ptr<Surface> add_surface(
@@ -47,9 +51,24 @@
4751
48 void raise(std::weak_ptr<Surface> const& surface) override;52 void raise(std::weak_ptr<Surface> const& surface) override;
4953
54 /**
55 * wrap_surface allows you wrap ("decorate") a surface in your own
56 * window management policy-enforcing class. It's important to keep
57 * the wrapping stage out of SurfaceFactory, so that a shell may choose
58 * to both partly reuse the default wrapper (ManagedSurface) for
59 * window management logic while also retaining access to the underlying
60 * BasicSurface if it wants to do anything that would be disallowed by
61 * the default policy of ManagedSurface.
62 * TODO: Move this up to SurfaceCoordinator (or some bespoke factory)
63 * in the public API later.
64 */
65 virtual std::shared_ptr<Surface>
66 wrap_surface(std::shared_ptr<Surface> const& raw);
67
50private:68private:
51 std::shared_ptr<SurfaceFactory> const surface_factory;69 std::shared_ptr<SurfaceFactory> const surface_factory;
52 std::shared_ptr<PlacementStrategy> const placement_strategy;70 std::shared_ptr<PlacementStrategy> const placement_strategy;
71 std::shared_ptr<shell::DisplayLayout> const display_layout;
53 std::shared_ptr<SurfaceStackModel> const surface_stack;72 std::shared_ptr<SurfaceStackModel> const surface_stack;
54};73};
5574
5675
=== added file 'src/server/scene/surface_wrapper.cpp'
--- src/server/scene/surface_wrapper.cpp 1970-01-01 00:00:00 +0000
+++ src/server/scene/surface_wrapper.cpp 2015-01-27 03:20:51 +0000
@@ -0,0 +1,229 @@
1/*
2 * Copyright © 2014 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com>
17 */
18
19#include "mir/scene/surface_wrapper.h"
20
21namespace mir { namespace scene {
22
23SurfaceWrapper::SurfaceWrapper(std::shared_ptr<Surface> const& impl)
24 : raw_surface(impl)
25{
26}
27
28SurfaceWrapper::~SurfaceWrapper()
29{
30}
31
32std::shared_ptr<mir::input::InputChannel> SurfaceWrapper::input_channel() const
33{
34 return raw_surface->input_channel();
35}
36
37mir::input::InputReceptionMode SurfaceWrapper::reception_mode() const
38{
39 return raw_surface->reception_mode();
40}
41
42std::string SurfaceWrapper::name() const
43{
44 return raw_surface->name();
45}
46
47geometry::Point SurfaceWrapper::top_left() const
48{
49 return raw_surface->top_left();
50}
51
52geometry::Size SurfaceWrapper::client_size() const
53{
54 return raw_surface->client_size();
55}
56
57geometry::Size SurfaceWrapper::size() const
58{
59 return raw_surface->size();
60}
61
62geometry::Rectangle SurfaceWrapper::input_bounds() const
63{
64 return raw_surface->input_bounds();
65}
66
67bool SurfaceWrapper::input_area_contains(mir::geometry::Point const& p) const
68{
69 return raw_surface->input_area_contains(p);
70}
71
72std::unique_ptr<graphics::Renderable> SurfaceWrapper::compositor_snapshot(void const* id) const
73{
74 return raw_surface->compositor_snapshot(id);
75}
76
77float SurfaceWrapper::alpha() const
78{
79 return raw_surface->alpha();
80}
81
82MirSurfaceType SurfaceWrapper::type() const
83{
84 return raw_surface->type();
85}
86
87MirSurfaceState SurfaceWrapper::state() const
88{
89 return raw_surface->state();
90}
91
92void SurfaceWrapper::hide()
93{
94 raw_surface->hide();
95}
96
97void SurfaceWrapper::show()
98{
99 raw_surface->show();
100}
101
102bool SurfaceWrapper::visible() const
103{
104 return raw_surface->visible();
105}
106
107void SurfaceWrapper::move_to(geometry::Point const& p)
108{
109 raw_surface->move_to(p);
110}
111
112void SurfaceWrapper::take_input_focus(std::shared_ptr<shell::InputTargeter> const& t)
113{
114 raw_surface->take_input_focus(t);
115}
116
117void SurfaceWrapper::set_input_region(std::vector<geometry::Rectangle> const& r)
118{
119 raw_surface->set_input_region(r);
120}
121
122void SurfaceWrapper::allow_framedropping(bool b)
123{
124 raw_surface->allow_framedropping(b);
125}
126
127void SurfaceWrapper::resize(geometry::Size const& s)
128{
129 raw_surface->resize(s);
130}
131
132void SurfaceWrapper::set_transformation(glm::mat4 const& t)
133{
134 raw_surface->set_transformation(t);
135}
136
137void SurfaceWrapper::set_alpha(float a)
138{
139 raw_surface->set_alpha(a);
140}
141
142void SurfaceWrapper::set_orientation(MirOrientation orientation)
143{
144 raw_surface->set_orientation(orientation);
145}
146
147void SurfaceWrapper::force_requests_to_complete()
148{
149 raw_surface->force_requests_to_complete();
150}
151
152void SurfaceWrapper::add_observer(std::shared_ptr<SurfaceObserver> const& ob)
153{
154 raw_surface->add_observer(ob);
155}
156
157void SurfaceWrapper::remove_observer(std::weak_ptr<SurfaceObserver> const& ob)
158{
159 raw_surface->remove_observer(ob);
160}
161
162void SurfaceWrapper::set_reception_mode(input::InputReceptionMode mode)
163{
164 raw_surface->set_reception_mode(mode);
165}
166
167void SurfaceWrapper::consume(MirEvent const& e)
168{
169 raw_surface->consume(e);
170}
171
172void SurfaceWrapper::set_cursor_image(std::shared_ptr<graphics::CursorImage> const& i)
173{
174 raw_surface->set_cursor_image(i);
175}
176
177std::shared_ptr<graphics::CursorImage> SurfaceWrapper::cursor_image() const
178{
179 return raw_surface->cursor_image();
180}
181
182void SurfaceWrapper::request_client_surface_close()
183{
184 raw_surface->request_client_surface_close();
185}
186
187MirPixelFormat SurfaceWrapper::pixel_format() const
188{
189 return raw_surface->pixel_format();
190}
191
192void SurfaceWrapper::swap_buffers(graphics::Buffer* old_buffer,
193 std::function<void(graphics::Buffer*)> callback)
194{
195 raw_surface->swap_buffers(old_buffer, callback);
196}
197
198bool SurfaceWrapper::supports_input() const
199{
200 return raw_surface->supports_input();
201}
202
203int SurfaceWrapper::client_input_fd() const
204{
205 return raw_surface->client_input_fd();
206}
207
208int SurfaceWrapper::configure(MirSurfaceAttrib a, int v)
209{
210 return raw_surface->configure(a, v);
211}
212
213int SurfaceWrapper::query(MirSurfaceAttrib a)
214{
215 return raw_surface->query(a);
216}
217
218void SurfaceWrapper::with_most_recent_buffer_do(
219 std::function<void(graphics::Buffer&)> const& callback)
220{
221 raw_surface->with_most_recent_buffer_do(callback);
222}
223
224std::shared_ptr<Surface> SurfaceWrapper::parent() const
225{
226 return raw_surface->parent();
227}
228
229}} // namespace mir::scene
0230
=== modified file 'tests/include/mir_test_doubles/mock_surface.h'
--- tests/include/mir_test_doubles/mock_surface.h 2015-01-14 06:39:13 +0000
+++ tests/include/mir_test_doubles/mock_surface.h 2015-01-27 03:20:51 +0000
@@ -57,6 +57,11 @@
57 MOCK_METHOD0(force_requests_to_complete, void());57 MOCK_METHOD0(force_requests_to_complete, void());
58 MOCK_METHOD0(advance_client_buffer, std::shared_ptr<graphics::Buffer>());58 MOCK_METHOD0(advance_client_buffer, std::shared_ptr<graphics::Buffer>());
5959
60 MOCK_CONST_METHOD0(state, MirSurfaceState());
61
62 MOCK_METHOD1(move_to, void(geometry::Point const&));
63 MOCK_CONST_METHOD0(top_left, geometry::Point());
64 MOCK_METHOD1(resize, void(geometry::Size const&));
60 MOCK_CONST_METHOD0(size, geometry::Size());65 MOCK_CONST_METHOD0(size, geometry::Size());
61 MOCK_CONST_METHOD0(pixel_format, MirPixelFormat());66 MOCK_CONST_METHOD0(pixel_format, MirPixelFormat());
6267
6368
=== modified file 'tests/unit-tests/scene/CMakeLists.txt'
--- tests/unit-tests/scene/CMakeLists.txt 2015-01-14 06:39:13 +0000
+++ tests/unit-tests/scene/CMakeLists.txt 2015-01-27 03:20:51 +0000
@@ -15,6 +15,7 @@
15 ${CMAKE_CURRENT_SOURCE_DIR}/test_surface.cpp15 ${CMAKE_CURRENT_SOURCE_DIR}/test_surface.cpp
16 ${CMAKE_CURRENT_SOURCE_DIR}/test_surface_impl.cpp16 ${CMAKE_CURRENT_SOURCE_DIR}/test_surface_impl.cpp
17 ${CMAKE_CURRENT_SOURCE_DIR}/test_basic_surface.cpp17 ${CMAKE_CURRENT_SOURCE_DIR}/test_basic_surface.cpp
18 ${CMAKE_CURRENT_SOURCE_DIR}/test_managed_surface.cpp
18 ${CMAKE_CURRENT_SOURCE_DIR}/test_surface_stack.cpp19 ${CMAKE_CURRENT_SOURCE_DIR}/test_surface_stack.cpp
19 ${CMAKE_CURRENT_SOURCE_DIR}/test_surface_controller.cpp20 ${CMAKE_CURRENT_SOURCE_DIR}/test_surface_controller.cpp
20 ${CMAKE_CURRENT_SOURCE_DIR}/test_legacy_scene_change_notification.cpp21 ${CMAKE_CURRENT_SOURCE_DIR}/test_legacy_scene_change_notification.cpp
2122
=== added file 'tests/unit-tests/scene/test_managed_surface.cpp'
--- tests/unit-tests/scene/test_managed_surface.cpp 1970-01-01 00:00:00 +0000
+++ tests/unit-tests/scene/test_managed_surface.cpp 2015-01-27 03:20:51 +0000
@@ -0,0 +1,249 @@
1/*
2 * Copyright © 2014 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com>
17 */
18
19#include "src/server/scene/managed_surface.h"
20#include "mir_test_doubles/mock_surface.h"
21#include "mir_test_doubles/mock_display_layout.h"
22#include <gtest/gtest.h>
23#include <gmock/gmock.h>
24
25using namespace testing;
26using namespace mir::scene;
27using namespace mir::geometry;
28using namespace mir::test::doubles;
29
30struct ManagedSurfaceTest : public Test
31{
32 std::shared_ptr<MockDisplayLayout>
33 mock_display_layout{std::make_shared<NiceMock<MockDisplayLayout>>()};
34
35 std::shared_ptr<MockSurface>
36 mock_basic_surface{std::make_shared<NiceMock<MockSurface>>()};
37 MirSurfaceState state_ = mir_surface_state_restored;
38 Rectangle position{{12,34}, {56,78}};
39
40 Rectangle const random_place{{31,41}, {59,26}};
41 Rectangle const fullscreen{{0,0}, {1366,768}};
42 Rectangle const maximized{fullscreen}; // will be different in future
43
44 void SetUp()
45 {
46 ON_CALL(*mock_display_layout, size_to_output(_))
47 .WillByDefault(SetArgReferee<0>(fullscreen));
48
49 // This could be served better by a FakeSurface later, but this
50 // requires less code for now.
51 ON_CALL(*mock_basic_surface, size())
52 .WillByDefault(ReturnPointee(&position.size));
53 ON_CALL(*mock_basic_surface, resize(_))
54 .WillByDefault(SaveArg<0>(&position.size));
55
56 ON_CALL(*mock_basic_surface, top_left())
57 .WillByDefault(ReturnPointee(&position.top_left));
58 ON_CALL(*mock_basic_surface, move_to(_))
59 .WillByDefault(SaveArg<0>(&position.top_left));
60
61 ON_CALL(*mock_basic_surface, state())
62 .WillByDefault(ReturnPointee(&state_));
63 ON_CALL(*mock_basic_surface, configure(mir_surface_attrib_state, _))
64 .WillByDefault(Invoke(
65 [this](MirSurfaceAttrib, int v) -> int
66 {
67 state_ = (MirSurfaceState)v;
68 return v;
69 }
70 ));
71 }
72};
73
74TEST_F(ManagedSurfaceTest, goes_fullscreen_and_restores)
75{
76 ManagedSurface surf(mock_basic_surface, mock_display_layout);
77
78 Rectangle const restored{surf.top_left(), surf.size()};
79 ASSERT_NE(fullscreen, restored);
80
81 InSequence seq;
82 EXPECT_CALL(*mock_basic_surface, move_to(fullscreen.top_left));
83 EXPECT_CALL(*mock_basic_surface, resize(fullscreen.size));
84 EXPECT_CALL(*mock_basic_surface, move_to(restored.top_left));
85 EXPECT_CALL(*mock_basic_surface, resize(restored.size));
86
87 surf.configure(mir_surface_attrib_state, mir_surface_state_fullscreen);
88 surf.configure(mir_surface_attrib_state, mir_surface_state_restored);
89}
90
91TEST_F(ManagedSurfaceTest, goes_maximized_and_restores)
92{
93 ManagedSurface surf(mock_basic_surface, mock_display_layout);
94
95 Rectangle const restored{surf.top_left(), surf.size()};
96 ASSERT_NE(maximized, restored);
97
98 InSequence seq;
99 EXPECT_CALL(*mock_basic_surface, move_to(maximized.top_left));
100 EXPECT_CALL(*mock_basic_surface, resize(maximized.size));
101 EXPECT_CALL(*mock_basic_surface, move_to(restored.top_left));
102 EXPECT_CALL(*mock_basic_surface, resize(restored.size));
103
104 surf.configure(mir_surface_attrib_state, mir_surface_state_maximized);
105 surf.configure(mir_surface_attrib_state, mir_surface_state_restored);
106}
107
108TEST_F(ManagedSurfaceTest, goes_vertmaximized_and_restores)
109{
110 ManagedSurface surf(mock_basic_surface, mock_display_layout);
111
112 Rectangle const restored{surf.top_left(), surf.size()};
113 ASSERT_NE(maximized, restored);
114
115 Rectangle const vertmaximized{
116 {restored.top_left.x, maximized.top_left.y},
117 {restored.size.width, maximized.size.height} };
118
119 InSequence seq;
120 EXPECT_CALL(*mock_basic_surface, move_to(vertmaximized.top_left));
121 EXPECT_CALL(*mock_basic_surface, resize(vertmaximized.size));
122 EXPECT_CALL(*mock_basic_surface, move_to(restored.top_left));
123 EXPECT_CALL(*mock_basic_surface, resize(restored.size));
124
125 surf.configure(mir_surface_attrib_state, mir_surface_state_vertmaximized);
126 surf.configure(mir_surface_attrib_state, mir_surface_state_restored);
127}
128
129TEST_F(ManagedSurfaceTest, goes_horizmaximized_and_restores)
130{
131 ManagedSurface surf(mock_basic_surface, mock_display_layout);
132
133 Rectangle const restored{surf.top_left(), surf.size()};
134 ASSERT_NE(maximized, restored);
135
136 Rectangle const horizmaximized{
137 {maximized.top_left.x, restored.top_left.y},
138 {maximized.size.width, restored.size.height} };
139
140 InSequence seq;
141 EXPECT_CALL(*mock_basic_surface, move_to(horizmaximized.top_left));
142 EXPECT_CALL(*mock_basic_surface, resize(horizmaximized.size));
143 EXPECT_CALL(*mock_basic_surface, move_to(restored.top_left));
144 EXPECT_CALL(*mock_basic_surface, resize(restored.size));
145
146 surf.configure(mir_surface_attrib_state, mir_surface_state_horizmaximized);
147 surf.configure(mir_surface_attrib_state, mir_surface_state_restored);
148}
149
150TEST_F(ManagedSurfaceTest, goes_minimized_and_restores)
151{
152 ManagedSurface surf(mock_basic_surface, mock_display_layout);
153
154 InSequence seq;
155 EXPECT_CALL(*mock_basic_surface, hide());
156 EXPECT_CALL(*mock_basic_surface, show());
157
158 surf.configure(mir_surface_attrib_state, mir_surface_state_minimized);
159 surf.configure(mir_surface_attrib_state, mir_surface_state_restored);
160}
161
162TEST_F(ManagedSurfaceTest, multistate_restores_to_original)
163{
164 ManagedSurface surf(mock_basic_surface, mock_display_layout);
165 Rectangle const restored{surf.top_left(), surf.size()};
166
167 surf.configure(mir_surface_attrib_state, mir_surface_state_vertmaximized);
168 surf.move_to({surf.top_left().x.as_int() + 5, surf.top_left().y});
169 EXPECT_NE(restored.top_left, surf.top_left());
170
171 surf.configure(mir_surface_attrib_state, mir_surface_state_fullscreen);
172 EXPECT_EQ(fullscreen.top_left, surf.top_left());
173 EXPECT_EQ(fullscreen.size, surf.size());
174
175 surf.configure(mir_surface_attrib_state, mir_surface_state_restored);
176 EXPECT_EQ(restored.top_left, surf.top_left());
177 EXPECT_EQ(restored.size, surf.size());
178}
179
180TEST_F(ManagedSurfaceTest, fullscreen_cant_move)
181{
182 ManagedSurface surf(mock_basic_surface, mock_display_layout);
183
184 Rectangle const restored{surf.top_left(), surf.size()};
185 ASSERT_NE(fullscreen, restored);
186
187 surf.configure(mir_surface_attrib_state, mir_surface_state_fullscreen);
188 surf.move_to(random_place.top_left);
189 surf.resize(random_place.size);
190 ASSERT_NE(random_place, fullscreen);
191 EXPECT_EQ(fullscreen.top_left, surf.top_left());
192 EXPECT_EQ(fullscreen.size, surf.size());
193}
194
195TEST_F(ManagedSurfaceTest, maximized_cant_move)
196{
197 ManagedSurface surf(mock_basic_surface, mock_display_layout);
198
199 Rectangle const restored{surf.top_left(), surf.size()};
200 ASSERT_NE(maximized, restored);
201
202 surf.configure(mir_surface_attrib_state, mir_surface_state_maximized);
203 surf.move_to(random_place.top_left);
204 surf.resize(random_place.size);
205 ASSERT_NE(random_place, maximized);
206 EXPECT_EQ(maximized.top_left, surf.top_left());
207 EXPECT_EQ(maximized.size, surf.size());
208}
209
210TEST_F(ManagedSurfaceTest, vertmaximized_can_move_only_horizontally)
211{
212 ManagedSurface surf(mock_basic_surface, mock_display_layout);
213
214 surf.configure(mir_surface_attrib_state, mir_surface_state_vertmaximized);
215 surf.move_to(random_place.top_left);
216 surf.resize(random_place.size);
217 EXPECT_EQ(random_place.top_left.x, surf.top_left().x);
218 EXPECT_EQ(maximized.top_left.y, surf.top_left().y);
219 EXPECT_EQ(random_place.size.width, surf.size().width);
220 EXPECT_EQ(maximized.size.height, surf.size().height);
221}
222
223TEST_F(ManagedSurfaceTest, horizmaximized_can_move_only_vertically)
224{
225 ManagedSurface surf(mock_basic_surface, mock_display_layout);
226
227 surf.configure(mir_surface_attrib_state, mir_surface_state_horizmaximized);
228 surf.move_to(random_place.top_left);
229 surf.resize(random_place.size);
230 EXPECT_EQ(maximized.top_left.x, surf.top_left().x);
231 EXPECT_EQ(random_place.top_left.y, surf.top_left().y);
232 EXPECT_EQ(maximized.size.width, surf.size().width);
233 EXPECT_EQ(random_place.size.height, surf.size().height);
234}
235
236TEST_F(ManagedSurfaceTest, restored_can_move_freely)
237{
238 ManagedSurface surf(mock_basic_surface, mock_display_layout);
239
240 Rectangle const restored{surf.top_left(), surf.size()};
241 EXPECT_NE(restored, random_place);
242
243 surf.configure(mir_surface_attrib_state, mir_surface_state_restored);
244 surf.move_to(random_place.top_left);
245 surf.resize(random_place.size);
246
247 EXPECT_EQ(random_place.top_left, surf.top_left());
248 EXPECT_EQ(random_place.size, surf.size());
249}
0250
=== modified file 'tests/unit-tests/scene/test_surface_controller.cpp'
--- tests/unit-tests/scene/test_surface_controller.cpp 2015-01-14 06:39:13 +0000
+++ tests/unit-tests/scene/test_surface_controller.cpp 2015-01-27 03:20:51 +0000
@@ -24,6 +24,7 @@
24#include "mir_test_doubles/stub_scene_session.h"24#include "mir_test_doubles/stub_scene_session.h"
2525
26#include "mir_test_doubles/mock_surface.h"26#include "mir_test_doubles/mock_surface.h"
27#include "mir_test_doubles/mock_display_layout.h"
27#include "mir_test/fake_shared.h"28#include "mir_test/fake_shared.h"
2829
29#include <gtest/gtest.h>30#include <gtest/gtest.h>
@@ -62,7 +63,8 @@
62struct SurfaceController : testing::Test63struct SurfaceController : testing::Test
63{64{
64 MockPlacementStrategy placement_strategy;65 MockPlacementStrategy placement_strategy;
65 mtd::MockSurface mock_surface;66 testing::NiceMock<mtd::MockDisplayLayout> mock_display_layout;
67 testing::NiceMock<mtd::MockSurface> mock_surface;
66 std::shared_ptr<ms::Surface> const expect_surface = mt::fake_shared(mock_surface);68 std::shared_ptr<ms::Surface> const expect_surface = mt::fake_shared(mock_surface);
67 testing::NiceMock<MockSurfaceAllocator> mock_surface_allocator;69 testing::NiceMock<MockSurfaceAllocator> mock_surface_allocator;
68 MockSurfaceStackModel model;70 MockSurfaceStackModel model;
@@ -73,6 +75,10 @@
73 using namespace ::testing;75 using namespace ::testing;
74 ON_CALL(mock_surface_allocator, create_surface(_)).WillByDefault(Return(expect_surface));76 ON_CALL(mock_surface_allocator, create_surface(_)).WillByDefault(Return(expect_surface));
75 ON_CALL(placement_strategy, place(_, _)).WillByDefault(ReturnArg<1>());77 ON_CALL(placement_strategy, place(_, _)).WillByDefault(ReturnArg<1>());
78 ON_CALL(mock_surface, size())
79 .WillByDefault(Return(geom::Size{12,34}));
80 ON_CALL(mock_surface, top_left())
81 .WillByDefault(Return(geom::Point{56,78}));
76 }82 }
77};83};
78}84}
@@ -81,11 +87,34 @@
81{87{
82 using namespace ::testing;88 using namespace ::testing;
8389
84 ms::SurfaceController controller(90 class MockSurfaceController : public ms::SurfaceController
91 {
92 public:
93 MockSurfaceController(
94 std::shared_ptr<ms::SurfaceFactory> const& surface_factory,
95 std::shared_ptr<ms::PlacementStrategy> const& placement_strategy,
96 std::shared_ptr<msh::DisplayLayout> const& display_layout,
97 std::shared_ptr<ms::SurfaceStackModel> const& surface_stack)
98 : ms::SurfaceController(surface_factory,
99 placement_strategy,
100 display_layout,
101 surface_stack)
102 {
103 }
104
105 MOCK_METHOD1(wrap_surface, std::shared_ptr<ms::Surface>(
106 std::shared_ptr<ms::Surface> const&));
107 };
108
109 MockSurfaceController controller(
85 mt::fake_shared(mock_surface_allocator),110 mt::fake_shared(mock_surface_allocator),
86 mt::fake_shared(placement_strategy),111 mt::fake_shared(placement_strategy),
112 mt::fake_shared(mock_display_layout),
87 mt::fake_shared(model));113 mt::fake_shared(model));
88114
115 EXPECT_CALL(controller, wrap_surface(expect_surface))
116 .WillOnce(Return(expect_surface));
117
89 InSequence seq;118 InSequence seq;
90 EXPECT_CALL(placement_strategy, place(_, _)).Times(1);119 EXPECT_CALL(placement_strategy, place(_, _)).Times(1);
91 EXPECT_CALL(mock_surface_allocator, create_surface(_)).Times(1).WillOnce(Return(expect_surface));120 EXPECT_CALL(mock_surface_allocator, create_surface(_)).Times(1).WillOnce(Return(expect_surface));
@@ -105,6 +134,7 @@
105 ms::SurfaceController controller(134 ms::SurfaceController controller(
106 mt::fake_shared(mock_surface_allocator),135 mt::fake_shared(mock_surface_allocator),
107 mt::fake_shared(placement_strategy),136 mt::fake_shared(placement_strategy),
137 mt::fake_shared(mock_display_layout),
108 mt::fake_shared(model));138 mt::fake_shared(model));
109139
110 EXPECT_CALL(model, raise(_)).Times(1);140 EXPECT_CALL(model, raise(_)).Times(1);
@@ -121,6 +151,7 @@
121 ms::SurfaceController controller(151 ms::SurfaceController controller(
122 mt::fake_shared(mock_surface_allocator),152 mt::fake_shared(mock_surface_allocator),
123 mt::fake_shared(placement_strategy),153 mt::fake_shared(placement_strategy),
154 mt::fake_shared(mock_display_layout),
124 mt::fake_shared(model));155 mt::fake_shared(model));
125156
126 auto params = ms::a_surface();157 auto params = ms::a_surface();
@@ -139,6 +170,7 @@
139 ms::SurfaceController controller(170 ms::SurfaceController controller(
140 mt::fake_shared(mock_surface_allocator),171 mt::fake_shared(mock_surface_allocator),
141 mt::fake_shared(placement_strategy),172 mt::fake_shared(placement_strategy),
173 mt::fake_shared(mock_display_layout),
142 mt::fake_shared(model));174 mt::fake_shared(model));
143175
144 auto params = ms::a_surface();176 auto params = ms::a_surface();

Subscribers

People subscribed via source and target branches