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 int primaryOrientation
52 property int nativeOrientation
53 property real nativeWidth
54 property real nativeHeight
55 property alias indicatorAreaShowProgress: panel.indicatorAreaShowProgress
56 property bool beingResized
57 property string usageScenario: "phone" // supported values: "phone", "tablet" or "desktop"
58 function updateFocusedAppOrientation() {
59 applicationsDisplayLoader.item.updateFocusedAppOrientation();
61 function updateFocusedAppOrientationAnimated() {
62 applicationsDisplayLoader.item.updateFocusedAppOrientationAnimated();
65 // to be read from outside
66 readonly property int mainAppWindowOrientationAngle:
67 applicationsDisplayLoader.item ? applicationsDisplayLoader.item.mainAppWindowOrientationAngle : 0
69 readonly property bool orientationChangesEnabled: panel.indicators.fullyClosed
70 && (applicationsDisplayLoader.item && applicationsDisplayLoader.item.orientationChangesEnabled)
73 property bool startingUp: true
74 Timer { id: finishStartUpTimer; interval: 500; onTriggered: startingUp = false }
76 property int supportedOrientations: {
78 // Ensure we don't rotate during start up
79 return Qt.PrimaryOrientation;
80 } else if (greeter.shown) {
81 return Qt.PrimaryOrientation;
83 return mainApp.supportedOrientations;
86 return Qt.PortraitOrientation
87 | Qt.LandscapeOrientation
88 | Qt.InvertedPortraitOrientation
89 | Qt.InvertedLandscapeOrientation;
93 // For autopilot consumption
94 readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
96 // internal props from here onwards
97 readonly property var mainApp:
98 applicationsDisplayLoader.item ? applicationsDisplayLoader.item.mainApp : null
100 // Disable everything while greeter is waiting, so that the user can't swipe
101 // the greeter or launcher until we know whether the session is locked.
102 enabled: !greeter.waiting
104 property real edgeSize: units.gu(2)
105 property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
106 property url background: asImageTester.status == Image.Ready ? asImageTester.source
107 : gsImageTester.status == Image.Ready ? gsImageTester.source : defaultBackground
109 // This is _only_ used to expose the property to autopilot tests
110 readonly property string testShellMode: shellMode
112 function activateApplication(appId) {
113 if (ApplicationManager.findApplication(appId)) {
114 ApplicationManager.requestFocusApplication(appId);
116 var execFlags = shell.usageScenario === "phone" ? ApplicationManager.ForceMainStage
117 : ApplicationManager.NoFlag;
118 ApplicationManager.startApplication(appId, execFlags);
122 function startLockedApp(app) {
123 if (greeter.locked) {
124 greeter.lockedApp = app;
126 shell.activateApplication(app);
129 // This is a dummy image to detect if the custom AS set wallpaper loads successfully.
132 source: AccountsService.backgroundFile != undefined && AccountsService.backgroundFile.length > 0 ? AccountsService.backgroundFile : ""
140 id: backgroundSettings
141 objectName: "backgroundSettings"
142 schema.id: "org.gnome.desktop.background"
145 // This is a dummy image to detect if the custom GSettings set wallpaper loads successfully.
148 source: backgroundSettings.pictureUri != undefined && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : ""
156 target: LauncherModel
157 property: "applicationManager"
158 value: ApplicationManager
161 Component.onCompleted: {
162 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
163 if (ApplicationManager.count > 0) {
164 ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
166 finishStartUpTimer.start();
175 objectName: "dashCommunicator"
179 id: physicalKeysMapper
181 onPowerKeyLongPressed: dialogs.showPowerDialog()
182 onVolumeDownTriggered: volumeControl.volumeDown();
183 onVolumeUpTriggered: volumeControl.volumeUp();
184 onScreenshotTriggered: screenGrabber.capture();
190 enabled: Powerd.status === Powerd.On
194 target: ApplicationManager
195 property: "forceDashActive"
196 value: launcher.shown || launcher.dashSwipe
200 Keys.onPressed: physicalKeysMapper.onKeyPressed(event);
201 Keys.onReleased: physicalKeysMapper.onKeyReleased(event);
205 onActivated: { launcher.fadeOut(); shell.showHome(); }
212 height: parent.height
215 target: ApplicationManager
217 // This signal is also fired when we try to focus the current app
218 // again. We rely on this!
219 onFocusedApplicationIdChanged: {
220 var appId = ApplicationManager.focusedApplicationId;
222 if (tutorial.running && appId != "" && appId != "unity8-dash") {
223 // If this happens on first boot, we may be in edge
224 // tutorial or wizard while receiving a call. But a call
225 // is more important than wizard so just bail out of those.
230 if (appId === "dialer-app" && callManager.hasCalls && greeter.locked) {
231 // If we are in the middle of a call, make dialer lockedApp and show it.
232 // This can happen if user backs out of dialer back to greeter, then
233 // launches dialer again.
234 greeter.lockedApp = appId;
236 greeter.notifyAppFocused(appId);
238 panel.indicators.hide();
241 onApplicationAdded: {
247 id: applicationsDisplayLoader
248 objectName: "applicationsDisplayLoader"
251 // When we have a locked app, we only want to show that one app.
252 // FIXME: do this in a less traumatic way. We currently only allow
253 // locked apps in phone mode (see FIXME in Lockscreen component in
254 // this same file). When that changes, we need to do something
255 // nicer here. But this code is currently just to prevent a
256 // theoretical attack where user enters lockedApp mode, then makes
257 // the screen larger (maybe connects to monitor) and tries to enter
260 property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp
262 : shell.usageScenario
264 if (applicationsDisplayLoader.usageScenario === "phone") {
265 return "Stages/PhoneStage.qml";
266 } else if (applicationsDisplayLoader.usageScenario === "tablet") {
267 return "Stages/TabletStage.qml";
269 return "Stages/DesktopStage.qml";
273 property bool interactive: tutorial.spreadEnabled
275 && panel.indicators.fullyClosed
276 && launcher.progress == 0
277 && !notifications.useModal
279 onInteractiveChanged: { if (interactive) { focus = true; } }
282 target: applicationsDisplayLoader.item
283 property: "objectName"
287 target: applicationsDisplayLoader.item
288 property: "dragAreaWidth"
289 value: shell.edgeSize
292 target: applicationsDisplayLoader.item
293 property: "maximizedAppTopMargin"
294 // Not just using panel.panelHeight as that changes depending on the focused app.
295 value: panel.indicators.minimizedPanelHeight + units.dp(2) // dp(2) for orange line
298 target: applicationsDisplayLoader.item
299 property: "interactive"
300 value: applicationsDisplayLoader.interactive
303 target: applicationsDisplayLoader.item
304 property: "spreadEnabled"
305 value: tutorial.spreadEnabled && !greeter.hasLockedApp
308 target: applicationsDisplayLoader.item
309 property: "inverseProgress"
310 value: greeter.locked ? 0 : launcher.progress
313 target: applicationsDisplayLoader.item
314 property: "shellOrientationAngle"
315 value: shell.orientationAngle
318 target: applicationsDisplayLoader.item
319 property: "shellOrientation"
320 value: shell.orientation
323 target: applicationsDisplayLoader.item
324 property: "background"
325 value: shell.background
328 target: applicationsDisplayLoader.item
329 property: "shellPrimaryOrientation"
330 value: shell.primaryOrientation
333 target: applicationsDisplayLoader.item
334 property: "nativeOrientation"
335 value: shell.nativeOrientation
338 target: applicationsDisplayLoader.item
339 property: "nativeWidth"
340 value: shell.nativeWidth
343 target: applicationsDisplayLoader.item
344 property: "nativeHeight"
345 value: shell.nativeHeight
348 target: applicationsDisplayLoader.item
349 property: "beingResized"
350 value: shell.beingResized
356 objectName: "tutorial"
358 active: AccountsService.demoEdges
359 paused: LightDM.Greeter.active
362 edgeSize: shell.edgeSize
364 // EdgeDragAreas don't work with mice. So to avoid trapping the user,
365 // we'll tell the tutorial to avoid using them on the Desktop. The
366 // Desktop doesn't use the same spread design anyway. The tutorial is
367 // all a bit of a placeholder on non-phone form factors right now.
368 // When the design team gives us more guidance, we can do something
370 // TODO: use DeviceConfiguration instead of checking source
371 useEdgeDragArea: applicationsDisplayLoader.source != Qt.resolvedUrl("Stages/DesktopStage.qml")
374 AccountsService.demoEdges = false;
375 active = false; // for immediate response / if AS is having problems
382 objectName: "inputMethod"
383 anchors { fill: parent; topMargin: panel.panelHeight }
384 z: notifications.useModal || panel.indicators.shown || wizard.active ? overlay.z + 1 : overlay.z - 1
388 target: SurfaceManager
390 if (surface.type == MirSurfaceItem.InputMethod) {
391 inputMethod.surface = surface;
395 onSurfaceDestroyed: {
396 if (inputMethod.surface == surface) {
397 inputMethod.surface = null;
398 surface.parent = null;
400 if (!surface.parent) {
401 // there's no one displaying it. delete it right away
407 target: SessionManager
409 if (!session.parentSession && !session.application) {
410 // nothing is using it. delete it right away
418 objectName: "greeter"
420 hides: [launcher, panel.indicators]
421 tabletMode: shell.usageScenario !== "phone"
422 launcherOffset: launcher.progress
423 forcedUnlock: tutorial.running
424 background: shell.background
427 anchors.topMargin: panel.panelHeight
429 // avoid overlapping with Launcher's edge drag area
430 // FIXME: Fix TouchRegistry & friends and remove this workaround
431 // Issue involves launcher's DDA getting disabled on a long
433 dragHandleLeftMargin: launcher.available ? launcher.dragAreaWidth + 1 : 0
440 if (!tutorial.running) {
445 onEmergencyCall: startLockedApp("dialer-app")
448 // See powerConnection for why this is useful
449 id: showGreeterDelayed
457 target: ApplicationManager
458 property: "suspended"
468 if (greeter.locked && callManager.hasCalls && greeter.lockedApp !== "dialer-app") {
469 // We just received an incoming call while locked. The
470 // indicator will have already launched dialer-app for us, but
471 // there is a race between "hasCalls" changing and the dialer
472 // starting up. So in case we lose that race, we'll start/
473 // focus the dialer ourselves here too. Even if the indicator
474 // didn't launch the dialer for some reason (or maybe a call
475 // started via some other means), if an active call is
476 // happening, we want to be in the dialer.
477 startLockedApp("dialer-app")
487 if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity &&
488 !callManager.hasCalls && !tutorial.running) {
489 // We don't want to simply call greeter.showNow() here, because
490 // that will take too long. Qt will delay button event
491 // handling until the greeter is done loading and may think the
492 // user held down the power button the whole time, leading to a
493 // power dialog being shown. Instead, delay showing the
494 // greeter until we've finished handling the event. We could
495 // make the greeter load asynchronously instead, but that
496 // introduces a whole host of timing issues, especially with
497 // its animations. So this is simpler.
498 showGreeterDelayed.start();
503 function showHome() {
504 if (tutorial.running) {
508 greeter.notifyAboutToFocusApp("unity8-dash");
510 var animate = !LightDM.Greeter.active && !stages.shown
511 dash.setCurrentScope(0, animate, false)
512 ApplicationManager.requestFocusApplication("unity8-dash")
515 function showDash() {
516 if (greeter.notifyShowingDashFromDrag()) {
520 if (!greeter.locked && ApplicationManager.focusedApplicationId != "unity8-dash") {
521 ApplicationManager.requestFocusApplication("unity8-dash")
535 anchors.fill: parent //because this draws indicator menus
538 available: tutorial.panelEnabled
539 && (!greeter.locked || AccountsService.enableIndicatorsWhileLocked)
540 && !greeter.hasLockedApp
541 contentEnabled: tutorial.panelContentEnabled
542 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
544 minimizedPanelHeight: units.gu(3)
545 expandedPanelHeight: units.gu(7)
547 indicatorsModel: Indicators.IndicatorsModel {
548 // tablet and phone both use the same profile
549 profile: shell.usageScenario === "desktop" ? "desktop" : "phone"
550 Component.onCompleted: load();
555 greeterShown: greeter.shown
558 property bool mainAppIsFullscreen: shell.mainApp && shell.mainApp.fullscreen
559 fullscreenMode: (mainAppIsFullscreen && !LightDM.Greeter.active && launcher.progress == 0)
560 || greeter.hasLockedApp
565 objectName: "launcher"
567 readonly property bool dashSwipe: progress > 0
569 anchors.top: parent.top
570 anchors.topMargin: inverted ? 0 : panel.panelHeight
571 anchors.bottom: parent.bottom
573 dragAreaWidth: shell.edgeSize
574 available: tutorial.launcherEnabled
575 && (!greeter.locked || AccountsService.enableLauncherWhileLocked)
576 && !greeter.hasLockedApp
577 inverted: shell.usageScenario !== "desktop"
578 shadeBackground: !tutorial.running
580 onShowDashHome: showHome()
582 onDashSwipeChanged: {
584 dash.setCurrentScope(0, false, true)
587 onLauncherApplicationSelected: {
588 if (!tutorial.running) {
589 greeter.notifyAboutToFocusApp(appId);
590 shell.activateApplication(appId)
595 panel.indicators.hide()
604 background: shell.background
606 function unlockWhenDoneWithWizard() {
608 Connectivity.unlockAllModems();
612 Component.onCompleted: unlockWhenDoneWithWizard()
613 onActiveChanged: unlockWhenDoneWithWizard()
617 id: modalNotificationBackground
619 visible: notifications.useModal
632 model: NotificationBackend.Model
635 y: topmostIsFullscreen ? 0 : panel.panelHeight
636 height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
641 when: overlay.width <= units.gu(60)
643 target: notifications
644 anchors.left: parent.left
645 anchors.right: parent.right
650 when: overlay.width > units.gu(60)
652 target: notifications
653 anchors.left: undefined
654 anchors.right: parent.right
656 PropertyChanges { target: notifications; width: units.gu(38) }
664 objectName: "dialogs"
668 shutdownFadeOutRectangle.enabled = true;
669 shutdownFadeOutRectangle.visible = true;
670 shutdownFadeOut.start();
675 target: SessionBroadcast
676 onShowHome: showHome()
680 id: shutdownFadeOutRectangle
681 z: screenGrabber.z + 10
687 NumberAnimation on opacity {
692 if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
693 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