Mir

Merge lp:~kdub/mir/demo-stream-titlebars into lp:mir

Proposed by Kevin DuBois
Status: Work in progress
Proposed branch: lp:~kdub/mir/demo-stream-titlebars
Merge into: lp:mir
Prerequisite: lp:~kdub/mir/fix-1563278
Diff against target: 821 lines (+219/-167)
16 files modified
examples/server_example_basic_window_manager.cpp (+1/-1)
examples/server_example_basic_window_manager.h (+1/-3)
examples/server_example_canonical_window_manager.cpp (+157/-105)
examples/server_example_canonical_window_manager.h (+1/-4)
examples/server_example_tiling_window_manager.cpp (+1/-3)
examples/server_example_tiling_window_manager.h (+1/-3)
examples/server_example_window_management.cpp (+1/-4)
examples/server_example_window_management_info.cpp (+16/-10)
examples/server_example_window_management_info.h (+9/-6)
include/server/mir/scene/surface_creation_parameters.h (+2/-1)
include/server/mir/shell/surface_specification.h (+1/-0)
src/server/frontend/session_mediator.cpp (+7/-7)
src/server/scene/application_session.cpp (+4/-18)
src/server/scene/surface_creation_parameters.cpp (+9/-2)
src/server/shell/surface_specification.cpp (+7/-0)
src/server/symbols.map (+1/-0)
To merge this branch: bzr merge lp:~kdub/mir/demo-stream-titlebars
Reviewer Review Type Date Requested Status
Chris Halse Rogers Approve
Daniel van Vugt Abstain
Cemil Azizoglu (community) Approve
Alan Griffiths Needs Fixing
Mir CI Bot continuous-integration Approve
Review via email: mp+291740@code.launchpad.net

Commit message

demos: transition CanonicalWindowManagerPolicy from using Surfaces to display titlebars to using Streams.

Our "Surfaces" are really more like windows (content, input, and WM), and Streams are the content. Its better to have titlebars that are merely content than to have two "Surfaces/windows" and force the WM policy to tie the two windows together to make it look like one of the windows is a titlebar to the other.

I did intentionally change behavior in the case of vertmaximized to correct behavior of the shell according to my reading of the spec.
Fixes: LP: #1569836

Description of the change

demos: transition CanonicalWindowManagerPolicy from using Surfaces to display titlebars to using Streams.

Our "Surfaces" are really more like windows (content, input, and WM), and Streams are the content. Its better to have titlebars that are merely content than to have two "Surfaces/windows" and force the WM policy to tie the two windows together to make it look like one of the windows is a titlebar to the other.

