Fix swiping onto a new workspace with multiple monitors. (#1971)

The previous code could run into issues into the following circumstances:

* The focused monitor is on its rightmost workspace with ID `i`.
* Another monitor has a workspace with ID `i+1`.
* `workspace_swipe_create_new` is enabled.

Then, swiping rightwards attempts to target a new workspace with ID
`i+1`: completing the swipe gesture unintentionally focuses that
workspace on whichever monitor it's already on while leaving the active
monitor in a broken state where it shows no windows but creates new
windows on the workspace it was previously on; and cancelling the swipe
gesture shifts the entire workspace `i+1` to the right by the width of
the active monitor.

By choosing an ID that doesn't exist, this problematic behavior is
avoided.  More specifically, it's the smallest ID greater than any
existing workspace's ID, because otherwise the new workspace that was
seemingly just created to the right of the rightmost workspace could end
up somewhere in the middle of the workspace order.
This commit is contained in:
Andrew Pritchard 2023-04-07 04:18:53 -07:00 committed by GitHub
parent 24ace03780
commit dfb78e0593
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -56,9 +56,21 @@ void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
auto workspaceIDLeft = getWorkspaceIDFromString(*PSWIPENUMBER ? "-1" : "m-1", wsname); auto workspaceIDLeft = getWorkspaceIDFromString(*PSWIPENUMBER ? "-1" : "m-1", wsname);
auto workspaceIDRight = getWorkspaceIDFromString(*PSWIPENUMBER ? "+1" : "m+1", wsname); auto workspaceIDRight = getWorkspaceIDFromString(*PSWIPENUMBER ? "+1" : "m+1", wsname);
if ((workspaceIDRight <= m_sActiveSwipe.pWorkspaceBegin->m_iID || (workspaceIDRight == workspaceIDLeft && workspaceIDLeft == m_sActiveSwipe.pWorkspaceBegin->m_iID)) && // If we've been swiping off the right end with PSWIPENEW enabled, there is
*PSWIPENEW) { // no workspace there yet, and we need to choose an ID for a new one now.
workspaceIDRight = m_sActiveSwipe.pWorkspaceBegin->m_iID > 0 ? m_sActiveSwipe.pWorkspaceBegin->m_iID + 1 : 1; // With multiple monitors, it might not be appropriate to choose one more
// than the ID of the workspace we're swiping from, because that ID might
// just be on another monitor. It's also not just the smallest unused ID,
// because that could be a gap in the existing workspace numbers, and it'd
// be counterintuitive to swipe rightwards onto a new workspace and end up
// left of where we started. Instead, it's one more than the greatest
// workspace ID that currently exists.
if (workspaceIDRight <= m_sActiveSwipe.pWorkspaceBegin->m_iID && *PSWIPENEW) {
int maxWorkspace = 0;
for (const auto& ws : g_pCompositor->m_vWorkspaces) {
maxWorkspace = std::max(maxWorkspace, ws->m_iID);
}
workspaceIDRight = maxWorkspace + 1;
} }
auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); // not guaranteed if PSWIPENEW || PSWIPENUMBER auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); // not guaranteed if PSWIPENEW || PSWIPENUMBER
@ -305,4 +317,4 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
beginWorkspaceSwipe(); beginWorkspaceSwipe();
} }
} }
} }