@@ -24,6 +24,7 @@ import "../Components"
2424import "../Components/PanelState"
2525import Utils 0.1
2626import Ubuntu.Gestures 0.1
27+import GlobalShortcut 1.0
2728
2829Rectangle {
2930 id: root
@@ -88,6 +89,53 @@ Rectangle {
8889 }
8990 }
9091
92+ GlobalShortcut {
93+ id: closeWindowShortcut
94+ shortcut: Qt.AltModifier|Qt.Key_F4
95+ onTriggered: ApplicationManager.stopApplication(priv.focusedAppId)
96+ active: priv.focusedAppId !== ""
97+ }
98+
99+ GlobalShortcut {
100+ id: showSpreadShortcut
101+ shortcut: Qt.MetaModifier|Qt.Key_W
102+ onTriggered: spread.state = "altTab"
103+ }
104+
105+ GlobalShortcut {
106+ id: minimizeAllShortcut
107+ shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_D
108+ onTriggered: priv.minimizeAllWindows()
109+ }
110+
111+ GlobalShortcut {
112+ id: maximizeWindowShortcut
113+ shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Up
114+ onTriggered: priv.focusedAppDelegate.minimized ? priv.focusedAppDelegate.restore() : priv.focusedAppDelegate.maximize()
115+ active: priv.focusedAppDelegate !== null
116+ }
117+
118+ GlobalShortcut {
119+ id: maximizeWindowLeftShortcut
120+ shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Left
121+ onTriggered: priv.focusedAppDelegate.maximizeLeft()
122+ active: priv.focusedAppDelegate !== null
123+ }
124+
125+ GlobalShortcut {
126+ id: maximizeWindowRightShortcut
127+ shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Right
128+ onTriggered: priv.focusedAppDelegate.maximizeRight()
129+ active: priv.focusedAppDelegate !== null
130+ }
131+
132+ GlobalShortcut {
133+ id: minimizeRestoreShortcut
134+ shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Down
135+ onTriggered: priv.focusedAppDelegate.maximized ? priv.focusedAppDelegate.restore() : priv.focusedAppDelegate.minimize()
136+ active: priv.focusedAppDelegate !== null
137+ }
138+
91139 QtObject {
92140 id: priv
93141
@@ -97,8 +145,8 @@ Rectangle {
97145 return index >= 0 && index < appRepeater.count ? appRepeater.itemAt(index) : null
98146 }
99147 onFocusedAppDelegateChanged: { // restore the window from minimization when we focus it (e.g. using spread)
100− if (priv.focusedAppDelegate && priv.focusedAppDelegate.minimized) {
101− priv.focusedAppDelegate.restore();
148+ if (focusedAppDelegate && focusedAppDelegate.minimized) {
149+ focusedAppDelegate.restore();
102150 }
103151 }
104152
@@ -117,35 +165,45 @@ Rectangle {
117165 if (appId === "unity8-dash")
118166 return;
119167
120− var oldIndex = priv.focusStack.indexOf(appId);
168+ var oldIndex = focusStack.indexOf(appId);
121169 if (oldIndex != -1) {
122170 // remove the old item
123− priv.focusStack.splice(oldIndex, 1);
171+ focusStack.splice(oldIndex, 1);
124172 }
125173 // append to the top of the focus stack
126− priv.focusStack.unshift(appId);
174+ focusStack.unshift(appId);
127175 }
128176
129177 function removeAndFocusPreviousInStack(appId) {
130178 if (appId === "unity8-dash")
131179 return;
132180
133− var removedIndex = priv.focusStack.indexOf(appId);
181+ var removedIndex = focusStack.indexOf(appId);
134182 if (removedIndex != -1) {
135− priv.focusStack.splice(removedIndex, 1); // remove one item from the focus stack
183+ focusStack.splice(removedIndex, 1); // remove one item from the focus stack
136184 if (removedIndex > 1)
137− ApplicationManager.focusApplication(priv.focusStack[removedIndex-1]); // focus the previous one
185+ ApplicationManager.focusApplication(focusStack[removedIndex-1]); // focus the previous one
138186 else
139187 focusFirstInStack(); // focus the next/first one
140188 }
141189 }
142190
143191 function focusFirstInStack() {
144− var newHead = priv.focusStack[0];
192+ var newHead = focusStack[0];
145193 if (newHead !== "") {
146194 ApplicationManager.focusApplication(newHead);
147195 }
148196 }
197+
198+ function minimizeAllWindows() {
199+ focusStack.forEach(function(appId) {
200+ var appDelegate = appRepeater.itemAt(indexOf(appId));
201+ if (appDelegate && !appDelegate.minimized) {
202+ // we don't want to mess with the focuStack itself or change the focus to a different window
203+ appDelegate.minimized = true;
204+ }
205+ });
206+ }
149207 }
150208
151209 Connections {
@@ -160,7 +218,7 @@ Rectangle {
160218 Binding {
161219 target: PanelState
162220 property: "buttonsVisible"
163− value: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.state === "maximized"
221+ value: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.maximized
164222 }
165223
166224 FocusScope {
@@ -187,14 +245,17 @@ Rectangle {
187245 y: units.gu(3)
188246 width: units.gu(60)
189247 height: units.gu(50)
190− focus: model.appId === priv.focusedAppId
248+ focus: appId === priv.focusedAppId
191249
192250 property bool maximized: false
251+ property bool maximizedLeft: false
252+ property bool maximizedRight: false
193253 property bool minimized: false
254+ readonly property string appId: model.appId
194255
195256 onFocusChanged: {
196− if (focus && ApplicationManager.focusedApplicationId !== model.appId) {
197− ApplicationManager.focusApplication(model.appId);
257+ if (focus && ApplicationManager.focusedApplicationId !== appId) {
258+ ApplicationManager.focusApplication(appId);
198259 }
199260 }
200261
@@ -212,26 +273,53 @@ Rectangle {
212273 function maximize() {
213274 minimized = false;
214275 maximized = true;
276+ maximizedLeft = false;
277+ maximizedRight = false;
278+ }
279+ function maximizeLeft() {
280+ minimized = false;
281+ maximized = false;
282+ maximizedLeft = true;
283+ maximizedRight = false;
284+ }
285+ function maximizeRight() {
286+ minimized = false;
287+ maximized = false;
288+ maximizedLeft = false;
289+ maximizedRight = true;
215290 }
216291 function minimize() {
217292 maximized = false;
218293 minimized = true;
219− priv.removeAndFocusPreviousInStack(model.appId);
294+ maximizedLeft = false;
295+ maximizedRight = false;
296+ priv.removeAndFocusPreviousInStack(appId);
220297 }
221298 function restore() {
222299 minimized = false;
223300 maximized = false;
224− priv.addToFocusStack(model.appId);
301+ maximizedLeft = false;
302+ maximizedRight = false;
303+ priv.addToFocusStack(appId);
225304 }
226305
227306 states: [
228307 State {
229308 name: "normal"; when: !appDelegate.maximized && !appDelegate.minimized
309+ && !appDelegate.maximizedLeft && !appDelegate.maximizedRight
230310 },
231311 State {
232312 name: "maximized"; when: appDelegate.maximized
233313 PropertyChanges { target: appDelegate; x: 0; y: 0; width: root.width; height: root.height }
234314 },
315+ State {
316+ name: "maximized_left"; when: appDelegate.maximizedLeft
317+ PropertyChanges { target: appDelegate; x: 0; y: units.gu(3); width: root.width/2; height: root.height }
318+ },
319+ State {
320+ name: "maximized_right"; when: appDelegate.maximizedRight
321+ PropertyChanges { target: appDelegate; x: root.width/2; y: units.gu(3); width: root.width/2; height: root.height }
322+ },
235323 State {
236324 name: "minimized"; when: appDelegate.minimized
237325 PropertyChanges { target: appDelegate; x: -appDelegate.width / 2; scale: units.gu(5) / appDelegate.width; opacity: 0 }
@@ -239,8 +327,8 @@ Rectangle {
239327 ]
240328 transitions: [
241329 Transition {
242− from: "maximized,minimized,normal,"
243− to: "maximized,minimized,normal,"
330+ from: "maximized,maximized_left,maximized_right,minimized,normal,"
331+ to: "maximized,maximized_left,maximized_right,minimized,normal,"
244332 PropertyAnimation { target: appDelegate; properties: "x,y,opacity,width,height,scale" }
245333 },
246334 Transition {
@@ -287,7 +375,7 @@ Rectangle {
287375 focus: true
288376
289377 onClose: ApplicationManager.stopApplication(model.appId)
290− onMaximize: appDelegate.maximize()
378+ onMaximize: appDelegate.maximized ? appDelegate.restore() : appDelegate.maximize()
291379 onMinimize: appDelegate.minimize()
292380 onDecorationPressed: { ApplicationManager.focusApplication(model.appId) }
293381 }