Получить заголовок активного окна в 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 ответа
Я немного изменил ваше решение, чтобы оно работало более эффективно (оно передает параметры в 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: при выходе стандартные файловые дескрипторы закрываются, и процесс ожидает".
Таким образом, нижеследующее, вероятно, более адекватно и менее ресурсоемко для новых питонов:
(также без with
s, вы можете столкнуться с проблемой "слишком много открытых файлов" - о чем я, конечно, узнал на собственном горьком опыте:) - если вы будете запрашивать заголовок окна достаточно часто в 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"