on xenial_-_blue-light-filter help sign in
unity8/qml/Shell.qml
823 lines 29 kB history raw
1/*
2 * Copyright (C) 2018 The UBports project
3 * Copyright (C) 2013-2016 Canonical, Ltd.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
18import QtQuick 2.4
19import QtQuick.Window 2.2
20import QtGraphicalEffects 1.0
21import AccountsService 0.1
22import Unity.Application 0.1
23import Ubuntu.Components 1.3
24import Ubuntu.Components.Popups 1.3
25import Ubuntu.Gestures 0.1
26import Ubuntu.Telephony 0.1 as Telephony
27import Unity.Connectivity 0.1
28import Unity.Launcher 0.1
29import GlobalShortcut 1.0 // has to be before Utils, because of WindowInputFilter
30import GSettings 1.0
31import ImageCache 0.1
32import Utils 0.1
33import Powerd 0.1
34import SessionBroadcast 0.1
35import "Greeter"
36import "Launcher"
37import "Panel"
38import "Components"
39import "Notifications"
40import "Stage"
41import "Tutorial"
42import "Wizard"
43import Unity.Notifications 1.0 as NotificationBackend
44import Unity.Session 0.1
45import Unity.DashCommunicator 0.1
46import Unity.Indicators 0.1 as Indicators
47import Cursor 1.1
48import WindowManager 0.1
51StyledItem {
52 id: shell
54 theme.name: "Ubuntu.Components.Themes.SuruDark"
56 // to be set from outside
57 property int orientationAngle: 0
58 property int orientation
59 property Orientations orientations
60 property real nativeWidth
61 property real nativeHeight
62 property alias indicatorAreaShowProgress: panel.indicatorAreaShowProgress
63 property string usageScenario: "phone" // supported values: "phone", "tablet" or "desktop"
64 property string mode: "full-greeter"
65 property alias oskEnabled: inputMethod.enabled
66 function updateFocusedAppOrientation() {
67 stage.updateFocusedAppOrientation();
68 }
69 function updateFocusedAppOrientationAnimated() {
70 stage.updateFocusedAppOrientationAnimated();
71 }
72 property bool hasMouse: false
74 // to be read from outside
75 readonly property int mainAppWindowOrientationAngle: stage.mainAppWindowOrientationAngle
77 readonly property bool orientationChangesEnabled: panel.indicators.fullyClosed
78 && stage.orientationChangesEnabled
79 && (!greeter || !greeter.animating)
81 readonly property bool showingGreeter: greeter && greeter.shown
83 property bool startingUp: true
84 Timer { id: finishStartUpTimer; interval: 500; onTriggered: startingUp = false }
86 property int supportedOrientations: {
87 if (startingUp) {
88 // Ensure we don't rotate during start up
89 return Qt.PrimaryOrientation;
90 } else if (showingGreeter || notifications.topmostIsFullscreen) {
91 return Qt.PrimaryOrientation;
92 } else {
93 return shell.orientations.map(stage.supportedOrientations);
94 }
95 }
97 readonly property var mainApp: stage.mainApp
99 onMainAppChanged: {
100 if (mainApp) {
101 _onMainAppChanged(mainApp.appId);
102 }
103 }
104 Connections {
105 target: ApplicationManager
106 onFocusRequested: {
107 if (shell.mainApp && shell.mainApp.appId === appId) {
108 _onMainAppChanged(appId);
109 }
110 }
111 }
112 function _onMainAppChanged(appId) {
113 if (wizard.active && appId != "" && appId != "unity8-dash") {
114 // If this happens on first boot, we may be in the
115 // wizard while receiving a call. But a call is more
116 // important than the wizard so just bail out of it.
117 wizard.hide();
118 }
120 if (appId === "dialer-app" && callManager.hasCalls && greeter.locked) {
121 // If we are in the middle of a call, make dialer lockedApp and show it.
122 // This can happen if user backs out of dialer back to greeter, then
123 // launches dialer again.
124 greeter.lockedApp = appId;
125 }
126 greeter.notifyAppFocusRequested(appId);
128 panel.indicators.hide();
129 launcher.hide();
130 }
132 // For autopilot consumption
133 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
135 // Note when greeter is waiting on PAM, so that we can disable edges until
136 // we know which user data to show and whether the session is locked.
137 readonly property bool waitingOnGreeter: greeter && greeter.waiting
139 property real edgeSize: units.gu(settings.edgeDragWidth)
141 WallpaperResolver {
142 id: wallpaperResolver
143 objectName: "wallpaperResolver"
145 readonly property url defaultBackground: "file://" + Constants.defaultWallpaper
146 readonly property bool hasCustomBackground: background != defaultBackground
148 // Use a cached version of the scaled-down wallpaper (as sometimes the
149 // image can be quite big compared to the device size, including for
150 // our default wallpaper). We use a name=wallpaper argument here to
151 // make sure we don't litter our cache with lots of scaled images. We
152 // only need to bother caching one at a time.
153 readonly property url cachedBackground: background.toString().indexOf("file:///") === 0 ? "image://unity8imagecache/" + background + "?name=wallpaper" : background
155 GSettings {
156 id: backgroundSettings
157 schema.id: "org.gnome.desktop.background"
158 }
160 candidates: [
161 AccountsService.backgroundFile,
162 backgroundSettings.pictureUri,
163 defaultBackground
164 ]
165 }
167 readonly property alias greeter: greeterLoader.item
169 function activateApplication(appId) {
170 // Either open the app in our own session, or -- if we're acting as a
171 // greeter -- ask the user's session to open it for us.
172 if (shell.mode === "greeter") {
173 activateURL("application:///" + appId + ".desktop");
174 } else {
175 startApp(appId);
176 }
177 }
179 function activateURL(url) {
180 SessionBroadcast.requestUrlStart(AccountsService.user, url);
181 greeter.notifyUserRequestedApp();
182 panel.indicators.hide();
183 }
185 function startApp(appId) {
186 if (ApplicationManager.findApplication(appId)) {
187 ApplicationManager.requestFocusApplication(appId);
188 } else {
189 ApplicationManager.startApplication(appId);
190 }
191 }
193 function startLockedApp(app) {
194 if (greeter.locked) {
195 greeter.lockedApp = app;
196 }
197 startApp(app); // locked apps are always in our same session
198 }
200 Binding {
201 target: LauncherModel
202 property: "applicationManager"
203 value: ApplicationManager
204 }
206 Component.onCompleted: {
207 finishStartUpTimer.start();
208 }
210 VolumeControl {
211 id: volumeControl
212 }
214 DashCommunicator {
215 id: dash
216 objectName: "dashCommunicator"
217 }
219 PhysicalKeysMapper {
220 id: physicalKeysMapper
221 objectName: "physicalKeysMapper"
223 onPowerKeyLongPressed: dialogs.showPowerDialog();
224 onVolumeDownTriggered: volumeControl.volumeDown();
225 onVolumeUpTriggered: volumeControl.volumeUp();
226 onScreenshotTriggered: itemGrabber.capture(shell);
227 }
229 GlobalShortcut {
230 // dummy shortcut to force creation of GlobalShortcutRegistry before WindowInputFilter
231 }
233 WindowInputFilter {
234 id: inputFilter
235 Keys.onPressed: physicalKeysMapper.onKeyPressed(event, lastInputTimestamp);
236 Keys.onReleased: physicalKeysMapper.onKeyReleased(event, lastInputTimestamp);
237 }
239 WindowInputMonitor {
240 objectName: "windowInputMonitor"
241 onHomeKeyActivated: {
242 // Ignore when greeter is active, to avoid pocket presses
243 if (!greeter.active) {
244 launcher.fadeOut();
245 shell.showHome();
246 }
247 }
248 onTouchBegun: { cursor.opacity = 0; }
249 onTouchEnded: {
250 // move the (hidden) cursor to the last known touch position
251 var mappedCoords = mapFromItem(null, pos.x, pos.y);
252 cursor.x = mappedCoords.x;
253 cursor.y = mappedCoords.y;
254 cursor.mouseNeverMoved = false;
255 }
256 }
258 GSettings {
259 id: settings
260 schema.id: "com.canonical.Unity8"
261 }
263 Item {
264 id: stages
265 objectName: "stages"
266 width: parent.width
267 height: parent.height
269 TopLevelSurfaceList {
270 id: topLevelSurfaceList
271 objectName: "topLevelSurfaceList"
272 applicationsModel: ApplicationManager
273 }
275 Stage {
276 id: stage
277 objectName: "stage"
278 anchors.fill: parent
279 focus: true
281 dragAreaWidth: shell.edgeSize
282 background: wallpaperResolver.background
283 leftEdgeDragProgress: !greeter || greeter.locked || !tutorial.launcherLongSwipeEnabled ? 0 :
284 Math.max(0, (launcher.dragDistance * (stage.width - launcher.panelWidth) / stage.width) - launcher.panelWidth)
286 applicationManager: ApplicationManager
287 topLevelSurfaceList: topLevelSurfaceList
288 inputMethodRect: inputMethod.visibleRect
290 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
291 ? "phone"
292 : shell.usageScenario
294 mode: usageScenario == "phone" ? "staged"
295 : usageScenario == "tablet" ? "stagedWithSideStage"
296 : "windowed"
298 shellOrientation: shell.orientation
299 shellOrientationAngle: shell.orientationAngle
300 orientations: shell.orientations
301 nativeWidth: shell.nativeWidth
302 nativeHeight: shell.nativeHeight
304 interactive: (!greeter || !greeter.shown)
305 && panel.indicators.fullyClosed
306 && launcher.progress == 0
307 && !notifications.useModal
309 onInteractiveChanged: { if (interactive) { focus = true; } }
311 leftMargin: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
312 suspended: greeter.shown
313 keepDashRunning: launcher.shown || launcher.dashSwipe
314 altTabPressed: physicalKeysMapper.altTabPressed
315 oskEnabled: shell.oskEnabled
316 spreadEnabled: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
317 }
318 }
320 InputMethod {
321 id: inputMethod
322 objectName: "inputMethod"
323 anchors {
324 fill: parent
325 topMargin: panel.panelHeight
326 leftMargin: launcher.lockedVisible ? launcher.panelWidth : 0
327 }
328 z: notifications.useModal || panel.indicators.shown || wizard.active || tutorial.running ? overlay.z + 1 : overlay.z - 1
329 }
331 Loader {
332 id: greeterLoader
333 objectName: "greeterLoader"
334 anchors.fill: parent
335 anchors.topMargin: panel.panelHeight
336 sourceComponent: shell.mode != "shell" ? integratedGreeter :
337 Qt.createComponent(Qt.resolvedUrl("Greeter/ShimGreeter.qml"));
338 onLoaded: {
339 item.objectName = "greeter"
340 }
341 }
343 Component {
344 id: integratedGreeter
345 Greeter {
347 enabled: panel.indicators.fullyClosed // hides OSK when panel is open
348 hides: [launcher, panel.indicators]
349 tabletMode: shell.usageScenario != "phone"
350 launcherOffset: launcher.progress
351 forcedUnlock: wizard.active && !wizard.isUpdate || shell.mode === "full-shell"
352 background: wallpaperResolver.cachedBackground
353 hasCustomBackground: wallpaperResolver.hasCustomBackground
354 allowFingerprint: !dialogs.hasActiveDialog &&
355 !notifications.topmostIsFullscreen &&
356 !panel.indicators.shown
358 // avoid overlapping with Launcher's edge drag area
359 // FIXME: Fix TouchRegistry & friends and remove this workaround
360 // Issue involves launcher's DDA getting disabled on a long
361 // left-edge drag
362 dragHandleLeftMargin: launcher.available ? launcher.dragAreaWidth + 1 : 0
364 onSessionStarted: {
365 launcher.hide();
366 }
368 onTease: {
369 if (!tutorial.running) {
370 launcher.tease();
371 }
372 }
374 onEmergencyCall: startLockedApp("dialer-app")
375 }
376 }
378 Timer {
379 // See powerConnection for why this is useful
380 id: showGreeterDelayed
381 interval: 1
382 onTriggered: {
383 greeter.forceShow();
384 }
385 }
387 Connections {
388 id: callConnection
389 target: callManager
391 onHasCallsChanged: {
392 if (greeter.locked && callManager.hasCalls && greeter.lockedApp !== "dialer-app") {
393 // We just received an incoming call while locked. The
394 // indicator will have already launched dialer-app for us, but
395 // there is a race between "hasCalls" changing and the dialer
396 // starting up. So in case we lose that race, we'll start/
397 // focus the dialer ourselves here too. Even if the indicator
398 // didn't launch the dialer for some reason (or maybe a call
399 // started via some other means), if an active call is
400 // happening, we want to be in the dialer.
401 startLockedApp("dialer-app")
402 }
403 }
404 }
406 Connections {
407 id: powerConnection
408 target: Powerd
410 onStatusChanged: {
411 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
412 !callManager.hasCalls && !wizard.active) {
413 // We don't want to simply call greeter.showNow() here, because
414 // that will take too long. Qt will delay button event
415 // handling until the greeter is done loading and may think the
416 // user held down the power button the whole time, leading to a
417 // power dialog being shown. Instead, delay showing the
418 // greeter until we've finished handling the event. We could
419 // make the greeter load asynchronously instead, but that
420 // introduces a whole host of timing issues, especially with
421 // its animations. So this is simpler.
422 showGreeterDelayed.start();
423 }
424 }
425 }
427 function showHome() {
428 greeter.notifyUserRequestedApp();
430 if (shell.mode === "greeter") {
431 SessionBroadcast.requestHomeShown(AccountsService.user);
432 } else {
433 var animate = !LightDMService.greeter.active && !stages.shown;
434 dash.setCurrentScope(0, animate, false);
435 ApplicationManager.requestFocusApplication("unity8-dash");
436 }
437 }
439 function showDash() {
440 if (greeter.notifyShowingDashFromDrag()) {
441 launcher.fadeOut();
442 }
444 if (!greeter.locked && tutorial.launcherLongSwipeEnabled
445 && (ApplicationManager.focusedApplicationId != "unity8-dash" || stage.spreadShown)) {
446 ApplicationManager.requestFocusApplication("unity8-dash")
447 launcher.fadeOut();
448 stage.closeSpread();
449 }
450 }
452 // Red filter overlay
453 ColorOverlay {
454 z: 11
455 opacity: settings.redFilterOpacity
456 visible: settings.redFilterEnabled && settings.redFilterOpacity > 0.01
457 anchors.fill: parent
458 source: parent
459 color: "#80800000"
460 }
462 Item {
463 id: overlay
464 z: 10
466 anchors.fill: parent
468 Panel {
469 id: panel
470 objectName: "panel"
471 anchors.fill: parent //because this draws indicator menus
472 indicators {
473 hides: [launcher]
474 available: tutorial.panelEnabled
475 && ((!greeter || !greeter.locked) || AccountsService.enableIndicatorsWhileLocked)
476 && (!greeter || !greeter.hasLockedApp)
477 && !shell.waitingOnGreeter
478 && settings.enableIndicatorMenu
479 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
481 minimizedPanelHeight: units.gu(3)
482 expandedPanelHeight: units.gu(7)
484 indicatorsModel: 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 callHint {
497 greeterShown: greeter.shown
498 }
500 readonly property bool focusedSurfaceIsFullscreen: MirFocusController.focusedSurface
501 ? MirFocusController.focusedSurface.state === Mir.FullscreenState
502 : false
503 fullscreenMode: (focusedSurfaceIsFullscreen && !LightDMService.greeter.active && launcher.progress == 0)
504 || greeter.hasLockedApp
505 locked: greeter && greeter.active
506 }
508 Launcher {
509 id: launcher
510 objectName: "launcher"
512 /*
513 * Since the Dash doesn't have the same controll over surfaces that the
514 * Shell does, it can't slowly move the scope out of the way, as the shell
515 * does with apps, and the dash is show instantly. This allows for some
516 * leeway and prevents accidental home swipes.
517 */
518 readonly property real offset: shell.focusedApplicationId == "unity8-dash" ? units.gu(12) : 0
519 readonly property bool dashSwipe: progress > offset
521 anchors.top: parent.top
522 anchors.topMargin: inverted ? 0 : panel.panelHeight
523 anchors.bottom: parent.bottom
524 width: parent.width
525 dragAreaWidth: shell.edgeSize
526 available: tutorial.launcherEnabled
527 && (!greeter.locked || AccountsService.enableLauncherWhileLocked)
528 && !greeter.hasLockedApp
529 && !shell.waitingOnGreeter
530 && settings.enableLauncher
531 inverted: shell.usageScenario !== "desktop"
532 superPressed: physicalKeysMapper.superPressed
533 superTabPressed: physicalKeysMapper.superTabPressed
534 panelWidth: units.gu(settings.launcherWidth)
535 lockedVisible: shell.usageScenario == "desktop" && !settings.autohideLauncher && !panel.fullscreenMode
537 onShowDashHome: showHome()
538 onDash: showDash()
539 onDashSwipeChanged: {
540 if (dashSwipe) {
541 dash.setCurrentScope(0, false, true)
542 }
543 }
544 onLauncherApplicationSelected: {
545 greeter.notifyUserRequestedApp();
546 shell.activateApplication(appId);
547 }
548 onShownChanged: {
549 if (shown) {
550 panel.indicators.hide()
551 }
552 }
553 onFocusChanged: {
554 if (!focus) {
555 stage.focus = true;
556 }
557 }
559 GlobalShortcut {
560 shortcut: Qt.AltModifier | Qt.Key_F1
561 onTriggered: {
562 launcher.openForKeyboardNavigation();
563 }
564 }
565 GlobalShortcut {
566 shortcut: Qt.MetaModifier | Qt.Key_0
567 onTriggered: {
568 if (LauncherModel.get(9)) {
569 activateApplication(LauncherModel.get(9).appId);
570 }
571 }
572 }
573 Repeater {
574 model: 9
575 GlobalShortcut {
576 shortcut: Qt.MetaModifier | (Qt.Key_1 + index)
577 onTriggered: {
578 if (LauncherModel.get(index)) {
579 activateApplication(LauncherModel.get(index).appId);
580 }
581 }
582 }
583 }
584 }
586 KeyboardShortcutsOverlay {
587 objectName: "shortcutsOverlay"
588 enabled: launcher.shortcutHintsShown && width < parent.width - (launcher.lockedVisible ? launcher.panelWidth : 0) - padding
589 && height < parent.height - padding - panel.panelHeight
590 anchors.centerIn: parent
591 anchors.horizontalCenterOffset: launcher.lockedVisible ? launcher.panelWidth/2 : 0
592 anchors.verticalCenterOffset: panel.panelHeight/2
593 visible: opacity > 0
594 opacity: enabled ? 0.95 : 0
596 Behavior on opacity {
597 UbuntuNumberAnimation {}
598 }
599 }
601 Tutorial {
602 id: tutorial
603 objectName: "tutorial"
604 anchors.fill: parent
606 paused: callManager.hasCalls || !greeter || greeter.active ||
607 wizard.active
608 delayed: dialogs.hasActiveDialog || notifications.hasNotification ||
609 inputMethod.visible ||
610 (launcher.shown && !launcher.lockedVisible) ||
611 panel.indicators.shown || stage.rightEdgeDragProgress > 0
612 usageScenario: shell.usageScenario
613 lastInputTimestamp: inputFilter.lastInputTimestamp
614 launcher: launcher
615 panel: panel
616 stage: stage
617 }
619 Wizard {
620 id: wizard
621 objectName: "wizard"
622 anchors.fill: parent
623 deferred: shell.mode === "greeter"
625 function unlockWhenDoneWithWizard() {
626 if (!active) {
627 Connectivity.unlockAllModems();
628 }
629 }
631 Component.onCompleted: unlockWhenDoneWithWizard()
632 onActiveChanged: unlockWhenDoneWithWizard()
633 }
635 MouseArea { // modal notifications prevent interacting with other contents
636 anchors.fill: parent
637 visible: notifications.useModal
638 enabled: visible
639 }
641 Notifications {
642 id: notifications
644 model: NotificationBackend.Model
645 margin: units.gu(1)
646 hasMouse: shell.hasMouse
647 background: wallpaperResolver.cachedBackground
649 y: topmostIsFullscreen ? 0 : panel.panelHeight
650 height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
652 states: [
653 State {
654 name: "narrow"
655 when: overlay.width <= units.gu(60)
656 AnchorChanges {
657 target: notifications
658 anchors.left: parent.left
659 anchors.right: parent.right
660 }
661 },
662 State {
663 name: "wide"
664 when: overlay.width > units.gu(60)
665 AnchorChanges {
666 target: notifications
667 anchors.left: undefined
668 anchors.right: parent.right
669 }
670 PropertyChanges { target: notifications; width: units.gu(38) }
671 }
672 ]
673 }
674 }
676 Dialogs {
677 id: dialogs
678 objectName: "dialogs"
679 anchors.fill: parent
680 z: overlay.z + 10
681 usageScenario: shell.usageScenario
682 onPowerOffClicked: {
683 shutdownFadeOutRectangle.enabled = true;
684 shutdownFadeOutRectangle.visible = true;
685 shutdownFadeOut.start();
686 }
687 }
689 Connections {
690 target: SessionBroadcast
691 onShowHome: if (shell.mode !== "greeter") showHome()
692 }
694 URLDispatcher {
695 id: urlDispatcher
696 objectName: "urlDispatcher"
697 active: shell.mode === "greeter"
698 onUrlRequested: shell.activateURL(url)
699 }
701 ItemGrabber {
702 id: itemGrabber
703 anchors.fill: parent
704 z: dialogs.z + 10
705 GlobalShortcut { shortcut: Qt.Key_Print; onTriggered: itemGrabber.capture(shell) }
706 Connections {
707 target: stage
708 ignoreUnknownSignals: true
709 onItemSnapshotRequested: itemGrabber.capture(item)
710 }
711 }
713 Timer {
714 id: cursorHidingTimer
715 interval: 3000
716 running: panel.focusedSurfaceIsFullscreen && cursor.opacity > 0
717 onTriggered: cursor.opacity = 0;
718 }
720 Cursor {
721 id: cursor
722 objectName: "cursor"
723 visible: shell.hasMouse
724 z: itemGrabber.z + 1
725 topBoundaryOffset: panel.panelHeight
727 confiningItem: stage.itemConfiningMouseCursor
729 property bool mouseNeverMoved: true
730 Binding {
731 target: cursor; property: "x"; value: shell.width / 2
732 when: cursor.mouseNeverMoved && cursor.visible
733 }
734 Binding {
735 target: cursor; property: "y"; value: shell.height / 2
736 when: cursor.mouseNeverMoved && cursor.visible
737 }
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 BrightnessControl {}
804 Rectangle {
805 id: shutdownFadeOutRectangle
806 z: cursor.z + 1
807 enabled: false
808 visible: false
809 color: "black"
810 anchors.fill: parent
811 opacity: 0.0
812 NumberAnimation on opacity {
813 id: shutdownFadeOut
814 from: 0.0
815 to: 1.0
816 onStopped: {
817 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
818 DBusUnitySessionService.shutdown();
819 }
820 }
821 }
822 }