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
262 source: "Stages/DesktopStage.qml"
263 readonly property string qmlComponent: {
264 if(shell.mode === "greeter") {
265 return "Stages/ShimStage.qml"
266 } else if (applicationsDisplayLoader.usageScenario === "phone") {
267 return "Stages/PhoneStage.qml";
268 } else if (applicationsDisplayLoader.usageScenario === "tablet") {
269 return "Stages/TabletStage.qml";
271 return "Stages/DesktopStage.qml";
275 property bool interactive: (!greeter || !greeter.shown)
276 && panel.indicators.fullyClosed
277 && launcher.progress == 0
278 && !notifications.useModal
280 onInteractiveChanged: { if (interactive) { focus = true; } }
283 target: applicationsDisplayLoader.item
285 value: applicationsDisplayLoader.usageScenario == "phone" ? "staged" : "windowed"
288 target: applicationsDisplayLoader.item
293 target: applicationsDisplayLoader.item
294 property: "objectName"
298 target: applicationsDisplayLoader.item
299 property: "dragAreaWidth"
300 value: shell.edgeSize
303 target: applicationsDisplayLoader.item
304 property: "maximizedAppTopMargin"
305 // Not just using panel.panelHeight as that changes depending on the focused app.
306 value: panel.indicators.minimizedPanelHeight
309 target: applicationsDisplayLoader.item
310 property: "interactive"
311 value: applicationsDisplayLoader.interactive
314 target: applicationsDisplayLoader.item
315 property: "spreadEnabled"
316 value: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
319 target: applicationsDisplayLoader.item
320 property: "inverseProgress"
321 value: greeter && greeter.locked ? 0 : launcher.progress
324 target: applicationsDisplayLoader.item
325 property: "shellOrientationAngle"
326 value: shell.orientationAngle
329 target: applicationsDisplayLoader.item
330 property: "shellOrientation"
331 value: shell.orientation
334 target: applicationsDisplayLoader.item
335 property: "orientations"
336 value: shell.orientations
339 target: applicationsDisplayLoader.item
340 property: "background"
341 value: wallpaperResolver.background
344 target: applicationsDisplayLoader.item
345 property: "nativeWidth"
346 value: shell.nativeWidth
349 target: applicationsDisplayLoader.item
350 property: "nativeHeight"
351 value: shell.nativeHeight
354 target: applicationsDisplayLoader.item
355 property: "beingResized"
356 value: shell.beingResized
359 target: applicationsDisplayLoader.item
360 property: "keepDashRunning"
361 value: launcher.shown || launcher.dashSwipe
364 target: applicationsDisplayLoader.item
365 property: "suspended"
369 target: applicationsDisplayLoader.item
370 property: "altTabPressed"
371 value: physicalKeysMapper.altTabPressed
374 target: applicationsDisplayLoader.item
375 property: "leftMargin"
376 value: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
379 target: applicationsDisplayLoader.item
380 property: "applicationManager"
381 value: ApplicationManager
384 target: applicationsDisplayLoader.item
385 property: "topLevelSurfaceList"
386 value: topLevelSurfaceList
393 objectName: "inputMethod"
396 topMargin: panel.panelHeight
397 leftMargin: launcher.lockedVisible ? launcher.panelWidth : 0
399 z: notifications.useModal || panel.indicators.shown || wizard.active || tutorial.running ? overlay.z + 1 : overlay.z - 1
405 anchors.topMargin: panel.panelHeight
406 sourceComponent: shell.mode != "shell" ? integratedGreeter :
407 Qt.createComponent(Qt.resolvedUrl("Greeter/ShimGreeter.qml"));
409 item.objectName = "greeter"
414 id: integratedGreeter
417 hides: [launcher, panel.indicators]
418 tabletMode: shell.usageScenario != "phone"
419 launcherOffset: launcher.progress
420 forcedUnlock: wizard.active
421 background: wallpaperResolver.background
423 // avoid overlapping with Launcher's edge drag area
424 // FIXME: Fix TouchRegistry & friends and remove this workaround
425 // Issue involves launcher's DDA getting disabled on a long
427 dragHandleLeftMargin: launcher.available ? launcher.dragAreaWidth + 1 : 0
434 if (!tutorial.running) {
439 onEmergencyCall: startLockedApp("dialer-app")
444 // See powerConnection for why this is useful
445 id: showGreeterDelayed
457 if (greeter.locked && callManager.hasCalls && greeter.lockedApp !== "dialer-app") {
458 // We just received an incoming call while locked. The
459 // indicator will have already launched dialer-app for us, but
460 // there is a race between "hasCalls" changing and the dialer
461 // starting up. So in case we lose that race, we'll start/
462 // focus the dialer ourselves here too. Even if the indicator
463 // didn't launch the dialer for some reason (or maybe a call
464 // started via some other means), if an active call is
465 // happening, we want to be in the dialer.
466 startLockedApp("dialer-app")
476 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
477 !callManager.hasCalls && !wizard.active) {
478 // We don't want to simply call greeter.showNow() here, because
479 // that will take too long. Qt will delay button event
480 // handling until the greeter is done loading and may think the
481 // user held down the power button the whole time, leading to a
482 // power dialog being shown. Instead, delay showing the
483 // greeter until we've finished handling the event. We could
484 // make the greeter load asynchronously instead, but that
485 // introduces a whole host of timing issues, especially with
486 // its animations. So this is simpler.
487 showGreeterDelayed.start();
492 function showHome() {
493 greeter.notifyUserRequestedApp("unity8-dash");
495 var animate = !lightDM.greeter.active && !stages.shown
496 dash.setCurrentScope(0, animate, false)
497 ApplicationManager.requestFocusApplication("unity8-dash")
500 function showDash() {
501 if (greeter.notifyShowingDashFromDrag()) {
505 if (!greeter.locked && ApplicationManager.focusedApplicationId != "unity8-dash") {
506 ApplicationManager.requestFocusApplication("unity8-dash")
520 anchors.fill: parent //because this draws indicator menus
523 available: tutorial.panelEnabled
524 && ((!greeter || !greeter.locked) || AccountsService.enableIndicatorsWhileLocked)
525 && (!greeter || !greeter.hasLockedApp)
526 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
528 minimizedPanelHeight: units.gu(3)
529 expandedPanelHeight: units.gu(7)
531 indicatorsModel: Indicators.IndicatorsModel {
532 // tablet and phone both use the same profile
534 Component.onCompleted: load();
539 greeterShown: greeter.shown
542 readonly property bool focusedSurfaceIsFullscreen: MirFocusController.focusedSurface
543 ? MirFocusController.focusedSurface.state === Mir.FullscreenState
545 fullscreenMode: (focusedSurfaceIsFullscreen && !lightDM.greeter.active && launcher.progress == 0)
546 || greeter.hasLockedApp
547 locked: greeter && greeter.active
552 objectName: "launcher"
554 readonly property bool dashSwipe: progress > 0
556 anchors.top: parent.top
557 anchors.topMargin: inverted ? 0 : panel.panelHeight
558 anchors.bottom: parent.bottom
560 dragAreaWidth: shell.edgeSize
561 available: tutorial.launcherEnabled
562 && (!greeter.locked || AccountsService.enableLauncherWhileLocked)
563 && !greeter.hasLockedApp
564 inverted: shell.usageScenario !== "desktop"
565 superPressed: physicalKeysMapper.superPressed
566 superTabPressed: physicalKeysMapper.superTabPressed
567 panelWidth: units.gu(settings.launcherWidth)
568 lockedVisible: shell.usageScenario == "desktop" && !settings.autohideLauncher && !panel.fullscreenMode
570 onShowDashHome: showHome()
572 onDashSwipeChanged: {
574 dash.setCurrentScope(0, false, true)
577 onLauncherApplicationSelected: {
578 greeter.notifyUserRequestedApp(appId);
579 shell.activateApplication(appId);
583 panel.indicators.hide()
588 applicationsDisplayLoader.focus = true;
593 shortcut: Qt.AltModifier | Qt.Key_F1
595 launcher.openForKeyboardNavigation();
599 shortcut: Qt.MetaModifier | Qt.Key_0
601 if (LauncherModel.get(9)) {
602 activateApplication(LauncherModel.get(9).appId);
609 shortcut: Qt.MetaModifier | (Qt.Key_1 + index)
611 if (LauncherModel.get(index)) {
612 activateApplication(LauncherModel.get(index).appId);
621 objectName: "tutorial"
624 paused: callManager.hasCalls || greeter.shown
625 keyboardVisible: inputMethod.state === "shown"
626 usageScenario: shell.usageScenario
627 lastInputTimestamp: inputFilter.lastInputTimestamp
630 stage: applicationsDisplayLoader.item
638 function unlockWhenDoneWithWizard() {
640 Connectivity.unlockAllModems();
644 Component.onCompleted: unlockWhenDoneWithWizard()
645 onActiveChanged: unlockWhenDoneWithWizard()
648 MouseArea { // modal notifications prevent interacting with other contents
650 visible: notifications.useModal
657 model: NotificationBackend.Model
659 hasMouse: shell.hasMouse
660 background: wallpaperResolver.background
662 y: topmostIsFullscreen ? 0 : panel.panelHeight
663 height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
668 when: overlay.width <= units.gu(60)
670 target: notifications
671 anchors.left: parent.left
672 anchors.right: parent.right
677 when: overlay.width > units.gu(60)
679 target: notifications
680 anchors.left: undefined
681 anchors.right: parent.right
683 PropertyChanges { target: notifications; width: units.gu(38) }
691 objectName: "dialogs"
694 usageScenario: shell.usageScenario
696 shutdownFadeOutRectangle.enabled = true;
697 shutdownFadeOutRectangle.visible = true;
698 shutdownFadeOut.start();
703 target: SessionBroadcast
704 onShowHome: showHome()
711 GlobalShortcut { shortcut: Qt.Key_Print; onTriggered: itemGrabber.capture(shell) }
713 target: applicationsDisplayLoader.item
714 ignoreUnknownSignals: true
715 onItemSnapshotRequested: itemGrabber.capture(item)
721 visible: shell.hasMouse
724 onPushedLeftBoundary: {
725 if (buttons === Qt.NoButton) {
726 launcher.pushEdge(amount);
730 onPushedRightBoundary: {
731 if (buttons === Qt.NoButton && applicationsDisplayLoader.item
732 && applicationsDisplayLoader.item.pushRightEdge) {
733 applicationsDisplayLoader.item.pushRightEdge(amount);
737 onMouseMoved: { cursor.opacity = 1; }
744 id: shutdownFadeOutRectangle
751 NumberAnimation on opacity {
756 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
757 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