Я могу действовать на событие, которое окно открывает без опроса?

Я пытаюсь найти способ обнаружить событие окна (любое окно) открываемый в Ubuntu 16.04

Я хотел бы смочь обнаружить "окно открытое" событие и проверка, если бы открытое окно было моим разыскиваемым окном и после этого запускало скрипт удара или функцию C/C++.

До сих пор я нашел, что могу использовать wmctrl -l найти, какие окна уже открыты. Я мог использовать эту команду и возможно grep найти, открыто ли мое разыскиваемое окно и затем действует на эту информацию.

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

Существует ли событие или сигнал, к которому я мог прислушаться для достижения этого? От ядра, менеджер окон (Compiz) или возможно некоторый файл журнала, который изменяется?

Править: Для разъяснения у меня есть приложение (не под моим управлением), который мог бы показать окно в любое время, это окно не имеет заголовка, но это действительно имеет набор WM_CLASS (WM_CLASS является тем же для всех окон приложения). Я хочу реагировать на событие, которое это окно показывают (или создают, какой бы ни является лучшим/легче).

Не кажется, что окно открыто "в" окне главных приложений. Используя xwininfo -children -id <window-id> шоу, что главное приложение и разыскиваемое окно находятся на различных ответвлениях, подключенных к "корневому окну".

Ответвления похожи на это, где R является "корневым узлом"; A является корневым узлом ответвления главного приложения, и Y является корнем ответвления с разыскиваемым окном W:

    R
   / \
  A   Y
 /\    \
B  C    X
    \    \
     Q    W

Таким образом, я надеюсь, что могу найти уникальную структуру Y-X-W

Я не уверен, что должен слушать все окна, но это - мое предположение, что я должен буду проверить то, что происходит в "корневом окне", и попытайтесь найти разыскиваемое окно.

6
задан 20 March 2018 в 04:25

1 ответ

Я нашел два способа решить эту проблему.

  1. Используйте xprop -spy -root _NET_ACTIVE_WINDOW команда в сочетании с grep в сценарии удара.
  2. Создайте C++ (возможно, был C или Python также, мой проект был в C++ для начала), приложение, пользующееся библиотекой Xlib для прислушиваний к событиям от X-сервера.

Я закончил тем, что использовал альтернативный 1, но я обеспечу некоторую информацию об обоих ниже.

Используя xprop: приложение, которое создает разыскиваемое окно всегда, помещает новое окно на вершину и в фокусе. xprop -spy <window-id>команда позволяет слушать изменения в свойствах <window-id> и -root идентификатор "корневого окна" (R в дереве в вопросе выше). Для прислушиваний к изменениям определенных свойств, мы можем обеспечить имя свойства в этом случае _NET_ACTIVE_WINDOW который содержит идентификатор окна в настоящее время в фокусе, посмотрите спецификацию. Мы затем получаем поток вывода как это:

_NET_ACTIVE_WINDOW(WINDOW): window id # 0x3c00010

и может использовать grep извлечь идентификатор. Чтобы проверить, является ли активное окно разыскиваемым окном, мы должны знать то, что делает его уникальным, это могло бы отличаться для всех, но скорее всего первый фильтр будет WM_CLASS свойство, см. описание. Вот небольшой пример этого:

#!/bin/bash
class_name=$1

# regex for extracting hex id's
grep_id='0[xX][a-zA-Z0-9]\{7\}'

xprop -spy -root _NET_ACTIVE_WINDOW | grep --line-buffered -o $grep_id |
while read -r id; do
    class="`xprop -id $id WM_CLASS | grep $class_name`"
    if [ -n "$class" ]; then
        # Found a window with the correct WM_CLASS now what makes your
        # window unique?
    fi
done

Суть Bash: Вот суть для случая в вопросе, где дерево было фактором идентификации.

Ограничения xprop -spy: это конкретно не слушает открытие окна, скорее когда окно фокусируется. Это означает, что, если окно остается открытым, идет не в фокусе и затем входит в фокус снова, этот сценарий все еще сообщит об этом событии.

Программирование Xlib: Это более сложно, но также и более мощно. Некоторые большие ресурсы для начала работы:

Поскольку этот должен открыть соединение и регистр как слушатель X-сервера:

// Open connection to X server
Display *dsp = XOpenDisplay(NIL);
assert(dsp);

// Start listening to root window
XSelectInput(dsp, DefaultRootWindow(dsp), SubstructureNotifyMask);

В зависимости от которых событий каждый ищет EventMask, должен быть выбран.

Для непрерывного приложения (которые хотят обработать последующие события) каждый, вероятно, хочет установить функцию обработчика ошибок, которая должна возвратиться 0 (возможно, с предупреждением), таким образом, выполнение продолжается гладко, как так:

XSetErrorHandler(bad_window_handler);

В цикле можно затем обработать события от X-сервера

XEvent e;
XNextEvent(dsp, &e); // blocks until next event from X-server

Обработать событие в e мы можем проверить тип e

e.type == CreateNotify    // A window was created
e.type == ReparentNotify  // A window got a new parent
e.type == MapNotify       // A window was drawn
e.type == DestroyNotify   // A window was destroyed

XEvent структура содержит информацию в различных типах структуры в зависимости от типа события.

Следующие библиотеки необходимы:

#include <X11/Xlib.h>
#include <X11/Xutil.h>

И приложения должны быть скомпилированы с -lX11 флаг для включения библиотек Xlib.

Суть Xlib + Глюки: я создал две сути, который слушает события от X-сервера. Обратите внимание, что я интересовался структурой дерева окна для идентификации. У других могли бы быть другие свойства для однозначного определения окон.

Первое слушает CreateNotify событие, чтобы определить, было ли окно с корректным WM_CLASS создано, назовите это W. В этой точке окно, вероятно, не будет в корректной древовидной структуре. Например, это могло бы быть создано как дочерний элемент к корню, а не окна, которыми управляет приложение. Мы поэтому слушаем ReparentNotify событие, чтобы видеть, имеет ли W нового родителя.

К сожалению, нам не гарантируют корректную древовидную структуру здесь также, поскольку другие окна могли бы позже быть добавлены к дереву W. Но если древовидная структура W уникальна, и это - форма, не поддерево другого окна с тем же классом, который мы можем, по крайней мере, найти их окном путем проверки ReparentNotify (мы даже, возможно, не должны были бы проверять CreateNotify поскольку мы можем проверить WM_CLASS в любой точке, у нас есть идентификатор окна).

Второе слушает MapNotify событие и проверки структура дерева окна. Это затем ищет корректный WM_CLASS в дереве. После того, как этот мог продолжить определять, корректна ли структура.

Снова, в MapNotify нам не гарантируют "законченную" древовидную структуру. Однако кажется, что структура обычно "улаживает" короткое время после этого события. Чтобы быть довольно уверенным, что структура не изменится, я добавил короткую паузу прежде, чем собрать дерево. Сколько времени эта пауза должна быть в порядке для не риска другими изменениями в дереве, которое я не знаю, 500 мс, казалось, работали хорошо на меня.

Misc: окна X11 могут быть созданы на многих различных языках, таким образом, я предполагаю слушать их, было бы возможно на многих различных языках также.

Некоторые инструменты для исследования окон с:

  • xprop
  • xwininfo конкретно с опциями -tree или -children

Можно также проверить исходный код команд выше, xprop и xwininfo, для некоторого руководства и вдохновения.

8
ответ дан 23 November 2019 в 07:37

Другие вопросы по тегам:

Похожие вопросы: