Skip to content

fix(libei): only restart the capture session on device change under GNOME - #480

Merged
feschber merged 1 commit into
feschber:mainfrom
mrcha033:fix/gate-eis-session-restart-to-gnome
Aug 31, 2026
Merged

fix(libei): only restart the capture session on device change under GNOME#480
feschber merged 1 commit into
feschber:mainfrom
mrcha033:fix/gate-eis-session-restart-to-gnome

Conversation

@mrcha033

@mrcha033 mrcha033 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Problem

handle_ei_event treats EiEvent::DeviceRemoved as a reason to release and recreate the entire input-capture session:

EiEvent::SeatRemoved(_) | /* EiEvent::DeviceAdded(_) | */ EiEvent::DeviceRemoved(_) => {
    log::debug!("releasing session: {ei_event:?}");
    release_session.notify_waiters();
}

That is a workaround for mutter, which stops delivering events after a device change — the same class of bug the comment above already documents for barrier updates. But it runs on every compositor.

On everything else the restart is pure overhead: each one costs a CreateSession + ConnectToEIS round trip, and devices come and go often enough that the session is rebuilt continuously during normal use.

On compositors that keep per-session state around it is actively harmful. Hyprland allocates a keymap fd per EIS session and only reaps a session when the portal client destroys the resource, which does not happen when we drop a session this way. Sessions accumulate, and CInputCaptureProtocol::updateKeymap() walks all of them on every focus change, so the leak grows quadratically. On my machine Hyprland reached 45k open fds and crashed (xkb_keymap_new_from_names() returns NULL under EMFILE and is dereferenced unchecked). That is a Hyprland bug and I am reporting it there separately, but lan-mouse is what drives the churn: ~35 ConnectToEIS per 38 minutes of ordinary use.

Change

Gate the device-change restart on GNOME. SeatRemoved still releases unconditionally — a seat disappearing genuinely invalidates the session.

The default comes from XDG_CURRENT_DESKTOP; LM_RESTART_SESSION_ON_DEVICE_CHANGE=1/0 overrides it, for compositors that need the mutter behaviour without advertising themselves as GNOME.

Testing

  • Hyprland 0.56.1: ConnectToEIS churn went from ~35 per 38 min to 0, capture/release across the barrier unchanged over a multi-hour session.
  • cargo clippy --all-targets and cargo fmt --check clean.

Note: splitting the match arm makes rustfmt format that block for the first time (it previously bailed on the inline comment inside the multi-pattern arm), so the commit also carries two one-line reformats it demanded in adjacent arms. Happy to drop them into a separate commit if you'd rather keep the diff to the behaviour change.

I do not have a GNOME setup to verify the mutter path still behaves — it should be unchanged, since XDG_CURRENT_DESKTOP contains GNOME there, but a second pair of eyes on that would be good.

@mrcha033
mrcha033 force-pushed the fix/gate-eis-session-restart-to-gnome branch from 10a9620 to 8c59706 Compare August 6, 2026 23:55
…NOME

`EiEvent::DeviceRemoved` currently tears down and recreates the whole
input-capture session. That is a workaround for mutter, which stops
delivering events after a device change, but it is applied on every
compositor.

Elsewhere the restart is pure overhead: every device change costs a
CreateSession + ConnectToEIS round trip. On compositors that keep
per-session state around it is worse than overhead - Hyprland keeps a
keymap fd per EIS session and never reaps sessions whose client went
away, so the churn drives it out of file descriptors and eventually
crashes it. On this machine the churn ran at ~35 ConnectToEIS per 38
minutes; gating it to GNOME brought that to 0 with no change in capture
behaviour.

`SeatRemoved` still releases unconditionally - a seat going away really
does invalidate the session.

The default is derived from XDG_CURRENT_DESKTOP and can be overridden
with LM_RESTART_SESSION_ON_DEVICE_CHANGE=1/0 for compositors that need
the mutter behaviour but do not advertise themselves as GNOME.
@feschber
feschber force-pushed the fix/gate-eis-session-restart-to-gnome branch from 8c59706 to 78df7a0 Compare August 31, 2026 11:26
@feschber

Copy link
Copy Markdown
Owner

Is there an open issue on Mutter about this?

I'm also considering dropping support for older versions of GNOME that necessitate the recreation of the capture session for every barrier update.

@feschber
feschber merged commit 6b1edde into feschber:main Aug 31, 2026
20 checks passed
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