on 6946049 help sign in
unity8/qml/Shell.qml
813 lines 29 kB history raw
1/*
2 * Copyright (C) 2013-2016 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.4
18import QtQuick.Window 2.2
19import AccountsService 0.1
20import Unity.Application 0.1
21import Ubuntu.Components 1.3
22import Ubuntu.Components.Popups 1.3
23import Ubuntu.Gestures 0.1
24import Ubuntu.Telephony 0.1 as Telephony
25import Unity.Connectivity 0.1
26import Unity.Launcher 0.1
27import GlobalShortcut 1.0 // has to be before Utils, because of WindowInputFilter
28import GSettings 1.0
29import Utils 0.1
30import Powerd 0.1
31import SessionBroadcast 0.1
32import "Greeter"
33import "Launcher"
34import "Panel"
35import "Components"
36import "Notifications"
37import "Stages"
38import "Tutorial"
39import "Wizard"
40import Unity.Notifications 1.0 as NotificationBackend
41import Unity.Session 0.1
42import Unity.DashCommunicator 0.1
43import Unity.Indicators 0.1 as Indicators
44import Cursor 1.1
45import WindowManager 0.1
48StyledItem {
49 id: shell
51 theme.name: "Ubuntu.Components.Themes.SuruDark"
53 // to be set from outside
54 property int orientationAngle: 0
55 property int orientation
56 property Orientations orientations
57 property real nativeWidth
58 property real nativeHeight
59 property alias indicatorAreaShowProgress: panel.indicatorAreaShowProgress
60 property bool beingResized
61 property string usageScenario: "phone" // supported values: "phone", "tablet" or "desktop"
62 property string mode: "full-greeter"
63 property alias oskEnabled: inputMethod.enabled
64 function updateFocusedAppOrientation() {
65 applicationsDisplayLoader.item.updateFocusedAppOrientation();
66 }
67 function updateFocusedAppOrientationAnimated() {
68 applicationsDisplayLoader.item.updateFocusedAppOrientationAnimated();
69 }
70 property bool hasMouse: false
72 // to be read from outside
73 readonly property int mainAppWindowOrientationAngle:
74 applicationsDisplayLoader.item ? applicationsDisplayLoader.item.mainAppWindowOrientationAngle : 0
76 readonly property bool orientationChangesEnabled: panel.indicators.fullyClosed
77 && (applicationsDisplayLoader.item && applicationsDisplayLoader.item.orientationChangesEnabled)
78 && (!greeter || !greeter.animating)
80 readonly property bool showingGreeter: greeter && greeter.shown
82 property bool startingUp: true
83 Timer { id: finishStartUpTimer; interval: 500; onTriggered: startingUp = false }
85 property int supportedOrientations: {
86 if (startingUp) {
87 // Ensure we don't rotate during start up
88 return Qt.PrimaryOrientation;
89 } else if (greeter && greeter.shown) {
90 return Qt.PrimaryOrientation;
91 } else if (applicationsDisplayLoader.item) {
92 return shell.orientations.map(applicationsDisplayLoader.item.supportedOrientations);
93 } else {
94 // we just don't care
95 return Qt.PortraitOrientation
96 | Qt.LandscapeOrientation
97 | Qt.InvertedPortraitOrientation
98 | Qt.InvertedLandscapeOrientation;
99 }
100 }
102 readonly property var mainApp:
103 applicationsDisplayLoader.item ? applicationsDisplayLoader.item.mainApp : null
104 onMainAppChanged: {
105 if (mainApp) {
106 _onMainAppChanged(mainApp.appId);
107 }
108 }
109 Connections {
110 target: ApplicationManager
111 onFocusRequested: {
112 if (shell.mainApp && shell.mainApp.appId === appId) {
113 _onMainAppChanged(appId);
114 }
115 }
116 }
117 function _onMainAppChanged(appId) {
118 if (wizard.active && appId != "" && appId != "unity8-dash") {
119 // If this happens on first boot, we may be in the
120 // wizard while receiving a call. But a call is more
121 // important than the wizard so just bail out of it.
122 wizard.hide();
123 }
125 if (appId === "dialer-app" && callManager.hasCalls && greeter.locked) {
126 // If we are in the middle of a call, make dialer lockedApp and show it.
127 // This can happen if user backs out of dialer back to greeter, then
128 // launches dialer again.
129 greeter.lockedApp = appId;
130 }
131 greeter.notifyAppFocusRequested(appId);
133 panel.indicators.hide();
134 launcher.hide();
135 }
137 // For autopilot consumption
138 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
140 // Disable everything while greeter is waiting, so that the user can't swipe
141 // the greeter or launcher until we know whether the session is locked.
142 enabled: greeter && !greeter.waiting
144 property real edgeSize: units.gu(settings.edgeDragWidth)
146 WallpaperResolver {
147 id: wallpaperResolver
148 width: shell.width
149 }
151 readonly property alias greeter: greeterLoader.item
153 function activateApplication(appId) {
154 if (ApplicationManager.findApplication(appId)) {
155 ApplicationManager.requestFocusApplication(appId);
156 } else {
157 ApplicationManager.startApplication(appId);
158 }
159 }
161 function startLockedApp(app) {
162 if (greeter.locked) {
163 greeter.lockedApp = app;
164 }
165 shell.activateApplication(app);
166 }
168 Binding {
169 target: LauncherModel
170 property: "applicationManager"
171 value: ApplicationManager
172 }
174 Component.onCompleted: {
175 finishStartUpTimer.start();
176 }
178 LightDM{id: lightDM} // Provide backend access
179 VolumeControl {
180 id: volumeControl
181 indicators: panel.indicators
182 }
184 DashCommunicator {
185 id: dash
186 objectName: "dashCommunicator"
187 }
189 PhysicalKeysMapper {
190 id: physicalKeysMapper
191 objectName: "physicalKeysMapper"
193 onPowerKeyLongPressed: dialogs.showPowerDialog();
194 onVolumeDownTriggered: volumeControl.volumeDown();
195 onVolumeUpTriggered: volumeControl.volumeUp();
196 onScreenshotTriggered: itemGrabber.capture(shell);
197 }
199 GlobalShortcut {
200 // dummy shortcut to force creation of GlobalShortcutRegistry before WindowInputFilter
201 }
203 WindowInputFilter {
204 id: inputFilter
205 Keys.onPressed: physicalKeysMapper.onKeyPressed(event, lastInputTimestamp);
206 Keys.onReleased: physicalKeysMapper.onKeyReleased(event, lastInputTimestamp);
207 }
209 WindowInputMonitor {
210 objectName: "windowInputMonitor"
211 onHomeKeyActivated: {
212 // Ignore when greeter is active, to avoid pocket presses
213 if (!greeter.active) {
214 launcher.fadeOut();
215 shell.showHome();
216 }
217 }
218 onTouchBegun: { cursor.opacity = 0; }
219 onTouchEnded: {
220 // move the (hidden) cursor to the last known touch position
221 var mappedCoords = mapFromItem(null, pos.x, pos.y);
222 cursor.x = mappedCoords.x;
223 cursor.y = mappedCoords.y;
224 cursor.mouseNeverMoved = false;
225 }
226 }
228 GSettings {
229 id: settings
230 schema.id: "com.canonical.Unity8"
231 }
233 Item {
234 id: stages
235 objectName: "stages"
236 width: parent.width
237 height: parent.height
239 TopLevelSurfaceList {
240 id: topLevelSurfaceList
241 objectName: "topLevelSurfaceList"
242 applicationsModel: ApplicationManager
243 }
245 Loader {
246 id: applicationsDisplayLoader
247 objectName: "applicationsDisplayLoader"
248 anchors.fill: parent
250 // When we have a locked app, we only want to show that one app.
251 // FIXME: do this in a less traumatic way. We currently only allow
252 // locked apps in phone mode (see FIXME in Lockscreen component in
253 // this same file). When that changes, we need to do something
254 // nicer here. But this code is currently just to prevent a
255 // theoretical attack where user enters lockedApp mode, then makes
256 // the screen larger (maybe connects to monitor) and tries to enter
257 // tablet mode.
259 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
260 ? "phone"
261 : shell.usageScenario
263 source: "Stages/DesktopStage.qml"
264 readonly property string qmlComponent: {
265 if(shell.mode === "greeter") {
266 return "Stages/ShimStage.qml"
267 } else if (applicationsDisplayLoader.usageScenario === "phone") {
268 return "Stages/PhoneStage.qml";
269 } else if (applicationsDisplayLoader.usageScenario === "tablet") {
270 return "Stages/TabletStage.qml";
271 } else {
272 return "Stages/DesktopStage.qml";
273 }
274 }
276 property bool interactive: (!greeter || !greeter.shown)
277 && panel.indicators.fullyClosed
278 && launcher.progress == 0
279 && !notifications.useModal
281 onInteractiveChanged: { if (interactive) { focus = true; } }
283 Binding {
284 target: applicationsDisplayLoader.item
285 property: "mode"
286 value: applicationsDisplayLoader.usageScenario == "phone" ? "staged"
287 : applicationsDisplayLoader.usageScenario == "tablet" ? "stagedWithSideStage"
288 : "windowed"
289 }
290 Binding {
291 target: applicationsDisplayLoader.item
292 property: "focus"
293 value: true
294 }
295 Binding {
296 target: applicationsDisplayLoader.item
297 property: "objectName"
298 value: "stage"
299 }
300 Binding {
301 target: applicationsDisplayLoader.item
302 property: "dragAreaWidth"
303 value: shell.edgeSize
304 }
305 Binding {
306 target: applicationsDisplayLoader.item
307 property: "maximizedAppTopMargin"
308 // Not just using panel.panelHeight as that changes depending on the focused app.
309 value: panel.indicators.minimizedPanelHeight
310 }
311 Binding {
312 target: applicationsDisplayLoader.item
313 property: "interactive"
314 value: applicationsDisplayLoader.interactive
315 }
316 Binding {
317 target: applicationsDisplayLoader.item
318 property: "spreadEnabled"
319 value: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
320 }
321 Binding {
322 target: applicationsDisplayLoader.item
323 property: "inverseProgress"
324 value: !greeter || greeter.locked || !tutorial.launcherLongSwipeEnabled ? 0 : launcher.progress
325 }
326 Binding {
327 target: applicationsDisplayLoader.item
328 property: "shellOrientationAngle"
329 value: shell.orientationAngle
330 }
331 Binding {
332 target: applicationsDisplayLoader.item
333 property: "shellOrientation"
334 value: shell.orientation
335 }
336 Binding {
337 target: applicationsDisplayLoader.item
338 property: "orientations"
339 value: shell.orientations
340 }
341 Binding {
342 target: applicationsDisplayLoader.item
343 property: "background"
344 value: wallpaperResolver.background
345 }
346 Binding {
347 target: applicationsDisplayLoader.item
348 property: "nativeWidth"
349 value: shell.nativeWidth
350 }
351 Binding {
352 target: applicationsDisplayLoader.item
353 property: "nativeHeight"
354 value: shell.nativeHeight
355 }
356 Binding {
357 target: applicationsDisplayLoader.item
358 property: "beingResized"
359 value: shell.beingResized
360 }
361 Binding {
362 target: applicationsDisplayLoader.item
363 property: "keepDashRunning"
364 value: launcher.shown || launcher.dashSwipe
365 }
366 Binding {
367 target: applicationsDisplayLoader.item
368 property: "suspended"
369 value: greeter.shown
370 }
371 Binding {
372 target: applicationsDisplayLoader.item
373 property: "altTabPressed"
374 value: physicalKeysMapper.altTabPressed
375 }
376 Binding {
377 target: applicationsDisplayLoader.item
378 property: "leftMargin"
379 value: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
380 }
381 Binding {
382 target: applicationsDisplayLoader.item
383 property: "applicationManager"
384 value: ApplicationManager
385 }
386 Binding {
387 target: applicationsDisplayLoader.item
388 property: "topLevelSurfaceList"
389 value: topLevelSurfaceList
390 }
391 Binding {
392 target: applicationsDisplayLoader.item
393 property: "oskEnabled"
394 value: shell.oskEnabled
395 }
396 }
397 }
399 InputMethod {
400 id: inputMethod
401 objectName: "inputMethod"
402 anchors {
403 fill: parent
404 topMargin: panel.panelHeight
405 leftMargin: launcher.lockedVisible ? launcher.panelWidth : 0
406 }
407 z: notifications.useModal || panel.indicators.shown || wizard.active || tutorial.running ? overlay.z + 1 : overlay.z - 1
408 }
410 Loader {
411 id: greeterLoader
412 anchors.fill: parent
413 anchors.topMargin: panel.panelHeight
414 sourceComponent: shell.mode != "shell" ? integratedGreeter :
415 Qt.createComponent(Qt.resolvedUrl("Greeter/ShimGreeter.qml"));
416 onLoaded: {
417 item.objectName = "greeter"
418 }
419 }
421 Component {
422 id: integratedGreeter
423 Greeter {
425 hides: [launcher, panel.indicators]
426 tabletMode: shell.usageScenario != "phone"
427 launcherOffset: launcher.progress
428 forcedUnlock: wizard.active || shell.mode === "full-shell"
429 background: wallpaperResolver.background
430 allowFingerprint: !dialogs.hasActiveDialog &&
431 !notifications.topmostIsFullscreen &&
432 !panel.indicators.shown
434 // avoid overlapping with Launcher's edge drag area
435 // FIXME: Fix TouchRegistry & friends and remove this workaround
436 // Issue involves launcher's DDA getting disabled on a long
437 // left-edge drag
438 dragHandleLeftMargin: launcher.available ? launcher.dragAreaWidth + 1 : 0
440 onSessionStarted: {
441 launcher.hide();
442 }
444 onTease: {
445 if (!tutorial.running) {
446 launcher.tease();
447 }
448 }
450 onEmergencyCall: startLockedApp("dialer-app")
451 }
452 }
454 Timer {
455 // See powerConnection for why this is useful
456 id: showGreeterDelayed
457 interval: 1
458 onTriggered: {
459 greeter.forceShow();
460 }
461 }
463 Connections {
464 id: callConnection
465 target: callManager
467 onHasCallsChanged: {
468 if (greeter.locked && callManager.hasCalls && greeter.lockedApp !== "dialer-app") {
469 // We just received an incoming call while locked. The
470 // indicator will have already launched dialer-app for us, but
471 // there is a race between "hasCalls" changing and the dialer
472 // starting up. So in case we lose that race, we'll start/
473 // focus the dialer ourselves here too. Even if the indicator
474 // didn't launch the dialer for some reason (or maybe a call
475 // started via some other means), if an active call is
476 // happening, we want to be in the dialer.
477 startLockedApp("dialer-app")
478 }
479 }
480 }
482 Connections {
483 id: powerConnection
484 target: Powerd
486 onStatusChanged: {
487 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
488 !callManager.hasCalls && !wizard.active) {
489 // We don't want to simply call greeter.showNow() here, because
490 // that will take too long. Qt will delay button event
491 // handling until the greeter is done loading and may think the
492 // user held down the power button the whole time, leading to a
493 // power dialog being shown. Instead, delay showing the
494 // greeter until we've finished handling the event. We could
495 // make the greeter load asynchronously instead, but that
496 // introduces a whole host of timing issues, especially with
497 // its animations. So this is simpler.
498 showGreeterDelayed.start();
499 }
500 }
501 }
503 function showHome() {
504 greeter.notifyUserRequestedApp("unity8-dash");
506 var animate = !lightDM.greeter.active && !stages.shown
507 dash.setCurrentScope(0, animate, false)
508 ApplicationManager.requestFocusApplication("unity8-dash")
509 }
511 function showDash() {
512 if (greeter.notifyShowingDashFromDrag()) {
513 launcher.fadeOut();
514 }
516 if (!greeter.locked && tutorial.launcherLongSwipeEnabled
517 && ApplicationManager.focusedApplicationId != "unity8-dash") {
518 ApplicationManager.requestFocusApplication("unity8-dash")
519 launcher.fadeOut();
520 }
521 }
523 Item {
524 id: overlay
525 z: 10
527 anchors.fill: parent
529 Panel {
530 id: panel
531 objectName: "panel"
532 anchors.fill: parent //because this draws indicator menus
533 indicators {
534 hides: [launcher]
535 available: tutorial.panelEnabled
536 && ((!greeter || !greeter.locked) || AccountsService.enableIndicatorsWhileLocked)
537 && (!greeter || !greeter.hasLockedApp)
538 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
540 minimizedPanelHeight: units.gu(3)
541 expandedPanelHeight: units.gu(7)
543 indicatorsModel: Indicators.IndicatorsModel {
544 // tablet and phone both use the same profile
545 profile: "phone"
546 Component.onCompleted: load();
547 }
548 }
550 callHint {
551 greeterShown: greeter.shown
552 }
554 readonly property bool focusedSurfaceIsFullscreen: MirFocusController.focusedSurface
555 ? MirFocusController.focusedSurface.state === Mir.FullscreenState
556 : false
557 fullscreenMode: (focusedSurfaceIsFullscreen && !lightDM.greeter.active && launcher.progress == 0)
558 || greeter.hasLockedApp
559 locked: greeter && greeter.active
560 }
562 Launcher {
563 id: launcher
564 objectName: "launcher"
566 /*
567 * Since the Dash doesn't have the same controll over surfaces that the
568 * Shell does, it can't slowly move the scope out of the way, as the shell
569 * does with apps, and the dash is show instantly. This allows for some
570 * leeway and prevents accidental home swipes.
571 */
572 readonly property real offset: shell.focusedApplicationId == "unity8-dash" ? units.gu(12) : 0
573 readonly property bool dashSwipe: progress > offset
575 anchors.top: parent.top
576 anchors.topMargin: inverted ? 0 : panel.panelHeight
577 anchors.bottom: parent.bottom
578 width: parent.width
579 dragAreaWidth: shell.edgeSize
580 available: tutorial.launcherEnabled
581 && (!greeter.locked || AccountsService.enableLauncherWhileLocked)
582 && !greeter.hasLockedApp
583 inverted: shell.usageScenario !== "desktop"
584 superPressed: physicalKeysMapper.superPressed
585 superTabPressed: physicalKeysMapper.superTabPressed
586 panelWidth: units.gu(settings.launcherWidth)
587 lockedVisible: shell.usageScenario == "desktop" && !settings.autohideLauncher && !panel.fullscreenMode
589 onShowDashHome: showHome()
590 onDash: showDash()
591 onDashSwipeChanged: {
592 if (dashSwipe) {
593 dash.setCurrentScope(0, false, true)
594 }
595 }
596 onLauncherApplicationSelected: {
597 greeter.notifyUserRequestedApp(appId);
598 shell.activateApplication(appId);
599 }
600 onShownChanged: {
601 if (shown) {
602 panel.indicators.hide()
603 }
604 }
605 onFocusChanged: {
606 if (!focus) {
607 applicationsDisplayLoader.focus = true;
608 }
609 }
611 GlobalShortcut {
612 shortcut: Qt.AltModifier | Qt.Key_F1
613 onTriggered: {
614 launcher.openForKeyboardNavigation();
615 }
616 }
617 GlobalShortcut {
618 shortcut: Qt.MetaModifier | Qt.Key_0
619 onTriggered: {
620 if (LauncherModel.get(9)) {
621 activateApplication(LauncherModel.get(9).appId);
622 }
623 }
624 }
625 Repeater {
626 model: 9
627 GlobalShortcut {
628 shortcut: Qt.MetaModifier | (Qt.Key_1 + index)
629 onTriggered: {
630 if (LauncherModel.get(index)) {
631 activateApplication(LauncherModel.get(index).appId);
632 }
633 }
634 }
635 }
636 }
638 KeyboardShortcutsOverlay {
639 objectName: "shortcutsOverlay"
640 enabled: launcher.shortcutHintsShown && width < parent.width - (launcher.lockedVisible ? launcher.panelWidth : 0) - padding
641 && height < parent.height - padding - panel.panelHeight
642 anchors.centerIn: parent
643 anchors.horizontalCenterOffset: launcher.lockedVisible ? launcher.panelWidth/2 : 0
644 anchors.verticalCenterOffset: panel.panelHeight/2
645 visible: opacity > 0
646 opacity: enabled ? 0.95 : 0
648 Behavior on opacity {
649 UbuntuNumberAnimation {}
650 }
651 }
653 Tutorial {
654 id: tutorial
655 objectName: "tutorial"
656 anchors.fill: parent
658 paused: callManager.hasCalls || !greeter || greeter.shown ||
659 wizard.active
660 delayed: dialogs.hasActiveDialog || notifications.hasNotification ||
661 inputMethod.state === "shown" ||
662 (launcher.shown && !launcher.lockedVisible) ||
663 panel.indicators.shown || stage.dragProgress > 0
664 usageScenario: shell.usageScenario
665 lastInputTimestamp: inputFilter.lastInputTimestamp
666 launcher: launcher
667 panel: panel
668 stage: applicationsDisplayLoader.item
669 }
671 Wizard {
672 id: wizard
673 objectName: "wizard"
674 anchors.fill: parent
676 function unlockWhenDoneWithWizard() {
677 if (!active) {
678 Connectivity.unlockAllModems();
679 }
680 }
682 Component.onCompleted: unlockWhenDoneWithWizard()
683 onActiveChanged: unlockWhenDoneWithWizard()
684 }
686 MouseArea { // modal notifications prevent interacting with other contents
687 anchors.fill: parent
688 visible: notifications.useModal
689 enabled: visible
690 }
692 Notifications {
693 id: notifications
695 model: NotificationBackend.Model
696 margin: units.gu(1)
697 hasMouse: shell.hasMouse
698 background: wallpaperResolver.background
700 y: topmostIsFullscreen ? 0 : panel.panelHeight
701 height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
703 states: [
704 State {
705 name: "narrow"
706 when: overlay.width <= units.gu(60)
707 AnchorChanges {
708 target: notifications
709 anchors.left: parent.left
710 anchors.right: parent.right
711 }
712 },
713 State {
714 name: "wide"
715 when: overlay.width > units.gu(60)
716 AnchorChanges {
717 target: notifications
718 anchors.left: undefined
719 anchors.right: parent.right
720 }
721 PropertyChanges { target: notifications; width: units.gu(38) }
722 }
723 ]
724 }
725 }
727 Dialogs {
728 id: dialogs
729 objectName: "dialogs"
730 anchors.fill: parent
731 z: overlay.z + 10
732 usageScenario: shell.usageScenario
733 onPowerOffClicked: {
734 shutdownFadeOutRectangle.enabled = true;
735 shutdownFadeOutRectangle.visible = true;
736 shutdownFadeOut.start();
737 }
738 }
740 Connections {
741 target: SessionBroadcast
742 onShowHome: showHome()
743 }
745 ItemGrabber {
746 id: itemGrabber
747 anchors.fill: parent
748 z: dialogs.z + 10
749 GlobalShortcut { shortcut: Qt.Key_Print; onTriggered: itemGrabber.capture(shell) }
750 Connections {
751 target: applicationsDisplayLoader.item
752 ignoreUnknownSignals: true
753 onItemSnapshotRequested: itemGrabber.capture(item)
754 }
755 }
757 Cursor {
758 id: cursor
759 visible: shell.hasMouse
760 z: itemGrabber.z + 1
762 property bool mouseNeverMoved: true
763 Binding {
764 target: cursor; property: "x"; value: shell.width / 2
765 when: cursor.mouseNeverMoved && cursor.visible
766 }
767 Binding {
768 target: cursor; property: "y"; value: shell.height / 2
769 when: cursor.mouseNeverMoved && cursor.visible
770 }
772 onPushedLeftBoundary: {
773 if (buttons === Qt.NoButton) {
774 launcher.pushEdge(amount);
775 }
776 }
778 onPushedRightBoundary: {
779 if (buttons === Qt.NoButton && applicationsDisplayLoader.item
780 && applicationsDisplayLoader.item.pushRightEdge) {
781 applicationsDisplayLoader.item.pushRightEdge(amount);
782 }
783 }
785 onMouseMoved: {
786 mouseNeverMoved = false;
787 cursor.opacity = 1;
788 }
789 }
791 // non-visual object
792 KeymapSwitcher {}
794 Rectangle {
795 id: shutdownFadeOutRectangle
796 z: cursor.z + 1
797 enabled: false
798 visible: false
799 color: "black"
800 anchors.fill: parent
801 opacity: 0.0
802 NumberAnimation on opacity {
803 id: shutdownFadeOut
804 from: 0.0
805 to: 1.0
806 onStopped: {
807 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
808 DBusUnitySessionService.shutdown();
809 }
810 }
811 }
812 }