2 * Copyright 2014-2016 Canonical Ltd.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 import Ubuntu.Components 1.3
19 import Unity.Application 0.1
23 implicitWidth: requestedWidth
24 implicitHeight: requestedHeight
26 // to be read from outside
27 property alias interactive: surfaceContainer.interactive
28 property bool orientationChangesEnabled: d.supportsSurfaceResize ? d.surfaceOldEnoughToBeResized : true
29 readonly property string title: surface && surface.name !== "" ? surface.name : d.name
30 readonly property QtObject focusedSurface: d.focusedSurface.surface
31 readonly property alias surfaceInitialized: d.surfaceInitialized
33 // to be set from outside
34 property QtObject surface
35 property QtObject application
36 property int surfaceOrientationAngle
37 property int requestedWidth: -1
38 property int requestedHeight: -1
39 property real splashRotation: 0
41 readonly property int minimumWidth: surface ? surface.minimumWidth : 0
42 readonly property int minimumHeight: surface ? surface.minimumHeight : 0
43 readonly property int maximumWidth: surface ? surface.maximumWidth : 0
44 readonly property int maximumHeight: surface ? surface.maximumHeight : 0
45 readonly property int widthIncrement: surface ? surface.widthIncrement : 0
46 readonly property int heightIncrement: surface ? surface.heightIncrement : 0
49 // The order in which the instructions are executed here matters, to that the correct state
50 // transitions in stateGroup take place.
51 // More specifically, the moment surfaceContainer.surface gets updated relative to the
52 // other instructions.
54 surfaceContainer.surface = surface;
55 d.liveSurface = surface.live;
56 d.surfaceSeenLive = d.liveSurface;
58 surfaceInitTimer.start();
60 if (d.surfaceInitialized) {
63 d.surfaceInitialized = false;
64 surfaceContainer.surface = null;
71 property bool liveSurface: false;
72 property var con: Connections {
75 d.liveSurface = root.surface.live;
77 d.surfaceSeenLive = true;
81 // using liveSurface instead of root.surface.live because with the latter
82 // this expression is not reevaluated when root.surface changes
83 readonly property bool needToTakeScreenshot: root.surface && d.surfaceInitialized && !d.liveSurface
84 && applicationState !== ApplicationInfoInterface.Running
85 onNeedToTakeScreenshotChanged: {
86 if (needToTakeScreenshot && screenshotImage.status === Image.Null) {
87 screenshotImage.take();
91 // helpers so that we don't have to check for the existence of an application everywhere
92 // (in order to avoid breaking qml binding due to a javascript exception)
93 readonly property string name: root.application ? root.application.name : ""
94 readonly property url icon: root.application ? root.application.icon : ""
95 readonly property int applicationState: root.application ? root.application.state : -1
96 readonly property string splashTitle: root.application ? root.application.splashTitle : ""
97 readonly property url splashImage: root.application ? root.application.splashImage : ""
98 readonly property bool splashShowHeader: root.application ? root.application.splashShowHeader : true
99 readonly property color splashColor: root.application ? root.application.splashColor : "#00000000"
100 readonly property color splashColorHeader: root.application ? root.application.splashColorHeader : "#00000000"
101 readonly property color splashColorFooter: root.application ? root.application.splashColorFooter : "#00000000"
103 // Whether the Application had a surface before but lost it.
104 property bool hadSurface: false
106 //FIXME - this is a hack to avoid the first few rendered frames as they
107 // might show the UI accommodating due to surface resizes on startup.
108 // Remove this when possible
109 property bool surfaceInitialized: false
110 property bool surfaceSeenLive: false
112 readonly property bool supportsSurfaceResize:
114 ((application.supportedOrientations & Qt.PortraitOrientation)
115 || (application.supportedOrientations & Qt.InvertedPortraitOrientation))
117 ((application.supportedOrientations & Qt.LandscapeOrientation)
118 || (application.supportedOrientations & Qt.InvertedLandscapeOrientation))
120 property bool surfaceOldEnoughToBeResized: false
122 property Item focusedSurface: promptSurfacesRepeater.count === 0 ? surfaceContainer
123 : promptSurfacesRepeater.first
124 onFocusedSurfaceChanged: {
125 if (focusedSurface) {
126 focusedSurface.focus = true;
132 target: root.application
133 property: "initialSurfaceSize"
134 value: Qt.size(root.requestedWidth, root.requestedHeight)
141 if (root.surface && root.surface.live) {d.surfaceInitialized = true;}
146 id: surfaceIsOldTimer
148 onTriggered: { if (stateGroup.state === "surface") { d.surfaceOldEnoughToBeResized = true; } }
153 objectName: "screenshotImage"
155 fillMode: Image.PreserveAspectCrop
156 horizontalAlignment: Image.AlignLeft
157 verticalAlignment: Image.AlignTop
158 antialiasing: !root.interactive
162 // Save memory by using a half-resolution (thus quarter size) screenshot.
163 // Do not make this a binding, we can only take the screenshot once!
164 surfaceContainer.grabToImage(
166 screenshotImage.source = result.url;
168 Qt.size(root.width / 2, root.height / 2));
177 z: screenshotImage.z + 1
178 sourceComponent: Component {
181 title: d.splashTitle ? d.splashTitle : d.name
182 imageSource: d.splashImage
184 showHeader: d.splashShowHeader
185 backgroundColor: d.splashColor
186 headerColor: d.splashColorHeader
187 footerColor: d.splashColorFooter
189 rotation: root.splashRotation
190 anchors.centerIn: parent
191 width: rotation == 0 || rotation == 180 ? root.width : root.height
192 height: rotation == 0 || rotation == 180 ? root.height : root.width
200 z: splashLoader.z + 1
201 requestedWidth: root.requestedWidth
202 requestedHeight: root.requestedHeight
203 surfaceOrientationAngle: application && application.rotatesWindowContents ? root.surfaceOrientationAngle : 0
207 id: promptSurfacesRepeater
208 objectName: "promptSurfacesRepeater"
209 // show only along with the top-most application surface
211 if (root.application && (
212 root.surface === root.application.surfaceList.first ||
213 root.application.surfaceList.count === 0)) {
214 return root.application.promptSurfaceList;
219 delegate: SurfaceContainer {
220 id: promptSurfaceContainer
221 interactive: index === 0 && root.interactive
222 surface: model.surface
225 requestedWidth: root.requestedWidth
226 requestedHeight: root.requestedHeight
227 isPromptSurface: true
228 z: surfaceContainer.z + (promptSurfacesRepeater.count - index)
229 property int index: model.index
230 onIndexChanged: updateFirst()
231 Component.onCompleted: updateFirst()
232 function updateFirst() {
234 promptSurfacesRepeater.first = promptSurfaceContainer;
243 property Item first: null
248 objectName: "applicationWindowStateGroup"
253 d.hadSurface && (!root.surface || !d.surfaceInitialized)
255 screenshotImage.status !== Image.Ready
260 !d.hadSurface && (!root.surface || !d.surfaceInitialized)
261 && (d.liveSurface || !d.surfaceSeenLive)
263 screenshotImage.status !== Image.Ready
268 (root.surface && d.surfaceInitialized)
271 (d.applicationState !== ApplicationInfoInterface.Running
272 && screenshotImage.status !== Image.Ready))
275 implicitWidth: surfaceContainer.implicitWidth
276 implicitHeight: surfaceContainer.implicitHeight
282 screenshotImage.status === Image.Ready
284 (d.applicationState !== ApplicationInfoInterface.Running
285 || !root.surface || !d.surfaceInitialized)
288 // This is a dead end. From here we expect the surface to be removed from the model
289 // shortly after we stop referencing to it in our SurfaceContainer.
292 // The surface died while the application is running. It must have been closed
293 // by the shell or the application decided to destroy it by itself
294 root.surface && (d.surfaceInitialized || d.surfaceSeenLive) && !d.liveSurface
295 && (d.applicationState === ApplicationInfoInterface.Running
296 || d.applicationState === ApplicationInfoInterface.Starting)
302 from: ""; to: "splashScreen"
303 PropertyAction { target: splashLoader; property: "active"; value: true }
304 PropertyAction { target: surfaceContainer
305 property: "visible"; value: false }
308 from: "splashScreen"; to: "surface"
309 SequentialAnimation {
310 PropertyAction { target: surfaceContainer
311 property: "opacity"; value: 0.0 }
312 PropertyAction { target: surfaceContainer
313 property: "visible"; value: true }
314 UbuntuNumberAnimation { target: surfaceContainer; property: "opacity";
316 duration: UbuntuAnimation.BriskDuration }
317 ScriptAction { script: {
318 splashLoader.active = false;
319 surfaceIsOldTimer.start();
324 from: "surface"; to: "splashScreen"
325 SequentialAnimation {
326 ScriptAction { script: {
327 surfaceIsOldTimer.stop();
328 d.surfaceOldEnoughToBeResized = false;
329 splashLoader.active = true;
330 surfaceContainer.visible = true;
332 UbuntuNumberAnimation { target: splashLoader; property: "opacity";
334 duration: UbuntuAnimation.BriskDuration }
335 PropertyAction { target: surfaceContainer
336 property: "visible"; value: false }
340 from: "surface"; to: "screenshot"
341 SequentialAnimation {
342 ScriptAction { script: {
343 surfaceIsOldTimer.stop();
344 d.surfaceOldEnoughToBeResized = false;
345 screenshotImage.visible = true;
347 UbuntuNumberAnimation { target: screenshotImage; property: "opacity";
349 duration: UbuntuAnimation.BriskDuration }
350 ScriptAction { script: {
351 surfaceContainer.visible = false;
352 surfaceContainer.surface = null;
358 from: "screenshot"; to: "surface"
359 SequentialAnimation {
360 PropertyAction { target: surfaceContainer
361 property: "visible"; value: true }
362 UbuntuNumberAnimation { target: screenshotImage; property: "opacity";
364 duration: UbuntuAnimation.BriskDuration }
365 ScriptAction { script: {
366 screenshotImage.visible = false;
367 screenshotImage.source = "";
368 surfaceIsOldTimer.start();
373 from: "splashScreen"; to: "screenshot"
374 SequentialAnimation {
375 PropertyAction { target: screenshotImage
376 property: "visible"; value: true }
377 UbuntuNumberAnimation { target: screenshotImage; property: "opacity";
379 duration: UbuntuAnimation.BriskDuration }
380 PropertyAction { target: splashLoader; property: "active"; value: false }
384 from: "surface"; to: "void"
385 ScriptAction { script: {
386 surfaceIsOldTimer.stop();
387 d.surfaceOldEnoughToBeResized = false;
388 surfaceContainer.visible = false;
392 from: "void"; to: "surface"
393 SequentialAnimation {
394 PropertyAction { target: surfaceContainer; property: "opacity"; value: 0.0 }
395 PropertyAction { target: surfaceContainer; property: "visible"; value: true }
396 UbuntuNumberAnimation { target: surfaceContainer; property: "opacity";
398 duration: UbuntuAnimation.BriskDuration }
399 ScriptAction { script: {
400 surfaceIsOldTimer.start();
406 SequentialAnimation {
407 ScriptAction { script: {
408 surfaceContainer.visible = false;
409 surfaceContainer.surface = null;