@@ -31,7 +31,6 @@ import "Panel"
3131import "Hud"
3232import "Components"
3333import "Bottombar"
34−import "SideStage"
3534import "Notifications"
3635import Unity.Notifications 1.0 as NotificationBackend
3736
@@ -49,20 +48,24 @@ FocusScope {
4948 readonly property real panelHeight: panel.panelHeight
5049
5150 property bool dashShown: dash.shown
52− property bool stageScreenshotsReady: {
53− if (sideStage.shown) {
54− if (mainStage.applications.count > 0) {
55− return mainStage.usingScreenshots && sideStage.usingScreenshots;
56− } else {
57− return sideStage.usingScreenshots;
51+
52+ property bool sideStageEnabled: shell.width >= units.gu(100)
53+ readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
54+
55+ function activateApplication(appId) {
56+ if (ApplicationManager.findApplication(appId)) {
57+ ApplicationManager.requestFocusApplication(appId);
58+ stages.show(true);
59+ if (stages.locked && ApplicationManager.focusedApplicationId == appId) {
60+ applicationsDisplayLoader.item.select(appId);
5861 }
5962 } else {
60− return mainStage.usingScreenshots;
63+ var execFlags = shell.sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
64+ ApplicationManager.startApplication(appId, execFlags);
65+ stages.show(false);
6166 }
6267 }
6368
64− property var applicationManager: ApplicationManagerWrapper {}
65−
6669 Binding {
6770 target: LauncherModel
6871 property: "applicationManager"
@@ -71,49 +74,6 @@ FocusScope {
7174
7275 Component.onCompleted: {
7376 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
74−
75− applicationManager.sideStageEnabled = Qt.binding(function() { return sideStage.enabled })
76−
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();
80− }
81−
82− readonly property bool applicationFocused: !!applicationManager.mainStageFocusedApplication
83− || !!applicationManager.sideStageFocusedApplication
84− // Used for autopilot testing.
85− readonly property string currentFocusedAppId: ApplicationManager.focusedApplicationId
86−
87− readonly property bool fullscreenMode: {
88− if (greeter.shown || lockscreen.shown) {
89− return false;
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;
94− } else {
95− return false;
96− }
97− }
98−
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);
104−
105− var application;
106− application = applicationManager.activateApplication(appId, argument);
107− if (application == null) {
108− return;
109− }
110− if (application.stage == ApplicationInfo.MainStage || !sideStage.enabled) {
111− mainStage.activateApplication(appId, addDelay);
112− } else {
113− sideStage.activateApplication(appId, addDelay);
114− }
115− stages.show();
116− }
11777 }
11878
11979 GSettings {
@@ -133,244 +93,219 @@ FocusScope {
13393 Keys.onVolumeDownPressed: volumeControl.volumeDown()
13494
13595 Item {
136− id: underlay
137− objectName: "underlay"
96+ id: underlayClipper
13897 anchors.fill: parent
98+ anchors.rightMargin: stages.overlayWidth
99+ clip: stages.overlayMode && !stages.painting
139100
140− // Whether the underlay is fully covered by opaque UI elements.
141− property bool fullyCovered: panel.indicators.fullyOpened && shell.width <= panel.indicatorsMenuWidth
101+ InputFilterArea {
102+ anchors.fill: parent
103+ blockInput: parent.clip
104+ }
142105
143− readonly property bool applicationRunning: ((mainStage.applications && mainStage.applications.count > 0)
144− || (sideStage.applications && sideStage.applications.count > 0))
106+ Item {
107+ id: underlay
108+ objectName: "underlay"
109+ anchors.fill: parent
110+ anchors.rightMargin: -parent.anchors.rightMargin
145111
146− // Whether the user should see the topmost application surface (if there's one at all).
147− readonly property bool applicationSurfaceShouldBeSeen: applicationRunning && !stages.fullyHidden
148− && !mainStage.usingScreenshots // but want sideStage animating over app surface
112+ // Whether the underlay is fully covered by opaque UI elements.
113+ property bool fullyCovered: panel.indicators.fullyOpened && shell.width <= panel.indicatorsMenuWidth
149114
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
150117
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
151121
152− // NB! Application surfaces are stacked behing the shell one. So they can only be seen by the user
153− // through the translucent parts of the shell surface.
154− visible: !fullyCovered && !applicationSurfaceShouldBeSeen
122+ CrossFadeImage {
123+ id: backgroundImage
124+ objectName: "backgroundImage"
155125
156− Rectangle {
157− anchors.fill: parent
158− color: "black"
159− opacity: dash.disappearingAnimationProgress
160− }
126+ anchors.fill: parent
127+ source: shell.background
128+ fillMode: Image.PreserveAspectCrop
129+ }
161130
162− Image {
163− anchors.fill: dash
164− source: shell.width > shell.height ? "Dash/graphics/paper_landscape.png" : "Dash/graphics/paper_portrait.png"
165− fillMode: Image.PreserveAspectCrop
166− horizontalAlignment: Image.AlignRight
167− verticalAlignment: Image.AlignTop
168− }
131+ Rectangle {
132+ anchors.fill: parent
133+ color: "black"
134+ opacity: dash.disappearingAnimationProgress
135+ }
169136
170− Dash {
171− id: dash
172− objectName: "dash"
173−
174− available: !greeter.shown && !lockscreen.shown
175− hides: [stages, launcher, panel.indicators]
176− shown: disappearingAnimationProgress !== 1.0
177− enabled: disappearingAnimationProgress === 0.0 && edgeDemo.dashEnabled
178− // FIXME: unfocus all applications when going back to the dash
179− onEnabledChanged: {
180− if (enabled) {
181− shell.applicationManager.unfocusCurrentApplication()
182− }
137+ Image {
138+ anchors.fill: dash
139+ source: shell.width > shell.height ? "Dash/graphics/paper_landscape.png" : "Dash/graphics/paper_portrait.png"
140+ fillMode: Image.PreserveAspectCrop
141+ horizontalAlignment: Image.AlignRight
142+ verticalAlignment: Image.AlignTop
183143 }
184144
185− anchors {
186− fill: parent
187− topMargin: panel.panelHeight
145+ Dash {
146+ id: dash
147+ objectName: "dash"
148+
149+ available: !greeter.shown && !lockscreen.shown
150+ hides: [stages, launcher, panel.indicators]
151+ shown: disappearingAnimationProgress !== 1.0
152+ enabled: disappearingAnimationProgress === 0.0 && edgeDemo.dashEnabled
153+
154+ anchors {
155+ fill: parent
156+ topMargin: panel.panelHeight
157+ }
158+
159+ contentScale: 1.0 - 0.2 * disappearingAnimationProgress
160+ opacity: 1.0 - disappearingAnimationProgress
161+ property real disappearingAnimationProgress: {
162+ if (greeter.shown) {
163+ return greeter.showProgress;
164+ } else {
165+ if (stages.overlayMode) {
166+ return 0;
167+ }
168+ return stages.showProgress
169+ }
170+ }
171+
172+ // FIXME: only necessary because stages.showProgress and
173+ // greeterRevealer.animatedProgress are not animated
174+ Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }}
188175 }
176+ }
177+ }
178+
179+ EdgeDragArea {
180+ id: stagesDragHandle
181+ direction: Direction.Leftwards
182+
183+ anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
184+ width: shell.edgeSize
189185
190− contentScale: 1.0 - 0.2 * disappearingAnimationProgress
191− opacity: 1.0 - disappearingAnimationProgress
192− property real disappearingAnimationProgress: {
193− if (greeter.shown) {
194− return greeter.showProgress;
186+ property real progress: stages.width
187+
188+ onTouchXChanged: {
189+ if (status == DirectionalDragArea.Recognized) {
190+ if (ApplicationManager.count == 0) {
191+ progress = Math.max(stages.width - stagesDragHandle.width + touchX, stages.width * .3)
195192 } else {
196− return stagesOuterContainer.showProgress;
193+ progress = stages.width - stagesDragHandle.width + touchX
197194 }
198195 }
196+ }
199197
200− // FIXME: only necessary because stagesOuterContainer.showProgress and
201− // greeterRevealer.animatedProgress are not animated
202− Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }}
198+ onDraggingChanged: {
199+ if (!dragging) {
200+ if (ApplicationManager.count > 0 && progress < stages.width - units.gu(10)) {
201+ stages.show(true)
202+ }
203+ stagesDragHandle.progress = stages.width;
204+ }
203205 }
204206 }
205207
206208 Item {
207− id: stagesOuterContainer
208−
209+ id: stages
210+ objectName: "stages"
209211 width: parent.width
210212 height: parent.height
211− x: launcher.progress
212− Behavior on x {SmoothedAnimation{velocity: 600}}
213213
214− property real showProgress:
215− MathUtils.clamp(1 - (x + stages.x) / shell.width, 0, 1)
214+ x: {
215+ if (shown) {
216+ if (overlayMode || locked) {
217+ return 0;
218+ }
219+ return launcher.progress
220+ } else {
221+ return stagesDragHandle.progress
222+ }
223+ }
224+
225+ Behavior on x { SmoothedAnimation { velocity: 600; duration: UbuntuAnimation.FastDuration } }
216226
217− Showable {
218− id: stages
219− objectName: "stages"
227+ property bool shown: false
220228
221− x: width
229+ property real showProgress: overlayMode ? 0 : MathUtils.clamp(1 - x / shell.width, 0, 1)
222230
223− property bool fullyShown: shown && x == 0 && parent.x == 0
224− property bool fullyHidden: !shown && x == width
225− available: !greeter.shown
226− hides: [panel.indicators]
227− shown: false
228− opacity: 1.0
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 }
231+ property bool fullyShown: x == 0
232+ property bool fullyHidden: x == width
231233
232− width: parent.width
233− height: parent.height
234+ property bool painting: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.painting : false
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
234239
235− // close the stages when no focused application remains
236− Connections {
237− target: shell.applicationManager
238− onMainStageFocusedApplicationChanged: stages.closeIfNoApplications()
239− onSideStageFocusedApplicationChanged: stages.closeIfNoApplications()
240− ignoreUnknownSignals: true
240+ function show(focusApp) {
241+ shown = true;
242+ panel.indicators.hide();
243+ if (!ApplicationManager.focusedApplicationId && ApplicationManager.count > 0 && focusApp) {
244+ ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
241245 }
246+ }
242247
243− function closeIfNoApplications() {
244− if (!shell.applicationManager.mainStageFocusedApplication
245− && !shell.applicationManager.sideStageFocusedApplication
246− && shell.applicationManager.mainStageApplications.count == 0
247− && shell.applicationManager.sideStageApplications.count == 0) {
248− stages.hide();
249− }
248+ function hide() {
249+ shown = false;
250+ if (ApplicationManager.focusedApplicationId) {
251+ ApplicationManager.unfocusCurrentApplication();
250252 }
253+ }
251254
252− // show the stages when an application gets the focus
253− Connections {
254− target: shell.applicationManager
255− onMainStageFocusedApplicationChanged: {
256− if (shell.applicationManager.mainStageFocusedApplication) {
257− mainStage.show();
258− stages.show();
259− }
260− }
261− onSideStageFocusedApplicationChanged: {
262− if (shell.applicationManager.sideStageFocusedApplication) {
263− sideStage.show();
264− stages.show();
255+ Connections {
256+ target: ApplicationManager
257+
258+ onFocusRequested: {
259+ stages.show(true);
260+ }
261+
262+ onFocusedApplicationIdChanged: {
263+ if (ApplicationManager.focusedApplicationId.length > 0) {
264+ stages.show(false);
265+ } else {
266+ if (!stages.overlayMode) {
267+ stages.hide();
265268 }
266269 }
267− ignoreUnknownSignals: true
268− }
269270
270− Stage {
271− id: mainStage
271+ // If any app is focused when greeter is open, it's due to a user action
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.
275+ greeter.hide()
276+ }
272277
273− anchors.fill: parent
274− fullyShown: stages.fullyShown
275− fullyHidden: stages.fullyHidden
276− shouldUseScreenshots: !fullyShown
277− rightEdgeEnabled: !sideStage.enabled
278−
279− applicationManager: shell.applicationManager
280− rightEdgeDraggingAreaWidth: shell.edgeSize
281− normalApplicationY: shell.panelHeight
282−
283− shown: true
284− function show() {
285− stages.show();
286− }
287− function hide() {
288− }
278+ onApplicationAdded: {
279+ stages.show(false);
280+ }
289281
290− // FIXME: workaround the fact that focusing a main stage application
291− // raises its surface on top of all other surfaces including the ones
292− // that belong to side stage applications.
293− onFocusedApplicationChanged: {
294− if (focusedApplication && sideStage.focusedApplication && sideStage.fullyShown) {
295− shell.applicationManager.focusApplication(sideStage.focusedApplication);
296− }
282+ onApplicationRemoved: {
283+ if (ApplicationManager.focusedApplicationId.length == 0) {
284+ stages.hide();
297285 }
298286 }
287+ }
299288
300− SideStage {
301− id: sideStage
302−
303− applicationManager: shell.applicationManager
304− rightEdgeDraggingAreaWidth: shell.edgeSize
305− normalApplicationY: shell.panelHeight
289+ Loader {
290+ id: applicationsDisplayLoader
291+ anchors.fill: parent
306292
307− onShownChanged: {
308− if (!shown && mainStage.applications.count == 0) {
309− stages.hide();
310− }
311− }
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);
318− }
319− }
293+ source: shell.sideStageEnabled ? "Stages/StageWithSideStage.qml" : "Stages/PhoneStage.qml"
320294
321− enabled: shell.width >= units.gu(100)
322− visible: enabled
323− fullyShown: stages.fullyShown && shown
324− && sideStage[sideStageRevealer.boundProperty] == sideStageRevealer.openedValue
325− shouldUseScreenshots: !fullyShown || mainStage.usingScreenshots || sideStageRevealer.pressed
326−
327− available: !greeter.shown && !lockscreen.shown && enabled
328− hides: [launcher, panel.indicators]
329− shown: false
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 }
332−
333− width: units.gu(40)
334− height: stages.height
335− handleExpanded: sideStageRevealer.pressed
336− }
337−
338− Revealer {
339− id: sideStageRevealer
340−
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
348− hard to grab.
349− */
350− handleSize: sideStage.shown ? units.gu(4) : shell.edgeSize
351− closedValue: parent.width + sideStage.handleSizeCollapsed
352− target: sideStage
353− x: parent.width - width
354− width: sideStage.width + handleSize * 0.7
355− height: sideStage.height
356− orientation: Qt.Horizontal
357− }
358−
359− DragHandle {
360− id: stagesDragHandle
361−
362− anchors.top: parent.top
363− anchors.bottom: parent.bottom
364− anchors.right: parent.left
365−
366− width: 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
370−
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
295+ Binding {
296+ target: applicationsDisplayLoader.item
297+ property: "moving"
298+ value: !stages.fullyShown
299+ }
300+ Binding {
301+ target: applicationsDisplayLoader.item
302+ property: "shown"
303+ value: stages.shown
304+ }
305+ Binding {
306+ target: applicationsDisplayLoader.item
307+ property: "dragAreaWidth"
308+ value: shell.edgeSize
374309 }
375310 }
376311 }
@@ -447,26 +382,6 @@ FocusScope {
447382
448383 dragHandleWidth: shell.edgeSize
449384
450− property var previousMainApp: null
451− property var previousSideApp: null
452−
453− function removeApplicationFocus() {
454− greeter.previousMainApp = applicationManager.mainStageFocusedApplication;
455− greeter.previousSideApp = applicationManager.sideStageFocusedApplication;
456− applicationManager.unfocusCurrentApplication();
457− }
458−
459− function restoreApplicationFocus() {
460− if (greeter.previousMainApp) {
461− applicationManager.focusApplication(greeter.previousMainApp);
462− greeter.previousMainApp = null;
463− }
464− if (greeter.previousSideApp) {
465− applicationManager.focusApplication(greeter.previousSideApp);
466− greeter.previousSideApp = null;
467− }
468− }
469−
470385 onShownChanged: {
471386 if (shown) {
472387 lockscreen.reset();
@@ -476,9 +391,6 @@ FocusScope {
476391 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
477392 }
478393 greeter.forceActiveFocus();
479− removeApplicationFocus();
480− } else {
481− restoreApplicationFocus();
482394 }
483395 }
484396
@@ -496,33 +408,16 @@ FocusScope {
496408 }
497409 }
498410
499− Connections {
500− target: applicationManager
501− ignoreUnknownSignals: true
502− // If any app is focused when greeter is open, it's due to a user action
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
510− greeter.hide()
511− }
512− }
513− onSideStageFocusedApplicationChanged: {
514− if (greeter.shown && applicationManager.sideStageFocusedApplication) {
515− greeter.previousMainApp = null // make way for new focused app
516− greeter.previousSideApp = null
517− greeter.hide()
518− }
519− }
411+ Binding {
412+ target: ApplicationManager
413+ property: "suspended"
414+ value: greeter.shown && greeter.showProgress == 1
520415 }
521416 }
522417
523418 InputFilterArea {
524419 anchors.fill: parent
525− blockInput: !applicationFocused || greeter.shown || lockscreen.shown || launcher.shown
420+ blockInput: ApplicationManager.focusedApplicationId.length === 0 || greeter.shown || lockscreen.shown || launcher.shown
526421 || panel.indicators.shown || hud.shown
527422 }
528423
@@ -571,7 +466,9 @@ FocusScope {
571466 available: edgeDemo.panelEnabled
572467 contentEnabled: edgeDemo.panelContentEnabled
573468 }
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
575472 searchVisible: !greeter.shown && !lockscreen.shown && dash.shown && dash.searchable
576473
577474 InputFilterArea {
@@ -597,9 +494,8 @@ FocusScope {
597494 hideAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: hudRevealer.closedValue; easing.type: Easing.Linear }
598495
599496 Connections {
600− target: shell.applicationManager
601− onMainStageFocusedApplicationChanged: hud.hide()
602− onSideStageFocusedApplicationChanged: hud.hide()
497+ target: ApplicationManager
498+ onFocusedApplicationIdChanged: hud.hide()
603499 }
604500 }
605501
@@ -624,7 +520,7 @@ FocusScope {
624520 theHud: hud
625521 anchors.fill: parent
626522 enabled: hud.available
627− applicationIsOnForeground: applicationFocused
523+ applicationIsOnForeground: ApplicationManager.focusedApplicationId
628524 }
629525
630526 InputFilterArea {
@@ -655,9 +551,11 @@ FocusScope {
655551 showHome()
656552 }
657553 onDash: {
658− if (stages.shown) {
659− stages.hide();
660− launcher.hide();
554+ if (stages.shown && !stages.overlayMode) {
555+ if (!stages.locked) {
556+ stages.hide();
557+ launcher.hide();
558+ }
661559 }
662560 }
663561 onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("clickscope", false, true)
@@ -750,14 +648,14 @@ FocusScope {
750648 anchors.bottom: parent.bottom
751649 anchors.left: parent.left
752650 anchors.right: parent.right
753− height: shell.applicationManager ? shell.applicationManager.keyboardHeight : 0
651+ height: ApplicationManager.keyboardVisible ? ApplicationManager.keyboardHeight : 0
754652
755− enabled: shell.applicationManager && shell.applicationManager.keyboardVisible
653+ enabled: ApplicationManager.keyboardVisible
756654 }
757655
758656 Label {
759657 anchors.centerIn: parent
760− visible: applicationManager.fake
658+ visible: ApplicationManager.fake ? ApplicationManager.fake : false
761659 text: "EARLY ALPHA\nNOT READY FOR USE"
762660 color: "lightgrey"
763661 opacity: 0.2