@@ -31,7 +31,6 @@ import "Panel"
31import "Hud"
31import "Hud"
32import "Components"
32import "Components"
33import "Bottombar"
33import "Bottombar"
35import "Notifications"
34import "Notifications"
36import Unity.Notifications 1.0 as NotificationBackend
35import Unity.Notifications 1.0 as NotificationBackend
@@ -49,20 +48,24 @@ FocusScope {
49 readonly property real panelHeight: panel.panelHeight
48 readonly property real panelHeight: panel.panelHeight
51 property bool dashShown: dash.shown
50 property bool dashShown: dash.shown
52− property bool stageScreenshotsReady: {
51+
53− if (sideStage.shown) {
52+ property bool sideStageEnabled: shell.width >= units.gu(100)
54− if (mainStage.applications.count > 0) {
53+ readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
55− return mainStage.usingScreenshots && sideStage.usingScreenshots;
54+
56− } else {
55+ function activateApplication(appId) {
57− return sideStage.usingScreenshots;
56+ if (ApplicationManager.findApplication(appId)) {
57+ ApplicationManager.requestFocusApplication(appId);
59+ if (stages.locked && ApplicationManager.focusedApplicationId == appId) {
60+ applicationsDisplayLoader.item.select(appId);
60− return mainStage.usingScreenshots;
63+ var execFlags = shell.sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
64+ ApplicationManager.startApplication(appId, execFlags);
64− property var applicationManager: ApplicationManagerWrapper {}
67 target: LauncherModel
70 target: LauncherModel
68 property: "applicationManager"
71 property: "applicationManager"
@@ -71,49 +74,6 @@ FocusScope {
72 Component.onCompleted: {
75 Component.onCompleted: {
73 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
76 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
75− applicationManager.sideStageEnabled = Qt.binding(function() { return sideStage.enabled })
77− // FIXME: if application focused before shell starts, shell draws on top of it only.
78− // We should detect already running applications on shell start and bring them to the front.
79− applicationManager.unfocusCurrentApplication();
82− readonly property bool applicationFocused: !!applicationManager.mainStageFocusedApplication
83− || !!applicationManager.sideStageFocusedApplication
84− // Used for autopilot testing.
85− readonly property string currentFocusedAppId: ApplicationManager.focusedApplicationId
87− readonly property bool fullscreenMode: {
88− if (greeter.shown || lockscreen.shown) {
90− } else if (mainStage.usingScreenshots) { // Window Manager animating so want to re-evaluate fullscreen mode
91− return mainStage.switchingFromFullscreenToFullscreen;
92− } else if (applicationManager.mainStageFocusedApplication) {
93− return applicationManager.mainStageFocusedApplication.fullscreen;
99− function activateApplication(appId, argument) {
100− if (applicationManager) {
101− // For newly started applications, as it takes them time to draw their first frame
102− // we add a delay before we hide the animation screenshots to compensate.
103− var addDelay = !applicationManager.getApplicationFromDesktopFile(appId);
106− application = applicationManager.activateApplication(appId, argument);
107− if (application == null) {
110− if (application.stage == ApplicationInfo.MainStage || !sideStage.enabled) {
111− mainStage.activateApplication(appId, addDelay);
113− sideStage.activateApplication(appId, addDelay);
119 GSettings {
79 GSettings {
@@ -133,244 +93,219 @@ FocusScope {
133 Keys.onVolumeDownPressed: volumeControl.volumeDown()
93 Keys.onVolumeDownPressed: volumeControl.volumeDown()
136− id: underlay
96+ id: underlayClipper
137− objectName: "underlay"
138 anchors.fill: parent
97 anchors.fill: parent
98+ anchors.rightMargin: stages.overlayWidth
99+ clip: stages.overlayMode && !stages.painting
140− // Whether the underlay is fully covered by opaque UI elements.
101+ InputFilterArea {
141− property bool fullyCovered: panel.indicators.fullyOpened && shell.width <= panel.indicatorsMenuWidth
102+ anchors.fill: parent
103+ blockInput: parent.clip
143− readonly property bool applicationRunning: ((mainStage.applications && mainStage.applications.count > 0)
106+ Item {
144− || (sideStage.applications && sideStage.applications.count > 0))
107+ id: underlay
108+ objectName: "underlay"
109+ anchors.fill: parent
110+ anchors.rightMargin: -parent.anchors.rightMargin
146− // Whether the user should see the topmost application surface (if there's one at all).
112+ // Whether the underlay is fully covered by opaque UI elements.
147− readonly property bool applicationSurfaceShouldBeSeen: applicationRunning && !stages.fullyHidden
113+ property bool fullyCovered: panel.indicators.fullyOpened && shell.width <= panel.indicatorsMenuWidth
148− && !mainStage.usingScreenshots // but want sideStage animating over app surface
115+ // Whether the user should see the topmost application surface (if there's one at all).
116+ readonly property bool applicationSurfaceShouldBeSeen: stages.shown && !stages.painting && !stages.overlayMode
118+ // NB! Application surfaces are stacked behind the shell one. So they can only be seen by the user
119+ // through the translucent parts of the shell surface.
120+ visible: !fullyCovered && !applicationSurfaceShouldBeSeen
152− // NB! Application surfaces are stacked behing the shell one. So they can only be seen by the user
122+ CrossFadeImage {
153− // through the translucent parts of the shell surface.
123+ id: backgroundImage
154− visible: !fullyCovered && !applicationSurfaceShouldBeSeen
124+ objectName: "backgroundImage"
157− anchors.fill: parent
126+ anchors.fill: parent
158− color: "black"
127+ source: shell.background
159− opacity: dash.disappearingAnimationProgress
128+ fillMode: Image.PreserveAspectCrop
162− Image {
131+ Rectangle {
163− anchors.fill: dash
132+ anchors.fill: parent
164− source: shell.width > shell.height ? "Dash/graphics/paper_landscape.png" : "Dash/graphics/paper_portrait.png"
133+ color: "black"
165− fillMode: Image.PreserveAspectCrop
134+ opacity: dash.disappearingAnimationProgress
166− horizontalAlignment: Image.AlignRight
167− verticalAlignment: Image.AlignTop
171− id: dash
138+ anchors.fill: dash
172− objectName: "dash"
139+ source: shell.width > shell.height ? "Dash/graphics/paper_landscape.png" : "Dash/graphics/paper_portrait.png"
173−
140+ fillMode: Image.PreserveAspectCrop
174− available: !greeter.shown && !lockscreen.shown
141+ horizontalAlignment: Image.AlignRight
175− hides: [stages, launcher, panel.indicators]
142+ verticalAlignment: Image.AlignTop
176− shown: disappearingAnimationProgress !== 1.0
177− enabled: disappearingAnimationProgress === 0.0 && edgeDemo.dashEnabled
178− // FIXME: unfocus all applications when going back to the dash
181− shell.applicationManager.unfocusCurrentApplication()
149+ available: !greeter.shown && !lockscreen.shown
150+ hides: [stages, launcher, panel.indicators]
151+ shown: disappearingAnimationProgress !== 1.0
152+ enabled: disappearingAnimationProgress === 0.0 && edgeDemo.dashEnabled
185− anchors {
154+ anchors {
186− fill: parent
155+ fill: parent
187− topMargin: panel.panelHeight
156+ topMargin: panel.panelHeight
159+ contentScale: 1.0 - 0.2 * disappearingAnimationProgress
160+ opacity: 1.0 - disappearingAnimationProgress
161+ property real disappearingAnimationProgress: {
162+ if (greeter.shown) {
163+ return greeter.showProgress;
165+ if (stages.overlayMode) {
168+ return stages.showProgress
172+ // FIXME: only necessary because stages.showProgress and
173+ // greeterRevealer.animatedProgress are not animated
174+ Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }}
180+ id: stagesDragHandle
181+ direction: Direction.Leftwards
183+ anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
184+ width: shell.edgeSize
190− contentScale: 1.0 - 0.2 * disappearingAnimationProgress
186+ property real progress: stages.width
191− opacity: 1.0 - disappearingAnimationProgress
187+
192− property real disappearingAnimationProgress: {
188+ onTouchXChanged: {
193− if (greeter.shown) {
189+ if (status == DirectionalDragArea.Recognized) {
194− return greeter.showProgress;
190+ if (ApplicationManager.count == 0) {
191+ progress = Math.max(stages.width - stagesDragHandle.width + touchX, stages.width * .3)
196− return stagesOuterContainer.showProgress;
193+ progress = stages.width - stagesDragHandle.width + touchX
200− // FIXME: only necessary because stagesOuterContainer.showProgress and
198+ onDraggingChanged: {
201− // greeterRevealer.animatedProgress are not animated
199+ if (!dragging) {
202− Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }}
200+ if (ApplicationManager.count > 0 && progress < stages.width - units.gu(10)) {
203+ stagesDragHandle.progress = stages.width;
207− id: stagesOuterContainer
209+ id: stages
208−
210+ objectName: "stages"
209 width: parent.width
211 width: parent.width
210 height: parent.height
212 height: parent.height
211− x: launcher.progress
212− Behavior on x {SmoothedAnimation{velocity: 600}}
214− property real showProgress:
214+ x: {
215− MathUtils.clamp(1 - (x + stages.x) / shell.width, 0, 1)
215+ if (shown) {
216+ if (overlayMode || locked) {
219+ return launcher.progress
221+ return stagesDragHandle.progress
225+ Behavior on x { SmoothedAnimation { velocity: 600; duration: UbuntuAnimation.FastDuration } }
217− Showable {
227+ property bool shown: false
219− objectName: "stages"
221− x: width
229+ property real showProgress: overlayMode ? 0 : MathUtils.clamp(1 - x / shell.width, 0, 1)
223− property bool fullyShown: shown && x == 0 && parent.x == 0
231+ property bool fullyShown: x == 0
224− property bool fullyHidden: !shown && x == width
232+ property bool fullyHidden: x == width
225− available: !greeter.shown
226− hides: [panel.indicators]
229− showAnimation: StandardAnimation { property: "x"; duration: 350; to: 0; easing.type: Easing.OutCubic }
230− hideAnimation: StandardAnimation { property: "x"; duration: 350; to: width; easing.type: Easing.OutCubic }
232− width: parent.width
234+ property bool painting: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.painting : false
233− height: parent.height
235+ property bool fullscreen: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.fullscreen : false
236+ property bool overlayMode: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.overlayMode : false
237+ property int overlayWidth: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.overlayWidth : false
238+ property bool locked: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.locked : false
235− // close the stages when no focused application remains
240+ function show(focusApp) {
236− Connections {
241+ shown = true;
237− target: shell.applicationManager
242+ panel.indicators.hide();
238− onMainStageFocusedApplicationChanged: stages.closeIfNoApplications()
243+ if (!ApplicationManager.focusedApplicationId && ApplicationManager.count > 0 && focusApp) {
239− onSideStageFocusedApplicationChanged: stages.closeIfNoApplications()
244+ ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
240− ignoreUnknownSignals: true
243− function closeIfNoApplications() {
248+ function hide() {
244− if (!shell.applicationManager.mainStageFocusedApplication
249+ shown = false;
245− && !shell.applicationManager.sideStageFocusedApplication
250+ if (ApplicationManager.focusedApplicationId) {
246− && shell.applicationManager.mainStageApplications.count == 0
251+ ApplicationManager.unfocusCurrentApplication();
247− && shell.applicationManager.sideStageApplications.count == 0) {
252− // show the stages when an application gets the focus
253− Connections {
255+ Connections {
254− target: shell.applicationManager
256+ target: ApplicationManager
255− onMainStageFocusedApplicationChanged: {
257+
256− if (shell.applicationManager.mainStageFocusedApplication) {
258+ onFocusRequested: {
257− mainStage.show();
259+ stages.show(true);
262+ onFocusedApplicationIdChanged: {
263+ if (ApplicationManager.focusedApplicationId.length > 0) {
258− stages.show();
264+ stages.show(false);
260− }
266+ if (!stages.overlayMode) {
261− onSideStageFocusedApplicationChanged: {
262− if (shell.applicationManager.sideStageFocusedApplication) {
264− stages.show();
267+ stages.hide();
267− ignoreUnknownSignals: true
270− Stage {
271+ // If any app is focused when greeter is open, it's due to a user action
271− id: mainStage
272+ // like a snap decision (say, an incoming call).
273+ // TODO: these should be protected to only unlock for certain applications / certain usecases
274+ // potentially only in connection with a notification.
273− anchors.fill: parent
278+ onApplicationAdded: {
274− fullyShown: stages.fullyShown
275− fullyHidden: stages.fullyHidden
276− shouldUseScreenshots: !fullyShown
277− rightEdgeEnabled: !sideStage.enabled
279− applicationManager: shell.applicationManager
280− rightEdgeDraggingAreaWidth: shell.edgeSize
281− normalApplicationY: shell.panelHeight
285− stages.show();
279+ stages.show(false);
290− // FIXME: workaround the fact that focusing a main stage application
282+ onApplicationRemoved: {
291− // raises its surface on top of all other surfaces including the ones
283+ if (ApplicationManager.focusedApplicationId.length == 0) {
292− // that belong to side stage applications.
284+ stages.hide();
293− onFocusedApplicationChanged: {
294− if (focusedApplication && sideStage.focusedApplication && sideStage.fullyShown) {
295− shell.applicationManager.focusApplication(sideStage.focusedApplication);
300− SideStage {
289+ Loader {
301− id: sideStage
290+ id: applicationsDisplayLoader
302−
291+ anchors.fill: parent
303− applicationManager: shell.applicationManager
304− rightEdgeDraggingAreaWidth: shell.edgeSize
305− normalApplicationY: shell.panelHeight
307− onShownChanged: {
293+ source: shell.sideStageEnabled ? "Stages/StageWithSideStage.qml" : "Stages/PhoneStage.qml"
308− if (!shown && mainStage.applications.count == 0) {
312− // FIXME: when hiding the side stage, refocus the main stage
313− // application so that it goes in front of the side stage
314− // application and hides it
315− onFullyShownChanged: {
316− if (!fullyShown && stages.fullyShown && sideStage.focusedApplication != null) {
317− shell.applicationManager.focusApplication(mainStage.focusedApplication);
321− enabled: shell.width >= units.gu(100)
295+ Binding {
322− visible: enabled
296+ target: applicationsDisplayLoader.item
323− fullyShown: stages.fullyShown && shown
297+ property: "moving"
324− && sideStage[sideStageRevealer.boundProperty] == sideStageRevealer.openedValue
298+ value: !stages.fullyShown
325− shouldUseScreenshots: !fullyShown || mainStage.usingScreenshots || sideStageRevealer.pressed
299+ }
327− available: !greeter.shown && !lockscreen.shown && enabled
301+ target: applicationsDisplayLoader.item
328− hides: [launcher, panel.indicators]
302+ property: "shown"
329− shown: false
303+ value: stages.shown
330− showAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.openedValue; easing.type: Easing.OutQuint }
331− hideAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.closedValue; easing.type: Easing.OutQuint }
334− height: stages.height
335− handleExpanded: sideStageRevealer.pressed
338− Revealer {
306+ target: applicationsDisplayLoader.item
339− id: sideStageRevealer
307+ property: "dragAreaWidth"
341− enabled: mainStage.applications.count > 0 && sideStage.applications.count > 0
342− && sideStage.available
343− direction: Qt.RightToLeft
344− openedValue: parent.width - sideStage.width
345− hintDisplacement: units.gu(3)
346− /* The size of the sidestage handle needs to be bigger than the
347− typical size used for edge detection otherwise it is really
350− handleSize: sideStage.shown ? units.gu(4) : shell.edgeSize
351− closedValue: parent.width + sideStage.handleSizeCollapsed
353− x: parent.width - width
354− width: sideStage.width + handleSize * 0.7
355− height: sideStage.height
356− orientation: Qt.Horizontal
360− id: stagesDragHandle
362− anchors.top: parent.top
363− anchors.bottom: parent.bottom
364− anchors.right: parent.left
366− width: shell.edgeSize
308+ value: shell.edgeSize
367− direction: Direction.Leftwards
368− enabled: greeter.showProgress == 0 && edgeDemo.dashEnabled
369− property bool haveApps: mainStage.applications.count > 0 || sideStage.applications.count > 0
371− maxTotalDragDistance: haveApps ? parent.width : parent.width * 0.7
372− // Make autocompletion impossible when !haveApps
373− edgeDragEvaluator.minDragDistance: haveApps ? maxTotalDragDistance * 0.1 : Number.MAX_VALUE
@@ -447,26 +382,6 @@ FocusScope {
448 dragHandleWidth: shell.edgeSize
383 dragHandleWidth: shell.edgeSize
450− property var previousMainApp: null
451− property var previousSideApp: null
453− function removeApplicationFocus() {
454− greeter.previousMainApp = applicationManager.mainStageFocusedApplication;
455− greeter.previousSideApp = applicationManager.sideStageFocusedApplication;
456− applicationManager.unfocusCurrentApplication();
459− function restoreApplicationFocus() {
460− if (greeter.previousMainApp) {
461− applicationManager.focusApplication(greeter.previousMainApp);
462− greeter.previousMainApp = null;
464− if (greeter.previousSideApp) {
465− applicationManager.focusApplication(greeter.previousSideApp);
466− greeter.previousSideApp = null;
470 onShownChanged: {
385 onShownChanged: {
471 if (shown) {
386 if (shown) {
472 lockscreen.reset();
387 lockscreen.reset();
@@ -476,9 +391,6 @@ FocusScope {
476 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
391 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
478 greeter.forceActiveFocus();
393 greeter.forceActiveFocus();
479− removeApplicationFocus();
481− restoreApplicationFocus();
@@ -496,33 +408,16 @@ FocusScope {
499− Connections {
411+ Binding {
500− target: applicationManager
412+ target: ApplicationManager
501− ignoreUnknownSignals: true
413+ property: "suspended"
502− // If any app is focused when greeter is open, it's due to a user action
414+ value: greeter.shown && greeter.showProgress == 1
503− // like a snap decision (say, an incoming call).
504− // TODO: these should be protected to only unlock for certain applications / certain usecases
505− // potentially only in connection with a notification.
506− onMainStageFocusedApplicationChanged: {
507− if (greeter.shown && applicationManager.mainStageFocusedApplication) {
508− greeter.previousMainApp = null // make way for new focused app
509− greeter.previousSideApp = null
513− onSideStageFocusedApplicationChanged: {
514− if (greeter.shown && applicationManager.sideStageFocusedApplication) {
515− greeter.previousMainApp = null // make way for new focused app
516− greeter.previousSideApp = null
523 InputFilterArea {
418 InputFilterArea {
524 anchors.fill: parent
419 anchors.fill: parent
525− blockInput: !applicationFocused || greeter.shown || lockscreen.shown || launcher.shown
420+ blockInput: ApplicationManager.focusedApplicationId.length === 0 || greeter.shown || lockscreen.shown || launcher.shown
526 || panel.indicators.shown || hud.shown
421 || panel.indicators.shown || hud.shown
@@ -571,7 +466,9 @@ FocusScope {
571 available: edgeDemo.panelEnabled
466 available: edgeDemo.panelEnabled
572 contentEnabled: edgeDemo.panelContentEnabled
467 contentEnabled: edgeDemo.panelContentEnabled
574− fullscreenMode: shell.fullscreenMode
469+ property string focusedAppId: ApplicationManager.focusedApplicationId
470+ property var focusedApplication: ApplicationManager.findApplication(focusedAppId)
471+ fullscreenMode: focusedApplication && stages.fullscreen && !greeter.shown && !lockscreen.shown
575 searchVisible: !greeter.shown && !lockscreen.shown && dash.shown && dash.searchable
472 searchVisible: !greeter.shown && !lockscreen.shown && dash.shown && dash.searchable
577 InputFilterArea {
474 InputFilterArea {
@@ -597,9 +494,8 @@ FocusScope {
597 hideAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: hudRevealer.closedValue; easing.type: Easing.Linear }
494 hideAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: hudRevealer.closedValue; easing.type: Easing.Linear }
599 Connections {
496 Connections {
600− target: shell.applicationManager
497+ target: ApplicationManager
601− onMainStageFocusedApplicationChanged: hud.hide()
498+ onFocusedApplicationIdChanged: hud.hide()
602− onSideStageFocusedApplicationChanged: hud.hide()
@@ -624,7 +520,7 @@ FocusScope {
624 theHud: hud
520 theHud: hud
625 anchors.fill: parent
521 anchors.fill: parent
626 enabled: hud.available
522 enabled: hud.available
627− applicationIsOnForeground: applicationFocused
523+ applicationIsOnForeground: ApplicationManager.focusedApplicationId
630 InputFilterArea {
526 InputFilterArea {
@@ -655,9 +551,11 @@ FocusScope {
655 showHome()
551 showHome()
657 onDash: {
553 onDash: {
658− if (stages.shown) {
554+ if (stages.shown && !stages.overlayMode) {
659− stages.hide();
555+ if (!stages.locked) {
660− launcher.hide();
557+ launcher.hide();
663 onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("clickscope", false, true)
561 onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("clickscope", false, true)
@@ -750,14 +648,14 @@ FocusScope {
750 anchors.bottom: parent.bottom
648 anchors.bottom: parent.bottom
751 anchors.left: parent.left
649 anchors.left: parent.left
752 anchors.right: parent.right
650 anchors.right: parent.right
753− height: shell.applicationManager ? shell.applicationManager.keyboardHeight : 0
651+ height: ApplicationManager.keyboardVisible ? ApplicationManager.keyboardHeight : 0
755− enabled: shell.applicationManager && shell.applicationManager.keyboardVisible
653+ enabled: ApplicationManager.keyboardVisible
759 anchors.centerIn: parent
657 anchors.centerIn: parent
760− visible: applicationManager.fake
658+ visible: ApplicationManager.fake ? ApplicationManager.fake : false
761 text: "EARLY ALPHA\nNOT READY FOR USE"
659 text: "EARLY ALPHA\nNOT READY FOR USE"
762 color: "lightgrey"
660 color: "lightgrey"
763 opacity: 0.2
661 opacity: 0.2