Mir

Merge lp:~alan-griffiths/mir/msh_SystemCompositorWindowManager into lp:mir

Proposed by Alan Griffiths
Status: Merged
Approved by: Alan Griffiths
Approved revision: no longer in the source branch.
Merged at revision: 2666
Proposed branch: lp:~alan-griffiths/mir/msh_SystemCompositorWindowManager
Merge into: lp:mir
Diff against target: 628 lines (+522/-2)
7 files modified
examples/server_example_window_management.cpp (+10/-1)
include/server/mir/shell/system_compositor_window_manager.h (+99/-0)
src/server/shell/CMakeLists.txt (+1/-0)
src/server/shell/system_compositor_window_manager.cpp (+151/-0)
src/server/symbols.map (+55/-1)
tests/acceptance-tests/CMakeLists.txt (+1/-0)
tests/acceptance-tests/test_system_compositor_window_manager.cpp (+205/-0)
To merge this branch: bzr merge lp:~alan-griffiths/mir/msh_SystemCompositorWindowManager
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Alexandros Frantzis (community) Approve
Review via email: mp+261751@code.launchpad.net

Commit message

shell, examples: add a basic SystemCompositorWindowManager

Description of the change

shell, examples: add a basic SystemCompositorWindowManager

Ensures we have explicit support for the system-compositor use case. The following mir_demo_server config now offers a minimal "system compositor":

    $ cat ~/.config/mir/mir_demo_server.config
    file=/tmp/mir_socket
    arw-file=
    vt=1
    display-config=sidebyside
    window-manager=system-compositor

SystemCompositorWindowManager is slightly simplified from USC's WindowManager - mostly by removing the SessionMonitor references and providing hooks to reinstate the behaviour downstream.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

Looks good.

