Merge lp:~3v1n0/unity/super-arrows-shortcuts into lp:unity

Proposed by Marco Trevisan (Treviño) on 2013-09-16
Status: Merged
Approved by: Christopher Townsend on 2013-09-16
Approved revision: 1886
Merged at revision: 3509
Proposed branch: lp:~3v1n0/unity/super-arrows-shortcuts
Merge into: lp:unity
Diff against target: 595 lines (+318/-20)
10 files modified
plugins/unityshell/src/unityshell.cpp (+23/-0)
plugins/unityshell/src/unityshell.h (+2/-0)
plugins/unityshell/unityshell.xml.in (+12/-0)
shortcuts/CompizShortcutModeller.cpp (+11/-11)
tests/autopilot/unity/tests/test_wm_keybindings.py (+110/-0)
unity-shared/PluginAdapter.cpp (+69/-0)
unity-shared/PluginAdapter.h (+8/-0)
unity-shared/StandaloneWindowManager.cpp (+71/-7)
unity-shared/StandaloneWindowManager.h (+7/-1)
unity-shared/WindowManager.h (+5/-1)
To merge this branch: bzr merge lp:~3v1n0/unity/super-arrows-shortcuts
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve on 2013-09-17
Christopher Townsend Approve on 2013-09-16
Alex Launi 2013-09-16 Pending
Review via email: mp+185850@code.launchpad.net

This proposal supersedes a proposal from 2012-01-28.

Commit message

UnityScreen: add support for Super+Arrows shortcuts to manage the focused window

Super+Arrows shortcut allows to move and maximize / restore / minimize
the focused window on the screen.

Description of the change

Added the Super+Left/Right arrows shortcuts support to manage the focused window, as defined on bug #751050

This branch requires lp:~3v1n0/autopilot/window-left+right-maximize-keys in order to make the tests pass.
The fixes is also complete when lp:~3v1n0/compiz/unity-wm-shortcuts-0.9.11 merges

To post a comment you must log in.
Alex Launi (alexlauni) wrote : Posted in a previous version of this proposal

These tests could be written with autopilot. Please make the necessary adjustments to automate these tests.

review: Needs Fixing
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Christopher Townsend (townsend) wrote :

Works great!

