From 4c38659f20c3479369bb50e0f70ac11b684deb10 Mon Sep 17 00:00:00 2001 From: Sébastien Dailly Date: Thu, 25 Jun 2026 13:46:15 +0200 Subject: Listen the active window if the name is updated --- xlib.py | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/xlib.py b/xlib.py index b4954da..ba8f02b 100644 --- a/xlib.py +++ b/xlib.py @@ -1,5 +1,6 @@ from threading import Thread +from contextlib import contextmanager import Xlib import Xlib.display @@ -11,13 +12,27 @@ from interfaces.message import Debug from interfaces import desktopEvent from consumer import Mapping + +@contextmanager +def window_obj(disp, win_id): + """Simplify dealing with BadWindow (make it either valid or None)""" + window_obj = None + if win_id: + try: + window_obj = disp.create_resource_object('window', win_id) + except Xlib.error.XError: + pass + yield window_obj + + @interface.implementer(desktopEvent.IDesktop) class Listener(Thread): def __init__(self, mapping): super().__init__() self.mapping = mapping - self.active_window = None + self.active_name = None + self.active_window_id = None self.last_code = None self.running = False self.daemon = True @@ -25,7 +40,7 @@ class Listener(Thread): def getForegroundWindowTitle(self): """ Return the name of the selected window """ - return self.active_window + return self.active_name def run(self): self.disp = Xlib.display.Display() @@ -43,7 +58,7 @@ class Listener(Thread): try: self.handle_event(root, self.disp.next_event()) except Exception as e: - component.handle(Debug( str(e) )) + component.handle(Debug(str(e))) print(e) def get_property_value(self, window, property_): @@ -54,7 +69,6 @@ class Listener(Thread): return str(prop_name.value).lower() return None - def handle_event(self, root, _event): try: window_id_property = root.get_full_property( @@ -64,18 +78,25 @@ class Listener(Thread): if window_id_property is None: return window_id = window_id_property.value[0] - window = self.disp.create_resource_object('window', window_id) - - window_name = self.get_property_value(window, self.NET_WM_NAME) \ - or self.get_property_value(window, self.WM_NAME) - class_name = self.get_property_value(window, self.WM_CLASS) + if self.active_window_id is not None and window_id != self.active_window_id: + with window_obj(self.disp, self.active_window_id) as window: + if window is not None: + window.change_attributes(event_mask=Xlib.X.NoEventMask) + with window_obj(self.disp, window_id) as window: + window.change_attributes(event_mask=Xlib.X.PropertyChangeMask) + self.active_window_id = window_id + + with window_obj(self.disp, self.active_window_id) as window: + window_name = self.get_property_value(window, self.NET_WM_NAME) \ + or self.get_property_value(window, self.WM_NAME) + class_name = self.get_property_value(window, self.WM_CLASS) except Xlib.error.XError: return - if window_name is None or window_name == self.active_window: + if window_name is None or window_name == self.active_name: return - self.active_window = window_name + self.active_name = window_name found = False # Create a reveverse dictionnary for getting the users added first -- cgit v1.2.3