Merge lp:~alan-griffiths/miral/workspaces-example into lp:miral

Proposed by Alan Griffiths on 2017-02-10
Status: Superseded
Proposed branch: lp:~alan-griffiths/miral/workspaces-example
Merge into: lp:miral
Prerequisite: lp:~alan-griffiths/miral/workspaces
Diff against target: 498 lines (+256/-29)
7 files modified
miral-shell/titlebar_provider.cpp (+6/-3)
miral-shell/titlebar_provider.h (+1/-1)
miral-shell/titlebar_window_manager.cpp (+182/-5)
miral-shell/titlebar_window_manager.h (+20/-1)
miral/basic_window_manager.cpp (+17/-14)
miral/mru_window_list.cpp (+24/-3)
test/mru_window_list.cpp (+6/-2)
To merge this branch: bzr merge lp:~alan-griffiths/miral/workspaces-example
Reviewer Review Type Date Requested Status
Alan Griffiths Abstain on 2017-02-16
Gerry Boland 2017-02-10 Approve on 2017-02-10
Review via email: mp+316975@code.launchpad.net

This proposal has been superseded by a proposal from 2017-02-17.

Commit Message

[miral-shell] Example workspaces implementation

Description of the Change

[miral-shell] Example workspaces implementation

Provides four workspaces:

  o Switch workspace . . . . . . . . . . : Meta-Alt-[F1|F2|F3|F4]
  o Switch workspace taking active window: Meta-Ctrl-[F1|F2|F3|F4]

To post a comment you must log in.
Gerry Boland (gerboland) wrote :

Looks quite ok. The old state save/restore and window_state_hidden updates are a bit repetitive, but more belong in the policy implementation, so is ok

review: Approve
508. By Alan Griffiths on 2017-02-13

merge lp:~alan-griffiths/miral/workspaces/

509. By Alan Griffiths on 2017-02-14

merge lp:~alan-griffiths/miral/workspaces

510. By Alan Griffiths on 2017-02-14

Tidy up code

511. By Alan Griffiths on 2017-02-15

merge lp:~alan-griffiths/miral/workspaces

512. By Alan Griffiths on 2017-02-15

merge lp:~alan-griffiths/miral/workspaces

Alan Griffiths (alan-griffiths) wrote :

The active window tracking gets confused here.

Start miral-app

Start an app from the command line (e.g. mir_demo_client_eglplasma)

Move that app to another workspace (e.g. Ctrl-Meta-F4)

Switch back to first workspace (Alt-Meta-F4)

Move the terminal too (e.g. Ctrl-Meta-F4)

Now
1. Both apps show a "focussed" toolbar
2. Alt-Tab doesn't switch between apps

review: Needs Fixing
Alan Griffiths (alan-griffiths) wrote :

If a window in a hidden sets the state from the client then it overrides the hidden state imposed by the workspace.

review: Needs Fixing
513. By Alan Griffiths on 2017-02-16

Factor out common code

514. By Alan Griffiths on 2017-02-16

Fix handling of window state changes when on hidden workspace

Alan Griffiths (alan-griffiths) wrote :

> If a window in a hidden sets the state from the client then it overrides the
> hidden state imposed by the workspace.

Fixed

515. By Alan Griffiths on 2017-02-16

Don't lose unhiding windows from the MRU list

516. By Alan Griffiths on 2017-02-16

Remember the current intensity of *each* titlebar, not just the last one painted

Alan Griffiths (alan-griffiths) wrote :

> 1. Both apps show a "focussed" toolbar
> 2. Alt-Tab doesn't switch between apps

Fixed

review: Abstain
Brandon Schaefer (brandontschaefer) wrote :

An issues I can reproduce:
1) Open egl plasma demo
2) Open egl triangle demo
3) egl triangle should be on top
4) switch work spaces to 2, meta + alt + f2
5) switch back to work space 1, meta + alt + f1
6) (note that egl triangle is ontop still but no window appears to be focused, ie. toolbars are greyed out)
7) switch back to work space 2, meta + alt + f2
8) switch back to work space 1, meta + alt + f1

Expected:
  egl triangle to still be on top and focused

