Bug fixes for reclaiming focus.

This commit is contained in:
Storm Dragon committed 2026-10-15 13:39:39 -04:00
1 parent ea509509e4
commit 52a3fddc77
6 files changed
+30 -43

No files matched your search

+13 -4
View File
@@ -203,10 +203,19 @@ activation, then checks recovery of its native foreground and button focus.
It also checks Linux focus, mismatched window-manager/keyboard focus, disabled
windows, multiple visible applications, hidden windows, existing foreground,
and repeated recovery. It also reproduces X11 focus on the launcher child
with no Win32 foreground, as seen after AudioQuake exits: recovery must send
Wine's activation notification even when X11 focus already selects that child.
The fixture acknowledges ICCCM window visibility on
the private display; the runner propagates the fixture's actual exit status.
with no Win32 foreground, as seen after AudioQuake exits. Recovery must restore
both Win32 activation/control focus and native keyboard focus, even when X11
already selects that child. The fixture deliberately leaves `WM_STATE` unset,
matching Wine's real virtual-desktop children. Adding a synthetic window-manager
acknowledgement masks the failure: native `WM_TAKE_FOCUS` alone can otherwise be
ignored while Wine awaits that state change. The runner propagates the fixture's
actual exit status.
Recovery queues `SetWindowPos` activation on the application's own window
thread and sets native X11 focus without changing its size or position. It
does not wait on the application's window procedure. A dispatched request
alone is not acceptance: the fixture then checks Win32 foreground and the
restored button focus after the application processes activation.
After installing the updated helper and restarting the reader, open AudioQuake,
play and close a game, then Tab and Shift+Tab through the launcher. Check speech
+5 -20
View File
@@ -57,21 +57,6 @@ int main(int argc, char **argv) {
if (!atomReply) return 2;
const auto activeAtom = atomReply->atom;
std::free(atomReply);
constexpr char stateName[] = "WM_STATE";
auto *stateReply = xcb_intern_atom_reply(connection,
xcb_intern_atom(connection, 0, sizeof(stateName) - 1, stateName), nullptr);
if (!stateReply) return 2;
const auto stateAtom = stateReply->atom;
std::free(stateReply);
auto acknowledge = [&](HWND window) {
const auto xid = static_cast<xcb_window_t>(reinterpret_cast<uintptr_t>(
GetPropW(window, L"__wine_x11_whole_window")));
const uint32_t state[] = {1, XCB_WINDOW_NONE}; // ICCCM NormalState.
xcb_change_property(connection, XCB_PROP_MODE_REPLACE, xid,
stateAtom, stateAtom, 32, 2, state);
xcb_flush(connection);
pump();
};
const auto linuxWindow = xcb_generate_id(connection);
xcb_create_window(connection, XCB_COPY_FROM_PARENT, linuxWindow, screen->root,
0, 0, 20, 20, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, 0, nullptr);
@@ -97,7 +82,7 @@ int main(int argc, char **argv) {
ShowWindow(launcher, SW_HIDE);
pump();
ShowWindow(launcher, SW_SHOWNOACTIVATE);
acknowledge(launcher);
pump();
focus(linuxWindow, linuxWindow);
ok &= check(!GetForegroundWindow(), "Linux focus clears Wine foreground");
ok &= check(!restore_virtual_desktop_focus() && !GetForegroundWindow(), "Linux focus is never taken");
@@ -111,7 +96,7 @@ int main(int argc, char **argv) {
ok &= check(!restore_virtual_desktop_focus(), "disabled application is not activated");
EnableWindow(launcher, TRUE);
ShowWindow(other, SW_SHOWNOACTIVATE);
acknowledge(other);
pump();
focus(linuxWindow, linuxWindow);
focus(desktop, desktop);
ok &= check(!restore_virtual_desktop_focus() && !GetForegroundWindow(), "ambiguous applications are not chosen");
@@ -126,7 +111,7 @@ int main(int argc, char **argv) {
ShowWindow(launcher, SW_HIDE);
pump();
ShowWindow(launcher, SW_SHOWNOACTIVATE);
acknowledge(launcher);
pump();
focus(linuxWindow, linuxWindow);
focus(desktop, desktop);
ok &= check(restore_virtual_desktop_focus(), "later workspace return recovers again");
@@ -134,14 +119,14 @@ int main(int argc, char **argv) {
ShowWindow(launcher, SW_HIDE);
pump();
ShowWindow(launcher, SW_SHOWNOACTIVATE);
acknowledge(launcher);
pump();
focus(linuxWindow, linuxWindow);
const auto launcherXid = static_cast<xcb_window_t>(reinterpret_cast<uintptr_t>(
GetPropW(launcher, L"__wine_x11_whole_window")));
focus(launcherXid, linuxWindow);
ok &= check(!restore_virtual_desktop_focus(), "focused child requires window manager desktop ownership");
ShowWindow(other, SW_SHOWNOACTIVATE);
acknowledge(other);
pump();
focus(launcherXid, desktop);
ok &= check(!restore_virtual_desktop_focus(), "focused child does not bypass ambiguous applications");
ShowWindow(other, SW_HIDE);