on dc16f42 help sign in
unity8/qml/Shell.qml
819 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 Unity.Notifications 1.0 as NotificationBackend
42import Unity.Session 0.1
43import Unity.DashCommunicator 0.1
44import Unity.Indicators 0.1 as Indicators
45import Cursor 1.1
46import WindowManager 1.0
49StyledItem {
50 id: shell
52 theme.name: "Ubuntu.Components.Themes.SuruDark"
54 // to be set from outside
55 property int orientationAngle: 0
56 property int orientation
57 property Orientations orientations
58 property real nativeWidth
59 property real nativeHeight
60 property alias indicatorAreaShowProgress: panel.indicatorAreaShowProgress
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 stage.updateFocusedAppOrientation();
66 }
67 function updateFocusedAppOrientationAnimated() {
68 stage.updateFocusedAppOrientationAnimated();
69 }
70 property bool hasMouse: false
72 // to be read from outside
73 readonly property int mainAppWindowOrientationAngle: stage.mainAppWindowOrientationAngle
75 readonly property bool orientationChangesEnabled: panel.indicators.fullyClosed
76 && stage.orientationChangesEnabled
77 && (!greeter || !greeter.animating)
79 readonly property bool showingGreeter: greeter && greeter.shown
81 property bool startingUp: true
82 Timer { id: finishStartUpTimer; interval: 500; onTriggered: startingUp = false }
84 property int supportedOrientations: {
85 if (startingUp) {
86 // Ensure we don't rotate during start up
87 return Qt.PrimaryOrientation;
88 } else if (showingGreeter || notifications.topmostIsFullscreen) {
89 return Qt.PrimaryOrientation;
90 } else {
91 return shell.orientations.map(stage.supportedOrientations);
92 }
93 }
95 readonly property var mainApp: stage.mainApp
97 onMainAppChanged: {
98 if (mainApp) {
99 _onMainAppChanged(mainApp.appId);
100 }
101 }
102 Connections {
103 target: ApplicationManager
104 onFocusRequested: {
105 if (shell.mainApp && shell.mainApp.appId === appId) {
106 _onMainAppChanged(appId);
107 }
108 }
109 }
110 function _onMainAppChanged(appId) {
111 if (wizard.active && appId != "" && appId != "unity8-dash") {
112 // If this happens on first boot, we may be in the
113 // wizard while receiving a call. But a call is more
114 // important than the wizard so just bail out of it.
115 wizard.hide();
116 }
118 if (appId === "dialer-app" && callManager.hasCalls && greeter.locked) {
119 // If we are in the middle of a call, make dialer lockedApp and show it.
120 // This can happen if user backs out of dialer back to greeter, then
121 // launches dialer again.
122 greeter.lockedApp = appId;
123 }
124 greeter.notifyAppFocusRequested(appId);
126 panel.indicators.hide();
127 launcher.hide();
128 }
130 // For autopilot consumption
131 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
133 // Note when greeter is waiting on PAM, so that we can disable edges until
134 // we know which user data to show and whether the session is locked.
135 readonly property bool waitingOnGreeter: greeter && greeter.waiting
137 property real edgeSize: units.gu(settings.edgeDragWidth)
139 WallpaperResolver {
140 id: wallpaperResolver
141 objectName: "wallpaperResolver"
143 readonly property url defaultBackground: "file://" + Constants.defaultWallpaper
144 readonly property bool hasCustomBackground: background != defaultBackground
146 // Use a cached version of the scaled-down wallpaper (as sometimes the
147 // image can be quite big compared to the device size, including for
148 // our default wallpaper). We use a name=wallpaper argument here to
149 // make sure we don't litter our cache with lots of scaled images. We
150 // only need to bother caching one at a time.
151 readonly property url cachedBackground: background.toString().indexOf("file:///") === 0 ? "image://unity8imagecache/" + background + "?name=wallpaper" : background
153 GSettings {
154 id: backgroundSettings
155 schema.id: "org.gnome.desktop.background"
156 }
158 candidates: [
159 AccountsService.backgroundFile,
160 backgroundSettings.pictureUri,
161 defaultBackground
162 ]
163 }
165 readonly property alias greeter: greeterLoader.item
167 function activateApplication(appId) {
168 // Either open the app in our own session, or -- if we're acting as a
169 // greeter -- ask the user's session to open it for us.
170 if (shell.mode === "greeter") {
171 activateURL("application:///" + appId + ".desktop");
172 } else {
173 startApp(appId);
174 }
175 }
177 function activateURL(url) {
178 SessionBroadcast.requestUrlStart(AccountsService.user, url);
179 greeter.notifyUserRequestedApp();
180 panel.indicators.hide();
181 }
183 function startApp(appId) {
184 if (ApplicationManager.findApplication(appId)) {
185 ApplicationManager.requestFocusApplication(appId);
186 } else {
187 ApplicationManager.startApplication(appId);
188 }
189 }
191 function startLockedApp(app) {
192 if (greeter.locked) {
193 greeter.lockedApp = app;
194 }
195 startApp(app); // locked apps are always in our same session
196 }
198 Binding {
199 target: LauncherModel
200 property: "applicationManager"
201 value: ApplicationManager
202 }
204 Component.onCompleted: {
205 finishStartUpTimer.start();
206 }
208 VolumeControl {
209 id: volumeControl
210 }
212 DashCommunicator {
213 id: dash
214 objectName: "dashCommunicator"
215 }
217 PhysicalKeysMapper {
218 id: physicalKeysMapper
219 objectName: "physicalKeysMapper"
221 onPowerKeyLongPressed: dialogs.showPowerDialog();
222 onVolumeDownTriggered: volumeControl.volumeDown();
223 onVolumeUpTriggered: volumeControl.volumeUp();
224 onScreenshotTriggered: itemGrabber.capture(shell);
225 }
227 GlobalShortcut {
228 // dummy shortcut to force creation of GlobalShortcutRegistry before WindowInputFilter
229 }
231 WindowInputFilter {
232 id: inputFilter
233 Keys.onPressed: physicalKeysMapper.onKeyPressed(event, lastInputTimestamp);
234 Keys.onReleased: physicalKeysMapper.onKeyReleased(event, lastInputTimestamp);
235 }
237 WindowInputMonitor {
238 objectName: "windowInputMonitor"
239 onHomeKeyActivated: {
240 // Ignore when greeter is active, to avoid pocket presses
241 if (!greeter.active) {
242 launcher.fadeOut();
243 shell.showHome();
244 }
245 }
246 onTouchBegun: { cursor.opacity = 0; }
247 onTouchEnded: {
248 // move the (hidden) cursor to the last known touch position
249 var mappedCoords = mapFromItem(null, pos.x, pos.y);
250 cursor.x = mappedCoords.x;
251 cursor.y = mappedCoords.y;
252 cursor.mouseNeverMoved = false;
253 }
254 }
256 GSettings {
257 id: settings
258 schema.id: "com.canonical.Unity8"
259 }
261 Item {
262 id: stages
263 objectName: "stages"
264 width: parent.width
265 height: parent.height
267 SurfaceManager {
268 id: surfaceMan
269 objectName: "surfaceManager"
270 }
271 TopLevelWindowModel {
272 id: topLevelSurfaceList
273 objectName: "topLevelSurfaceList"
274 applicationManager: ApplicationManager // it's a singleton
275 surfaceManager: surfaceMan
276 }
278 Stage {
279 id: stage
280 objectName: "stage"
281 anchors.fill: parent
282 focus: true
284 dragAreaWidth: shell.edgeSize
285 background: wallpaperResolver.background
286 leftEdgeDragProgress: !greeter || greeter.locked || !tutorial.launcherLongSwipeEnabled ? 0 :
287 Math.max(0, (launcher.dragDistance * (stage.width - launcher.panelWidth) / stage.width) - launcher.panelWidth)
289 applicationManager: ApplicationManager
290 topLevelSurfaceList: topLevelSurfaceList
291 inputMethodRect: inputMethod.visibleRect
293 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
294 ? "phone"
295 : shell.usageScenario
297 mode: usageScenario == "phone" ? "staged"
298 : usageScenario == "tablet" ? "stagedWithSideStage"
299 : "windowed"
301 shellOrientation: shell.orientation
302 shellOrientationAngle: shell.orientationAngle
303 orientations: shell.orientations
304 nativeWidth: shell.nativeWidth
305 nativeHeight: shell.nativeHeight
307 interactive: (!greeter || !greeter.shown)
308 && panel.indicators.fullyClosed
309 && launcher.progress == 0
310 && !notifications.useModal
312 onInteractiveChanged: { if (interactive) { focus = true; } }
314 leftMargin: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
315 suspended: greeter.shown
316 keepDashRunning: launcher.shown || launcher.dashSwipe
317 altTabPressed: physicalKeysMapper.altTabPressed
318 oskEnabled: shell.oskEnabled
319 spreadEnabled: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
320 }
321 }
323 InputMethod {
324 id: inputMethod
325 objectName: "inputMethod"
326 surface: topLevelSurfaceList.inputMethodSurface
327 anchors {
328 fill: parent
329 topMargin: panel.panelHeight
330 leftMargin: launcher.lockedVisible ? launcher.panelWidth : 0
331 }
332 z: notifications.useModal || panel.indicators.shown || wizard.active || tutorial.running ? overlay.z + 1 : overlay.z - 1
333 }
335 Loader {
336 id: greeterLoader
337 objectName: "greeterLoader"
338 anchors.fill: parent
339 anchors.topMargin: panel.panelHeight
340 sourceComponent: shell.mode != "shell" ? integratedGreeter :
341 Qt.createComponent(Qt.resolvedUrl("Greeter/ShimGreeter.qml"));
342 onLoaded: {
343 item.objectName = "greeter"
344 }
345 }
347 Component {
348 id: integratedGreeter
349 Greeter {
351 enabled: panel.indicators.fullyClosed // hides OSK when panel is open
352 hides: [launcher, panel.indicators]
353 tabletMode: shell.usageScenario != "phone"
354 launcherOffset: launcher.progress
355 forcedUnlock: wizard.active || shell.mode === "full-shell"
356 background: wallpaperResolver.cachedBackground
357 hasCustomBackground: wallpaperResolver.hasCustomBackground
358 allowFingerprint: !dialogs.hasActiveDialog &&
359 !notifications.topmostIsFullscreen &&
360 !panel.indicators.shown
362 // avoid overlapping with Launcher's edge drag area
363 // FIXME: Fix TouchRegistry & friends and remove this workaround
364 // Issue involves launcher's DDA getting disabled on a long
365 // left-edge drag
366 dragHandleLeftMargin: launcher.available ? launcher.dragAreaWidth + 1 : 0
368 onSessionStarted: {
369 launcher.hide();
370 }
372 onTease: {
373 if (!tutorial.running) {
374 launcher.tease();
375 }
376 }
378 onEmergencyCall: startLockedApp("dialer-app")
379 }
380 }
382 Timer {
383 // See powerConnection for why this is useful
384 id: showGreeterDelayed
385 interval: 1
386 onTriggered: {
387 greeter.forceShow();
388 }
389 }
391 Connections {
392 id: callConnection
393 target: callManager
395 onHasCallsChanged: {
396 if (greeter.locked && callManager.hasCalls && greeter.lockedApp !== "dialer-app") {
397 // We just received an incoming call while locked. The
398 // indicator will have already launched dialer-app for us, but
399 // there is a race between "hasCalls" changing and the dialer
400 // starting up. So in case we lose that race, we'll start/
401 // focus the dialer ourselves here too. Even if the indicator
402 // didn't launch the dialer for some reason (or maybe a call
403 // started via some other means), if an active call is
404 // happening, we want to be in the dialer.
405 startLockedApp("dialer-app")
406 }
407 }
408 }
410 Connections {
411 id: powerConnection
412 target: Powerd
414 onStatusChanged: {
415 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
416 !callManager.hasCalls && !wizard.active) {
417 // We don't want to simply call greeter.showNow() here, because
418 // that will take too long. Qt will delay button event
419 // handling until the greeter is done loading and may think the
420 // user held down the power button the whole time, leading to a
421 // power dialog being shown. Instead, delay showing the
422 // greeter until we've finished handling the event. We could
423 // make the greeter load asynchronously instead, but that
424 // introduces a whole host of timing issues, especially with
425 // its animations. So this is simpler.
426 showGreeterDelayed.start();
427 }
428 }
429 }
431 function showHome() {
432 greeter.notifyUserRequestedApp();
434 if (shell.mode === "greeter") {
435 SessionBroadcast.requestHomeShown(AccountsService.user);
436 } else {
437 var animate = !LightDMService.greeter.active && !stages.shown;
438 dash.setCurrentScope(0, animate, false);
439 ApplicationManager.requestFocusApplication("unity8-dash");
440 }
441 }
443 function showDash() {
444 if (greeter.notifyShowingDashFromDrag()) {
445 launcher.fadeOut();
446 }
448 if (!greeter.locked && tutorial.launcherLongSwipeEnabled
449 && (ApplicationManager.focusedApplicationId != "unity8-dash" || stage.spreadShown)) {
450 ApplicationManager.requestFocusApplication("unity8-dash")
451 launcher.fadeOut();
452 stage.closeSpread();
453 }
454 }
456 Item {
457 id: overlay
458 z: 10
460 anchors.fill: parent
462 Panel {
463 id: panel
464 objectName: "panel"
465 anchors.fill: parent //because this draws indicator menus
466 indicators {
467 hides: [launcher]
468 available: tutorial.panelEnabled
469 && ((!greeter || !greeter.locked) || AccountsService.enableIndicatorsWhileLocked)
470 && (!greeter || !greeter.hasLockedApp)
471 && !shell.waitingOnGreeter
472 && settings.enableIndicatorMenu
473 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
475 minimizedPanelHeight: units.gu(3)
476 expandedPanelHeight: units.gu(7)
478 indicatorsModel: Indicators.IndicatorsModel {
479 // tablet and phone both use the same profile
480 // FIXME: use just "phone" for greeter too, but first fix
481 // greeter app launching to either load the app inside the
482 // greeter or tell the session to load the app. This will
483 // involve taking the url-dispatcher dbus name and using
484 // SessionBroadcast to tell the session.
485 profile: shell.mode === "greeter" ? "desktop_greeter" : "phone"
486 Component.onCompleted: load();
487 }
488 }
490 callHint {
491 greeterShown: greeter.shown
492 }
494 readonly property bool focusedSurfaceIsFullscreen: topLevelSurfaceList.focusedWindow
495 ? topLevelSurfaceList.focusedWindow.state === Mir.FullscreenState
496 : false
497 fullscreenMode: (focusedSurfaceIsFullscreen && !LightDMService.greeter.active && launcher.progress == 0)
498 || greeter.hasLockedApp
499 locked: greeter && greeter.active
500 }
502 Launcher {
503 id: launcher
504 objectName: "launcher"
506 /*
507 * Since the Dash doesn't have the same controll over surfaces that the
508 * Shell does, it can't slowly move the scope out of the way, as the shell
509 * does with apps, and the dash is show instantly. This allows for some
510 * leeway and prevents accidental home swipes.
511 */
512 readonly property real offset: shell.focusedApplicationId == "unity8-dash" ? units.gu(12) : 0
513 readonly property bool dashSwipe: progress > offset
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
531 onShowDashHome: showHome()
532 onDash: showDash()
533 onDashSwipeChanged: {
534 if (dashSwipe) {
535 dash.setCurrentScope(0, false, true)
536 }
537 }
538 onLauncherApplicationSelected: {
539 greeter.notifyUserRequestedApp();
540 shell.activateApplication(appId);
541 }
542 onShownChanged: {
543 if (shown) {
544 panel.indicators.hide()
545 }
546 }
547 onFocusChanged: {
548 if (!focus) {
549 stage.focus = true;
550 }
551 }
553 GlobalShortcut {
554 shortcut: Qt.AltModifier | Qt.Key_F1
555 onTriggered: {
556 launcher.openForKeyboardNavigation();
557 }
558 }
559 GlobalShortcut {
560 shortcut: Qt.MetaModifier | Qt.Key_0
561 onTriggered: {
562 if (LauncherModel.get(9)) {
563 activateApplication(LauncherModel.get(9).appId);
564 }
565 }
566 }
567 Repeater {
568 model: 9
569 GlobalShortcut {
570 shortcut: Qt.MetaModifier | (Qt.Key_1 + index)
571 onTriggered: {
572 if (LauncherModel.get(index)) {
573 activateApplication(LauncherModel.get(index).appId);
574 }
575 }
576 }
577 }
578 }
580 KeyboardShortcutsOverlay {
581 objectName: "shortcutsOverlay"
582 enabled: launcher.shortcutHintsShown && width < parent.width - (launcher.lockedVisible ? launcher.panelWidth : 0) - padding
583 && height < parent.height - padding - panel.panelHeight
584 anchors.centerIn: parent
585 anchors.horizontalCenterOffset: launcher.lockedVisible ? launcher.panelWidth/2 : 0
586 anchors.verticalCenterOffset: panel.panelHeight/2
587 visible: opacity > 0
588 opacity: enabled ? 0.95 : 0
590 Behavior on opacity {
591 UbuntuNumberAnimation {}
592 }
593 }
595 Tutorial {
596 id: tutorial
597 objectName: "tutorial"
598 anchors.fill: parent
600 paused: callManager.hasCalls || !greeter || greeter.active ||
601 wizard.active
602 delayed: dialogs.hasActiveDialog || notifications.hasNotification ||
603 inputMethod.visible ||
604 (launcher.shown && !launcher.lockedVisible) ||
605 panel.indicators.shown || stage.rightEdgeDragProgress > 0
606 usageScenario: shell.usageScenario
607 lastInputTimestamp: inputFilter.lastInputTimestamp
608 launcher: launcher
609 panel: panel
610 stage: stage
611 }
613 Wizard {
614 id: wizard
615 objectName: "wizard"
616 anchors.fill: parent
617 deferred: shell.mode === "greeter"
619 function unlockWhenDoneWithWizard() {
620 if (!active) {
621 Connectivity.unlockAllModems();
622 }
623 }
625 Component.onCompleted: unlockWhenDoneWithWizard()
626 onActiveChanged: unlockWhenDoneWithWizard()
627 }
629 MouseArea { // modal notifications prevent interacting with other contents
630 anchors.fill: parent
631 visible: notifications.useModal
632 enabled: visible
633 }
635 Notifications {
636 id: notifications
638 model: NotificationBackend.Model
639 margin: units.gu(1)
640 hasMouse: shell.hasMouse
641 background: wallpaperResolver.cachedBackground
643 y: topmostIsFullscreen ? 0 : panel.panelHeight
644 height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
646 states: [
647 State {
648 name: "narrow"
649 when: overlay.width <= units.gu(60)
650 AnchorChanges {
651 target: notifications
652 anchors.left: parent.left
653 anchors.right: parent.right
654 }
655 },
656 State {
657 name: "wide"
658 when: overlay.width > units.gu(60)
659 AnchorChanges {
660 target: notifications
661 anchors.left: undefined
662 anchors.right: parent.right
663 }
664 PropertyChanges { target: notifications; width: units.gu(38) }
665 }
666 ]
667 }
668 }
670 Dialogs {
671 id: dialogs
672 objectName: "dialogs"
673 anchors.fill: parent
674 z: overlay.z + 10
675 usageScenario: shell.usageScenario
676 onPowerOffClicked: {
677 shutdownFadeOutRectangle.enabled = true;
678 shutdownFadeOutRectangle.visible = true;
679 shutdownFadeOut.start();
680 }
681 }
683 Connections {
684 target: SessionBroadcast
685 onShowHome: if (shell.mode !== "greeter") showHome()
686 }
688 URLDispatcher {
689 id: urlDispatcher
690 objectName: "urlDispatcher"
691 active: shell.mode === "greeter"
692 onUrlRequested: shell.activateURL(url)
693 }
695 ItemGrabber {
696 id: itemGrabber
697 anchors.fill: parent
698 z: dialogs.z + 10
699 GlobalShortcut { shortcut: Qt.Key_Print; onTriggered: itemGrabber.capture(shell) }
700 Connections {
701 target: stage
702 ignoreUnknownSignals: true
703 onItemSnapshotRequested: itemGrabber.capture(item)
704 }
705 }
707 Timer {
708 id: cursorHidingTimer
709 interval: 3000
710 running: panel.focusedSurfaceIsFullscreen && cursor.opacity > 0
711 onTriggered: cursor.opacity = 0;
712 }
714 Cursor {
715 id: cursor
716 objectName: "cursor"
717 visible: shell.hasMouse
718 z: itemGrabber.z + 1
719 topBoundaryOffset: panel.panelHeight
721 confiningItem: stage.itemConfiningMouseCursor
723 property bool mouseNeverMoved: true
724 Binding {
725 target: cursor; property: "x"; value: shell.width / 2
726 when: cursor.mouseNeverMoved && cursor.visible
727 }
728 Binding {
729 target: cursor; property: "y"; value: shell.height / 2
730 when: cursor.mouseNeverMoved && cursor.visible
731 }
733 height: units.gu(3)
735 readonly property var previewRectangle: stage.previewRectangle.target &&
736 stage.previewRectangle.target.dragging ?
737 stage.previewRectangle : null
739 onPushedLeftBoundary: {
740 if (buttons === Qt.NoButton) {
741 launcher.pushEdge(amount);
742 } else if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeMaximizedLeftRight) {
743 previewRectangle.maximizeLeft(amount);
744 }
745 }
747 onPushedRightBoundary: {
748 if (buttons === Qt.NoButton) {
749 stage.pushRightEdge(amount);
750 } else if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeMaximizedLeftRight) {
751 previewRectangle.maximizeRight(amount);
752 }
753 }
755 onPushedTopBoundary: {
756 if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeMaximized) {
757 previewRectangle.maximize(amount);
758 }
759 }
760 onPushedTopLeftCorner: {
761 if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeCornerMaximized) {
762 previewRectangle.maximizeTopLeft(amount);
763 }
764 }
765 onPushedTopRightCorner: {
766 if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeCornerMaximized) {
767 previewRectangle.maximizeTopRight(amount);
768 }
769 }
770 onPushedBottomLeftCorner: {
771 if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeCornerMaximized) {
772 previewRectangle.maximizeBottomLeft(amount);
773 }
774 }
775 onPushedBottomRightCorner: {
776 if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeCornerMaximized) {
777 previewRectangle.maximizeBottomRight(amount);
778 }
779 }
780 onPushStopped: {
781 if (previewRectangle) {
782 previewRectangle.stop();
783 }
784 }
786 onMouseMoved: {
787 mouseNeverMoved = false;
788 cursor.opacity = 1;
789 }
791 Behavior on opacity { UbuntuNumberAnimation {} }
792 }
794 // non-visual objects
795 KeymapSwitcher {
796 focusedSurface: topLevelSurfaceList.focusedWindow ? topLevelSurfaceList.focusedWindow.surface : null
797 }
798 BrightnessControl {}
800 Rectangle {
801 id: shutdownFadeOutRectangle
802 z: cursor.z + 1
803 enabled: false
804 visible: false
805 color: "black"
806 anchors.fill: parent
807 opacity: 0.0
808 NumberAnimation on opacity {
809 id: shutdownFadeOut
810 from: 0.0
811 to: 1.0
812 onStopped: {
813 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
814 DBusUnitySessionService.shutdown();
815 }
816 }
817 }
818 }