Result:
  egl triangle is below egl plasma and plasma has focus

You can test this by alt+tabbing to get triangle back on top.

517. By Alan Griffiths on 2017-02-17

Track active window history better when hiding windows

518. By Alan Griffiths on 2017-02-17

When switching workspaces, remember where focus was, so it doesn't randomly go to the first window we unhide

Alan Griffiths (alan-griffiths) wrote :

> An issues I can reproduce:
> 1) Open egl plasma demo
> 2) Open egl triangle demo
> 3) egl triangle should be on top
> 4) switch work spaces to 2, meta + alt + f2
> 5) switch back to work space 1, meta + alt + f1
> 6) (note that egl triangle is ontop still but no window appears to be focused,
> ie. toolbars are greyed out)
> 7) switch back to work space 2, meta + alt + f2
> 8) switch back to work space 1, meta + alt + f1
>
> Expected:
> egl triangle to still be on top and focused
>
> Result:
> egl triangle is below egl plasma and plasma has focus
>
> You can test this by alt+tabbing to get triangle back on top.

Fixed

519. By Alan Griffiths on 2017-02-17

merge :parent

520. By Alan Griffiths on 2017-02-17

merge lp:~alan-griffiths/miral/mru-window-visiblity

521. By Alan Griffiths on 2017-02-17

merge lp:~alan-griffiths/miral/workspace-examples-prerequisites

522. By Alan Griffiths on 2017-02-17

Add workspace keys

523. By Alan Griffiths on 2017-02-17

merge lp:~alan-griffiths/miral/workspace-examples-prerequisites

524. By Alan Griffiths on 2017-02-17

Fix logging

525. By Alan Griffiths on 2017-02-17

Fix

526. By Alan Griffiths on 2017-02-17

Fix logging

527. By Alan Griffiths on 2017-02-17

Better solution

528. By Alan Griffiths on 2017-02-20

Comments to clarify code I can't simplify

529. By Alan Griffiths on 2017-02-20

DRY - reduce repetitive workspace visible/hidden code

530. By Alan Griffiths on 2017-02-20

merge :parent

531. By Alan Griffiths on 2017-02-20

merge lp:~alan-griffiths/miral/workspace-examples-prerequisites

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'miral-shell/titlebar_provider.cpp'
2--- miral-shell/titlebar_provider.cpp 2017-02-14 11:49:59 +0000
3+++ miral-shell/titlebar_provider.cpp 2017-02-17 12:58:48 +0000
4@@ -222,10 +222,10 @@
5
6 void TitlebarProvider::paint_titlebar_for(miral::WindowInfo const& info, int intensity)
7 {
8- this->intensity = intensity;
9-
10 if (auto data = find_titlebar_data(info.window()))
11 {
12+ data->intensity = intensity;
13+
14 auto const title = info.name();
15
16 if (auto surface = data->titlebar.load())
17@@ -339,7 +339,10 @@
18 auto const title = window_info.name();
19
20 if (auto surface = data->titlebar.load())
21- enqueue_work([this, surface, title]{ paint_surface(surface, title, intensity); });
22+ {
23+ enqueue_work([this, surface, title, intensity=data->intensity.load()]
24+ { paint_surface(surface, title, intensity); });
25+ }
26 }
27 }
28
29
30=== modified file 'miral-shell/titlebar_provider.h'
31--- miral-shell/titlebar_provider.h 2017-02-14 11:49:59 +0000
32+++ miral-shell/titlebar_provider.h 2017-02-17 12:58:48 +0000
33@@ -79,6 +79,7 @@
34 struct Data
35 {
36 std::atomic<MirWindow*> titlebar{nullptr};
37+ std::atomic<int> intensity{0xff};
38 std::function<void(MirWindow* surface)> on_create{[](MirWindow*){}};
39 miral::Window window;
40
41@@ -92,7 +93,6 @@
42 std::mutex mutable mutex;
43 mir::client::Connection connection;
44 std::weak_ptr<mir::scene::Session> weak_session;
45- std::atomic<int> intensity{0xff};
46
47 SurfaceMap window_to_titlebar;
48 TitleMap windows_awaiting_titlebar;
49
50=== modified file 'miral-shell/titlebar_window_manager.cpp'
51--- miral-shell/titlebar_window_manager.cpp 2017-02-15 16:54:12 +0000
52+++ miral-shell/titlebar_window_manager.cpp 2017-02-17 12:58:48 +0000
53@@ -32,6 +32,44 @@
54 namespace
55 {
56 int const title_bar_height = 12;
57+
58+struct PolicyData
59+{
60+ bool in_hidden_workspace{false};
61+
62+ void update_for_active_workspace(WindowManagerTools& tools, WindowInfo const& window_info)
63+ {
64+ if (in_hidden_workspace)
65+ {
66+ in_hidden_workspace = false;
67+ WindowSpecification modifications;
68+ modifications.state() = old_state;
69+ tools.place_and_size_for_state(modifications, window_info);
70+ tools.modify_window(window_info.window(), modifications);
71+ }
72+ }
73+
74+ void update_for_hidden_workspace(WindowManagerTools& tools, WindowInfo const& window_info)
75+ {
76+ if (!in_hidden_workspace)
77+ {
78+ in_hidden_workspace = true;
79+ old_state = window_info.state();
80+
81+ WindowSpecification modifications;
82+ modifications.state() = mir_window_state_hidden;
83+ tools.place_and_size_for_state(modifications, window_info);
84+ tools.modify_window(window_info.window(), modifications);
85+ }
86+ }
87+
88+ MirWindowState old_state;
89+};
90+
91+inline PolicyData& policy_data_for(WindowInfo const& info)
92+{
93+ return *std::static_pointer_cast<PolicyData>(info.userdata());
94+}
95 }
96
97 TitlebarWindowManagerPolicy::TitlebarWindowManagerPolicy(
98@@ -43,6 +81,11 @@
99 titlebar_provider{std::make_unique<TitlebarProvider>(tools)}
100 {
101 launcher.launch("decorations", *titlebar_provider);
102+
103+ for (auto key : {KEY_F1, KEY_F2, KEY_F3, KEY_F4})
104+ key_to_workspace[key] = this->tools.create_workspace();
105+
106+ active_workspace = key_to_workspace[KEY_F1];
107 }
108
109 TitlebarWindowManagerPolicy::~TitlebarWindowManagerPolicy() = default;
110@@ -267,18 +310,31 @@
111 CanonicalWindowManagerPolicy::advise_new_window(window_info);
112
113 auto const application = window_info.window().application();
114-
115- if (application == titlebar_provider->session())
116+ auto const parent = window_info.parent();
117+
118+ auto const is_titlebar = application == titlebar_provider->session();
119+
120+ if (is_titlebar)
121 {
122 titlebar_provider->advise_new_titlebar(window_info);
123
124- auto const parent = window_info.parent();
125-
126 if (tools.active_window() == parent)
127 titlebar_provider->paint_titlebar_for(tools.info_for(parent), 0xFF);
128 else
129 titlebar_provider->paint_titlebar_for(tools.info_for(parent), 0x3F);
130 }
131+
132+ if (!parent)
133+ tools.add_tree_to_workspace(window_info.window(), active_workspace);
134+ else
135+ {
136+ auto& pdata = policy_data_for(window_info);
137+
138+ pdata.in_hidden_workspace = policy_data_for(tools.info_for(parent)).in_hidden_workspace;
139+
140+ if (policy_data_for(tools.info_for(parent)).in_hidden_workspace)
141+ pdata.update_for_hidden_workspace(tools, window_info);
142+ }
143 }
144
145 void TitlebarWindowManagerPolicy::handle_window_ready(WindowInfo& window_info)
146@@ -339,6 +395,36 @@
147 auto const scan_code = mir_keyboard_event_scan_code(event);
148 auto const modifiers = mir_keyboard_event_modifiers(event) & modifier_mask;
149
150+ // Switch workspaces
151+ if (action == mir_keyboard_action_down &&
152+ modifiers == (mir_input_event_modifier_alt | mir_input_event_modifier_meta))
153+ {
154+ switch (scan_code)
155+ {
156+ case KEY_F1:
157+ case KEY_F2:
158+ case KEY_F3:
159+ case KEY_F4:
160+ switch_workspace_to(key_to_workspace[scan_code]);
161+ return true;
162+ }
163+ }
164+
165+ // Switch workspace taking the active window
166+ if (action == mir_keyboard_action_down &&
167+ modifiers == (mir_input_event_modifier_ctrl | mir_input_event_modifier_meta))
168+ {
169+ switch (scan_code)
170+ {
171+ case KEY_F1:
172+ case KEY_F2:
173+ case KEY_F3:
174+ case KEY_F4:
175+ switch_workspace_to(key_to_workspace[scan_code], tools.active_window());
176+ return true;
177+ }
178+ }
179+
180 if (action != mir_keyboard_action_repeat)
181 end_resize();
182
183@@ -364,7 +450,7 @@
184 }
185 else if (action == mir_keyboard_action_down && scan_code == KEY_F4)
186 {
187- switch (modifiers & modifier_mask)
188+ switch (modifiers)
189 {
190 case mir_input_event_modifier_alt|mir_input_event_modifier_shift:
191 if (auto const& window = tools.active_window())
192@@ -571,5 +657,96 @@
193 if (app_info.application() == titlebar_provider->session())
194 titlebar_provider->place_new_titlebar(parameters);
195
196+ parameters.userdata() = std::make_shared<PolicyData>();
197 return parameters;
198 }
199+
200+void TitlebarWindowManagerPolicy::advise_adding_to_workspace(
201+ std::shared_ptr<Workspace> const& workspace, std::vector<Window> const& windows)
202+{
203+ if (windows.empty())
204+ return;
205+
206+ for (auto const& window : windows)
207+ {
208+ auto const& window_info = tools.info_for(window);
209+ auto& pdata = policy_data_for(window_info);
210+
211+ if (workspace == active_workspace)
212+ {
213+ pdata.update_for_active_workspace(tools, window_info);
214+ }
215+ else
216+ {
217+ pdata.update_for_hidden_workspace(tools, window_info);
218+ }
219+ }
220+}
221+
222+void TitlebarWindowManagerPolicy::switch_workspace_to(
223+ std::shared_ptr<Workspace> const& workspace,
224+ Window const& window)
225+{
226+ if (workspace == active_workspace)
227+ return;
228+
229+ auto const old_active = active_workspace;
230+ active_workspace = workspace;
231+
232+ // Remember active_window when we switch away
233+ workspace_to_active[old_active] = tools.active_window();
234+
235+ tools.add_tree_to_workspace(window, active_workspace);
236+
237+ if (!window)
238+ {
239+ if (auto const ww = workspace_to_active[workspace])
240+ {
241+ tools.for_each_workspace_containing(ww, [&](std::shared_ptr<miral::Workspace> const& ws)
242+ {
243+ if (ws == workspace)
244+ {
245+ auto const& window_info = tools.info_for(ww);
246+ auto& pdata = policy_data_for(window_info);
247+ pdata.update_for_active_workspace(tools, window_info);
248+ }
249+ });
250+ }
251+ }
252+
253+ tools.for_each_window_in_workspace(active_workspace, [&](Window const& window)
254+ {
255+ if (window.application() == titlebar_provider->session())
256+ return; // titlebars are taken care of automatically
257+
258+ auto const& window_info = tools.info_for(window);
259+ auto& pdata = policy_data_for(window_info);
260+ pdata.update_for_active_workspace(tools, window_info);
261+ });
262+
263+ tools.remove_tree_from_workspace(window, old_active);
264+
265+ tools.for_each_window_in_workspace(old_active, [&](Window const& window)
266+ {
267+ if (window.application() == titlebar_provider->session())
268+ return; // titlebars are taken care of automatically
269+
270+ auto const& window_info = tools.info_for(window);
271+ auto& pdata = policy_data_for(window_info);
272+
273+ pdata.update_for_hidden_workspace(tools, window_info);
274+ });
275+}
276+
277+void TitlebarWindowManagerPolicy::handle_modify_window(WindowInfo& window_info, WindowSpecification const& modifications)
278+{
279+ auto mods = modifications;
280+
281+ auto& pdata = policy_data_for(window_info);
282+
283+ if (pdata.in_hidden_workspace && mods.state().is_set())
284+ pdata.old_state = mods.state().consume();
285+
286+ CanonicalWindowManagerPolicy::handle_modify_window(window_info, mods);
287+}
288+
289
290=== modified file 'miral-shell/titlebar_window_manager.h'
291--- miral-shell/titlebar_window_manager.h 2017-02-15 16:54:12 +0000
292+++ miral-shell/titlebar_window_manager.h 2017-02-17 12:58:48 +0000
293@@ -20,10 +20,12 @@
294 #define MIRAL_SHELL_TITLEBAR_WINDOW_MANAGER_H
295
296 #include <miral/canonical_window_manager.h>
297+#include <miral/workspace_policy.h>
298
299 #include "spinner/splash.h"
300
301 #include <chrono>
302+#include <map>
303
304 namespace miral { class InternalClientLauncher; }
305
306@@ -31,7 +33,7 @@
307
308 class TitlebarProvider;
309
310-class TitlebarWindowManagerPolicy : public miral::CanonicalWindowManagerPolicy
311+class TitlebarWindowManagerPolicy : public miral::CanonicalWindowManagerPolicy, miral::WorkspacePolicy
312 {
313 public:
314 TitlebarWindowManagerPolicy(miral::WindowManagerTools const& tools, SpinnerSplash const& spinner, miral::InternalClientLauncher const& launcher);
315@@ -48,6 +50,8 @@
316 * o Maximize/restore current window (to display size): Alt-F11
317 * o Maximize/restore current window (to display height): Shift-F11
318 * o Maximize/restore current window (to display width): Ctrl-F11
319+ * o Switch workspace . . . . . . . . . . : Meta-Alt-[F1|F2|F3|F4]
320+ * o Switch workspace taking active window: Meta-Ctrl-[F1|F2|F3|F4]
321 * @{ */
322 bool handle_pointer_event(MirPointerEvent const* event) override;
323 bool handle_touch_event(MirTouchEvent const* event) override;
324@@ -63,6 +67,8 @@
325 void advise_state_change(miral::WindowInfo const& window_info, MirWindowState state) override;
326 void advise_resize(miral::WindowInfo const& window_info, Size const& new_size) override;
327 void advise_delete_window(miral::WindowInfo const& window_info) override;
328+
329+ void handle_modify_window(miral::WindowInfo& window_info, miral::WindowSpecification const& modifications) override;
330 /** @} */
331
332 protected:
333@@ -104,6 +110,19 @@
334
335 // Workaround for lp:1627697
336 std::chrono::steady_clock::time_point last_resize;
337+
338+ void advise_adding_to_workspace(
339+ std::shared_ptr<miral::Workspace> const& workspace,
340+ std::vector<miral::Window> const& windows) override;
341+
342+ // Switch workspace, taking window (if not null)
343+ void switch_workspace_to(
344+ std::shared_ptr<miral::Workspace> const& workspace,
345+ miral::Window const& window = miral::Window{});
346+
347+ std::shared_ptr<miral::Workspace> active_workspace;
348+ std::map<int, std::shared_ptr<miral::Workspace>> key_to_workspace;
349+ std::map<std::shared_ptr<miral::Workspace>, miral::Window> workspace_to_active;
350 };
351
352 #endif //MIRAL_SHELL_TITLEBAR_WINDOW_MANAGER_H
353
354=== modified file 'miral/basic_window_manager.cpp'
355--- miral/basic_window_manager.cpp 2017-02-13 16:23:29 +0000
356+++ miral/basic_window_manager.cpp 2017-02-17 12:58:48 +0000
357@@ -1041,16 +1041,11 @@
358 window_info.state() == mir_window_state_minimized;
359
360 policy->advise_state_change(window_info, value);
361- window_info.state(value);
362-
363- mir_surface->configure(mir_window_attrib_state, value);
364
365 switch (value)
366 {
367 case mir_window_state_hidden:
368 case mir_window_state_minimized:
369- mir_surface->hide();
370-
371 if (window == active_window())
372 {
373 auto const workspaces_containing_window = workspaces_containing(window);
374@@ -1087,15 +1082,23 @@
375
376 if (window == active_window())
377 select_active_window({});
378-
379- mru_active_windows.erase(window);
380 }
381+
382+ window_info.state(value);
383+ mir_surface->configure(mir_window_attrib_state, value);
384+ mir_surface->hide();
385+
386 break;
387
388 default:
389+ auto const none_active = !active_window();
390+ window_info.state(value);
391+ mir_surface->configure(mir_window_attrib_state, value);
392 mir_surface->show();
393- if (was_hidden && !active_window())
394+ if (was_hidden && none_active)
395+ {
396 select_active_window(window);
397+ }
398 }
399 }
400
401@@ -1920,13 +1923,13 @@
402
403 std::function<void(WindowInfo const& info)> const add_children =
404 [&,this](WindowInfo const& info)
405+ {
406+ for (auto const& child : info.children())
407 {
408- for (auto const& child : info.children())
409- {
410- windows.push_back(child);
411- add_children(info_for(child));
412- }
413- };
414+ windows.push_back(child);
415+ add_children(info_for(child));
416+ }
417+ };
418
419 windows.push_back(root);
420 add_children(*info);
421
422=== modified file 'miral/mru_window_list.cpp'
423--- miral/mru_window_list.cpp 2017-02-02 11:31:52 +0000
424+++ miral/mru_window_list.cpp 2017-02-17 12:58:48 +0000
425@@ -18,8 +18,27 @@
426
427 #include "mru_window_list.h"
428
429+#include <mir/scene/surface.h>
430+
431 #include <algorithm>
432
433+namespace
434+{
435+bool visible(miral::Window const& window)
436+{
437+ std::shared_ptr<mir::scene::Surface> const& surface{window};
438+
439+ switch (surface->state())
440+ {
441+ case mir_window_state_hidden:
442+ case mir_window_state_minimized:
443+ return false;
444+ default:
445+ return surface->visible();
446+ }
447+}
448+}
449+
450 void miral::MRUWindowList::push(Window const& window)
451 {
452 windows.erase(remove(begin(windows), end(windows), window), end(windows));
453@@ -33,12 +52,14 @@
454
455 auto miral::MRUWindowList::top() const -> Window
456 {
457- return (!windows.empty()) ? windows.back() : Window{};
458+ auto const& found = std::find_if(rbegin(windows), rend(windows), visible);
459+ return (found != rend(windows)) ? *found: Window{};
460 }
461
462 void miral::MRUWindowList::enumerate(Enumerator const& enumerator) const
463 {
464 for (auto i = windows.rbegin(); i != windows.rend(); ++i)
465- if (!enumerator(const_cast<Window&>(*i)))
466- break;
467+ if (visible(*i))
468+ if (!enumerator(const_cast<Window&>(*i)))
469+ break;
470 }
471
472=== modified file 'test/mru_window_list.cpp'
473--- test/mru_window_list.cpp 2016-08-05 08:53:45 +0000
474+++ test/mru_window_list.cpp 2017-02-17 12:58:48 +0000
475@@ -24,17 +24,21 @@
476 #include <gtest/gtest.h>
477 #include <gmock/gmock.h>
478
479-using StubSurface = mir::test::doubles::StubSurface;
480 using namespace testing;
481
482 namespace
483 {
484+struct StubSurface : mir::test::doubles::StubSurface
485+{
486+ bool visible() const override { return true; }
487+};
488+
489 struct StubSession : mir::test::doubles::StubSession
490 {
491 StubSession(int number_of_surfaces)
492 {
493 for (auto i = 0; i != number_of_surfaces; ++i)
494- surfaces.push_back(std::make_shared<mir::test::doubles::StubSurface>());
495+ surfaces.push_back(std::make_shared<StubSurface>());
496 }
497
498 std::shared_ptr<mir::scene::Surface> surface(mir::frontend::SurfaceId surface) const override

Subscribers

People subscribed via source and target branches