55
52
std::lock_guard<std::mutex> const lock;
56
miral::WindowManagementPolicy* const policy;
53
WindowManagementPolicy* const policy;
56
miral::BasicWindowManager::Locker::Locker(BasicWindowManager* self) :
58
policy{self->policy.get()}
60
policy->advise_begin();
61
std::vector<std::weak_ptr<Workspace>> workspaces;
63
std::lock_guard<std::mutex> const lock{self->dead_workspaces.dead_workspaces_mutex};
64
workspaces.swap(self->dead_workspaces.workspaces);
67
for (auto const& workspace : workspaces)
68
self->workspaces_to_windows.left.erase(workspace);
74
auto find_workspace_policy(std::unique_ptr<miral::WindowManagementPolicy> const& policy) -> miral::WorkspacePolicy*
76
miral::WorkspacePolicy* result = dynamic_cast<miral::WorkspacePolicy*>(policy.get());
81
struct NullWorkspacePolicy : miral::WorkspacePolicy
83
void advise_adding_to_workspace(
84
std::shared_ptr<miral::Workspace> const&, std::vector<miral::Window> const&) override
88
void advise_removing_from_workspace(
89
std::shared_ptr<miral::Workspace> const&, std::vector<miral::Window> const&) override
94
static NullWorkspacePolicy null_workspace_policy;
96
return &null_workspace_policy;
60
101
miral::BasicWindowManager::BasicWindowManager(
61
102
shell::FocusController* focus_controller,
65
106
focus_controller(focus_controller),
66
107
display_layout(display_layout),
67
108
persistent_surface_store{persistent_surface_store},
68
policy(build(WindowManagerTools{this}))
109
policy(build(WindowManagerTools{this})),
110
workspace_policy{find_workspace_policy(policy)}
72
114
void miral::BasicWindowManager::add_session(std::shared_ptr<scene::Session> const& session)
74
Locker lock{mutex, policy};
75
117
policy->advise_new_app(app_info[session] = ApplicationInfo(session));
78
120
void miral::BasicWindowManager::remove_session(std::shared_ptr<scene::Session> const& session)
80
Locker lock{mutex, policy};
81
123
policy->advise_delete_app(app_info[session]);
82
124
app_info.erase(session);
153
198
std::shared_ptr<scene::Session> const& session,
154
199
std::weak_ptr<scene::Surface> const& surface)
156
Locker lock{mutex, policy};
157
202
remove_window(session, info_for(surface));
160
205
void miral::BasicWindowManager::remove_window(Application const& application, miral::WindowInfo const& info)
207
bool const is_active_window{mru_active_windows.top() == info.window()};
208
auto const workspaces_containing_window = workspaces_containing(info.window());
211
std::vector<Window> const windows_removed{info.window()};
213
for (auto const& workspace : workspaces_containing_window)
215
workspace_policy->advise_removing_from_workspace(workspace, windows_removed);
218
workspaces_to_windows.right.erase(info.window());
162
221
policy->advise_delete_window(info);
164
bool const is_active_window{mru_active_windows.top() == info.window()};
166
223
info_for(application).remove_window(info.window());
167
224
mru_active_windows.erase(info.window());
168
225
fullscreen_surfaces.erase(info.window());
176
233
if (is_active_window)
178
// Try to make the parent active
179
if (parent && select_active_window(parent))
182
if (can_activate_window_for_session(application))
185
// Try to activate to recently active window of any application
187
miral::Window new_focus;
189
mru_active_windows.enumerate([&](miral::Window& window)
235
refocus(application, parent, workspaces_containing_window);
239
void miral::BasicWindowManager::refocus(
240
miral::Application const& application, miral::Window const& parent,
241
std::vector<std::shared_ptr<Workspace>> const& workspaces_containing_window)
243
// Try to make the parent active
244
if (parent && select_active_window(parent))
247
if (can_activate_window_for_session_in_workspace(application, workspaces_containing_window))
250
// Try to activate to recently active window of any application in a shared workspace
252
miral::Window new_focus;
254
mru_active_windows.enumerate([&](miral::Window& window)
256
// select_active_window() calls set_focus_to() which updates mru_active_windows and changes window
257
auto const w = window;
259
for (auto const& workspace : workspaces_containing(w))
191
// select_active_window() calls set_focus_to() which updates mru_active_windows and changes window
192
auto const w = window;
193
return !(new_focus = select_active_window(w));
196
if (new_focus) return;
199
// Fallback to cycling through applications
200
focus_next_application();
261
for (auto const& ww : workspaces_containing_window)
265
return !(new_focus = select_active_window(w));
273
if (new_focus) return;
276
if (can_activate_window_for_session(application))
279
// Try to activate to recently active window of any application
281
miral::Window new_focus;
283
mru_active_windows.enumerate([&](miral::Window& window)
285
// select_active_window() calls set_focus_to() which updates mru_active_windows and changes window
286
auto const w = window;
287
return !(new_focus = select_active_window(w));
290
if (new_focus) return;
293
// Fallback to cycling through applications
294
focus_next_application();
204
297
void miral::BasicWindowManager::erase(miral::WindowInfo const& info)
246
339
bool miral::BasicWindowManager::handle_keyboard_event(MirKeyboardEvent const* event)
248
Locker lock{mutex, policy};
249
342
update_event_timestamp(event);
250
343
return policy->handle_keyboard_event(event);
253
346
bool miral::BasicWindowManager::handle_touch_event(MirTouchEvent const* event)
255
Locker lock{mutex, policy};
256
349
update_event_timestamp(event);
257
350
return policy->handle_touch_event(event);
260
353
bool miral::BasicWindowManager::handle_pointer_event(MirPointerEvent const* event)
262
Locker lock{mutex, policy};
263
356
update_event_timestamp(event);
408
501
void miral::BasicWindowManager::focus_next_application()
503
if (auto const prev = active_window())
505
auto const workspaces_containing_window = workspaces_containing(prev);
507
if (!workspaces_containing_window.empty())
511
focus_controller->focus_next_session();
513
if (can_activate_window_for_session_in_workspace(
514
focus_controller->focused_session(),
515
workspaces_containing_window))
520
while (focus_controller->focused_session() != prev.application());
410
525
focus_controller->focus_next_session();
412
527
if (can_activate_window_for_session(focus_controller->focused_session()))
417
532
select_active_window(focussed_surface ? info_for(focussed_surface).window() : Window{});
535
auto miral::BasicWindowManager::workspaces_containing(Window const& window) const
536
-> std::vector<std::shared_ptr<Workspace>>
538
auto const iter_pair = workspaces_to_windows.right.equal_range(window);
540
std::vector<std::shared_ptr<Workspace>> workspaces_containing_window;
541
for (auto kv = iter_pair.first; kv != iter_pair.second; ++kv)
543
if (auto const workspace = kv->second.lock())
545
workspaces_containing_window.push_back(workspace);
549
return workspaces_containing_window;
420
552
void miral::BasicWindowManager::focus_next_within_application()
422
554
if (auto const prev = active_window())
556
auto const workspaces_containing_window = workspaces_containing(prev);
424
557
auto const& siblings = info_for(prev.application()).windows();
425
558
auto current = find(begin(siblings), end(siblings), prev);
427
560
if (current != end(siblings))
562
while (++current != end(siblings))
564
for (auto const& workspace : workspaces_containing(*current))
566
for (auto const& ww : workspaces_containing_window)
570
if (prev != select_active_window(*current))
578
for (current = begin(siblings); *current != prev; ++current)
580
for (auto const& workspace : workspaces_containing(*current))
582
for (auto const& ww : workspaces_containing_window)
586
if (prev != select_active_window(*current))
593
current = find(begin(siblings), end(siblings), prev);
594
if (current != end(siblings))
429
596
while (++current != end(siblings) && prev == select_active_window(*current))
887
1054
if (window == active_window())
1056
auto const workspaces_containing_window = workspaces_containing(window);
889
1058
// Try to activate to recently active window of any application
890
1059
mru_active_windows.enumerate([&](Window& candidate)
892
1061
if (candidate == window)
894
1063
auto const w = candidate;
1064
for (auto const& workspace : workspaces_containing(w))
1066
for (auto const& ww : workspaces_containing_window)
1068
if (ww == workspace)
1070
return !(select_active_window(w));
1078
// Try to activate to recently active window of any application
1079
if (window == active_window() || !active_window())
1080
mru_active_windows.enumerate([&](Window& candidate)
1082
if (candidate == window)
1084
auto const w = candidate;
895
1085
return !(select_active_window(w));
1076
1266
return new_focus;
1269
auto miral::BasicWindowManager::can_activate_window_for_session_in_workspace(
1270
Application const& session,
1271
std::vector<std::shared_ptr<Workspace>> const& workspaces) -> bool
1273
miral::Window new_focus;
1275
mru_active_windows.enumerate([&](miral::Window& window)
1277
// select_active_window() calls set_focus_to() which updates mru_active_windows and changes window
1278
auto const w = window;
1280
if (w.application() != session)
1283
for (auto const& workspace : workspaces_containing(w))
1285
for (auto const& ww : workspaces)
1287
if (ww == workspace)
1288
return !(new_focus = select_active_window(w));
1079
1298
auto miral::BasicWindowManager::place_new_surface(ApplicationInfo const& app_info, WindowSpecification parameters)
1080
1299
-> WindowSpecification
1610
1829
BOOST_THROW_EXCEPTION(std::runtime_error("height must be positive"));
1833
class miral::Workspace
1836
explicit Workspace(miral::BasicWindowManager::DeadWorkspaces& dead_workspaces) :
1837
dead_workspaces{dead_workspaces} {}
1839
std::weak_ptr<Workspace> self;
1843
std::lock_guard<std::mutex> lock {dead_workspaces.dead_workspaces_mutex};
1844
dead_workspaces.workspaces.push_back(self);
1848
miral::BasicWindowManager::DeadWorkspaces& dead_workspaces;
1851
auto miral::BasicWindowManager::create_workspace() -> std::shared_ptr<Workspace>
1853
auto const result = std::make_shared<Workspace>(dead_workspaces);
1854
result->self = result;
1858
void miral::BasicWindowManager::add_tree_to_workspace(
1859
miral::Window const& window, std::shared_ptr<miral::Workspace> const& workspace)
1861
if (!window) return;
1864
auto const* info = &info_for(root);
1866
while (auto const& parent = info->parent())
1869
info = &info_for(root);
1872
std::vector<Window> windows;
1874
std::function<void(WindowInfo const& info)> const add_children =
1875
[&,this](WindowInfo const& info)
1877
for (auto const& child : info.children())
1879
windows.push_back(child);
1880
add_children(info_for(child));
1884
windows.push_back(root);
1885
add_children(*info);
1887
auto const iter_pair = workspaces_to_windows.left.equal_range(workspace);
1889
std::vector<Window> windows_added;
1891
for (auto& w : windows)
1893
if (!std::count_if(iter_pair.first, iter_pair.second,
1894
[&w](wwbimap_t::left_value_type const& kv) { return kv.second == w; }))
1896
workspaces_to_windows.left.insert(wwbimap_t::left_value_type{workspace, w});
1897
windows_added.push_back(w);
1901
if (!windows_added.empty())
1902
workspace_policy->advise_adding_to_workspace(workspace, windows_added);
1905
void miral::BasicWindowManager::remove_tree_from_workspace(
1906
miral::Window const& window, std::shared_ptr<miral::Workspace> const& workspace)
1908
if (!window) return;
1911
auto const* info = &info_for(root);
1913
while (auto const& parent = info->parent())
1916
info = &info_for(root);
1919
std::vector<Window> windows;
1921
std::function<void(WindowInfo const& info)> const add_children =
1922
[&,this](WindowInfo const& info)
1924
for (auto const& child : info.children())
1926
windows.push_back(child);
1927
add_children(info_for(child));
1931
windows.push_back(root);
1932
add_children(*info);
1934
std::vector<Window> windows_removed;
1936
auto const iter_pair = workspaces_to_windows.left.equal_range(workspace);
1937
for (auto kv = iter_pair.first; kv != iter_pair.second; ++kv)
1939
if (std::count(begin(windows), end(windows), kv->second))
1941
workspaces_to_windows.left.erase(kv);
1942
windows_removed.push_back(kv->second);
1946
if (!windows_removed.empty())
1947
workspace_policy->advise_removing_from_workspace(workspace, windows_removed);
1950
void miral::BasicWindowManager::for_each_workspace_containing(
1951
miral::Window const& window, std::function<void(std::shared_ptr<miral::Workspace> const&)> const& callback)
1953
auto const iter_pair = workspaces_to_windows.right.equal_range(window);
1954
for (auto kv = iter_pair.first; kv != iter_pair.second; ++kv)
1956
if (auto const workspace = kv->second.lock())
1957
callback(workspace);
1961
void miral::BasicWindowManager::for_each_window_in_workspace(
1962
std::shared_ptr<miral::Workspace> const& workspace, std::function<void(miral::Window const&)> const& callback)
1964
auto const iter_pair = workspaces_to_windows.left.equal_range(workspace);
1965
for (auto kv = iter_pair.first; kv != iter_pair.second; ++kv)
1966
callback(kv->second);