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 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();
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
144 readonly property alias greeter: greeterLoader.item
146 function activateApplication(appId) {
147 if (ApplicationManager.findApplication(appId)) {
148 ApplicationManager.requestFocusApplication(appId);
150 ApplicationManager.startApplication(appId);
154 function startLockedApp(app) {
155 if (greeter.locked) {
156 greeter.lockedApp = app;
158 shell.activateApplication(app);
162 target: LauncherModel
163 property: "applicationManager"
164 value: ApplicationManager
167 Component.onCompleted: {
168 finishStartUpTimer.start();
173 indicators: panel.indicators
178 objectName: "dashCommunicator"
182 id: physicalKeysMapper
183 objectName: "physicalKeysMapper"
185 onPowerKeyLongPressed: dialogs.showPowerDialog();
186 onVolumeDownTriggered: volumeControl.volumeDown();
187 onVolumeUpTriggered: volumeControl.volumeUp();
188 onScreenshotTriggered: itemGrabber.capture(shell);
192 // dummy shortcut to force creation of GlobalShortcutRegistry before WindowInputFilter
197 Keys.onPressed: physicalKeysMapper.onKeyPressed(event, lastInputTimestamp);
198 Keys.onReleased: physicalKeysMapper.onKeyReleased(event, lastInputTimestamp);
202 objectName: "windowInputMonitor"
203 onHomeKeyActivated: {
204 // Ignore when greeter is active, to avoid pocket presses
205 if (!greeter.active) {
210 onTouchBegun: { cursor.opacity = 0; }
212 // move the (hidden) cursor to the last known touch position
213 var mappedCoords = mapFromItem(null, pos.x, pos.y);
214 cursor.x = mappedCoords.x;
215 cursor.y = mappedCoords.y;
216 cursor.mouseNeverMoved = false;
222 schema.id: "com.canonical.Unity8"
229 height: parent.height
231 TopLevelSurfaceList {
232 id: topLevelSurfaceList
233 objectName: "topLevelSurfaceList"
234 applicationsModel: ApplicationManager
243 dragAreaWidth: shell.edgeSize
244 background: wallpaperResolver.background
246 applicationManager: ApplicationManager
247 topLevelSurfaceList: topLevelSurfaceList
249 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
251 : shell.usageScenario
253 mode: usageScenario == "phone" ? "staged"
254 : usageScenario == "tablet" ? "stagedWithSideStage"
257 shellOrientation: shell.orientation
258 shellOrientationAngle: shell.orientationAngle
259 orientations: shell.orientations
260 nativeWidth: shell.nativeWidth
261 nativeHeight: shell.nativeHeight
262 // TODO: Is this still needed? Didn't come across it. Needs checking before merging
263 beingResized: shell.beingResized
265 // TODO: Is this still needed? Didn't come across it. Needs checking before merging
266 // Not just using panel.panelHeight as that changes depending on the focused app.
267 maximizedAppTopMargin: panel.indicators.minimizedPanelHeight
269 interactive: (!greeter || !greeter.shown)
270 && panel.indicators.fullyClosed
271 && launcher.progress == 0
272 && !notifications.useModal
274 onInteractiveChanged: { if (interactive) { focus = true; } }
276 // TODO: This is not implemented yet in the new stage...
277 spreadEnabled: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
278 keepDashRunning: launcher.shown || launcher.dashSwipe
279 suspended: greeter.shown
280 leftMargin: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
282 // TODO: this is not implemented yet in the new stage...
283 inverseProgress: !greeter || greeter.locked || !tutorial.launcherLongSwipeEnabled ? 0 : launcher.progress
284 altTabPressed: physicalKeysMapper.altTabPressed
285 oskEnabled: shell.oskEnabled
291 objectName: "inputMethod"
294 topMargin: panel.panelHeight
295 leftMargin: launcher.lockedVisible ? launcher.panelWidth : 0
297 z: notifications.useModal || panel.indicators.shown || wizard.active || tutorial.running ? overlay.z + 1 : overlay.z - 1
302 objectName: "greeterLoader"
304 anchors.topMargin: panel.panelHeight
305 sourceComponent: shell.mode != "shell" ? integratedGreeter :
306 Qt.createComponent(Qt.resolvedUrl("Greeter/ShimGreeter.qml"));
308 item.objectName = "greeter"
313 id: integratedGreeter
316 hides: [launcher, panel.indicators]
317 tabletMode: shell.usageScenario != "phone"
318 launcherOffset: launcher.progress
319 forcedUnlock: wizard.active || shell.mode === "full-shell"
320 background: wallpaperResolver.background
321 allowFingerprint: !dialogs.hasActiveDialog &&
322 !notifications.topmostIsFullscreen &&
323 !panel.indicators.shown
325 // avoid overlapping with Launcher's edge drag area
326 // FIXME: Fix TouchRegistry & friends and remove this workaround
327 // Issue involves launcher's DDA getting disabled on a long
329 dragHandleLeftMargin: launcher.available ? launcher.dragAreaWidth + 1 : 0
336 if (!tutorial.running) {
341 onEmergencyCall: startLockedApp("dialer-app")
346 // See powerConnection for why this is useful
347 id: showGreeterDelayed
359 if (greeter.locked && callManager.hasCalls && greeter.lockedApp !== "dialer-app") {
360 // We just received an incoming call while locked. The
361 // indicator will have already launched dialer-app for us, but
362 // there is a race between "hasCalls" changing and the dialer
363 // starting up. So in case we lose that race, we'll start/
364 // focus the dialer ourselves here too. Even if the indicator
365 // didn't launch the dialer for some reason (or maybe a call
366 // started via some other means), if an active call is
367 // happening, we want to be in the dialer.
368 startLockedApp("dialer-app")
378 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
379 !callManager.hasCalls && !wizard.active) {
380 // We don't want to simply call greeter.showNow() here, because
381 // that will take too long. Qt will delay button event
382 // handling until the greeter is done loading and may think the
383 // user held down the power button the whole time, leading to a
384 // power dialog being shown. Instead, delay showing the
385 // greeter until we've finished handling the event. We could
386 // make the greeter load asynchronously instead, but that
387 // introduces a whole host of timing issues, especially with
388 // its animations. So this is simpler.
389 showGreeterDelayed.start();
394 function showHome() {
395 greeter.notifyUserRequestedApp("unity8-dash");
397 var animate = !LightDMService.greeter.active && !stages.shown
398 dash.setCurrentScope(0, animate, false)
399 ApplicationManager.requestFocusApplication("unity8-dash")
402 function showDash() {
403 if (greeter.notifyShowingDashFromDrag()) {
407 if (!greeter.locked && tutorial.launcherLongSwipeEnabled
408 && ApplicationManager.focusedApplicationId != "unity8-dash") {
409 ApplicationManager.requestFocusApplication("unity8-dash")
423 anchors.fill: parent //because this draws indicator menus
426 available: tutorial.panelEnabled
427 && ((!greeter || !greeter.locked) || AccountsService.enableIndicatorsWhileLocked)
428 && (!greeter || !greeter.hasLockedApp)
429 && !shell.waitingOnGreeter
430 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
432 minimizedPanelHeight: units.gu(3)
433 expandedPanelHeight: units.gu(7)
435 indicatorsModel: Indicators.IndicatorsModel {
436 // tablet and phone both use the same profile
437 // FIXME: use just "phone" for greeter too, but first fix
438 // greeter app launching to either load the app inside the
439 // greeter or tell the session to load the app. This will
440 // involve taking the url-dispatcher dbus name and using
441 // SessionBroadcast to tell the session.
442 profile: shell.mode === "greeter" ? "desktop_greeter" : "phone"
443 Component.onCompleted: load();
448 greeterShown: greeter.shown
451 readonly property bool focusedSurfaceIsFullscreen: MirFocusController.focusedSurface
452 ? MirFocusController.focusedSurface.state === Mir.FullscreenState
454 fullscreenMode: (focusedSurfaceIsFullscreen && !LightDMService.greeter.active && launcher.progress == 0)
455 || greeter.hasLockedApp
456 locked: greeter && greeter.active
461 objectName: "launcher"
464 * Since the Dash doesn't have the same controll over surfaces that the
465 * Shell does, it can't slowly move the scope out of the way, as the shell
466 * does with apps, and the dash is show instantly. This allows for some
467 * leeway and prevents accidental home swipes.
469 readonly property real offset: shell.focusedApplicationId == "unity8-dash" ? units.gu(12) : 0
470 readonly property bool dashSwipe: progress > offset
472 anchors.top: parent.top
473 anchors.topMargin: inverted ? 0 : panel.panelHeight
474 anchors.bottom: parent.bottom
476 dragAreaWidth: shell.edgeSize
477 available: tutorial.launcherEnabled
478 && (!greeter.locked || AccountsService.enableLauncherWhileLocked)
479 && !greeter.hasLockedApp
480 && !shell.waitingOnGreeter
481 inverted: shell.usageScenario !== "desktop"
482 superPressed: physicalKeysMapper.superPressed
483 superTabPressed: physicalKeysMapper.superTabPressed
484 panelWidth: units.gu(settings.launcherWidth)
485 lockedVisible: shell.usageScenario == "desktop" && !settings.autohideLauncher && !panel.fullscreenMode
487 onShowDashHome: showHome()
489 onDashSwipeChanged: {
491 dash.setCurrentScope(0, false, true)
494 onLauncherApplicationSelected: {
495 greeter.notifyUserRequestedApp(appId);
496 shell.activateApplication(appId);
500 panel.indicators.hide()
510 shortcut: Qt.AltModifier | Qt.Key_F1
512 launcher.openForKeyboardNavigation();
516 shortcut: Qt.MetaModifier | Qt.Key_0
518 if (LauncherModel.get(9)) {
519 activateApplication(LauncherModel.get(9).appId);
526 shortcut: Qt.MetaModifier | (Qt.Key_1 + index)
528 if (LauncherModel.get(index)) {
529 activateApplication(LauncherModel.get(index).appId);
536 KeyboardShortcutsOverlay {
537 objectName: "shortcutsOverlay"
538 enabled: launcher.shortcutHintsShown && width < parent.width - (launcher.lockedVisible ? launcher.panelWidth : 0) - padding
539 && height < parent.height - padding - panel.panelHeight
540 anchors.centerIn: parent
541 anchors.horizontalCenterOffset: launcher.lockedVisible ? launcher.panelWidth/2 : 0
542 anchors.verticalCenterOffset: panel.panelHeight/2
544 opacity: enabled ? 0.95 : 0
546 Behavior on opacity {
547 UbuntuNumberAnimation {}
553 objectName: "tutorial"
556 paused: callManager.hasCalls || !greeter || greeter.shown ||
558 delayed: dialogs.hasActiveDialog || notifications.hasNotification ||
559 inputMethod.visible ||
560 (launcher.shown && !launcher.lockedVisible) ||
561 panel.indicators.shown || stage.dragProgress > 0
562 usageScenario: shell.usageScenario
563 lastInputTimestamp: inputFilter.lastInputTimestamp
573 deferred: shell.mode === "greeter"
575 function unlockWhenDoneWithWizard() {
577 Connectivity.unlockAllModems();
581 Component.onCompleted: unlockWhenDoneWithWizard()
582 onActiveChanged: unlockWhenDoneWithWizard()
585 MouseArea { // modal notifications prevent interacting with other contents
587 visible: notifications.useModal
594 model: NotificationBackend.Model
596 hasMouse: shell.hasMouse
597 background: wallpaperResolver.background
599 y: topmostIsFullscreen ? 0 : panel.panelHeight
600 height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
605 when: overlay.width <= units.gu(60)
607 target: notifications
608 anchors.left: parent.left
609 anchors.right: parent.right
614 when: overlay.width > units.gu(60)
616 target: notifications
617 anchors.left: undefined
618 anchors.right: parent.right
620 PropertyChanges { target: notifications; width: units.gu(38) }
628 objectName: "dialogs"
631 usageScenario: shell.usageScenario
633 shutdownFadeOutRectangle.enabled = true;
634 shutdownFadeOutRectangle.visible = true;
635 shutdownFadeOut.start();
640 target: SessionBroadcast
641 onShowHome: showHome()
648 GlobalShortcut { shortcut: Qt.Key_Print; onTriggered: itemGrabber.capture(shell) }
651 ignoreUnknownSignals: true
652 onItemSnapshotRequested: itemGrabber.capture(item)
658 visible: shell.hasMouse
661 property bool mouseNeverMoved: true
663 target: cursor; property: "x"; value: shell.width / 2
664 when: cursor.mouseNeverMoved && cursor.visible
667 target: cursor; property: "y"; value: shell.height / 2
668 when: cursor.mouseNeverMoved && cursor.visible
673 onPushedLeftBoundary: {
674 if (buttons === Qt.NoButton) {
675 launcher.pushEdge(amount);
679 onPushedRightBoundary: {
680 if (buttons === Qt.NoButton) {
681 stage.pushRightEdge(amount);
686 mouseNeverMoved = false;
695 id: shutdownFadeOutRectangle
702 NumberAnimation on opacity {
707 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
708 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