fix(focus): détecter correctement l'unfocus sur les backends Wayland
Le suivi du focus laissait les injections app-controlled actives lors d'une perte de focus réelle (fermeture de la fenêtre courante, retour à un bureau vide). On corrige la détection sur toute la chaîne : - FocusService: un app_id vide est désormais traité comme un unfocus réel (et non un focus transitoire ignoré), ce qui stoppe les injections liées à l'application. - Sway: on ignore les events 'new' (pas un changement de focus) et on relit le focus courant sur un event 'title' non focused. - WlrForeignToplevelBackend: suit _current_handle, le clear sur stop() et émet un FocusEvent vide quand le toplevel actuellement focus se ferme. Tests: test_focus_service + test_focus_watcher (67) OK; lot feature historique (295) OK. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -171,10 +171,14 @@ class SwayFocusBackend(FocusBackend):
|
||||
return
|
||||
|
||||
change = data.get("change")
|
||||
if change not in ("focus", "title", "new"):
|
||||
if change not in ("focus", "title"):
|
||||
return
|
||||
|
||||
event = _container_to_event(data.get("container") or {})
|
||||
if change == "title" and not (data.get("container") or {}).get("focused"):
|
||||
event = self.get_current()
|
||||
else:
|
||||
event = _container_to_event(data.get("container") or {})
|
||||
|
||||
if event is not None and self._on_focus is not None:
|
||||
self._on_focus(event)
|
||||
|
||||
|
||||
@ -69,6 +69,7 @@ class WlrForeignToplevelBackend(FocusBackend):
|
||||
# handle -> {"app_id": str, "title": str, "activated": bool}
|
||||
self._toplevels: Dict[Any, Dict[str, Any]] = {}
|
||||
self._current: Optional[FocusEvent] = None
|
||||
self._current_handle: Optional[Any] = None
|
||||
|
||||
@staticmethod
|
||||
def is_available() -> bool:
|
||||
@ -171,12 +172,20 @@ class WlrForeignToplevelBackend(FocusBackend):
|
||||
event = FocusEvent(
|
||||
app_id=info["app_id"], title=info["title"], backend=self.name
|
||||
)
|
||||
self._current_handle = handle
|
||||
self._current = event
|
||||
if self._on_focus is not None:
|
||||
self._on_focus(event)
|
||||
|
||||
def _on_closed(self, handle) -> None:
|
||||
self._toplevels.pop(handle, None)
|
||||
if handle != self._current_handle:
|
||||
return
|
||||
|
||||
self._current_handle = None
|
||||
self._current = FocusEvent(app_id="", title="", backend=self.name)
|
||||
if self._on_focus is not None:
|
||||
self._on_focus(self._current)
|
||||
|
||||
def _on_readable(self, _fd: int, condition: int) -> bool:
|
||||
if condition & (GLib.IO_HUP | GLib.IO_ERR):
|
||||
@ -207,4 +216,5 @@ class WlrForeignToplevelBackend(FocusBackend):
|
||||
self._manager = None
|
||||
self._registry = None
|
||||
self._toplevels.clear()
|
||||
self._current_handle = None
|
||||
self._current = None
|
||||
|
||||
Reference in New Issue
Block a user