on xenial help sign in
provide shortcuts for common window operations
f338bb3Lukáš Tinkl
qml/Stages/DesktopStage.qml+106−18
@@ -24,6 +24,7 @@ import "../Components"
24import "../Components/PanelState"
24import "../Components/PanelState"
25import Utils 0.1
25import Utils 0.1
26import Ubuntu.Gestures 0.1
26import Ubuntu.Gestures 0.1
27+import GlobalShortcut 1.0
27
28
28Rectangle {
29Rectangle {
29 id: root
30 id: root
@@ -88,6 +89,53 @@ Rectangle {
88 }
89 }
89 }
90 }
90
91
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+
91 QtObject {
139 QtObject {
92 id: priv
140 id: priv
93
141
@@ -97,8 +145,8 @@ Rectangle {
97 return index >= 0 && index < appRepeater.count ? appRepeater.itemAt(index) : null
145 return index >= 0 && index < appRepeater.count ? appRepeater.itemAt(index) : null
98 }
146 }
99 onFocusedAppDelegateChanged: { // restore the window from minimization when we focus it (e.g. using spread)
147 onFocusedAppDelegateChanged: { // restore the window from minimization when we focus it (e.g. using spread)
100− if (priv.focusedAppDelegate && priv.focusedAppDelegate.minimized) {
148+ if (focusedAppDelegate && focusedAppDelegate.minimized) {
101− priv.focusedAppDelegate.restore();
149+ focusedAppDelegate.restore();
102 }
150 }
103 }
151 }
104
152
@@ -117,35 +165,45 @@ Rectangle {
117 if (appId === "unity8-dash")
165 if (appId === "unity8-dash")
118 return;
166 return;
119
167
120− var oldIndex = priv.focusStack.indexOf(appId);
168+ var oldIndex = focusStack.indexOf(appId);
121 if (oldIndex != -1) {
169 if (oldIndex != -1) {
122 // remove the old item
170 // remove the old item
123− priv.focusStack.splice(oldIndex, 1);
171+ focusStack.splice(oldIndex, 1);
124 }
172 }
125 // append to the top of the focus stack
173 // append to the top of the focus stack
126− priv.focusStack.unshift(appId);
174+ focusStack.unshift(appId);
127 }
175 }
128
176
129 function removeAndFocusPreviousInStack(appId) {
177 function removeAndFocusPreviousInStack(appId) {
130 if (appId === "unity8-dash")
178 if (appId === "unity8-dash")
131 return;
179 return;
132
180
133− var removedIndex = priv.focusStack.indexOf(appId);
181+ var removedIndex = focusStack.indexOf(appId);
134 if (removedIndex != -1) {
182 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
136 if (removedIndex > 1)
184 if (removedIndex > 1)
137− ApplicationManager.focusApplication(priv.focusStack[removedIndex-1]); // focus the previous one
185+ ApplicationManager.focusApplication(focusStack[removedIndex-1]); // focus the previous one
138 else
186 else
139 focusFirstInStack(); // focus the next/first one
187 focusFirstInStack(); // focus the next/first one
140 }
188 }
141 }
189 }
142
190
143 function focusFirstInStack() {
191 function focusFirstInStack() {
144− var newHead = priv.focusStack[0];
192+ var newHead = focusStack[0];
145 if (newHead !== "") {
193 if (newHead !== "") {
146 ApplicationManager.focusApplication(newHead);
194 ApplicationManager.focusApplication(newHead);
147 }
195 }
148 }
196 }
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+ }
149 }
207 }
150
208
151 Connections {
209 Connections {
@@ -160,7 +218,7 @@ Rectangle {
160 Binding {
218 Binding {
161 target: PanelState
219 target: PanelState
162 property: "buttonsVisible"
220 property: "buttonsVisible"
163− value: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.state === "maximized"
221+ value: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.maximized
164 }
222 }
165
223
166 FocusScope {
224 FocusScope {
@@ -187,14 +245,17 @@ Rectangle {
187 y: units.gu(3)
245 y: units.gu(3)
188 width: units.gu(60)
246 width: units.gu(60)
189 height: units.gu(50)
247 height: units.gu(50)
190− focus: model.appId === priv.focusedAppId
248+ focus: appId === priv.focusedAppId
191
249
192 property bool maximized: false
250 property bool maximized: false
251+ property bool maximizedLeft: false
252+ property bool maximizedRight: false
193 property bool minimized: false
253 property bool minimized: false
254+ readonly property string appId: model.appId
194
255
195 onFocusChanged: {
256 onFocusChanged: {
196− if (focus && ApplicationManager.focusedApplicationId !== model.appId) {
257+ if (focus && ApplicationManager.focusedApplicationId !== appId) {
197− ApplicationManager.focusApplication(model.appId);
258+ ApplicationManager.focusApplication(appId);
198 }
259 }
199 }
260 }
200
261
@@ -212,26 +273,53 @@ Rectangle {
212 function maximize() {
273 function maximize() {
213 minimized = false;
274 minimized = false;
214 maximized = true;
275 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;
215 }
290 }
216 function minimize() {
291 function minimize() {
217 maximized = false;
292 maximized = false;
218 minimized = true;
293 minimized = true;
294+ maximizedLeft = false;
295+ maximizedRight = false;
219− priv.removeAndFocusPreviousInStack(model.appId);
296+ priv.removeAndFocusPreviousInStack(appId);
220 }
297 }
221 function restore() {
298 function restore() {
222 minimized = false;
299 minimized = false;
223 maximized = false;
300 maximized = false;
301+ maximizedLeft = false;
302+ maximizedRight = false;
224− priv.addToFocusStack(model.appId);
303+ priv.addToFocusStack(appId);
225 }
304 }
226
305
227 states: [
306 states: [
228 State {
307 State {
229 name: "normal"; when: !appDelegate.maximized && !appDelegate.minimized
308 name: "normal"; when: !appDelegate.maximized && !appDelegate.minimized
309+ && !appDelegate.maximizedLeft && !appDelegate.maximizedRight
230 },
310 },
231 State {
311 State {
232 name: "maximized"; when: appDelegate.maximized
312 name: "maximized"; when: appDelegate.maximized
233 PropertyChanges { target: appDelegate; x: 0; y: 0; width: root.width; height: root.height }
313 PropertyChanges { target: appDelegate; x: 0; y: 0; width: root.width; height: root.height }
234 },
314 },
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+ },
235 State {
323 State {
236 name: "minimized"; when: appDelegate.minimized
324 name: "minimized"; when: appDelegate.minimized
237 PropertyChanges { target: appDelegate; x: -appDelegate.width / 2; scale: units.gu(5) / appDelegate.width; opacity: 0 }
325 PropertyChanges { target: appDelegate; x: -appDelegate.width / 2; scale: units.gu(5) / appDelegate.width; opacity: 0 }
@@ -239,8 +327,8 @@ Rectangle {
239 ]
327 ]
240 transitions: [
328 transitions: [
241 Transition {
329 Transition {
242− from: "maximized,minimized,normal,"
330+ from: "maximized,maximized_left,maximized_right,minimized,normal,"
243− to: "maximized,minimized,normal,"
331+ to: "maximized,maximized_left,maximized_right,minimized,normal,"
244 PropertyAnimation { target: appDelegate; properties: "x,y,opacity,width,height,scale" }
332 PropertyAnimation { target: appDelegate; properties: "x,y,opacity,width,height,scale" }
245 },
333 },
246 Transition {
334 Transition {
@@ -287,7 +375,7 @@ Rectangle {
287 focus: true
375 focus: true
288
376
289 onClose: ApplicationManager.stopApplication(model.appId)
377 onClose: ApplicationManager.stopApplication(model.appId)
290− onMaximize: appDelegate.maximize()
378+ onMaximize: appDelegate.maximized ? appDelegate.restore() : appDelegate.maximize()
291 onMinimize: appDelegate.minimize()
379 onMinimize: appDelegate.minimize()
292 onDecorationPressed: { ApplicationManager.focusApplication(model.appId) }
380 onDecorationPressed: { ApplicationManager.focusApplication(model.appId) }
293 }
381 }