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(); }
191 height: parent.height
194 target: ApplicationManager
196 // This signal is also fired when we try to focus the current app
197 // again. We rely on this!
198 onFocusedApplicationIdChanged: {
199 var appId = ApplicationManager.focusedApplicationId;
201 if (tutorial.running && appId != "" && appId != "unity8-dash") {
202 // If this happens on first boot, we may be in edge
203 // tutorial or wizard while receiving a call. But a call
204 // is more important than wizard so just bail out of those.
209 if (appId === "dialer-app" && callManager.hasCalls && greeter.locked) {
210 // If we are in the middle of a call, make dialer lockedApp and show it.
211 // This can happen if user backs out of dialer back to greeter, then
212 // launches dialer again.
213 greeter.lockedApp = appId;
215 greeter.notifyAppFocused(appId);
217 panel.indicators.hide();
220 onApplicationAdded: {
226 id: applicationsDisplayLoader
227 objectName: "applicationsDisplayLoader"
230 // When we have a locked app, we only want to show that one app.
231 // FIXME: do this in a less traumatic way. We currently only allow
232 // locked apps in phone mode (see FIXME in Lockscreen component in
233 // this same file). When that changes, we need to do something
234 // nicer here. But this code is currently just to prevent a
235 // theoretical attack where user enters lockedApp mode, then makes
236 // the screen larger (maybe connects to monitor) and tries to enter
238 property bool tabletMode: shell.sideStageEnabled && !greeter.hasLockedApp
239 source: usageModeSettings.usageMode === "Windowed" ? "Stages/DesktopStage.qml"
240 : tabletMode ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml"
242 property bool interactive: tutorial.spreadEnabled
244 && panel.indicators.fullyClosed
245 && launcher.progress == 0
246 && !notifications.useModal
248 onInteractiveChanged: { if (interactive) { focus = true; } }
251 target: applicationsDisplayLoader.item
252 property: "objectName"
256 target: applicationsDisplayLoader.item
257 property: "dragAreaWidth"
258 value: shell.edgeSize
261 target: applicationsDisplayLoader.item
262 property: "maximizedAppTopMargin"
263 // Not just using panel.panelHeight as that changes depending on the focused app.
264 value: panel.indicators.minimizedPanelHeight + units.dp(2) // dp(2) for orange line
267 target: applicationsDisplayLoader.item
268 property: "interactive"
269 value: applicationsDisplayLoader.interactive
272 target: applicationsDisplayLoader.item
273 property: "spreadEnabled"
274 value: tutorial.spreadEnabled && !greeter.hasLockedApp
277 target: applicationsDisplayLoader.item
278 property: "inverseProgress"
279 value: greeter.locked ? 0 : launcher.progress
282 target: applicationsDisplayLoader.item
283 property: "orientation"
284 value: shell.orientation
287 target: applicationsDisplayLoader.item
288 property: "background"
289 value: shell.background
295 objectName: "tutorial"
297 active: AccountsService.demoEdges
298 paused: LightDM.Greeter.active
301 edgeSize: shell.edgeSize
303 // EdgeDragAreas don't work with mice. So to avoid trapping the user,
304 // we'll tell the tutorial to avoid using them on the Desktop. The
305 // Desktop doesn't use the same spread design anyway. The tutorial is
306 // all a bit of a placeholder on non-phone form factors right now.
307 // When the design team gives us more guidance, we can do something
309 // TODO: use DeviceConfiguration instead of checking source
310 useEdgeDragArea: applicationsDisplayLoader.source != Qt.resolvedUrl("Stages/DesktopStage.qml")
313 AccountsService.demoEdges = false;
314 active = false; // for immediate response / if AS is having problems
321 objectName: "inputMethod"
322 anchors { fill: parent; topMargin: panel.panelHeight }
323 z: notifications.useModal || panel.indicators.shown || wizard.active ? overlay.z + 1 : overlay.z - 1
327 target: SurfaceManager
329 if (surface.type == MirSurfaceItem.InputMethod) {
330 inputMethod.surface = surface;
334 onSurfaceDestroyed: {
335 if (inputMethod.surface == surface) {
336 inputMethod.surface = null;
337 surface.parent = null;
339 if (!surface.parent) {
340 // there's no one displaying it. delete it right away
346 target: SessionManager
348 if (!session.parentSession && !session.application) {
349 // nothing is using it. delete it right away
357 objectName: "greeter"
359 hides: [launcher, panel.indicators]
360 tabletMode: shell.sideStageEnabled
361 launcherOffset: launcher.progress
362 forcedUnlock: tutorial.running
363 background: shell.background
366 anchors.topMargin: panel.panelHeight
368 // avoid overlapping with Launcher's edge drag area
369 // FIXME: Fix TouchRegistry & friends and remove this workaround
370 // Issue involves launcher's DDA getting disabled on a long
372 dragHandleLeftMargin: launcher.available ? launcher.dragAreaWidth + 1 : 0
379 if (!tutorial.running) {
384 onEmergencyCall: startLockedApp("dialer-app")
387 // See powerConnection for why this is useful
388 id: showGreeterDelayed
396 target: ApplicationManager
397 property: "suspended"
407 if (greeter.locked && callManager.hasCalls && greeter.lockedApp !== "dialer-app") {
408 // We just received an incoming call while locked. The
409 // indicator will have already launched dialer-app for us, but
410 // there is a race between "hasCalls" changing and the dialer
411 // starting up. So in case we lose that race, we'll start/
412 // focus the dialer ourselves here too. Even if the indicator
413 // didn't launch the dialer for some reason (or maybe a call
414 // started via some other means), if an active call is
415 // happening, we want to be in the dialer.
416 startLockedApp("dialer-app")
426 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
427 !callManager.hasCalls && !tutorial.running) {
428 // We don't want to simply call greeter.showNow() here, because
429 // that will take too long. Qt will delay button event
430 // handling until the greeter is done loading and may think the
431 // user held down the power button the whole time, leading to a
432 // power dialog being shown. Instead, delay showing the
433 // greeter until we've finished handling the event. We could
434 // make the greeter load asynchronously instead, but that
435 // introduces a whole host of timing issues, especially with
436 // its animations. So this is simpler.
437 showGreeterDelayed.start();
442 function showHome() {
443 if (tutorial.running) {
447 greeter.notifyAboutToFocusApp("unity8-dash");
449 var animate = !LightDM.Greeter.active && !stages.shown
450 dash.setCurrentScope(0, animate, false)
451 ApplicationManager.requestFocusApplication("unity8-dash")
454 function showDash() {
455 if (greeter.notifyShowingDashFromDrag()) {
459 if (!greeter.locked && ApplicationManager.focusedApplicationId != "unity8-dash") {
460 ApplicationManager.requestFocusApplication("unity8-dash")
474 anchors.fill: parent //because this draws indicator menus
477 available: tutorial.panelEnabled
478 && (!greeter.locked || AccountsService.enableIndicatorsWhileLocked)
479 && !greeter.hasLockedApp
480 contentEnabled: tutorial.panelContentEnabled
481 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
483 minimizedPanelHeight: units.gu(3)
484 expandedPanelHeight: units.gu(7)
486 indicatorsModel: Indicators.IndicatorsModel {
487 // TODO: This should be sourced by device type (e.g. "desktop", "tablet", "phone"...)
488 profile: indicatorProfile
489 Component.onCompleted: load()
493 greeterShown: greeter.shown
496 property bool topmostApplicationIsFullscreen:
497 ApplicationManager.focusedApplicationId &&
498 ApplicationManager.findApplication(ApplicationManager.focusedApplicationId).fullscreen
500 fullscreenMode: (topmostApplicationIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
501 || greeter.hasLockedApp
506 objectName: "launcher"
508 readonly property bool dashSwipe: progress > 0
510 anchors.top: parent.top
511 anchors.topMargin: inverted ? 0 : panel.panelHeight
512 anchors.bottom: parent.bottom
514 dragAreaWidth: shell.edgeSize
515 available: tutorial.launcherEnabled
516 && (!greeter.locked || AccountsService.enableLauncherWhileLocked)
517 && !greeter.hasLockedApp
518 inverted: usageModeSettings.usageMode === "Staged"
519 shadeBackground: !tutorial.running
521 onShowDashHome: showHome()
523 onDashSwipeChanged: {
525 dash.setCurrentScope(0, false, true)
528 onLauncherApplicationSelected: {
529 if (!tutorial.running) {
530 greeter.notifyAboutToFocusApp(appId);
531 shell.activateApplication(appId)
536 panel.indicators.hide()
545 background: shell.background
547 function unlockWhenDoneWithWizard() {
549 Connectivity.unlockAllModems();
553 Component.onCompleted: unlockWhenDoneWithWizard()
554 onActiveChanged: unlockWhenDoneWithWizard()
558 id: modalNotificationBackground
560 visible: notifications.useModal && (notifications.state == "narrow")
573 model: NotificationBackend.Model
576 y: topmostIsFullscreen ? 0 : panel.panelHeight
577 height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
582 when: overlay.width <= units.gu(60)
584 target: notifications
585 anchors.left: parent.left
586 anchors.right: parent.right
591 when: overlay.width > units.gu(60)
593 target: notifications
594 anchors.left: undefined
595 anchors.right: parent.right
597 PropertyChanges { target: notifications; width: units.gu(38) }
608 shutdownFadeOutRectangle.enabled = true;
609 shutdownFadeOutRectangle.visible = true;
610 shutdownFadeOut.start();
615 target: SessionBroadcast
616 onShowHome: showHome()
620 id: shutdownFadeOutRectangle
621 z: screenGrabber.z + 10
627 NumberAnimation on opacity {
632 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
633 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