Unity 8
 All Classes Functions
Shell.qml
1 /*
2  * Copyright (C) 2013 Canonical, Ltd.
3  *
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.
7  *
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.
12  *
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/>.
15  */
16 
17 import QtQuick 2.0
18 import QtQuick.Window 2.0
19 import AccountsService 0.1
20 import GSettings 1.0
21 import Unity.Application 0.1
22 import Ubuntu.Components 0.1
23 import Ubuntu.Components.Popups 1.0
24 import Ubuntu.Gestures 0.1
25 import Ubuntu.SystemImage 0.1
26 import Ubuntu.Telephony 0.1 as Telephony
27 import Unity.Connectivity 0.1
28 import Unity.Launcher 0.1
29 import Utils 0.1
30 import LightDM 0.1 as LightDM
31 import Powerd 0.1
32 import SessionBroadcast 0.1
33 import "Greeter"
34 import "Launcher"
35 import "Panel"
36 import "Components"
37 import "Notifications"
38 import "Stages"
39 import Unity.Notifications 1.0 as NotificationBackend
40 import Unity.Session 0.1
41 import Unity.DashCommunicator 0.1
42 
43 Item {
44  id: shell
45 
46  // this is only here to select the width / height of the window if not running fullscreen
47  property bool tablet: false
48  width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
49  height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
50 
51  property real edgeSize: units.gu(2)
52  property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
53  property url background
54  readonly property real panelHeight: panel.panelHeight
55 
56  readonly property bool locked: LightDM.Greeter.active && !LightDM.Greeter.authenticated && !forcedUnlock
57  readonly property bool forcedUnlock: edgeDemo.running
58  onForcedUnlockChanged: if (forcedUnlock) lockscreen.hide()
59 
60  property bool sideStageEnabled: shell.width >= units.gu(100)
61  readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
62 
63  property int maxFailedLogins: -1 // disabled by default for now, will enable via settings in future
64  property int failedLoginsDelayAttempts: 7 // number of failed logins
65  property int failedLoginsDelayMinutes: 5 // minutes of forced waiting
66 
67  property int orientation
68  readonly property int deviceOrientationAngle: Screen.angleBetween(Screen.primaryOrientation, Screen.orientation)
69  onDeviceOrientationAngleChanged: {
70  if (!OrientationLock.enabled) {
71  orientation = Screen.orientation;
72  }
73  }
74  readonly property bool orientationLockEnabled: OrientationLock.enabled
75  onOrientationLockEnabledChanged: {
76  if (orientationLockEnabled) {
77  OrientationLock.savedOrientation = Screen.orientation;
78  } else {
79  orientation = Screen.orientation;
80  }
81  }
82 
83  function activateApplication(appId) {
84  if (ApplicationManager.findApplication(appId)) {
85  ApplicationManager.requestFocusApplication(appId);
86  } else {
87  var execFlags = shell.sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
88  ApplicationManager.startApplication(appId, execFlags);
89  }
90  }
91 
92  function startLockedApp(app) {
93  if (!shell.locked) {
94  console.warn("Called startLockedApp(%1) when not locked, ignoring".arg(app))
95  return
96  }
97  greeter.lockedApp = app
98  shell.activateApplication(app)
99  }
100 
101  Binding {
102  target: LauncherModel
103  property: "applicationManager"
104  value: ApplicationManager
105  }
106 
107  Component.onCompleted: {
108  Theme.name = "Ubuntu.Components.Themes.SuruGradient"
109  if (ApplicationManager.count > 0) {
110  ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
111  }
112  if (orientationLockEnabled) {
113  orientation = OrientationLock.savedOrientation;
114  }
115  }
116 
117  GSettings {
118  id: backgroundSettings
119  schema.id: "org.gnome.desktop.background"
120  }
121  property url gSettingsPicture: backgroundSettings.pictureUri != undefined && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : shell.defaultBackground
122  onGSettingsPictureChanged: {
123  shell.background = gSettingsPicture
124  }
125 
126  VolumeControl {
127  id: volumeControl
128  }
129 
130  DashCommunicator {
131  id: dash
132  objectName: "dashCommunicator"
133  }
134 
135  Binding {
136  target: ApplicationManager
137  property: "forceDashActive"
138  value: launcher.shown || launcher.dashSwipe
139  }
140 
141 
142  WindowKeysFilter {
143  // Handle but do not filter out volume keys
144  Keys.onVolumeUpPressed: { volumeControl.volumeUp(); event.accepted = false; }
145  Keys.onVolumeDownPressed: { volumeControl.volumeDown(); event.accepted = false; }
146 
147  Keys.onPressed: {
148  if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
149  dialogs.onPowerKeyPressed();
150  event.accepted = true;
151  } else {
152  event.accepted = false;
153  }
154  }
155 
156  Keys.onReleased: {
157  if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
158  dialogs.onPowerKeyReleased();
159  event.accepted = true;
160  } else {
161  event.accepted = false;
162  }
163  }
164  }
165 
166  Item {
167  id: stages
168  objectName: "stages"
169  width: parent.width
170  height: parent.height
171  visible: !ApplicationManager.empty
172 
173  Connections {
174  target: ApplicationManager
175  onFocusRequested: {
176  if (greeter.narrowMode) {
177  if (appId === "dialer-app" && callManager.hasCalls) {
178  // If we are in the middle of a call, make dialer lockedApp and show it.
179  // This can happen if user backs out of dialer back to greeter, then
180  // launches dialer again.
181  greeter.lockedApp = appId;
182  }
183  if (greeter.hasLockedApp) {
184  if (appId === greeter.lockedApp) {
185  lockscreen.hide() // show locked app
186  } else {
187  greeter.startUnlock() // show lockscreen if necessary
188  }
189  }
190  greeter.hide();
191  } else {
192  if (LightDM.Greeter.active) {
193  greeter.startUnlock()
194  }
195  }
196  }
197 
198  onFocusedApplicationIdChanged: {
199  if (greeter.hasLockedApp && greeter.lockedApp !== ApplicationManager.focusedApplicationId) {
200  greeter.startUnlock()
201  }
202  panel.indicators.hide();
203  }
204 
205  onApplicationAdded: {
206  if (greeter.shown && appId != "unity8-dash") {
207  greeter.startUnlock()
208  }
209  if (greeter.narrowMode && greeter.hasLockedApp && appId === greeter.lockedApp) {
210  lockscreen.hide() // show locked app
211  }
212  launcher.hide();
213  }
214  }
215 
216  Loader {
217  id: applicationsDisplayLoader
218  objectName: "applicationsDisplayLoader"
219  anchors.fill: parent
220 
221  // When we have a locked app, we only want to show that one app.
222  // FIXME: do this in a less traumatic way. We currently only allow
223  // locked apps in phone mode (see FIXME in Lockscreen component in
224  // this same file). When that changes, we need to do something
225  // nicer here. But this code is currently just to prevent a
226  // theoretical attack where user enters lockedApp mode, then makes
227  // the screen larger (maybe connects to monitor) and tries to enter
228  // tablet mode.
229  property bool tabletMode: shell.sideStageEnabled && !greeter.hasLockedApp
230  source: tabletMode ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml"
231 
232  Binding {
233  target: applicationsDisplayLoader.item
234  property: "objectName"
235  value: "stage"
236  }
237  Binding {
238  target: applicationsDisplayLoader.item
239  property: "dragAreaWidth"
240  value: shell.edgeSize
241  }
242  Binding {
243  target: applicationsDisplayLoader.item
244  property: "maximizedAppTopMargin"
245  // Not just using panel.panelHeight as that changes depending on the focused app.
246  value: panel.indicators.panelHeight
247  }
248  Binding {
249  target: applicationsDisplayLoader.item
250  property: "interactive"
251  value: edgeDemo.stagesEnabled && !greeter.shown && !lockscreen.shown && panel.indicators.fullyClosed && launcher.progress == 0
252  }
253  Binding {
254  target: applicationsDisplayLoader.item
255  property: "spreadEnabled"
256  value: edgeDemo.stagesEnabled && !greeter.hasLockedApp
257  }
258  Binding {
259  target: applicationsDisplayLoader.item
260  property: "inverseProgress"
261  value: launcher.progress
262  }
263  Binding {
264  target: applicationsDisplayLoader.item
265  property: "orientation"
266  value: shell.orientation
267  }
268  }
269  }
270 
271  InputMethod {
272  id: inputMethod
273  objectName: "inputMethod"
274  anchors { fill: parent; topMargin: panel.panelHeight }
275  z: notifications.useModal || panel.indicators.shown ? overlay.z + 1 : overlay.z - 1
276  }
277 
278  Connections {
279  target: SurfaceManager
280  onSurfaceCreated: {
281  if (surface.type == MirSurfaceItem.InputMethod) {
282  inputMethod.surface = surface;
283  }
284  }
285 
286  onSurfaceDestroyed: {
287  if (inputMethod.surface == surface) {
288  inputMethod.surface = null;
289  surface.parent = null;
290  }
291  if (!surface.parent) {
292  // there's no one displaying it. delete it right away
293  surface.release();
294  }
295  }
296  }
297  Connections {
298  target: SessionManager
299  onSessionStopping: {
300  if (!session.parentSession && !session.application) {
301  // nothing is using it. delete it right away
302  session.release();
303  }
304  }
305  }
306 
307  Lockscreen {
308  id: lockscreen
309  objectName: "lockscreen"
310 
311  hides: [launcher, panel.indicators]
312  shown: false
313  enabled: true
314  showAnimation: StandardAnimation { property: "opacity"; to: 1 }
315  hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
316  y: panel.panelHeight
317  visible: required
318  width: parent.width
319  height: parent.height - panel.panelHeight
320  background: shell.background
321  alphaNumeric: AccountsService.passwordDisplayHint === AccountsService.Keyboard
322  minPinLength: 4
323  maxPinLength: 4
324 
325  // FIXME: We *should* show emergency dialer if there is a SIM present,
326  // regardless of whether the side stage is enabled. But right now,
327  // the assumption is that narrow screens are phones which have SIMs
328  // and wider screens are tablets which don't. When we do allow this
329  // on devices with a side stage and a SIM, work should be done to
330  // ensure that the main stage is disabled while the dialer is present
331  // in the side stage. See the FIXME in the stage loader in this file.
332  showEmergencyCallButton: !shell.sideStageEnabled
333 
334  onEntered: LightDM.Greeter.respond(passphrase);
335  onCancel: greeter.show()
336  onEmergencyCall: startLockedApp("dialer-app")
337 
338  onShownChanged: if (shown) greeter.lockedApp = ""
339 
340  function maybeShow() {
341  if (!shell.forcedUnlock) {
342  show()
343  }
344  }
345 
346  Timer {
347  id: forcedDelayTimer
348  interval: 1000 * 60
349  onTriggered: {
350  if (lockscreen.delayMinutes > 0) {
351  lockscreen.delayMinutes -= 1
352  if (lockscreen.delayMinutes > 0) {
353  start() // go again
354  }
355  }
356  }
357  }
358 
359  Component.onCompleted: {
360  if (greeter.narrowMode) {
361  LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
362  }
363  }
364  }
365 
366  Connections {
367  target: LightDM.Greeter
368 
369  onShowGreeter: greeter.show()
370  onHideGreeter: greeter.login()
371 
372  onShowPrompt: {
373  if (greeter.narrowMode) {
374  if (isDefaultPrompt) {
375  if (lockscreen.alphaNumeric) {
376  lockscreen.infoText = i18n.tr("Enter passphrase")
377  lockscreen.errorText = i18n.tr("Sorry, incorrect passphrase") + "\n" +
378  i18n.tr("Please re-enter")
379  } else {
380  lockscreen.infoText = i18n.tr("Enter passcode")
381  lockscreen.errorText = i18n.tr("Sorry, incorrect passcode")
382  }
383  } else {
384  lockscreen.infoText = i18n.tr("Enter %1").arg(text.toLowerCase())
385  lockscreen.errorText = i18n.tr("Sorry, incorrect %1").arg(text.toLowerCase())
386  }
387 
388  lockscreen.maybeShow();
389  }
390  }
391 
392  onPromptlessChanged: {
393  if (greeter.narrowMode) {
394  if (LightDM.Greeter.promptless && LightDM.Greeter.authenticated) {
395  lockscreen.hide()
396  } else {
397  lockscreen.reset();
398  lockscreen.maybeShow();
399  }
400  }
401  }
402 
403  onAuthenticationComplete: {
404  if (LightDM.Greeter.authenticated) {
405  AccountsService.failedLogins = 0
406  }
407  // Else only penalize user for a failed login if they actually were
408  // prompted for a password. We do this below after the promptless
409  // early exit.
410 
411  if (LightDM.Greeter.promptless) {
412  return;
413  }
414 
415  if (LightDM.Greeter.authenticated) {
416  greeter.login();
417  } else {
418  AccountsService.failedLogins++
419  if (maxFailedLogins >= 2) { // require at least a warning
420  if (AccountsService.failedLogins === maxFailedLogins - 1) {
421  var title = lockscreen.alphaNumeric ?
422  i18n.tr("Sorry, incorrect passphrase.") :
423  i18n.tr("Sorry, incorrect passcode.")
424  var text = i18n.tr("This will be your last attempt.") + " " +
425  (lockscreen.alphaNumeric ?
426  i18n.tr("If passphrase is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted.") :
427  i18n.tr("If passcode is entered incorrectly, your phone will conduct a factory reset and all personal data will be deleted."))
428  lockscreen.showInfoPopup(title, text)
429  } else if (AccountsService.failedLogins >= maxFailedLogins) {
430  SystemImage.factoryReset() // Ouch!
431  }
432  }
433  if (failedLoginsDelayAttempts > 0 && AccountsService.failedLogins % failedLoginsDelayAttempts == 0) {
434  lockscreen.delayMinutes = failedLoginsDelayMinutes
435  forcedDelayTimer.start()
436  }
437 
438  lockscreen.clear(true);
439  if (greeter.narrowMode) {
440  LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
441  }
442  }
443  }
444  }
445 
446  Binding {
447  target: LightDM.Greeter
448  property: "active"
449  value: greeter.shown || lockscreen.shown || greeter.hasLockedApp
450  }
451 
452  Rectangle {
453  anchors.fill: parent
454  color: "black"
455  opacity: greeterWrapper.showProgress * 0.8
456  }
457 
458  Item {
459  // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
460  id: greeterWrapper
461  objectName: "greeterWrapper"
462  x: greeter.narrowMode ? launcher.progress : 0
463  y: panel.panelHeight
464  width: parent.width
465  height: parent.height - panel.panelHeight
466 
467  Behavior on x {
468  enabled: !launcher.dashSwipe
469  StandardAnimation {}
470  }
471 
472  property bool fullyShown: showProgress === 1.0
473  onFullyShownChanged: {
474  // Wait until the greeter is completely covering lockscreen before resetting it.
475  if (greeter.narrowMode && fullyShown && !LightDM.Greeter.authenticated) {
476  lockscreen.reset();
477  lockscreen.maybeShow();
478  }
479  }
480 
481  readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
482  onShowProgressChanged: {
483  if (showProgress === 0) {
484  if ((LightDM.Greeter.promptless && LightDM.Greeter.authenticated) || shell.forcedUnlock) {
485  greeter.login()
486  } else if (greeter.narrowMode) {
487  lockscreen.clear(false) // to reset focus if necessary
488  }
489  }
490  }
491 
492  Greeter {
493  id: greeter
494  objectName: "greeter"
495 
496  signal sessionStarted() // helpful for tests
497 
498  property string lockedApp: ""
499  property bool hasLockedApp: lockedApp !== ""
500 
501  available: true
502  hides: [launcher, panel.indicators]
503  shown: true
504  loadContent: required || lockscreen.required // keeps content in memory for quick show()
505 
506  locked: shell.locked
507 
508  defaultBackground: shell.background
509 
510  width: parent.width
511  height: parent.height
512 
513  dragHandleWidth: shell.edgeSize
514 
515  function startUnlock() {
516  if (narrowMode) {
517  if (!LightDM.Greeter.authenticated) {
518  lockscreen.maybeShow()
519  }
520  hide()
521  } else {
522  show()
523  tryToUnlock()
524  }
525  }
526 
527  function login() {
528  enabled = false;
529  if (LightDM.Greeter.startSessionSync()) {
530  sessionStarted();
531  greeter.hide();
532  lockscreen.hide();
533  launcher.hide();
534  }
535  enabled = true;
536  }
537 
538  onShownChanged: {
539  if (shown) {
540  if (greeter.narrowMode) {
541  LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
542  } else {
543  reset()
544  }
545  greeter.lockedApp = "";
546  greeter.forceActiveFocus();
547  }
548  }
549 
550  /* TODO re-enable when the corresponding changes in the service land (LP: #1361074)
551  Component.onCompleted: {
552  Connectivity.unlockAllModems()
553  } */
554 
555  onUnlocked: greeter.hide()
556  onSelected: {
557  // Update launcher items for new user
558  var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
559  AccountsService.user = user;
560  LauncherModel.setUser(user);
561  }
562 
563  onTease: launcher.tease()
564 
565  Binding {
566  target: ApplicationManager
567  property: "suspended"
568  value: greeter.shown && greeterWrapper.showProgress == 1
569  }
570  }
571  }
572 
573  Connections {
574  id: callConnection
575  target: callManager
576 
577  onHasCallsChanged: {
578  if (shell.locked && callManager.hasCalls) {
579  // We just received an incoming call while locked. The
580  // indicator will have already launched dialer-app for us, but
581  // there is a race between "hasCalls" changing and the dialer
582  // starting up. So in case we lose that race, we'll start/
583  // focus the dialer ourselves here too. Even if the indicator
584  // didn't launch the dialer for some reason (or maybe a call
585  // started via some other means), if an active call is
586  // happening, we want to be in the dialer.
587  startLockedApp("dialer-app")
588  }
589  }
590  }
591 
592  Connections {
593  id: powerConnection
594  target: Powerd
595 
596  onStatusChanged: {
597  if (Powerd.status === Powerd.Off && !callManager.hasCalls && !edgeDemo.running) {
598  greeter.showNow()
599  }
600  }
601  }
602 
603  function showHome() {
604  if (edgeDemo.running) {
605  return
606  }
607 
608  if (LightDM.Greeter.active) {
609  greeter.startUnlock()
610  }
611 
612  var animate = !LightDM.Greeter.active && !stages.shown
613  dash.setCurrentScope("clickscope", animate, false)
614  ApplicationManager.requestFocusApplication("unity8-dash")
615  }
616 
617  function showDash() {
618  if (greeter.hasLockedApp || // just in case user gets here
619  (!greeter.narrowMode && shell.locked)) {
620  return
621  }
622 
623  if (greeter.shown) {
624  greeter.hideRight();
625  launcher.fadeOut();
626  }
627 
628  if (ApplicationManager.focusedApplicationId != "unity8-dash") {
629  ApplicationManager.requestFocusApplication("unity8-dash")
630  launcher.fadeOut();
631  }
632  }
633 
634  Item {
635  id: overlay
636  z: 10
637 
638  anchors.fill: parent
639 
640  Panel {
641  id: panel
642  objectName: "panel"
643  anchors.fill: parent //because this draws indicator menus
644  indicators {
645  hides: [launcher]
646  available: edgeDemo.panelEnabled && (!shell.locked || AccountsService.enableIndicatorsWhileLocked) && !greeter.hasLockedApp
647  contentEnabled: edgeDemo.panelContentEnabled
648  width: parent.width > units.gu(60) ? units.gu(40) : parent.width
649  panelHeight: units.gu(3)
650  }
651 
652  property bool topmostApplicationIsFullscreen:
653  ApplicationManager.focusedApplicationId &&
654  ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
655 
656  fullscreenMode: (topmostApplicationIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
657  || greeter.hasLockedApp
658  }
659 
660  Launcher {
661  id: launcher
662  objectName: "launcher"
663 
664  readonly property bool dashSwipe: progress > 0
665 
666  anchors.top: parent.top
667  anchors.bottom: parent.bottom
668  width: parent.width
669  dragAreaWidth: shell.edgeSize
670  available: edgeDemo.launcherEnabled && (!shell.locked || AccountsService.enableLauncherWhileLocked) && !greeter.hasLockedApp
671 
672  onShowDashHome: showHome()
673  onDash: showDash()
674  onDashSwipeChanged: {
675  if (dashSwipe) {
676  dash.setCurrentScope("clickscope", false, true)
677  }
678  }
679  onLauncherApplicationSelected: {
680  if (greeter.hasLockedApp) {
681  greeter.startUnlock()
682  }
683  if (!edgeDemo.running)
684  shell.activateApplication(appId)
685  }
686  onShownChanged: {
687  if (shown) {
688  panel.indicators.hide()
689  }
690  }
691  }
692 
693  Rectangle {
694  id: modalNotificationBackground
695 
696  visible: notifications.useModal && !greeter.shown && (notifications.state == "narrow")
697  color: "#000000"
698  anchors.fill: parent
699  opacity: 0.9
700 
701  MouseArea {
702  anchors.fill: parent
703  }
704  }
705 
706  Notifications {
707  id: notifications
708 
709  model: NotificationBackend.Model
710  margin: units.gu(1)
711 
712  y: panel.panelHeight
713  width: parent.width
714  height: parent.height - panel.panelHeight
715 
716  states: [
717  State {
718  name: "narrow"
719  when: overlay.width <= units.gu(60)
720  AnchorChanges { target: notifications; anchors.left: parent.left }
721  },
722  State {
723  name: "wide"
724  when: overlay.width > units.gu(60)
725  AnchorChanges { target: notifications; anchors.left: undefined }
726  PropertyChanges { target: notifications; width: units.gu(38) }
727  }
728  ]
729  }
730  }
731 
732  Dialogs {
733  id: dialogs
734  anchors.fill: parent
735  z: overlay.z + 10
736  onPowerOffClicked: {
737  shutdownFadeOutRectangle.enabled = true;
738  shutdownFadeOutRectangle.visible = true;
739  shutdownFadeOut.start();
740  }
741  }
742 
743  Label {
744  id: alphaDisclaimerLabel
745  anchors.centerIn: parent
746  visible: ApplicationManager.fake ? ApplicationManager.fake : false
747  z: dialogs.z + 10
748  text: "EARLY ALPHA\nNOT READY FOR USE"
749  color: "lightgrey"
750  opacity: 0.2
751  font.weight: Font.Black
752  horizontalAlignment: Text.AlignHCenter
753  verticalAlignment: Text.AlignVCenter
754  fontSizeMode: Text.Fit
755  rotation: -45
756  scale: Math.min(parent.width, parent.height) / width
757  }
758 
759  EdgeDemo {
760  id: edgeDemo
761  objectName: "edgeDemo"
762  z: alphaDisclaimerLabel.z + 10
763  paused: Powerd.status === Powerd.Off // Saves power
764  greeter: greeter
765  launcher: launcher
766  indicators: panel.indicators
767  stages: stages
768  }
769 
770  Connections {
771  target: SessionBroadcast
772  onShowHome: showHome()
773  }
774 
775  Rectangle {
776  id: shutdownFadeOutRectangle
777  z: edgeDemo.z + 10
778  enabled: false
779  visible: false
780  color: "black"
781  anchors.fill: parent
782  opacity: 0.0
783  NumberAnimation on opacity {
784  id: shutdownFadeOut
785  from: 0.0
786  to: 1.0
787  onStopped: {
788  if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
789  DBusUnitySessionService.Shutdown();
790  }
791  }
792  }
793  }
794 
795 }