Уведомление об изменениях заголовка окна

… без опроса.

Я хочу определить, когда меняется окно, в котором происходит фокусировка, так что я могу обновить часть пользовательского графического интерфейса в моей системе.

Пункты интересов:

  • уведомления в режиме реального времени. Имея отставание 0,2 с в порядке, наличие отставания 1 с является мехом, с запасом 5 с совершенно неприемлемым.
  • ресурсоемкость: по этой причине я хочу избежать опроса. Запуск xdotool getactivewindow getwindowname каждые, скажем, полсекунды, работает вполне нормально … но порождает 2 процесса в секунду все, что мне нравится в моей системе?

В bspwm можно использовать bspc subscribe которая печатает строку с некоторыми (очень) базовыми статистическими bspc subscribe , каждый раз при изменении фокуса окна. Сначала этот подход кажется приятным, но прислушаться к этому не обнаружит, когда заголовок окна изменится сам по себе (например, изменение вкладок в веб-браузере останется незамеченным таким образом.)

Итак, каждый раз, когда на Linux появляется новый процесс, каждые полторы секунды, а если нет, как я могу сделать что-то лучше?

Одна вещь, которая приходит мне на ум – попытаться подражать тому, что делают окна-менеджеры. Но могу ли я писать крючки для таких событий, как «создание окна», «запрос на изменение названия» и т. Д. Независимо от рабочего диспетчера окон, или мне нужно стать самим оконным менеджером? Нужно ли мне root для этого?

(Еще одна вещь, которая пришла мне в голову, – это посмотреть на xdotool и подражать только тем, которые меня интересуют, чтобы я мог избежать всех шаблонов нереста процесса, но он все равно будет опросом.)

  • Как настроить параметры разрешения X
  • Xorg Dualhead карты клавиатуры и мыши ввода только на конкретный экран
  • Ярлык клавиатуры для замены средней кнопки мыши
  • Определенный пользователь не может войти (после подключения телевизора), не может понять, почему
  • Есть ли способ изменить размер окна графического интерфейса приложения масштаба?
  • как создать пользовательский сеанс рабочего стола для x2go
  • Начните два сервера X при загрузке на RHEL
  • Xrandr debian черный экран при изменении разрешения
  • 2 Solutions collect form web for “Уведомление об изменениях заголовка окна”

    Я не мог заставить ваш подход сфокусироваться на надежную работу под Kwin 4.x, но современные оконные менеджеры поддерживают свойство _NET_ACTIVE_WINDOW в корневом окне, которое вы можете прослушать для изменений.

    Вот реализация Python:

     #!/usr/bin/python from contextlib import contextmanager import Xlib import Xlib.display disp = Xlib.display.Display() root = disp.screen().root NET_ACTIVE_WINDOW = disp.intern_atom('_NET_ACTIVE_WINDOW') NET_WM_NAME = disp.intern_atom('_NET_WM_NAME') # UTF-8 WM_NAME = disp.intern_atom('WM_NAME') # Legacy encoding last_seen = { 'xid': None, 'title': None } @contextmanager def window_obj(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 def get_active_window(): win_id = root.get_full_property(NET_ACTIVE_WINDOW, Xlib.X.AnyPropertyType).value[0] focus_changed = (win_id != last_seen['xid']) if focus_changed: with window_obj(last_seen['xid']) as old_win: if old_win: old_win.change_attributes(event_mask=Xlib.X.NoEventMask) last_seen['xid'] = win_id with window_obj(win_id) as new_win: if new_win: new_win.change_attributes(event_mask=Xlib.X.PropertyChangeMask) return win_id, focus_changed def _get_window_name_inner(win_obj): """Simplify dealing with _NET_WM_NAME (UTF-8) vs. WM_NAME (legacy)""" for atom in (NET_WM_NAME, WM_NAME): try: window_name = win_obj.get_full_property(atom, 0) except UnicodeDecodeError: # Apparently a Debian distro package bug title = "<could not decode characters>" else: if window_name: win_name = window_name.value if isinstance(win_name, bytes): # Apparently COMPOUND_TEXT is so arcane that this is how # tools like xprop deal with receiving it these days win_name = win_name.decode('latin1', 'replace') return win_name else: title = "<unnamed window>" return "{} (XID: {})".format(title, win_obj.id) def get_window_name(win_id): if not win_id: last_seen['title'] = "<no window id>" return last_seen['title'] title_changed = False with window_obj(win_id) as wobj: if wobj: win_title = _get_window_name_inner(wobj) title_changed = (win_title != last_seen['title']) last_seen['title'] = win_title return last_seen['title'], title_changed def handle_xevent(event): if event.type != Xlib.X.PropertyNotify: return changed = False if event.atom == NET_ACTIVE_WINDOW: if get_active_window()[1]: changed = changed or get_window_name(last_seen['xid'])[1] elif event.atom in (NET_WM_NAME, WM_NAME): changed = changed or get_window_name(last_seen['xid'])[1] if changed: handle_change(last_seen) def handle_change(new_state): """Replace this with whatever you want to actually do""" print(new_state) if __name__ == '__main__': root.change_attributes(event_mask=Xlib.X.PropertyChangeMask) get_window_name(get_active_window()[0]) handle_change(last_seen) while True: # next_event() sleeps until we get an event handle_xevent(disp.next_event()) 

    Более полная заявленная версия, которую я написал в качестве примера для кого-то, находится в этом контексте .

    UPDATE: теперь он также демонстрирует вторую половину (прослушивание _NET_WM_NAME ), чтобы выполнить именно то, что было запрошено.

    ОБНОВЛЕНИЕ # 2: … и третья часть: WM_NAME к WM_NAME если что-то вроде xterm не установило _NET_WM_NAME . (Последний кодируется в кодировке UTF-8, в то время как первый должен использовать кодировку устаревшего символа, называемую составным текстом, но, поскольку никто, похоже, не знает, как с ней работать, вы получаете программы, бросающие туда любой поток байтов, и xprop просто предполагая, что это будет ISO-8859-1.)

    Хорошо, благодаря комментарию @ Basile, я многому научился и придумал следующий рабочий пример:

     #!/usr/bin/python3 import Xlib import Xlib.display disp = Xlib.display.Display() root = disp.screen().root NET_WM_NAME = disp.intern_atom('_NET_WM_NAME') NET_ACTIVE_WINDOW = disp.intern_atom('_NET_ACTIVE_WINDOW') root.change_attributes(event_mask=Xlib.X.FocusChangeMask) while True: try: window_id = root.get_full_property(NET_ACTIVE_WINDOW, Xlib.X.AnyPropertyType).value[0] window = disp.create_resource_object('window', window_id) window.change_attributes(event_mask=Xlib.X.PropertyChangeMask) window_name = window.get_full_property(NET_WM_NAME, 0).value except Xlib.error.XError: window_name = None print(window_name) event = disp.next_event() 

    Вместо того, чтобы xdotool запускать xdotool , он синхронно слушает события, генерируемые X, и это именно то, что я получил после.

    Linux и Unix - лучшая ОС в мире.