A finishing activity no longer takes the next one's Surface; the library label is environment, not an argument

Hand-off from the desktop to a Steam session: the new activity attached its Surface, then the
old one's surfaceDestroyed detached it - the compositor presented nothing while gamescope sent
frames by the thousand (black screen, sound only). detach() now takes the Surface being destroyed
and ignores one that is not attached. BL_LIBRARY_LABEL was added to the guest list after the
script's mode and reached the Steam client as an argument; it is an environment variable now.
This commit is contained in:
The412Banner committed 2026-09-22 11:01:58 -04:00
1 parent b28e91128f
commit 593ef8fcaf
3 files changed
+18 -3

No files matched your search

@@ -361,7 +361,7 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
override fun surfaceDestroyed(holder: SurfaceHolder) {
surfaceW = 0
surfaceH = 0
CompositorHost.detach()
CompositorHost.detach(holder.surface)
}
/**
@@ -292,6 +292,8 @@ class SessionService : Service() {
}
// Where the guest leaves a request for another session (the desktop's Steam launchers).
guest.add("BL_LAUNCH_DIR=" + sessionRoot.path)
// The second library's name, for bannerlator-steam-library; the bind itself is made below.
GameStorage.effective(this)?.let { guest.add("BL_LIBRARY_LABEL=" + it.label.replace('"', ' ')) }
if (SessionState.mode == MODE_STEAM && SessionState.steamUi == "desktop") guest.add("BL_STEAM_UI=desktop")
guest.add(LinuxRuntime.SESSION_SCRIPT)
guest.add(SessionState.mode)
@@ -339,7 +341,6 @@ class SessionService : Service() {
if (problem == null) {
File(LinuxRuntime.rootDir(this), "mnt/bannerlator-sd").mkdirs()
binds.add("${library.path}:/mnt/bannerlator-sd")
guest.add("BL_LIBRARY_LABEL=" + library.label.replace('"', ' '))
Log.i(TAG, "game storage: ${library.path} -> /mnt/bannerlator-sd (\"${library.label}\")")
} else {
Log.w(TAG, "game storage: $problem; internal only this session")
@@ -34,6 +34,7 @@ object CompositorHost {
refreshHz: Float,
): Boolean {
if (started) {
attached = surface
WaylandCompositor.nativeSetSurface(surface)
resumeVsync()
return false
@@ -43,6 +44,7 @@ object CompositorHost {
WaylandCompositor.nativeStartWithSurface(
surface, xdgRuntimeDir, driverPath, libraryName, nativeLibDir,
)
attached = surface
started = true
resumeVsync()
return true
@@ -66,6 +68,7 @@ object CompositorHost {
WaylandCompositor.nativeSetFrameGenArmed(false, 0)
WaylandCompositor.nativeLog("screen", "surface resized: rebinding the window, frame generation re-armed after")
WaylandCompositor.nativeSetSurface(null)
attached = surface
WaylandCompositor.nativeSetSurface(surface)
android.os.Handler(android.os.Looper.getMainLooper()).postDelayed(rearm, 600)
}
@@ -87,9 +90,20 @@ object CompositorHost {
* The activity is going away. The compositor keeps running with nothing to present into —
* the guest carries on, and its next frames land on the Surface the next activity brings.
*/
/** The Surface the compositor presents on; only its own owner may take it away. */
private var attached: Surface? = null
/**
* Only for the Surface that is attached. When one session hands over to the next (the
* desktop's Steam launchers), the new activity attaches its Surface before the old one is
* destroyed - and the old one's surfaceDestroyed then arrived here and took the new Surface
* away: gamescope's frames came in by the thousand and nothing reached the screen.
*/
@Synchronized
fun detach() {
fun detach(surface: Surface?) {
if (!started) return
if (surface != null && attached != null && attached !== surface) return
attached = null
pauseVsync()
WaylandCompositor.nativeSetSurface(null)
}