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 console.log("JOSH: Shell: " + deviceSpecificOrientationOverrides.hello);
197 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
198 if (ApplicationManager.count > 0) {
199 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
201 finishStartUpTimer.start();
210 objectName: "dashCommunicator"
214 id: physicalKeysMapper
215 objectName: "physicalKeysMapper"
217 onPowerKeyLongPressed: dialogs.showPowerDialog()
218 onVolumeDownTriggered: volumeControl.volumeDown();
219 onVolumeUpTriggered: volumeControl.volumeUp();
220 onScreenshotTriggered: screenGrabber.capture();
229 Keys.onPressed: physicalKeysMapper.onKeyPressed(event);
230 Keys.onReleased: physicalKeysMapper.onKeyReleased(event);
234 onActivated: { launcher.fadeOut(); shell.showHome(); }
241 height: parent.height
244 target: ApplicationManager
246 // This signal is also fired when we try to focus the current app
247 // again. We rely on this!
248 onFocusedApplicationIdChanged: {
249 var appId = ApplicationManager.focusedApplicationId;
251 if (tutorial.running && appId != "" && appId != "unity8-dash") {
252 // If this happens on first boot, we may be in edge
253 // tutorial or wizard while receiving a call. But a call
254 // is more important than wizard so just bail out of those.
259 if (appId === "dialer-app" && callManager.hasCalls && greeter.locked) {
260 // If we are in the middle of a call, make dialer lockedApp and show it.
261 // This can happen if user backs out of dialer back to greeter, then
262 // launches dialer again.
263 greeter.lockedApp = appId;
265 greeter.notifyAppFocused(appId);
267 panel.indicators.hide();
270 onApplicationAdded: {
276 id: applicationsDisplayLoader
277 objectName: "applicationsDisplayLoader"
280 // When we have a locked app, we only want to show that one app.
281 // FIXME: do this in a less traumatic way. We currently only allow
282 // locked apps in phone mode (see FIXME in Lockscreen component in
283 // this same file). When that changes, we need to do something
284 // nicer here. But this code is currently just to prevent a
285 // theoretical attack where user enters lockedApp mode, then makes
286 // the screen larger (maybe connects to monitor) and tries to enter
289 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
291 : shell.usageScenario
293 if(shell.mode === "greeter") {
294 return "Stages/ShimStage.qml"
295 } else if (applicationsDisplayLoader.usageScenario === "phone") {
296 return "Stages/PhoneStage.qml";
297 } else if (applicationsDisplayLoader.usageScenario === "tablet") {
298 return "Stages/TabletStage.qml";
300 return "Stages/DesktopStage.qml";
304 onLoaded: console.log("JOSH in shell loader: " + deviceSpecificOrientationOverrides.hello)
306 property bool interactive: tutorial.spreadEnabled
307 && (!greeter || !greeter.shown)
308 && panel.indicators.fullyClosed
309 && launcher.progress == 0
310 && !notifications.useModal
312 onInteractiveChanged: { if (interactive) { focus = true; } }
315 target: applicationsDisplayLoader.item
316 property: "objectName"
320 target: applicationsDisplayLoader.item
321 property: "dragAreaWidth"
322 value: shell.edgeSize
325 target: applicationsDisplayLoader.item
326 property: "maximizedAppTopMargin"
327 // Not just using panel.panelHeight as that changes depending on the focused app.
328 value: panel.indicators.minimizedPanelHeight + units.dp(2) // dp(2) for orange line
331 target: applicationsDisplayLoader.item
332 property: "interactive"
333 value: applicationsDisplayLoader.interactive
336 target: applicationsDisplayLoader.item
337 property: "spreadEnabled"
338 value: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
341 target: applicationsDisplayLoader.item
342 property: "inverseProgress"
343 value: greeter && greeter.locked ? 0 : launcher.progress
346 target: applicationsDisplayLoader.item
347 property: "shellOrientationAngle"
348 value: shell.orientationAngle
351 target: applicationsDisplayLoader.item
352 property: "shellOrientation"
353 value: shell.orientation
356 target: applicationsDisplayLoader.item
357 property: "background"
358 value: shell.background
361 target: applicationsDisplayLoader.item
362 property: "shellPrimaryOrientation"
363 value: shell.primaryOrientation
366 target: applicationsDisplayLoader.item
367 property: "nativeOrientation"
368 value: shell.nativeOrientation
371 target: applicationsDisplayLoader.item
372 property: "nativeWidth"
373 value: shell.nativeWidth
376 target: applicationsDisplayLoader.item
377 property: "deviceSpecificOrientationOverrides"
378 value: shell.deviceSpecificOrientationOverrides
381 target: applicationsDisplayLoader.item
382 property: "nativeHeight"
383 value: shell.nativeHeight
386 target: applicationsDisplayLoader.item
387 property: "beingResized"
388 value: shell.beingResized
391 target: applicationsDisplayLoader.item
392 property: "keepDashRunning"
393 value: launcher.shown || launcher.dashSwipe
396 target: applicationsDisplayLoader.item
397 property: "suspended"
401 target: applicationsDisplayLoader.item
402 property: "altTabPressed"
403 value: physicalKeysMapper.altTabPressed
409 objectName: "tutorial"
411 active: AccountsService.demoEdges
412 paused: LightDM.Greeter.active
415 edgeSize: shell.edgeSize
417 // EdgeDragAreas don't work with mice. So to avoid trapping the user,
418 // we'll tell the tutorial to avoid using them on the Desktop. The
419 // Desktop doesn't use the same spread design anyway. The tutorial is
420 // all a bit of a placeholder on non-phone form factors right now.
421 // When the design team gives us more guidance, we can do something
423 // TODO: use DeviceConfiguration instead of checking source
424 useEdgeDragArea: applicationsDisplayLoader.source != Qt.resolvedUrl("Stages/DesktopStage.qml")
427 AccountsService.demoEdges = false;
428 active = false; // for immediate response / if AS is having problems
435 objectName: "inputMethod"
436 anchors { fill: parent; topMargin: panel.panelHeight }
437 z: notifications.useModal || panel.indicators.shown || wizard.active ? overlay.z + 1 : overlay.z - 1
441 target: SurfaceManager
443 if (surface.type == MirSurfaceItem.InputMethod) {
444 inputMethod.surface = surface;
448 onSurfaceDestroyed: {
449 if (inputMethod.surface == surface) {
450 inputMethod.surface = null;
451 surface.parent = null;
453 if (!surface.parent) {
454 // there's no one displaying it. delete it right away
460 target: SessionManager
462 if (!session.parentSession && !session.application) {
463 // nothing is using it. delete it right away
472 anchors.topMargin: panel.panelHeight
473 sourceComponent: shell.mode != "shell" ? integratedGreeter :
474 Qt.createComponent(Qt.resolvedUrl("Greeter/ShimGreeter.qml"));
476 item.objectName = "greeter"
481 id: integratedGreeter
484 hides: [launcher, panel.indicators]
485 tabletMode: shell.usageScenario != "phone"
486 launcherOffset: launcher.progress
487 forcedUnlock: tutorial.running
488 background: shell.background
490 // avoid overlapping with Launcher's edge drag area
491 // FIXME: Fix TouchRegistry & friends and remove this workaround
492 // Issue involves launcher's DDA getting disabled on a long
494 dragHandleLeftMargin: launcher.available ? launcher.dragAreaWidth + 1 : 0
501 if (!tutorial.running) {
506 onEmergencyCall: startLockedApp("dialer-app")
511 // See powerConnection for why this is useful
512 id: showGreeterDelayed
524 if (greeter.locked && callManager.hasCalls && greeter.lockedApp !== "dialer-app") {
525 // We just received an incoming call while locked. The
526 // indicator will have already launched dialer-app for us, but
527 // there is a race between "hasCalls" changing and the dialer
528 // starting up. So in case we lose that race, we'll start/
529 // focus the dialer ourselves here too. Even if the indicator
530 // didn't launch the dialer for some reason (or maybe a call
531 // started via some other means), if an active call is
532 // happening, we want to be in the dialer.
533 startLockedApp("dialer-app")
543 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
544 !callManager.hasCalls && !tutorial.running) {
545 // We don't want to simply call greeter.showNow() here, because
546 // that will take too long. Qt will delay button event
547 // handling until the greeter is done loading and may think the
548 // user held down the power button the whole time, leading to a
549 // power dialog being shown. Instead, delay showing the
550 // greeter until we've finished handling the event. We could
551 // make the greeter load asynchronously instead, but that
552 // introduces a whole host of timing issues, especially with
553 // its animations. So this is simpler.
554 showGreeterDelayed.start();
559 function showHome() {
560 if (tutorial.running) {
564 greeter.notifyAboutToFocusApp("unity8-dash");
566 var animate = !LightDM.Greeter.active && !stages.shown
567 dash.setCurrentScope(0, animate, false)
568 ApplicationManager.requestFocusApplication("unity8-dash")
571 function showDash() {
572 if (greeter.notifyShowingDashFromDrag()) {
576 if (!greeter.locked && ApplicationManager.focusedApplicationId != "unity8-dash") {
577 ApplicationManager.requestFocusApplication("unity8-dash")
591 anchors.fill: parent //because this draws indicator menus
594 available: tutorial.panelEnabled
595 && ((!greeter || !greeter.locked) || AccountsService.enableIndicatorsWhileLocked)
596 && (!greeter || !greeter.hasLockedApp)
597 contentEnabled: tutorial.panelContentEnabled
598 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
600 minimizedPanelHeight: units.gu(3)
601 expandedPanelHeight: units.gu(7)
603 indicatorsModel: Indicators.IndicatorsModel {
604 // tablet and phone both use the same profile
605 profile: shell.usageScenario === "desktop" ? "desktop" : "phone"
606 Component.onCompleted: load();
611 greeterShown: greeter.shown
614 property bool mainAppIsFullscreen: shell.mainApp && shell.mainApp.fullscreen
615 fullscreenMode: (mainAppIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
616 || greeter.hasLockedApp
621 objectName: "launcher"
623 readonly property bool dashSwipe: progress > 0
625 anchors.top: parent.top
626 anchors.topMargin: inverted ? 0 : panel.panelHeight
627 anchors.bottom: parent.bottom
629 dragAreaWidth: shell.edgeSize
630 available: tutorial.launcherEnabled
631 && (!greeter.locked || AccountsService.enableLauncherWhileLocked)
632 && !greeter.hasLockedApp
633 inverted: shell.usageScenario !== "desktop"
634 shadeBackground: !tutorial.running
636 onShowDashHome: showHome()
638 onDashSwipeChanged: {
640 dash.setCurrentScope(0, false, true)
643 onLauncherApplicationSelected: {
644 if (!tutorial.running) {
645 greeter.notifyAboutToFocusApp(appId);
646 shell.activateApplication(appId)
651 panel.indicators.hide()
660 background: shell.background
662 function unlockWhenDoneWithWizard() {
664 Connectivity.unlockAllModems();
668 Component.onCompleted: unlockWhenDoneWithWizard()
669 onActiveChanged: unlockWhenDoneWithWizard()
673 id: modalNotificationBackground
675 visible: notifications.useModal
688 model: NotificationBackend.Model
691 y: topmostIsFullscreen ? 0 : panel.panelHeight
692 height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
697 when: overlay.width <= units.gu(60)
699 target: notifications
700 anchors.left: parent.left
701 anchors.right: parent.right
706 when: overlay.width > units.gu(60)
708 target: notifications
709 anchors.left: undefined
710 anchors.right: parent.right
712 PropertyChanges { target: notifications; width: units.gu(38) }
720 objectName: "dialogs"
724 shutdownFadeOutRectangle.enabled = true;
725 shutdownFadeOutRectangle.visible = true;
726 shutdownFadeOut.start();
731 target: SessionBroadcast
732 onShowHome: showHome()
736 id: shutdownFadeOutRectangle
737 z: screenGrabber.z + 10
743 NumberAnimation on opacity {
748 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
749 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