Skip to content

Conversation

@dkondor
Copy link
Contributor

@dkondor dkondor commented Apr 12, 2025

Also continuation of #2527 and #2626, creating a (mostly) complete solution for focus stealing prevention.

This adds an option (core/focus_on_map) that determines whether newly mapped (opened) views are focused. The default is true which keeps the current behavior (as I imagine the newly introduced behavior would be too restrictive for most users). When set to false, views must explicitly use the xdg-activation protocol to gain focus, even when first mapped.

This PR is organized into 4 parts:

This is currently a draft, since some functionality is still missing:

  • The main issue is that currently, newly mapped views are still stacked on top, but do not receive keyboard focus; ideally, they would be stacked below the currently active view, but I haven't yet figured out how to do this.
  • From a UI perspective, I actually don't like putting this option in core. it would be nice to collect all focus stealing / activation related options in one place (i.e. with xdg-activation); however, since this option needs to be accessed from core, I don't like the idea of putting it under a plugin. Maybe an alternative would be introducing one more signal, but that also sounds overkill.
  • Also, I'm unsure if this handles XWayland views correctly; I'm wondering if I should prevent focus here as well; in any case, I haven't tested with XWayland yet, but will do so next.
  • I'll need to do more testing, but potentially I want to separately track the active view for normal and self-generated tokens (my main concern is that some commands will not result in a new view opening, so they should not invalidate normal tokens, but this is of course and edge case).

dkondor added 9 commits June 16, 2025 20:41
This is necessary as some apps will send the "activate" request before their view is mapped.
…run by Wayfire

This is required for them to activate if focusing newly mapped views by default is disabled.
Dialogs are identified as a view with a parent.

This commit also moves shared code between xdg-shell and xwayland to a common location (toplevel_view_interface_t::focus_toplevel_on_map())
@killown
Copy link
Contributor

killown commented Jul 2, 2025

I think it's easier with python and a few lines:

from wayfire import WayfireSocket
sock = WayfireSocket()
last_focused_view_id = sock.get_focused_view()["id"]

sock.watch(["view-mapped", "view-focused"])


def should_continue(msg):
    if "view" in msg:
        if msg["view"] is not None:
            if msg["view"]["role"] == "toplevel":
                return msg["view"]
    return None


while True:
    msg = sock.read_next_event()
    view = should_continue(msg)

    if view is None:
        continue

    if msg["event"] == "view-mapped":
        sock.set_focus(last_focused_view_id)
    if msg["event"] == "view-focused":
        last_focused_view_id = sock.get_focused_view()["id"]

@ammen99
Copy link
Member

ammen99 commented Jul 2, 2025

I think it's easier with python and a few lines:


from wayfire import WayfireSocket
sock = WayfireSocket()

last_focused_view_id = sock.get_focused_view()["id"]

sock.watch(["view-mapped", "view-focused"])

while True:
    msg = sock.read_next_event()
    if msg["event"] == "view-mapped":
        sock.set_focus(last_focused_view_id)
    if msg["event"] == "view-focused":
        last_focused_view_id = sock.get_focused_view()["id"]

While this is a good workaround in practice, we still switch the focus and then back. Depending on the app, this might not be what we want.

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.

3 participants