monitor: keep workspace monitor bindings on full reconnect (#13384)
When all monitors disconnect, non-active workspaces could migrate to the wrong output after reconnect. Preserve workspace ownership and re-apply assigned monitor bindings on connect.
This commit is contained in:
parent
82729db330
commit
c2bed4103c
3 changed files with 47 additions and 11 deletions
|
|
@ -3067,6 +3067,27 @@ void CCompositor::ensurePersistentWorkspacesPresent(const std::vector<SWorkspace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CCompositor::ensureWorkspacesOnAssignedMonitors() {
|
||||||
|
for (auto const& ws : getWorkspacesCopy()) {
|
||||||
|
if (!valid(ws) || ws->m_isSpecialWorkspace)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto RULE = g_pConfigManager->getWorkspaceRuleFor(ws);
|
||||||
|
if (RULE.monitor.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto PMONITOR = getMonitorFromString(RULE.monitor);
|
||||||
|
if (!PMONITOR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ws->m_monitor == PMONITOR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Log::logger->log(Log::DEBUG, "ensureWorkspacesOnAssignedMonitors: moving workspace {} to {}", ws->m_name, PMONITOR->m_name);
|
||||||
|
moveWorkspaceToMonitor(ws, PMONITOR, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<unsigned int> CCompositor::getVTNr() {
|
std::optional<unsigned int> CCompositor::getVTNr() {
|
||||||
if (!m_aqBackend->hasSession())
|
if (!m_aqBackend->hasSession())
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
|
|
||||||
|
|
@ -161,6 +161,7 @@ class CCompositor {
|
||||||
void updateSuspendedStates();
|
void updateSuspendedStates();
|
||||||
void onNewMonitor(SP<Aquamarine::IOutput> output);
|
void onNewMonitor(SP<Aquamarine::IOutput> output);
|
||||||
void ensurePersistentWorkspacesPresent(const std::vector<SWorkspaceRule>& rules, PHLWORKSPACE pWorkspace = nullptr);
|
void ensurePersistentWorkspacesPresent(const std::vector<SWorkspaceRule>& rules, PHLWORKSPACE pWorkspace = nullptr);
|
||||||
|
void ensureWorkspacesOnAssignedMonitors();
|
||||||
std::optional<unsigned int> getVTNr();
|
std::optional<unsigned int> getVTNr();
|
||||||
bool isVRRActiveOnAnyMonitor() const;
|
bool isVRRActiveOnAnyMonitor() const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,10 @@ void CMonitor::onConnect(bool noRule) {
|
||||||
m_zoomAnimProgress->setValueAndWarp(0.F);
|
m_zoomAnimProgress->setValueAndWarp(0.F);
|
||||||
m_zoomAnimFrameCounter = 0;
|
m_zoomAnimFrameCounter = 0;
|
||||||
|
|
||||||
g_pEventLoopManager->doLater([] { g_pConfigManager->ensurePersistentWorkspacesPresent(); });
|
g_pEventLoopManager->doLater([] {
|
||||||
|
g_pConfigManager->ensurePersistentWorkspacesPresent();
|
||||||
|
g_pCompositor->ensureWorkspacesOnAssignedMonitors();
|
||||||
|
});
|
||||||
|
|
||||||
m_listeners.frame = m_output->events.frame.listen([this] {
|
m_listeners.frame = m_output->events.frame.listen([this] {
|
||||||
if (m_frameScheduler)
|
if (m_frameScheduler)
|
||||||
|
|
@ -290,10 +293,16 @@ void CMonitor::onConnect(bool noRule) {
|
||||||
if (!valid(ws))
|
if (!valid(ws))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (ws->m_lastMonitor == m_name || g_pCompositor->m_monitors.size() == 1 /* avoid lost workspaces on recover */) {
|
const auto CURRENTMON = ws->m_monitor.lock();
|
||||||
|
const bool ORPHANED = !CURRENTMON || std::ranges::none_of(g_pCompositor->m_monitors, [&](const auto& mon) { return mon == CURRENTMON; });
|
||||||
|
const bool RETURNING = ws->m_lastMonitor == m_name;
|
||||||
|
const bool RECOVERY = g_pCompositor->m_monitors.size() == 1 && ORPHANED; // temporarily recover orphaned workspaces
|
||||||
|
|
||||||
|
if (RETURNING || RECOVERY) {
|
||||||
g_pCompositor->moveWorkspaceToMonitor(ws, m_self.lock());
|
g_pCompositor->moveWorkspaceToMonitor(ws, m_self.lock());
|
||||||
g_pDesktopAnimationManager->startAnimation(ws, CDesktopAnimationManager::ANIMATION_TYPE_IN, true, true);
|
g_pDesktopAnimationManager->startAnimation(ws, CDesktopAnimationManager::ANIMATION_TYPE_IN, true, true);
|
||||||
ws->m_lastMonitor = "";
|
if (RETURNING)
|
||||||
|
ws->m_lastMonitor = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -429,19 +438,24 @@ void CMonitor::onDisconnect(bool destroy) {
|
||||||
m_enabled = false;
|
m_enabled = false;
|
||||||
m_renderingInitPassed = false;
|
m_renderingInitPassed = false;
|
||||||
|
|
||||||
|
std::vector<PHLWORKSPACE> wspToMove;
|
||||||
|
for (auto const& w : g_pCompositor->getWorkspaces()) {
|
||||||
|
if (w->m_monitor == m_self || !w->m_monitor)
|
||||||
|
wspToMove.emplace_back(w.lock());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preserve ownership across cascaded monitor disconnects.
|
||||||
|
// The first disconnected monitor "owns" where a workspace should return.
|
||||||
|
for (auto const& w : wspToMove) {
|
||||||
|
if (w && w->m_lastMonitor.empty())
|
||||||
|
w->m_lastMonitor = m_name;
|
||||||
|
}
|
||||||
|
|
||||||
if (BACKUPMON) {
|
if (BACKUPMON) {
|
||||||
// snap cursor
|
// snap cursor
|
||||||
g_pCompositor->warpCursorTo(BACKUPMON->m_position + BACKUPMON->m_transformedSize / 2.F, true);
|
g_pCompositor->warpCursorTo(BACKUPMON->m_position + BACKUPMON->m_transformedSize / 2.F, true);
|
||||||
|
|
||||||
// move workspaces
|
|
||||||
std::vector<PHLWORKSPACE> wspToMove;
|
|
||||||
for (auto const& w : g_pCompositor->getWorkspaces()) {
|
|
||||||
if (w->m_monitor == m_self || !w->m_monitor)
|
|
||||||
wspToMove.emplace_back(w.lock());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto const& w : wspToMove) {
|
for (auto const& w : wspToMove) {
|
||||||
w->m_lastMonitor = m_name;
|
|
||||||
g_pCompositor->moveWorkspaceToMonitor(w, BACKUPMON);
|
g_pCompositor->moveWorkspaceToMonitor(w, BACKUPMON);
|
||||||
g_pDesktopAnimationManager->startAnimation(w, CDesktopAnimationManager::ANIMATION_TYPE_IN, true, true);
|
g_pDesktopAnimationManager->startAnimation(w, CDesktopAnimationManager::ANIMATION_TYPE_IN, true, true);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue