2 * Copyright (C) 2013-2015 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 // to be set from outside
49 property int orientationAngle: 0
50 property int orientation
51 property QtObject deviceSpecificOrientationOverrides
52 property int primaryOrientation
53 property int nativeOrientation
54 property real nativeWidth
55 property real nativeHeight
56 property alias indicatorAreaShowProgress: panel.indicatorAreaShowProgress
57 property bool beingResized
58 property string usageScenario: "phone" // supported values: "phone", "tablet" or "desktop"
59 property string mode: "full-greeter"
60 function updateFocusedAppOrientation() {
61 applicationsDisplayLoader.item.updateFocusedAppOrientation();
63 function updateFocusedAppOrientationAnimated() {
64 applicationsDisplayLoader.item.updateFocusedAppOrientationAnimated();
67 // to be read from outside
68 readonly property int mainAppWindowOrientationAngle:
69 applicationsDisplayLoader.item ? applicationsDisplayLoader.item.mainAppWindowOrientationAngle : 0
71 readonly property bool orientationChangesEnabled: panel.indicators.fullyClosed
72 && (applicationsDisplayLoader.item && applicationsDisplayLoader.item.orientationChangesEnabled)
73 && (!greeter || !greeter.animating)
75 readonly property bool showingGreeter: greeter && greeter.shown
77 property bool startingUp: true
78 Timer { id: finishStartUpTimer; interval: 500; onTriggered: startingUp = false }
80 property int supportedOrientations: {
82 // Ensure we don't rotate during start up
83 return Qt.PrimaryOrientation;
84 } else if (greeter && greeter.shown) {
85 return Qt.PrimaryOrientation;
87 return mainApp.supportedOrientations;
90 return Qt.PortraitOrientation
91 | Qt.LandscapeOrientation
92 | Qt.InvertedPortraitOrientation
93 | Qt.InvertedLandscapeOrientation;
97 // For autopilot consumption
98 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
100 // internal props from here onwards
101 readonly property var mainApp:
102 applicationsDisplayLoader.item ? applicationsDisplayLoader.item.mainApp : null
104 // Disable everything while greeter is waiting, so that the user can't swipe
105 // the greeter or launcher until we know whether the session is locked.
106 enabled: greeter && !greeter.waiting
108 property real edgeSize: units.gu(2)
109 property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
110 property url background: asImageTester.status == Image.Ready ? asImageTester.source
111 : gsImageTester.status == Image.Ready ? gsImageTester.source : defaultBackground
113 readonly property alias greeter: greeterLoader.item
115 function activateApplication(appId) {
116 if (ApplicationManager.findApplication(appId)) {
117 ApplicationManager.requestFocusApplication(appId);
119 var execFlags = shell.usageScenario === "phone" ? ApplicationManager.ForceMainStage
120 : ApplicationManager.NoFlag;
121 ApplicationManager.startApplication(appId, execFlags);
125 function startLockedApp(app) {
126 if (greeter.locked) {
127 greeter.lockedApp = app;
129 shell.activateApplication(app);
132 // This is a dummy image to detect if the custom AS set wallpaper loads successfully.
135 source: AccountsService.backgroundFile != undefined && AccountsService.backgroundFile.length > 0 ? AccountsService.backgroundFile : ""
143 id: backgroundSettings
144 schema.id: "org.gnome.desktop.background"
147 // This is a dummy image to detect if the custom GSettings set wallpaper loads successfully.
150 source: backgroundSettings.pictureUri != undefined && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : ""
158 target: LauncherModel
159 property: "applicationManager"
160 value: ApplicationManager
163function serialize(object, maxDepth) {
164 function _processObject(object, maxDepth, level) {
167 if (maxDepth == undefined) {
170 if (level == undefined) {
173 var padding = Array(level + 1).join(pad)
175 output.push((Array.isArray(object) ? "[" : "{"))
177 for (var key in object) {
178 var keyText = Array.isArray(object) ? "" : ("\"" + key + "\": ")
179 if (typeof (object[key]) == "object" && key != "parent" && maxDepth != 0) {
180 var res = _processObject(object[key], maxDepth > 0 ? maxDepth - 1 : -1, level + 1)
181 fields.push(padding + pad + keyText + res)
183 fields.push(padding + pad + keyText + "\"" + object[key] + "\"")
186 output.push(fields.join(",\n"))
187 output.push(padding + (Array.isArray(object) ? "]" : "}"))
189 return output.join("\n")
192 return _processObject(object, maxDepth)
195 Component.onCompleted: {
196 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
197 if (ApplicationManager.count > 0) {
198 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
200 finishStartUpTimer.start();
209 objectName: "dashCommunicator"
213 id: physicalKeysMapper
214 objectName: "physicalKeysMapper"
216 onPowerKeyLongPressed: dialogs.showPowerDialog()
217 onVolumeDownTriggered: volumeControl.volumeDown();
218 onVolumeUpTriggered: volumeControl.volumeUp();
219 onScreenshotTriggered: screenGrabber.capture();
228 Keys.onPressed: physicalKeysMapper.onKeyPressed(event);
229 Keys.onReleased: physicalKeysMapper.onKeyReleased(event);
233 onActivated: { launcher.fadeOut(); shell.showHome(); }
240 height: parent.height
243 target: ApplicationManager
245 // This signal is also fired when we try to focus the current app
246 // again. We rely on this!
247 onFocusedApplicationIdChanged: {
248 var appId = ApplicationManager.focusedApplicationId;
250 if (tutorial.running && appId != "" && appId != "unity8-dash") {
251 // If this happens on first boot, we may be in edge
252 // tutorial or wizard while receiving a call. But a call
253 // is more important than wizard so just bail out of those.
258 if (appId === "dialer-app" && callManager.hasCalls && greeter.locked) {
259 // If we are in the middle of a call, make dialer lockedApp and show it.
260 // This can happen if user backs out of dialer back to greeter, then
261 // launches dialer again.
262 greeter.lockedApp = appId;
264 greeter.notifyAppFocused(appId);
266 panel.indicators.hide();
269 onApplicationAdded: {
275 id: applicationsDisplayLoader
276 objectName: "applicationsDisplayLoader"
279 // When we have a locked app, we only want to show that one app.
280 // FIXME: do this in a less traumatic way. We currently only allow
281 // locked apps in phone mode (see FIXME in Lockscreen component in
282 // this same file). When that changes, we need to do something
283 // nicer here. But this code is currently just to prevent a
284 // theoretical attack where user enters lockedApp mode, then makes
285 // the screen larger (maybe connects to monitor) and tries to enter
288 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
290 : shell.usageScenario
292 if(shell.mode === "greeter") {
293 return "Stages/ShimStage.qml"
294 } else if (applicationsDisplayLoader.usageScenario === "phone") {
295 return "Stages/PhoneStage.qml";
296 } else if (applicationsDisplayLoader.usageScenario === "tablet") {
297 return "Stages/TabletStage.qml";
299 return "Stages/DesktopStage.qml";
303 property bool interactive: tutorial.spreadEnabled
304 && (!greeter || !greeter.shown)
305 && panel.indicators.fullyClosed
306 && launcher.progress == 0
307 && !notifications.useModal
309 onInteractiveChanged: { if (interactive) { focus = true; } }
312 target: applicationsDisplayLoader.item
313 property: "objectName"
317 target: applicationsDisplayLoader.item
318 property: "dragAreaWidth"
319 value: shell.edgeSize
322 target: applicationsDisplayLoader.item
323 property: "maximizedAppTopMargin"
324 // Not just using panel.panelHeight as that changes depending on the focused app.
325 value: panel.indicators.minimizedPanelHeight + units.dp(2) // dp(2) for orange line
328 target: applicationsDisplayLoader.item
329 property: "interactive"
330 value: applicationsDisplayLoader.interactive
333 target: applicationsDisplayLoader.item
334 property: "spreadEnabled"
335 value: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
338 target: applicationsDisplayLoader.item
339 property: "inverseProgress"
340 value: greeter && greeter.locked ? 0 : launcher.progress
343 target: applicationsDisplayLoader.item
344 property: "shellOrientationAngle"
345 value: shell.orientationAngle
348 target: applicationsDisplayLoader.item
349 property: "shellOrientation"
350 value: shell.orientation
353 target: applicationsDisplayLoader.item
354 property: "background"
355 value: shell.background
358 target: applicationsDisplayLoader.item
359 property: "shellPrimaryOrientation"
360 value: shell.primaryOrientation
363 target: applicationsDisplayLoader.item
364 property: "nativeOrientation"
365 value: shell.nativeOrientation
368 target: applicationsDisplayLoader.item
369 property: "nativeWidth"
370 value: shell.nativeWidth
373 target: applicationsDisplayLoader.item
374 property: "deviceSpecificOrientationOverrides"
375 value: shell.deviceSpecificOrientationOverrides
378 target: applicationsDisplayLoader.item
379 property: "nativeHeight"
380 value: shell.nativeHeight
383 target: applicationsDisplayLoader.item
384 property: "beingResized"
385 value: shell.beingResized
388 target: applicationsDisplayLoader.item
389 property: "keepDashRunning"
390 value: launcher.shown || launcher.dashSwipe
393 target: applicationsDisplayLoader.item
394 property: "suspended"
398 target: applicationsDisplayLoader.item
399 property: "altTabPressed"
400 value: physicalKeysMapper.altTabPressed
406 objectName: "tutorial"
408 active: AccountsService.demoEdges
409 paused: LightDM.Greeter.active
412 edgeSize: shell.edgeSize
414 // EdgeDragAreas don't work with mice. So to avoid trapping the user,
415 // we'll tell the tutorial to avoid using them on the Desktop. The
416 // Desktop doesn't use the same spread design anyway. The tutorial is
417 // all a bit of a placeholder on non-phone form factors right now.
418 // When the design team gives us more guidance, we can do something
420 // TODO: use DeviceConfiguration instead of checking source
421 useEdgeDragArea: applicationsDisplayLoader.source != Qt.resolvedUrl("Stages/DesktopStage.qml")
424 AccountsService.demoEdges = false;
425 active = false; // for immediate response / if AS is having problems
432 objectName: "inputMethod"
433 anchors { fill: parent; topMargin: panel.panelHeight }
434 z: notifications.useModal || panel.indicators.shown || wizard.active ? overlay.z + 1 : overlay.z - 1
438 target: SurfaceManager
440 if (surface.type == MirSurfaceItem.InputMethod) {
441 inputMethod.surface = surface;
445 onSurfaceDestroyed: {
446 if (inputMethod.surface == surface) {
447 inputMethod.surface = null;
448 surface.parent = null;
450 if (!surface.parent) {
451 // there's no one displaying it. delete it right away
457 target: SessionManager
459 if (!session.parentSession && !session.application) {
460 // nothing is using it. delete it right away
469 anchors.topMargin: panel.panelHeight
470 sourceComponent: shell.mode != "shell" ? integratedGreeter :
471 Qt.createComponent(Qt.resolvedUrl("Greeter/ShimGreeter.qml"));
473 item.objectName = "greeter"
478 id: integratedGreeter
481 hides: [launcher, panel.indicators]
482 tabletMode: shell.usageScenario != "phone"
483 launcherOffset: launcher.progress
484 forcedUnlock: tutorial.running
485 background: shell.background
487 // avoid overlapping with Launcher's edge drag area
488 // FIXME: Fix TouchRegistry & friends and remove this workaround
489 // Issue involves launcher's DDA getting disabled on a long
491 dragHandleLeftMargin: launcher.available ? launcher.dragAreaWidth + 1 : 0
498 if (!tutorial.running) {
503 onEmergencyCall: startLockedApp("dialer-app")
508 // See powerConnection for why this is useful
509 id: showGreeterDelayed
521 if (greeter.locked && callManager.hasCalls && greeter.lockedApp !== "dialer-app") {
522 // We just received an incoming call while locked. The
523 // indicator will have already launched dialer-app for us, but
524 // there is a race between "hasCalls" changing and the dialer
525 // starting up. So in case we lose that race, we'll start/
526 // focus the dialer ourselves here too. Even if the indicator
527 // didn't launch the dialer for some reason (or maybe a call
528 // started via some other means), if an active call is
529 // happening, we want to be in the dialer.
530 startLockedApp("dialer-app")
540 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
541 !callManager.hasCalls && !tutorial.running) {
542 // We don't want to simply call greeter.showNow() here, because
543 // that will take too long. Qt will delay button event
544 // handling until the greeter is done loading and may think the
545 // user held down the power button the whole time, leading to a
546 // power dialog being shown. Instead, delay showing the
547 // greeter until we've finished handling the event. We could
548 // make the greeter load asynchronously instead, but that
549 // introduces a whole host of timing issues, especially with
550 // its animations. So this is simpler.
551 showGreeterDelayed.start();
556 function showHome() {
557 if (tutorial.running) {
561 greeter.notifyAboutToFocusApp("unity8-dash");
563 var animate = !LightDM.Greeter.active && !stages.shown
564 dash.setCurrentScope(0, animate, false)
565 ApplicationManager.requestFocusApplication("unity8-dash")
568 function showDash() {
569 if (greeter.notifyShowingDashFromDrag()) {
573 if (!greeter.locked && ApplicationManager.focusedApplicationId != "unity8-dash") {
574 ApplicationManager.requestFocusApplication("unity8-dash")
588 anchors.fill: parent //because this draws indicator menus
591 available: tutorial.panelEnabled
592 && ((!greeter || !greeter.locked) || AccountsService.enableIndicatorsWhileLocked)
593 && (!greeter || !greeter.hasLockedApp)
594 contentEnabled: tutorial.panelContentEnabled
595 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
597 minimizedPanelHeight: units.gu(3)
598 expandedPanelHeight: units.gu(7)
600 indicatorsModel: Indicators.IndicatorsModel {
601 // tablet and phone both use the same profile
602 profile: shell.usageScenario === "desktop" ? "desktop" : "phone"
603 Component.onCompleted: load();
608 greeterShown: greeter.shown
611 property bool mainAppIsFullscreen: shell.mainApp && shell.mainApp.fullscreen
612 fullscreenMode: (mainAppIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
613 || greeter.hasLockedApp
618 objectName: "launcher"
620 readonly property bool dashSwipe: progress > 0
622 anchors.top: parent.top
623 anchors.topMargin: inverted ? 0 : panel.panelHeight
624 anchors.bottom: parent.bottom
626 dragAreaWidth: shell.edgeSize
627 available: tutorial.launcherEnabled
628 && (!greeter.locked || AccountsService.enableLauncherWhileLocked)
629 && !greeter.hasLockedApp
630 inverted: shell.usageScenario !== "desktop"
631 shadeBackground: !tutorial.running
633 onShowDashHome: showHome()
635 onDashSwipeChanged: {
637 dash.setCurrentScope(0, false, true)
640 onLauncherApplicationSelected: {
641 if (!tutorial.running) {
642 greeter.notifyAboutToFocusApp(appId);
643 shell.activateApplication(appId)
648 panel.indicators.hide()
657 background: shell.background
659 function unlockWhenDoneWithWizard() {
661 Connectivity.unlockAllModems();
665 Component.onCompleted: unlockWhenDoneWithWizard()
666 onActiveChanged: unlockWhenDoneWithWizard()
670 id: modalNotificationBackground
672 visible: notifications.useModal
685 model: NotificationBackend.Model
688 y: topmostIsFullscreen ? 0 : panel.panelHeight
689 height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
694 when: overlay.width <= units.gu(60)
696 target: notifications
697 anchors.left: parent.left
698 anchors.right: parent.right
703 when: overlay.width > units.gu(60)
705 target: notifications
706 anchors.left: undefined
707 anchors.right: parent.right
709 PropertyChanges { target: notifications; width: units.gu(38) }
717 objectName: "dialogs"
721 shutdownFadeOutRectangle.enabled = true;
722 shutdownFadeOutRectangle.visible = true;
723 shutdownFadeOut.start();
728 target: SessionBroadcast
729 onShowHome: showHome()
733 id: shutdownFadeOutRectangle
734 z: screenGrabber.z + 10
740 NumberAnimation on opacity {
745 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
746 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