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 theme.name: "Ubuntu.Components.Themes.SuruDark"
53 // to be set from outside
54 property int orientationAngle: 0
55 property int orientation
56 property Orientations orientations
57 property real nativeWidth
58 property real nativeHeight
59 property alias indicatorAreaShowProgress: panel.indicatorAreaShowProgress
60 property bool beingResized
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 applicationsDisplayLoader.item.updateFocusedAppOrientation();
67 function updateFocusedAppOrientationAnimated() {
68 applicationsDisplayLoader.item.updateFocusedAppOrientationAnimated();
70 property bool hasMouse: false
72 // to be read from outside
73 readonly property int mainAppWindowOrientationAngle:
74 applicationsDisplayLoader.item ? applicationsDisplayLoader.item.mainAppWindowOrientationAngle : 0
76 readonly property bool orientationChangesEnabled: panel.indicators.fullyClosed
77 && (applicationsDisplayLoader.item && applicationsDisplayLoader.item.orientationChangesEnabled)
78 && (!greeter || !greeter.animating)
80 readonly property bool showingGreeter: greeter && greeter.shown
82 property bool startingUp: true
83 Timer { id: finishStartUpTimer; interval: 500; onTriggered: startingUp = false }
85 property int supportedOrientations: {
87 // Ensure we don't rotate during start up
88 return Qt.PrimaryOrientation;
89 } else if (greeter && greeter.shown) {
90 return Qt.PrimaryOrientation;
91 } else if (applicationsDisplayLoader.item) {
92 return shell.orientations.map(applicationsDisplayLoader.item.supportedOrientations);
95 return Qt.PortraitOrientation
96 | Qt.LandscapeOrientation
97 | Qt.InvertedPortraitOrientation
98 | Qt.InvertedLandscapeOrientation;
102 readonly property var mainApp:
103 applicationsDisplayLoader.item ? applicationsDisplayLoader.item.mainApp : null
106 _onMainAppChanged(mainApp.appId);
110 target: ApplicationManager
112 if (shell.mainApp && shell.mainApp.appId === appId) {
113 _onMainAppChanged(appId);
117 function _onMainAppChanged(appId) {
118 if (wizard.active && appId != "" && appId != "unity8-dash") {
119 // If this happens on first boot, we may be in the
120 // wizard while receiving a call. But a call is more
121 // important than the wizard so just bail out of it.
125 if (appId === "dialer-app" && callManager.hasCalls && greeter.locked) {
126 // If we are in the middle of a call, make dialer lockedApp and show it.
127 // This can happen if user backs out of dialer back to greeter, then
128 // launches dialer again.
129 greeter.lockedApp = appId;
131 greeter.notifyAppFocusRequested(appId);
133 panel.indicators.hide();
137 // For autopilot consumption
138 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
140 // Disable everything while greeter is waiting, so that the user can't swipe
141 // the greeter or launcher until we know whether the session is locked.
142 enabled: greeter && !greeter.waiting
144 property real edgeSize: units.gu(settings.edgeDragWidth)
147 id: wallpaperResolver
151 readonly property alias greeter: greeterLoader.item
153 function activateApplication(appId) {
154 if (ApplicationManager.findApplication(appId)) {
155 ApplicationManager.requestFocusApplication(appId);
157 ApplicationManager.startApplication(appId);
161 function startLockedApp(app) {
162 if (greeter.locked) {
163 greeter.lockedApp = app;
165 shell.activateApplication(app);
169 target: LauncherModel
170 property: "applicationManager"
171 value: ApplicationManager
174 Component.onCompleted: {
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;
224 cursor.mouseNeverMoved = false;
230 schema.id: "com.canonical.Unity8"
237 height: parent.height
239 TopLevelSurfaceList {
240 id: topLevelSurfaceList
241 objectName: "topLevelSurfaceList"
242 applicationsModel: ApplicationManager
246 id: applicationsDisplayLoader
247 objectName: "applicationsDisplayLoader"
250 // When we have a locked app, we only want to show that one app.
251 // FIXME: do this in a less traumatic way. We currently only allow
252 // locked apps in phone mode (see FIXME in Lockscreen component in
253 // this same file). When that changes, we need to do something
254 // nicer here. But this code is currently just to prevent a
255 // theoretical attack where user enters lockedApp mode, then makes
256 // the screen larger (maybe connects to monitor) and tries to enter
259 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
261 : shell.usageScenario
262 readonly property string qmlComponent: {
263 if(shell.mode === "greeter") {
264 return "Stages/ShimStage.qml"
265 } else if (applicationsDisplayLoader.usageScenario === "phone") {
266 return "Stages/PhoneStage.qml";
267 } else if (applicationsDisplayLoader.usageScenario === "tablet") {
268 return "Stages/TabletStage.qml";
270 return "Stages/DesktopStage.qml";
273 // TODO: Ensure the current stage is destroyed before the new one gets loaded.
274 // Currently the new one will get loaded while the old is still hanging
275 // around for a bit, which might lead to conflicts where both stages
276 // change the model simultaneously.
277 onQmlComponentChanged: {
278 if (item) item.stageAboutToBeUnloaded();
279 source = qmlComponent;
282 property bool interactive: (!greeter || !greeter.shown)
283 && panel.indicators.fullyClosed
284 && launcher.progress == 0
285 && !notifications.useModal
287 onInteractiveChanged: { if (interactive) { focus = true; } }
290 target: applicationsDisplayLoader.item
295 target: applicationsDisplayLoader.item
296 property: "objectName"
300 target: applicationsDisplayLoader.item
301 property: "dragAreaWidth"
302 value: shell.edgeSize
305 target: applicationsDisplayLoader.item
306 property: "maximizedAppTopMargin"
307 // Not just using panel.panelHeight as that changes depending on the focused app.
308 value: panel.indicators.minimizedPanelHeight
311 target: applicationsDisplayLoader.item
312 property: "interactive"
313 value: applicationsDisplayLoader.interactive
316 target: applicationsDisplayLoader.item
317 property: "spreadEnabled"
318 value: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
321 target: applicationsDisplayLoader.item
322 property: "inverseProgress"
323 value: !greeter || greeter.locked || !tutorial.launcherLongSwipeEnabled ? 0 : launcher.progress
326 target: applicationsDisplayLoader.item
327 property: "shellOrientationAngle"
328 value: shell.orientationAngle
331 target: applicationsDisplayLoader.item
332 property: "shellOrientation"
333 value: shell.orientation
336 target: applicationsDisplayLoader.item
337 property: "orientations"
338 value: shell.orientations
341 target: applicationsDisplayLoader.item
342 property: "background"
343 value: wallpaperResolver.background
346 target: applicationsDisplayLoader.item
347 property: "nativeWidth"
348 value: shell.nativeWidth
351 target: applicationsDisplayLoader.item
352 property: "nativeHeight"
353 value: shell.nativeHeight
356 target: applicationsDisplayLoader.item
357 property: "beingResized"
358 value: shell.beingResized
361 target: applicationsDisplayLoader.item
362 property: "keepDashRunning"
363 value: launcher.shown || launcher.dashSwipe
366 target: applicationsDisplayLoader.item
367 property: "suspended"
371 target: applicationsDisplayLoader.item
372 property: "altTabPressed"
373 value: physicalKeysMapper.altTabPressed
376 target: applicationsDisplayLoader.item
377 property: "leftMargin"
378 value: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
381 target: applicationsDisplayLoader.item
382 property: "applicationManager"
383 value: ApplicationManager
386 target: applicationsDisplayLoader.item
387 property: "topLevelSurfaceList"
388 value: topLevelSurfaceList
391 target: applicationsDisplayLoader.item
392 property: "oskEnabled"
393 value: shell.oskEnabled
400 objectName: "inputMethod"
403 topMargin: panel.panelHeight
404 leftMargin: launcher.lockedVisible ? launcher.panelWidth : 0
406 z: notifications.useModal || panel.indicators.shown || wizard.active || tutorial.running ? overlay.z + 1 : overlay.z - 1
412 anchors.topMargin: panel.panelHeight
413 sourceComponent: shell.mode != "shell" ? integratedGreeter :
414 Qt.createComponent(Qt.resolvedUrl("Greeter/ShimGreeter.qml"));
416 item.objectName = "greeter"
421 id: integratedGreeter
424 hides: [launcher, panel.indicators]
425 tabletMode: shell.usageScenario != "phone"
426 launcherOffset: launcher.progress
427 forcedUnlock: wizard.active || shell.mode === "full-shell"
428 background: wallpaperResolver.background
429 allowFingerprint: !dialogs.hasActiveDialog &&
430 !notifications.topmostIsFullscreen &&
431 !panel.indicators.shown
433 // avoid overlapping with Launcher's edge drag area
434 // FIXME: Fix TouchRegistry & friends and remove this workaround
435 // Issue involves launcher's DDA getting disabled on a long
437 dragHandleLeftMargin: launcher.available ? launcher.dragAreaWidth + 1 : 0
444 if (!tutorial.running) {
449 onEmergencyCall: startLockedApp("dialer-app")
454 // See powerConnection for why this is useful
455 id: showGreeterDelayed
467 if (greeter.locked && callManager.hasCalls && greeter.lockedApp !== "dialer-app") {
468 // We just received an incoming call while locked. The
469 // indicator will have already launched dialer-app for us, but
470 // there is a race between "hasCalls" changing and the dialer
471 // starting up. So in case we lose that race, we'll start/
472 // focus the dialer ourselves here too. Even if the indicator
473 // didn't launch the dialer for some reason (or maybe a call
474 // started via some other means), if an active call is
475 // happening, we want to be in the dialer.
476 startLockedApp("dialer-app")
486 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
487 !callManager.hasCalls && !wizard.active) {
488 // We don't want to simply call greeter.showNow() here, because
489 // that will take too long. Qt will delay button event
490 // handling until the greeter is done loading and may think the
491 // user held down the power button the whole time, leading to a
492 // power dialog being shown. Instead, delay showing the
493 // greeter until we've finished handling the event. We could
494 // make the greeter load asynchronously instead, but that
495 // introduces a whole host of timing issues, especially with
496 // its animations. So this is simpler.
497 showGreeterDelayed.start();
502 function showHome() {
503 greeter.notifyUserRequestedApp("unity8-dash");
505 var animate = !lightDM.greeter.active && !stages.shown
506 dash.setCurrentScope(0, animate, false)
507 ApplicationManager.requestFocusApplication("unity8-dash")
510 function showDash() {
511 if (greeter.notifyShowingDashFromDrag()) {
515 if (!greeter.locked && tutorial.launcherLongSwipeEnabled
516 && ApplicationManager.focusedApplicationId != "unity8-dash") {
517 ApplicationManager.requestFocusApplication("unity8-dash")
531 anchors.fill: parent //because this draws indicator menus
534 available: tutorial.panelEnabled
535 && ((!greeter || !greeter.locked) || AccountsService.enableIndicatorsWhileLocked)
536 && (!greeter || !greeter.hasLockedApp)
537 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
539 minimizedPanelHeight: units.gu(3)
540 expandedPanelHeight: units.gu(7)
542 indicatorsModel: Indicators.IndicatorsModel {
543 // tablet and phone both use the same profile
545 Component.onCompleted: load();
550 greeterShown: greeter.shown
553 readonly property bool focusedSurfaceIsFullscreen: MirFocusController.focusedSurface
554 ? MirFocusController.focusedSurface.state === Mir.FullscreenState
556 fullscreenMode: (focusedSurfaceIsFullscreen && !lightDM.greeter.active && launcher.progress == 0)
557 || greeter.hasLockedApp
558 locked: greeter && greeter.active
563 objectName: "launcher"
566 * Since the Dash doesn't have the same controll over surfaces that the
567 * Shell does, it can't slowly move the scope out of the way, as the shell
568 * does with apps, and the dash is show instantly. This allows for some
569 * leeway and prevents accidental home swipes.
571 readonly property real offset: shell.focusedApplicationId == "unity8-dash" ? units.gu(12) : 0
572 readonly property bool dashSwipe: progress > offset
574 anchors.top: parent.top
575 anchors.topMargin: inverted ? 0 : panel.panelHeight
576 anchors.bottom: parent.bottom
578 dragAreaWidth: shell.edgeSize
579 available: tutorial.launcherEnabled
580 && (!greeter.locked || AccountsService.enableLauncherWhileLocked)
581 && !greeter.hasLockedApp
582 inverted: shell.usageScenario !== "desktop"
583 superPressed: physicalKeysMapper.superPressed
584 superTabPressed: physicalKeysMapper.superTabPressed
585 panelWidth: units.gu(settings.launcherWidth)
586 lockedVisible: shell.usageScenario == "desktop" && !settings.autohideLauncher && !panel.fullscreenMode
588 onShowDashHome: showHome()
590 onDashSwipeChanged: {
592 dash.setCurrentScope(0, false, true)
595 onLauncherApplicationSelected: {
596 greeter.notifyUserRequestedApp(appId);
597 shell.activateApplication(appId);
601 panel.indicators.hide()
606 applicationsDisplayLoader.focus = true;
611 shortcut: Qt.AltModifier | Qt.Key_F1
613 launcher.openForKeyboardNavigation();
617 shortcut: Qt.MetaModifier | Qt.Key_0
619 if (LauncherModel.get(9)) {
620 activateApplication(LauncherModel.get(9).appId);
627 shortcut: Qt.MetaModifier | (Qt.Key_1 + index)
629 if (LauncherModel.get(index)) {
630 activateApplication(LauncherModel.get(index).appId);
637 KeyboardShortcutsOverlay {
638 objectName: "shortcutsOverlay"
639 enabled: launcher.shortcutHintsShown && width < parent.width - (launcher.lockedVisible ? launcher.panelWidth : 0) - padding
640 && height < parent.height - padding - panel.panelHeight
641 anchors.centerIn: parent
642 anchors.horizontalCenterOffset: launcher.lockedVisible ? launcher.panelWidth/2 : 0
643 anchors.verticalCenterOffset: panel.panelHeight/2
645 opacity: enabled ? 0.95 : 0
647 Behavior on opacity {
648 UbuntuNumberAnimation {}
654 objectName: "tutorial"
657 paused: callManager.hasCalls || !greeter || greeter.shown ||
659 delayed: dialogs.hasActiveDialog || notifications.hasNotification ||
660 inputMethod.state === "shown" ||
661 (launcher.shown && !launcher.lockedVisible) ||
662 panel.indicators.shown || stage.dragProgress > 0
663 usageScenario: shell.usageScenario
664 lastInputTimestamp: inputFilter.lastInputTimestamp
667 stage: applicationsDisplayLoader.item
675 function unlockWhenDoneWithWizard() {
677 Connectivity.unlockAllModems();
681 Component.onCompleted: unlockWhenDoneWithWizard()
682 onActiveChanged: unlockWhenDoneWithWizard()
685 MouseArea { // modal notifications prevent interacting with other contents
687 visible: notifications.useModal
694 model: NotificationBackend.Model
696 hasMouse: shell.hasMouse
697 background: wallpaperResolver.background
699 y: topmostIsFullscreen ? 0 : panel.panelHeight
700 height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
705 when: overlay.width <= units.gu(60)
707 target: notifications
708 anchors.left: parent.left
709 anchors.right: parent.right
714 when: overlay.width > units.gu(60)
716 target: notifications
717 anchors.left: undefined
718 anchors.right: parent.right
720 PropertyChanges { target: notifications; width: units.gu(38) }
728 objectName: "dialogs"
731 usageScenario: shell.usageScenario
733 shutdownFadeOutRectangle.enabled = true;
734 shutdownFadeOutRectangle.visible = true;
735 shutdownFadeOut.start();
740 target: SessionBroadcast
741 onShowHome: showHome()
748 GlobalShortcut { shortcut: Qt.Key_Print; onTriggered: itemGrabber.capture(shell) }
750 target: applicationsDisplayLoader.item
751 ignoreUnknownSignals: true
752 onItemSnapshotRequested: itemGrabber.capture(item)
758 visible: shell.hasMouse
761 property bool mouseNeverMoved: true
763 target: cursor; property: "x"; value: shell.width / 2
764 when: cursor.mouseNeverMoved && cursor.visible
767 target: cursor; property: "y"; value: shell.height / 2
768 when: cursor.mouseNeverMoved && cursor.visible
771 onPushedLeftBoundary: {
772 if (buttons === Qt.NoButton) {
773 launcher.pushEdge(amount);
777 onPushedRightBoundary: {
778 if (buttons === Qt.NoButton && applicationsDisplayLoader.item
779 && applicationsDisplayLoader.item.pushRightEdge) {
780 applicationsDisplayLoader.item.pushRightEdge(amount);
785 mouseNeverMoved = false;
794 id: shutdownFadeOutRectangle
801 NumberAnimation on opacity {
806 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
807 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