Pass focus when KWin falls back to the desktop window on close/minimize (issue 136) - #195
Open
dev-ahad-ali wants to merge 1 commit into
Open
Conversation
When the active window is closed or minimized, KWin activates another window before it emits `windowRemoved` or `minimizedChanged`. With KWin's default `SeparateScreenFocus=true`, its focus chain only considers windows whose frame intersects the screen. When all other windows are entirely off-screen (e.g. a full-width column with no gaps and margins), KWin finds no candidate and activates the desktop window instead. Karousel then saw the desktop window as the last focused client, so it skipped passing focus from the closed window, leaving no window focused. Treat a desktop window that got activated right after the closed/minimized window as a KWin fallback rather than a real focus change, and still pass focus to the neighboring window in that case. Tests: model KWin's pre-removal activation (including the desktop window fallback) in the mock workspace, and make MockQSignal match Qt by not delivering an emission to handlers connected during that emission.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #136. Very likely also fixes #146 (same trigger: only one window visible, neighbors entirely off-screen).
Problem
With no gaps and margins, a full-width column's neighbors lie entirely off-screen. Closing (or minimizing) that column's window then leaves no window focused.
Cause
On Wayland, KWin activates another window before it emits
windowRemoved(Workspace::removeWaylandWindow→activateNextWindow) and beforeminimizedChanged(XdgToplevelWindow::doMinimize→activateNextWindow).Since Plasma 6,
SeparateScreenFocusdefaults totrue(kwin.kcfg). With it on,FocusChain::isUsableFocusCandidaterequiresWindow::isOnOutput, which isoutput->geometry().intersects(frameGeometry()). A neighbor that is entirely off-screen fails that check, so KWin finds no candidate and falls back to activating the desktop window (findDesktop).Karousel receives
windowActivated(desktopWindow)first, records it as the last focused client, and thenClientManager.removeClientsees the closed window is no longer the last focused client and downgradespassFocustoNone. Karousel's own neighbor-focus logic never runs. With a left/right margin the neighbor intersects the screen by a few pixels, KWin's chain accepts it, and everything works, which is why the bug only shows with zero margins.(Verified against the Plasma/6.7 sources:
activation.cpp,focuschain.cpp,window.cpp,xdgshellwindow.cpp,kwin.kcfg.)Fix
ClientManagernow remembers the previously focused client. If the last focused client is a desktop window and the client being removed/minimized is the one focused right before it, treat that as KWin's fallback rather than a real focus change and still pass focus. Karousel'sWindow.focus()goes throughWorkspace.activeWindow = …→activateWindow→requestFocus, which has no on-screen check, so focusing the off-screen neighbor succeeds and the resulting focus event scrolls it into view.desktopWindowis added to theKwinClientinterface (KWin scripting API:Q_PROPERTY(bool desktopWindow READ isDesktop CONSTANT)).Tests
MockWorkspace.removeWindowand the mockminimizedsetter now mimicWorkspace::activateNextWindow: only windows intersecting the screen are candidates, otherwise the desktop window gets activated (a desktop window is now always present in the mock workspace).passFocus.tscover close and minimize with zero gaps and full-width windows. Both fail on master (focus stays onDesktop) and pass with the fix.MockQSignal.fireno longer delivers an emission to handlers connected (or disconnected) during that emission, matching Qt. Without this, minimizing a tiled window in the mock ping-pongs betweenTiledandTiledMinimizedforever.make lintandmake test(51 tests) pass.