2 * Copyright (C) 2013-2016 Canonical, Ltd.
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.
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.
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/>.
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
32import SessionBroadcast 0.1
41import Unity.Notifications 1.0 as NotificationBackend
42import Unity.Session 0.1
43import Unity.DashCommunicator 0.1
44import Unity.Indicators 0.1 as Indicators
46import WindowManager 1.0
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();
67 function updateFocusedAppOrientationAnimated() {
68 stage.updateFocusedAppOrientationAnimated();
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: {
86 // Ensure we don't rotate during start up
87 return Qt.PrimaryOrientation;
88 } else if (showingGreeter || notifications.topmostIsFullscreen) {
89 return Qt.PrimaryOrientation;
91 return shell.orientations.map(stage.supportedOrientations);
95 readonly property var mainApp: stage.mainApp
99 _onMainAppChanged(mainApp.appId);
103 target: ApplicationManager
105 if (shell.mainApp && shell.mainApp.appId === appId) {
106 _onMainAppChanged(appId);
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.
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;
124 greeter.notifyAppFocusRequested(appId);
126 panel.indicators.hide();
127 launcher.hide(launcher.ignoreHideIfMouseOverLauncher);
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)
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
154 id: backgroundSettings
155 schema.id: "org.gnome.desktop.background"
159 AccountsService.backgroundFile,
160 backgroundSettings.pictureUri,
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");
177 function activateURL(url) {
178 SessionBroadcast.requestUrlStart(AccountsService.user, url);
179 greeter.notifyUserRequestedApp();
180 panel.indicators.hide();
183 function startApp(appId) {
184 if (ApplicationManager.findApplication(appId)) {
185 ApplicationManager.requestFocusApplication(appId);
187 ApplicationManager.startApplication(appId);
191 function startLockedApp(app) {
192 if (greeter.locked) {
193 greeter.lockedApp = app;
195 startApp(app); // locked apps are always in our same session
199 target: LauncherModel
200 property: "applicationManager"
201 value: ApplicationManager
204 Component.onCompleted: {
205 finishStartUpTimer.start();
214 objectName: "dashCommunicator"
218 id: physicalKeysMapper
219 objectName: "physicalKeysMapper"
221 onPowerKeyLongPressed: dialogs.showPowerDialog();
222 onVolumeDownTriggered: volumeControl.volumeDown();
223 onVolumeUpTriggered: volumeControl.volumeUp();
224 onScreenshotTriggered: itemGrabber.capture(shell);
228 // dummy shortcut to force creation of GlobalShortcutRegistry before WindowInputFilter
233 Keys.onPressed: physicalKeysMapper.onKeyPressed(event, lastInputTimestamp);
234 Keys.onReleased: physicalKeysMapper.onKeyReleased(event, lastInputTimestamp);
238 objectName: "windowInputMonitor"
239 onHomeKeyActivated: {
240 // Ignore when greeter is active, to avoid pocket presses
241 if (!greeter.active) {
246 onTouchBegun: { cursor.opacity = 0; }
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;
257 schema.id: "com.canonical.Unity8"
264 height: parent.height
268 objectName: "surfaceManager"
270 TopLevelWindowModel {
271 id: topLevelSurfaceList
272 objectName: "topLevelSurfaceList"
273 applicationManager: ApplicationManager // it's a singleton
274 surfaceManager: surfaceMan
283 dragAreaWidth: shell.edgeSize
284 background: wallpaperResolver.background
286 applicationManager: ApplicationManager
287 topLevelSurfaceList: topLevelSurfaceList
288 inputMethodRect: inputMethod.visibleRect
290 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
292 : shell.usageScenario
294 mode: usageScenario == "phone" ? "staged"
295 : usageScenario == "tablet" ? "stagedWithSideStage"
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 && !notifications.useModal
308 onInteractiveChanged: { if (interactive) { focus = true; } }
310 leftMargin: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
311 suspended: greeter.shown
312 altTabPressed: physicalKeysMapper.altTabPressed
313 oskEnabled: shell.oskEnabled
314 spreadEnabled: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
320 objectName: "inputMethod"
321 surface: topLevelSurfaceList.inputMethodSurface
324 topMargin: panel.panelHeight
325 leftMargin: launcher.lockedVisible ? launcher.panelWidth : 0
327 z: notifications.useModal || panel.indicators.shown || wizard.active || tutorial.running || launcher.drawerShown ? overlay.z + 1 : overlay.z - 1
332 objectName: "greeterLoader"
334 anchors.topMargin: panel.panelHeight
336 if (shell.mode != "shell") {
337 if (screenWindow.primary) return integratedGreeter;
338 return secondaryGreeter;
340 return Qt.createComponent(Qt.resolvedUrl("Greeter/ShimGreeter.qml"));
343 item.objectName = "greeter"
348 id: integratedGreeter
351 enabled: panel.indicators.fullyClosed // hides OSK when panel is open
352 hides: [launcher, panel.indicators]
353 tabletMode: shell.usageScenario != "phone"
354 forcedUnlock: wizard.active || shell.mode === "full-shell"
355 background: wallpaperResolver.cachedBackground
356 hasCustomBackground: wallpaperResolver.hasCustomBackground
357 allowFingerprint: !dialogs.hasActiveDialog &&
358 !notifications.topmostIsFullscreen &&
359 !panel.indicators.shown
361 // avoid overlapping with Launcher's edge drag area
362 // FIXME: Fix TouchRegistry & friends and remove this workaround
363 // Issue involves launcher's DDA getting disabled on a long
365 dragHandleLeftMargin: launcher.available ? launcher.dragAreaWidth + 1 : 0
372 if (!tutorial.running) {
377 onEmergencyCall: startLockedApp("dialer-app")
384 hides: [launcher, panel.indicators]
389 // See powerConnection for why this is useful
390 id: showGreeterDelayed
402 if (greeter.locked && callManager.hasCalls && greeter.lockedApp !== "dialer-app") {
403 // We just received an incoming call while locked. The
404 // indicator will have already launched dialer-app for us, but
405 // there is a race between "hasCalls" changing and the dialer
406 // starting up. So in case we lose that race, we'll start/
407 // focus the dialer ourselves here too. Even if the indicator
408 // didn't launch the dialer for some reason (or maybe a call
409 // started via some other means), if an active call is
410 // happening, we want to be in the dialer.
411 startLockedApp("dialer-app")
421 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
422 !callManager.hasCalls && !wizard.active) {
423 // We don't want to simply call greeter.showNow() here, because
424 // that will take too long. Qt will delay button event
425 // handling until the greeter is done loading and may think the
426 // user held down the power button the whole time, leading to a
427 // power dialog being shown. Instead, delay showing the
428 // greeter until we've finished handling the event. We could
429 // make the greeter load asynchronously instead, but that
430 // introduces a whole host of timing issues, especially with
431 // its animations. So this is simpler.
432 showGreeterDelayed.start();
437 function showHome() {
438 greeter.notifyUserRequestedApp();
440 if (shell.mode === "greeter") {
441 SessionBroadcast.requestHomeShown(AccountsService.user);
443 var animate = !LightDMService.greeter.active && !stages.shown;
444 dash.setCurrentScope(0, animate, false);
445 ApplicationManager.requestFocusApplication("unity8-dash");
458 anchors.fill: parent //because this draws indicator menus
461 available: tutorial.panelEnabled
462 && ((!greeter || !greeter.locked) || AccountsService.enableIndicatorsWhileLocked)
463 && (!greeter || !greeter.hasLockedApp)
464 && !shell.waitingOnGreeter
465 && settings.enableIndicatorMenu
466 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
468 minimizedPanelHeight: units.gu(3)
469 expandedPanelHeight: units.gu(7)
471 indicatorsModel: Indicators.IndicatorsModel {
472 // tablet and phone both use the same profile
473 // FIXME: use just "phone" for greeter too, but first fix
474 // greeter app launching to either load the app inside the
475 // greeter or tell the session to load the app. This will
476 // involve taking the url-dispatcher dbus name and using
477 // SessionBroadcast to tell the session.
478 profile: shell.mode === "greeter" ? "desktop_greeter" : "phone"
479 Component.onCompleted: load();
484 greeterShown: greeter.shown
487 readonly property bool focusedSurfaceIsFullscreen: topLevelSurfaceList.focusedWindow
488 ? topLevelSurfaceList.focusedWindow.state === Mir.FullscreenState
490 fullscreenMode: (focusedSurfaceIsFullscreen && !LightDMService.greeter.active && launcher.progress == 0)
491 || greeter.hasLockedApp
492 locked: greeter && greeter.active
497 objectName: "launcher"
499 anchors.top: parent.top
500 anchors.topMargin: inverted ? 0 : panel.panelHeight
501 anchors.bottom: parent.bottom
503 dragAreaWidth: shell.edgeSize
504 available: tutorial.launcherEnabled
505 && (!greeter.locked || AccountsService.enableLauncherWhileLocked)
506 && !greeter.hasLockedApp
507 && !shell.waitingOnGreeter
508 && settings.enableLauncher
509 inverted: shell.usageScenario !== "desktop"
510 superPressed: physicalKeysMapper.superPressed
511 superTabPressed: physicalKeysMapper.superTabPressed
512 panelWidth: units.gu(settings.launcherWidth)
513 lockedVisible: shell.usageScenario == "desktop" && !settings.autohideLauncher && !panel.fullscreenMode
514 blurSource: greeter.shown ? greeter : stages
515 topPanelHeight: panel.panelHeight
516 drawerEnabled: !greeter.shown
518 onShowDashHome: showHome()
519 onLauncherApplicationSelected: {
520 greeter.notifyUserRequestedApp();
521 shell.activateApplication(appId);
525 panel.indicators.hide()
535 shortcut: Qt.MetaModifier | Qt.Key_A
537 launcher.openDrawer(true);
541 shortcut: Qt.AltModifier | Qt.Key_F1
543 launcher.openForKeyboardNavigation();
547 shortcut: Qt.MetaModifier | Qt.Key_0
549 if (LauncherModel.get(9)) {
550 activateApplication(LauncherModel.get(9).appId);
557 shortcut: Qt.MetaModifier | (Qt.Key_1 + index)
559 if (LauncherModel.get(index)) {
560 activateApplication(LauncherModel.get(index).appId);
567 KeyboardShortcutsOverlay {
568 objectName: "shortcutsOverlay"
569 enabled: launcher.shortcutHintsShown && width < parent.width - (launcher.lockedVisible ? launcher.panelWidth : 0) - padding
570 && height < parent.height - padding - panel.panelHeight
571 anchors.centerIn: parent
572 anchors.horizontalCenterOffset: launcher.lockedVisible ? launcher.panelWidth/2 : 0
573 anchors.verticalCenterOffset: panel.panelHeight/2
575 opacity: enabled ? 0.95 : 0
577 Behavior on opacity {
578 UbuntuNumberAnimation {}
584 objectName: "tutorial"
587 paused: callManager.hasCalls || !greeter || greeter.active ||
589 delayed: dialogs.hasActiveDialog || notifications.hasNotification ||
590 inputMethod.visible ||
591 (launcher.shown && !launcher.lockedVisible) ||
592 panel.indicators.shown || stage.rightEdgeDragProgress > 0
593 usageScenario: shell.usageScenario
594 lastInputTimestamp: inputFilter.lastInputTimestamp
604 deferred: shell.mode === "greeter"
606 function unlockWhenDoneWithWizard() {
608 Connectivity.unlockAllModems();
612 Component.onCompleted: unlockWhenDoneWithWizard()
613 onActiveChanged: unlockWhenDoneWithWizard()
616 MouseArea { // modal notifications prevent interacting with other contents
618 visible: notifications.useModal
625 model: NotificationBackend.Model
627 hasMouse: shell.hasMouse
628 background: wallpaperResolver.cachedBackground
630 y: topmostIsFullscreen ? 0 : panel.panelHeight
631 height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
636 when: overlay.width <= units.gu(60)
638 target: notifications
639 anchors.left: parent.left
640 anchors.right: parent.right
645 when: overlay.width > units.gu(60)
647 target: notifications
648 anchors.left: undefined
649 anchors.right: parent.right
651 PropertyChanges { target: notifications; width: units.gu(38) }
659 objectName: "dialogs"
662 usageScenario: shell.usageScenario
664 shutdownFadeOutRectangle.enabled = true;
665 shutdownFadeOutRectangle.visible = true;
666 shutdownFadeOut.start();
671 target: SessionBroadcast
672 onShowHome: if (shell.mode !== "greeter") showHome()
677 objectName: "urlDispatcher"
678 active: shell.mode === "greeter"
679 onUrlRequested: shell.activateURL(url)
686 GlobalShortcut { shortcut: Qt.Key_Print; onTriggered: itemGrabber.capture(shell) }
689 ignoreUnknownSignals: true
690 onItemSnapshotRequested: itemGrabber.capture(item)
695 id: cursorHidingTimer
697 running: panel.focusedSurfaceIsFullscreen && cursor.opacity > 0
698 onTriggered: cursor.opacity = 0;
703 visible: shell.hasMouse
706 topBoundaryOffset: panel.panelHeight
708 confiningItem: stage.itemConfiningMouseCursor
712 readonly property var previewRectangle: stage.previewRectangle.target &&
713 stage.previewRectangle.target.dragging ?
714 stage.previewRectangle : null
716 onPushedLeftBoundary: {
717 if (buttons === Qt.NoButton) {
718 launcher.pushEdge(amount);
719 } else if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeMaximizedLeftRight) {
720 previewRectangle.maximizeLeft(amount);
724 onPushedRightBoundary: {
725 if (buttons === Qt.NoButton) {
726 stage.pushRightEdge(amount);
727 } else if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeMaximizedLeftRight) {
728 previewRectangle.maximizeRight(amount);
732 onPushedTopBoundary: {
733 if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeMaximized) {
734 previewRectangle.maximize(amount);
737 onPushedTopLeftCorner: {
738 if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeCornerMaximized) {
739 previewRectangle.maximizeTopLeft(amount);
742 onPushedTopRightCorner: {
743 if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeCornerMaximized) {
744 previewRectangle.maximizeTopRight(amount);
747 onPushedBottomLeftCorner: {
748 if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeCornerMaximized) {
749 previewRectangle.maximizeBottomLeft(amount);
752 onPushedBottomRightCorner: {
753 if (buttons === Qt.LeftButton && previewRectangle && previewRectangle.target.canBeCornerMaximized) {
754 previewRectangle.maximizeBottomRight(amount);
758 if (previewRectangle) {
759 previewRectangle.stop();
767 Behavior on opacity { UbuntuNumberAnimation {} }
770 // non-visual objects
772 focusedSurface: topLevelSurfaceList.focusedWindow ? topLevelSurfaceList.focusedWindow.surface : null
777 id: shutdownFadeOutRectangle
784 NumberAnimation on opacity {
789 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
790 DBusUnitySessionService.shutdown();
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list