Получать уведомления при изменении активного окна X с помощью Python xlib - PullRequest
3 голосов
/ 09 февраля 2020

Я хотел бы отслеживать, какое окно активно в Linux системе с X, и когда это активное окно изменяется или перемещается. Я могу отслеживать активное окно (оно хранится в свойстве _NET_ACTIVE_WINDOW в окне root, и я могу зарегистрироваться для событий PropertyNotify в окне root, чтобы узнать, когда это свойство изменяется). Тем не менее, я не знаю, как отслеживать активное окно, чтобы узнать, было ли оно изменено или перемещено.

import Xlib
import Xlib.display

disp = Xlib.display.Display()
Xroot = disp.screen().root
NET_ACTIVE_WINDOW = disp.intern_atom('_NET_ACTIVE_WINDOW')
Xroot.change_attributes(event_mask=Xlib.X.PropertyChangeMask)

while True:
    # loop until an event happens that we care about
    # we care about a change to which window is active
    # (NET_ACTIVE_WINDOW property changes on the root)
    # or about the currently active window changing
    # in size or position (don't know how to do this)
    event = disp.next_event()
    if (event.type == Xlib.X.PropertyNotify and
            event.atom == NET_ACTIVE_WINDOW):
        active = disp.get_input_focus().focus
        try:
            name = active.get_wm_class()[1]
        except TypeError:
            name = "unknown"
        print("The active window has changed! It is now", name)

Есть ли способ сделать это? Это может включать прослушивание событий ConfigureNotify в текущем активном окне (и вызов change_attributes в этом окне, когда оно становится активным для установки соответствующей маски), но я не могу заставить это работать.

(Примечание : Я не использую Gtk, поэтому никаких решений Gtk, пожалуйста.)

Обновление: существует довольно подозрительный подход к обнаружению окна , изменяющего размер , путем наблюдения активного значения окна изменение свойства _NET_WM_OPAQUE_REGION (поскольку я правильно получаю события PropertyChange, хотя я не получаю события ConfigureNotify). Однако не ясно, что все оконные менеджеры устанавливают это свойство, и это изменяется только при изменении размера окна; оно не изменяется при перемещении окна (и при этом никакое другое свойство).

1 Ответ

1 голос
/ 10 февраля 2020

Способ сделать это - выбрать для SubstructureNotifyMask в окне root, а затем прочитать все ConfigureNotify события и игнорировать те, которые не относятся к интересующему нас окну, таким образом:

import Xlib
import Xlib.display

disp = Xlib.display.Display()
Xroot = disp.screen().root
NET_ACTIVE_WINDOW = disp.intern_atom('_NET_ACTIVE_WINDOW')
Xroot.change_attributes(event_mask=Xlib.X.PropertyChangeMask |
                        Xlib.X.SubstructureNotifyMask)

windows = []

while True:
    # loop until an event happens that we care about
    # we care about a change to which window is active
    # (NET_ACTIVE_WINDOW property changes on the root)
    # or about the currently active window changing
    # in size or position (ConfigureNotify event for
    # our window or one of its ancestors)
    event = disp.next_event()
    if (event.type == Xlib.X.PropertyNotify and
            event.atom == NET_ACTIVE_WINDOW):
        active = disp.get_input_focus().focus
        try:
            name = active.get_wm_class()[1]
        except TypeError:
            name = "unknown"
        print("The active window has changed! It is now", name)

        # Because an X window is not necessarily just what one thinks of
        # as a window (the window manager may add an invisible frame, and
        # so on), we record not just the active window but its ancestors
        # up to the root, and treat a ConfigureNotify on any of those
        # ancestors as meaning that the active window has been moved or resized
        pointer = active
        windows = []
        while pointer.id != Xroot.id:
            windows.append(pointer)
            pointer = pointer.query_tree().parent
    elif event.type == Xlib.X.ConfigureNotify and event.window in windows:
        print("Active window size/position is now", event.x, event.y,
              event.width, event.height)
...