From d79536b56d04c256ebd301595d451fe6942d1e47 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Thu, 22 Oct 2026 20:06:46 -0500 Subject: [PATCH] Only accept usable bounds if they differ from the full bounds Some platforms (Wayland) just report the full display area, so we incorrectly assume the entire display is usable for a window. Fixes #2056 --- app/streaming/session.cpp | 60 ++++++++++++++++++++++++--------------- app/utils.h | 1 + app/wm.cpp | 46 ++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 23 deletions(-) diff --git a/app/streaming/session.cpp b/app/streaming/session.cpp index 40c1e59c..c6e3470d 100644 --- a/app/streaming/session.cpp +++ b/app/streaming/session.cpp @@ -1363,34 +1363,48 @@ void Session::getWindowDimensions(int& x, int& y, } } + // Get the usable display bounds SDL_Rect usableBounds; - if (SDL_GetDisplayUsableBounds(displayIndex, &usableBounds) == 0) { - // If the stream resolution fits within the usable display area, use it directly - if (m_StreamConfig.width <= usableBounds.w && - m_StreamConfig.height <= usableBounds.h) { - width = m_StreamConfig.width; - height = m_StreamConfig.height; - } else { - // Otherwise, use 80% of usable bounds and preserve aspect ratio - SDL_Rect src, dst; - src.x = src.y = dst.x = dst.y = 0; - src.w = m_StreamConfig.width; - src.h = m_StreamConfig.height; - - dst.w = ((int)(usableBounds.w * 0.80f)) & ~0x1; // even width - dst.h = ((int)(usableBounds.h * 0.80f)) & ~0x1; // even height - - StreamUtils::scaleSourceToDestinationSurface(&src, &dst); - - width = dst.w; - height = dst.h; - } - } - else { + if (SDL_GetDisplayUsableBounds(displayIndex, &usableBounds) != 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_GetDisplayUsableBounds() failed: %s", SDL_GetError()); + SDL_zero(usableBounds); + } + // Use the usable display bounds if they are valid + if (usableBounds.w != 0 && + WMUtils::hasDisplayUsableBounds() && + m_StreamConfig.width <= usableBounds.w && + m_StreamConfig.height <= usableBounds.h) { + // We fit pixel-perfect in the usable area, so don't scale at all + width = m_StreamConfig.width; + height = m_StreamConfig.height; + } + else if (usableBounds.w != 0 || SDL_GetDisplayBounds(displayIndex, &usableBounds) == 0) { + // Otherwise, use 80% of usable bounds and preserve aspect ratio + SDL_Rect src, dst; + src.x = src.y = dst.x = dst.y = 0; + src.w = m_StreamConfig.width; + src.h = m_StreamConfig.height; + + dst.w = ((int)(usableBounds.w * 0.80f)) & ~0x1; // even width + dst.h = ((int)(usableBounds.h * 0.80f)) & ~0x1; // even height + + StreamUtils::scaleSourceToDestinationSurface(&src, &dst); + + // Only scale the size down, never up + if (m_StreamConfig.width >= dst.w || m_StreamConfig.height >= dst.h) { + width = dst.w; + height = dst.h; + } + else { + width = m_StreamConfig.width; + height = m_StreamConfig.height; + } + } + else { + // Oh well, hope for the best width = m_StreamConfig.width; height = m_StreamConfig.height; } diff --git a/app/utils.h b/app/utils.h index 61a0348f..f9105422 100644 --- a/app/utils.h +++ b/app/utils.h @@ -12,6 +12,7 @@ namespace WMUtils { bool isRunningWayland(); bool isRunningWindowManager(); bool isRunningDesktopEnvironment(); + bool hasDisplayUsableBounds(); QString getDrmCardOverride(); bool isGpuSlow(); } diff --git a/app/wm.cpp b/app/wm.cpp index 88bda333..2c070a61 100644 --- a/app/wm.cpp +++ b/app/wm.cpp @@ -205,6 +205,52 @@ bool WMUtils::isRunningDesktopEnvironment() #endif } +bool WMUtils::hasDisplayUsableBounds() +{ + static SDL_atomic_t hasDisplayUsableBounds; + + // If the value is not set yet, populate it now. + int val = SDL_AtomicGet(&hasDisplayUsableBounds); + if (!(val & VALUE_SET)) { + int numDisplays = SDL_GetNumVideoDisplays(); + bool hasUsableBounds = false; + + for (int i = 0; i < numDisplays; i++) { + SDL_Rect displayBounds; + SDL_Rect usableBounds; + + if (SDL_GetDisplayBounds(i, &displayBounds) != 0) { + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, + "SDL_GetDisplayBounds(%d) failed: %s", + i, SDL_GetError()); + continue; + } + + if (SDL_GetDisplayUsableBounds(i, &usableBounds) != 0) { + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, + "SDL_GetDisplayUsableBounds(%d) failed: %s", + i, SDL_GetError()); + continue; + } + + // If at least one display has usable bounds that differ from the + // complete bounds, we assume that usable bounds are accurate. + if (!SDL_RectEquals(&displayBounds, &usableBounds)) { + hasUsableBounds = true; + break; + } + } + + // Populate the value to return and have for next time. + // This can race with another thread populating the same data, + // but that's no big deal. + val = VALUE_SET | (hasUsableBounds ? VALUE_TRUE : 0); + SDL_AtomicSet(&hasDisplayUsableBounds, val); + } + + return !!(val & VALUE_TRUE); +} + bool WMUtils::isGpuSlow() { bool ret;