on 23f461e help sign in
unity8/qml/Shell.qml
841 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 }
326 }
328 InputMethod {
329 id: inputMethod
330 objectName: "inputMethod"
331 surface: topLevelSurfaceList.inputMethodSurface
332 anchors {
333 fill: parent
334 topMargin: panel.panelHeight
335 leftMargin: launcher.lockedVisible ? launcher.panelWidth : 0
336 }
337 z: notifications.useModal || panel.indicators.shown || wizard.active || tutorial.running || launcher.drawerShown ? overlay.z + 1 : overlay.z - 1
338 }
340 Loader {
341 id: greeterLoader
342 objectName: "greeterLoader"
343 anchors.fill: parent
344 anchors.topMargin: panel.panelHeight
345 sourceComponent: {
346 if (shell.mode != "shell") {
347 if (screenWindow.primary) return integratedGreeter;
348 return secondaryGreeter;
349 }
350 return Qt.createComponent(Qt.resolvedUrl("Greeter/ShimGreeter.qml"));
351 }
352 onLoaded: {
353 item.objectName = "greeter"
354 }
355 }
357 Component {
358 id: integratedGreeter
359 Greeter {
361 enabled: panel.indicators.fullyClosed // hides OSK when panel is open
362 hides: [launcher, panel.indicators, panel.applicationMenus]
363 tabletMode: shell.usageScenario != "phone"
364 forcedUnlock: wizard.active || shell.mode === "full-shell"
365 background: wallpaperResolver.cachedBackground
366 hasCustomBackground: wallpaperResolver.hasCustomBackground
367 allowFingerprint: !dialogs.hasActiveDialog &&
368 !notifications.topmostIsFullscreen &&
369 !panel.indicators.shown
371 // avoid overlapping with Launcher's edge drag area
372 // FIXME: Fix TouchRegistry & friends and remove this workaround
373 // Issue involves launcher's DDA getting disabled on a long
374 // left-edge drag
375 dragHandleLeftMargin: launcher.available ? launcher.dragAreaWidth + 1 : 0
377 onSessionStarted: {
378 launcher.hide();
379 }
381 onTease: {
382 if (!tutorial.running) {
383 launcher.tease();
384 }
385 }
387 onEmergencyCall: startLockedApp("dialer-app")
388 }
389 }
391 Component {
392 id: secondaryGreeter
393 SecondaryGreeter {
394 hides: [launcher, panel.indicators]
395 }
396 }
398 Timer {
399 // See powerConnection for why this is useful
400 id: showGreeterDelayed
401 interval: 1
402 onTriggered: {
403 greeter.forceShow();
404 }
405 }
407 Connections {
408 id: callConnection
409 target: callManager
411 onHasCallsChanged: {
412 if (greeter.locked && callManager.hasCalls && greeter.lockedApp !== "dialer-app") {
413 // We just received an incoming call while locked. The
414 // indicator will have already launched dialer-app for us, but
415 // there is a race between "hasCalls" changing and the dialer
416 // starting up. So in case we lose that race, we'll start/
417 // focus the dialer ourselves here too. Even if the indicator
418 // didn't launch the dialer for some reason (or maybe a call
419 // started via some other means), if an active call is
420 // happening, we want to be in the dialer.
421 startLockedApp("dialer-app")
422 }
423 }
424 }
426 Connections {
427 id: powerConnection
428 target: Powerd
430 onStatusChanged: {
431 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
432 !callManager.hasCalls && !wizard.active) {
433 // We don't want to simply call greeter.showNow() here, because
434 // that will take too long. Qt will delay button event
435 // handling until the greeter is done loading and may think the
436 // user held down the power button the whole time, leading to a
437 // power dialog being shown. Instead, delay showing the
438 // greeter until we've finished handling the event. We could
439 // make the greeter load asynchronously instead, but that
440 // introduces a whole host of timing issues, especially with
441 // its animations. So this is simpler.
442 showGreeterDelayed.start();
443 }
444 }
445 }
447 function showHome() {
448 greeter.notifyUserRequestedApp();
450 if (shell.mode === "greeter") {
451 SessionBroadcast.requestHomeShown(AccountsService.user);
452 } else {
453 var animate = !LightDMService.greeter.active && !stages.shown;
454 dash.setCurrentScope(0, animate, false);
455 ApplicationManager.requestFocusApplication("unity8-dash");
456 }
457 }
459 Item {
460 id: overlay
461 z: 10
463 anchors.fill: parent
465 Panel {
466 id: panel
467 objectName: "panel"
468 anchors.fill: parent //because this draws indicator menus
470 mode: shell.usageScenario == "desktop" ? "windowed" : "staged"
471 minimizedPanelHeight: units.gu(3)
472 expandedPanelHeight: units.gu(7)
473 indicatorMenuWidth: parent.width > units.gu(60) ? units.gu(40) : parent.width
474 applicationMenuWidth: parent.width > units.gu(60) ? units.gu(40) : parent.width
476 indicators {
477 hides: [launcher]
478 available: tutorial.panelEnabled
479 && ((!greeter || !greeter.locked) || AccountsService.enableIndicatorsWhileLocked)
480 && (!greeter || !greeter.hasLockedApp)
481 && !shell.waitingOnGreeter
482 && settings.enableIndicatorMenu
484 model: Indicators.IndicatorsModel {
485 // tablet and phone both use the same profile
486 // FIXME: use just "phone" for greeter too, but first fix
487 // greeter app launching to either load the app inside the
488 // greeter or tell the session to load the app. This will
489 // involve taking the url-dispatcher dbus name and using
490 // SessionBroadcast to tell the session.
491 profile: shell.mode === "greeter" ? "desktop_greeter" : "phone"
492 Component.onCompleted: load();
493 }
494 }
496 applicationMenus {
497 hides: [launcher]
498 available: (!greeter || !greeter.shown)
499 && !shell.waitingOnGreeter
500 }
502 readonly property bool focusedSurfaceIsFullscreen: topLevelSurfaceList.focusedWindow
503 ? topLevelSurfaceList.focusedWindow.state === Mir.FullscreenState
504 : false
505 fullscreenMode: (focusedSurfaceIsFullscreen && !LightDMService.greeter.active && launcher.progress == 0)
506 || greeter.hasLockedApp
507 greeterShown: greeter && greeter.shown
508 panelState: panelState
509 }
511 Launcher {
512 id: launcher
513 objectName: "launcher"
515 anchors.top: parent.top
516 anchors.topMargin: inverted ? 0 : panel.panelHeight
517 anchors.bottom: parent.bottom
518 width: parent.width
519 dragAreaWidth: shell.edgeSize
520 available: tutorial.launcherEnabled
521 && (!greeter.locked || AccountsService.enableLauncherWhileLocked)
522 && !greeter.hasLockedApp
523 && !shell.waitingOnGreeter
524 && settings.enableLauncher
525 inverted: shell.usageScenario !== "desktop"
526 superPressed: physicalKeysMapper.superPressed
527 superTabPressed: physicalKeysMapper.superTabPressed
528 panelWidth: units.gu(settings.launcherWidth)
529 lockedVisible: shell.usageScenario == "desktop" && !settings.autohideLauncher && !panel.fullscreenMode
530 blurSource: greeter.shown ? greeter : stages
531 topPanelHeight: panel.panelHeight
532 drawerEnabled: !greeter.shown
534 onShowDashHome: showHome()
535 onLauncherApplicationSelected: {
536 greeter.notifyUserRequestedApp();
537 shell.activateApplication(appId);
538 }
539 onShownChanged: {
540 if (shown) {
541 panel.indicators.hide()
542 }
543 }
544 onFocusChanged: {
545 if (!focus) {
546 stage.focus = true;
547 }
548 }
550 GlobalShortcut {
551 shortcut: Qt.MetaModifier | Qt.Key_A
552 onTriggered: {
553 launcher.openDrawer(true);
554 }
555 }
556 GlobalShortcut {
557 shortcut: Qt.AltModifier | Qt.Key_F1
558 onTriggered: {
559 launcher.openForKeyboardNavigation();
560 }
561 }
562 GlobalShortcut {
563 shortcut: Qt.MetaModifier | Qt.Key_0
564 onTriggered: {
565 if (LauncherModel.get(9)) {
566 activateApplication(LauncherModel.get(9).appId);
567 }
568 }
569 }
570 Repeater {
571 model: 9
572 GlobalShortcut {
573 shortcut: Qt.MetaModifier | (Qt.Key_1 + index)
574 onTriggered: {
575 if (LauncherModel.get(index)) {
576 activateApplication(LauncherModel.get(index).appId);
577 }
578 }
579 }
580 }
581 }
583 KeyboardShortcutsOverlay {
584 objectName: "shortcutsOverlay"
585 enabled: launcher.shortcutHintsShown && width < parent.width - (launcher.lockedVisible ? launcher.panelWidth : 0) - padding
586 && height < parent.height - padding - panel.panelHeight
587 anchors.centerIn: parent
588 anchors.horizontalCenterOffset: launcher.lockedVisible ? launcher.panelWidth/2 : 0
589 anchors.verticalCenterOffset: panel.panelHeight/2
590 visible: opacity > 0
591 opacity: enabled ? 0.95 : 0
593 Behavior on opacity {
594 UbuntuNumberAnimation {}
595 }
596 }
598 Tutorial {
599 id: tutorial
600 objectName: "tutorial"
601 anchors.fill: parent
603 paused: callManager.hasCalls || !greeter || greeter.active ||
604 wizard.active
605 delayed: dialogs.hasActiveDialog || notifications.hasNotification ||
606 inputMethod.visible ||
607 (launcher.shown && !launcher.lockedVisible) ||
608 panel.indicators.shown || stage.rightEdgeDragProgress > 0
609 usageScenario: shell.usageScenario
610 lastInputTimestamp: inputFilter.lastInputTimestamp
611 launcher: launcher
612 panel: panel
613 stage: stage
614 }
616 Wizard {
617 id: wizard
618 objectName: "wizard"
619 anchors.fill: parent
620 deferred: shell.mode === "greeter"
622 function unlockWhenDoneWithWizard() {
623 if (!active) {
624 Connectivity.unlockAllModems();
625 }
626 }
628 Component.onCompleted: unlockWhenDoneWithWizard()
629 onActiveChanged: unlockWhenDoneWithWizard()
630 }
632 MouseArea { // modal notifications prevent interacting with other contents
633 anchors.fill: parent
634 visible: notifications.useModal
635 enabled: visible
636 }
638 Notifications {
639 id: notifications
641 model: NotificationBackend.Model
642 margin: units.gu(1)
643 hasMouse: shell.hasMouse
644 background: wallpaperResolver.cachedBackground
646 y: topmostIsFullscreen ? 0 : panel.panelHeight
647 height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
649 states: [
650 State {
651 name: "narrow"
652 when: overlay.width <= units.gu(60)
653 AnchorChanges {
654 target: notifications
655 anchors.left: parent.left
656 anchors.right: parent.right
657 }
658 },
659 State {
660 name: "wide"
661 when: overlay.width > units.gu(60)
662 AnchorChanges {
663 target: notifications
664 anchors.left: undefined
665 anchors.right: parent.right
666 }
667 PropertyChanges { target: notifications; width: units.gu(38) }
668 }
669 ]
670 }
671 }
673 Dialogs {
674 id: dialogs
675 objectName: "dialogs"
676 anchors.fill: parent
677 z: overlay.z + 10
678 usageScenario: shell.usageScenario
679 onPowerOffClicked: {
680 shutdownFadeOutRectangle.enabled = true;
681 shutdownFadeOutRectangle.visible = true;
682 shutdownFadeOut.start();
683 }
684 }
686 Connections {
687 target: SessionBroadcast
688 onShowHome: if (shell.mode !== "greeter") showHome()
689 }
691 URLDispatcher {
692 id: urlDispatcher
693 objectName: "urlDispatcher"
694 active: shell.mode === "greeter"
695 onUrlRequested: shell.activateURL(url)
696 }
698 ItemGrabber {
699 id: itemGrabber
700 anchors.fill: parent
701 z: dialogs.z + 10
702 GlobalShortcut { shortcut: Qt.Key_Print; onTriggered: itemGrabber.capture(shell) }
703 Connections {
704 target: stage
705 ignoreUnknownSignals: true
706 onItemSnapshotRequested: itemGrabber.capture(item)
707 }
708 }
710 Timer {
711 id: cursorHidingTimer
712 interval: 3000
713 running: panel.focusedSurfaceIsFullscreen && cursor.opacity > 0
714 onTriggered: cursor.opacity = 0;
715 }
717 Cursor {
718 id: cursor
719 objectName: "Pointer-"+screenWindow.objectName
721 z: itemGrabber.z + 1
722 opacity: 0
723 topBoundaryOffset: panel.panelHeight
724 enabled: shell.hasMouse && screenWindow.active
725 visible: enabled
727 property bool mouseNeverMoved: true
728 Binding {
729 target: cursor; property: "x"; value: shell.width / 2
730 when: cursor.mouseNeverMoved && cursor.visible
731 }
732 Binding {
733 target: cursor; property: "y"; value: shell.height / 2
734 when: cursor.mouseNeverMoved && cursor.visible
735 }
737 confiningItem: stage.itemConfiningMouseCursor
739 height: units.gu(3)
741 readonly property var previewRectangle: stage.previewRectangle.target &&
742 stage.previewRectangle.target.dragging ?
743 stage.previewRectangle : null
745 onPushedLeftBoundary: {
746 if (buttons === Qt.NoButton) {
747 launcher.pushEdge(amount);
748 } else if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeMaximizedLeftRight) {
749 previewRectangle.maximizeLeft(amount);
750 }
751 }
753 onPushedRightBoundary: {
754 if (buttons === Qt.NoButton) {
755 stage.pushRightEdge(amount);
756 } else if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeMaximizedLeftRight) {
757 previewRectangle.maximizeRight(amount);
758 }
759 }
761 onPushedTopBoundary: {
762 if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeMaximized) {
763 previewRectangle.maximize(amount);
764 }
765 }
766 onPushedTopLeftCorner: {
767 if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeCornerMaximized) {
768 previewRectangle.maximizeTopLeft(amount);
769 }
770 }
771 onPushedTopRightCorner: {
772 if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeCornerMaximized) {
773 previewRectangle.maximizeTopRight(amount);
774 }
775 }
776 onPushedBottomLeftCorner: {
777 if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeCornerMaximized) {
778 previewRectangle.maximizeBottomLeft(amount);
779 }
780 }
781 onPushedBottomRightCorner: {
782 if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeCornerMaximized) {
783 previewRectangle.maximizeBottomRight(amount);
784 }
785 }
786 onPushStopped: {
787 if (previewRectangle) {
788 previewRectangle.stop();
789 }
790 }
792 onMouseMoved: {
793 mouseNeverMoved = false;
794 cursor.opacity = 1;
795 }
797 Behavior on opacity { UbuntuNumberAnimation {} }
798 }
800 // non-visual objects
801 KeymapSwitcher {
802 focusedSurface: topLevelSurfaceList.focusedWindow ? topLevelSurfaceList.focusedWindow.surface : null
803 }
804 BrightnessControl {}
806 Rectangle {
807 id: shutdownFadeOutRectangle
808 z: cursor.z + 1
809 enabled: false
810 visible: false
811 color: "black"
812 anchors.fill: parent
813 opacity: 0.0
814 NumberAnimation on opacity {
815 id: shutdownFadeOut
816 from: 0.0
817 to: 1.0
818 onStopped: {
819 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
820 DBusUnitySessionService.shutdown();
821 }
822 }
823 }
824 }
826 Loader {
827 z: shutdownFadeOutRectangle.z + 1
828 active: DebuggingController.logOverlay
830 sourceComponent: Text {
831 width: shell.width
832 height: shell.height
834 text: consoleLog.out
835 Debug.ConsoleLog {
836 id: consoleLog
837 enabled: true
838 }
839 }
840 }