Skip to content

Add option to disable auto-raise for focus-follows-cursor - #2535

Closed
perpetualbits wants to merge 3 commits into
pop-os:masterfrom
perpetualbits:focus-follows-cursor-no-raise
Closed

Add option to disable auto-raise for focus-follows-cursor#2535
perpetualbits wants to merge 3 commits into
pop-os:masterfrom
perpetualbits:focus-follows-cursor-no-raise

Conversation

@perpetualbits

@perpetualbits perpetualbits commented Jul 8, 2026

Copy link
Copy Markdown
  • I have disclosed use of any AI generated code in my commit messages.
  • I understand these changes in full and will be able to respond to review comments.
  • My change is accurately described in the commit message.
  • My contribution is tested and working as described.
  • I have read the Developer Certificate of Origin and certify my contribution under its conditions.

Addresses #863.

AI assistance disclosure

This change was developed with AI assistance (Claude Code); the commits carry an
Assisted-by: trailer. Per your policy I want to be upfront about it rather than
hide it. The design decisions here are mine and I understand the change in full:
the intent-enum approach, the reason a persisted mark is needed (see
Implementation), and the trade-offs in the scope note are all things I can defend
in review. It was validated by me on real hardware (see Testing). I'm happy to
walk through any part of it or make changes on request.

Summary

Adds a new compositor config option, focus_follows_cursor_raise (default true,
preserving current behaviour), that decouples raising from focusing when focus
follows the cursor.

With focus_follows_cursor enabled and focus_follows_cursor_raise set to
false, moving the pointer over a floating window gives it keyboard focus
without raising it to the front ("sloppy focus"). Explicit focus — a click, a
keyboard focus action, or an application activating itself — still raises the
window as before.

Motivation

Today focus and raising are coupled: any focus change runs update_active(),
which raises the focused floating window. With focus-follows-cursor that means a
window jumps to the front merely because the pointer crossed it. This option lets
the two behaviours be chosen independently, which is the long-standing "focus
follows mouse, no auto-raise" model many users prefer.

Implementation

  • New field focus_follows_cursor_raise in cosmic-comp-config (default true),
    with live reload wired into the existing config watcher.
  • A small Raise { Yes, No } intent enum threaded through Shell::set_focus. A
    named enum is used rather than a second bool next to the existing
    update_cursor argument, so call sites stay self-documenting and the compiler
    enforces completeness — a missed call site cannot build. Every explicit-focus
    call site passes Raise::Yes; only the focus-follows-cursor timer passes the
    configured choice.
  • A persisted no_raise_window mark on Shell. This is needed because focus is
    reconciled periodically: update_active() is re-run and would re-raise the
    focused floating window on the next pass, so suppressing the raise once is not
    enough. Instead the hovered window is recorded and update_active() skips
    raising it every time it runs, under the same write lock that runs
    update_active() so the two never disagree. The mark is set on passive focus
    with raising disabled and cleared on any explicit focus.

Testing

  • cargo build and cargo fmt --check are clean.
  • The default (focus_follows_cursor_raise = true) is covered by a unit test in
    cosmic-comp-config.
  • Validated on real hardware: run as the session compositor. With
    focus_follows_cursor on and focus_follows_cursor_raise off, hovering a
    partly-covered floating window focuses it without raising it, and clicking still
    raises it. Toggling focus_follows_cursor_raise at runtime switches the
    behaviour immediately (live reload).

Note: focus-follows-cursor only triggers under the KMS backend, since the
follow-cursor logic lives in the relative-motion (PointerMotion) handler; the
nested winit/x11 backends deliver absolute motion, so this must be exercised on
a real session rather than nested.

Note on scope

The no-raise mark is a single value on Shell rather than per-seat. In the common
single-seat case this is exact. In a multi-seat setup, one seat's explicit focus
clears another seat's hover mark, so the other seat's hovered window can be
re-raised on the next reconciliation. This keeps the change small; happy to make
it per-seat if preferred.

@leviport

leviport commented Jul 8, 2026

Copy link
Copy Markdown
Member

The PR template is required.

Assisted-by: Claude Code (Anthropic)
Signed-off-by: Roland Nagtegaal <perpetualbits@gmail.com>
Assisted-by: Claude Code (Anthropic)
Signed-off-by: Roland Nagtegaal <perpetualbits@gmail.com>
Add a Raise intent enum threaded through Shell::set_focus and a single
persisted no-raise window mark on Shell. update_active() skips raising the
marked window, so focus-follows-cursor can move focus without lifting the
window (sloppy focus) when focus_follows_cursor_raise is false. Explicit
focus (click, keyboard, activation) passes Raise::Yes and still raises.

Assisted-by: Claude Code (Anthropic)
Signed-off-by: Roland Nagtegaal <perpetualbits@gmail.com>
@perpetualbits

Copy link
Copy Markdown
Author

Superseded by #2612.

While addressing the checklist request I re-tested this change on real hardware
and found a bug: with raise disabled, moving the pointer off a hovered floating
window onto the empty desktop still raised the window. Rather than patch a stalled
PR, I've opened a fresh, fully-documented replacement — #2612 — containing the
same feature plus the fix (root cause and fix explained in the description and
commit message), with the required checklist completed and AI assistance
disclosed.

Closing this in favour of #2612 to keep review in one place. Thanks!

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants