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

Proposed by Alan Griffiths
Status: Merged
Approved by: Alan Griffiths
Approved revision: 531
Merged at revision: 516
Proposed branch: lp:~alan-griffiths/miral/workspaces-example
Merge into: lp:miral
Prerequisite: lp:~alan-griffiths/miral/workspace-examples-prerequisites
Diff against target: 338 lines (+212/-8)
4 files modified
miral-shell/decoration_provider.cpp (+3/-3)
miral-shell/titlebar_window_manager.cpp (+184/-3)
miral-shell/titlebar_window_manager.h (+24/-1)
miral/window_management_trace.cpp (+1/-1)
To merge this branch: bzr merge lp:~alan-griffiths/miral/workspaces-example
Reviewer Review Type Date Requested Status
Brandon Schaefer (community) Approve
Gerry Boland Pending
Alan Griffiths Pending
Review via email: mp+317630@code.launchpad.net

This proposal supersedes 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]

~~~

Note: the "prerequisite" branch lp:~alan-griffiths/miral/workspace-examples-prerequisites only exists to workaround the launchpad limitation of a single prerequisite.

To post a comment you must log in.
Revision history for this message
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal

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
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

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
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

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
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

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

Fixed

Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

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

Fixed

review: Abstain
Revision history for this message
Brandon Schaefer (brandontschaefer) wrote : Posted in a previous version of this proposal

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.

Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

> 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

Revision history for this message
Brandon Schaefer (brandontschaefer) wrote : Posted in a previous version of this proposal

Randomly seem to be getting garbage for window addresses:
[2017-02-17 07:26:25.497852] miral::Window Management: for_each_workspace_containing window=<80><81>^GÄX^?

522. By Alan Griffiths

Add workspace keys

523. By Alan Griffiths

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

524. By Alan Griffiths

Fix logging

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

> Randomly seem to be getting garbage for window addresses:
> [2017-02-17 07:26:25.497852] miral::Window Management: for_each_workspace_containing window=<80><81>^GÄX^?

Fixed

Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

1) Open egl plasma
2) Open egl triangle
3) Switch back and forth from f1 <---> f2 a few times with meta + alt
4) Switch to f1 with meta + alt, then using meta + ctrl moving the egl triangle to f2 then back to f1 with out letting go of the hot key
5) Switch to f2 using meta + alt

Expected:
  An emtpy workspace

Result:
  Egl triangle on this workspace, note if you switch to any other workspaces the egl triangle will still be there

Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

Ok easier way:

1) Open egl plasma and egl triangle
2) meta + ctrl + f2
3) meta + ctrl + f1
4) meta + alt + f2

Expected:
  An emtpy workspace

Result:
  App on all workspaces

525. By Alan Griffiths

Fix

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

> Ok easier way:
>
> 1) Open egl plasma and egl triangle
> 2) meta + ctrl + f2
> 3) meta + ctrl + f1
> 4) meta + alt + f2
>
> Expected:
> An emtpy workspace
>
> Result:
> App on all workspaces

Fixed

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

> > Ok easier way:
> >
> > 1) Open egl plasma and egl triangle
> > 2) meta + ctrl + f2
> > 3) meta + ctrl + f1
> > 4) meta + alt + f2
> >
> > Expected:
> > An emtpy workspace
> >
> > Result:
> > App on all workspaces
>
> Fixed

Well, mostly fixed. There are some related scenarios I'm still qualifying that are not quite there yet.

But possibly good enough?

526. By Alan Griffiths

Fix logging

527. By Alan Griffiths

Better solution

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

OK now?

Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

Yup, looking good to me!

review: Approve
528. By Alan Griffiths

Comments to clarify code I can't simplify

529. By Alan Griffiths

DRY - reduce repetitive workspace visible/hidden code

530. By Alan Griffiths

merge :parent

531. By Alan Griffiths

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'miral-shell/decoration_provider.cpp'
2--- miral-shell/decoration_provider.cpp 2017-02-17 11:00:17 +0000
3+++ miral-shell/decoration_provider.cpp 2017-02-20 17:31:27 +0000
4@@ -169,9 +169,9 @@
5 " o Maximize/restore current window (to display size). : Alt-F11",
6 " o Maximize/restore current window (to display height): Shift-F11",
7 " o Maximize/restore current window (to display width) : Ctrl-F11",
8-// "",
9-// " o Switch workspace: Meta-Alt-[F1|F2|F3|F4]",
10-// " o Switch workspace taking active window: Meta-Ctrl-[F1|F2|F3|F4]",
11+ "",
12+ " o Switch workspace: Meta-Alt-[F1|F2|F3|F4]",
13+ " o Switch workspace taking active window: Meta-Ctrl-[F1|F2|F3|F4]",
14 "",
15 " o To exit: Ctrl-Alt-BkSp",
16 };
17
18=== modified file 'miral-shell/titlebar_window_manager.cpp'
19--- miral-shell/titlebar_window_manager.cpp 2017-02-20 15:47:49 +0000
20+++ miral-shell/titlebar_window_manager.cpp 2017-02-20 17:31:27 +0000
21@@ -32,6 +32,18 @@
22 namespace
23 {
24 int const title_bar_height = 12;
25+
26+struct PolicyData
27+{
28+ bool in_hidden_workspace{false};
29+
30+ MirWindowState old_state;
31+};
32+
33+inline PolicyData& policy_data_for(WindowInfo const& info)
34+{
35+ return *std::static_pointer_cast<PolicyData>(info.userdata());
36+}
37 }
38
39 TitlebarWindowManagerPolicy::TitlebarWindowManagerPolicy(
40@@ -43,6 +55,11 @@
41 decoration_provider{std::make_unique<DecorationProvider>(tools)}
42 {
43 launcher.launch("decorations", *decoration_provider);
44+
45+ for (auto key : {KEY_F1, KEY_F2, KEY_F3, KEY_F4})
46+ key_to_workspace[key] = this->tools.create_workspace();
47+
48+ active_workspace = key_to_workspace[KEY_F1];
49 }
50
51 TitlebarWindowManagerPolicy::~TitlebarWindowManagerPolicy() = default;
52@@ -266,17 +283,25 @@
53 {
54 CanonicalWindowManagerPolicy::advise_new_window(window_info);
55
56+ auto const parent = window_info.parent();
57+
58 if (decoration_provider->is_titlebar(window_info))
59 {
60 decoration_provider->advise_new_titlebar(window_info);
61
62- auto const parent = window_info.parent();
63-
64 if (tools.active_window() == parent)
65 decoration_provider->paint_titlebar_for(tools.info_for(parent), 0xFF);
66 else
67 decoration_provider->paint_titlebar_for(tools.info_for(parent), 0x3F);
68 }
69+
70+ if (!parent)
71+ tools.add_tree_to_workspace(window_info.window(), active_workspace);
72+ else
73+ {
74+ if (policy_data_for(tools.info_for(parent)).in_hidden_workspace)
75+ apply_workspace_hidden_to(window_info.window());
76+ }
77 }
78
79 void TitlebarWindowManagerPolicy::handle_window_ready(WindowInfo& window_info)
80@@ -337,6 +362,36 @@
81 auto const scan_code = mir_keyboard_event_scan_code(event);
82 auto const modifiers = mir_keyboard_event_modifiers(event) & modifier_mask;
83
84+ // Switch workspaces
85+ if (action == mir_keyboard_action_down &&
86+ modifiers == (mir_input_event_modifier_alt | mir_input_event_modifier_meta))
87+ {
88+ switch (scan_code)
89+ {
90+ case KEY_F1:
91+ case KEY_F2:
92+ case KEY_F3:
93+ case KEY_F4:
94+ switch_workspace_to(key_to_workspace[scan_code]);
95+ return true;
96+ }
97+ }
98+
99+ // Switch workspace taking the active window
100+ if (action == mir_keyboard_action_down &&
101+ modifiers == (mir_input_event_modifier_ctrl | mir_input_event_modifier_meta))
102+ {
103+ switch (scan_code)
104+ {
105+ case KEY_F1:
106+ case KEY_F2:
107+ case KEY_F3:
108+ case KEY_F4:
109+ switch_workspace_to(key_to_workspace[scan_code], tools.active_window());
110+ return true;
111+ }
112+ }
113+
114 if (action != mir_keyboard_action_repeat)
115 end_resize();
116
117@@ -362,7 +417,7 @@
118 }
119 else if (action == mir_keyboard_action_down && scan_code == KEY_F4)
120 {
121- switch (modifiers & modifier_mask)
122+ switch (modifiers)
123 {
124 case mir_input_event_modifier_alt|mir_input_event_modifier_shift:
125 if (auto const& window = tools.active_window())
126@@ -569,5 +624,131 @@
127 if (app_info.application() == decoration_provider->session())
128 decoration_provider->place_new_decoration(parameters);
129
130+ parameters.userdata() = std::make_shared<PolicyData>();
131 return parameters;
132 }
133+
134+void TitlebarWindowManagerPolicy::advise_adding_to_workspace(
135+ std::shared_ptr<Workspace> const& workspace, std::vector<Window> const& windows)
136+{
137+ if (windows.empty())
138+ return;
139+
140+ for (auto const& window : windows)
141+ {
142+ if (workspace == active_workspace)
143+ {
144+ apply_workspace_visible_to(window);
145+ }
146+ else
147+ {
148+ apply_workspace_hidden_to(window);
149+ }
150+ }
151+}
152+
153+void TitlebarWindowManagerPolicy::switch_workspace_to(
154+ std::shared_ptr<Workspace> const& workspace,
155+ Window const& window)
156+{
157+ if (workspace == active_workspace)
158+ return;
159+
160+ auto const old_active = active_workspace;
161+ active_workspace = workspace;
162+
163+ auto const old_active_window = tools.active_window();
164+
165+ if (!old_active_window)
166+ {
167+ // If there's no active window, the first shown grabs focus: get the right one
168+ if (auto const ww = workspace_to_active[workspace])
169+ {
170+ tools.for_each_workspace_containing(ww, [&](std::shared_ptr<miral::Workspace> const& ws)
171+ {
172+ if (ws == workspace)
173+ {
174+ apply_workspace_visible_to(ww);
175+ }
176+ });
177+ }
178+ }
179+
180+ tools.remove_tree_from_workspace(window, old_active);
181+ tools.add_tree_to_workspace(window, active_workspace);
182+
183+ tools.for_each_window_in_workspace(active_workspace, [&](Window const& window)
184+ {
185+ if (decoration_provider->is_decoration(window))
186+ return; // decorations are taken care of automatically
187+
188+ apply_workspace_visible_to(window);
189+ });
190+
191+ bool hide_old_active = false;
192+ tools.for_each_window_in_workspace(old_active, [&](Window const& window)
193+ {
194+ if (decoration_provider->is_decoration(window))
195+ return; // decorations are taken care of automatically
196+
197+ if (window == old_active_window)
198+ {
199+ // If we hide the active window focus will shift: do that last
200+ hide_old_active = true;
201+ return;
202+ }
203+
204+ apply_workspace_hidden_to(window);
205+ });
206+
207+ if (hide_old_active)
208+ {
209+ apply_workspace_hidden_to(old_active_window);
210+
211+ // Remember the old active_window when we switch away
212+ workspace_to_active[old_active] = old_active_window;
213+ }
214+}
215+
216+void TitlebarWindowManagerPolicy::apply_workspace_hidden_to(Window const& window)
217+{
218+ auto const& window_info = tools.info_for(window);
219+ auto& pdata = policy_data_for(window_info);
220+ if (!pdata.in_hidden_workspace)
221+ {
222+ pdata.in_hidden_workspace = true;
223+ pdata.old_state = window_info.state();
224+
225+ WindowSpecification modifications;
226+ modifications.state() = mir_window_state_hidden;
227+ tools.place_and_size_for_state(modifications, window_info);
228+ tools.modify_window(window_info.window(), modifications);
229+ }
230+}
231+
232+void TitlebarWindowManagerPolicy::apply_workspace_visible_to(Window const& window)
233+{
234+ auto const& window_info = tools.info_for(window);
235+ auto& pdata = policy_data_for(window_info);
236+ if (pdata.in_hidden_workspace)
237+ {
238+ pdata.in_hidden_workspace = false;
239+ WindowSpecification modifications;
240+ modifications.state() = pdata.old_state;
241+ tools.place_and_size_for_state(modifications, window_info);
242+ tools.modify_window(window_info.window(), modifications);
243+ }
244+}
245+
246+void TitlebarWindowManagerPolicy::handle_modify_window(WindowInfo& window_info, WindowSpecification const& modifications)
247+{
248+ auto mods = modifications;
249+
250+ auto& pdata = policy_data_for(window_info);
251+
252+ if (pdata.in_hidden_workspace && mods.state().is_set())
253+ pdata.old_state = mods.state().consume();
254+
255+ CanonicalWindowManagerPolicy::handle_modify_window(window_info, mods);
256+}
257+
258
259=== modified file 'miral-shell/titlebar_window_manager.h'
260--- miral-shell/titlebar_window_manager.h 2017-02-20 15:47:49 +0000
261+++ miral-shell/titlebar_window_manager.h 2017-02-20 17:31:27 +0000
262@@ -20,10 +20,12 @@
263 #define MIRAL_SHELL_TITLEBAR_WINDOW_MANAGER_H
264
265 #include <miral/canonical_window_manager.h>
266+#include <miral/workspace_policy.h>
267
268 #include "spinner/splash.h"
269
270 #include <chrono>
271+#include <map>
272
273 namespace miral { class InternalClientLauncher; }
274
275@@ -31,7 +33,7 @@
276
277 class DecorationProvider;
278
279-class TitlebarWindowManagerPolicy : public miral::CanonicalWindowManagerPolicy
280+class TitlebarWindowManagerPolicy : public miral::CanonicalWindowManagerPolicy, miral::WorkspacePolicy
281 {
282 public:
283 TitlebarWindowManagerPolicy(miral::WindowManagerTools const& tools, SpinnerSplash const& spinner, miral::InternalClientLauncher const& launcher);
284@@ -48,6 +50,8 @@
285 * o Maximize/restore current window (to display size): Alt-F11
286 * o Maximize/restore current window (to display height): Shift-F11
287 * o Maximize/restore current window (to display width): Ctrl-F11
288+ * o Switch workspace . . . . . . . . . . : Meta-Alt-[F1|F2|F3|F4]
289+ * o Switch workspace taking active window: Meta-Ctrl-[F1|F2|F3|F4]
290 * @{ */
291 bool handle_pointer_event(MirPointerEvent const* event) override;
292 bool handle_touch_event(MirTouchEvent const* event) override;
293@@ -63,6 +67,8 @@
294 void advise_state_change(miral::WindowInfo const& window_info, MirWindowState state) override;
295 void advise_resize(miral::WindowInfo const& window_info, Size const& new_size) override;
296 void advise_delete_window(miral::WindowInfo const& window_info) override;
297+
298+ void handle_modify_window(miral::WindowInfo& window_info, miral::WindowSpecification const& modifications) override;
299 /** @} */
300
301 protected:
302@@ -104,6 +110,23 @@
303
304 // Workaround for lp:1627697
305 std::chrono::steady_clock::time_point last_resize;
306+
307+ void advise_adding_to_workspace(
308+ std::shared_ptr<miral::Workspace> const& workspace,
309+ std::vector<miral::Window> const& windows) override;
310+
311+ // Switch workspace, taking window (if not null)
312+ void switch_workspace_to(
313+ std::shared_ptr<miral::Workspace> const& workspace,
314+ miral::Window const& window = miral::Window{});
315+
316+ std::shared_ptr<miral::Workspace> active_workspace;
317+ std::map<int, std::shared_ptr<miral::Workspace>> key_to_workspace;
318+ std::map<std::shared_ptr<miral::Workspace>, miral::Window> workspace_to_active;
319+
320+ void apply_workspace_visible_to(miral::Window const& window);
321+
322+ void apply_workspace_hidden_to(miral::Window const& window);
323 };
324
325 #endif //MIRAL_SHELL_TITLEBAR_WINDOW_MANAGER_H
326
327=== modified file 'miral/window_management_trace.cpp'
328--- miral/window_management_trace.cpp 2017-02-10 15:22:37 +0000
329+++ miral/window_management_trace.cpp 2017-02-20 17:31:27 +0000
330@@ -558,7 +558,7 @@
331 void miral::WindowManagementTrace::for_each_workspace_containing(
332 miral::Window const& window, std::function<void(std::shared_ptr<miral::Workspace> const&)> const& callback)
333 try {
334- mir::log_info("%s window=%s", __func__, dump_of(window));
335+ mir::log_info("%s window=%s", __func__, dump_of(window).c_str());
336 wrapped.for_each_workspace_containing(window, callback);
337 }
338 MIRAL_TRACE_EXCEPTION

Subscribers

People subscribed via source and target branches