Merge lp:~alan-griffiths/miral/workspaces-example into lp:miral
- workspaces-example
- Merge into trunk
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 |
Related bugs: |
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-
o Switch workspace taking active window: Meta-Ctrl-
~~~
Note: the "prerequisite" branch lp:~alan-griffiths/miral/workspace-examples-prerequisites only exists to workaround the launchpad limitation of a single prerequisite.
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal | # |
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_
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
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.
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
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
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.
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
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_
- 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
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_
Fixed
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
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
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
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
Alan Griffiths (alan-griffiths) wrote : | # |
OK now?
Brandon Schaefer (brandontschaefer) wrote : | # |
Yup, looking good to me!
- 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
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 |
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