2 * Copyright (C) 2013 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.0
19import AccountsService 0.1
21import Unity.Application 0.1
22import Ubuntu.Components 0.1
23import Ubuntu.Components.Popups 1.0
24import Ubuntu.Gestures 0.1
25import Ubuntu.Telephony 0.1 as Telephony
26import Unity.Connectivity 0.1
27import Unity.Launcher 0.1
29import LightDM 0.1 as LightDM
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
48 // Disable everything while greeter is waiting, so that the user can't swipe
49 // the greeter or launcher until we know whether the session is locked.
50 enabled: !greeter.waiting
52 // this is only here to select the width / height of the window if not running fullscreen
53 property bool tablet: false
54 width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
55 height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
57 property real edgeSize: units.gu(2)
58 property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
59 property url background: asImageTester.status == Image.Ready ? asImageTester.source
60 : gsImageTester.status == Image.Ready ? gsImageTester.source : defaultBackground
61 readonly property real panelHeight: panel.panelHeight
63 property bool sideStageEnabled: shell.width >= units.gu(100)
64 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
66 property int orientation
67 readonly property int deviceOrientationAngle: Screen.angleBetween(Screen.primaryOrientation, Screen.orientation)
68 onDeviceOrientationAngleChanged: {
69 if (!OrientationLock.enabled) {
70 orientation = Screen.orientation;
73 readonly property bool orientationLockEnabled: OrientationLock.enabled
74 onOrientationLockEnabledChanged: {
75 if (orientationLockEnabled) {
76 OrientationLock.savedOrientation = Screen.orientation;
78 orientation = Screen.orientation;
82 // This is _only_ used to expose the property to autopilot tests
83 readonly property string testShellMode: shellMode
85 function activateApplication(appId) {
86 if (ApplicationManager.findApplication(appId)) {
87 ApplicationManager.requestFocusApplication(appId);
89 var execFlags = shell.sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
90 ApplicationManager.startApplication(appId, execFlags);
94 function startLockedApp(app) {
96 greeter.lockedApp = app;
98 shell.activateApplication(app);
101 // This is a dummy image to detect if the custom AS set wallpaper loads successfully.
104 source: AccountsService.backgroundFile != undefined && AccountsService.backgroundFile.length > 0 ? AccountsService.backgroundFile : ""
112 id: backgroundSettings
113 objectName: "backgroundSettings"
114 schema.id: "org.gnome.desktop.background"
117 // This is a dummy image to detect if the custom GSettings set wallpaper loads successfully.
120 source: backgroundSettings.pictureUri != undefined && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : ""
128 id: usageModeSettings
129 schema.id: "com.canonical.Unity8"
133 target: LauncherModel
134 property: "applicationManager"
135 value: ApplicationManager
138 Component.onCompleted: {
139 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
140 if (ApplicationManager.count > 0) {
141 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
143 if (orientationLockEnabled) {
144 orientation = OrientationLock.savedOrientation;
154 objectName: "dashCommunicator"
158 id: physicalKeysMapper
160 onPowerKeyLongPressed: dialogs.showPowerDialog()
161 onVolumeDownTriggered: volumeControl.volumeDown();
162 onVolumeUpTriggered: volumeControl.volumeUp();
163 onScreenshotTriggered: screenGrabber.capture();
169 enabled: Powerd.status === Powerd.On
173 target: ApplicationManager
174 property: "forceDashActive"
175 value: launcher.shown || launcher.dashSwipe
179 Keys.onPressed: physicalKeysMapper.onKeyPressed(event);
180 Keys.onReleased: physicalKeysMapper.onKeyReleased(event);
184 onActivated: { launcher.fadeOut(); shell.showHome(); }
192 height: parent.height
195 target: ApplicationManager
197 // This signal is also fired when we try to focus the current app
198 // again. We rely on this!
199 onFocusedApplicationIdChanged: {
200 var appId = ApplicationManager.focusedApplicationId;
202 if (tutorial.running && appId != "" && appId != "unity8-dash") {
203 // If this happens on first boot, we may be in edge
204 // tutorial or wizard while receiving a call. But a call
205 // is more important than wizard so just bail out of those.
210 if (appId === "dialer-app" && callManager.hasCalls && greeter.locked) {
211 // If we are in the middle of a call, make dialer lockedApp and show it.
212 // This can happen if user backs out of dialer back to greeter, then
213 // launches dialer again.
214 greeter.lockedApp = appId;
216 greeter.notifyAppFocused(appId);
218 panel.indicators.hide();
221 onApplicationAdded: {
227 id: applicationsDisplayLoader
228 objectName: "applicationsDisplayLoader"
231 // When we have a locked app, we only want to show that one app.
232 // FIXME: do this in a less traumatic way. We currently only allow
233 // locked apps in phone mode (see FIXME in Lockscreen component in
234 // this same file). When that changes, we need to do something
235 // nicer here. But this code is currently just to prevent a
236 // theoretical attack where user enters lockedApp mode, then makes
237 // the screen larger (maybe connects to monitor) and tries to enter
239 property bool tabletMode: shell.sideStageEnabled && !greeter.hasLockedApp
240 source: usageModeSettings.usageMode === "Windowed" ? "Stages/DesktopStage.qml"
241 : tabletMode ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml"
243 property bool interactive: tutorial.spreadEnabled
245 && panel.indicators.fullyClosed
246 && launcher.progress == 0
247 && !notifications.useModal
249 onInteractiveChanged: { if (interactive) { focus = true; } }
252 target: applicationsDisplayLoader.item
253 property: "objectName"
257 target: applicationsDisplayLoader.item
258 property: "dragAreaWidth"
259 value: shell.edgeSize
262 target: applicationsDisplayLoader.item
263 property: "maximizedAppTopMargin"
264 // Not just using panel.panelHeight as that changes depending on the focused app.
265 value: panel.indicators.minimizedPanelHeight + units.dp(2) // dp(2) for orange line
268 target: applicationsDisplayLoader.item
269 property: "interactive"
270 value: applicationsDisplayLoader.interactive
273 target: applicationsDisplayLoader.item
274 property: "spreadEnabled"
275 value: tutorial.spreadEnabled && !greeter.hasLockedApp
278 target: applicationsDisplayLoader.item
279 property: "inverseProgress"
280 value: greeter.locked ? 0 : launcher.progress
283 target: applicationsDisplayLoader.item
284 property: "orientation"
285 value: shell.orientation
288 target: applicationsDisplayLoader.item
289 property: "background"
290 value: shell.background
296 objectName: "tutorial"
298 active: AccountsService.demoEdges
299 paused: LightDM.Greeter.active
302 edgeSize: shell.edgeSize
304 // EdgeDragAreas don't work with mice. So to avoid trapping the user,
305 // we'll tell the tutorial to avoid using them on the Desktop. The
306 // Desktop doesn't use the same spread design anyway. The tutorial is
307 // all a bit of a placeholder on non-phone form factors right now.
308 // When the design team gives us more guidance, we can do something
310 // TODO: use DeviceConfiguration instead of checking source
311 useEdgeDragArea: applicationsDisplayLoader.source != Qt.resolvedUrl("Stages/DesktopStage.qml")
314 AccountsService.demoEdges = false;
315 active = false; // for immediate response / if AS is having problems
322 objectName: "inputMethod"
323 anchors { fill: parent; topMargin: panel.panelHeight }
324 z: notifications.useModal || panel.indicators.shown || wizard.active ? overlay.z + 1 : overlay.z - 1
328 target: SurfaceManager
330 if (surface.type == MirSurfaceItem.InputMethod) {
331 inputMethod.surface = surface;
335 onSurfaceDestroyed: {
336 if (inputMethod.surface == surface) {
337 inputMethod.surface = null;
338 surface.parent = null;
340 if (!surface.parent) {
341 // there's no one displaying it. delete it right away
347 target: SessionManager
349 if (!session.parentSession && !session.application) {
350 // nothing is using it. delete it right away
358 objectName: "greeter"
360 hides: [launcher, panel.indicators]
361 tabletMode: shell.sideStageEnabled
362 launcherOffset: launcher.progress
363 forcedUnlock: tutorial.running
364 background: shell.background
367 anchors.topMargin: panel.panelHeight
369 // avoid overlapping with Launcher's edge drag area
370 // FIXME: Fix TouchRegistry & friends and remove this workaround
371 // Issue involves launcher's DDA getting disabled on a long
373 dragHandleLeftMargin: launcher.available ? launcher.dragAreaWidth + 1 : 0
380 if (!tutorial.running) {
385 onEmergencyCall: startLockedApp("dialer-app")
388 // See powerConnection for why this is useful
389 id: showGreeterDelayed
397 target: ApplicationManager
398 property: "suspended"
408 if (greeter.locked && callManager.hasCalls && greeter.lockedApp !== "dialer-app") {
409 // We just received an incoming call while locked. The
410 // indicator will have already launched dialer-app for us, but
411 // there is a race between "hasCalls" changing and the dialer
412 // starting up. So in case we lose that race, we'll start/
413 // focus the dialer ourselves here too. Even if the indicator
414 // didn't launch the dialer for some reason (or maybe a call
415 // started via some other means), if an active call is
416 // happening, we want to be in the dialer.
417 startLockedApp("dialer-app")
427 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
428 !callManager.hasCalls && !tutorial.running) {
429 // We don't want to simply call greeter.showNow() here, because
430 // that will take too long. Qt will delay button event
431 // handling until the greeter is done loading and may think the
432 // user held down the power button the whole time, leading to a
433 // power dialog being shown. Instead, delay showing the
434 // greeter until we've finished handling the event. We could
435 // make the greeter load asynchronously instead, but that
436 // introduces a whole host of timing issues, especially with
437 // its animations. So this is simpler.
438 showGreeterDelayed.start();
443 function showHome() {
444 if (tutorial.running) {
448 greeter.notifyAboutToFocusApp("unity8-dash");
450 var animate = !LightDM.Greeter.active && !stages.shown
451 dash.setCurrentScope(0, animate, false)
452 ApplicationManager.requestFocusApplication("unity8-dash")
455 function showDash() {
456 if (greeter.notifyShowingDashFromDrag()) {
460 if (!greeter.locked && ApplicationManager.focusedApplicationId != "unity8-dash") {
461 ApplicationManager.requestFocusApplication("unity8-dash")
475 anchors.fill: parent //because this draws indicator menus
478 available: tutorial.panelEnabled
479 && (!greeter.locked || AccountsService.enableIndicatorsWhileLocked)
480 && !greeter.hasLockedApp
481 contentEnabled: tutorial.panelContentEnabled
482 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
484 minimizedPanelHeight: units.gu(3)
485 expandedPanelHeight: units.gu(7)
487 indicatorsModel: Indicators.IndicatorsModel {
488 // TODO: This should be sourced by device type (e.g. "desktop", "tablet", "phone"...)
489 profile: indicatorProfile
490 Component.onCompleted: load()
494 greeterShown: greeter.shown
497 property bool topmostApplicationIsFullscreen:
498 ApplicationManager.focusedApplicationId &&
499 ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
501 fullscreenMode: (topmostApplicationIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
502 || greeter.hasLockedApp
507 objectName: "launcher"
509 readonly property bool dashSwipe: progress > 0
511 anchors.top: parent.top
512 anchors.topMargin: inverted ? 0 : panel.panelHeight
513 anchors.bottom: parent.bottom
515 dragAreaWidth: shell.edgeSize
516 available: tutorial.launcherEnabled
517 && (!greeter.locked || AccountsService.enableLauncherWhileLocked)
518 && !greeter.hasLockedApp
519 inverted: usageModeSettings.usageMode === "Staged"
520 shadeBackground: !tutorial.running
522 onShowDashHome: showHome()
524 onDashSwipeChanged: {
526 dash.setCurrentScope(0, false, true)
529 onLauncherApplicationSelected: {
530 if (!tutorial.running) {
531 greeter.notifyAboutToFocusApp(appId);
532 shell.activateApplication(appId)
537 panel.indicators.hide()
546 background: shell.background
548 function unlockWhenDoneWithWizard() {
550 Connectivity.unlockAllModems();
554 Component.onCompleted: unlockWhenDoneWithWizard()
555 onActiveChanged: unlockWhenDoneWithWizard()
559 id: modalNotificationBackground
561 visible: notifications.useModal && (notifications.state == "narrow")
574 model: NotificationBackend.Model
577 y: topmostIsFullscreen ? 0 : panel.panelHeight
578 height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
583 when: overlay.width <= units.gu(60)
585 target: notifications
586 anchors.left: parent.left
587 anchors.right: parent.right
592 when: overlay.width > units.gu(60)
594 target: notifications
595 anchors.left: undefined
596 anchors.right: parent.right
598 PropertyChanges { target: notifications; width: units.gu(38) }
609 shutdownFadeOutRectangle.enabled = true;
610 shutdownFadeOutRectangle.visible = true;
611 shutdownFadeOut.start();
616 target: SessionBroadcast
617 onShowHome: showHome()
621 id: shutdownFadeOutRectangle
622 z: screenGrabber.z + 10
628 NumberAnimation on opacity {
633 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
634 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