Skip to content

Make Focus() / Blur() reliable and let Blur() return focus to the previous app #69

Description

@lijy91

Window::Focus() and Blur() follow the platforms' simplest calls and fail in common cases:

  • Windows: Focus() is SetForegroundWindow + SetFocus, which the foreground lock refuses when the app isn't in the foreground (only the taskbar flashes). Consider the AttachThreadInput / AllowSetForegroundWindow approaches, and check IsFocused() after focus changes.
  • Linux: gtk_window_present() without a timestamp is subject to focus-stealing prevention; use gtk_window_present_with_time() with the last event time.
  • Blur() should hand focus back to the previously active window or app. On macOS it only does orderBack:, and on Windows SetFocus(nullptr), which leaves the app active. Typical use: a launcher/search bar that hides and pastes into the previous app. Related: libnativeapi/nativeapi#59 (app-level hide on macOS).

Background:

Activity

  1. lijy91 commented on Oct 6, 2026

    @lijy91
    MemberAuthor

    Implemented in 8553d4d (workspace: libnativeapi/nativeapi@02c2e5a). No signature changes; the platform behavior is documented on Focus() / Blur().

    • Focus() and Show() remember the window or app that had the focus. Blur() hands it back, falls back to the window the platform would pick next, and does nothing on a window without focus.
    • macOS: activates the app (unless non-activating) and deminiaturizes; Blur() keys the previous own window, or yields activation to the previous app and activates it.
    • Windows: restores a minimized window and retries through AttachThreadInput when the foreground lock refuses; doesn't steal a child HWND's focus (Flutter). Blur() gives the foreground to the recorded window, else the next one down the Z order.
    • Linux: presents with the event/X server time as before; Blur() presents the previous own window, or on X11 activates the previous client's window (else the next in _NET_CLIENT_LIST_STACKING) through _NET_ACTIVE_WINDOW as a pager. Wayland can only return focus to another window of the same app.

    Verified (no mouse or keyboard input; the anchor is a second process):

    • macOS (real window server): 14 checks, 5/5 runs.
    • Windows 11: 7/8 runs fully green; one early run failed the cross-process return once and did not reproduce in 6 consecutive reruns.
    • Linux X11 (Xvfb + Openbox): 5/5.

    Tests: tests/window_focus_return_test.cpp (Windows, Linux X11), tests/window_focus_return_macos_test.mm.

    Still open: a real GNOME/KDE desktop run. Keeping this open until then.

  2. lijy91 commented on Oct 7, 2026

    @lijy91
    MemberAuthor

    GNOME result (Ubuntu 24.04, GNOME 46, core 1097ca6): tests/window_focus_return_test passes completely under GNOME's Xwayland with Mutter as the window manager: Focus() from a background process, Blur() back to the previous own window and to another process's window, and the fallback to the next window in _NET_CLIENT_LIST_STACKING.

    Still not covered: native Wayland clients (Wayland only allows returning focus to the same app's windows, as documented) and KDE.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions