2 * Copyright (C) 2014-2017 Canonical, Ltd.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 import QtQuick.Window 2.2
19 import Ubuntu.Components 1.3
20 import Unity.Application 0.1
21 import "../Components/PanelState"
22 import "../Components"
24 import Ubuntu.Gestures 0.1
25 import GlobalShortcut 1.0
28 import "Spread/MathUtils.js" as MathUtils
29 import WindowManager 1.0
35 property QtObject applicationManager
36 property QtObject topLevelSurfaceList
37 property bool altTabPressed
38 property url background
39 property int dragAreaWidth
40 property real nativeHeight
41 property real nativeWidth
42 property QtObject orientations
43 property int shellOrientation
44 property int shellOrientationAngle
45 property bool spreadEnabled: true // If false, animations and right edge will be disabled
46 property bool suspended
47 property bool oskEnabled: false
48 property rect inputMethodRect
49 property real rightEdgePushProgress: 0
50 property Item availableDesktopArea
51 property PanelState panelState
53 // Whether outside forces say that the Stage may have focus
54 property bool allowInteractivity
56 readonly property bool interactive: (state === "staged" || state === "stagedWithSideStage" || state === "windowed") && allowInteractivity
59 property string mode: "staged"
61 readonly property var temporarySelectedWorkspace: state == "spread" ? screensAndWorkspaces.activeWorkspace : null
62 property bool workspaceEnabled: (mode == "windowed" || settings.forceEnableWorkspace) && settings.enableWorkspace
64 // Used by the tutorial code
65 readonly property real rightEdgeDragProgress: rightEdgeDragArea.dragging ? rightEdgeDragArea.progress : 0 // How far left the stage has been dragged
67 // used by the snap windows (edge maximize) feature
68 readonly property alias previewRectangle: fakeRectangle
70 readonly property bool spreadShown: state == "spread"
71 readonly property var mainApp: priv.focusedAppDelegate ? priv.focusedAppDelegate.application : null
73 // application windows never rotate independently
74 property int mainAppWindowOrientationAngle: shellOrientationAngle
76 property bool orientationChangesEnabled: !priv.focusedAppDelegate || priv.focusedAppDelegate.orientationChangesEnabled
78 property int supportedOrientations: {
82 return mainApp.supportedOrientations;
83 case "stagedWithSideStage":
84 var orientations = mainApp.supportedOrientations;
85 orientations |= Qt.LandscapeOrientation | Qt.InvertedLandscapeOrientation;
86 if (priv.sideStageItemId) {
87 // If we have a sidestage app, support Portrait orientation
88 // so that it will switch the sidestage app to mainstage on rotate to portrait
89 orientations |= Qt.PortraitOrientation|Qt.InvertedPortraitOrientation;
95 return Qt.PortraitOrientation |
96 Qt.LandscapeOrientation |
97 Qt.InvertedPortraitOrientation |
98 Qt.InvertedLandscapeOrientation;
103 schema.id: "com.canonical.Unity8"
106 property int launcherLeftMargin : 0
109 target: topLevelSurfaceList
110 property: "rootFocus"
114 onInteractiveChanged: {
115 // Stage must have focus before activating windows, including null
121 onAltTabPressedChanged: {
124 if (root.spreadEnabled) {
125 altTabDelayTimer.start();
128 // Alt Tab has been released, did we already go to spread?
129 if (priv.goneToSpread) {
130 priv.goneToSpread = false;
132 // No we didn't, do a quick alt-tab
133 if (appRepeater.count > 1) {
134 appRepeater.itemAt(1).activate();
135 } else if (appRepeater.count > 0) {
136 appRepeater.itemAt(0).activate(); // quick alt-tab to the only (minimized) window should still activate it
147 if (root.altTabPressed) {
148 priv.goneToSpread = true;
153 // For MirAL window management
155 normal: Qt.rect(0, root.mode === "windowed" ? priv.windowDecorationHeight : 0, 0, 0)
159 property Item itemConfiningMouseCursor: !spreadShown && priv.focusedAppDelegate && priv.focusedAppDelegate.window.confinesMousePointer ?
160 priv.focusedAppDelegate.clientAreaItem : null;
162 signal itemSnapshotRequested(Item item)
164 // functions to be called from outside
165 function updateFocusedAppOrientation() { /* TODO */ }
166 function updateFocusedAppOrientationAnimated() { /* TODO */}
168 function closeSpread() {
169 spreadItem.highlightedIndex = -1;
170 priv.goneToSpread = false;
173 onSpreadEnabledChanged: {
174 if (!spreadEnabled && spreadShown) {
179 onRightEdgePushProgressChanged: {
180 if (spreadEnabled && rightEdgePushProgress >= 1) {
181 priv.goneToSpread = true
186 id: lifecycleExceptions
187 schema.id: "com.canonical.qtmir"
190 function isExemptFromLifecycle(appId) {
191 var shortAppId = appId.split('_')[0];
192 for (var i = 0; i < lifecycleExceptions.lifecycleExemptAppids.length; i++) {
193 if (shortAppId === lifecycleExceptions.lifecycleExemptAppids[i]) {
201 id: closeFocusedShortcut
202 shortcut: Qt.AltModifier|Qt.Key_F4
204 if (priv.focusedAppDelegate) {
205 priv.focusedAppDelegate.close();
211 id: showSpreadShortcut
212 shortcut: Qt.MetaModifier|Qt.Key_W
213 active: root.spreadEnabled
214 onTriggered: priv.goneToSpread = true
218 id: minimizeAllShortcut
219 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_D
220 onTriggered: priv.minimizeAllWindows()
221 active: root.state == "windowed"
225 id: maximizeWindowShortcut
226 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Up
227 onTriggered: priv.focusedAppDelegate.requestMaximize()
228 active: root.state == "windowed" && priv.focusedAppDelegate && priv.focusedAppDelegate.canBeMaximized
232 id: maximizeWindowLeftShortcut
233 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Left
234 onTriggered: priv.focusedAppDelegate.requestMaximizeLeft()
235 active: root.state == "windowed" && priv.focusedAppDelegate && priv.focusedAppDelegate.canBeMaximizedLeftRight
239 id: maximizeWindowRightShortcut
240 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Right
241 onTriggered: priv.focusedAppDelegate.requestMaximizeRight()
242 active: root.state == "windowed" && priv.focusedAppDelegate && priv.focusedAppDelegate.canBeMaximizedLeftRight
246 id: minimizeRestoreShortcut
247 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Down
249 if (priv.focusedAppDelegate.anyMaximized) {
250 priv.focusedAppDelegate.requestRestore();
252 priv.focusedAppDelegate.requestMinimize();
255 active: root.state == "windowed" && priv.focusedAppDelegate
259 shortcut: Qt.AltModifier|Qt.Key_Print
260 onTriggered: root.itemSnapshotRequested(priv.focusedAppDelegate)
261 active: priv.focusedAppDelegate !== null
265 shortcut: Qt.ControlModifier|Qt.AltModifier|Qt.Key_T
267 // try in this order: snap pkg, new deb name, old deb name
268 var candidates = ["ubuntu-terminal-app_ubuntu-terminal-app", "ubuntu-terminal-app", "com.ubuntu.terminal"];
269 for (var i = 0; i < candidates.length; i++) {
270 if (priv.startApp(candidates[i]))
277 id: showWorkspaceSwitcherShortcutLeft
278 shortcut: Qt.AltModifier|Qt.ControlModifier|Qt.Key_Left
279 active: !workspaceSwitcher.active
282 workspaceSwitcher.showLeft()
286 id: showWorkspaceSwitcherShortcutRight
287 shortcut: Qt.AltModifier|Qt.ControlModifier|Qt.Key_Right
288 active: !workspaceSwitcher.active
291 workspaceSwitcher.showRight()
295 id: showWorkspaceSwitcherShortcutUp
296 shortcut: Qt.AltModifier|Qt.ControlModifier|Qt.Key_Up
297 active: !workspaceSwitcher.active
300 workspaceSwitcher.showUp()
304 id: showWorkspaceSwitcherShortcutDown
305 shortcut: Qt.AltModifier|Qt.ControlModifier|Qt.Key_Down
306 active: !workspaceSwitcher.active
309 workspaceSwitcher.showDown()
315 objectName: "DesktopStagePrivate"
317 function startApp(appId) {
318 if (root.applicationManager.findApplication(appId)) {
319 return root.applicationManager.requestFocusApplication(appId);
321 return root.applicationManager.startApplication(appId) !== null;
325 property var focusedAppDelegate: null
326 property var foregroundMaximizedAppDelegate: null // for stuff like drop shadow and focusing maximized app by clicking panel
328 property bool goneToSpread: false
329 property int closingIndex: -1
330 property int animationDuration: UbuntuAnimation.FastDuration
332 function updateForegroundMaximizedApp() {
334 for (var i = 0; i < appRepeater.count && !found; i++) {
335 var item = appRepeater.itemAt(i);
336 if (item && item.visuallyMaximized) {
337 foregroundMaximizedAppDelegate = item;
342 foregroundMaximizedAppDelegate = null;
346 function minimizeAllWindows() {
347 for (var i = appRepeater.count - 1; i >= 0; i--) {
348 var appDelegate = appRepeater.itemAt(i);
349 if (appDelegate && !appDelegate.minimized) {
350 appDelegate.requestMinimize();
355 readonly property bool sideStageEnabled: root.mode === "stagedWithSideStage" &&
356 (root.shellOrientation == Qt.LandscapeOrientation ||
357 root.shellOrientation == Qt.InvertedLandscapeOrientation)
358 onSideStageEnabledChanged: {
359 for (var i = 0; i < appRepeater.count; i++) {
360 appRepeater.itemAt(i).refreshStage();
362 priv.updateMainAndSideStageIndexes();
365 property var mainStageDelegate: null
366 property var sideStageDelegate: null
367 property int mainStageItemId: 0
368 property int sideStageItemId: 0
369 property string mainStageAppId: ""
370 property string sideStageAppId: ""
372 onSideStageDelegateChanged: {
373 if (!sideStageDelegate) {
378 function updateMainAndSideStageIndexes() {
379 if (root.mode != "stagedWithSideStage") {
380 priv.sideStageDelegate = null;
381 priv.sideStageItemId = 0;
382 priv.sideStageAppId = "";
383 priv.mainStageDelegate = appRepeater.itemAt(0);
384 priv.mainStageItemId = topLevelSurfaceList.idAt(0);
385 priv.mainStageAppId = topLevelSurfaceList.applicationAt(0) ? topLevelSurfaceList.applicationAt(0).appId : ""
389 var choseMainStage = false;
390 var choseSideStage = false;
392 if (!root.topLevelSurfaceList)
395 for (var i = 0; i < appRepeater.count && (!choseMainStage || !choseSideStage); ++i) {
396 var appDelegate = appRepeater.itemAt(i);
398 // This might happen during startup phase... If the delegate appears and claims focus
399 // things are updated and appRepeater.itemAt(x) still returns null while appRepeater.count >= x
400 // Lets just skip it, on startup it will be generated at a later point too...
403 if (sideStage.shown && appDelegate.stage == ApplicationInfoInterface.SideStage
404 && !choseSideStage) {
405 priv.sideStageDelegate = appDelegate
406 priv.sideStageItemId = root.topLevelSurfaceList.idAt(i);
407 priv.sideStageAppId = root.topLevelSurfaceList.applicationAt(i).appId;
408 choseSideStage = true;
409 } else if (!choseMainStage && appDelegate.stage == ApplicationInfoInterface.MainStage) {
410 priv.mainStageDelegate = appDelegate;
411 priv.mainStageItemId = root.topLevelSurfaceList.idAt(i);
412 priv.mainStageAppId = root.topLevelSurfaceList.applicationAt(i).appId;
413 choseMainStage = true;
416 if (!choseMainStage && priv.mainStageDelegate) {
417 priv.mainStageDelegate = null;
418 priv.mainStageItemId = 0;
419 priv.mainStageAppId = "";
421 if (!choseSideStage && priv.sideStageDelegate) {
422 priv.sideStageDelegate = null;
423 priv.sideStageItemId = 0;
424 priv.sideStageAppId = "";
428 property int nextInStack: {
429 var mainStageIndex = priv.mainStageDelegate ? priv.mainStageDelegate.itemIndex : -1;
430 var sideStageIndex = priv.sideStageDelegate ? priv.sideStageDelegate.itemIndex : -1;
431 if (sideStageIndex == -1) {
432 return topLevelSurfaceList.count > 1 ? 1 : -1;
434 if (mainStageIndex == 0 || sideStageIndex == 0) {
435 if (mainStageIndex == 1 || sideStageIndex == 1) {
436 return topLevelSurfaceList.count > 2 ? 2 : -1;
443 readonly property real virtualKeyboardHeight: root.inputMethodRect.height
445 readonly property real windowDecorationHeight: units.gu(3)
448 Component.onCompleted: priv.updateMainAndSideStageIndexes()
452 onCloseClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.close(); } }
453 onMinimizeClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.requestMinimize(); } }
454 onRestoreClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.requestRestore(); } }
459 property: "decorationsVisible"
460 value: mode == "windowed" && priv.focusedAppDelegate && priv.focusedAppDelegate.maximized && !root.spreadShown
467 if (priv.focusedAppDelegate !== null) {
468 if (priv.focusedAppDelegate.maximized)
469 return priv.focusedAppDelegate.title
471 return priv.focusedAppDelegate.appName
475 when: priv.focusedAppDelegate
480 property: "focusedPersistentSurfaceId"
482 if (priv.focusedAppDelegate !== null) {
483 if (priv.focusedAppDelegate.surface) {
484 return priv.focusedAppDelegate.surface.persistentId;
489 when: priv.focusedAppDelegate
494 property: "dropShadow"
495 value: priv.focusedAppDelegate && !priv.focusedAppDelegate.maximized && priv.foregroundMaximizedAppDelegate !== null && mode == "windowed"
500 property: "closeButtonShown"
501 value: priv.focusedAppDelegate && priv.focusedAppDelegate.maximized
504 Component.onDestruction: {
505 panelState.title = "";
506 panelState.decorationsVisible = false;
507 panelState.dropShadow = false;
511 model: root.applicationManager
513 property var stateBinding: Binding {
514 target: model.application
515 property: "requestedState"
517 // TODO: figure out some lifecycle policy, like suspending minimized apps
518 // or something if running windowed.
519 // TODO: If the device has a dozen suspended apps because it was running
520 // in staged mode, when it switches to Windowed mode it will suddenly
521 // resume all those apps at once. We might want to avoid that.
522 value: root.mode === "windowed"
523 || (!root.suspended && model.application && priv.focusedAppDelegate &&
524 (priv.focusedAppDelegate.appId === model.application.appId ||
525 priv.mainStageAppId === model.application.appId ||
526 priv.sideStageAppId === model.application.appId))
527 ? ApplicationInfoInterface.RequestedRunning
528 : ApplicationInfoInterface.RequestedSuspended
531 property var lifecycleBinding: Binding {
532 target: model.application
533 property: "exemptFromLifecycle"
534 value: model.application
535 ? (!model.application.isTouchApp || isExemptFromLifecycle(model.application.appId))
539 property var focusRequestedConnection: Connections {
540 target: model.application
543 // Application emits focusRequested when it has no surface (i.e. their processes died).
544 // Find the topmost window for this application and activate it, after which the app
545 // will be requested to be running.
547 for (var i = 0; i < appRepeater.count; i++) {
548 var appDelegate = appRepeater.itemAt(i);
549 if (appDelegate.application.appId === model.application.appId) {
550 appDelegate.activate();
555 console.warn("Application requested te be focused but no window for it. What should we do?");
563 name: "spread"; when: priv.goneToSpread
564 PropertyChanges { target: floatingFlickable; enabled: true }
565 PropertyChanges { target: root; focus: true }
566 PropertyChanges { target: spreadItem; focus: true }
567 PropertyChanges { target: hoverMouseArea; enabled: true }
568 PropertyChanges { target: rightEdgeDragArea; enabled: false }
569 PropertyChanges { target: cancelSpreadMouseArea; enabled: true }
570 PropertyChanges { target: noAppsRunningHint; visible: (root.topLevelSurfaceList.count < 1) }
571 PropertyChanges { target: blurLayer; visible: true; blurRadius: 32; brightness: .65; opacity: 1 }
572 PropertyChanges { target: wallpaper; visible: false }
573 PropertyChanges { target: screensAndWorkspaces; opacity: 1 }
576 name: "stagedRightEdge"; when: root.spreadEnabled && (rightEdgeDragArea.dragging || rightEdgePushProgress > 0) && root.mode == "staged"
584 PropertyChanges { target: noAppsRunningHint; visible: (root.topLevelSurfaceList.count < 1) }
587 name: "sideStagedRightEdge"; when: root.spreadEnabled && (rightEdgeDragArea.dragging || rightEdgePushProgress > 0) && root.mode == "stagedWithSideStage"
588 extend: "stagedRightEdge"
591 opacity: priv.sideStageDelegate && priv.sideStageDelegate.x === sideStage.x ? 1 : 0
596 name: "windowedRightEdge"; when: root.spreadEnabled && (rightEdgeDragArea.dragging || rightEdgePushProgress > 0) && root.mode == "windowed"
602 opacity: MathUtils.linearAnimation(spreadItem.rightEdgeBreakPoint, 1, 0, 1, Math.max(rightEdgeDragArea.dragging ? rightEdgeDragArea.progress : 0, rightEdgePushProgress))
606 name: "staged"; when: root.mode === "staged"
607 PropertyChanges { target: wallpaper; visible: !priv.focusedAppDelegate || priv.focusedAppDelegate.x !== 0 }
608 PropertyChanges { target: root; focus: true }
609 PropertyChanges { target: appContainer; focus: true }
612 name: "stagedWithSideStage"; when: root.mode === "stagedWithSideStage"
613 PropertyChanges { target: triGestureArea; enabled: priv.sideStageEnabled }
614 PropertyChanges { target: sideStage; visible: true }
615 PropertyChanges { target: root; focus: true }
616 PropertyChanges { target: appContainer; focus: true }
619 name: "windowed"; when: root.mode === "windowed"
620 PropertyChanges { target: root; focus: true }
621 PropertyChanges { target: appContainer; focus: true }
626 from: "stagedRightEdge,sideStagedRightEdge,windowedRightEdge"; to: "spread"
627 PropertyAction { target: spreadItem; property: "highlightedIndex"; value: -1 }
628 PropertyAction { target: screensAndWorkspaces; property: "activeWorkspace"; value: WMScreen.currentWorkspace }
629 PropertyAnimation { target: blurLayer; properties: "brightness,blurRadius"; duration: priv.animationDuration }
630 UbuntuNumberAnimation { target: screensAndWorkspaces; property: "opacity"; duration: priv.animationDuration }
634 PropertyAction { target: screensAndWorkspaces; property: "activeWorkspace"; value: WMScreen.currentWorkspace }
635 PropertyAction { target: spreadItem; property: "highlightedIndex"; value: appRepeater.count > 1 ? 1 : 0 }
636 PropertyAction { target: floatingFlickable; property: "contentX"; value: 0 }
637 UbuntuNumberAnimation { target: screensAndWorkspaces; property: "opacity"; duration: priv.animationDuration }
641 SequentialAnimation {
644 var item = appRepeater.itemAt(Math.max(0, spreadItem.highlightedIndex));
645 if (item.stage == ApplicationInfoInterface.SideStage && !sideStage.shown) {
648 item.playFocusAnimation();
651 PropertyAction { target: spreadItem; property: "highlightedIndex"; value: -1 }
652 PropertyAction { target: floatingFlickable; property: "contentX"; value: 0 }
656 to: "stagedRightEdge,sideStagedRightEdge"
657 PropertyAction { target: floatingFlickable; property: "contentX"; value: 0 }
660 to: "stagedWithSideStage"
661 ScriptAction { script: priv.updateMainAndSideStageIndexes(); }
667 id: cancelSpreadMouseArea
670 onClicked: priv.goneToSpread = false
675 objectName: "appContainer"
682 source: root.background
683 // Make sure it's the lowest item. Due to the left edge drag we sometimes need
684 // to put the dash at -1 and we don't want it behind the Wallpaper
695 ScreensAndWorkspaces {
696 id: screensAndWorkspaces
697 anchors { left: parent.left; top: parent.top; right: parent.right; leftMargin: root.leftMargin }
698 height: Math.max(units.gu(30), parent.height * .3)
699 background: root.background
701 visible: workspaceEnabled ? opacity > 0 : false
702 enabled: workspaceEnabled
703 onCloseSpread: priv.goneToSpread = false;
708 objectName: "spreadItem"
711 bottom: parent.bottom;
713 top: workspaceEnabled ? screensAndWorkspaces.bottom : parent.top;
715 leftMargin: root.availableDesktopArea.x
716 model: root.topLevelSurfaceList
717 spreadFlickable: floatingFlickable
721 priv.goneToSpread = false;
725 appRepeater.itemAt(highlightedIndex).close();
729 id: floatingFlickable
730 objectName: "spreadFlickable"
733 contentWidth: spreadItem.spreadTotalWidth
735 function snap(toIndex) {
736 var delegate = appRepeater.itemAt(toIndex)
737 var targetContentX = floatingFlickable.contentWidth / spreadItem.totalItemCount * toIndex;
738 if (targetContentX - floatingFlickable.contentX > spreadItem.rightStackXPos - (spreadItem.spreadItemWidth / 2)) {
739 var offset = (spreadItem.rightStackXPos - (spreadItem.spreadItemWidth / 2)) - (targetContentX - floatingFlickable.contentX)
740 snapAnimation.to = floatingFlickable.contentX - offset;
741 snapAnimation.start();
742 } else if (targetContentX - floatingFlickable.contentX < spreadItem.leftStackXPos + units.gu(1)) {
743 var offset = (spreadItem.leftStackXPos + units.gu(1)) - (targetContentX - floatingFlickable.contentX);
744 snapAnimation.to = floatingFlickable.contentX - offset;
745 snapAnimation.start();
748 UbuntuNumberAnimation {id: snapAnimation; target: floatingFlickable; property: "contentX"}
753 objectName: "hoverMouseArea"
755 propagateComposedEvents: true
759 property bool wasTouchPress: false
761 property int scrollAreaWidth: width / 3
762 property bool progressiveScrollingEnabled: false
765 mouse.accepted = false
767 if (hoverMouseArea.pressed || wasTouchPress) {
771 // Find the hovered item and mark it active
772 for (var i = appRepeater.count - 1; i >= 0; i--) {
773 var appDelegate = appRepeater.itemAt(i);
774 var mapped = mapToItem(appDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
775 var itemUnder = appDelegate.childAt(mapped.x, mapped.y);
776 if (itemUnder && (itemUnder.objectName === "dragArea" || itemUnder.objectName === "windowInfoItem" || itemUnder.objectName == "closeMouseArea")) {
777 spreadItem.highlightedIndex = i;
782 if (floatingFlickable.contentWidth > floatingFlickable.width) {
783 var margins = floatingFlickable.width * 0.05;
785 if (!progressiveScrollingEnabled && mouseX < floatingFlickable.width - scrollAreaWidth) {
786 progressiveScrollingEnabled = true
789 // do we need to scroll?
790 if (mouseX < scrollAreaWidth + margins) {
791 var progress = Math.min(1, (scrollAreaWidth + margins - mouseX) / (scrollAreaWidth - margins));
792 var contentX = (1 - progress) * (floatingFlickable.contentWidth - floatingFlickable.width)
793 floatingFlickable.contentX = Math.max(0, Math.min(floatingFlickable.contentX, contentX))
795 if (mouseX > floatingFlickable.width - scrollAreaWidth && progressiveScrollingEnabled) {
796 var progress = Math.min(1, (mouseX - (floatingFlickable.width - scrollAreaWidth)) / (scrollAreaWidth - margins))
797 var contentX = progress * (floatingFlickable.contentWidth - floatingFlickable.width)
798 floatingFlickable.contentX = Math.min(floatingFlickable.contentWidth - floatingFlickable.width, Math.max(floatingFlickable.contentX, contentX))
804 mouse.accepted = false;
805 wasTouchPress = mouse.source === Qt.MouseEventSynthesizedByQt;
808 onExited: wasTouchPress = false;
813 id: noAppsRunningHint
815 anchors.horizontalCenter: parent.horizontalCenter
816 anchors.verticalCenter: parent.verticalCenter
818 horizontalAlignment: Qt.AlignHCenter
819 verticalAlignment: Qt.AlignVCenter
820 anchors.leftMargin: root.launcherLeftMargin
821 wrapMode: Label.WordWrap
823 text: i18n.tr("No running apps")
827 target: root.topLevelSurfaceList
828 onListChanged: priv.updateMainAndSideStageIndexes()
833 objectName: "MainStageDropArea"
837 bottom: parent.bottom
839 width: appContainer.width - sideStage.width
840 enabled: priv.sideStageEnabled
843 drop.source.appDelegate.saveStage(ApplicationInfoInterface.MainStage);
844 drop.source.appDelegate.focus = true;
851 objectName: "sideStage"
853 height: appContainer.height
854 x: appContainer.width - width
856 Behavior on opacity { UbuntuNumberAnimation {} }
858 if (!priv.mainStageItemId) return 0;
860 if (priv.sideStageItemId && priv.nextInStack > 0) {
862 // Due the order in which bindings are evaluated, this might be triggered while shuffling
863 // the list and index doesn't yet match with itemIndex (even though itemIndex: index)
864 // Let's walk the list and compare itemIndex to make sure we have the correct one.
865 var nextDelegateInStack = -1;
866 for (var i = 0; i < appRepeater.count; i++) {
867 if (appRepeater.itemAt(i).itemIndex == priv.nextInStack) {
868 nextDelegateInStack = appRepeater.itemAt(i);
873 if (nextDelegateInStack.stage === ApplicationInfoInterface.MainStage) {
874 // if the next app in stack is a main stage app, put the sidestage on top of it.
884 if (!shown && priv.mainStageDelegate && !root.spreadShown) {
885 priv.mainStageDelegate.activate();
890 id: sideStageDropArea
891 objectName: "SideStageDropArea"
894 property bool dropAllowed: true
897 dropAllowed = drag.keys != "Disabled";
903 if (drop.keys == "MainStage") {
904 drop.source.appDelegate.saveStage(ApplicationInfoInterface.SideStage);
905 drop.source.appDelegate.focus = true;
910 if (!sideStageDropArea.drag.source) {
920 property real previewScale: .5
921 height: (screensAndWorkspaces.height - units.gu(8)) / 2
923 width: implicitWidth * height / implicitHeight
926 opacity: surface != null ? 1 : 0
927 Behavior on opacity { UbuntuNumberAnimation {} }
929 enabled: workspaceSwitcher
931 Drag.active: surface != null
932 Drag.keys: ["application"]
939 model: topLevelSurfaceList
940 objectName: "appRepeater"
942 function indexOf(delegateItem) {
943 for (var i = 0; i < count; i++) {
944 if (itemAt(i) === delegateItem) {
951 delegate: FocusScope {
953 objectName: "appDelegate_" + model.window.id
954 property int itemIndex: index // We need this from outside the repeater
955 // z might be overriden in some cases by effects, but we need z ordering
956 // to calculate occlusion detection
957 property int normalZ: topLevelSurfaceList.count - index
959 if (visuallyMaximized) {
960 priv.updateForegroundMaximizedApp();
965 opacity: fakeDragItem.surface == model.window.surface && fakeDragItem.Drag.active ? 0 : 1
966 Behavior on opacity { UbuntuNumberAnimation {} }
968 // Set these as propertyes as they wont update otherwise
969 property real screenOffsetX: Screen.virtualX
970 property real screenOffsetY: Screen.virtualY
972 // Normally we want x/y where the surface thinks it is. Width/height of our delegate will
973 // match what the actual surface size is.
974 // Don't write to those, they will be set by states
976 // Here we will also need to remove the screen offset from miral's results
977 // as unity8 x,y will be relative to the current screen only
978 // FIXME: when proper multiscreen lands
979 x: model.window.position.x - clientAreaItem.x - screenOffsetX
980 y: model.window.position.y - clientAreaItem.y - screenOffsetY
981 width: decoratedWindow.implicitWidth
982 height: decoratedWindow.implicitHeight
984 // requestedX/Y/width/height is what we ask the actual surface to be.
985 // Do not write to those, they will be set by states
986 property real requestedX: windowedX
987 property real requestedY: windowedY
988 property real requestedWidth: windowedWidth
989 property real requestedHeight: windowedHeight
991 // For both windowed and staged need to tell miral what screen we are on,
992 // so we need to add the screen offset to the position we tell miral
993 // FIXME: when proper multiscreen lands
995 target: model.window; property: "requestedPosition"
996 // miral doesn't know about our window decorations. So we have to deduct them
997 value: Qt.point(appDelegate.requestedX + appDelegate.clientAreaItem.x + screenOffsetX,
998 appDelegate.requestedY + appDelegate.clientAreaItem.y + screenOffsetY)
999 when: root.mode == "windowed"
1002 target: model.window; property: "requestedPosition"
1003 value: Qt.point(screenOffsetX, screenOffsetY)
1004 when: root.mode != "windowed"
1007 // In those are for windowed mode. Those values basically store the window's properties
1008 // when having a floating window. If you want to move/resize a window in normal mode, this is what you want to write to.
1009 property real windowedX
1010 property real windowedY
1011 property real windowedWidth
1012 property real windowedHeight
1014 // unlike windowedX/Y, this is the last known grab position before being pushed against edges/corners
1015 // when restoring, the window should return to these, not to the place where it was dropped near the edge
1016 property real restoredX
1017 property real restoredY
1019 // Keeps track of the window geometry while in normal or restored state
1020 // Useful when returning from some maxmized state or when saving the geometry while maximized
1021 // FIXME: find a better solution
1022 property real normalX: 0
1023 property real normalY: 0
1024 property real normalWidth: 0
1025 property real normalHeight: 0
1026 function updateNormalGeometry() {
1027 if (appDelegate.state == "normal" || appDelegate.state == "restored") {
1028 normalX = appDelegate.requestedX;
1029 normalY = appDelegate.requestedY;
1030 normalWidth = appDelegate.width;
1031 normalHeight = appDelegate.height;
1034 function updateRestoredGeometry() {
1035 if (appDelegate.state == "normal" || appDelegate.state == "restored") {
1036 // save the x/y to restore to
1037 restoredX = appDelegate.x;
1038 restoredY = appDelegate.y;
1044 onXChanged: appDelegate.updateNormalGeometry();
1045 onYChanged: appDelegate.updateNormalGeometry();
1046 onWidthChanged: appDelegate.updateNormalGeometry();
1047 onHeightChanged: appDelegate.updateNormalGeometry();
1050 // True when the Stage is focusing this app and playing its own animation.
1051 // Stays true until the app is unfocused.
1052 // If it is, we don't want to play the slide in/out transition from StageMaths.
1053 // Setting it imperatively is not great, but any declarative solution hits
1054 // race conditions, causing two animations to play for one focus event.
1055 property bool inhibitSlideAnimation: false
1060 value: appDelegate.requestedY -
1061 Math.min(appDelegate.requestedY - root.availableDesktopArea.y,
1062 Math.max(0, priv.virtualKeyboardHeight - (appContainer.height - (appDelegate.requestedY + appDelegate.height))))
1063 when: root.oskEnabled && appDelegate.focus && (appDelegate.state == "normal" || appDelegate.state == "restored")
1064 && root.inputMethodRect.height > 0
1067 Behavior on x { id: xBehavior; enabled: priv.closingIndex >= 0; UbuntuNumberAnimation { onRunningChanged: if (!running) priv.closingIndex = -1} }
1071 onShellOrientationAngleChanged: {
1072 // at this point decoratedWindow.surfaceOrientationAngle is the old shellOrientationAngle
1073 if (application && application.rotatesWindowContents) {
1074 if (root.state == "windowed") {
1075 var angleDiff = decoratedWindow.surfaceOrientationAngle - shellOrientationAngle;
1076 angleDiff = (360 + angleDiff) % 360;
1077 if (angleDiff === 90 || angleDiff === 270) {
1078 var aux = decoratedWindow.requestedHeight;
1079 decoratedWindow.requestedHeight = decoratedWindow.requestedWidth + decoratedWindow.actualDecorationHeight;
1080 decoratedWindow.requestedWidth = aux - decoratedWindow.actualDecorationHeight;
1083 decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
1085 decoratedWindow.surfaceOrientationAngle = 0;
1090 readonly property alias application: decoratedWindow.application
1091 readonly property alias minimumWidth: decoratedWindow.minimumWidth
1092 readonly property alias minimumHeight: decoratedWindow.minimumHeight
1093 readonly property alias maximumWidth: decoratedWindow.maximumWidth
1094 readonly property alias maximumHeight: decoratedWindow.maximumHeight
1095 readonly property alias widthIncrement: decoratedWindow.widthIncrement
1096 readonly property alias heightIncrement: decoratedWindow.heightIncrement
1098 readonly property bool maximized: windowState === WindowStateStorage.WindowStateMaximized
1099 readonly property bool maximizedLeft: windowState === WindowStateStorage.WindowStateMaximizedLeft
1100 readonly property bool maximizedRight: windowState === WindowStateStorage.WindowStateMaximizedRight
1101 readonly property bool maximizedHorizontally: windowState === WindowStateStorage.WindowStateMaximizedHorizontally
1102 readonly property bool maximizedVertically: windowState === WindowStateStorage.WindowStateMaximizedVertically
1103 readonly property bool maximizedTopLeft: windowState === WindowStateStorage.WindowStateMaximizedTopLeft
1104 readonly property bool maximizedTopRight: windowState === WindowStateStorage.WindowStateMaximizedTopRight
1105 readonly property bool maximizedBottomLeft: windowState === WindowStateStorage.WindowStateMaximizedBottomLeft
1106 readonly property bool maximizedBottomRight: windowState === WindowStateStorage.WindowStateMaximizedBottomRight
1107 readonly property bool anyMaximized: maximized || maximizedLeft || maximizedRight || maximizedHorizontally || maximizedVertically ||
1108 maximizedTopLeft || maximizedTopRight || maximizedBottomLeft || maximizedBottomRight
1110 readonly property bool minimized: windowState & WindowStateStorage.WindowStateMinimized
1111 readonly property bool fullscreen: windowState === WindowStateStorage.WindowStateFullscreen
1113 readonly property bool canBeMaximized: canBeMaximizedHorizontally && canBeMaximizedVertically
1114 readonly property bool canBeMaximizedLeftRight: (maximumWidth == 0 || maximumWidth >= appContainer.width/2) &&
1115 (maximumHeight == 0 || maximumHeight >= appContainer.height)
1116 readonly property bool canBeCornerMaximized: (maximumWidth == 0 || maximumWidth >= appContainer.width/2) &&
1117 (maximumHeight == 0 || maximumHeight >= appContainer.height/2)
1118 readonly property bool canBeMaximizedHorizontally: maximumWidth == 0 || maximumWidth >= appContainer.width
1119 readonly property bool canBeMaximizedVertically: maximumHeight == 0 || maximumHeight >= appContainer.height
1120 readonly property alias orientationChangesEnabled: decoratedWindow.orientationChangesEnabled
1122 // TODO drop our own windowType once Mir/Miral/Qtmir gets in sync with ours
1123 property int windowState: WindowStateStorage.WindowStateNormal
1124 property int prevWindowState: WindowStateStorage.WindowStateRestored
1126 property bool animationsEnabled: true
1127 property alias title: decoratedWindow.title
1128 readonly property string appName: model.application ? model.application.name : ""
1129 property bool visuallyMaximized: false
1130 property bool visuallyMinimized: false
1131 readonly property alias windowedTransitionRunning: windowedTransition.running
1133 property int stage: ApplicationInfoInterface.MainStage
1134 function saveStage(newStage) {
1135 appDelegate.stage = newStage;
1136 WindowStateStorage.saveStage(appId, newStage);
1137 priv.updateMainAndSideStageIndexes()
1140 readonly property var surface: model.window.surface
1141 readonly property var window: model.window
1143 readonly property alias focusedSurface: decoratedWindow.focusedSurface
1144 readonly property bool dragging: touchControls.overlayShown ? touchControls.dragging : decoratedWindow.dragging
1146 readonly property string appId: model.application.appId
1147 readonly property alias clientAreaItem: decoratedWindow.clientAreaItem
1149 function activate() {
1150 if (model.window.focused) {
1151 updateQmlFocusFromMirSurfaceFocus();
1153 model.window.activate();
1156 function requestMaximize() { model.window.requestState(Mir.MaximizedState); }
1157 function requestMaximizeVertically() { model.window.requestState(Mir.VertMaximizedState); }
1158 function requestMaximizeHorizontally() { model.window.requestState(Mir.HorizMaximizedState); }
1159 function requestMaximizeLeft() { model.window.requestState(Mir.MaximizedLeftState); }
1160 function requestMaximizeRight() { model.window.requestState(Mir.MaximizedRightState); }
1161 function requestMaximizeTopLeft() { model.window.requestState(Mir.MaximizedTopLeftState); }
1162 function requestMaximizeTopRight() { model.window.requestState(Mir.MaximizedTopRightState); }
1163 function requestMaximizeBottomLeft() { model.window.requestState(Mir.MaximizedBottomLeftState); }
1164 function requestMaximizeBottomRight() { model.window.requestState(Mir.MaximizedBottomRightState); }
1165 function requestMinimize() { model.window.requestState(Mir.MinimizedState); }
1166 function requestRestore() { model.window.requestState(Mir.RestoredState); }
1168 function claimFocus() {
1169 if (root.state == "spread") {
1170 spreadItem.highlightedIndex = index
1172 if (root.mode == "stagedWithSideStage") {
1173 if (appDelegate.stage == ApplicationInfoInterface.SideStage && !sideStage.shown) {
1176 priv.updateMainAndSideStageIndexes();
1178 appDelegate.focus = true;
1180 // Don't set focusedAppDelegate (and signal mainAppChanged) unnecessarily
1181 // which can happen after getting interactive again.
1182 if (priv.focusedAppDelegate !== appDelegate)
1183 priv.focusedAppDelegate = appDelegate;
1186 function updateQmlFocusFromMirSurfaceFocus() {
1187 if (model.window.focused) {
1189 decoratedWindow.focus = true;
1194 id: windowStateSaver
1196 screenWidth: appContainer.width
1197 screenHeight: appContainer.height
1198 leftMargin: root.availableDesktopArea.x
1199 minimumY: root.availableDesktopArea.y
1203 target: model.window
1205 updateQmlFocusFromMirSurfaceFocus();
1206 if (!model.window.focused) {
1207 inhibitSlideAnimation = false;
1211 appDelegate.activate();
1214 if (value == Mir.MinimizedState) {
1215 appDelegate.minimize();
1216 } else if (value == Mir.MaximizedState) {
1217 appDelegate.maximize();
1218 } else if (value == Mir.VertMaximizedState) {
1219 appDelegate.maximizeVertically();
1220 } else if (value == Mir.HorizMaximizedState) {
1221 appDelegate.maximizeHorizontally();
1222 } else if (value == Mir.MaximizedLeftState) {
1223 appDelegate.maximizeLeft();
1224 } else if (value == Mir.MaximizedRightState) {
1225 appDelegate.maximizeRight();
1226 } else if (value == Mir.MaximizedTopLeftState) {
1227 appDelegate.maximizeTopLeft();
1228 } else if (value == Mir.MaximizedTopRightState) {
1229 appDelegate.maximizeTopRight();
1230 } else if (value == Mir.MaximizedBottomLeftState) {
1231 appDelegate.maximizeBottomLeft();
1232 } else if (value == Mir.MaximizedBottomRightState) {
1233 appDelegate.maximizeBottomRight();
1234 } else if (value == Mir.RestoredState) {
1235 if (appDelegate.fullscreen && appDelegate.prevWindowState != WindowStateStorage.WindowStateRestored
1236 && appDelegate.prevWindowState != WindowStateStorage.WindowStateNormal) {
1237 model.window.requestState(WindowStateStorage.toMirState(appDelegate.prevWindowState));
1239 appDelegate.restore();
1241 } else if (value == Mir.FullscreenState) {
1242 appDelegate.prevWindowState = appDelegate.windowState;
1243 appDelegate.windowState = WindowStateStorage.WindowStateFullscreen;
1248 readonly property bool windowReady: clientAreaItem.surfaceInitialized
1249 onWindowReadyChanged: {
1251 var loadedMirState = WindowStateStorage.toMirState(windowStateSaver.loadedState);
1252 var state = loadedMirState;
1254 if (window.state == Mir.FullscreenState) {
1255 // If the app is fullscreen at startup, we should not use saved state
1256 // Example of why: if you open game that only requests fullscreen at
1257 // Statup, this will automaticly be set to "restored state" since
1258 // thats the default value of stateStorage, this will result in the app
1259 // having the "restored state" as it will not make a fullscreen
1260 // call after the app has started.
1261 console.log("Inital window state is fullscreen, not using saved state.");
1262 state = window.state;
1263 } else if (loadedMirState == Mir.FullscreenState) {
1264 // If saved state is fullscreen, we should use app inital state
1265 // Example of why: if you open browser with youtube video at fullscreen
1266 // and close this app, it will be fullscreen next time you open the app.
1267 console.log("Saved window state is fullscreen, using inital window state");
1268 state = window.state;
1271 // need to apply the shell chrome policy on top the saved window state
1273 if (root.mode == "windowed") {
1274 policy = windowedFullscreenPolicy;
1276 policy = stagedFullscreenPolicy
1278 window.requestState(policy.applyPolicy(state, surface.shellChrome));
1282 Component.onCompleted: {
1283 if (application && application.rotatesWindowContents) {
1284 decoratedWindow.surfaceOrientationAngle = shellOrientationAngle;
1286 decoratedWindow.surfaceOrientationAngle = 0;
1289 // First, cascade the newly created window, relative to the currently/old focused window.
1290 windowedX = priv.focusedAppDelegate ? priv.focusedAppDelegate.windowedX + units.gu(3) : (normalZ - 1) * units.gu(3)
1291 windowedY = priv.focusedAppDelegate ? priv.focusedAppDelegate.windowedY + units.gu(3) : normalZ * units.gu(3)
1292 // Now load any saved state. This needs to happen *after* the cascading!
1293 windowStateSaver.load();
1295 updateQmlFocusFromMirSurfaceFocus();
1298 _constructing = false;
1300 Component.onDestruction: {
1301 windowStateSaver.save();
1304 // This stage is about to be destroyed. Don't mess up with the model at this point
1308 if (visuallyMaximized) {
1309 priv.updateForegroundMaximizedApp();
1313 onVisuallyMaximizedChanged: priv.updateForegroundMaximizedApp()
1315 property bool _constructing: true;
1317 if (!_constructing) {
1318 priv.updateMainAndSideStageIndexes();
1324 && !greeter.fullyShown
1325 && (priv.foregroundMaximizedAppDelegate === null || priv.foregroundMaximizedAppDelegate.normalZ <= z)
1327 || appDelegate.fullscreen
1328 || focusAnimation.running || rightEdgeFocusAnimation.running || hidingAnimation.running
1331 model.window.close();
1334 function maximize(animated) {
1335 animationsEnabled = (animated === undefined) || animated;
1336 windowState = WindowStateStorage.WindowStateMaximized;
1338 function maximizeLeft(animated) {
1339 animationsEnabled = (animated === undefined) || animated;
1340 windowState = WindowStateStorage.WindowStateMaximizedLeft;
1342 function maximizeRight(animated) {
1343 animationsEnabled = (animated === undefined) || animated;
1344 windowState = WindowStateStorage.WindowStateMaximizedRight;
1346 function maximizeHorizontally(animated) {
1347 animationsEnabled = (animated === undefined) || animated;
1348 windowState = WindowStateStorage.WindowStateMaximizedHorizontally;
1350 function maximizeVertically(animated) {
1351 animationsEnabled = (animated === undefined) || animated;
1352 windowState = WindowStateStorage.WindowStateMaximizedVertically;
1354 function maximizeTopLeft(animated) {
1355 animationsEnabled = (animated === undefined) || animated;
1356 windowState = WindowStateStorage.WindowStateMaximizedTopLeft;
1358 function maximizeTopRight(animated) {
1359 animationsEnabled = (animated === undefined) || animated;
1360 windowState = WindowStateStorage.WindowStateMaximizedTopRight;
1362 function maximizeBottomLeft(animated) {
1363 animationsEnabled = (animated === undefined) || animated;
1364 windowState = WindowStateStorage.WindowStateMaximizedBottomLeft;
1366 function maximizeBottomRight(animated) {
1367 animationsEnabled = (animated === undefined) || animated;
1368 windowState = WindowStateStorage.WindowStateMaximizedBottomRight;
1370 function minimize(animated) {
1371 animationsEnabled = (animated === undefined) || animated;
1372 windowState |= WindowStateStorage.WindowStateMinimized; // add the minimized bit
1374 function restore(animated,state) {
1375 animationsEnabled = (animated === undefined) || animated;
1376 windowState = state || WindowStateStorage.WindowStateRestored;
1377 windowState &= ~WindowStateStorage.WindowStateMinimized; // clear the minimized bit
1378 prevWindowState = windowState;
1381 function playFocusAnimation() {
1382 if (state == "stagedRightEdge") {
1383 // TODO: Can we drop this if and find something that always works?
1384 if (root.mode == "staged") {
1385 rightEdgeFocusAnimation.targetX = 0
1386 rightEdgeFocusAnimation.start()
1387 } else if (root.mode == "stagedWithSideStage") {
1388 rightEdgeFocusAnimation.targetX = appDelegate.stage == ApplicationInfoInterface.SideStage ? sideStage.x : 0
1389 rightEdgeFocusAnimation.start()
1391 } else if (state == "windowedRightEdge" || state == "windowed") {
1394 focusAnimation.start()
1397 function playHidingAnimation() {
1398 if (state != "windowedRightEdge") {
1399 hidingAnimation.start()
1403 function refreshStage() {
1404 var newStage = ApplicationInfoInterface.MainStage;
1405 if (priv.sideStageEnabled) { // we're in lanscape rotation.
1406 if (application && application.supportedOrientations & (Qt.PortraitOrientation|Qt.InvertedPortraitOrientation)) {
1407 var defaultStage = ApplicationInfoInterface.SideStage; // if application supports portrait, it defaults to sidestage.
1408 if (application.supportedOrientations & (Qt.LandscapeOrientation|Qt.InvertedLandscapeOrientation)) {
1409 // if it supports lanscape, it defaults to mainstage.
1410 defaultStage = ApplicationInfoInterface.MainStage;
1412 newStage = WindowStateStorage.getStage(application.appId, defaultStage);
1417 if (focus && stage == ApplicationInfoInterface.SideStage && !sideStage.shown) {
1422 UbuntuNumberAnimation {
1428 duration: UbuntuAnimation.SnapDuration
1430 topLevelSurfaceList.pendingActivation();
1431 topLevelSurfaceList.raiseId(model.window.id);
1434 appDelegate.activate();
1438 id: rightEdgeFocusAnimation
1439 property int targetX: 0
1440 UbuntuNumberAnimation { target: appDelegate; properties: "x"; to: rightEdgeFocusAnimation.targetX; duration: priv.animationDuration }
1441 UbuntuNumberAnimation { target: decoratedWindow; properties: "angle"; to: 0; duration: priv.animationDuration }
1442 UbuntuNumberAnimation { target: decoratedWindow; properties: "itemScale"; to: 1; duration: priv.animationDuration }
1444 topLevelSurfaceList.pendingActivation();
1445 inhibitSlideAnimation = true;
1448 appDelegate.activate();
1453 UbuntuNumberAnimation { target: appDelegate; property: "opacity"; to: 0; duration: priv.animationDuration }
1454 onStopped: appDelegate.opacity = 1
1461 flickable: floatingFlickable
1465 sceneWidth: root.width
1466 stage: appDelegate.stage
1467 thisDelegate: appDelegate
1468 mainStageDelegate: priv.mainStageDelegate
1469 sideStageDelegate: priv.sideStageDelegate
1470 sideStageWidth: sideStage.panelWidth
1471 sideStageX: sideStage.x
1472 itemIndex: appDelegate.itemIndex
1473 nextInStack: priv.nextInStack
1474 animationDuration: priv.animationDuration
1477 StagedRightEdgeMaths {
1478 id: stagedRightEdgeMaths
1479 sceneWidth: root.availableDesktopArea.width
1480 sceneHeight: appContainer.height
1481 isMainStageApp: priv.mainStageDelegate == appDelegate
1482 isSideStageApp: priv.sideStageDelegate == appDelegate
1483 sideStageWidth: sideStage.width
1484 sideStageOpen: sideStage.shown
1486 nextInStack: priv.nextInStack
1488 targetHeight: spreadItem.stackHeight
1489 targetX: spreadMaths.targetX
1490 startY: appDelegate.fullscreen ? 0 : root.availableDesktopArea.y
1491 targetY: spreadMaths.targetY
1492 targetAngle: spreadMaths.targetAngle
1493 targetScale: spreadMaths.targetScale
1494 shuffledZ: stageMaths.itemZ
1495 breakPoint: spreadItem.rightEdgeBreakPoint
1498 WindowedRightEdgeMaths {
1499 id: windowedRightEdgeMaths
1501 startWidth: appDelegate.requestedWidth
1502 startHeight: appDelegate.requestedHeight
1503 targetHeight: spreadItem.stackHeight
1504 targetX: spreadMaths.targetX
1505 targetY: spreadMaths.targetY
1506 normalZ: appDelegate.normalZ
1507 targetAngle: spreadMaths.targetAngle
1508 targetScale: spreadMaths.targetScale
1509 breakPoint: spreadItem.rightEdgeBreakPoint
1514 name: "spread"; when: root.state == "spread"
1515 StateChangeScript { script: { decoratedWindow.cancelDrag(); } }
1517 target: decoratedWindow;
1518 showDecoration: false;
1519 angle: spreadMaths.targetAngle
1520 itemScale: spreadMaths.targetScale
1521 scaleToPreviewSize: spreadItem.stackHeight
1522 scaleToPreviewProgress: 1
1523 hasDecoration: root.mode === "windowed"
1524 shadowOpacity: spreadMaths.shadowOpacity
1525 showHighlight: spreadItem.highlightedIndex === index
1526 darkening: spreadItem.highlightedIndex >= 0
1527 anchors.topMargin: dragArea.distance
1531 x: spreadMaths.targetX
1532 y: spreadMaths.targetY
1534 height: spreadItem.spreadItemHeight
1535 visible: spreadMaths.itemVisible
1537 PropertyChanges { target: dragArea; enabled: true }
1538 PropertyChanges { target: windowInfoItem; opacity: spreadMaths.tileInfoOpacity; visible: spreadMaths.itemVisible }
1539 PropertyChanges { target: touchControls; enabled: false }
1542 name: "stagedRightEdge"
1543 when: (root.mode == "staged" || root.mode == "stagedWithSideStage") && (root.state == "sideStagedRightEdge" || root.state == "stagedRightEdge" || rightEdgeFocusAnimation.running || hidingAnimation.running)
1545 target: stagedRightEdgeMaths
1546 progress: Math.max(rightEdgePushProgress, rightEdgeDragArea.draggedProgress)
1550 x: stagedRightEdgeMaths.animatedX
1551 y: stagedRightEdgeMaths.animatedY
1552 z: stagedRightEdgeMaths.animatedZ
1553 height: stagedRightEdgeMaths.animatedHeight
1554 visible: appDelegate.x < root.width
1557 target: decoratedWindow
1558 hasDecoration: false
1559 angle: stagedRightEdgeMaths.animatedAngle
1560 itemScale: stagedRightEdgeMaths.animatedScale
1561 scaleToPreviewSize: spreadItem.stackHeight
1562 scaleToPreviewProgress: stagedRightEdgeMaths.scaleToPreviewProgress
1565 // make sure it's visible but transparent so it fades in when we transition to spread
1566 PropertyChanges { target: windowInfoItem; opacity: 0; visible: true }
1569 name: "windowedRightEdge"
1570 when: root.mode == "windowed" && (root.state == "windowedRightEdge" || rightEdgeFocusAnimation.running || hidingAnimation.running || rightEdgePushProgress > 0)
1572 target: windowedRightEdgeMaths
1573 swipeProgress: rightEdgeDragArea.dragging ? rightEdgeDragArea.progress : 0
1574 pushProgress: rightEdgePushProgress
1578 x: windowedRightEdgeMaths.animatedX
1579 y: windowedRightEdgeMaths.animatedY
1580 z: windowedRightEdgeMaths.animatedZ
1581 height: stagedRightEdgeMaths.animatedHeight
1584 target: decoratedWindow
1585 showDecoration: windowedRightEdgeMaths.decorationHeight
1586 angle: windowedRightEdgeMaths.animatedAngle
1587 itemScale: windowedRightEdgeMaths.animatedScale
1588 scaleToPreviewSize: spreadItem.stackHeight
1589 scaleToPreviewProgress: windowedRightEdgeMaths.scaleToPreviewProgress
1593 target: opacityEffect;
1594 opacityValue: windowedRightEdgeMaths.opacityMask
1595 sourceItem: windowedRightEdgeMaths.opacityMask < 1 ? decoratedWindow : null
1599 name: "staged"; when: root.state == "staged"
1603 y: root.availableDesktopArea.y
1604 visuallyMaximized: true
1605 visible: appDelegate.x < root.width
1609 requestedWidth: appContainer.width
1610 requestedHeight: root.availableDesktopArea.height
1611 restoreEntryValues: false
1614 target: decoratedWindow
1615 hasDecoration: false
1623 animateX: !focusAnimation.running && !rightEdgeFocusAnimation.running && itemIndex !== spreadItem.highlightedIndex && !inhibitSlideAnimation
1626 target: appDelegate.window
1627 allowClientResize: false
1631 name: "stagedWithSideStage"; when: root.state == "stagedWithSideStage"
1639 y: root.availableDesktopArea.y
1641 visuallyMaximized: true
1642 visible: appDelegate.x < root.width
1646 requestedWidth: stageMaths.itemWidth
1647 requestedHeight: root.availableDesktopArea.height
1648 restoreEntryValues: false
1651 target: decoratedWindow
1652 hasDecoration: false
1659 target: appDelegate.window
1660 allowClientResize: false
1664 name: "maximized"; when: appDelegate.maximized && !appDelegate.minimized
1666 target: appDelegate;
1667 requestedX: root.availableDesktopArea.x;
1669 visuallyMinimized: false;
1670 visuallyMaximized: true
1674 requestedWidth: root.availableDesktopArea.width;
1675 requestedHeight: appContainer.height;
1676 restoreEntryValues: false
1678 PropertyChanges { target: touchControls; enabled: true }
1679 PropertyChanges { target: decoratedWindow; windowControlButtonsVisible: false }
1682 name: "fullscreen"; when: appDelegate.fullscreen && !appDelegate.minimized
1684 target: appDelegate;
1690 requestedWidth: appContainer.width
1691 requestedHeight: appContainer.height
1692 restoreEntryValues: false
1694 PropertyChanges { target: decoratedWindow; hasDecoration: false }
1698 when: appDelegate.windowState == WindowStateStorage.WindowStateNormal
1701 visuallyMinimized: false
1703 PropertyChanges { target: touchControls; enabled: true }
1704 PropertyChanges { target: resizeArea; enabled: true }
1705 PropertyChanges { target: decoratedWindow; shadowOpacity: .3; windowControlButtonsVisible: true}
1708 requestedWidth: windowedWidth
1709 requestedHeight: windowedHeight
1710 restoreEntryValues: false
1715 when: appDelegate.windowState == WindowStateStorage.WindowStateRestored
1718 restoreEntryValues: false
1719 target: appDelegate;
1720 windowedX: restoredX;
1721 windowedY: restoredY;
1725 name: "maximizedLeft"; when: appDelegate.maximizedLeft && !appDelegate.minimized
1729 windowedX: root.availableDesktopArea.x
1730 windowedY: root.availableDesktopArea.y
1731 windowedWidth: root.availableDesktopArea.width / 2
1732 windowedHeight: root.availableDesktopArea.height
1736 name: "maximizedRight"; when: appDelegate.maximizedRight && !appDelegate.minimized
1737 extend: "maximizedLeft"
1739 target: appDelegate;
1740 windowedX: root.availableDesktopArea.x + (root.availableDesktopArea.width / 2)
1744 name: "maximizedTopLeft"; when: appDelegate.maximizedTopLeft && !appDelegate.minimized
1748 windowedX: root.availableDesktopArea.x
1749 windowedY: root.availableDesktopArea.y
1750 windowedWidth: root.availableDesktopArea.width / 2
1751 windowedHeight: root.availableDesktopArea.height / 2
1755 name: "maximizedTopRight"; when: appDelegate.maximizedTopRight && !appDelegate.minimized
1756 extend: "maximizedTopLeft"
1759 windowedX: root.availableDesktopArea.x + (root.availableDesktopArea.width / 2)
1763 name: "maximizedBottomLeft"; when: appDelegate.maximizedBottomLeft && !appDelegate.minimized
1767 windowedX: root.availableDesktopArea.x
1768 windowedY: root.availableDesktopArea.y + (root.availableDesktopArea.height / 2)
1769 windowedWidth: root.availableDesktopArea.width / 2
1770 windowedHeight: root.availableDesktopArea.height / 2
1774 name: "maximizedBottomRight"; when: appDelegate.maximizedBottomRight && !appDelegate.minimized
1775 extend: "maximizedBottomLeft"
1778 windowedX: root.availableDesktopArea.x + (root.availableDesktopArea.width / 2)
1782 name: "maximizedHorizontally"; when: appDelegate.maximizedHorizontally && !appDelegate.minimized
1786 windowedX: root.availableDesktopArea.x; windowedY: windowedY
1787 windowedWidth: root.availableDesktopArea.width; windowedHeight: windowedHeight
1791 name: "maximizedVertically"; when: appDelegate.maximizedVertically && !appDelegate.minimized
1795 windowedX: windowedX; windowedY: root.availableDesktopArea.y
1796 windowedWidth: windowedWidth; windowedHeight: root.availableDesktopArea.height
1800 name: "minimized"; when: appDelegate.minimized
1803 scale: units.gu(5) / appDelegate.width
1805 visuallyMinimized: true
1806 visuallyMaximized: false
1807 x: -appDelegate.width / 2
1815 // These two animate applications into position from Staged to Desktop and back
1817 from: "staged,stagedWithSideStage"
1818 to: "normal,restored,maximized,maximizedHorizontally,maximizedVertically,maximizedLeft,maximizedRight,maximizedTopLeft,maximizedBottomLeft,maximizedTopRight,maximizedBottomRight"
1819 enabled: appDelegate.animationsEnabled
1820 PropertyAction { target: appDelegate; properties: "visuallyMinimized,visuallyMaximized" }
1821 UbuntuNumberAnimation { target: appDelegate; properties: "x,y,requestedX,requestedY,opacity,requestedWidth,requestedHeight,scale"; duration: priv.animationDuration }
1824 from: "normal,restored,maximized,maximizedHorizontally,maximizedVertically,maximizedLeft,maximizedRight,maximizedTopLeft,maximizedBottomLeft,maximizedTopRight,maximizedBottomRight"
1825 to: "staged,stagedWithSideStage"
1826 UbuntuNumberAnimation { target: appDelegate; properties: "x,y,requestedX,requestedY,requestedWidth,requestedHeight"; duration: priv.animationDuration}
1830 from: "normal,restored,maximized,maximizedHorizontally,maximizedVertically,maximizedLeft,maximizedRight,maximizedTopLeft,maximizedBottomLeft,maximizedTopRight,maximizedBottomRight,staged,stagedWithSideStage,windowedRightEdge,stagedRightEdge";
1832 // DecoratedWindow wants the scaleToPreviewSize set before enabling scaleToPreview
1833 PropertyAction { target: appDelegate; properties: "z,visible" }
1834 PropertyAction { target: decoratedWindow; property: "scaleToPreviewSize" }
1835 UbuntuNumberAnimation { target: appDelegate; properties: "x,y,height"; duration: priv.animationDuration }
1836 UbuntuNumberAnimation { target: decoratedWindow; properties: "width,height,itemScale,angle,scaleToPreviewProgress"; duration: priv.animationDuration }
1837 UbuntuNumberAnimation { target: windowInfoItem; properties: "opacity"; duration: priv.animationDuration }
1840 from: "normal,staged"; to: "stagedWithSideStage"
1841 UbuntuNumberAnimation { target: appDelegate; properties: "x,y,requestedWidth,requestedHeight"; duration: priv.animationDuration }
1844 to: "windowedRightEdge"
1847 windowedRightEdgeMaths.startX = appDelegate.requestedX
1848 windowedRightEdgeMaths.startY = appDelegate.requestedY
1851 var thisRect = { x: appDelegate.windowedX, y: appDelegate.windowedY, width: appDelegate.requestedWidth, height: appDelegate.requestedHeight }
1852 var otherDelegate = appRepeater.itemAt(0);
1853 var otherRect = { x: otherDelegate.windowedX, y: otherDelegate.windowedY, width: otherDelegate.requestedWidth, height: otherDelegate.requestedHeight }
1854 var intersectionRect = MathUtils.intersectionRect(thisRect, otherRect)
1855 var mappedInterSectionRect = appDelegate.mapFromItem(root, intersectionRect.x, intersectionRect.y)
1856 opacityEffect.maskX = mappedInterSectionRect.x
1857 opacityEffect.maskY = mappedInterSectionRect.y
1858 opacityEffect.maskWidth = intersectionRect.width
1859 opacityEffect.maskHeight = intersectionRect.height
1865 from: "stagedRightEdge"; to: "staged"
1866 enabled: rightEdgeDragArea.cancelled // only transition back to state if the gesture was cancelled, in the other cases we play the focusAnimations.
1867 SequentialAnimation {
1869 UbuntuNumberAnimation { target: appDelegate; properties: "x,y,height,width,scale"; duration: priv.animationDuration }
1870 UbuntuNumberAnimation { target: decoratedWindow; properties: "width,height,itemScale,angle,scaleToPreviewProgress"; duration: priv.animationDuration }
1872 // We need to release scaleToPreviewSize at last
1873 PropertyAction { target: decoratedWindow; property: "scaleToPreviewSize" }
1874 PropertyAction { target: appDelegate; property: "visible" }
1878 from: ",normal,restored,maximized,maximizedLeft,maximizedRight,maximizedTopLeft,maximizedTopRight,maximizedBottomLeft,maximizedBottomRight,maximizedHorizontally,maximizedVertically,fullscreen"
1880 SequentialAnimation {
1881 ScriptAction { script: { fakeRectangle.stop(); } }
1882 PropertyAction { target: appDelegate; property: "visuallyMaximized" }
1883 PropertyAction { target: appDelegate; property: "visuallyMinimized" }
1884 UbuntuNumberAnimation { target: appDelegate; properties: "x,y,scale,opacity"; duration: priv.animationDuration }
1885 PropertyAction { target: appDelegate; property: "visuallyMinimized" }
1890 to: ",normal,restored,maximized,maximizedLeft,maximizedRight,maximizedTopLeft,maximizedTopRight,maximizedBottomLeft,maximizedBottomRight,maximizedHorizontally,maximizedVertically,fullscreen"
1891 SequentialAnimation {
1892 PropertyAction { target: appDelegate; property: "visuallyMinimized,z" }
1894 UbuntuNumberAnimation { target: appDelegate; properties: "x"; from: -appDelegate.width / 2; duration: priv.animationDuration }
1895 UbuntuNumberAnimation { target: appDelegate; properties: "y,opacity"; duration: priv.animationDuration }
1896 UbuntuNumberAnimation { target: appDelegate; properties: "scale"; from: 0; duration: priv.animationDuration }
1898 PropertyAction { target: appDelegate; property: "visuallyMaximized" }
1902 id: windowedTransition
1903 from: ",normal,restored,maximized,maximizedLeft,maximizedRight,maximizedTopLeft,maximizedTopRight,maximizedBottomLeft,maximizedBottomRight,maximizedHorizontally,maximizedVertically,fullscreen,minimized"
1904 to: ",normal,restored,maximized,maximizedLeft,maximizedRight,maximizedTopLeft,maximizedTopRight,maximizedBottomLeft,maximizedBottomRight,maximizedHorizontally,maximizedVertically,fullscreen"
1905 enabled: appDelegate.animationsEnabled
1906 SequentialAnimation {
1907 ScriptAction { script: {
1908 if (appDelegate.visuallyMaximized) visuallyMaximized = false; // maximized before -> going to restored
1911 PropertyAction { target: appDelegate; property: "visuallyMinimized" }
1912 UbuntuNumberAnimation { target: appDelegate; properties: "requestedX,requestedY,windowedX,windowedY,opacity,scale,requestedWidth,requestedHeight,windowedWidth,windowedHeight";
1913 duration: priv.animationDuration }
1914 ScriptAction { script: {
1915 fakeRectangle.stop();
1916 appDelegate.visuallyMaximized = appDelegate.maximized; // reflect the target state
1925 property: "decorationsAlwaysVisible"
1926 value: appDelegate && appDelegate.maximized && touchControls.overlayShown
1931 objectName: "windowResizeArea"
1933 anchors.fill: appDelegate
1935 // workaround so that it chooses the correct resize borders when you drag from a corner ResizeGrip
1936 anchors.margins: touchControls.overlayShown ? borderThickness/2 : -borderThickness
1939 boundsItem: root.availableDesktopArea
1940 minWidth: units.gu(10)
1941 minHeight: units.gu(10)
1942 borderThickness: units.gu(2)
1945 readyToAssesBounds: !appDelegate._constructing
1948 appDelegate.activate();
1954 objectName: "decoratedWindow"
1955 anchors.left: appDelegate.left
1956 anchors.top: appDelegate.top
1957 application: model.application
1958 surface: model.window.surface
1959 active: model.window.focused
1961 interactive: root.interactive
1963 decorationHeight: priv.windowDecorationHeight
1964 maximizeButtonShown: appDelegate.canBeMaximized
1965 overlayShown: touchControls.overlayShown
1966 width: implicitWidth
1967 height: implicitHeight
1968 highlightSize: windowInfoItem.iconMargin / 2
1969 boundsItem: root.availableDesktopArea
1970 panelState: root.panelState
1971 altDragEnabled: root.mode == "windowed"
1973 requestedWidth: appDelegate.requestedWidth
1974 requestedHeight: appDelegate.requestedHeight
1976 onCloseClicked: { appDelegate.close(); }
1977 onMaximizeClicked: {
1978 if (appDelegate.canBeMaximized) {
1979 appDelegate.anyMaximized ? appDelegate.requestRestore() : appDelegate.requestMaximize();
1982 onMaximizeHorizontallyClicked: {
1983 if (appDelegate.canBeMaximizedHorizontally) {
1984 appDelegate.maximizedHorizontally ? appDelegate.requestRestore() : appDelegate.requestMaximizeHorizontally()
1987 onMaximizeVerticallyClicked: {
1988 if (appDelegate.canBeMaximizedVertically) {
1989 appDelegate.maximizedVertically ? appDelegate.requestRestore() : appDelegate.requestMaximizeVertically()
1992 onMinimizeClicked: { appDelegate.requestMinimize(); }
1993 onDecorationPressed: { appDelegate.activate(); }
1994 onDecorationReleased: fakeRectangle.visible ? fakeRectangle.commit() : appDelegate.updateRestoredGeometry()
1996 property real angle: 0
1997 Behavior on angle { enabled: priv.closingIndex >= 0; UbuntuNumberAnimation {} }
1998 property real itemScale: 1
1999 Behavior on itemScale { enabled: priv.closingIndex >= 0; UbuntuNumberAnimation {} }
2004 origin.y: decoratedWindow.implicitHeight / 2
2005 xScale: decoratedWindow.itemScale
2006 yScale: decoratedWindow.itemScale
2009 origin { x: 0; y: (decoratedWindow.height / 2) }
2010 axis { x: 0; y: 1; z: 0 }
2011 angle: decoratedWindow.angle
2018 anchors.fill: decoratedWindow
2021 WindowControlsOverlay {
2023 anchors.fill: appDelegate
2025 resizeArea: resizeArea
2028 boundsItem: root.availableDesktopArea
2030 onFakeMaximizeAnimationRequested: if (!appDelegate.maximized) fakeRectangle.maximize(amount, true)
2031 onFakeMaximizeLeftAnimationRequested: if (!appDelegate.maximizedLeft) fakeRectangle.maximizeLeft(amount, true)
2032 onFakeMaximizeRightAnimationRequested: if (!appDelegate.maximizedRight) fakeRectangle.maximizeRight(amount, true)
2033 onFakeMaximizeTopLeftAnimationRequested: if (!appDelegate.maximizedTopLeft) fakeRectangle.maximizeTopLeft(amount, true);
2034 onFakeMaximizeTopRightAnimationRequested: if (!appDelegate.maximizedTopRight) fakeRectangle.maximizeTopRight(amount, true);
2035 onFakeMaximizeBottomLeftAnimationRequested: if (!appDelegate.maximizedBottomLeft) fakeRectangle.maximizeBottomLeft(amount, true);
2036 onFakeMaximizeBottomRightAnimationRequested: if (!appDelegate.maximizedBottomRight) fakeRectangle.maximizeBottomRight(amount, true);
2037 onStopFakeAnimation: fakeRectangle.stop();
2038 onDragReleased: fakeRectangle.visible ? fakeRectangle.commit() : appDelegate.updateRestoredGeometry()
2041 WindowedFullscreenPolicy {
2042 id: windowedFullscreenPolicy
2044 StagedFullscreenPolicy {
2045 id: stagedFullscreenPolicy
2046 active: root.mode == "staged" || root.mode == "stagedWithSideStage"
2047 surface: model.window.surface
2050 SpreadDelegateInputArea {
2052 objectName: "dragArea"
2053 anchors.fill: decoratedWindow
2057 dragDelegate: fakeDragItem
2060 spreadItem.highlightedIndex = index;
2061 if (distance == 0) {
2062 priv.goneToSpread = false;
2066 priv.closingIndex = index
2067 appDelegate.close();
2073 objectName: "windowInfoItem"
2074 anchors { left: parent.left; top: decoratedWindow.bottom; topMargin: units.gu(1) }
2075 title: model.application.name
2076 iconSource: model.application.icon
2077 height: spreadItem.appInfoHeight
2080 visible: opacity > 0
2082 var nextApp = appRepeater.itemAt(index + 1);
2084 return Math.max(iconHeight, nextApp.x - appDelegate.x - units.gu(1))
2086 return appDelegate.width;
2090 spreadItem.highlightedIndex = index;
2091 priv.goneToSpread = false;
2097 objectName: "closeMouseArea"
2098 anchors { left: parent.left; top: parent.top; leftMargin: -height / 2; topMargin: -height / 2 + spreadMaths.closeIconOffset }
2099 readonly property var mousePos: hoverMouseArea.mapToItem(appDelegate, hoverMouseArea.mouseX, hoverMouseArea.mouseY)
2100 readonly property bool shown: dragArea.distance == 0
2101 && index == spreadItem.highlightedIndex
2102 && mousePos.y < (decoratedWindow.height / 3)
2103 && mousePos.y > -units.gu(4)
2104 && mousePos.x > -units.gu(4)
2105 && mousePos.x < (decoratedWindow.width * 2 / 3)
2106 opacity: shown ? 1 : 0
2107 visible: opacity > 0
2108 Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
2113 priv.closingIndex = index;
2114 appDelegate.close();
2118 source: "graphics/window-close.svg"
2119 anchors.fill: closeMouseArea
2120 anchors.margins: units.gu(2)
2121 sourceSize.width: width
2122 sourceSize.height: height
2127 // Group all child windows in this item so that we can fade them out together when going to the spread
2128 // (and fade them in back again when returning from it)
2129 readonly property bool stageOnProperState: root.state === "windowed"
2130 || root.state === "staged"
2131 || root.state === "stagedWithSideStage"
2133 // TODO: Is it worth the extra cost of layering to avoid the opacity artifacts of intersecting children?
2134 // Btw, will involve more than uncommenting the line below as children won't necessarily fit this item's
2135 // geometry. This is just a reference.
2136 //layer.enabled: opacity !== 0.0 && opacity !== 1.0
2138 opacity: stageOnProperState ? 1.0 : 0.0
2139 visible: opacity !== 0.0 // make it transparent to input as well
2140 Behavior on opacity { UbuntuNumberAnimation {} }
2143 id: childWindowRepeater
2144 model: appDelegate.surface ? appDelegate.surface.childSurfaceList : null
2146 delegate: ChildWindowTree {
2147 surface: model.surface
2149 // Account for the displacement caused by window decoration in the top-level surface
2150 // Ie, the top-level surface is not positioned at (0,0) of this ChildWindow's parent (appDelegate)
2151 displacementX: appDelegate.clientAreaItem.x
2152 displacementY: appDelegate.clientAreaItem.y
2154 boundsItem: root.availableDesktopArea
2155 decorationHeight: priv.windowDecorationHeight
2157 z: childWindowRepeater.count - model.index
2161 // some child surface in this tree got focus.
2162 // Ensure we also have it at the top-level hierarchy
2163 appDelegate.claimFocus();
2173 FakeMaximizeDelegate {
2175 target: priv.focusedAppDelegate
2176 leftMargin: root.availableDesktopArea.x
2177 appContainerWidth: appContainer.width
2178 appContainerHeight: appContainer.height
2179 panelState: root.panelState
2183 id: workspaceSwitcher
2184 enabled: workspaceEnabled
2185 anchors.centerIn: parent
2186 height: units.gu(20)
2187 width: root.width - units.gu(8)
2188 background: root.background
2191 appContainer.focus = true;
2197 id: shortRightEdgeSwipeAnimation
2200 duration: priv.animationDuration
2204 id: rightEdgeDragArea
2205 objectName: "rightEdgeDragArea"
2206 direction: Direction.Leftwards
2207 anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
2208 width: root.dragAreaWidth
2209 enabled: root.spreadEnabled
2211 property var gesturePoints: []
2212 property bool cancelled: false
2214 property real progress: -touchPosition.x / root.width
2215 onProgressChanged: {
2217 draggedProgress = progress;
2221 property real draggedProgress: 0
2223 onTouchPositionChanged: {
2224 gesturePoints.push(touchPosition.x);
2225 if (gesturePoints.length > 10) {
2226 gesturePoints.splice(0, gesturePoints.length - 10)
2230 onDraggingChanged: {
2232 // A potential edge-drag gesture has started. Start recording it
2235 draggedProgress = 0;
2237 // Ok. The user released. Did he drag far enough to go to full spread?
2238 if (gesturePoints[gesturePoints.length - 1] < -spreadItem.rightEdgeBreakPoint * spreadItem.width ) {
2240 // He dragged far enough, but if the last movement was a flick to the right again, he wants to cancel the spread again.
2241 var oneWayFlickToRight = true;
2242 var smallestX = gesturePoints[0]-1;
2243 for (var i = 0; i < gesturePoints.length; i++) {
2244 if (gesturePoints[i] <= smallestX) {
2245 oneWayFlickToRight = false;
2248 smallestX = gesturePoints[i];
2251 if (!oneWayFlickToRight) {
2252 // Ok, the user made it, let's go to spread!
2253 priv.goneToSpread = true;
2258 // Ok, the user didn't drag far enough to cross the breakPoint
2259 // Find out if it was a one-way movement to the left, in which case we just switch directly to next app.
2260 var oneWayFlick = true;
2261 var smallestX = rightEdgeDragArea.width;
2262 for (var i = 0; i < gesturePoints.length; i++) {
2263 if (gesturePoints[i] >= smallestX) {
2264 oneWayFlick = false;
2267 smallestX = gesturePoints[i];
2270 if (appRepeater.count > 1 &&
2271 (oneWayFlick && rightEdgeDragArea.distance > units.gu(2) || rightEdgeDragArea.distance > spreadItem.rightEdgeBreakPoint * spreadItem.width)) {
2272 var nextStage = appRepeater.itemAt(priv.nextInStack).stage
2273 for (var i = 0; i < appRepeater.count; i++) {
2274 if (i != priv.nextInStack && appRepeater.itemAt(i).stage == nextStage) {
2275 appRepeater.itemAt(i).playHidingAnimation()
2279 appRepeater.itemAt(priv.nextInStack).playFocusAnimation()
2280 if (appRepeater.itemAt(priv.nextInStack).stage == ApplicationInfoInterface.SideStage && !sideStage.shown) {
2294 TabletSideStageTouchGesture {
2296 objectName: "triGestureArea"
2297 anchors.fill: parent
2299 property Item appDelegate
2301 dragComponent: dragComponent
2302 dragComponentProperties: { "appDelegate": appDelegate }
2305 function matchDelegate(obj) { return String(obj.objectName).indexOf("appDelegate") >= 0; }
2307 var delegateAtCenter = Functions.itemAt(appContainer, x, y, matchDelegate);
2308 if (!delegateAtCenter) return;
2310 appDelegate = delegateAtCenter;
2314 if (sideStage.shown) {
2318 priv.updateMainAndSideStageIndexes()
2323 // If we're dragging to the sidestage.
2324 if (!sideStage.shown) {
2332 property Item appDelegate
2334 surface: appDelegate ? appDelegate.surface : null
2336 consumesInput: false
2339 requestedWidth: appDelegate ? appDelegate.requestedWidth : 0
2340 requestedHeight: appDelegate ? appDelegate.requestedHeight : 0
2343 height: units.gu(40)
2345 Drag.hotSpot.x: width/2
2346 Drag.hotSpot.y: height/2
2347 // only accept opposite stage.
2349 if (!surface) return "Disabled";
2351 if (appDelegate.stage === ApplicationInfo.MainStage) {
2352 if (appDelegate.application.supportedOrientations
2353 & (Qt.PortraitOrientation|Qt.InvertedPortraitOrientation)) {