Document focus-stealing issue with workaround - #3575
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #3575 +/- ##
==========================================
+ Coverage 74.39% 74.46% +0.06%
==========================================
Files 253 253
Lines 37817 37817
Branches 5107 5109 +2
==========================================
+ Hits 28135 28159 +24
+ Misses 9682 9658 -24 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
6af9bcb to
45595d6
Compare
There was a problem hiding this comment.
Pull request overview
Adds a user-facing option to show CopyQ’s main window and tray menu without taking keyboard focus from the currently active application, with platform-specific implementations and a new regression test.
Changes:
- Adds “Avoid grabbing keyboard focus” preference and corresponding
avoid_focus_stealingconfig option. - Introduces platform hooks for non-activating raise and (on X11) a keyboard grab–based intercept for non-activated main window interaction.
- Adds an automated test covering focus retention when showing the window with the option enabled.
Reviewed changes
Copilot reviewed 23 out of 23 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/ui/configtabgeneral.ui | Adds the new preference checkbox and tab order entry. |
| src/gui/configurationmanager.cpp | Binds the new config option and hides the checkbox on unsupported platforms. |
| src/common/appconfig.h | Defines Config::avoid_focus_stealing with default false. |
| src/gui/windowgeometryguard.h | Declares raiseWindowWithoutActivating(). |
| src/gui/windowgeometryguard.cpp | Implements raiseWindowWithoutActivating() and calls into platform window raise. |
| src/platform/platformwindow.h | Adds PlatformWindow::raiseWithoutActivating() API (default fallback to raise()). |
| src/platform/platformnativeinterface.h | Adds canAvoidFocusStealing(), focus-on-show hint, and keyboard intercept hooks. |
| src/platform/x11/x11platform.h | Declares X11 support for focus avoidance and keyboard intercept. |
| src/platform/x11/x11platform.cpp | Implements X11 focus-on-show hint and XGrabKeyboard/XUngrabKeyboard intercept. |
| src/platform/x11/x11platformwindow.h | Adds raiseWithoutActivating() override. |
| src/platform/x11/x11platformwindow.cpp | Implements non-activating raise via XRaiseWindow. |
| src/platform/win/winplatform.h | Reports focus-avoidance capability on Windows. |
| src/platform/win/winplatformwindow.h | Adds raiseWithoutActivating() override. |
| src/platform/win/winplatformwindow.cpp | Implements non-activating raise via SetWindowPos. |
| src/platform/mac/macplatform.h | Reports focus-avoidance capability on macOS. |
| src/platform/mac/macplatformwindow.h | Adds raiseWithoutActivating() override. |
| src/platform/mac/macplatformwindow.mm | Implements non-activating raise via orderFrontRegardless. |
| src/platform/dummy/dummyplatform.h | Implements new capability API as unsupported. |
| src/gui/mainwindow.h | Adds option field and state tracking for non-activating show. |
| src/gui/mainwindow.cpp | Uses the option to show menu/window without activation and installs/removes keyboard intercept. |
| src/tests/tests.h | Declares new avoidFocusStealing() test slot. |
| src/tests/tests_other.cpp | Adds a focus-retention test for the new option. |
| docs/known-issues.rst | Documents the issue and points users to the new preference. |
Comments suppressed due to low confidence (1)
src/gui/mainwindow.cpp:3030
- m_shownWithoutActivating is used to suppress close-on-unfocus behavior, but it’s never cleared when the window later becomes active (QEvent::WindowActivate). This means close_on_unfocus stays disabled for the rest of the visible lifetime, and the “shown without activating” state can leak into normal interactions. Consider clearing m_shownWithoutActivating (and removing the keyboard intercept if it’s no longer needed) once the window is actually activated, so close-on-unfocus can work again.
if (m_options.closeOnUnfocus && !m_shownWithoutActivating) {
if (
type == QEvent::WindowDeactivate
) {
hideWindowOnUnfocus(AppConfig().option<Config::close_on_unfocus_delay_ms>());
} else if (
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
40fc6ec to
8877bb3
Compare
When CopyQ shows its main window or tray menu, it steals keyboard focus from the previously active window. This can cause side effects such as file renames aborting, combo boxes selecting content, and short-lived widgets dismissing. Add a known-issues.rst section documenting the problem and a practical workaround: use next()/previous() global shortcuts to cycle clipboard history without opening any window. Closes: #3540 Assisted-by: Claude (Anthropic)
8877bb3 to
c65e039
Compare
Co-authored-by: Philippe Cloutier <chealer@gmail.com>
|
Thanks, @Chealer. I've applied your suggestions. |
Co-authored-by: Philippe Cloutier <chealer@gmail.com>
for more information, see https://pre-commit.ci
When CopyQ shows its main window or tray menu, it steals keyboard focus
from the previously active window. This can cause side effects such as
file renames aborting, combo boxes selecting content, and short-lived
widgets dismissing.
Add a known-issues.rst section documenting the problem and a practical
workaround: use next()/previous() global shortcuts to cycle clipboard
history without opening any window.
Closes: #3540
Assisted-by: Claude (Anthropic)