diff options
| author | John Mylchreest <jmylchreest@gmail.com> | 2026-01-08 21:27:00 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-08 22:27:00 +0100 |
| commit | 5b1b79c29c5e0ea974b2a9da5d122dd0f3bedca6 (patch) | |
| tree | 3285d6e97dc25ead427cc541edadb1c1d9e84d7d /src/helpers/Monitor.cpp | |
| parent | eb623bd91dfdab468600924aabac51f06d3a8f99 (diff) | |
fix: handle fullscreen windows on special workspaces (#12851)
* fix: handle fullscreen windows on special workspaces
inFullscreenMode() only checked m_activeWorkspace, missing fullscreen
windows on special workspaces. This caused crashes and incorrect
behavior when fullscreen windows were on special workspaces.
Changes:
- inFullscreenMode() now checks special workspace first since it
renders on top of regular workspaces
- Added getFullscreenWindow() helper to safely get fullscreen window
from either active or special workspace
- Updated callers (shouldSkipScheduleFrameOnMouseEvent, Renderer,
getFSImageDescription) to use the new helper
- Reset m_aboveFullscreen for layer surfaces when opening, closing,
or stealing special workspaces between monitors
* test: add special workspace fullscreen detection tests
Add tests for the new special workspace fullscreen handling introduced
in the previous commit. The tests cover:
1. Fullscreen detection on special workspace - verifies that a window
made fullscreen on a special workspace is correctly detected
2. Special workspace fullscreen precedence - verifies that when both
regular and special workspaces have fullscreen windows, the special
workspace window can be focused when the special workspace is opened
3. Toggle special workspace behavior - verifies that toggling the
special workspace off properly hides it and returns focus to the
regular workspace's fullscreen window
These tests exercise the key code paths modified in the fix:
- inFullscreenMode() checking special workspace first
- getFullscreenWindow() helper returning correct window
- Layer surface m_aboveFullscreen reset on special workspace toggle
Diffstat (limited to 'src/helpers/Monitor.cpp')
| -rw-r--r-- | src/helpers/Monitor.cpp | 38 |
1 files changed, 34 insertions, 4 deletions
diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 5069f5d8..397df6ee 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -1026,8 +1026,8 @@ bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() { static auto PMINRR = CConfigValue<Hyprlang::INT>("cursor:min_refresh_rate"); // skip scheduling extra frames for fullsreen apps with vrr - const bool shouldSkip = inFullscreenMode() && (*PNOBREAK == 1 || (*PNOBREAK == 2 && m_activeWorkspace->getFullscreenWindow()->getContentType() == CONTENT_TYPE_GAME)) && - m_output->state->state().adaptiveSync; + const auto FS_WINDOW = getFullscreenWindow(); + const bool shouldSkip = FS_WINDOW && (*PNOBREAK == 1 || (*PNOBREAK == 2 && FS_WINDOW->getContentType() == CONTENT_TYPE_GAME)) && m_output->state->state().adaptiveSync; // keep requested minimum refresh rate if (shouldSkip && *PMINRR && m_lastPresentationTimer.getMillis() > 1000.0f / *PMINRR) { @@ -1357,6 +1357,12 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) { g_pDesktopAnimationManager->startAnimation(m_activeSpecialWorkspace, CDesktopAnimationManager::ANIMATION_TYPE_OUT, false); g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", "," + m_name}); g_pEventManager->postEvent(SHyprIPCEvent{"activespecialv2", ",," + m_name}); + + // Reset layer surface state when closing special workspace + for (auto const& ls : g_pCompositor->m_layers) { + if (ls->m_monitor == m_self) + ls->m_aboveFullscreen = false; + } } m_activeSpecialWorkspace.reset(); @@ -1396,6 +1402,12 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) { g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", "," + PMWSOWNER->m_name}); g_pEventManager->postEvent(SHyprIPCEvent{"activespecialv2", ",," + PMWSOWNER->m_name}); + // Reset layer surfaces on the old monitor when special workspace is stolen + for (auto const& ls : g_pCompositor->m_layers) { + if (ls->m_monitor == PMWSOWNER) + ls->m_aboveFullscreen = false; + } + const auto PACTIVEWORKSPACE = PMWSOWNER->m_activeWorkspace; g_pDesktopAnimationManager->setFullscreenFadeAnimation(PACTIVEWORKSPACE, PACTIVEWORKSPACE && PACTIVEWORKSPACE->m_hasFullscreenWindow ? CDesktopAnimationManager::ANIMATION_TYPE_IN : @@ -1409,6 +1421,12 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) { m_activeSpecialWorkspace = pWorkspace; m_activeSpecialWorkspace->m_visible = true; + // Reset layer surface state when opening special workspace + for (auto const& ls : g_pCompositor->m_layers) { + if (ls->m_monitor == m_self) + ls->m_aboveFullscreen = false; + } + if (POLDSPECIAL) POLDSPECIAL->m_events.activeChanged.emit(); @@ -2017,16 +2035,28 @@ bool CMonitor::inHDR() { } bool CMonitor::inFullscreenMode() { + // Check special workspace first since it renders on top of regular workspaces + if (m_activeSpecialWorkspace && m_activeSpecialWorkspace->m_hasFullscreenWindow && m_activeSpecialWorkspace->m_fullscreenMode == FSMODE_FULLSCREEN) + return true; return m_activeWorkspace && m_activeWorkspace->m_hasFullscreenWindow && m_activeWorkspace->m_fullscreenMode == FSMODE_FULLSCREEN; } +PHLWINDOW CMonitor::getFullscreenWindow() { + // Check special workspace first since it renders on top of regular workspaces + if (m_activeSpecialWorkspace && m_activeSpecialWorkspace->m_hasFullscreenWindow && m_activeSpecialWorkspace->m_fullscreenMode == FSMODE_FULLSCREEN) + return m_activeSpecialWorkspace->getFullscreenWindow(); + if (m_activeWorkspace && m_activeWorkspace->m_hasFullscreenWindow && m_activeWorkspace->m_fullscreenMode == FSMODE_FULLSCREEN) + return m_activeWorkspace->getFullscreenWindow(); + return nullptr; +} + std::optional<NColorManagement::PImageDescription> CMonitor::getFSImageDescription() { if (!inFullscreenMode()) return {}; - const auto FS_WINDOW = m_activeWorkspace->getFullscreenWindow(); + const auto FS_WINDOW = getFullscreenWindow(); if (!FS_WINDOW) - return {}; // should be unreachable + return {}; const auto ROOT_SURF = FS_WINDOW->wlSurface()->resource(); const auto SURF = ROOT_SURF->findWithCM(); |
