on 2f4159a help sign in
unity8/qml/Shell.qml
846 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 ImageCache 0.1
30import Utils 0.1
31import Powerd 0.1
32import SessionBroadcast 0.1
33import "Greeter"
34import "Launcher"
35import "Panel"
36import "Components"
37import "Notifications"
38import "Stage"
39import "Tutorial"
40import "Wizard"
41import "Components/PanelState"
42import Unity.Notifications 1.0 as NotificationBackend
43import Unity.Session 0.1
44import Unity.DashCommunicator 0.1
45import Unity.Indicators 0.1 as Indicators
46import Cursor 1.1
47import WindowManager 1.0
48import Unity.Debug 0.1 as Debug
51StyledItem {
52 id: shell
54 theme.name: "Ubuntu.Components.Themes.SuruDark"
56 // to be set from outside
57 property alias surfaceManager: topLevelSurfaceList.surfaceManager
58 property int orientationAngle: 0
59 property int orientation
60 property Orientations orientations
61 property real nativeWidth
62 property real nativeHeight
63 property alias panelAreaShowProgress: panel.panelAreaShowProgress
64 property string usageScenario: "phone" // supported values: "phone", "tablet" or "desktop"
65 property string mode: "full-greeter"
66 property alias oskEnabled: inputMethod.enabled
67 function updateFocusedAppOrientation() {
68 stage.updateFocusedAppOrientation();
69 }
70 function updateFocusedAppOrientationAnimated() {
71 stage.updateFocusedAppOrientationAnimated();
72 }
73 property bool hasMouse: false
75 // to be read from outside
76 readonly property int mainAppWindowOrientationAngle: stage.mainAppWindowOrientationAngle
78 readonly property bool orientationChangesEnabled: panel.indicators.fullyClosed
79 && stage.orientationChangesEnabled
80 && (!greeter || !greeter.animating)
82 readonly property bool showingGreeter: greeter && greeter.shown
84 property bool startingUp: true
85 Timer { id: finishStartUpTimer; interval: 500; onTriggered: startingUp = false }
87 property int supportedOrientations: {
88 if (startingUp) {
89 // Ensure we don't rotate during start up
90 return Qt.PrimaryOrientation;
91 } else if (showingGreeter || notifications.topmostIsFullscreen) {
92 return Qt.PrimaryOrientation;
93 } else {
94 return shell.orientations.map(stage.supportedOrientations);
95 }
96 }
98 readonly property var mainApp: stage.mainApp
100 onMainAppChanged: {
101 if (mainApp) {
102 _onMainAppChanged(mainApp.appId);
103 }
104 }
105 Connections {
106 target: ApplicationManager
107 onFocusRequested: {
108 if (shell.mainApp && shell.mainApp.appId === appId) {
109 _onMainAppChanged(appId);
110 }
111 }
112 }
113 function _onMainAppChanged(appId) {
114 if (wizard.active && appId != "" && appId != "unity8-dash") {
115 // If this happens on first boot, we may be in the
116 // wizard while receiving a call. But a call is more
117 // important than the wizard so just bail out of it.
118 wizard.hide();
119 }
121 if (appId === "dialer-app" && callManager.hasCalls && greeter.locked) {
122 // If we are in the middle of a call, make dialer lockedApp and show it.
123 // This can happen if user backs out of dialer back to greeter, then
124 // launches dialer again.
125 greeter.lockedApp = appId;
126 }
127 greeter.notifyAppFocusRequested(appId);
129 panel.indicators.hide();
130 launcher.hide(launcher.ignoreHideIfMouseOverLauncher);
131 }
133 // For autopilot consumption
134 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
136 // Note when greeter is waiting on PAM, so that we can disable edges until
137 // we know which user data to show and whether the session is locked.
138 readonly property bool waitingOnGreeter: greeter && greeter.waiting
140 property real edgeSize: units.gu(settings.edgeDragWidth)
142 WallpaperResolver {
143 id: wallpaperResolver
144 objectName: "wallpaperResolver"
146 readonly property url defaultBackground: "file://" + Constants.defaultWallpaper
147 readonly property bool hasCustomBackground: background != defaultBackground
149 // Use a cached version of the scaled-down wallpaper (as sometimes the
150 // image can be quite big compared to the device size, including for
151 // our default wallpaper). We use a name=wallpaper argument here to
152 // make sure we don't litter our cache with lots of scaled images. We
153 // only need to bother caching one at a time.
154 readonly property url cachedBackground: background.toString().indexOf("file:///") === 0 ? "image://unity8imagecache/" + background + "?name=wallpaper" : background
156 GSettings {
157 id: backgroundSettings
158 schema.id: "org.gnome.desktop.background"
159 }
161 candidates: [
162 AccountsService.backgroundFile,
163 backgroundSettings.pictureUri,
164 defaultBackground
165 ]
166 }
168 readonly property alias greeter: greeterLoader.item
170 function activateApplication(appId) {
171 // Either open the app in our own session, or -- if we're acting as a
172 // greeter -- ask the user's session to open it for us.
173 if (shell.mode === "greeter") {
174 activateURL("application:///" + appId + ".desktop");
175 } else {
176 startApp(appId);
177 }
178 }
180 function activateURL(url) {
181 SessionBroadcast.requestUrlStart(AccountsService.user, url);
182 greeter.notifyUserRequestedApp();
183 panel.indicators.hide();
184 }
186 function startApp(appId) {
187 if (ApplicationManager.findApplication(appId)) {
188 ApplicationManager.requestFocusApplication(appId);
189 } else {
190 ApplicationManager.startApplication(appId);
191 }
192 }
194 function startLockedApp(app) {
195 if (greeter.locked) {
196 greeter.lockedApp = app;
197 }
198 startApp(app); // locked apps are always in our same session
199 }
201 Binding {
202 target: LauncherModel
203 property: "applicationManager"
204 value: ApplicationManager
205 }
207 Component.onCompleted: {
208 finishStartUpTimer.start();
209 }
211 VolumeControl {
212 id: volumeControl
213 }
215 DashCommunicator {
216 id: dash
217 objectName: "dashCommunicator"
218 }
220 PhysicalKeysMapper {
221 id: physicalKeysMapper
222 objectName: "physicalKeysMapper"
224 onPowerKeyLongPressed: dialogs.showPowerDialog();
225 onVolumeDownTriggered: volumeControl.volumeDown();
226 onVolumeUpTriggered: volumeControl.volumeUp();
227 onScreenshotTriggered: itemGrabber.capture(shell);
228 }
230 GlobalShortcut {
231 // dummy shortcut to force creation of GlobalShortcutRegistry before WindowInputFilter
232 }
234 WindowInputFilter {
235 id: inputFilter
236 Keys.onPressed: physicalKeysMapper.onKeyPressed(event, lastInputTimestamp);
237 Keys.onReleased: physicalKeysMapper.onKeyReleased(event, lastInputTimestamp);
238 }
240 WindowInputMonitor {
241 objectName: "windowInputMonitor"
242 onHomeKeyActivated: {
243 // Ignore when greeter is active, to avoid pocket presses
244 if (!greeter.active) {
245 launcher.fadeOut();
246 shell.showHome();
247 }
248 }
249 onTouchBegun: { cursor.opacity = 0; }
250 onTouchEnded: {
251 // move the (hidden) cursor to the last known touch position
252 var mappedCoords = mapFromItem(null, pos.x, pos.y);
253 cursor.x = mappedCoords.x;
254 cursor.y = mappedCoords.y;
255 cursor.mouseNeverMoved = false;
256 }
257 }
259 GSettings {
260 id: settings
261 schema.id: "com.canonical.Unity8"
262 }
264 PanelState {
265 id: panelState
266 objectName: "panelState"
267 }
269 Item {
270 id: stages
271 objectName: "stages"
272 width: parent.width
273 height: parent.height
275 TopLevelWindowModel {
276 id: topLevelSurfaceList
277 objectName: "topLevelSurfaceList"
278 applicationManager: ApplicationManager // it's a singleton
279 }
281 Stage {
282 id: stage
283 objectName: "stage"
284 anchors.fill: parent
285 focus: true
287 dragAreaWidth: shell.edgeSize
288 background: wallpaperResolver.background
290 applicationManager: ApplicationManager
291 topLevelSurfaceList: topLevelSurfaceList
292 inputMethodRect: inputMethod.visibleRect
294 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
295 ? "phone"
296 : shell.usageScenario
298 mode: usageScenario == "phone" ? "staged"
299 : usageScenario == "tablet" ? "stagedWithSideStage"
300 : "windowed"
302 shellOrientation: shell.orientation
303 shellOrientationAngle: shell.orientationAngle
304 orientations: shell.orientations
305 nativeWidth: shell.nativeWidth
306 nativeHeight: shell.nativeHeight
308 interactive: (!greeter || !greeter.shown)
309 && panel.indicators.fullyClosed
310 && !notifications.useModal
312 onInteractiveChanged: { if (interactive) { focus = true; } }
314 leftMargin: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
315 suspended: greeter.shown
316 altTabPressed: physicalKeysMapper.altTabPressed
317 oskEnabled: shell.oskEnabled
318 spreadEnabled: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
319 panelState: panelState
321 onSpreadShownChanged: {
322 panel.indicators.hide();
323 panel.applicationMenus.hide();
324 }
325 Binding {
326 target: applicationsDisplayLoader.item
327 property: "oskEnabled"
328 value: shell.oskEnabled
329 }
330 }
331 }
333 InputMethod {
334 id: inputMethod
335 objectName: "inputMethod"
336 surface: topLevelSurfaceList.inputMethodSurface
337 anchors {
338 fill: parent
339 topMargin: panel.panelHeight
340 leftMargin: launcher.lockedVisible ? launcher.panelWidth : 0
341 }
342 z: notifications.useModal || panel.indicators.shown || wizard.active || tutorial.running || launcher.drawerShown ? overlay.z + 1 : overlay.z - 1
343 }
345 Loader {
346 id: greeterLoader
347 objectName: "greeterLoader"
348 anchors.fill: parent
349 anchors.topMargin: panel.panelHeight
350 sourceComponent: {
351 if (shell.mode != "shell") {
352 if (screenWindow.primary) return integratedGreeter;
353 return secondaryGreeter;
354 }
355 return Qt.createComponent(Qt.resolvedUrl("Greeter/ShimGreeter.qml"));
356 }
357 onLoaded: {
358 item.objectName = "greeter"
359 }
360 }
362 Component {
363 id: integratedGreeter
364 Greeter {
366 enabled: panel.indicators.fullyClosed // hides OSK when panel is open
367 hides: [launcher, panel.indicators, panel.applicationMenus]
368 tabletMode: shell.usageScenario != "phone"
369 forcedUnlock: wizard.active || shell.mode === "full-shell"
370 background: wallpaperResolver.cachedBackground
371 hasCustomBackground: wallpaperResolver.hasCustomBackground
372 allowFingerprint: !dialogs.hasActiveDialog &&
373 !notifications.topmostIsFullscreen &&
374 !panel.indicators.shown
376 // avoid overlapping with Launcher's edge drag area
377 // FIXME: Fix TouchRegistry & friends and remove this workaround
378 // Issue involves launcher's DDA getting disabled on a long
379 // left-edge drag
380 dragHandleLeftMargin: launcher.available ? launcher.dragAreaWidth + 1 : 0
382 onSessionStarted: {
383 launcher.hide();
384 }
386 onTease: {
387 if (!tutorial.running) {
388 launcher.tease();
389 }
390 }
392 onEmergencyCall: startLockedApp("dialer-app")
393 }
394 }
396 Component {
397 id: secondaryGreeter
398 SecondaryGreeter {
399 hides: [launcher, panel.indicators]
400 }
401 }
403 Timer {
404 // See powerConnection for why this is useful
405 id: showGreeterDelayed
406 interval: 1
407 onTriggered: {
408 greeter.forceShow();
409 }
410 }
412 Connections {
413 id: callConnection
414 target: callManager
416 onHasCallsChanged: {
417 if (greeter.locked && callManager.hasCalls && greeter.lockedApp !== "dialer-app") {
418 // We just received an incoming call while locked. The
419 // indicator will have already launched dialer-app for us, but
420 // there is a race between "hasCalls" changing and the dialer
421 // starting up. So in case we lose that race, we'll start/
422 // focus the dialer ourselves here too. Even if the indicator
423 // didn't launch the dialer for some reason (or maybe a call
424 // started via some other means), if an active call is
425 // happening, we want to be in the dialer.
426 startLockedApp("dialer-app")
427 }
428 }
429 }
431 Connections {
432 id: powerConnection
433 target: Powerd
435 onStatusChanged: {
436 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
437 !callManager.hasCalls && !wizard.active) {
438 // We don't want to simply call greeter.showNow() here, because
439 // that will take too long. Qt will delay button event
440 // handling until the greeter is done loading and may think the
441 // user held down the power button the whole time, leading to a
442 // power dialog being shown. Instead, delay showing the
443 // greeter until we've finished handling the event. We could
444 // make the greeter load asynchronously instead, but that
445 // introduces a whole host of timing issues, especially with
446 // its animations. So this is simpler.
447 showGreeterDelayed.start();
448 }
449 }
450 }
452 function showHome() {
453 greeter.notifyUserRequestedApp();
455 if (shell.mode === "greeter") {
456 SessionBroadcast.requestHomeShown(AccountsService.user);
457 } else {
458 var animate = !LightDMService.greeter.active && !stages.shown;
459 dash.setCurrentScope(0, animate, false);
460 ApplicationManager.requestFocusApplication("unity8-dash");
461 }
462 }
464 Item {
465 id: overlay
466 z: 10
468 anchors.fill: parent
470 Panel {
471 id: panel
472 objectName: "panel"
473 anchors.fill: parent //because this draws indicator menus
475 mode: shell.usageScenario == "desktop" ? "windowed" : "staged"
476 minimizedPanelHeight: units.gu(3)
477 expandedPanelHeight: units.gu(7)
478 indicatorMenuWidth: parent.width > units.gu(60) ? units.gu(40) : parent.width
479 applicationMenuWidth: parent.width > units.gu(60) ? units.gu(40) : parent.width
481 indicators {
482 hides: [launcher]
483 available: tutorial.panelEnabled
484 && ((!greeter || !greeter.locked) || AccountsService.enableIndicatorsWhileLocked)
485 && (!greeter || !greeter.hasLockedApp)
486 && !shell.waitingOnGreeter
487 && settings.enableIndicatorMenu
489 model: Indicators.IndicatorsModel {
490 // tablet and phone both use the same profile
491 // FIXME: use just "phone" for greeter too, but first fix
492 // greeter app launching to either load the app inside the
493 // greeter or tell the session to load the app. This will
494 // involve taking the url-dispatcher dbus name and using
495 // SessionBroadcast to tell the session.
496 profile: shell.mode === "greeter" ? "desktop_greeter" : "phone"
497 Component.onCompleted: load();
498 }
499 }
501 applicationMenus {
502 hides: [launcher]
503 available: (!greeter || !greeter.shown)
504 && !shell.waitingOnGreeter
505 }
507 readonly property bool focusedSurfaceIsFullscreen: topLevelSurfaceList.focusedWindow
508 ? topLevelSurfaceList.focusedWindow.state === Mir.FullscreenState
509 : false
510 fullscreenMode: (focusedSurfaceIsFullscreen && !LightDMService.greeter.active && launcher.progress == 0)
511 || greeter.hasLockedApp
512 greeterShown: greeter && greeter.shown
513 panelState: panelState
514 }
516 Launcher {
517 id: launcher
518 objectName: "launcher"
520 anchors.top: parent.top
521 anchors.topMargin: inverted ? 0 : panel.panelHeight
522 anchors.bottom: parent.bottom
523 width: parent.width
524 dragAreaWidth: shell.edgeSize
525 available: tutorial.launcherEnabled
526 && (!greeter.locked || AccountsService.enableLauncherWhileLocked)
527 && !greeter.hasLockedApp
528 && !shell.waitingOnGreeter
529 && settings.enableLauncher
530 inverted: shell.usageScenario !== "desktop"
531 superPressed: physicalKeysMapper.superPressed
532 superTabPressed: physicalKeysMapper.superTabPressed
533 panelWidth: units.gu(settings.launcherWidth)
534 lockedVisible: shell.usageScenario == "desktop" && !settings.autohideLauncher && !panel.fullscreenMode
535 blurSource: greeter.shown ? greeter : stages
536 topPanelHeight: panel.panelHeight
537 drawerEnabled: !greeter.shown
539 onShowDashHome: showHome()
540 onLauncherApplicationSelected: {
541 greeter.notifyUserRequestedApp();
542 shell.activateApplication(appId);
543 }
544 onShownChanged: {
545 if (shown) {
546 panel.indicators.hide()
547 }
548 }
549 onFocusChanged: {
550 if (!focus) {
551 stage.focus = true;
552 }
553 }
555 GlobalShortcut {
556 shortcut: Qt.MetaModifier | Qt.Key_A
557 onTriggered: {
558 launcher.openDrawer(true);
559 }
560 }
561 GlobalShortcut {
562 shortcut: Qt.AltModifier | Qt.Key_F1
563 onTriggered: {
564 launcher.openForKeyboardNavigation();
565 }
566 }
567 GlobalShortcut {
568 shortcut: Qt.MetaModifier | Qt.Key_0
569 onTriggered: {
570 if (LauncherModel.get(9)) {
571 activateApplication(LauncherModel.get(9).appId);
572 }
573 }
574 }
575 Repeater {
576 model: 9
577 GlobalShortcut {
578 shortcut: Qt.MetaModifier | (Qt.Key_1 + index)
579 onTriggered: {
580 if (LauncherModel.get(index)) {
581 activateApplication(LauncherModel.get(index).appId);
582 }
583 }
584 }
585 }
586 }
588 KeyboardShortcutsOverlay {
589 objectName: "shortcutsOverlay"
590 enabled: launcher.shortcutHintsShown && width < parent.width - (launcher.lockedVisible ? launcher.panelWidth : 0) - padding
591 && height < parent.height - padding - panel.panelHeight
592 anchors.centerIn: parent
593 anchors.horizontalCenterOffset: launcher.lockedVisible ? launcher.panelWidth/2 : 0
594 anchors.verticalCenterOffset: panel.panelHeight/2
595 visible: opacity > 0
596 opacity: enabled ? 0.95 : 0
598 Behavior on opacity {
599 UbuntuNumberAnimation {}
600 }
601 }
603 Tutorial {
604 id: tutorial
605 objectName: "tutorial"
606 anchors.fill: parent
608 paused: callManager.hasCalls || !greeter || greeter.active ||
609 wizard.active
610 delayed: dialogs.hasActiveDialog || notifications.hasNotification ||
611 inputMethod.visible ||
612 (launcher.shown && !launcher.lockedVisible) ||
613 panel.indicators.shown || stage.rightEdgeDragProgress > 0
614 usageScenario: shell.usageScenario
615 lastInputTimestamp: inputFilter.lastInputTimestamp
616 launcher: launcher
617 panel: panel
618 stage: stage
619 }
621 Wizard {
622 id: wizard
623 objectName: "wizard"
624 anchors.fill: parent
625 deferred: shell.mode === "greeter"
627 function unlockWhenDoneWithWizard() {
628 if (!active) {
629 Connectivity.unlockAllModems();
630 }
631 }
633 Component.onCompleted: unlockWhenDoneWithWizard()
634 onActiveChanged: unlockWhenDoneWithWizard()
635 }
637 MouseArea { // modal notifications prevent interacting with other contents
638 anchors.fill: parent
639 visible: notifications.useModal
640 enabled: visible
641 }
643 Notifications {
644 id: notifications
646 model: NotificationBackend.Model
647 margin: units.gu(1)
648 hasMouse: shell.hasMouse
649 background: wallpaperResolver.cachedBackground
651 y: topmostIsFullscreen ? 0 : panel.panelHeight
652 height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
654 states: [
655 State {
656 name: "narrow"
657 when: overlay.width <= units.gu(60)
658 AnchorChanges {
659 target: notifications
660 anchors.left: parent.left
661 anchors.right: parent.right
662 }
663 },
664 State {
665 name: "wide"
666 when: overlay.width > units.gu(60)
667 AnchorChanges {
668 target: notifications
669 anchors.left: undefined
670 anchors.right: parent.right
671 }
672 PropertyChanges { target: notifications; width: units.gu(38) }
673 }
674 ]
675 }
676 }
678 Dialogs {
679 id: dialogs
680 objectName: "dialogs"
681 anchors.fill: parent
682 z: overlay.z + 10
683 usageScenario: shell.usageScenario
684 onPowerOffClicked: {
685 shutdownFadeOutRectangle.enabled = true;
686 shutdownFadeOutRectangle.visible = true;
687 shutdownFadeOut.start();
688 }
689 }
691 Connections {
692 target: SessionBroadcast
693 onShowHome: if (shell.mode !== "greeter") showHome()
694 }
696 URLDispatcher {
697 id: urlDispatcher
698 objectName: "urlDispatcher"
699 active: shell.mode === "greeter"
700 onUrlRequested: shell.activateURL(url)
701 }
703 ItemGrabber {
704 id: itemGrabber
705 anchors.fill: parent
706 z: dialogs.z + 10
707 GlobalShortcut { shortcut: Qt.Key_Print; onTriggered: itemGrabber.capture(shell) }
708 Connections {
709 target: stage
710 ignoreUnknownSignals: true
711 onItemSnapshotRequested: itemGrabber.capture(item)
712 }
713 }
715 Timer {
716 id: cursorHidingTimer
717 interval: 3000
718 running: panel.focusedSurfaceIsFullscreen && cursor.opacity > 0
719 onTriggered: cursor.opacity = 0;
720 }
722 Cursor {
723 id: cursor
724 objectName: "Pointer-"+screenWindow.objectName
726 z: itemGrabber.z + 1
727 opacity: 0
728 topBoundaryOffset: panel.panelHeight
729 enabled: shell.hasMouse && screenWindow.active
730 visible: enabled
732 property bool mouseNeverMoved: true
733 Binding {
734 target: cursor; property: "x"; value: shell.width / 2
735 when: cursor.mouseNeverMoved && cursor.visible
736 }
737 Binding {
738 target: cursor; property: "y"; value: shell.height / 2
739 when: cursor.mouseNeverMoved && cursor.visible
740 }
742 confiningItem: stage.itemConfiningMouseCursor
744 height: units.gu(3)
746 readonly property var previewRectangle: stage.previewRectangle.target &&
747 stage.previewRectangle.target.dragging ?
748 stage.previewRectangle : null
750 onPushedLeftBoundary: {
751 if (buttons === Qt.NoButton) {
752 launcher.pushEdge(amount);
753 } else if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeMaximizedLeftRight) {
754 previewRectangle.maximizeLeft(amount);
755 }
756 }
758 onPushedRightBoundary: {
759 if (buttons === Qt.NoButton) {
760 stage.pushRightEdge(amount);
761 } else if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeMaximizedLeftRight) {
762 previewRectangle.maximizeRight(amount);
763 }
764 }
766 onPushedTopBoundary: {
767 if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeMaximized) {
768 previewRectangle.maximize(amount);
769 }
770 }
771 onPushedTopLeftCorner: {
772 if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeCornerMaximized) {
773 previewRectangle.maximizeTopLeft(amount);
774 }
775 }
776 onPushedTopRightCorner: {
777 if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeCornerMaximized) {
778 previewRectangle.maximizeTopRight(amount);
779 }
780 }
781 onPushedBottomLeftCorner: {
782 if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeCornerMaximized) {
783 previewRectangle.maximizeBottomLeft(amount);
784 }
785 }
786 onPushedBottomRightCorner: {
787 if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeCornerMaximized) {
788 previewRectangle.maximizeBottomRight(amount);
789 }
790 }
791 onPushStopped: {
792 if (previewRectangle) {
793 previewRectangle.stop();
794 }
795 }
797 onMouseMoved: {
798 mouseNeverMoved = false;
799 cursor.opacity = 1;
800 }
802 Behavior on opacity { UbuntuNumberAnimation {} }
803 }
805 // non-visual objects
806 KeymapSwitcher {
807 focusedSurface: topLevelSurfaceList.focusedWindow ? topLevelSurfaceList.focusedWindow.surface : null
808 }
809 BrightnessControl {}
811 Rectangle {
812 id: shutdownFadeOutRectangle
813 z: cursor.z + 1
814 enabled: false
815 visible: false
816 color: "black"
817 anchors.fill: parent
818 opacity: 0.0
819 NumberAnimation on opacity {
820 id: shutdownFadeOut
821 from: 0.0
822 to: 1.0
823 onStopped: {
824 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
825 DBusUnitySessionService.shutdown();
826 }
827 }
828 }
829 }
831 Loader {
832 z: shutdownFadeOutRectangle.z + 1
833 active: DebuggingController.logOverlay
835 sourceComponent: Text {
836 width: shell.width
837 height: shell.height
839 text: consoleLog.out
840 Debug.ConsoleLog {
841 id: consoleLog
842 enabled: true
843 }
844 }
845 }