Получить заголовок активного окна в X

Я пытаюсь получить название активного окна. Приложение является фоновой задачей, поэтому, если у пользователя открыт Eclipse, функция возвращает "Eclipse - blabla", поэтому он не получает заголовок окна моего собственного окна. Я разрабатываю это в Python 2.6 с использованием PyQt4.

Мое текущее решение, заимствованное и слегка измененное из старого ответа здесь, в SO, выглядит так:

def get_active_window_title():
    title = ''
    root_check = ''

    root = Popen(['xprop', '-root'],  stdout=PIPE)

    if root.stdout != root_check:
        root_check = root.stdout

        for i in root.stdout:
            if '_NET_ACTIVE_WINDOW(WINDOW):' in i:
                id_ = i.split()[4]
                id_w = Popen(['xprop', '-id', id_], stdout=PIPE)

        for j in id_w.stdout:
            if 'WM_ICON_NAME(STRING)' in j:
                if title != j.split()[2]:
                    return j.split("= ")[1].strip(' \n\"')

Это работает для большинства окон, но не для всех. Например, он не может найти мои окна чата kopete или название приложения, которое я сейчас разрабатываю.

Моя следующая попытка выглядит так:

def get_active_window_title(self):
    screen = wnck.screen_get_default()
    if screen == None:
        return "Could not get screen"
    window = screen.get_active_window()
    if window == None:
        return "Could not get window"
    title = window.get_name()
    return title;

Но по какой-то причине окно всегда None.

У кого-нибудь есть лучший способ получить текущий заголовок окна или как изменить один из моих способов, который работает для всех окон?

Редактировать:

В случае, если кому-то интересно, я обнаружил, что этот способ работает для всех окон.

def get_active_window_title(self):
    root_check = ''
    root = Popen(['xprop', '-root'],  stdout=PIPE)

    if root.stdout != root_check:
        root_check = root.stdout

        for i in root.stdout:
            if '_NET_ACTIVE_WINDOW(WINDOW):' in i:
                id_ = i.split()[4]
                id_w = Popen(['xprop', '-id', id_], stdout=PIPE)
        id_w.wait()
        buff = []
        for j in id_w.stdout:
            buff.append(j)

        for line in buff:
            match = re.match("WM_NAME\((?P<type>.+)\) = (?P<name>.+)", line)
            if match != None:
                type = match.group("type")
                if type == "STRING" or type == "COMPOUND_TEXT":
                    return match.group("name")
        return "Active window not found"

3 ответа

Решение

xdotool могу сделать это.

xdotool getactivewindow

Я немного изменил ваше решение, чтобы оно работало более эффективно (оно передает параметры в xprop, поэтому возвращаются только те данные, которые ему нужны). Кроме того, я не уверен, что необходимо буферизовать вывод xprop, поэтому я убрал его. Также следует исправить возвращаемое "Активное окно не найдено", если по какой-то причине оно не может найти активное окно.

def get_active_window_title(self):
    root = Popen(['xprop', '-root', '_NET_ACTIVE_WINDOW'], stdout=PIPE)

    for line in root.stdout:
        m = re.search('^_NET_ACTIVE_WINDOW.* ([\w]+)$', line)
        if m != None:
            id_ = m.group(1)
            id_w = Popen(['xprop', '-id', id_, 'WM_NAME'], stdout=PIPE)
            break

    if id_w != None:
        for line in id_w.stdout:
            match = re.match("WM_NAME\(\w+\) = (?P<name>.+)$", line)
            if match != None:
                return match.group("name")

    return "Active window not found"

Вы можете получить активный заголовок окна с xdotool:

$ xdotool getactivewindow getwindowname

Это слишком поздно, чтобы быть полезным, но это работает, и у меня есть программы, которые используют wnck.

В wnck пример нужен вызов screen.force_update() перед wnckбудет работать. Без этогоwnckне имеет информации об окнах на экране. То есть:

def get_active_window_title(self):
    screen = wnck.screen_get_default()
    if screen is None:
        return "Could not get screen"
    screen.force_update()
    window = screen.get_active_window()
    if window is None:
        return "Could not get window"
    title = window.get_name()
    return title

Я вижу, что вопрос уже немного запыленный, также поддержка Python 2 приближается к концу запланированного срока службы, поэтому я подумал, что упомянул бы еще одну версию Python 3'ic.

Фактически, это, вероятно, лучше, чем просто больше 3-стилей - в Python 3 "объекты Popen поддерживаются в качестве менеджеров контекста через оператор with: при выходе стандартные файловые дескрипторы закрываются, и процесс ожидает".

Таким образом, нижеследующее, вероятно, более адекватно и менее ресурсоемко для новых питонов:

(также без withs, вы можете столкнуться с проблемой "слишком много открытых файлов" - о чем я, конечно, узнал на собственном горьком опыте:) - если вы будете запрашивать заголовок окна достаточно часто в Ubuntu ~16 .)

    with Popen(['xprop', '-root', '_NET_ACTIVE_WINDOW'], stdout=PIPE) as root:
        for line in root.stdout:
            line = str(line, encoding="UTF-8")

            m = re.search('^_NET_ACTIVE_WINDOW.* ([\w]+)$', line)
            if m is not None:
                id_ = m.group(1)
                with Popen(['xprop', '-id', id_, 'WM_NAME'],
                           stdout=PIPE) as id_w:
                    for line in id_w.stdout:
                        line = str(line, encoding="UTF-8")
                        match = re.match("WM_NAME\(\w+\) = \"(?P<name>.+)\"$",
                                         line)
                    if match is not None:
                        return match.group("name")
                break
    return "Active window not found"
Другие вопросы по тегам