2
* Copyright © 2015 Canonical Ltd.
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.
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.
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/>.
16
* Authored By: Alan Griffiths <alan@octopull.co.uk>
19
#ifndef MIR_SHELL_BASIC_WINDOW_MANAGER_H_
20
#define MIR_SHELL_BASIC_WINDOW_MANAGER_H_
22
#include "mir/geometry/rectangles.h"
23
#include "mir/scene/session.h"
24
#include "mir/scene/surface.h"
25
#include "mir/scene/surface_creation_parameters.h"
26
#include "mir/shell/abstract_shell.h"
27
#include "mir/shell/window_manager.h"
36
template<typename Info>
39
using type = std::map<std::weak_ptr<scene::Surface>, Info, std::owner_less<std::weak_ptr<scene::Surface>>>;
42
template<typename Info>
45
using type = std::map<std::weak_ptr<scene::Session>, Info, std::owner_less<std::weak_ptr<scene::Session>>>;
48
/// The interface through which the policy instructs the controller.
49
/// These functions assume that the BasicWindowManager data structures can be accessed freely.
50
/// I.e. should only be invoked by the policy handle_... methods (where any necessary locks are held).
51
template<typename SessionInfo, typename SurfaceInfo>
52
class BasicWindowManagerTools
55
virtual auto find_session(std::function<bool(SessionInfo const& info)> const& predicate)
56
-> std::shared_ptr<scene::Session> = 0;
58
virtual auto info_for(std::weak_ptr<scene::Session> const& session) const -> SessionInfo& = 0;
60
virtual auto info_for(std::weak_ptr<scene::Surface> const& surface) const -> SurfaceInfo& = 0;
62
virtual auto focused_session() const -> std::shared_ptr<scene::Session> = 0;
64
virtual auto focused_surface() const -> std::shared_ptr<scene::Surface> = 0;
66
virtual void focus_next_session() = 0;
68
virtual void set_focus_to(
69
std::shared_ptr<scene::Session> const& focus,
70
std::shared_ptr<scene::Surface> const& surface) = 0;
72
virtual auto surface_at(geometry::Point cursor) const -> std::shared_ptr<scene::Surface> = 0;
74
virtual void raise(SurfaceSet const& surfaces) = 0;
76
virtual auto active_display() -> geometry::Rectangle const = 0;
78
virtual ~BasicWindowManagerTools() = default;
79
BasicWindowManagerTools() = default;
80
BasicWindowManagerTools(BasicWindowManagerTools const&) = delete;
81
BasicWindowManagerTools& operator=(BasicWindowManagerTools const&) = delete;
84
/// A policy based window manager.
85
/// This takes care of the management of any meta implementation held for the sessions and surfaces.
87
/// \tparam WindowManagementPolicy the constructor must take a pointer to BasicWindowManagerTools<>
88
/// as its first parameter. (Any additional parameters can be forwarded by
89
/// BasicWindowManager::BasicWindowManager.)
90
/// In addition WindowManagementPolicy must implement the following methods:
91
/// - void handle_session_info_updated(SessionInfoMap& session_info, Rectangles const& displays);
92
/// - void handle_displays_updated(SessionInfoMap& session_info, Rectangles const& displays);
93
/// - auto handle_place_new_surface(std::shared_ptr<ms::Session> const& session, ms::SurfaceCreationParameters const& request_parameters) -> ms::SurfaceCreationParameters;
94
/// - void handle_new_surface(std::shared_ptr<ms::Session> const& session, std::shared_ptr<ms::Surface> const& surface);
95
/// - void handle_delete_surface(std::shared_ptr<ms::Session> const& /*session*/, std::weak_ptr<ms::Surface> const& /*surface*/);
96
/// - int handle_set_state(std::shared_ptr<ms::Surface> const& surface, MirSurfaceState value);
97
/// - bool handle_keyboard_event(MirKeyboardEvent const* event);
98
/// - bool handle_touch_event(MirTouchEvent const* event);
99
/// - bool handle_pointer_event(MirPointerEvent const* event);
101
/// \tparam SessionInfo must be default constructable.
103
/// \tparam SurfaceInfo must be constructable from (std::shared_ptr<ms::Session>, std::shared_ptr<ms::Surface>, ms::SurfaceCreationParameters const& params)
104
template<typename WindowManagementPolicy, typename SessionInfo, typename SurfaceInfo>
105
class BasicWindowManager : public WindowManager,
106
private BasicWindowManagerTools<SessionInfo, SurfaceInfo>
109
template <typename... PolicyArgs>
111
FocusController* focus_controller,
112
PolicyArgs&&... policy_args) :
113
focus_controller(focus_controller),
114
policy(this, std::forward<PolicyArgs>(policy_args)...)
119
void add_session(std::shared_ptr<scene::Session> const& session) override
121
std::lock_guard<decltype(mutex)> lock(mutex);
122
session_info[session] = SessionInfo();
123
policy.handle_session_info_updated(session_info, displays);
126
void remove_session(std::shared_ptr<scene::Session> const& session) override
128
std::lock_guard<decltype(mutex)> lock(mutex);
129
session_info.erase(session);
130
policy.handle_session_info_updated(session_info, displays);
133
frontend::SurfaceId add_surface(
134
std::shared_ptr<scene::Session> const& session,
135
scene::SurfaceCreationParameters const& params,
136
std::function<frontend::SurfaceId(std::shared_ptr<scene::Session> const& session, scene::SurfaceCreationParameters const& params)> const& build) override
138
std::lock_guard<decltype(mutex)> lock(mutex);
139
scene::SurfaceCreationParameters const placed_params = policy.handle_place_new_surface(session, params);
140
auto const result = build(session, placed_params);
141
auto const surface = session->surface(result);
142
policy.handle_new_surface(session, surface);
143
surface_info.emplace(surface, SurfaceInfo{session, surface, placed_params});
148
std::shared_ptr<scene::Session> const& session,
149
std::shared_ptr<scene::Surface> const& surface,
150
shell::SurfaceSpecification const& modifications) override
152
std::lock_guard<decltype(mutex)> lock(mutex);
153
policy.handle_modify_surface(session, surface, modifications);
157
std::shared_ptr<scene::Session> const& session,
158
std::weak_ptr<scene::Surface> const& surface) override
160
std::lock_guard<decltype(mutex)> lock(mutex);
161
policy.handle_delete_surface(session, surface);
163
surface_info.erase(surface);
166
void add_display(geometry::Rectangle const& area) override
168
std::lock_guard<decltype(mutex)> lock(mutex);
170
policy.handle_displays_updated(session_info, displays);
173
void remove_display(geometry::Rectangle const& area) override
175
std::lock_guard<decltype(mutex)> lock(mutex);
176
displays.remove(area);
177
policy.handle_displays_updated(session_info, displays);
180
bool handle_keyboard_event(MirKeyboardEvent const* event) override
182
std::lock_guard<decltype(mutex)> lock(mutex);
183
return policy.handle_keyboard_event(event);
186
bool handle_touch_event(MirTouchEvent const* event) override
188
std::lock_guard<decltype(mutex)> lock(mutex);
189
return policy.handle_touch_event(event);
192
bool handle_pointer_event(MirPointerEvent const* event) override
194
std::lock_guard<decltype(mutex)> lock(mutex);
197
mir_pointer_event_axis_value(event, mir_pointer_axis_x),
198
mir_pointer_event_axis_value(event, mir_pointer_axis_y)};
200
return policy.handle_pointer_event(event);
203
int set_surface_attribute(
204
std::shared_ptr<scene::Session> const& /*session*/,
205
std::shared_ptr<scene::Surface> const& surface,
206
MirSurfaceAttrib attrib,
209
std::lock_guard<decltype(mutex)> lock(mutex);
212
case mir_surface_attrib_state:
214
auto const state = policy.handle_set_state(surface, MirSurfaceState(value));
215
return surface->configure(attrib, state);
218
return surface->configure(attrib, value);
222
auto find_session(std::function<bool(SessionInfo const& info)> const& predicate)
223
-> std::shared_ptr<scene::Session> override
225
for(auto& info : session_info)
227
if (predicate(info.second))
229
return info.first.lock();
233
return std::shared_ptr<scene::Session>{};
236
auto info_for(std::weak_ptr<scene::Session> const& session) const -> SessionInfo& override
238
return const_cast<SessionInfo&>(session_info.at(session));
241
auto info_for(std::weak_ptr<scene::Surface> const& surface) const -> SurfaceInfo& override
243
return const_cast<SurfaceInfo&>(surface_info.at(surface));
246
auto focused_session() const -> std::shared_ptr<scene::Session> override
248
return focus_controller->focused_session();
251
auto focused_surface() const -> std::shared_ptr<scene::Surface> override
253
return focus_controller->focused_surface();
256
void focus_next_session() override
258
focus_controller->focus_next_session();
262
std::shared_ptr<scene::Session> const& focus,
263
std::shared_ptr<scene::Surface> const& surface) override
265
focus_controller->set_focus_to(focus, surface);
268
auto surface_at(geometry::Point cursor) const -> std::shared_ptr<scene::Surface> override
270
return focus_controller->surface_at(cursor);
273
void raise(SurfaceSet const& surfaces) override
275
focus_controller->raise(surfaces);
278
auto active_display() -> geometry::Rectangle const override
280
geometry::Rectangle result;
282
// 1. If a window has input focus, whichever display contains the largest
283
// proportion of the area of that window.
284
if (auto const surface = focused_surface())
286
auto const surface_rect = surface->input_bounds();
287
int max_overlap_area = -1;
289
for (auto const& display : displays)
291
auto const intersection = surface_rect.intersection_with(display).size;
292
if (intersection.width.as_int()*intersection.height.as_int() > max_overlap_area)
294
max_overlap_area = intersection.width.as_int()*intersection.height.as_int();
301
// 2. Otherwise, if any window previously had input focus, for the window that had
302
// it most recently, the display that contained the largest proportion of the
303
// area of that window at the moment it closed, as long as that display is still
306
// 3. Otherwise, the display that contains the pointer, if there is one.
307
for (auto const& display : displays)
309
if (display.contains(cursor))
311
// Ignore the (unspecified) possiblity of overlapping displays
316
// 4. Otherwise, the primary display, if there is one (for example, the laptop display).
318
// 5. Otherwise, the first display.
320
result = *displays.begin();
325
FocusController* const focus_controller;
326
WindowManagementPolicy policy;
329
typename SessionTo<SessionInfo>::type session_info;
330
typename SurfaceTo<SurfaceInfo>::type surface_info;
331
geometry::Rectangles displays;
332
geometry::Point cursor;
337
#endif /* MIR_SHELL_BASIC_WINDOW_MANAGER_H_ */