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
31import SessionBroadcast 0.1
40import Unity.Notifications 1.0 as NotificationBackend
41import Unity.Session 0.1
42import Unity.DashCommunicator 0.1
43import Unity.Indicators 0.1 as Indicators
45import WindowManager 0.1
51 // to be set from outside
52 property int orientationAngle: 0
53 property int orientation
54 property Orientations orientations
55 property real nativeWidth
56 property real nativeHeight
57 property alias indicatorAreaShowProgress: panel.indicatorAreaShowProgress
58 property bool beingResized
59 property string usageScenario: "phone" // supported values: "phone", "tablet" or "desktop"
60 property string mode: "full-greeter"
61 property alias oskEnabled: inputMethod.enabled
62 function updateFocusedAppOrientation() {
63 applicationsDisplayLoader.item.updateFocusedAppOrientation();
65 function updateFocusedAppOrientationAnimated() {
66 applicationsDisplayLoader.item.updateFocusedAppOrientationAnimated();
68 property bool hasMouse: false
70 // to be read from outside
71 readonly property int mainAppWindowOrientationAngle:
72 applicationsDisplayLoader.item ? applicationsDisplayLoader.item.mainAppWindowOrientationAngle : 0
74 readonly property bool orientationChangesEnabled: panel.indicators.fullyClosed
75 && (applicationsDisplayLoader.item && applicationsDisplayLoader.item.orientationChangesEnabled)
76 && (!greeter || !greeter.animating)
78 readonly property bool showingGreeter: greeter && greeter.shown
80 property bool startingUp: true
81 Timer { id: finishStartUpTimer; interval: 500; onTriggered: startingUp = false }
83 property int supportedOrientations: {
85 // Ensure we don't rotate during start up
86 return Qt.PrimaryOrientation;
87 } else if (greeter && greeter.shown) {
88 return Qt.PrimaryOrientation;
89 } else if (applicationsDisplayLoader.item) {
90 return shell.orientations.map(applicationsDisplayLoader.item.supportedOrientations);
93 return Qt.PortraitOrientation
94 | Qt.LandscapeOrientation
95 | Qt.InvertedPortraitOrientation
96 | Qt.InvertedLandscapeOrientation;
100 readonly property var mainApp:
101 applicationsDisplayLoader.item ? applicationsDisplayLoader.item.mainApp : null
104 _onMainAppChanged(mainApp.appId);
108 target: ApplicationManager
110 if (shell.mainApp && shell.mainApp.appId === appId) {
111 _onMainAppChanged(appId);
115 function _onMainAppChanged(appId) {
116 if (wizard.active && appId != "" && appId != "unity8-dash") {
117 // If this happens on first boot, we may be in edge
118 // tutorial or wizard while receiving a call. But a call
119 // is more important than wizard so just bail out of those.
124 if (appId === "dialer-app" && callManager.hasCalls && greeter.locked) {
125 // If we are in the middle of a call, make dialer lockedApp and show it.
126 // This can happen if user backs out of dialer back to greeter, then
127 // launches dialer again.
128 greeter.lockedApp = appId;
130 greeter.notifyAppFocusRequested(appId);
132 panel.indicators.hide();
136 // For autopilot consumption
137 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
139 // Disable everything while greeter is waiting, so that the user can't swipe
140 // the greeter or launcher until we know whether the session is locked.
141 enabled: greeter && !greeter.waiting
143 property real edgeSize: units.gu(settings.edgeDragWidth)
146 id: wallpaperResolver
150 readonly property alias greeter: greeterLoader.item
152 function activateApplication(appId) {
153 if (ApplicationManager.findApplication(appId)) {
154 ApplicationManager.requestFocusApplication(appId);
156 ApplicationManager.startApplication(appId);
160 function startLockedApp(app) {
161 if (greeter.locked) {
162 greeter.lockedApp = app;
164 shell.activateApplication(app);
168 target: LauncherModel
169 property: "applicationManager"
170 value: ApplicationManager
173 Component.onCompleted: {
174 theme.name = "Ubuntu.Components.Themes.SuruDark"
175 finishStartUpTimer.start();
178 LightDM{id: lightDM} // Provide backend access
181 indicators: panel.indicators
186 objectName: "dashCommunicator"
190 id: physicalKeysMapper
191 objectName: "physicalKeysMapper"
193 onPowerKeyLongPressed: dialogs.showPowerDialog();
194 onVolumeDownTriggered: volumeControl.volumeDown();
195 onVolumeUpTriggered: volumeControl.volumeUp();
196 onScreenshotTriggered: itemGrabber.capture(shell);
200 // dummy shortcut to force creation of GlobalShortcutRegistry before WindowInputFilter
205 Keys.onPressed: physicalKeysMapper.onKeyPressed(event, lastInputTimestamp);
206 Keys.onReleased: physicalKeysMapper.onKeyReleased(event, lastInputTimestamp);
210 objectName: "windowInputMonitor"
211 onHomeKeyActivated: {
212 // Ignore when greeter is active, to avoid pocket presses
213 if (!greeter.active) {
218 onTouchBegun: { cursor.opacity = 0; }
220 // move the (hidden) cursor to the last known touch position
221 var mappedCoords = mapFromItem(null, pos.x, pos.y);
222 cursor.x = mappedCoords.x;
223 cursor.y = mappedCoords.y;
229 schema.id: "com.canonical.Unity8"
236 height: parent.height
238 TopLevelSurfaceList {
239 id: topLevelSurfaceList
240 objectName: "topLevelSurfaceList"
241 applicationsModel: ApplicationManager
245 id: applicationsDisplayLoader
246 objectName: "applicationsDisplayLoader"
249 // When we have a locked app, we only want to show that one app.
250 // FIXME: do this in a less traumatic way. We currently only allow
251 // locked apps in phone mode (see FIXME in Lockscreen component in
252 // this same file). When that changes, we need to do something
253 // nicer here. But this code is currently just to prevent a
254 // theoretical attack where user enters lockedApp mode, then makes
255 // the screen larger (maybe connects to monitor) and tries to enter
258 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
260 : shell.usageScenario
261 readonly property string qmlComponent: {
262 if(shell.mode === "greeter") {
263 return "Stages/ShimStage.qml"
264 } else if (applicationsDisplayLoader.usageScenario === "phone") {
265 return "Stages/PhoneStage.qml";
266 } else if (applicationsDisplayLoader.usageScenario === "tablet") {
267 return "Stages/TabletStage.qml";
269 return "Stages/DesktopStage.qml";
272 // TODO: Ensure the current stage is destroyed before the new one gets loaded.
273 // Currently the new one will get loaded while the old is still hanging
274 // around for a bit, which might lead to conflicts where both stages
275 // change the model simultaneously.
276 onQmlComponentChanged: {
277 if (item) item.stageAboutToBeUnloaded();
278 source = qmlComponent;
281 property bool interactive: (!greeter || !greeter.shown)
282 && panel.indicators.fullyClosed
283 && launcher.progress == 0
284 && !notifications.useModal
286 onInteractiveChanged: { if (interactive) { focus = true; } }
289 target: applicationsDisplayLoader.item
294 target: applicationsDisplayLoader.item
295 property: "objectName"
299 target: applicationsDisplayLoader.item
300 property: "dragAreaWidth"
301 value: shell.edgeSize
304 target: applicationsDisplayLoader.item
305 property: "maximizedAppTopMargin"
306 // Not just using panel.panelHeight as that changes depending on the focused app.
307 value: panel.indicators.minimizedPanelHeight
310 target: applicationsDisplayLoader.item
311 property: "interactive"
312 value: applicationsDisplayLoader.interactive
315 target: applicationsDisplayLoader.item
316 property: "spreadEnabled"
317 value: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
320 target: applicationsDisplayLoader.item
321 property: "inverseProgress"
322 value: greeter && greeter.locked ? 0 : launcher.progress
325 target: applicationsDisplayLoader.item
326 property: "shellOrientationAngle"
327 value: shell.orientationAngle
330 target: applicationsDisplayLoader.item
331 property: "shellOrientation"
332 value: shell.orientation
335 target: applicationsDisplayLoader.item
336 property: "orientations"
337 value: shell.orientations
340 target: applicationsDisplayLoader.item
341 property: "background"
342 value: wallpaperResolver.background
345 target: applicationsDisplayLoader.item
346 property: "nativeWidth"
347 value: shell.nativeWidth
350 target: applicationsDisplayLoader.item
351 property: "nativeHeight"
352 value: shell.nativeHeight
355 target: applicationsDisplayLoader.item
356 property: "beingResized"
357 value: shell.beingResized
360 target: applicationsDisplayLoader.item
361 property: "keepDashRunning"
362 value: launcher.shown || launcher.dashSwipe
365 target: applicationsDisplayLoader.item
366 property: "suspended"
370 target: applicationsDisplayLoader.item
371 property: "altTabPressed"
372 value: physicalKeysMapper.altTabPressed
375 target: applicationsDisplayLoader.item
376 property: "leftMargin"
377 value: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
380 target: applicationsDisplayLoader.item
381 property: "applicationManager"
382 value: ApplicationManager
385 target: applicationsDisplayLoader.item
386 property: "topLevelSurfaceList"
387 value: topLevelSurfaceList
394 objectName: "inputMethod"
397 topMargin: panel.panelHeight
398 leftMargin: launcher.lockedVisible ? launcher.panelWidth : 0
400 z: notifications.useModal || panel.indicators.shown || wizard.active || tutorial.running ? overlay.z + 1 : overlay.z - 1
406 anchors.topMargin: panel.panelHeight
407 sourceComponent: shell.mode != "shell" ? integratedGreeter :
408 Qt.createComponent(Qt.resolvedUrl("Greeter/ShimGreeter.qml"));
410 item.objectName = "greeter"
415 id: integratedGreeter
418 hides: [launcher, panel.indicators]
419 tabletMode: shell.usageScenario != "phone"
420 launcherOffset: launcher.progress
421 forcedUnlock: wizard.active
422 background: wallpaperResolver.background
424 // avoid overlapping with Launcher's edge drag area
425 // FIXME: Fix TouchRegistry & friends and remove this workaround
426 // Issue involves launcher's DDA getting disabled on a long
428 dragHandleLeftMargin: launcher.available ? launcher.dragAreaWidth + 1 : 0
435 if (!tutorial.running) {
440 onEmergencyCall: startLockedApp("dialer-app")
445 // See powerConnection for why this is useful
446 id: showGreeterDelayed
458 if (greeter.locked && callManager.hasCalls && greeter.lockedApp !== "dialer-app") {
459 // We just received an incoming call while locked. The
460 // indicator will have already launched dialer-app for us, but
461 // there is a race between "hasCalls" changing and the dialer
462 // starting up. So in case we lose that race, we'll start/
463 // focus the dialer ourselves here too. Even if the indicator
464 // didn't launch the dialer for some reason (or maybe a call
465 // started via some other means), if an active call is
466 // happening, we want to be in the dialer.
467 startLockedApp("dialer-app")
477 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
478 !callManager.hasCalls && !wizard.active) {
479 // We don't want to simply call greeter.showNow() here, because
480 // that will take too long. Qt will delay button event
481 // handling until the greeter is done loading and may think the
482 // user held down the power button the whole time, leading to a
483 // power dialog being shown. Instead, delay showing the
484 // greeter until we've finished handling the event. We could
485 // make the greeter load asynchronously instead, but that
486 // introduces a whole host of timing issues, especially with
487 // its animations. So this is simpler.
488 showGreeterDelayed.start();
493 function showHome() {
494 greeter.notifyUserRequestedApp("unity8-dash");
496 var animate = !lightDM.greeter.active && !stages.shown
497 dash.setCurrentScope(0, animate, false)
498 ApplicationManager.requestFocusApplication("unity8-dash")
501 function showDash() {
502 if (greeter.notifyShowingDashFromDrag()) {
506 if (!greeter.locked && ApplicationManager.focusedApplicationId != "unity8-dash") {
507 ApplicationManager.requestFocusApplication("unity8-dash")
521 anchors.fill: parent //because this draws indicator menus
524 available: tutorial.panelEnabled
525 && ((!greeter || !greeter.locked) || AccountsService.enableIndicatorsWhileLocked)
526 && (!greeter || !greeter.hasLockedApp)
527 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
529 minimizedPanelHeight: units.gu(3)
530 expandedPanelHeight: units.gu(7)
532 indicatorsModel: Indicators.IndicatorsModel {
533 // tablet and phone both use the same profile
535 Component.onCompleted: load();
540 greeterShown: greeter.shown
543 readonly property bool focusedSurfaceIsFullscreen: MirFocusController.focusedSurface
544 ? MirFocusController.focusedSurface.state === Mir.FullscreenState
546 fullscreenMode: (focusedSurfaceIsFullscreen && !lightDM.greeter.active && launcher.progress == 0)
547 || greeter.hasLockedApp
548 locked: greeter && greeter.active
553 objectName: "launcher"
556 * Since the Dash doesn't have the same controll over surfaces that the
557 * Shell does, it can't slowly move the scope out of the way, as the shell
558 * does with apps, and the dash is show instantly. This allows for some
559 * leeway and prevents accidental home swipes.
561 readonly property real offset: shell.focusedApplicationId == "unity8-dash" ? units.gu(12) : 0
562 readonly property bool dashSwipe: progress > offset
564 anchors.top: parent.top
565 anchors.topMargin: inverted ? 0 : panel.panelHeight
566 anchors.bottom: parent.bottom
568 dragAreaWidth: shell.edgeSize
569 available: tutorial.launcherEnabled
570 && (!greeter.locked || AccountsService.enableLauncherWhileLocked)
571 && !greeter.hasLockedApp
572 inverted: shell.usageScenario !== "desktop"
573 superPressed: physicalKeysMapper.superPressed
574 superTabPressed: physicalKeysMapper.superTabPressed
575 panelWidth: units.gu(settings.launcherWidth)
576 lockedVisible: shell.usageScenario == "desktop" && !settings.autohideLauncher && !panel.fullscreenMode
578 onShowDashHome: showHome()
580 onDashSwipeChanged: {
582 dash.setCurrentScope(0, false, true)
585 onLauncherApplicationSelected: {
586 greeter.notifyUserRequestedApp(appId);
587 shell.activateApplication(appId);
591 panel.indicators.hide()
596 applicationsDisplayLoader.focus = true;
601 shortcut: Qt.AltModifier | Qt.Key_F1
603 launcher.openForKeyboardNavigation();
607 shortcut: Qt.MetaModifier | Qt.Key_0
609 if (LauncherModel.get(9)) {
610 activateApplication(LauncherModel.get(9).appId);
617 shortcut: Qt.MetaModifier | (Qt.Key_1 + index)
619 if (LauncherModel.get(index)) {
620 activateApplication(LauncherModel.get(index).appId);
629 objectName: "tutorial"
632 paused: callManager.hasCalls || greeter.shown
633 keyboardVisible: inputMethod.state === "shown"
634 usageScenario: shell.usageScenario
635 lastInputTimestamp: inputFilter.lastInputTimestamp
638 stage: applicationsDisplayLoader.item
646 function unlockWhenDoneWithWizard() {
648 Connectivity.unlockAllModems();
652 Component.onCompleted: unlockWhenDoneWithWizard()
653 onActiveChanged: unlockWhenDoneWithWizard()
656 MouseArea { // modal notifications prevent interacting with other contents
658 visible: notifications.useModal
665 model: NotificationBackend.Model
667 hasMouse: shell.hasMouse
668 background: wallpaperResolver.background
670 y: topmostIsFullscreen ? 0 : panel.panelHeight
671 height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
676 when: overlay.width <= units.gu(60)
678 target: notifications
679 anchors.left: parent.left
680 anchors.right: parent.right
685 when: overlay.width > units.gu(60)
687 target: notifications
688 anchors.left: undefined
689 anchors.right: parent.right
691 PropertyChanges { target: notifications; width: units.gu(38) }
699 objectName: "dialogs"
702 usageScenario: shell.usageScenario
704 shutdownFadeOutRectangle.enabled = true;
705 shutdownFadeOutRectangle.visible = true;
706 shutdownFadeOut.start();
711 target: SessionBroadcast
712 onShowHome: showHome()
719 GlobalShortcut { shortcut: Qt.Key_Print; onTriggered: itemGrabber.capture(shell) }
721 target: applicationsDisplayLoader.item
722 ignoreUnknownSignals: true
723 onItemSnapshotRequested: itemGrabber.capture(item)
729 visible: shell.hasMouse
732 onPushedLeftBoundary: {
733 if (buttons === Qt.NoButton) {
734 launcher.pushEdge(amount);
738 onPushedRightBoundary: {
739 if (buttons === Qt.NoButton && applicationsDisplayLoader.item
740 && applicationsDisplayLoader.item.pushRightEdge) {
741 applicationsDisplayLoader.item.pushRightEdge(amount);
745 onMouseMoved: { cursor.opacity = 1; }
752 id: shutdownFadeOutRectangle
759 NumberAnimation on opacity {
764 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
765 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