I was a bit torn when I started reviewing this (not sure if it's worth the trouble and extra coupling), but I think this may be useful for simple products based on Mir. I still don't think it's worth doing this if it's just to simplify USC.

95 + /// Called the first time each surface owned by the session posts its first buffer

We have always assumed one surface per system-compositor client, so it's not clear what's the correct behavior if such a client creates and posts to multiple surfaces. I guess the proposed approach of always focusing the "default" surface is OK for now, but perhaps in the future on_session_ready method should be extended to also provide the surface that became ready.

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

> We have always assumed one surface per system-compositor client, so it's not
> clear what's the correct behavior if such a client creates and posts to
> multiple surfaces. I guess the proposed approach of always focusing the
> "default" surface is OK for now, but perhaps in the future on_session_ready
> method should be extended to also provide the surface that became ready.

What we actually have (c.f. the nested code and spinner) is one surface for each output for each system-compositor client.

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'examples/server_example_window_management.cpp'
--- examples/server_example_window_management.cpp 2015-05-19 21:34:34 +0000
+++ examples/server_example_window_management.cpp 2015-06-16 08:37:48 +0000
@@ -27,6 +27,7 @@
27#include "mir/input/composite_event_filter.h"27#include "mir/input/composite_event_filter.h"
28#include "mir/options/option.h"28#include "mir/options/option.h"
29#include "mir/shell/display_layout.h"29#include "mir/shell/display_layout.h"
30#include "mir/shell/system_compositor_window_manager.h"
3031
31namespace me = mir::examples;32namespace me = mir::examples;
32namespace mf = mir::frontend;33namespace mf = mir::frontend;
@@ -42,11 +43,12 @@
42namespace43namespace
43{44{
44char const* const wm_option = "window-manager";45char const* const wm_option = "window-manager";
45char const* const wm_description = "window management strategy [{tiling|fullscreen|canonical}]";46char const* const wm_description = "window management strategy [{tiling|fullscreen|canonical|system-compositor}]";
4647
47char const* const wm_tiling = "tiling";48char const* const wm_tiling = "tiling";
48char const* const wm_fullscreen = "fullscreen";49char const* const wm_fullscreen = "fullscreen";
49char const* const wm_canonical = "canonical";50char const* const wm_canonical = "canonical";
51char const* const wm_system_compositor = "system-compositor";
5052
51struct NullSessionInfo53struct NullSessionInfo
52{54{
@@ -149,6 +151,13 @@
149 {151 {
150 return std::make_shared<CanonicalWindowManager>(focus_controller, server.the_shell_display_layout());152 return std::make_shared<CanonicalWindowManager>(focus_controller, server.the_shell_display_layout());
151 }153 }
154 else if (selection == wm_system_compositor)
155 {
156 return std::make_shared<msh::SystemCompositorWindowManager>(
157 focus_controller,
158 server.the_shell_display_layout(),
159 server.the_session_coordinator());
160 }
152161
153 throw mir::AbnormalExit("Unknown window manager: " + selection);162 throw mir::AbnormalExit("Unknown window manager: " + selection);
154 });163 });
155164
=== added file 'include/server/mir/shell/system_compositor_window_manager.h'
--- include/server/mir/shell/system_compositor_window_manager.h 1970-01-01 00:00:00 +0000
+++ include/server/mir/shell/system_compositor_window_manager.h 2015-06-16 08:37:48 +0000
@@ -0,0 +1,99 @@
1/*
2 * Copyright © 2015 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: Alan Griffiths <alan@octopull.co.uk>
17 */
18
19#ifndef MIR_SHELL_SYSTEM_COMPOSITOR_WINDOW_MANAGER_H_
20#define MIR_SHELL_SYSTEM_COMPOSITOR_WINDOW_MANAGER_H_
21
22#include "mir/shell/window_manager.h"
23
24namespace mir
25{
26namespace scene { class PlacementStrategy; class SessionCoordinator; }
27namespace shell
28{
29class FocusController;
30class DisplayLayout;
31
32/** Minimal window management for system compositing.
33 */
34class SystemCompositorWindowManager : public WindowManager
35{
36public:
37 SystemCompositorWindowManager(
38 FocusController* focus_controller,
39 std::shared_ptr<shell::DisplayLayout> const& display_layout,
40 std::shared_ptr<scene::SessionCoordinator> const& session_coordinator);
41
42/** @name Customization points
43 * These are the likely events that a system compositor will care about
44 * @{ */
45 /// Called when a session first connects (before any surfaces are ready)
46 virtual void on_session_added(std::shared_ptr<scene::Session> const& session) const;
47
48 /// Called when a session disconnects
49 virtual void on_session_removed(std::shared_ptr<scene::Session> const& session) const;
50
51 /// Called the first time each surface owned by the session posts its first buffer
52 virtual void on_session_ready(std::shared_ptr<scene::Session> const& session) const;
53/** @} */
54
55protected:
56 FocusController* const focus_controller;
57 std::shared_ptr<DisplayLayout> const display_layout;
58 std::shared_ptr<scene::SessionCoordinator> const session_coordinator;
59
60private:
61 void add_session(std::shared_ptr<scene::Session> const& session) override;
62
63 void remove_session(std::shared_ptr<scene::Session> const& session) override;
64
65 frontend::SurfaceId add_surface(
66 std::shared_ptr<scene::Session> const& session,
67 scene::SurfaceCreationParameters const& params,
68 std::function<frontend::SurfaceId(std::shared_ptr<scene::Session> const& session, scene::SurfaceCreationParameters const& params)> const& build) override;
69
70 void modify_surface(
71 std::shared_ptr<scene::Session> const& session,
72 std::shared_ptr<scene::Surface> const& surface,
73 SurfaceSpecification const& modifications) override;
74
75 void remove_surface(
76 std::shared_ptr<scene::Session> const& session,
77 std::weak_ptr<scene::Surface> const& surface) override;
78
79 void add_display(geometry::Rectangle const& area) override;
80
81 void remove_display(geometry::Rectangle const& area) override;
82
83 bool handle_keyboard_event(MirKeyboardEvent const* event) override;
84
85 bool handle_touch_event(MirTouchEvent const* event) override;
86
87 bool handle_pointer_event(MirPointerEvent const* event) override;
88
89 int set_surface_attribute(
90 std::shared_ptr<scene::Session> const& session,
91 std::shared_ptr<scene::Surface> const& surface,
92 MirSurfaceAttrib attrib,
93 int value) override;
94};
95}
96}
97
98
99#endif /* MIR_SHELL_SYSTEM_COMPOSITOR_WINDOW_MANAGER_H_ */
0100
=== modified file 'src/server/shell/CMakeLists.txt'
--- src/server/shell/CMakeLists.txt 2015-05-28 07:48:04 +0000
+++ src/server/shell/CMakeLists.txt 2015-06-16 08:37:48 +0000
@@ -10,6 +10,7 @@
10 default_window_manager.cpp10 default_window_manager.cpp
11 shell_wrapper.cpp11 shell_wrapper.cpp
12 surface_ready_observer.cpp12 surface_ready_observer.cpp
13 system_compositor_window_manager.cpp
13 default_persistent_surface_store.cpp14 default_persistent_surface_store.cpp
14 persistent_surface_store.cpp15 persistent_surface_store.cpp
15)16)
1617
=== added file 'src/server/shell/system_compositor_window_manager.cpp'
--- src/server/shell/system_compositor_window_manager.cpp 1970-01-01 00:00:00 +0000
+++ src/server/shell/system_compositor_window_manager.cpp 2015-06-16 08:37:48 +0000
@@ -0,0 +1,151 @@
1/*
2 * Copyright © 2015 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: Alan Griffiths <alan@octopull.co.uk>
17 */
18
19#include "mir/shell/system_compositor_window_manager.h"
20
21#include "mir/shell/display_layout.h"
22#include "mir/shell/focus_controller.h"
23#include "mir/shell/surface_ready_observer.h"
24#include "mir/shell/surface_specification.h"
25
26#include "mir/scene/session.h"
27#include "mir/scene/session_coordinator.h"
28#include "mir/scene/surface.h"
29#include "mir/scene/surface_creation_parameters.h"
30
31namespace mf = mir::frontend;
32namespace ms = mir::scene;
33namespace msh = mir::shell;
34
35msh::SystemCompositorWindowManager::SystemCompositorWindowManager(
36 FocusController* focus_controller,
37 std::shared_ptr<DisplayLayout> const& display_layout,
38 std::shared_ptr<ms::SessionCoordinator> const& session_coordinator) :
39 focus_controller{focus_controller},
40 display_layout{display_layout},
41 session_coordinator{session_coordinator}
42{
43}
44
45void msh::SystemCompositorWindowManager::add_session(std::shared_ptr<ms::Session> const& session)
46{
47 on_session_added(session);
48}
49
50void msh::SystemCompositorWindowManager::remove_session(std::shared_ptr<ms::Session> const& session)
51{
52 on_session_removed(session);
53}
54
55auto msh::SystemCompositorWindowManager::add_surface(
56 std::shared_ptr<ms::Session> const& session,
57 ms::SurfaceCreationParameters const& params,
58 std::function<mf::SurfaceId(std::shared_ptr<ms::Session> const& session, ms::SurfaceCreationParameters const& params)> const& build)
59-> mf::SurfaceId
60{
61 mir::geometry::Rectangle rect{params.top_left, params.size};
62
63 display_layout->place_in_output(params.output_id, rect);
64
65 auto placed_parameters = params;
66 placed_parameters.top_left = rect.top_left;
67 placed_parameters.size = rect.size;
68
69 auto const result = build(session, placed_parameters);
70 auto const surface = session->surface(result);
71
72 auto const session_ready_observer = std::make_shared<SurfaceReadyObserver>(
73 [this](std::shared_ptr<ms::Session> const& session, std::shared_ptr<ms::Surface> const& /*surface*/)
74 {
75 on_session_ready(session);
76 },
77 session,
78 surface);
79
80 surface->add_observer(session_ready_observer);
81
82 return result;
83}
84
85void msh::SystemCompositorWindowManager::modify_surface(
86 std::shared_ptr<ms::Session> const& /*session*/,
87 std::shared_ptr<ms::Surface> const& surface,
88 SurfaceSpecification const& modifications)
89{
90 if (modifications.name.is_set())
91 surface->rename(modifications.name.value());
92}
93
94void msh::SystemCompositorWindowManager::remove_surface(
95 std::shared_ptr<ms::Session> const& /*session*/,
96 std::weak_ptr<ms::Surface> const& /*surface*/)
97{
98}
99
100void msh::SystemCompositorWindowManager::add_display(mir::geometry::Rectangle const& /*area*/)
101{
102}
103
104void msh::SystemCompositorWindowManager::remove_display(mir::geometry::Rectangle const& /*area*/)
105{
106}
107
108bool msh::SystemCompositorWindowManager::handle_keyboard_event(MirKeyboardEvent const* /*event*/)
109{
110 return false;
111}
112
113bool msh::SystemCompositorWindowManager::handle_touch_event(MirTouchEvent const* /*event*/)
114{
115 return false;
116}
117
118bool msh::SystemCompositorWindowManager::handle_pointer_event(MirPointerEvent const* /*event*/)
119{
120 return false;
121}
122
123int msh::SystemCompositorWindowManager::set_surface_attribute(
124 std::shared_ptr<ms::Session> const& /*session*/,
125 std::shared_ptr<ms::Surface> const& surface,
126 MirSurfaceAttrib attrib,
127 int value)
128{
129 return surface->configure(attrib, value);
130}
131
132void msh::SystemCompositorWindowManager::on_session_added(std::shared_ptr<mir::scene::Session> const& /*session*/) const
133{
134}
135
136void msh::SystemCompositorWindowManager::on_session_removed(std::shared_ptr<mir::scene::Session> const& session) const
137{
138 if (focus_controller->focused_session() == session)
139 {
140 auto const next_session = session_coordinator->successor_of({});
141 if (next_session)
142 focus_controller->set_focus_to(next_session, next_session->default_surface());
143 else
144 focus_controller->set_focus_to(next_session, {});
145 }
146}
147
148void msh::SystemCompositorWindowManager::on_session_ready(std::shared_ptr<mir::scene::Session> const& session) const
149{
150 focus_controller->set_focus_to(session, session->default_surface());
151}
0152
=== modified file 'src/server/symbols.map'
--- src/server/symbols.map 2015-06-10 23:37:28 +0000
+++ src/server/symbols.map 2015-06-16 08:37:48 +0000
@@ -5,7 +5,8 @@
5 vtable?for?mir::input::NullInputDispatcher;5 vtable?for?mir::input::NullInputDispatcher;
6 VTT?for?mir::DefaultServerConfiguration;6 VTT?for?mir::DefaultServerConfiguration;
7 VTT?for?mir::shell::ShellWrapper;7 VTT?for?mir::shell::ShellWrapper;
8 8 VTT?for?mir::shell::SystemCompositorWindowManager;
9
9# The following symbols come from running a script over the generated docs. Vis:10# The following symbols come from running a script over the generated docs. Vis:
10# ../tools/process_doxygen_xml.py doc/xml/*.xml | grep "^mirserver public" | sed "s/mirserver public: / /" | sort 11# ../tools/process_doxygen_xml.py doc/xml/*.xml | grep "^mirserver public" | sed "s/mirserver public: / /" | sort
11 mir::compositor::Compositor::Compositor*;12 mir::compositor::Compositor::Compositor*;
@@ -252,6 +253,34 @@
252 mir::shell::ShellWrapper::surface_at*;253 mir::shell::ShellWrapper::surface_at*;
253 mir::shell::SurfaceReadyObserver::SurfaceReadyObserver*;254 mir::shell::SurfaceReadyObserver::SurfaceReadyObserver*;
254 mir::shell::SurfaceReadyObserver::?SurfaceReadyObserver*;255 mir::shell::SurfaceReadyObserver::?SurfaceReadyObserver*;
256 mir::shell::SystemCompositorWindowManager::SystemCompositorWindowManager*;
257 mir::shell::SystemCompositorWindowManager::add_display*;
258 mir::shell::SystemCompositorWindowManager::add_prompt_provider_for*;
259 mir::shell::SystemCompositorWindowManager::add_session*;
260 mir::shell::SystemCompositorWindowManager::add_surface*;
261 mir::shell::SystemCompositorWindowManager::close_session*;
262 mir::shell::SystemCompositorWindowManager::create_surface*;
263 mir::shell::SystemCompositorWindowManager::destroy_surface*;
264 mir::shell::SystemCompositorWindowManager::focused_session*;
265 mir::shell::SystemCompositorWindowManager::focused_surface*;
266 mir::shell::SystemCompositorWindowManager::focus_next_session*;
267 mir::shell::SystemCompositorWindowManager::get_surface_attribute*;
268 mir::shell::SystemCompositorWindowManager::handle*;
269 mir::shell::SystemCompositorWindowManager::modify_surface*;
270 mir::shell::SystemCompositorWindowManager::on_session_added*;
271 mir::shell::SystemCompositorWindowManager::on_session_removed*;
272 mir::shell::SystemCompositorWindowManager::on_session_ready*;
273 mir::shell::SystemCompositorWindowManager::open_session*;
274 mir::shell::SystemCompositorWindowManager::raise*;
275 mir::shell::SystemCompositorWindowManager::remove_display*;
276 mir::shell::SystemCompositorWindowManager::remove_session*;
277 mir::shell::SystemCompositorWindowManager::remove_surface*;
278 mir::shell::SystemCompositorWindowManager::set_focus_to*;
279 mir::shell::SystemCompositorWindowManager::set_surface_attribute*;
280 mir::shell::SystemCompositorWindowManager::ShellWrapper*;
281 mir::shell::SystemCompositorWindowManager::start_prompt_session_for*;
282 mir::shell::SystemCompositorWindowManager::stop_prompt_session*;
283 mir::shell::SystemCompositorWindowManager::surface_at*;
255 mir::shell::WindowManager::operator*;284 mir::shell::WindowManager::operator*;
256 mir::shell::WindowManager::?WindowManager*;285 mir::shell::WindowManager::?WindowManager*;
257 mir::shell::WindowManager::WindowManager*;286 mir::shell::WindowManager::WindowManager*;
@@ -345,6 +374,29 @@
345 non-virtual?thunk?to?mir::shell::ShellWrapper::stop_prompt_session*;374 non-virtual?thunk?to?mir::shell::ShellWrapper::stop_prompt_session*;
346 non-virtual?thunk?to?mir::shell::ShellWrapper::surface_at*;375 non-virtual?thunk?to?mir::shell::ShellWrapper::surface_at*;
347 non-virtual?thunk?to?mir::shell::SurfaceReadyObserver::?SurfaceReadyObserver*;376 non-virtual?thunk?to?mir::shell::SurfaceReadyObserver::?SurfaceReadyObserver*;
377 non-virtual?thunk?to?mir::shell::SystemCompositorWindowManager::add_display*;
378 non-virtual?thunk?to?mir::shell::SystemCompositorWindowManager::add_prompt_provider_for*;
379 non-virtual?thunk?to?mir::shell::SystemCompositorWindowManager::close_session*;
380 non-virtual?thunk?to?mir::shell::SystemCompositorWindowManager::create_surface*;
381 non-virtual?thunk?to?mir::shell::SystemCompositorWindowManager::destroy_surface*;
382 non-virtual?thunk?to?mir::shell::SystemCompositorWindowManager::focused_session*;
383 non-virtual?thunk?to?mir::shell::SystemCompositorWindowManager::focused_surface*;
384 non-virtual?thunk?to?mir::shell::SystemCompositorWindowManager::focus_next_session*;
385 non-virtual?thunk?to?mir::shell::SystemCompositorWindowManager::get_surface_attribute*;
386 non-virtual?thunk?to?mir::shell::SystemCompositorWindowManager::handle*;
387 non-virtual?thunk?to?mir::shell::SystemCompositorWindowManager::modify_surface*;
388 non-virtual?thunk?to?mir::shell::SystemCompositorWindowManager::on_session_added*;
389 non-virtual?thunk?to?mir::shell::SystemCompositorWindowManager::on_session_removed*;
390 non-virtual?thunk?to?mir::shell::SystemCompositorWindowManager::on_session_ready*;
391 non-virtual?thunk?to?mir::shell::SystemCompositorWindowManager::open_session*;
392 non-virtual?thunk?to?mir::shell::SystemCompositorWindowManager::raise*;
393 non-virtual?thunk?to?mir::shell::SystemCompositorWindowManager::remove_display*;
394 non-virtual?thunk?to?mir::shell::SystemCompositorWindowManager::set_focus_to*;
395 non-virtual?thunk?to?mir::shell::SystemCompositorWindowManager::set_surface_attribute*;
396 non-virtual?thunk?to?mir::shell::SystemCompositorWindowManager::ShellWrapper*;
397 non-virtual?thunk?to?mir::shell::SystemCompositorWindowManager::start_prompt_session_for*;
398 non-virtual?thunk?to?mir::shell::SystemCompositorWindowManager::stop_prompt_session*;
399 non-virtual?thunk?to?mir::shell::SystemCompositorWindowManager::surface_at*;
348 non-virtual?thunk?to?mir::shell::WindowManager::?WindowManager*;400 non-virtual?thunk?to?mir::shell::WindowManager::?WindowManager*;
349 non-virtual?thunk?to?mir::time::Alarm::?Alarm*;401 non-virtual?thunk?to?mir::time::Alarm::?Alarm*;
350 non-virtual?thunk?to?mir::time::AlarmFactory::?AlarmFactory*;402 non-virtual?thunk?to?mir::time::AlarmFactory::?AlarmFactory*;
@@ -402,6 +454,7 @@
402 typeinfo?for?mir::shell::Shell;454 typeinfo?for?mir::shell::Shell;
403 typeinfo?for?mir::shell::ShellWrapper;455 typeinfo?for?mir::shell::ShellWrapper;
404 typeinfo?for?mir::shell::SurfaceReadyObserver;456 typeinfo?for?mir::shell::SurfaceReadyObserver;
457 typeinfo?for?mir::shell::SystemCompositorWindowManager;
405 typeinfo?for?mir::shell::WindowManager;458 typeinfo?for?mir::shell::WindowManager;
406 typeinfo?for?mir::time::Alarm;459 typeinfo?for?mir::time::Alarm;
407 typeinfo?for?mir::time::AlarmFactory;460 typeinfo?for?mir::time::AlarmFactory;
@@ -459,6 +512,7 @@
459 vtable?for?mir::shell::Shell;512 vtable?for?mir::shell::Shell;
460 vtable?for?mir::shell::ShellWrapper;513 vtable?for?mir::shell::ShellWrapper;
461 vtable?for?mir::shell::SurfaceReadyObserver;514 vtable?for?mir::shell::SurfaceReadyObserver;
515 vtable?for?mir::shell::SystemCompositorWindowManager;
462 vtable?for?mir::shell::WindowManager;516 vtable?for?mir::shell::WindowManager;
463 vtable?for?mir::time::Alarm;517 vtable?for?mir::time::Alarm;
464 vtable?for?mir::time::AlarmFactory;518 vtable?for?mir::time::AlarmFactory;
465519
=== modified file 'tests/acceptance-tests/CMakeLists.txt'
--- tests/acceptance-tests/CMakeLists.txt 2015-06-11 09:41:30 +0000
+++ tests/acceptance-tests/CMakeLists.txt 2015-06-16 08:37:48 +0000
@@ -45,6 +45,7 @@
45 test_surface_modifications.cpp45 test_surface_modifications.cpp
46 test_surface_placement.cpp46 test_surface_placement.cpp
47 test_surface_morphing.cpp47 test_surface_morphing.cpp
48 test_system_compositor_window_manager.cpp
48 test_session_mediator_report.cpp49 test_session_mediator_report.cpp
49)50)
5051
5152
=== added file 'tests/acceptance-tests/test_system_compositor_window_manager.cpp'
--- tests/acceptance-tests/test_system_compositor_window_manager.cpp 1970-01-01 00:00:00 +0000
+++ tests/acceptance-tests/test_system_compositor_window_manager.cpp 2015-06-16 08:37:48 +0000
@@ -0,0 +1,205 @@
1/*
2 * Copyright © 2015 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: Alan Griffiths <alan@octopull.co.uk>
17 */
18
19#include "mir/shell/system_compositor_window_manager.h"
20#include "mir_toolkit/mir_client_library.h"
21
22#include "mir/geometry/rectangle.h"
23#include "mir_test_framework/headless_test.h"
24#include "mir_test/signal.h"
25
26#include "gmock/gmock.h"
27
28namespace msh = mir::shell;
29namespace mt = mir::test;
30namespace mtf = mir_test_framework;
31
32using namespace testing;
33using namespace std::chrono_literals;
34
35namespace
36{
37class SurfaceHandle
38{
39public:
40 explicit SurfaceHandle(MirSurface* surface) : surface{surface} {}
41 ~SurfaceHandle() { if (surface) mir_surface_release_sync(surface); }
42
43 operator MirSurface*() const { return surface; }
44
45 void post_buffer()
46 {
47 mir_buffer_stream_swap_buffers_sync(mir_surface_get_buffer_stream(surface));
48 }
49
50 SurfaceHandle(SurfaceHandle const&& that) : surface{that.surface} { surface = nullptr; }
51private:
52 SurfaceHandle(SurfaceHandle const&) = delete;
53 MirSurface* surface;
54};
55
56struct MockClient
57{
58 explicit MockClient(char const* connect_string) :
59 connection{mir_connect_sync(connect_string, __PRETTY_FUNCTION__)}
60 {
61 }
62
63 MockClient(MockClient&& source) :
64 connection{nullptr}
65 {
66 std::swap(connection, source.connection);
67 }
68
69 auto create_surface(int output_id) -> SurfaceHandle
70 {
71 auto const spec = mir_connection_create_spec_for_normal_surface(
72 connection, 800, 600, mir_pixel_format_bgr_888);
73
74 mir_surface_spec_set_fullscreen_on_output(spec, output_id);
75 auto const surface = mir_surface_create_sync(spec);
76 mir_surface_spec_release(spec);
77
78 mir_surface_set_event_handler(surface, on_surface_event, this);
79
80 return SurfaceHandle{surface};
81 };
82
83 void disconnect()
84 {
85 if (connection)
86 mir_connection_release(connection);
87
88 connection = nullptr;
89 }
90
91 ~MockClient() noexcept
92 {
93 disconnect();
94 }
95
96 MOCK_METHOD2(surface_event, void(MirSurface* surface, const MirEvent* event));
97
98private:
99 MirConnection* connection{nullptr};
100
101 static void on_surface_event(MirSurface* surface, const MirEvent* event, void* client_ptr)
102 {
103 static_cast<MockClient*>(client_ptr)->surface_event(surface, event);
104 }
105};
106
107struct SystemCompositorWindowManager : mtf::HeadlessTest
108{
109 void SetUp() override
110 {
111 add_to_environment("MIR_SERVER_NO_FILE", "");
112
113 initial_display_layout({{{0, 0}, { 640, 480}}, {{480, 0}, {1920, 1080}}});
114
115 server.override_the_window_manager_builder(
116 [this](msh::FocusController* focus_controller)
117 {
118 return std::make_shared<msh::SystemCompositorWindowManager>(
119 focus_controller,
120 server.the_shell_display_layout(),
121 server.the_session_coordinator());
122 });
123
124 start_server();
125 }
126
127 void TearDown() override
128 {
129 stop_server();
130 }
131
132 MockClient connect_client()
133 {
134 return MockClient(new_connection().c_str());
135 }
136};
137
138MATCHER_P(MirFocusEvent, expected, "")
139{
140 if (mir_event_get_type(arg) != mir_event_type_surface)
141 return false;
142
143 auto surface_event = mir_event_get_surface_event(arg);
144 auto attrib = mir_surface_event_get_attribute(surface_event);
145 auto value = mir_surface_event_get_attribute_value(surface_event);
146
147 return (attrib == mir_surface_attrib_focus)
148 && (value == expected);
149}
150}
151
152TEST_F(SystemCompositorWindowManager, when_output_is_valid_surfaces_creation_succeeds)
153{
154 auto client = connect_client();
155
156 auto surface1 = client.create_surface(1);
157 auto surface2 = client.create_surface(2);
158
159 EXPECT_TRUE(mir_surface_is_valid(surface1));
160 EXPECT_TRUE(mir_surface_is_valid(surface2));
161}
162
163TEST_F(SystemCompositorWindowManager, when_output_ID_not_specified_surfaces_creation_fails)
164{
165 auto client = connect_client();
166
167 auto surface = client.create_surface(0);
168
169 EXPECT_FALSE(mir_surface_is_valid(surface));
170 EXPECT_THAT(mir_surface_get_error_message(surface), HasSubstr("Failed to place surface"));
171}
172
173TEST_F(SystemCompositorWindowManager, if_a_surface_posts_client_gets_focus)
174{
175 auto client = connect_client();
176
177 // Throw away all uninteresting surface events
178 EXPECT_CALL(client, surface_event(_, Not(MirFocusEvent(mir_surface_focused)))).Times(AnyNumber());
179
180 auto surface = client.create_surface(1);
181
182 mt::Signal signal;
183
184 EXPECT_CALL(client, surface_event(_, MirFocusEvent(mir_surface_focused))).Times(1)
185 .WillOnce(InvokeWithoutArgs([&] { signal.raise(); }));
186
187 surface.post_buffer();
188
189 signal.wait_for(1s);
190}
191
192TEST_F(SystemCompositorWindowManager, if_no_surface_posts_client_never_gets_focus)
193{
194 auto client = connect_client();
195 auto surface = client.create_surface(1);
196
197 mt::Signal signal;
198
199 ON_CALL(client, surface_event(_, MirFocusEvent(mir_surface_focused)))
200 .WillByDefault(InvokeWithoutArgs([&] { signal.raise(); }));
201
202 EXPECT_CALL(client, surface_event(_, MirFocusEvent(mir_surface_focused))).Times(0);
203
204 signal.wait_for(100ms);
205}

Subscribers

People subscribed via source and target branches