I did intentionally change behavior in the case of vertmaximized to correct behavior of the shell according to my reading of the spec (LP: #1569836)

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

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

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

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

This doesn't seem to get all the focus based repainting right:

$ bin/mir_demo_server
$ bin/mirrun gnome-terminal

...

in the terminal:

$ mir_demo_client_multiwin

Expected: multiwin has bright (focussed) titlebars, terminal has dim (unfocussed) titlebars
Actual .: Both the terminal and multiwin have "focus" titlebars.

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

I don't see where this is being used.
640 + SurfaceCreationParameters& with_buffer_streams(std::vector<shell::StreamSpecification> const& streams);

why is it needed? Is there a followup branch?

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

> I don't see where this is being used.
> 640 + SurfaceCreationParameters&
> with_buffer_streams(std::vector<shell::StreamSpecification> const& streams);
>
> why is it needed? Is there a followup branch?

It is providing a similar way to set the stream fields, eg:
ms::a_surface()
    .with_size(...)
    .with_bufer_usage(...)
    .with_buffer_streams(...);

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

> > I don't see where this is being used.
> > 640 + SurfaceCreationParameters&
> > with_buffer_streams(std::vector<shell::StreamSpecification> const& streams);
> >
> > why is it needed? Is there a followup branch?
>
> It is providing a similar way to set the stream fields, eg:
> ms::a_surface()
> .with_size(...)
> .with_bufer_usage(...)
> .with_buffer_streams(...);

Ok I guess it sounds useful.

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

I've made a few attempts on this topic over the years. Although I feel treating the titlebar as the only type of decoration is quite wrong, simultaneously ignoring the past and not looking to the future.

Please read:
https://bugs.launchpad.net/mir/+bug/1569836/comments/1

Also consider how you would support a theme with:
  * Window borders around the sides
  * No titlebar
  * Titlebar on the side
  * Titlebar non-rectangular, or not the same length as the window
  * Titlebar on the bottom
  * A titlebar that is hidden and only pops up sometimes, maybe with floating buttons.

There is prior art for all of these. The only commonality really is that the client area is usually (but not always) rectangular. And decorations may be arbitrary.

I hesitate to disapprove, because the problem is also pre-existing. But we should be thinking about more generic solutions than this.

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

Looks reasonable to me, modulo Alan's needs-fixing.

This isn't code for actual Mir shell clients to use, and we don't need to implement fancy decorations in our demo server.

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

hit some difficulty with "mirrun", so branch has been lingering. Trying to fix once again.

re the various examples, the location and appearance of the titlebar are controlled by the shell, so different shell logic could control these different locations.

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

> Looks reasonable to me, modulo Alan's needs-fixing.
>
> This isn't code for actual Mir shell clients to use, and we don't need to
> implement fancy decorations in our demo server.

Right, this is just to stop giving an example of binding up a MirSurface to use as a titlebar, and to eliminate a use of the 'primary_buffer_stream()'

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

bit of bitrot while I did 0.23 testing and sync fence investigation, fixing up

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

back to WIP

Unmerged revisions

3452. By Kevin DuBois

make sure to expose == operator for StreamSpecification

3451. By Kevin DuBois

port over changes that transition the CanonicalWM to using streams instead of surfaces for titlebars

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'examples/server_example_basic_window_manager.cpp'
2--- examples/server_example_basic_window_manager.cpp 2015-11-27 13:58:54 +0000
3+++ examples/server_example_basic_window_manager.cpp 2016-04-13 11:13:46 +0000
4@@ -58,7 +58,7 @@
5 auto const surface = session->surface(result);
6 surface_info.emplace(surface, SurfaceInfo{session, surface, placed_params});
7 policy->handle_new_surface(session, surface);
8- policy->generate_decorations_for(session, surface, surface_info, build);
9+ policy->generate_decorations_for(session, surface);
10 return result;
11 }
12
13
14=== modified file 'examples/server_example_basic_window_manager.h'
15--- examples/server_example_basic_window_manager.h 2016-01-29 08:18:22 +0000
16+++ examples/server_example_basic_window_manager.h 2016-04-13 11:13:46 +0000
17@@ -104,9 +104,7 @@
18 virtual int handle_set_state(std::shared_ptr<scene::Surface> const& surface, MirSurfaceState value) = 0;
19
20 virtual void generate_decorations_for(
21- std::shared_ptr<scene::Session> const& session, std::shared_ptr<scene::Surface> const& surface,
22- SurfaceInfoMap& surface_info,
23- std::function<frontend::SurfaceId(std::shared_ptr<scene::Session> const&, scene::SurfaceCreationParameters const&)> const& build) = 0;
24+ std::shared_ptr<scene::Session> const& session, std::shared_ptr<scene::Surface> const& surface) = 0;
25
26 virtual bool handle_keyboard_event(MirKeyboardEvent const* event) = 0;
27
28
29=== modified file 'examples/server_example_canonical_window_manager.cpp'
30--- examples/server_example_canonical_window_manager.cpp 2016-04-12 14:10:00 +0000
31+++ examples/server_example_canonical_window_manager.cpp 2016-04-13 11:13:46 +0000
32@@ -30,6 +30,7 @@
33
34 namespace me = mir::examples;
35 namespace ms = mir::scene;
36+namespace mg = mir::graphics;
37 using namespace mir::geometry;
38
39 ///\example server_example_canonical_window_manager.cpp
40@@ -38,18 +39,95 @@
41 namespace
42 {
43 int const title_bar_height = 10;
44+Displacement const titlebar_displacement { 0, -10 };
45+
46 Size titlebar_size_for_window(Size window_size)
47 {
48 return {window_size.width, Height{title_bar_height}};
49 }
50
51-Point titlebar_position_for_window(Point window_position)
52-{
53- return {
54- window_position.x,
55- window_position.y - DeltaY(title_bar_height)
56- };
57-}
58+void constrain_input_to(std::vector<Rectangle>& rectangles, Rectangle constraint)
59+{
60+ auto surface_displacement = constraint.top_left - Point{0, 0};
61+ for(auto& rect : rectangles)
62+ {
63+ rect.top_left = rect.top_left + surface_displacement;
64+ rect = rect.intersection_with(constraint);
65+ rect.top_left = rect.top_left - surface_displacement;
66+ }
67+}
68+
69+std::vector<Rectangle> input_content_area(me::SurfaceInfo& info, Rectangle surface_rect)
70+{
71+ std::vector<Rectangle> rectangles;
72+ if (info.input_shape.is_set() && !info.input_shape.value().empty())
73+ return info.input_shape.value();
74+ else
75+ return { { Point{0,0}, surface_rect.size } };
76+}
77+
78+void apply_input_content_area(
79+ me::SurfaceInfo& info, ms::Surface& surface, Rectangle surface_rect)
80+{
81+ surface.set_input_region(input_content_area(info, surface_rect));
82+}
83+
84+void apply_input_titlebar_and_content_area(
85+ me::SurfaceInfo& info, ms::Surface& surface,
86+ Rectangle surface_rect)
87+{
88+ auto rectangles = input_content_area(info, surface_rect);
89+ info.titlebar_input_shape =
90+ { Point{0,0} + titlebar_displacement, titlebar_size_for_window(surface_rect.size) };
91+ rectangles.emplace_back(info.titlebar_input_shape.value());
92+ surface.set_input_region(rectangles);
93+}
94+
95+void content_and_titlebar(me::SurfaceInfo& info, ms::Surface& surface, Size new_size)
96+{
97+ auto streams = info.streams.value();
98+ auto titlebar = std::find_if(streams.begin(), streams.end(),
99+ [&](mir::shell::StreamSpecification const& entry)
100+ {
101+ return entry.stream_id == info.titlebar_id;
102+ });
103+
104+ if (titlebar == streams.end())
105+ {
106+ streams.push_back(
107+ { info.titlebar_id, titlebar_displacement, {titlebar_size_for_window(new_size)}});
108+ }
109+ else
110+ {
111+ titlebar->size = titlebar_size_for_window(new_size);
112+ }
113+
114+ if (auto session = info.session.lock())
115+ session->configure_streams(surface, streams);
116+
117+ info.streams = streams;
118+ info.visible_titlebar = true;
119+}
120+
121+void content_only(me::SurfaceInfo& info, ms::Surface& surface)
122+{
123+ auto streams = info.streams.value();
124+ for(auto it = streams.begin(); it != streams.end();)
125+ {
126+ if (it->stream_id == info.titlebar_id)
127+ it = streams.erase(it);
128+ else
129+ it++;
130+ }
131+
132+ if (auto session = info.session.lock())
133+ session->configure_streams(surface, streams);
134+
135+ info.streams = streams;
136+ info.visible_titlebar = false;
137+}
138+
139+
140 }
141
142 me::CanonicalWindowManagerPolicyCopy::CanonicalWindowManagerPolicyCopy(
143@@ -83,7 +161,7 @@
144
145 display_layout->place_in_output(info.output_id.value(), rect);
146 surface->move_to(rect.top_left);
147- surface->resize(rect.size);
148+ apply_resize(surface, rect.top_left, rect.size);
149 }
150 }
151 }
152@@ -103,9 +181,6 @@
153 auto surf_type = parameters.type.is_set() ? parameters.type.value() : mir_surface_type_normal;
154 bool const needs_titlebar = SurfaceInfo::needs_titlebar(surf_type);
155
156- if (needs_titlebar)
157- parameters.size.height = parameters.size.height + DeltaY{title_bar_height};
158-
159 if (!parameters.state.is_set())
160 parameters.state = mir_surface_state_restored;
161
162@@ -238,45 +313,34 @@
163 parameters.size.height = parameters.size.height - DeltaY{title_bar_height};
164 }
165
166+ if (parameters.input_shape.is_set())
167+ {
168+ auto rect = parameters.input_shape.value();
169+ constrain_input_to(rect, {parameters.top_left, parameters.size});
170+ parameters.input_shape = rect;
171+ }
172+
173 return parameters;
174 }
175
176 void me::CanonicalWindowManagerPolicyCopy::generate_decorations_for(
177 std::shared_ptr<scene::Session> const& session,
178- std::shared_ptr<scene::Surface> const& surface,
179- SurfaceInfoMap& surface_map,
180- std::function<frontend::SurfaceId(std::shared_ptr<scene::Session> const& session, scene::SurfaceCreationParameters const& params)> const& build)
181+ std::shared_ptr<scene::Surface> const& surface)
182 {
183 if (!SurfaceInfo::needs_titlebar(surface->type()))
184 return;
185
186 auto format = mir_pixel_format_xrgb_8888;
187- mir::graphics::BufferProperties properties(titlebar_size_for_window(surface->size()),
188- format, mir::graphics::BufferUsage::software);
189- auto stream_id = session->create_buffer_stream(properties);
190- auto params = ms::a_surface()
191- .of_size(titlebar_size_for_window(surface->size()))
192- .of_name("decoration")
193- .of_pixel_format(format)
194- .of_buffer_usage(mir::graphics::BufferUsage::software)
195- .of_position(titlebar_position_for_window(surface->top_left()))
196- .of_type(mir_surface_type_gloss)
197- .with_buffer_stream(stream_id);
198- auto id = build(session, params);
199- auto titlebar = session->surface(id);
200- titlebar->set_alpha(0.9);
201-
202+ auto size = titlebar_size_for_window(surface->size());
203+ auto usage = mir::graphics::BufferUsage::software;
204 auto& surface_info = tools->info_for(surface);
205- surface_info.titlebar = titlebar;
206- surface_info.titlebar_id = id;
207- surface_info.titlebar_stream_id = stream_id;
208- surface_info.children.push_back(titlebar);
209+ surface_info.has_titlebar = true;
210+ surface_info.titlebar_id = session->create_buffer_stream(mg::BufferProperties{size, format, usage});
211+ surface_info.init_titlebar(size);
212+ surface_info.paint_titlebar(0xFF);
213
214- SurfaceInfo& titlebar_info =
215- surface_map.emplace(titlebar, SurfaceInfo{session, titlebar, {}}).first->second;
216- titlebar_info.is_titlebar = true;
217- titlebar_info.parent = surface;
218- titlebar_info.init_titlebar(titlebar);
219+ content_and_titlebar(surface_info, *surface, size);
220+ apply_input_titlebar_and_content_area(surface_info, *surface, {surface->top_left(), surface->size()});
221 }
222
223 void me::CanonicalWindowManagerPolicyCopy::handle_new_surface(std::shared_ptr<ms::Session> const& session, std::shared_ptr<ms::Surface> const& surface)
224@@ -289,18 +353,6 @@
225
226 tools->info_for(session).surfaces.push_back(surface);
227
228- if (surface_info.can_be_active())
229- {
230- surface->add_observer(std::make_shared<shell::SurfaceReadyObserver>(
231- [this](std::shared_ptr<scene::Session> const& /*session*/,
232- std::shared_ptr<scene::Surface> const& surface)
233- {
234- select_active_surface(surface);
235- },
236- session,
237- surface));
238- }
239-
240 if (surface_info.state == mir_surface_state_fullscreen)
241 fullscreen_surfaces.insert(surface);
242 }
243@@ -362,6 +414,19 @@
244
245 #undef COPY_IF_SET
246
247+ if (modifications.input_shape.is_set())
248+ {
249+ auto rects = modifications.input_shape.value();
250+ constrain_input_to(rects, {surface->top_left(), surface->size()} );
251+ surface_info.input_shape = rects;
252+
253+ std::vector<Rectangle> input_area;
254+ if (surface_info.visible_titlebar)
255+ apply_input_titlebar_and_content_area(surface_info, *surface, {surface->top_left(), surface->size()});
256+ else
257+ apply_input_content_area(surface_info, *surface, {surface->top_left(), surface->size()});
258+ }
259+
260 std::swap(surface_info, surface_info_old);
261
262 if (modifications.name.is_set())
263@@ -394,7 +459,7 @@
264 false,
265 display_area);
266
267- apply_resize(surface, surface_info.titlebar, top_left, new_size);
268+ apply_resize(surface, top_left, new_size);
269 }
270
271 if (modifications.input_shape.is_set())
272@@ -439,12 +504,8 @@
273 }
274
275 session->destroy_surface(surface);
276- if (info.titlebar)
277- {
278- session->destroy_surface(info.titlebar_id);
279- session->destroy_buffer_stream(info.titlebar_stream_id);
280- tools->forget(info.titlebar);
281- }
282+ if (info.has_titlebar)
283+ session->destroy_buffer_stream(info.titlebar_id);
284
285 auto& surfaces = tools->info_for(session).surfaces;
286
287@@ -511,36 +572,28 @@
288 {
289 case mir_surface_state_restored:
290 movement = info.restore_rect.top_left - old_pos;
291- surface->resize(info.restore_rect.size);
292- if (info.titlebar)
293- {
294- info.titlebar->resize(titlebar_size_for_window(info.restore_rect.size));
295- info.titlebar->show();
296- }
297+ info.visible_titlebar = true;
298+ apply_resize(surface, surface->top_left() + movement, info.restore_rect.size);
299 break;
300
301 case mir_surface_state_maximized:
302 movement = display_area.top_left - old_pos;
303- surface->resize(display_area.size);
304- if (info.titlebar)
305- info.titlebar->hide();
306+ movement.dy = movement.dy - titlebar_displacement.dy;
307+ info.visible_titlebar = true;
308+ apply_resize(surface, surface->top_left() + movement, display_area.size);
309 break;
310
311 case mir_surface_state_horizmaximized:
312 movement = Point{display_area.top_left.x, info.restore_rect.top_left.y} - old_pos;
313- surface->resize({display_area.size.width, info.restore_rect.size.height});
314- if (info.titlebar)
315- {
316- info.titlebar->resize(titlebar_size_for_window({display_area.size.width, info.restore_rect.size.height}));
317- info.titlebar->show();
318- }
319+ info.visible_titlebar = true;
320+ apply_resize(surface, surface->top_left() + movement, {display_area.size.width, info.restore_rect.size.height});
321 break;
322
323 case mir_surface_state_vertmaximized:
324 movement = Point{info.restore_rect.top_left.x, display_area.top_left.y} - old_pos;
325- surface->resize({info.restore_rect.size.width, display_area.size.height});
326- if (info.titlebar)
327- info.titlebar->hide();
328+ movement.dy = movement.dy - titlebar_displacement.dy;
329+ info.visible_titlebar = true;
330+ apply_resize(surface, surface->top_left() + movement, {info.restore_rect.size.width, display_area.size.height});
331 break;
332
333 case mir_surface_state_fullscreen:
334@@ -557,14 +610,15 @@
335 }
336
337 movement = rect.top_left - old_pos;
338- surface->resize(rect.size);
339+
340+ //needs to be content only
341+ info.visible_titlebar = false;
342+ apply_resize(surface, surface->top_left() + movement, rect.size);
343 break;
344 }
345
346 case mir_surface_state_hidden:
347 case mir_surface_state_minimized:
348- if (info.titlebar)
349- info.titlebar->hide();
350 surface->hide();
351 return info.state = value;
352
353@@ -572,11 +626,6 @@
354 break;
355 }
356
357- // TODO It is rather simplistic to move a tree WRT the top_left of the root
358- // TODO when resizing. But for more sophistication we would need to encode
359- // TODO some sensible layout rules.
360- move_tree(surface, movement);
361-
362 info.state = value;
363
364 if (info.is_visible())
365@@ -757,9 +806,9 @@
366 {
367 if (mir_pointer_event_button_state(event, mir_pointer_button_primary))
368 {
369- if (auto const possible_titlebar = tools->surface_at(old_cursor))
370+ if (auto const surface = tools->surface_at(old_cursor))
371 {
372- if (tools->info_for(possible_titlebar).is_titlebar)
373+ if (old_cursor.y < surface->top_left().y)
374 {
375 drag(cursor);
376 consumes_event = true;
377@@ -783,6 +832,7 @@
378
379 auto const value = handle_set_state(surface, MirSurfaceState(state));
380 surface->configure(mir_surface_attrib_state, value);
381+ handle_set_state(surface, state);
382 }
383 }
384
385@@ -795,10 +845,7 @@
386 {
387 if (auto const active_surface = active_surface_.lock())
388 {
389- if (auto const titlebar = tools->info_for(active_surface).titlebar)
390- {
391- tools->info_for(titlebar).paint_titlebar(0x3F);
392- }
393+ tools->info_for(active_surface).paint_titlebar(0x3F);
394 }
395
396 if (active_surface_.lock())
397@@ -814,15 +861,9 @@
398 {
399 if (auto const active_surface = active_surface_.lock())
400 {
401- if (auto const titlebar = tools->info_for(active_surface).titlebar)
402- {
403- tools->info_for(titlebar).paint_titlebar(0x3F);
404- }
405- }
406- if (auto const titlebar = tools->info_for(surface).titlebar)
407- {
408- tools->info_for(titlebar).paint_titlebar(0xFF);
409- }
410+ tools->info_for(active_surface).paint_titlebar(0x3F);
411+ }
412+ tools->info_for(surface).paint_titlebar(0xFF);
413 tools->set_focus_to(info_for.session.lock(), surface);
414 tools->raise_tree(surface);
415 active_surface_ = surface;
416@@ -852,7 +893,7 @@
417
418 bool me::CanonicalWindowManagerPolicyCopy::resize(std::shared_ptr<ms::Surface> const& surface, Point cursor, Point old_cursor, Rectangle bounds)
419 {
420- if (!surface || !surface->input_area_contains(old_cursor))
421+ if (!surface)
422 return false;
423
424 auto const top_left = surface->top_left();
425@@ -883,27 +924,38 @@
426
427 Point new_pos = top_left + left_resize*delta.dx + top_resize*delta.dy;
428
429-
430 auto const& surface_info = tools->info_for(surface);
431
432 surface_info.constrain_resize(surface, new_pos, new_size, left_resize, top_resize, bounds);
433
434- apply_resize(surface, surface_info.titlebar, new_pos, new_size);
435+ apply_resize(surface, new_pos, new_size);
436
437 return true;
438 }
439
440 void me::CanonicalWindowManagerPolicyCopy::apply_resize(
441 std::shared_ptr<ms::Surface> const& surface,
442- std::shared_ptr<ms::Surface> const& titlebar,
443 Point const& new_pos,
444 Size const& new_size) const
445 {
446- if (titlebar)
447- titlebar->resize({new_size.width, Height{title_bar_height}});
448+ auto& surface_info = tools->info_for(surface);
449+
450+ if (surface_info.visible_titlebar)
451+ {
452+ apply_input_titlebar_and_content_area(surface_info, *surface, {new_pos, new_size});
453+ content_and_titlebar(surface_info, *surface, new_size);
454+ }
455+ else
456+ {
457+ apply_input_content_area(surface_info, *surface, {new_pos, new_size});
458+ content_only(surface_info, *surface);
459+ }
460
461 surface->resize(new_size);
462
463+ // TODO It is rather simplistic to move a tree WRT the top_left of the root
464+ // TODO when resizing. But for more sophistication we would need to encode
465+ // TODO some sensible layout rules.
466 move_tree(surface, new_pos-surface->top_left());
467 }
468
469@@ -912,7 +964,7 @@
470 if (!surface)
471 return false;
472
473- if (!surface->input_area_contains(from) && !tools->info_for(surface).titlebar)
474+ if (!surface->input_area_contains(from))
475 return false;
476
477 auto movement = to - from;
478
479=== modified file 'examples/server_example_canonical_window_manager.h'
480--- examples/server_example_canonical_window_manager.h 2016-01-29 08:18:22 +0000
481+++ examples/server_example_canonical_window_manager.h 2016-04-13 11:13:46 +0000
482@@ -88,9 +88,7 @@
483
484 void generate_decorations_for(
485 std::shared_ptr<scene::Session> const& session,
486- std::shared_ptr<scene::Surface> const& surface,
487- SurfaceInfoMap& surface_map,
488- std::function<frontend::SurfaceId(std::shared_ptr<scene::Session> const& session, scene::SurfaceCreationParameters const& params)> const& build);
489+ std::shared_ptr<scene::Surface> const& surface);
490
491 private:
492 static const int modifier_mask =
493@@ -112,7 +110,6 @@
494 void move_tree(std::shared_ptr<scene::Surface> const& root, geometry::Displacement movement) const;
495 void apply_resize(
496 std::shared_ptr<mir::scene::Surface> const& surface,
497- std::shared_ptr<mir::scene::Surface> const& titlebar,
498 geometry::Point const& new_pos,
499 geometry::Size const& new_size) const;
500
501
502=== modified file 'examples/server_example_tiling_window_manager.cpp'
503--- examples/server_example_tiling_window_manager.cpp 2016-01-29 08:18:22 +0000
504+++ examples/server_example_tiling_window_manager.cpp 2016-04-13 11:13:46 +0000
505@@ -138,9 +138,7 @@
506
507 void me::TilingWindowManagerPolicy::generate_decorations_for(
508 std::shared_ptr<ms::Session> const&,
509- std::shared_ptr<ms::Surface> const&,
510- SurfaceInfoMap&,
511- std::function<mf::SurfaceId(std::shared_ptr<ms::Session> const&, ms::SurfaceCreationParameters const&)> const&)
512+ std::shared_ptr<ms::Surface> const&)
513 {
514 }
515
516
517=== modified file 'examples/server_example_tiling_window_manager.h'
518--- examples/server_example_tiling_window_manager.h 2016-01-29 08:18:22 +0000
519+++ examples/server_example_tiling_window_manager.h 2016-04-13 11:13:46 +0000
520@@ -78,9 +78,7 @@
521 std::shared_ptr<scene::Surface> const& surface);
522
523 void generate_decorations_for(
524- std::shared_ptr<scene::Session> const& session, std::shared_ptr<scene::Surface> const& surface,
525- SurfaceInfoMap& surface_info,
526- std::function<frontend::SurfaceId(std::shared_ptr<scene::Session> const&, scene::SurfaceCreationParameters const&)> const& build);
527+ std::shared_ptr<scene::Session> const& session, std::shared_ptr<scene::Surface> const& surface);
528
529 private:
530 static const int modifier_mask =
531
532=== modified file 'examples/server_example_window_management.cpp'
533--- examples/server_example_window_management.cpp 2016-03-23 06:39:56 +0000
534+++ examples/server_example_window_management.cpp 2016-04-13 11:13:46 +0000
535@@ -105,10 +105,7 @@
536 }
537
538 void generate_decorations_for(
539- std::shared_ptr<ms::Session> const&,
540- std::shared_ptr<ms::Surface> const&,
541- SurfaceInfoMap&,
542- std::function<mf::SurfaceId(std::shared_ptr<ms::Session> const&, ms::SurfaceCreationParameters const&)> const&) override
543+ std::shared_ptr<ms::Session> const&, std::shared_ptr<ms::Surface> const&) override
544 {
545 }
546 private:
547
548=== modified file 'examples/server_example_window_management_info.cpp'
549--- examples/server_example_window_management_info.cpp 2016-01-29 08:18:22 +0000
550+++ examples/server_example_window_management_info.cpp 2016-04-13 11:13:46 +0000
551@@ -19,6 +19,7 @@
552 #include "server_example_window_management_info.h"
553
554 #include "mir/scene/surface.h"
555+#include "mir/scene/session.h"
556 #include "mir/scene/surface_creation_parameters.h"
557
558 #include "mir/graphics/buffer.h"
559@@ -46,7 +47,9 @@
560 width_inc{params.width_inc},
561 height_inc{params.height_inc},
562 min_aspect{params.min_aspect},
563- max_aspect{params.max_aspect}
564+ max_aspect{params.max_aspect},
565+ input_shape{params.input_shape.is_set() ? params.input_shape.value() : std::vector<Rectangle>{}},
566+ streams{params.streams.is_set() ? params.streams.value() : std::vector<shell::StreamSpecification>{}}
567 {
568 if (params.output_id != mir::graphics::DisplayConfigurationOutputId{0})
569 output_id = params.output_id;
570@@ -243,16 +246,19 @@
571 mg::BufferID back_buffer;
572 };
573
574-void mir::examples::SurfaceInfo::init_titlebar(std::shared_ptr<scene::Surface> const& surface)
575+void mir::examples::SurfaceInfo::init_titlebar(Size titlebar_size)
576 {
577- auto stream = surface->primary_buffer_stream();
578- try
579- {
580- stream_painter = std::make_shared<AllocatingPainter>(stream, surface->size());
581- }
582- catch (...)
583- {
584- stream_painter = std::make_shared<SwappingPainter>(stream);
585+ if (auto s = session.lock())
586+ {
587+ auto stream = s->get_buffer_stream(titlebar_id);
588+ try
589+ {
590+ stream_painter = std::make_shared<AllocatingPainter>(stream, titlebar_size);
591+ }
592+ catch (...)
593+ {
594+ stream_painter = std::make_shared<SwappingPainter>(stream);
595+ }
596 }
597 }
598
599
600=== modified file 'examples/server_example_window_management_info.h'
601--- examples/server_example_window_management_info.h 2016-03-30 14:08:54 +0000
602+++ examples/server_example_window_management_info.h 2016-04-13 11:13:46 +0000
603@@ -63,10 +63,6 @@
604 std::weak_ptr <scene::Session> session;
605 std::weak_ptr <scene::Surface> parent;
606 std::vector <std::weak_ptr<scene::Surface>> children;
607- std::shared_ptr <scene::Surface> titlebar;
608- frontend::SurfaceId titlebar_id;
609- frontend::BufferStreamId titlebar_stream_id;
610- bool is_titlebar = false;
611 geometry::Width min_width;
612 geometry::Height min_height;
613 geometry::Width max_width;
614@@ -76,8 +72,15 @@
615 mir::optional_value<shell::SurfaceAspectRatio> min_aspect;
616 mir::optional_value<shell::SurfaceAspectRatio> max_aspect;
617 mir::optional_value<graphics::DisplayConfigurationOutputId> output_id;
618-
619- void init_titlebar(std::shared_ptr <scene::Surface> const& surface);
620+ mir::optional_value<std::vector<geometry::Rectangle>> input_shape;
621+ mir::optional_value<geometry::Rectangle> titlebar_input_shape;
622+
623+ mir::optional_value<std::vector<shell::StreamSpecification>> streams;
624+ frontend::BufferStreamId titlebar_id;
625+ bool has_titlebar = false;
626+ bool visible_titlebar = false;
627+
628+ void init_titlebar(geometry::Size titlebar_size);
629
630 void paint_titlebar(int intensity);
631
632
633=== modified file 'include/server/mir/scene/surface_creation_parameters.h'
634--- include/server/mir/scene/surface_creation_parameters.h 2016-03-29 16:30:22 +0000
635+++ include/server/mir/scene/surface_creation_parameters.h 2016-04-13 11:13:46 +0000
636@@ -72,6 +72,8 @@
637
638 SurfaceCreationParameters& with_buffer_stream(frontend::BufferStreamId const& id);
639
640+ SurfaceCreationParameters& with_buffer_streams(std::vector<shell::StreamSpecification> const& streams);
641+
642 std::string name;
643 geometry::Size size;
644 geometry::Point top_left;
645@@ -84,7 +86,6 @@
646 mir::optional_value<MirSurfaceType> type;
647 mir::optional_value<MirOrientationMode> preferred_orientation;
648 mir::optional_value<frontend::SurfaceId> parent_id;
649- mir::optional_value<frontend::BufferStreamId> content_id;
650 mir::optional_value<geometry::Rectangle> aux_rect;
651 mir::optional_value<MirEdgeAttachment> edge_attachment;
652
653
654=== modified file 'include/server/mir/shell/surface_specification.h'
655--- include/server/mir/shell/surface_specification.h 2016-03-23 06:39:56 +0000
656+++ include/server/mir/shell/surface_specification.h 2016-04-13 11:13:46 +0000
657@@ -45,6 +45,7 @@
658 geometry::Displacement displacement;
659 optional_value<geometry::Size> size;
660 };
661+bool operator==(StreamSpecification const& lhs, StreamSpecification const& rhs);
662
663 /// Specification of surface properties requested by client
664 struct SurfaceSpecification
665
666=== modified file 'src/server/frontend/session_mediator.cpp'
667--- src/server/frontend/session_mediator.cpp 2016-04-12 14:10:00 +0000
668+++ src/server/frontend/session_mediator.cpp 2016-04-13 11:13:46 +0000
669@@ -287,10 +287,10 @@
670 #undef COPY_IF_SET
671
672 mf::BufferStreamId buffer_stream_id;
673- std::shared_ptr<mf::BufferStream> legacy_stream = nullptr;
674+ std::shared_ptr<mf::BufferStream> legacy_stream;
675+ std::vector<msh::StreamSpecification> stream_spec;
676 if (request->stream_size() > 0)
677 {
678- std::vector<msh::StreamSpecification> stream_spec;
679 for (auto& stream : request->stream())
680 {
681 if (stream.has_width() && stream.has_height())
682@@ -310,16 +310,17 @@
683 {}});
684 }
685 }
686- params.streams = std::move(stream_spec);
687 }
688 else
689 {
690 buffer_stream_id = session->create_buffer_stream(
691 {params.size, params.pixel_format, params.buffer_usage});
692 legacy_stream = session->get_buffer_stream(buffer_stream_id);
693- params.content_id = buffer_stream_id;
694+ stream_spec.emplace_back(msh::StreamSpecification{ {buffer_stream_id}, {0, 0}, {}});
695 }
696
697+ params.streams = std::move(stream_spec);
698+
699 if (request->has_min_aspect())
700 params.min_aspect = { request->min_aspect().width(), request->min_aspect().height()};
701
702@@ -334,17 +335,16 @@
703 auto const surf_id = shell->create_surface(session, params, sink);
704
705 auto surface = session->get_surface(surf_id);
706- auto stream = session->get_buffer_stream(buffer_stream_id);
707 auto const& client_size = surface->client_size();
708 response->mutable_id()->set_value(surf_id.as_value());
709 response->set_width(client_size.width.as_uint32_t());
710 response->set_height(client_size.height.as_uint32_t());
711
712 // TODO: Deprecate
713- response->set_pixel_format(stream->pixel_format());
714+ response->set_pixel_format(params.pixel_format);
715 response->set_buffer_usage(request->buffer_usage());
716
717- response->mutable_buffer_stream()->set_pixel_format(stream->pixel_format());
718+ response->mutable_buffer_stream()->set_pixel_format(params.pixel_format);
719 response->mutable_buffer_stream()->set_buffer_usage(request->buffer_usage());
720
721 if (surface->supports_input())
722
723=== modified file 'src/server/scene/application_session.cpp'
724--- src/server/scene/application_session.cpp 2016-04-13 11:13:46 +0000
725+++ src/server/scene/application_session.cpp 2016-04-13 11:13:46 +0000
726@@ -94,19 +94,12 @@
727 //TODO: we take either the content_id or the first streams content for now.
728 // Once the surface factory interface takes more than one stream,
729 // we can take all the streams as content.
730- if (!((the_params.content_id.is_set()) ||
731- (the_params.streams.is_set() && the_params.streams.value().size() > 0)))
732- {
733+ if (!(the_params.streams.is_set() && the_params.streams.value().size() > 0))
734 BOOST_THROW_EXCEPTION(std::logic_error("surface must have content"));
735- }
736
737 auto params = the_params;
738
739- mf::BufferStreamId stream_id;
740- if (params.content_id.is_set())
741- stream_id = params.content_id.value();
742- else
743- stream_id = params.streams.value()[0].stream_id;
744+ mf::BufferStreamId stream_id = params.streams.value()[0].stream_id;
745
746 if (params.parent_id.is_set())
747 params.parent = checked_find(the_params.parent_id.value())->second;
748@@ -116,15 +109,8 @@
749 buffer_stream->resize(params.size);
750
751 std::list<StreamInfo> streams;
752- if (the_params.content_id.is_set())
753- {
754- streams.push_back({checked_find(the_params.content_id.value())->second, {0,0}, {}});
755- }
756- else
757- {
758- for (auto& stream : params.streams.value())
759- streams.push_back({checked_find(stream.stream_id)->second, stream.displacement, stream.size});
760- }
761+ for (auto& stream : params.streams.value())
762+ streams.push_back({checked_find(stream.stream_id)->second, stream.displacement, stream.size});
763
764 auto surface = surface_factory->create_surface(streams, params);
765
766
767=== modified file 'src/server/scene/surface_creation_parameters.cpp'
768--- src/server/scene/surface_creation_parameters.cpp 2016-01-29 08:18:22 +0000
769+++ src/server/scene/surface_creation_parameters.cpp 2016-04-13 11:13:46 +0000
770@@ -130,7 +130,14 @@
771
772 ms::SurfaceCreationParameters& ms::SurfaceCreationParameters::with_buffer_stream(mf::BufferStreamId const& id)
773 {
774- content_id = id;
775+ streams = std::vector<shell::StreamSpecification>{ {id, {}, {}} };
776+ return *this;
777+}
778+
779+ms::SurfaceCreationParameters& ms::SurfaceCreationParameters::with_buffer_streams(
780+ std::vector<shell::StreamSpecification> const& s)
781+{
782+ streams = s;
783 return *this;
784 }
785
786@@ -149,7 +156,7 @@
787 lhs.type == rhs.type &&
788 lhs.preferred_orientation == rhs.preferred_orientation &&
789 lhs.parent_id == rhs.parent_id &&
790- lhs.content_id == rhs.content_id;
791+ lhs.streams == rhs.streams;
792 }
793
794 bool ms::operator!=(
795
796=== modified file 'src/server/shell/surface_specification.cpp'
797--- src/server/shell/surface_specification.cpp 2015-10-15 04:20:44 +0000
798+++ src/server/shell/surface_specification.cpp 2016-04-13 11:13:46 +0000
799@@ -47,3 +47,10 @@
800 !parent.is_set() &&
801 !input_shape.is_set();
802 }
803+
804+bool msh::operator==(StreamSpecification const& lhs, StreamSpecification const& rhs)
805+{
806+ return lhs.stream_id == rhs.stream_id &&
807+ lhs.displacement == rhs.displacement &&
808+ lhs.size == rhs.size;
809+}
810
811=== modified file 'src/server/symbols.map'
812--- src/server/symbols.map 2016-03-28 23:15:00 +0000
813+++ src/server/symbols.map 2016-04-13 11:13:46 +0000
814@@ -290,6 +290,7 @@
815 mir::shell::ShellWrapper::start_prompt_session_for*;
816 mir::shell::ShellWrapper::stop_prompt_session*;
817 mir::shell::ShellWrapper::surface_at*;
818+ mir::shell::StreamSpecification::operator*;
819 mir::shell::SurfaceReadyObserver::frame_posted*;
820 mir::shell::SurfaceReadyObserver::?SurfaceReadyObserver*;
821 mir::shell::SurfaceReadyObserver::SurfaceReadyObserver*;

Subscribers

People subscribed via source and target branches