review: Approve
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/unityshell/src/unityshell.cpp'
2--- plugins/unityshell/src/unityshell.cpp 2013-09-12 03:12:04 +0000
3+++ plugins/unityshell/src/unityshell.cpp 2013-09-16 16:11:09 +0000
4@@ -349,6 +349,9 @@
5 optionSetLauncherSwitcherPrevInitiate(boost::bind(&UnityScreen::launcherSwitcherPrevInitiate, this, _1, _2, _3));
6 optionSetLauncherSwitcherForwardTerminate(boost::bind(&UnityScreen::launcherSwitcherTerminate, this, _1, _2, _3));
7
8+ optionSetWindowRightMaximizeInitiate(boost::bind(&UnityScreen::rightMaximizeKeyInitiate, this, _1, _2, _3));
9+ optionSetWindowLeftMaximizeInitiate(boost::bind(&UnityScreen::leftMaximizeKeyInitiate, this, _1, _2, _3));
10+
11 optionSetStopVelocityNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
12 optionSetRevealPressureNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
13 optionSetEdgeResponsivenessNotify(boost::bind(&UnityScreen::optionChanged, this, _1, _2));
14@@ -2136,12 +2139,14 @@
15 action->setState(action->state() | CompAction::StateTermKey);
16 return true;
17 }
18+
19 bool UnityScreen::launcherSwitcherPrevInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options)
20 {
21 launcher_controller_->KeyNavPrevious();
22
23 return true;
24 }
25+
26 bool UnityScreen::launcherSwitcherTerminate(CompAction* action, CompAction::State state, CompOption::Vector& options)
27 {
28 bool accept_state = (state & CompAction::StateCancel) == 0;
29@@ -2164,6 +2169,20 @@
30 return true;
31 }
32
33+bool UnityScreen::rightMaximizeKeyInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options)
34+{
35+ auto& WM = WindowManager::Default();
36+ WM.RightMaximize(WM.GetActiveWindow());
37+ return true;
38+}
39+
40+bool UnityScreen::leftMaximizeKeyInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options)
41+{
42+ auto& WM = WindowManager::Default();
43+ WM.LeftMaximize(WM.GetActiveWindow());
44+ return true;
45+}
46+
47 void UnityScreen::OnLauncherStartKeyNav(GVariant* data)
48 {
49 // Put the launcher BaseWindow at the top of the BaseWindow stack. The
50@@ -3554,6 +3573,10 @@
51 .add("xid", (uint64_t)xid)
52 .add("title", wm.GetWindowName(xid))
53 .add("fake_decorated", uScreen->fake_decorated_windows_.find(this) != uScreen->fake_decorated_windows_.end())
54+ .add("maximized", wm.IsWindowVerticallyMaximized(xid))
55+ .add("horizontally_maximized", wm.IsWindowHorizontallyMaximized(xid))
56+ .add("vertically_maximized", wm.IsWindowVerticallyMaximized(xid))
57+ .add("minimized", wm.IsWindowMinimized(xid))
58 .add("scaled", scaled)
59 .add("scaled_close_x", close_button_geo_.x)
60 .add("scaled_close_y", close_button_geo_.y)
61
62=== modified file 'plugins/unityshell/src/unityshell.h'
63--- plugins/unityshell/src/unityshell.h 2013-08-08 23:04:44 +0000
64+++ plugins/unityshell/src/unityshell.h 2013-09-16 16:11:09 +0000
65@@ -165,6 +165,8 @@
66 bool launcherSwitcherForwardInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options);
67 bool launcherSwitcherPrevInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options);
68 bool launcherSwitcherTerminate(CompAction* action, CompAction::State state, CompOption::Vector& options);
69+ bool rightMaximizeKeyInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options);
70+ bool leftMaximizeKeyInitiate(CompAction* action, CompAction::State state, CompOption::Vector& options);
71
72 /* handle option changes and change settings inside of the
73 * panel and dock views */
74
75=== modified file 'plugins/unityshell/unityshell.xml.in'
76--- plugins/unityshell/unityshell.xml.in 2013-09-11 19:32:34 +0000
77+++ plugins/unityshell/unityshell.xml.in 2013-09-16 16:11:09 +0000
78@@ -68,6 +68,18 @@
79 <default>&lt;Alt&gt;F10</default>
80 </option>
81
82+ <option name="window_right_maximize" type="key">
83+ <_short>Key to vertically maximize the focused window to the right</_short>
84+ <_long>Semi-maximize vertically the focused window on the half right width of the screen</_long>
85+ <default>&lt;Control&gt;&lt;Super&gt;Right</default>
86+ </option>
87+
88+ <option name="window_left_maximize" type="key">
89+ <_short>Key to vertically maximize the focused window to the left</_short>
90+ <_long>Semi-maximize vertically the focused window to the half left width of the screen</_long>
91+ <default>&lt;Control&gt;&lt;Super&gt;Left</default>
92+ </option>
93+
94 <option name="panel_opacity" type="float">
95 <_short>Panel Opacity</_short>
96 <_long>The opacity of the Panel background.</_long>
97
98=== modified file 'shortcuts/CompizShortcutModeller.cpp'
99--- shortcuts/CompizShortcutModeller.cpp 2013-07-07 02:46:28 +0000
100+++ shortcuts/CompizShortcutModeller.cpp 2013-09-16 16:11:09 +0000
101@@ -32,7 +32,6 @@
102 // Compiz' plug-in names
103 const std::string CORE_PLUGIN_NAME = "core";
104 const std::string EXPO_PLUGIN_NAME = "expo";
105- const std::string GRID_PLUGIN_NAME = "grid";
106 const std::string MOVE_PLUGIN_NAME = "move";
107 const std::string RESIZE_PLUGIN_NAME = "resize";
108 const std::string SCALE_PLUGIN_NAME = "scale";
109@@ -41,17 +40,14 @@
110
111 // Compiz Core Options
112 const std::string CORE_OPTION_SHOW_DESKTOP_KEY = "show_desktop_key";
113- const std::string CORE_OPTION_MAXIMIZE_WINDOW_KEY = "maximize_window_key";
114- const std::string CORE_OPTION_UNMAXIMIZE_OR_MINIMIZE_WINDOW_KEY = "unmaximize_or_minimize_window_key";
115+ const std::string CORE_OPTION_MAXIMIZE_KEY = "maximize_window_key";
116+ const std::string CORE_OPTION_RESTORE_MINIMIZE_KEY = "unmaximize_or_minimize_window_key";
117 const std::string CORE_OPTION_CLOSE_WINDOW_KEY = "close_window_key";
118 const std::string CORE_OPTION_WINDOW_MENU_KEY = "window_menu_key";
119
120 // Compiz Expo Options
121 const std::string EXPO_OPTION_EXPO_KEY = "expo_key";
122
123- // Compiz Grid Options
124- const std::string GRID_OPTION_PUT_LEFT_KEY = "put_left_key";
125-
126 // Compiz Move Options
127 const std::string MOVE_OPTION_INITIATE_BUTTON = "initiate_button";
128
129@@ -69,6 +65,10 @@
130 const std::string UNITYSHELL_OPTION_PANEL_FIRST_MENU = "panel_first_menu";
131 const std::string UNITYSHELL_OPTION_ALT_TAB_FORWARD = "alt_tab_forward";
132 const std::string UNITYSHELL_OPTION_ALT_TAB_NEXT_WINDOW = "alt_tab_next_window";
133+ const std::string UNITYSHELL_OPTION_MAXIMIZE = "window_maximize";
134+ const std::string UNITYSHELL_OPTION_LEFT_MAXIMIZE = "window_left_maximize";
135+ const std::string UNITYSHELL_OPTION_RIGHT_MAXIMIZE = "window_right_maximize";
136+ const std::string UNITYSHELL_OPTION_RESTORE_MINIMIZE = "window_restore_minimize";
137
138 // Compiz Wall Options
139 const std::string WALL_OPTION_LEFT_KEY = "left_key";
140@@ -304,19 +304,19 @@
141 _("Maximises the current window."),
142 shortcut::OptionType::COMPIZ_KEY,
143 CORE_PLUGIN_NAME,
144- CORE_OPTION_MAXIMIZE_WINDOW_KEY));
145+ CORE_OPTION_MAXIMIZE_KEY));
146
147 hints.push_back(std::make_shared<shortcut::Hint>(windows, "", "",
148 _("Restores or minimises the current window."),
149 shortcut::OptionType::COMPIZ_KEY,
150 CORE_PLUGIN_NAME,
151- CORE_OPTION_UNMAXIMIZE_OR_MINIMIZE_WINDOW_KEY));
152+ CORE_OPTION_RESTORE_MINIMIZE_KEY));
153
154 hints.push_back(std::make_shared<shortcut::Hint>(windows, "", _(" or Right"),
155 _("Semi-maximise the current window."),
156 shortcut::OptionType::COMPIZ_KEY,
157- GRID_PLUGIN_NAME,
158- GRID_OPTION_PUT_LEFT_KEY));
159+ UNITYSHELL_PLUGIN_NAME,
160+ UNITYSHELL_OPTION_LEFT_MAXIMIZE));
161
162 hints.push_back(std::make_shared<shortcut::Hint>(windows, "", "",
163 _("Closes the current window."),
164@@ -333,7 +333,7 @@
165 hints.push_back(std::make_shared<shortcut::Hint>(windows, "", "",
166 _("Places the window in corresponding position."),
167 shortcut::OptionType::HARDCODED,
168- _("Ctrl + Alt + Num")));
169+ _("Ctrl + Alt + Num (keypad)")));
170
171 hints.push_back(std::make_shared<shortcut::Hint>(windows, "", _(" Drag"),
172 _("Moves the window."),
173
174=== added file 'tests/autopilot/unity/tests/test_wm_keybindings.py'
175--- tests/autopilot/unity/tests/test_wm_keybindings.py 1970-01-01 00:00:00 +0000
176+++ tests/autopilot/unity/tests/test_wm_keybindings.py 2013-09-16 16:11:09 +0000
177@@ -0,0 +1,110 @@
178+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
179+# Copyright 2013 Canonical
180+# Author: Marco Trevisan (Treviño)
181+#
182+# This program is free software: you can redistribute it and/or modify it
183+# under the terms of the GNU General Public License version 3, as published
184+# by the Free Software Foundation.
185+
186+from __future__ import absolute_import
187+
188+from autopilot.matchers import Eventually
189+from testtools.matchers import Equals, NotEquals
190+from unity.tests import UnityTestCase
191+
192+class WindowManagerKeybindings(UnityTestCase):
193+ """Window Manager keybindings tests"""
194+
195+ scenarios = [('Restored Window', {'start_restored': True}),
196+ ('Maximized Window', {'start_restored': False})]
197+
198+ def setUp(self):
199+ super(WindowManagerKeybindings, self).setUp()
200+ self.start_test_window()
201+
202+ def keybinding_if_not_minimized(self, keybinding):
203+ if not self.screen_win.minimized:
204+ self.keybinding(keybinding)
205+
206+ def keybinding_if_not_restored(self, keybinding):
207+ if self.screen_win.vertically_maximized or self.screen_win.horizontally_maximized:
208+ self.keybinding(keybinding)
209+
210+ def start_test_window(self, app_name="Character Map"):
211+ """Start a restored/maximized window of the requested application"""
212+ self.process_manager.close_all_app(app_name)
213+ self.bamf_win = self.process_manager.start_app_window(app_name)
214+ win_fn = lambda: self.unity.screen.window(self.bamf_win.x_id)
215+ self.assertThat(win_fn, Eventually(NotEquals(None)))
216+ self.screen_win = win_fn()
217+
218+ if self.start_restored:
219+ if self.screen_win.vertically_maximized or self.screen_win.horizontally_maximized:
220+ self.addCleanup(self.keybinding_if_not_minimized, "window/maximize")
221+ self.keybinding("window/restore")
222+ else:
223+ if not self.screen_win.vertically_maximized and not self.screen_win.horizontally_maximized:
224+ self.addCleanup(self.keybinding_if_not_restored, "window/restore")
225+ self.keybinding("window/maximize")
226+
227+ def get_window_workarea(self):
228+ monitor = self.bamf_win.monitor
229+ monitor_geo = self.display.get_screen_geometry(monitor)
230+ launcher = self.unity.launcher.get_launcher_for_monitor(monitor)
231+ launcher_w = 0 if launcher.hidemode else launcher.geometry[2]
232+ panel_h = self.unity.panels.get_panel_for_monitor(monitor).geometry[3]
233+ return (monitor_geo[0] + launcher_w, monitor_geo[1] + panel_h,
234+ monitor_geo[2] - launcher_w, monitor_geo[3] - panel_h)
235+
236+ def test_maximize_window(self):
237+ if self.start_restored:
238+ self.addCleanup(self.keybinding, "window/restore")
239+ self.keybinding("window/maximize")
240+ self.assertThat(self.screen_win.maximized, Eventually(Equals(True)))
241+
242+ def test_restore_maximized_window(self):
243+ if self.start_restored:
244+ self.keybinding("window/maximize")
245+ self.keybinding("window/restore")
246+ self.assertThat(self.screen_win.maximized, Eventually(Equals(False)))
247+ self.assertThat(self.screen_win.minimized, Eventually(Equals(False)))
248+
249+ def test_restore_vertically_maximized_window(self):
250+ if not self.start_restored:
251+ self.addCleanup(self.keybinding, "window/maximize")
252+ self.keybinding("window/restore")
253+ self.keyboard.press_and_release("Ctrl+Super+Right")
254+ self.keybinding("window/restore")
255+ self.assertThat(self.screen_win.vertically_maximized, Eventually(Equals(False)))
256+ self.assertThat(self.screen_win.minimized, Eventually(Equals(False)))
257+
258+ def test_minimize_restored_window(self):
259+ if not self.start_restored:
260+ self.addCleanup(self.keybinding_if_not_minimized, "window/maximize")
261+ self.keybinding("window/restore")
262+ self.keybinding("window/restore")
263+ self.assertThat(self.screen_win.minimized, Eventually(Equals(True)))
264+
265+ def test_left_maximize(self):
266+ self.addCleanup(self.keybinding, "window/restore" if self.start_restored else "window/maximize")
267+ self.keyboard.press_and_release("Ctrl+Super+Left")
268+ self.assertThat(self.screen_win.vertically_maximized, Eventually(Equals(True)))
269+ self.assertThat(self.screen_win.horizontally_maximized, Eventually(Equals(False)))
270+
271+ workarea_geo = self.get_window_workarea()
272+ self.assertThat(self.screen_win.x, Eventually(Equals(workarea_geo[0])))
273+ self.assertThat(self.screen_win.y, Eventually(Equals(workarea_geo[1])))
274+ self.assertThat(self.screen_win.width, Eventually(Equals(workarea_geo[2]/2)))
275+ self.assertThat(self.screen_win.height, Eventually(Equals(workarea_geo[3])))
276+
277+ def test_right_maximize(self):
278+ self.addCleanup(self.keybinding, "window/restore" if self.start_restored else "window/maximize")
279+ self.keyboard.press_and_release("Ctrl+Super+Right")
280+ self.assertThat(self.screen_win.vertically_maximized, Eventually(Equals(True)))
281+ self.assertThat(self.screen_win.horizontally_maximized, Eventually(Equals(False)))
282+
283+ workarea_geo = self.get_window_workarea()
284+ self.assertThat(self.screen_win.x, Eventually(Equals(workarea_geo[0]+workarea_geo[2]/2)))
285+ self.assertThat(self.screen_win.y, Eventually(Equals(workarea_geo[1])))
286+ self.assertThat(self.screen_win.width, Eventually(Equals(workarea_geo[2]/2)))
287+ self.assertThat(self.screen_win.height, Eventually(Equals(workarea_geo[3])))
288
289=== modified file 'unity-shared/PluginAdapter.cpp'
290--- unity-shared/PluginAdapter.cpp 2013-08-08 14:43:50 +0000
291+++ unity-shared/PluginAdapter.cpp 2013-09-16 16:11:09 +0000
292@@ -461,6 +461,22 @@
293 return false;
294 }
295
296+bool PluginAdapter::IsWindowVerticallyMaximized(Window window_id) const
297+{
298+ if (CompWindow* window = m_Screen->findWindow(window_id))
299+ return (window->state() & CompWindowStateMaximizedVertMask);
300+
301+ return false;
302+}
303+
304+bool PluginAdapter::IsWindowHorizontallyMaximized(Window window_id) const
305+{
306+ if (CompWindow* window = m_Screen->findWindow(window_id))
307+ return (window->state() & CompWindowStateMaximizedHorzMask);
308+
309+ return false;
310+}
311+
312 unsigned long PluginAdapter::GetMwnDecorations(Window window_id) const
313 {
314 Display* display = m_Screen->dpy();
315@@ -697,6 +713,59 @@
316 window->maximize(MAXIMIZE_STATE);
317 }
318
319+void PluginAdapter::VerticallyMaximizeWindowAt(CompWindow* window, nux::Geometry const& geo)
320+{
321+ if (window && ((window->type() & CompWindowTypeNormalMask) ||
322+ ((window->actions() & CompWindowActionMaximizeVertMask) &&
323+ window->actions() & CompWindowActionResizeMask)))
324+ {
325+ /* First we unmaximize the Window */
326+ if (window->state() & MAXIMIZE_STATE)
327+ window->maximize(0);
328+
329+ /* Then we vertically maximize the it so it can be unminimized correctly */
330+ if (!(window->state() & CompWindowStateMaximizedVertMask))
331+ window->maximize(CompWindowStateMaximizedVertMask);
332+
333+ /* Then we resize and move it on the requested place */
334+ MoveResizeWindow(window->id(), geo);
335+ }
336+}
337+
338+void PluginAdapter::LeftMaximize(Window window_id)
339+{
340+ CompWindow* window = m_Screen->findWindow(window_id);
341+
342+ if (!window)
343+ return;
344+
345+ /* Let's compute the area where the window should stay */
346+ CompRect workarea = m_Screen->getWorkareaForOutput(window->outputDevice());
347+ nux::Geometry win_geo(workarea.x() + window->border().left,
348+ workarea.y() + window->border().top,
349+ workarea.width() / 2 - (window->border().left + window->border().right),
350+ workarea.height() - (window->border().top + window->border().bottom));
351+
352+ VerticallyMaximizeWindowAt(window, win_geo);
353+}
354+
355+void PluginAdapter::RightMaximize(Window window_id)
356+{
357+ CompWindow* window = m_Screen->findWindow(window_id);
358+
359+ if (!window)
360+ return;
361+
362+ /* Let's compute the area where the window should stay */
363+ CompRect workarea = m_Screen->getWorkareaForOutput(window->outputDevice());
364+ nux::Geometry win_geo(workarea.x() + workarea.width() / 2 + window->border().left,
365+ workarea.y() + window->border().top,
366+ workarea.width() / 2 - (window->border().left + window->border().right),
367+ workarea.height() - (window->border().top + window->border().bottom));
368+
369+ VerticallyMaximizeWindowAt(window, win_geo);
370+}
371+
372 void PluginAdapter::Restore(Window window_id)
373 {
374 CompWindow* window = m_Screen->findWindow(window_id);
375
376=== modified file 'unity-shared/PluginAdapter.h'
377--- unity-shared/PluginAdapter.h 2013-08-08 14:43:50 +0000
378+++ unity-shared/PluginAdapter.h 2013-09-16 16:11:09 +0000
379@@ -130,6 +130,8 @@
380
381 // WindowManager implementation
382 bool IsWindowMaximized(Window window_id) const;
383+ bool IsWindowVerticallyMaximized(Window window_id) const;
384+ bool IsWindowHorizontallyMaximized(Window window_id) const;
385 bool IsWindowDecorated(Window window_id) const;
386 bool IsWindowOnCurrentDesktop(Window window_id) const;
387 bool IsWindowObscured(Window window_id) const;
388@@ -143,6 +145,8 @@
389 bool HasWindowDecorations(Window window_id) const;
390
391 void Maximize(Window window_id);
392+ void LeftMaximize(Window window_id);
393+ void RightMaximize(Window window_id);
394 void Restore(Window window_id);
395 void RestoreAt(Window window_id, int x, int y);
396 void Minimize(Window window_id);
397@@ -196,6 +200,8 @@
398
399 Window GetTopWindowAbove(Window xid) const;
400
401+ void MoveResizeWindow(guint32 xid, nux::Geometry geometry);
402+
403 protected:
404 PluginAdapter(CompScreen* screen);
405 void AddProperties(GVariantBuilder* builder);
406@@ -215,6 +221,8 @@
407 std::string GetUtf8Property(Window xid, Atom atom) const;
408 std::vector<long> GetCardinalProperty(Window xid, Atom atom) const;
409
410+ void VerticallyMaximizeWindowAt(CompWindow* window, nux::Geometry const& geo);
411+
412 CompScreen* m_Screen;
413 MultiActionList m_ExpoActionList;
414 MultiActionList m_ScaleActionList;
415
416=== modified file 'unity-shared/StandaloneWindowManager.cpp'
417--- unity-shared/StandaloneWindowManager.cpp 2013-08-08 14:43:50 +0000
418+++ unity-shared/StandaloneWindowManager.cpp 2013-09-16 16:11:09 +0000
419@@ -43,7 +43,8 @@
420 , active(false)
421 , mapped(true)
422 , visible(true)
423- , maximized(false)
424+ , v_maximized(false)
425+ , h_maximized(false)
426 , minimized(false)
427 , decorated(true)
428 , has_decorations(true)
429@@ -67,6 +68,20 @@
430
431 return false;
432 });
433+
434+ maximized.SetGetterFunction([this] { return v_maximized && h_maximized; });
435+ maximized.SetSetterFunction([this] (bool value) {
436+ if (maximized() == value)
437+ return false;
438+
439+ v_maximized = value;
440+ h_maximized = value;
441+ decorated = !value;
442+ return true;
443+ });
444+
445+ v_maximized.changed.connect([this] (bool value) { maximized.changed.emit(maximized()); });
446+ h_maximized.changed.connect([this] (bool value) { maximized.changed.emit(maximized()); });
447 }
448
449 WindowManagerPtr create_window_manager()
450@@ -125,6 +140,24 @@
451 return false;
452 }
453
454+bool StandaloneWindowManager::IsWindowVerticallyMaximized(Window window_id) const
455+{
456+ auto window = GetWindowByXid(window_id);
457+ if (window)
458+ return window->v_maximized;
459+
460+ return false;
461+}
462+
463+bool StandaloneWindowManager::IsWindowHorizontallyMaximized(Window window_id) const
464+{
465+ auto window = GetWindowByXid(window_id);
466+ if (window)
467+ return window->h_maximized;
468+
469+ return false;
470+}
471+
472 bool StandaloneWindowManager::IsWindowDecorated(Window window_id) const
473 {
474 auto window = GetWindowByXid(window_id);
475@@ -249,20 +282,51 @@
476 {
477 auto window = GetWindowByXid(window_id);
478 if (window)
479- {
480 window->maximized = true;
481- Undecorate(window_id);
482- }
483+}
484+
485+void StandaloneWindowManager::LeftMaximize(Window window_id)
486+{
487+ auto window = GetWindowByXid(window_id);
488+
489+ if (!window)
490+ return;
491+
492+ /* Let's compute the area where the window should be put */
493+ auto workarea = GetWorkAreaGeometry(window_id);
494+ workarea.width /= 2;
495+
496+ if (window->maximized)
497+ window->maximized = false;
498+
499+ window->v_maximized = true;
500+ MoveResizeWindow(window_id, workarea);
501+}
502+
503+void StandaloneWindowManager::RightMaximize(Window window_id)
504+{
505+ auto window = GetWindowByXid(window_id);
506+
507+ if (!window)
508+ return;
509+
510+ /* Let's compute the area where the window should be put */
511+ auto workarea = GetWorkAreaGeometry(window_id);
512+ workarea.width /= 2;
513+ workarea.x += workarea.width;
514+
515+ if (window->maximized)
516+ window->maximized = false;
517+
518+ window->v_maximized = true;
519+ MoveResizeWindow(window_id, workarea);
520 }
521
522 void StandaloneWindowManager::Restore(Window window_id)
523 {
524 auto window = GetWindowByXid(window_id);
525 if (window)
526- {
527 window->maximized = false;
528- Decorate(window_id);
529- }
530 }
531
532 void StandaloneWindowManager::RestoreAt(Window window_id, int x, int y)
533
534=== modified file 'unity-shared/StandaloneWindowManager.h'
535--- unity-shared/StandaloneWindowManager.h 2013-08-08 14:43:50 +0000
536+++ unity-shared/StandaloneWindowManager.h 2013-09-16 16:11:09 +0000
537@@ -48,7 +48,9 @@
538 nux::Property<bool> active;
539 nux::Property<bool> mapped;
540 nux::Property<bool> visible;
541- nux::Property<bool> maximized;
542+ nux::RWProperty<bool> maximized;
543+ nux::Property<bool> v_maximized;
544+ nux::Property<bool> h_maximized;
545 nux::Property<bool> minimized;
546 nux::Property<bool> decorated;
547 nux::Property<bool> has_decorations;
548@@ -70,6 +72,8 @@
549 std::vector<Window> GetWindowsInStackingOrder() const override;
550
551 virtual bool IsWindowMaximized(Window window_id) const;
552+ virtual bool IsWindowVerticallyMaximized(Window window_id) const;
553+ virtual bool IsWindowHorizontallyMaximized(Window window_id) const;
554 virtual bool IsWindowDecorated(Window window_id) const;
555 virtual bool IsWindowOnCurrentDesktop(Window window_id) const;
556 virtual bool IsWindowObscured(Window window_id) const;
557@@ -86,6 +90,8 @@
558 virtual bool InShowDesktop() const;
559
560 virtual void Maximize(Window window_id);
561+ virtual void LeftMaximize(Window window_id);
562+ virtual void RightMaximize(Window window_id);
563 virtual void Restore(Window window_id);
564 virtual void RestoreAt(Window window_id, int x, int y);
565 virtual void Minimize(Window window_id);
566
567=== modified file 'unity-shared/WindowManager.h'
568--- unity-shared/WindowManager.h 2013-08-08 14:43:50 +0000
569+++ unity-shared/WindowManager.h 2013-09-16 16:11:09 +0000
570@@ -77,6 +77,9 @@
571 virtual std::vector<Window> GetWindowsInStackingOrder() const = 0;
572
573 virtual bool IsWindowMaximized(Window window_id) const = 0;
574+ virtual bool IsWindowVerticallyMaximized(Window window_id) const = 0;
575+ virtual bool IsWindowHorizontallyMaximized(Window window_id) const = 0;
576+ virtual bool IsWindowMaximizable(Window window_id) const = 0;
577 virtual bool IsWindowDecorated(Window window_id) const = 0;
578 virtual bool IsWindowOnCurrentDesktop(Window window_id) const = 0;
579 virtual bool IsWindowObscured(Window window_id) const = 0;
580@@ -86,13 +89,14 @@
581 virtual bool IsWindowClosable(Window window_id) const = 0;
582 virtual bool IsWindowMinimized(Window window_id) const = 0;
583 virtual bool IsWindowMinimizable(Window window_id) const = 0;
584- virtual bool IsWindowMaximizable(Window window_id) const = 0;
585 virtual bool HasWindowDecorations(Window window_id) const = 0;
586
587 virtual void ShowDesktop() = 0;
588 virtual bool InShowDesktop() const = 0;
589
590 virtual void Maximize(Window window_id) = 0;
591+ virtual void LeftMaximize(Window window_id) = 0;
592+ virtual void RightMaximize(Window window_id) = 0;
593 virtual void Restore(Window window_id) = 0;
594 virtual void RestoreAt(Window window_id, int x, int y) = 0;
595 virtual void Minimize(Window window_id) = 0;