on xenial help sign in
Fix ghost window if application creates and destroys surface early in lifecycle

When surface is destroyed by application, SurfaceManager won't destroy it immediately if it is displayed. liveChanged(false) signal is propagaded instead all the way up to ApplicationWindow.qml and TopLevelWindowModel. TopLevelWindowModel may set removeOnceSurfaceDestroyed = true to remove the window in onSurfaceDestroyed handler. However it won't get fired until ApplicationWindow unreferences surface in surfaceContainer. ApplicationWindow has a surfaceInitialized variable hack which is set by a timer after 100ms the surface is live. So if a surface is destroyed faster than that, it never sets the variable and does not reach "closed" state which unreferences the surface. Attempt to fix that by introducing one more "surfaceSeenLive" variable that is set once surface becomes live and helps to understand if it appeared but died too quickly.

commitff11a2443537d99dcf990353c93233297bc9f5ad authorTheKit <nekit1000@gmail.com> dateThu 7 Oct 2021, 19:54 (5 years ago) parent7b30fe3
2 files changed+16−6
plugins/WindowManager/TopLevelWindowModel.cpp+4−3 qml/Stage/ApplicationWindow.qml+12−3
plugins/WindowManager/TopLevelWindowModel.cpp+4−3
@@ -317,10 +317,11 @@ void TopLevelWindowModel::onSurfaceDied(unityapi::MirSurfaceInterface *surface)
317317
318318 auto application = m_windowModel[i].application;
319319
320− // can't be starting if it already has a surface
321− Q_ASSERT(application->state() != unityapi::ApplicationInfoInterface::Starting);
320+ DEBUG_MSG << " application->name()=" << application->name()
321+ << " application->state()=" << application->state();
322322
323− if (application->state() == unityapi::ApplicationInfoInterface::Running) {
323+ if (application->state() == unityapi::ApplicationInfoInterface::Running
324+ || application->state() == unityapi::ApplicationInfoInterface::Starting) {
324325 m_windowModel[i].removeOnceSurfaceDestroyed = true;
325326 } else {
326327 // assume it got killed by the out-of-memory daemon.
qml/Stage/ApplicationWindow.qml+12−3
@@ -53,6 +53,7 @@ FocusScope {
5353 if (surface) {
5454 surfaceContainer.surface = surface;
5555 d.liveSurface = surface.live;
56+ d.surfaceSeenLive = d.liveSurface;
5657 d.hadSurface = false;
5758 surfaceInitTimer.start();
5859 } else {
@@ -70,7 +71,12 @@ FocusScope {
7071 property bool liveSurface: false;
7172 property var con: Connections {
7273 target: root.surface
73− onLiveChanged: d.liveSurface = root.surface.live
74+ onLiveChanged: {
75+ d.liveSurface = root.surface.live;
76+ if (d.liveSurface) {
77+ d.surfaceSeenLive = true;
78+ }
79+ }
7480 }
7581 // using liveSurface instead of root.surface.live because with the latter
7682 // this expression is not reevaluated when root.surface changes
@@ -101,6 +107,7 @@ FocusScope {
101107 // might show the UI accommodating due to surface resizes on startup.
102108 // Remove this when possible
103109 property bool surfaceInitialized: false
110+ property bool surfaceSeenLive: false
104111
105112 readonly property bool supportsSurfaceResize:
106113 application &&
@@ -251,6 +258,7 @@ FocusScope {
251258 name: "splashScreen"
252259 when:
253260 !d.hadSurface && (!root.surface || !d.surfaceInitialized)
261+ && (d.liveSurface || !d.surfaceSeenLive)
254262 &&
255263 screenshotImage.status !== Image.Ready
256264 },
@@ -283,8 +291,9 @@ FocusScope {
283291 when:
284292 // The surface died while the application is running. It must have been closed
285293 // by the shell or the application decided to destroy it by itself
286− root.surface && d.surfaceInitialized && !d.liveSurface
287− && d.applicationState === ApplicationInfoInterface.Running
294+ root.surface && (d.surfaceInitialized || d.surfaceSeenLive) && !d.liveSurface
295+ && (d.applicationState === ApplicationInfoInterface.Running
296+ || d.applicationState === ApplicationInfoInterface.Starting)
288297 }
289298 ]
290299