on a093667 help sign in
unity8/qml/Shell.qml
927 lines 30 kB history raw
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 */
17import QtQuick 2.0
18import AccountsService 0.1
19import GSettings 1.0
20import Unity.Application 0.1
21import Ubuntu.Components 0.1
22import Ubuntu.Components.Popups 0.1
23import Ubuntu.Gestures 0.1
24import Unity.Launcher 0.1
25import LightDM 0.1 as LightDM
26import Powerd 0.1
27import SessionBroadcast 0.1
28import "Dash"
29import "Greeter"
30import "Launcher"
31import "Panel"
32import "Components"
33import "Notifications"
34import Unity.Notifications 1.0 as NotificationBackend
35import Unity.Session 0.1
37FocusScope {
38 id: shell
40 // this is only here to select the width / height of the window if not running fullscreen
41 property bool tablet: false
42 width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
43 height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
45 property real edgeSize: units.gu(2)
46 property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
47 property url background
48 readonly property real panelHeight: panel.panelHeight
50 property bool dashShown: dash.shown
52 property bool sideStageEnabled: shell.width >= units.gu(100)
53 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
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);
61 }
62 } else {
63 var execFlags = shell.sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
64 ApplicationManager.startApplication(appId, execFlags);
65 stages.show(false);
66 }
67 }
69 Binding {
70 target: LauncherModel
71 property: "applicationManager"
72 value: ApplicationManager
73 }
75 Component.onCompleted: {
76 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
77 }
79 GSettings {
80 id: backgroundSettings
81 schema.id: "org.gnome.desktop.background"
82 }
83 property url gSettingsPicture: backgroundSettings.pictureUri != undefined && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : shell.defaultBackground
84 onGSettingsPictureChanged: {
85 shell.background = gSettingsPicture
86 }
88 VolumeControl {
89 id: volumeControl
90 }
92 Keys.onVolumeUpPressed: volumeControl.volumeUp()
93 Keys.onVolumeDownPressed: volumeControl.volumeDown()
95 Item {
96 id: underlayClipper
97 anchors.fill: parent
98 anchors.rightMargin: stages.overlayWidth
99 clip: stages.overlayMode && !stages.painting
101 InputFilterArea {
102 anchors.fill: parent
103 blockInput: parent.clip
104 }
106 Item {
107 id: underlay
108 objectName: "underlay"
109 anchors.fill: parent
110 anchors.rightMargin: -parent.anchors.rightMargin
112 // Whether the underlay is fully covered by opaque UI elements.
113 property bool fullyCovered: panel.indicators.fullyOpened && shell.width <= panel.indicators.width
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
122 Rectangle {
123 anchors.fill: parent
124 color: "black"
125 opacity: dash.disappearingAnimationProgress
126 }
128 Dash {
129 id: dash
130 objectName: "dash"
132 available: !LightDM.Greeter.active
133 hides: [stages, launcher, panel.indicators]
134 shown: disappearingAnimationProgress !== 1.0 && greeterWrapper.showProgress !== 1.0
135 enabled: disappearingAnimationProgress === 0.0 && greeterWrapper.showProgress === 0.0 && edgeDemo.dashEnabled
137 overviewHandleHeight: shell.edgeSize
139 anchors {
140 fill: parent
141 topMargin: panel.panelHeight
142 }
144 contentScale: 1.0 - 0.2 * disappearingAnimationProgress
145 opacity: 1.0 - disappearingAnimationProgress
146 property real disappearingAnimationProgress: {
147 if (stages.overlayMode) {
148 return 0;
149 } else {
150 return stages.showProgress
151 }
152 }
154 // FIXME: only necessary because stages.showProgress is not animated
155 Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }}
156 }
157 }
158 }
160 EdgeDragArea {
161 id: stagesDragHandle
162 direction: Direction.Leftwards
164 anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
165 width: shell.edgeSize
167 property real progress: stages.width
169 onTouchXChanged: {
170 if (status == DirectionalDragArea.Recognized) {
171 if (ApplicationManager.count == 0) {
172 progress = Math.max(stages.width - stagesDragHandle.width + touchX, stages.width * .3)
173 } else {
174 progress = stages.width - stagesDragHandle.width + touchX
175 }
176 }
177 }
179 onDraggingChanged: {
180 if (!dragging) {
181 if (ApplicationManager.count > 0 && progress < stages.width - units.gu(10)) {
182 stages.show(true)
183 }
184 stagesDragHandle.progress = stages.width;
185 }
186 }
187 }
189 Item {
190 id: stages
191 objectName: "stages"
192 width: parent.width
193 height: parent.height
195 x: {
196 if (shown) {
197 if (overlayMode || locked || greeter.fakeActiveForApp !== "") {
198 return 0;
199 }
200 return launcher.progress
201 } else {
202 return stagesDragHandle.progress
203 }
204 }
206 Behavior on x { SmoothedAnimation { velocity: 600; duration: UbuntuAnimation.FastDuration } }
208 property bool shown: false
210 property real showProgress: overlayMode ? 0 : MathUtils.clamp(1 - x / shell.width, 0, 1)
212 property bool fullyShown: x == 0
213 property bool fullyHidden: x == width
215 property bool painting: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.painting : false
216 property bool fullscreen: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.fullscreen : false
217 property bool overlayMode: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.overlayMode : false
218 property int overlayWidth: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.overlayWidth : false
219 property bool locked: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.locked : false
221 function show(focusApp) {
222 shown = true;
223 panel.indicators.hide();
224 edgeDemo.stopDemo();
225 greeter.hide();
226 if (!ApplicationManager.focusedApplicationId && ApplicationManager.count > 0 && focusApp) {
227 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
228 }
229 }
231 function hide() {
232 shown = false;
233 if (ApplicationManager.focusedApplicationId) {
234 ApplicationManager.unfocusCurrentApplication();
235 }
236 }
238 Connections {
239 target: ApplicationManager
241 onFocusRequested: {
242 if (greeter.fakeActiveForApp !== "" && greeter.fakeActiveForApp !== appId) {
243 lockscreen.show();
244 }
245 greeter.hide();
246 stages.show(true);
247 }
249 onFocusedApplicationIdChanged: {
250 if (greeter.fakeActiveForApp !== "" && greeter.fakeActiveForApp !== ApplicationManager.focusedApplicationId) {
251 lockscreen.show();
252 }
253 if (ApplicationManager.focusedApplicationId.length > 0) {
254 stages.show(false);
255 } else {
256 if (!stages.overlayMode) {
257 stages.hide();
258 }
259 }
260 }
262 onApplicationAdded: {
263 stages.show(false);
264 }
266 onApplicationRemoved: {
267 if (ApplicationManager.focusedApplicationId.length == 0) {
268 stages.hide();
269 }
270 }
271 }
273 property bool dialogShown: false
275 Component {
276 id: logoutDialog
277 Dialog {
278 id: dialogueLogout
279 title: "Logout"
280 text: "Are you sure that you want to logout?"
281 Button {
282 text: "Cancel"
283 onClicked: {
284 PopupUtils.close(dialogueLogout);
285 stages.dialogShown = false;
286 }
287 }
288 Button {
289 text: "Yes"
290 onClicked: {
291 DBusUnitySessionService.Logout();
292 PopupUtils.close(dialogueLogout);
293 stages.dialogShown = false;
294 }
295 }
296 }
297 }
299 Component {
300 id: shutdownDialog
301 Dialog {
302 id: dialogueShutdown
303 title: "Shutdown"
304 text: "Are you sure that you want to shutdown?"
305 Button {
306 text: "Cancel"
307 onClicked: {
308 PopupUtils.close(dialogueShutdown);
309 stages.dialogShown = false;
310 }
311 }
312 Button {
313 text: "Yes"
314 onClicked: {
315 dBusUnitySessionServiceConnection.closeAllApps();
316 DBusUnitySessionService.Shutdown();
317 PopupUtils.close(dialogueShutdown);
318 stages.dialogShown = false;
319 }
320 }
321 }
322 }
324 Component {
325 id: rebootDialog
326 Dialog {
327 id: dialogueReboot
328 title: "Reboot"
329 text: "Are you sure that you want to reboot?"
330 Button {
331 text: "Cancel"
332 onClicked: {
333 PopupUtils.close(dialogueReboot)
334 stages.dialogShown = false;
335 }
336 }
337 Button {
338 text: "Yes"
339 onClicked: {
340 dBusUnitySessionServiceConnection.closeAllApps();
341 DBusUnitySessionService.Reboot();
342 PopupUtils.close(dialogueReboot);
343 stages.dialogShown = false;
344 }
345 }
346 }
347 }
349 Component {
350 id: powerDialog
351 Dialog {
352 id: dialoguePower
353 title: "Power"
354 text: i18n.tr("Are you sure you would like to turn power off?")
355 Button {
356 text: i18n.tr("Power off")
357 onClicked: {
358 dBusUnitySessionServiceConnection.closeAllApps();
359 PopupUtils.close(dialoguePower);
360 stages.dialogShown = false;
361 shutdownFadeOutRectangle.enabled = true;
362 shutdownFadeOutRectangle.visible = true;
363 shutdownFadeOut.start();
364 }
365 }
366 Button {
367 text: i18n.tr("Restart")
368 onClicked: {
369 dBusUnitySessionServiceConnection.closeAllApps();
370 DBusUnitySessionService.Reboot();
371 PopupUtils.close(dialoguePower);
372 stages.dialogShown = false;
373 }
374 }
375 Button {
376 text: i18n.tr("Cancel")
377 onClicked: {
378 PopupUtils.close(dialoguePower);
379 stages.dialogShown = false;
380 }
381 }
382 }
383 }
385 function showPowerDialog() {
386 if (!stages.dialogShown) {
387 stages.dialogShown = true;
388 PopupUtils.open(powerDialog);
389 }
390 }
392 Connections {
393 id: dBusUnitySessionServiceConnection
394 objectName: "dBusUnitySessionServiceConnection"
395 target: DBusUnitySessionService
397 function closeAllApps() {
398 while (true) {
399 var app = ApplicationManager.get(0);
400 if (app === null) {
401 break;
402 }
403 ApplicationManager.stopApplication(app.appId);
404 }
405 }
407 onLogoutRequested: {
408 // Display a dialog to ask the user to confirm.
409 if (!stages.dialogShown) {
410 stages.dialogShown = true;
411 PopupUtils.open(logoutDialog);
412 }
413 }
415 onShutdownRequested: {
416 // Display a dialog to ask the user to confirm.
417 if (!stages.dialogShown) {
418 stages.dialogShown = true;
419 PopupUtils.open(shutdownDialog);
420 }
421 }
423 onRebootRequested: {
424 // Display a dialog to ask the user to confirm.
425 if (!stages.dialogShown) {
426 stages.dialogShown = true;
427 PopupUtils.open(rebootDialog);
428 }
429 }
431 onLogoutReady: {
432 closeAllApps();
433 Qt.quit();
434 }
435 }
437 Loader {
438 id: applicationsDisplayLoader
439 anchors.fill: parent
441 source: shell.sideStageEnabled ? "Stages/StageWithSideStage.qml" : "Stages/PhoneStage.qml"
443 Binding {
444 target: applicationsDisplayLoader.item
445 property: "objectName"
446 value: "stage"
447 }
448 Binding {
449 target: applicationsDisplayLoader.item
450 property: "moving"
451 value: !stages.fullyShown
452 }
453 Binding {
454 target: applicationsDisplayLoader.item
455 property: "shown"
456 value: stages.shown
457 }
458 Binding {
459 target: applicationsDisplayLoader.item
460 property: "dragAreaWidth"
461 value: shell.edgeSize
462 }
463 Binding {
464 target: applicationsDisplayLoader.item
465 property: "spreadEnabled"
466 value: greeter.fakeActiveForApp === "" // to support emergency dialer hack
467 }
468 }
469 }
471 Lockscreen {
472 id: lockscreen
473 objectName: "lockscreen"
475 readonly property int backgroundTopMargin: -panel.panelHeight
477 hides: [launcher, panel.indicators]
478 shown: false
479 enabled: true
480 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
481 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
482 y: panel.panelHeight
483 x: required ? 0 : - width
484 width: parent.width
485 height: parent.height - panel.panelHeight
486 background: shell.background
487 minPinLength: 4
488 maxPinLength: 4
490 onEntered: LightDM.Greeter.respond(passphrase);
491 onCancel: greeter.show()
492 onEmergencyCall: {
493 greeter.fakeActiveForApp = "dialer-app"
494 shell.activateApplication("dialer-app")
495 lockscreen.hide()
496 }
498 onShownChanged: if (shown) greeter.fakeActiveForApp = ""
500 Component.onCompleted: {
501 if (LightDM.Users.count == 1) {
502 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
503 }
504 }
505 }
507 Connections {
508 target: LightDM.Greeter
510 onShowGreeter: greeter.show()
512 onShowPrompt: {
513 if (LightDM.Users.count == 1) {
514 // TODO: There's no better way for now to determine if its a PIN or a passphrase.
515 if (text == "PIN") {
516 lockscreen.alphaNumeric = false
517 } else {
518 lockscreen.alphaNumeric = true
519 }
520 lockscreen.placeholderText = i18n.tr("Please enter %1").arg(text);
521 lockscreen.show();
522 }
523 }
525 onAuthenticationComplete: {
526 if (LightDM.Greeter.promptless) {
527 return;
528 }
529 if (LightDM.Greeter.authenticated) {
530 lockscreen.hide();
531 greeter.login();
532 } else {
533 lockscreen.clear(true);
534 }
535 }
536 }
538 Binding {
539 target: LightDM.Greeter
540 property: "active"
541 value: greeter.shown || lockscreen.shown || greeter.fakeActiveForApp != ""
542 }
544 Rectangle {
545 anchors.fill: parent
546 color: "black"
547 opacity: greeterWrapper.showProgress * 0.8
548 }
550 Item {
551 // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
552 id: greeterWrapper
553 x: launcher.progress
554 y: panel.panelHeight
555 width: parent.width
556 height: parent.height - panel.panelHeight
558 Behavior on x {
559 enabled: !launcher.dashSwipe
560 StandardAnimation {}
561 }
563 readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
564 onShowProgressChanged: if (LightDM.Greeter.promptless && showProgress === 0) greeter.login()
566 Greeter {
567 id: greeter
568 objectName: "greeter"
570 signal sessionStarted() // helpful for tests
572 property string fakeActiveForApp: ""
574 available: true
575 hides: [launcher, panel.indicators]
576 shown: true
578 defaultBackground: shell.background
580 width: parent.width
581 height: parent.height
583 dragHandleWidth: shell.edgeSize
585 function login() {
586 enabled = false;
587 LightDM.Greeter.startSessionSync();
588 sessionStarted();
589 greeter.hide();
590 lockscreen.hide();
591 launcher.hide();
592 enabled = true;
593 }
595 onShownChanged: {
596 if (shown) {
597 lockscreen.reset();
598 if (!LightDM.Greeter.promptless) {
599 lockscreen.show();
600 }
601 // If there is only one user, we start authenticating with that one here.
602 // If there are more users, the Greeter will handle that
603 if (LightDM.Users.count == 1) {
604 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
605 }
606 greeter.fakeActiveForApp = "";
607 greeter.forceActiveFocus();
608 }
609 }
611 onUnlocked: greeter.hide()
612 onSelected: {
613 // Update launcher items for new user
614 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
615 AccountsService.user = user;
616 LauncherModel.setUser(user);
617 }
619 onTease: launcher.tease()
621 Binding {
622 target: ApplicationManager
623 property: "suspended"
624 value: greeter.shown && greeterWrapper.showProgress == 1
625 }
626 }
627 }
629 InputFilterArea {
630 anchors.fill: parent
631 blockInput: ApplicationManager.focusedApplicationId.length === 0 || greeter.shown || lockscreen.shown || launcher.shown
632 || panel.indicators.shown
633 }
635 Connections {
636 id: powerConnection
637 target: Powerd
639 onDisplayPowerStateChange: {
640 // We ignore any display-off signals when the proximity sensor
641 // is active. This usually indicates something like a phone call.
642 if (status == Powerd.Off && reason != Powerd.Proximity) {
643 greeter.showNow();
644 }
646 // No reason to chew demo CPU when user isn't watching
647 if (status == Powerd.Off) {
648 edgeDemo.paused = true;
649 } else if (status == Powerd.On) {
650 edgeDemo.paused = false;
651 }
652 }
653 }
655 function showHome() {
656 if (edgeDemo.running) {
657 return
658 }
660 if (LightDM.Greeter.active) {
661 if (!LightDM.Greeter.promptless) {
662 lockscreen.show()
663 }
664 greeter.hide()
665 }
667 var animate = !LightDM.Greeter.active && !stages.shown
668 dash.setCurrentScope("clickscope", animate, false)
669 stages.hide()
670 }
672 function showDash() {
673 if (LightDM.Greeter.active && !LightDM.Greeter.promptless) {
674 return;
675 }
677 if (stages.shown && !stages.overlayMode && !stages.locked) {
678 stages.hide();
679 launcher.fadeOut();
680 } else {
681 launcher.switchToNextState("visible");
682 }
684 if (greeter.shown) {
685 greeter.hideRight();
686 launcher.fadeOut();
687 }
688 }
690 Item {
691 id: overlay
693 anchors.fill: parent
695 Panel {
696 id: panel
697 objectName: "panel"
698 anchors.fill: parent //because this draws indicator menus
699 indicators {
700 hides: [launcher]
701 available: edgeDemo.panelEnabled && greeter.fakeActiveForApp === ""
702 contentEnabled: edgeDemo.panelContentEnabled
703 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
704 panelHeight: units.gu(3)
705 }
706 property string focusedAppId: ApplicationManager.focusedApplicationId
707 property var focusedApplication: ApplicationManager.findApplication(focusedAppId)
708 fullscreenMode: (focusedApplication && stages.fullscreen && !LightDM.Greeter.active) || greeter.fakeActiveForApp !== ""
710 InputFilterArea {
711 anchors {
712 top: parent.top
713 left: parent.left
714 right: parent.right
715 }
716 height: (panel.fullscreenMode) ? shell.edgeSize : panel.panelHeight
717 blockInput: true
718 }
719 }
721 InputFilterArea {
722 blockInput: launcher.shown
723 anchors {
724 top: parent.top
725 bottom: parent.bottom
726 left: parent.left
727 }
728 width: launcher.width
729 }
731 Launcher {
732 id: launcher
733 objectName: "launcher"
735 readonly property bool dashSwipe: progress > 0
737 anchors.top: parent.top
738 anchors.bottom: parent.bottom
739 width: parent.width
740 dragAreaWidth: shell.edgeSize
741 available: edgeDemo.launcherEnabled && greeter.fakeActiveForApp === ""
743 onShowDashHome: showHome()
744 onDash: showDash()
745 onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("clickscope", false, true)
746 onLauncherApplicationSelected: {
747 if (greeter.fakeActiveForApp !== "") {
748 lockscreen.show()
749 }
750 if (!edgeDemo.running)
751 shell.activateApplication(appId)
752 }
753 onShownChanged: {
754 if (shown) {
755 panel.indicators.hide()
756 }
757 }
758 }
760 Rectangle {
761 id: modalNotificationBackground
763 visible: notifications.useModal && !greeter.shown && (notifications.state == "narrow")
764 color: "#000000"
765 anchors.fill: parent
766 opacity: 0.5
768 MouseArea {
769 anchors.fill: parent
770 }
772 InputFilterArea {
773 anchors.fill: parent
774 blockInput: modalNotificationBackground.visible
775 }
776 }
778 Notifications {
779 id: notifications
781 model: NotificationBackend.Model
782 margin: units.gu(1)
784 y: panel.panelHeight
785 width: parent.width
786 height: parent.height - panel.panelHeight
788 states: [
789 State {
790 name: "narrow"
791 when: overlay.width <= units.gu(60)
792 AnchorChanges { target: notifications; anchors.left: parent.left }
793 },
794 State {
795 name: "wide"
796 when: overlay.width > units.gu(60)
797 AnchorChanges { target: notifications; anchors.left: undefined }
798 PropertyChanges { target: notifications; width: units.gu(38) }
799 }
800 ]
802 InputFilterArea {
803 anchors { left: parent.left; right: parent.right }
804 height: parent.contentHeight
805 blockInput: height > 0
806 }
807 }
808 }
810 focus: true
811 onFocusChanged: if (!focus) forceActiveFocus();
813 InputFilterArea {
814 anchors {
815 top: parent.top
816 bottom: parent.bottom
817 left: parent.left
818 }
819 width: shell.edgeSize
820 blockInput: true
821 }
823 InputFilterArea {
824 anchors {
825 top: parent.top
826 bottom: parent.bottom
827 right: parent.right
828 }
829 width: shell.edgeSize
830 blockInput: true
831 }
833 Binding {
834 target: i18n
835 property: "domain"
836 value: "unity8"
837 }
839 OSKController {
840 anchors.topMargin: panel.panelHeight
841 anchors.fill: parent // as needs to know the geometry of the shell
842 }
844 //FIXME: This should be handled in the input stack, keyboard shouldnt propagate
845 MouseArea {
846 anchors.bottom: parent.bottom
847 anchors.left: parent.left
848 anchors.right: parent.right
849 height: ApplicationManager.keyboardVisible ? ApplicationManager.keyboardHeight : 0
851 enabled: ApplicationManager.keyboardVisible
852 }
854 Label {
855 anchors.centerIn: parent
856 visible: ApplicationManager.fake ? ApplicationManager.fake : false
857 text: "EARLY ALPHA\nNOT READY FOR USE"
858 color: "lightgrey"
859 opacity: 0.2
860 font.weight: Font.Black
861 horizontalAlignment: Text.AlignHCenter
862 verticalAlignment: Text.AlignVCenter
863 fontSizeMode: Text.Fit
864 rotation: -45
865 scale: Math.min(parent.width, parent.height) / width
866 }
868 EdgeDemo {
869 id: edgeDemo
870 greeter: greeter
871 launcher: launcher
872 dash: dash
873 indicators: panel.indicators
874 underlay: underlay
875 }
877 Connections {
878 target: SessionBroadcast
879 onShowHome: showHome()
880 }
882 Keys.onPressed: {
883 if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
884 if (!powerKeyTimer.running) {
885 powerKeyTimer.start();
886 }
887 event.accepted = true;
888 }
889 }
891 Keys.onReleased: {
892 if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
893 powerKeyTimer.stop();
894 event.accepted = true;
895 }
896 }
898 Timer {
899 id: powerKeyTimer
900 interval: 2000
901 repeat: false
902 triggeredOnStart: false
904 onTriggered: {
905 stages.showPowerDialog();
906 }
907 }
909 Rectangle {
910 id: shutdownFadeOutRectangle
911 enabled: false
912 visible: false
913 color: "black"
914 anchors.fill: parent
915 opacity: 0.0
916 NumberAnimation on opacity {
917 id: shutdownFadeOut
918 from: 0.0
919 to: 1.0
920 onStopped: {
921 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
922 DBusUnitySessionService.Shutdown();
923 }
924 }
925 }
926 }