on 69519ed help sign in
unity8/qml/Shell.qml
807 lines 28 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
262 readonly property string qmlComponent: {
263 if(shell.mode === "greeter") {
264 return "Stages/ShimStage.qml"
265 } else if (applicationsDisplayLoader.usageScenario === "phone") {
266 return "Stages/PhoneStage.qml";
267 } else if (applicationsDisplayLoader.usageScenario === "tablet") {
268 return "Stages/TabletStage.qml";
269 } else {
270 return "Stages/DesktopStage.qml";
271 }
272 }
273 // TODO: Ensure the current stage is destroyed before the new one gets loaded.
274 // Currently the new one will get loaded while the old is still hanging
275 // around for a bit, which might lead to conflicts where both stages
276 // change the model simultaneously.
277 onQmlComponentChanged: {
278 if (item) item.stageAboutToBeUnloaded();
279 source = qmlComponent;
280 }
282 property bool interactive: (!greeter || !greeter.shown)
283 && panel.indicators.fullyClosed
284 && launcher.progress == 0
285 && !notifications.useModal
287 onInteractiveChanged: { if (interactive) { focus = true; } }
289 Binding {
290 target: applicationsDisplayLoader.item
291 property: "focus"
292 value: true
293 }
294 Binding {
295 target: applicationsDisplayLoader.item
296 property: "objectName"
297 value: "stage"
298 }
299 Binding {
300 target: applicationsDisplayLoader.item
301 property: "dragAreaWidth"
302 value: shell.edgeSize
303 }
304 Binding {
305 target: applicationsDisplayLoader.item
306 property: "maximizedAppTopMargin"
307 // Not just using panel.panelHeight as that changes depending on the focused app.
308 value: panel.indicators.minimizedPanelHeight
309 }
310 Binding {
311 target: applicationsDisplayLoader.item
312 property: "interactive"
313 value: applicationsDisplayLoader.interactive
314 }
315 Binding {
316 target: applicationsDisplayLoader.item
317 property: "spreadEnabled"
318 value: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
319 }
320 Binding {
321 target: applicationsDisplayLoader.item
322 property: "inverseProgress"
323 value: !greeter || greeter.locked || !tutorial.launcherLongSwipeEnabled ? 0 : launcher.progress
324 }
325 Binding {
326 target: applicationsDisplayLoader.item
327 property: "shellOrientationAngle"
328 value: shell.orientationAngle
329 }
330 Binding {
331 target: applicationsDisplayLoader.item
332 property: "shellOrientation"
333 value: shell.orientation
334 }
335 Binding {
336 target: applicationsDisplayLoader.item
337 property: "orientations"
338 value: shell.orientations
339 }
340 Binding {
341 target: applicationsDisplayLoader.item
342 property: "background"
343 value: wallpaperResolver.background
344 }
345 Binding {
346 target: applicationsDisplayLoader.item
347 property: "nativeWidth"
348 value: shell.nativeWidth
349 }
350 Binding {
351 target: applicationsDisplayLoader.item
352 property: "nativeHeight"
353 value: shell.nativeHeight
354 }
355 Binding {
356 target: applicationsDisplayLoader.item
357 property: "beingResized"
358 value: shell.beingResized
359 }
360 Binding {
361 target: applicationsDisplayLoader.item
362 property: "keepDashRunning"
363 value: launcher.shown || launcher.dashSwipe
364 }
365 Binding {
366 target: applicationsDisplayLoader.item
367 property: "suspended"
368 value: greeter.shown
369 }
370 Binding {
371 target: applicationsDisplayLoader.item
372 property: "altTabPressed"
373 value: physicalKeysMapper.altTabPressed
374 }
375 Binding {
376 target: applicationsDisplayLoader.item
377 property: "leftMargin"
378 value: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
379 }
380 Binding {
381 target: applicationsDisplayLoader.item
382 property: "applicationManager"
383 value: ApplicationManager
384 }
385 Binding {
386 target: applicationsDisplayLoader.item
387 property: "topLevelSurfaceList"
388 value: topLevelSurfaceList
389 }
390 }
391 }
393 InputMethod {
394 id: inputMethod
395 objectName: "inputMethod"
396 anchors {
397 fill: parent
398 topMargin: panel.panelHeight
399 leftMargin: launcher.lockedVisible ? launcher.panelWidth : 0
400 }
401 z: notifications.useModal || panel.indicators.shown || wizard.active || tutorial.running ? overlay.z + 1 : overlay.z - 1
402 }
404 Loader {
405 id: greeterLoader
406 anchors.fill: parent
407 anchors.topMargin: panel.panelHeight
408 sourceComponent: shell.mode != "shell" ? integratedGreeter :
409 Qt.createComponent(Qt.resolvedUrl("Greeter/ShimGreeter.qml"));
410 onLoaded: {
411 item.objectName = "greeter"
412 }
413 }
415 Component {
416 id: integratedGreeter
417 Greeter {
419 hides: [launcher, panel.indicators]
420 tabletMode: shell.usageScenario != "phone"
421 launcherOffset: launcher.progress
422 forcedUnlock: wizard.active || shell.mode === "full-shell"
423 background: wallpaperResolver.background
424 allowFingerprint: !dialogs.hasActiveDialog &&
425 !notifications.topmostIsFullscreen &&
426 !panel.indicators.shown
428 // avoid overlapping with Launcher's edge drag area
429 // FIXME: Fix TouchRegistry & friends and remove this workaround
430 // Issue involves launcher's DDA getting disabled on a long
431 // left-edge drag
432 dragHandleLeftMargin: launcher.available ? launcher.dragAreaWidth + 1 : 0
434 onSessionStarted: {
435 launcher.hide();
436 }
438 onTease: {
439 if (!tutorial.running) {
440 launcher.tease();
441 }
442 }
444 onEmergencyCall: startLockedApp("dialer-app")
445 }
446 }
448 Timer {
449 // See powerConnection for why this is useful
450 id: showGreeterDelayed
451 interval: 1
452 onTriggered: {
453 greeter.forceShow();
454 }
455 }
457 Connections {
458 id: callConnection
459 target: callManager
461 onHasCallsChanged: {
462 if (greeter.locked && callManager.hasCalls && greeter.lockedApp !== "dialer-app") {
463 // We just received an incoming call while locked. The
464 // indicator will have already launched dialer-app for us, but
465 // there is a race between "hasCalls" changing and the dialer
466 // starting up. So in case we lose that race, we'll start/
467 // focus the dialer ourselves here too. Even if the indicator
468 // didn't launch the dialer for some reason (or maybe a call
469 // started via some other means), if an active call is
470 // happening, we want to be in the dialer.
471 startLockedApp("dialer-app")
472 }
473 }
474 }
476 Connections {
477 id: powerConnection
478 target: Powerd
480 onStatusChanged: {
481 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
482 !callManager.hasCalls && !wizard.active) {
483 // We don't want to simply call greeter.showNow() here, because
484 // that will take too long. Qt will delay button event
485 // handling until the greeter is done loading and may think the
486 // user held down the power button the whole time, leading to a
487 // power dialog being shown. Instead, delay showing the
488 // greeter until we've finished handling the event. We could
489 // make the greeter load asynchronously instead, but that
490 // introduces a whole host of timing issues, especially with
491 // its animations. So this is simpler.
492 showGreeterDelayed.start();
493 }
494 }
495 }
497 function showHome() {
498 greeter.notifyUserRequestedApp("unity8-dash");
500 var animate = !lightDM.greeter.active && !stages.shown
501 dash.setCurrentScope(0, animate, false)
502 ApplicationManager.requestFocusApplication("unity8-dash")
503 }
505 function showDash() {
506 if (greeter.notifyShowingDashFromDrag()) {
507 launcher.fadeOut();
508 }
510 if (!greeter.locked && tutorial.launcherLongSwipeEnabled
511 && ApplicationManager.focusedApplicationId != "unity8-dash") {
512 ApplicationManager.requestFocusApplication("unity8-dash")
513 launcher.fadeOut();
514 }
515 }
517 Item {
518 id: overlay
519 z: 10
521 anchors.fill: parent
523 Panel {
524 id: panel
525 objectName: "panel"
526 anchors.fill: parent //because this draws indicator menus
527 indicators {
528 hides: [launcher]
529 available: tutorial.panelEnabled
530 && ((!greeter || !greeter.locked) || AccountsService.enableIndicatorsWhileLocked)
531 && (!greeter || !greeter.hasLockedApp)
532 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
534 minimizedPanelHeight: units.gu(3)
535 expandedPanelHeight: units.gu(7)
537 indicatorsModel: Indicators.IndicatorsModel {
538 // tablet and phone both use the same profile
539 profile: "phone"
540 Component.onCompleted: load();
541 }
542 }
544 callHint {
545 greeterShown: greeter.shown
546 }
548 readonly property bool focusedSurfaceIsFullscreen: MirFocusController.focusedSurface
549 ? MirFocusController.focusedSurface.state === Mir.FullscreenState
550 : false
551 fullscreenMode: (focusedSurfaceIsFullscreen && !lightDM.greeter.active && launcher.progress == 0)
552 || greeter.hasLockedApp
553 locked: greeter && greeter.active
554 }
556 Launcher {
557 id: launcher
558 objectName: "launcher"
560 /*
561 * Since the Dash doesn't have the same controll over surfaces that the
562 * Shell does, it can't slowly move the scope out of the way, as the shell
563 * does with apps, and the dash is show instantly. This allows for some
564 * leeway and prevents accidental home swipes.
565 */
566 readonly property real offset: shell.focusedApplicationId == "unity8-dash" ? units.gu(12) : 0
567 readonly property bool dashSwipe: progress > offset
569 anchors.top: parent.top
570 anchors.topMargin: inverted ? 0 : panel.panelHeight
571 anchors.bottom: parent.bottom
572 width: parent.width
573 dragAreaWidth: shell.edgeSize
574 available: tutorial.launcherEnabled
575 && (!greeter.locked || AccountsService.enableLauncherWhileLocked)
576 && !greeter.hasLockedApp
577 inverted: shell.usageScenario !== "desktop"
578 superPressed: physicalKeysMapper.superPressed
579 superTabPressed: physicalKeysMapper.superTabPressed
580 panelWidth: units.gu(settings.launcherWidth)
581 lockedVisible: shell.usageScenario == "desktop" && !settings.autohideLauncher && !panel.fullscreenMode
583 onShowDashHome: showHome()
584 onDash: showDash()
585 onDashSwipeChanged: {
586 if (dashSwipe) {
587 dash.setCurrentScope(0, false, true)
588 }
589 }
590 onLauncherApplicationSelected: {
591 greeter.notifyUserRequestedApp(appId);
592 shell.activateApplication(appId);
593 }
594 onShownChanged: {
595 if (shown) {
596 panel.indicators.hide()
597 }
598 }
599 onFocusChanged: {
600 if (!focus) {
601 applicationsDisplayLoader.focus = true;
602 }
603 }
605 GlobalShortcut {
606 shortcut: Qt.AltModifier | Qt.Key_F1
607 onTriggered: {
608 launcher.openForKeyboardNavigation();
609 }
610 }
611 GlobalShortcut {
612 shortcut: Qt.MetaModifier | Qt.Key_0
613 onTriggered: {
614 if (LauncherModel.get(9)) {
615 activateApplication(LauncherModel.get(9).appId);
616 }
617 }
618 }
619 Repeater {
620 model: 9
621 GlobalShortcut {
622 shortcut: Qt.MetaModifier | (Qt.Key_1 + index)
623 onTriggered: {
624 if (LauncherModel.get(index)) {
625 activateApplication(LauncherModel.get(index).appId);
626 }
627 }
628 }
629 }
630 }
632 KeyboardShortcutsOverlay {
633 objectName: "shortcutsOverlay"
634 enabled: launcher.shortcutHintsShown && width < parent.width - (launcher.lockedVisible ? launcher.panelWidth : 0) - padding
635 && height < parent.height - padding - panel.panelHeight
636 anchors.centerIn: parent
637 anchors.horizontalCenterOffset: launcher.lockedVisible ? launcher.panelWidth/2 : 0
638 anchors.verticalCenterOffset: panel.panelHeight/2
639 visible: opacity > 0
640 opacity: enabled ? 0.95 : 0
642 Behavior on opacity {
643 UbuntuNumberAnimation {}
644 }
645 }
647 Tutorial {
648 id: tutorial
649 objectName: "tutorial"
650 anchors.fill: parent
652 paused: callManager.hasCalls || !greeter || greeter.shown ||
653 wizard.active
654 delayed: dialogs.hasActiveDialog || notifications.hasNotification ||
655 inputMethod.state === "shown" ||
656 (launcher.shown && !launcher.lockedVisible) ||
657 panel.indicators.shown || stage.dragProgress > 0
658 usageScenario: shell.usageScenario
659 lastInputTimestamp: inputFilter.lastInputTimestamp
660 launcher: launcher
661 panel: panel
662 stage: applicationsDisplayLoader.item
663 }
665 Wizard {
666 id: wizard
667 objectName: "wizard"
668 anchors.fill: parent
670 function unlockWhenDoneWithWizard() {
671 if (!active) {
672 Connectivity.unlockAllModems();
673 }
674 }
676 Component.onCompleted: unlockWhenDoneWithWizard()
677 onActiveChanged: unlockWhenDoneWithWizard()
678 }
680 MouseArea { // modal notifications prevent interacting with other contents
681 anchors.fill: parent
682 visible: notifications.useModal
683 enabled: visible
684 }
686 Notifications {
687 id: notifications
689 model: NotificationBackend.Model
690 margin: units.gu(1)
691 hasMouse: shell.hasMouse
692 background: wallpaperResolver.background
694 y: topmostIsFullscreen ? 0 : panel.panelHeight
695 height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
697 states: [
698 State {
699 name: "narrow"
700 when: overlay.width <= units.gu(60)
701 AnchorChanges {
702 target: notifications
703 anchors.left: parent.left
704 anchors.right: parent.right
705 }
706 },
707 State {
708 name: "wide"
709 when: overlay.width > units.gu(60)
710 AnchorChanges {
711 target: notifications
712 anchors.left: undefined
713 anchors.right: parent.right
714 }
715 PropertyChanges { target: notifications; width: units.gu(38) }
716 }
717 ]
718 }
719 }
721 Dialogs {
722 id: dialogs
723 objectName: "dialogs"
724 anchors.fill: parent
725 z: overlay.z + 10
726 usageScenario: shell.usageScenario
727 onPowerOffClicked: {
728 shutdownFadeOutRectangle.enabled = true;
729 shutdownFadeOutRectangle.visible = true;
730 shutdownFadeOut.start();
731 }
732 }
734 Connections {
735 target: SessionBroadcast
736 onShowHome: showHome()
737 }
739 ItemGrabber {
740 id: itemGrabber
741 anchors.fill: parent
742 z: dialogs.z + 10
743 GlobalShortcut { shortcut: Qt.Key_Print; onTriggered: itemGrabber.capture(shell) }
744 Connections {
745 target: applicationsDisplayLoader.item
746 ignoreUnknownSignals: true
747 onItemSnapshotRequested: itemGrabber.capture(item)
748 }
749 }
751 Cursor {
752 id: cursor
753 visible: shell.hasMouse
754 z: itemGrabber.z + 1
756 property bool mouseNeverMoved: true
757 Binding {
758 target: cursor; property: "x"; value: shell.width / 2
759 when: cursor.mouseNeverMoved && cursor.visible
760 }
761 Binding {
762 target: cursor; property: "y"; value: shell.height / 2
763 when: cursor.mouseNeverMoved && cursor.visible
764 }
766 onPushedLeftBoundary: {
767 if (buttons === Qt.NoButton) {
768 launcher.pushEdge(amount);
769 }
770 }
772 onPushedRightBoundary: {
773 if (buttons === Qt.NoButton && applicationsDisplayLoader.item
774 && applicationsDisplayLoader.item.pushRightEdge) {
775 applicationsDisplayLoader.item.pushRightEdge(amount);
776 }
777 }
779 onMouseMoved: {
780 mouseNeverMoved = false;
781 cursor.opacity = 1;
782 }
783 }
785 // non-visual object
786 KeymapSwitcher {}
788 Rectangle {
789 id: shutdownFadeOutRectangle
790 z: cursor.z + 1
791 enabled: false
792 visible: false
793 color: "black"
794 anchors.fill: parent
795 opacity: 0.0
796 NumberAnimation on opacity {
797 id: shutdownFadeOut
798 from: 0.0
799 to: 1.0
800 onStopped: {
801 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
802 DBusUnitySessionService.shutdown();
803 }
804 }
805 }
806 }