Как определить окна X11 верхнего уровня, используя xlib?

StackOverflow https://stackoverflow.com/questions/1201179

  •  05-07-2019
  •  | 
  •  

Вопрос

Я пытаюсь получить список всех окон рабочего стола верхнего уровня в сеансе X11. По сути, я хочу получить список всех окон, которые отображаются в интерфейсе переключения приложений диспетчера окон (обычно открывается, когда пользователь нажимает ALT + TAB).

Я никогда раньше не занимался программированием на X11, но до сих пор мне удавалось перечислять весь список окон с помощью кода, который выглядит примерно так:

void CSoftwareInfoLinux::enumerateWindows(Display *display, Window rootWindow)
{
    Window parent;
    Window *children;
    Window *child;
    quint32 nNumChildren;

    XTextProperty wmName;
    XTextProperty wmCommand;

    int status = XGetWMName(display, rootWindow, &wmName);
    if (status && wmName.value && wmName.nitems)
    {
        int i;
        char **list;
        status = XmbTextPropertyToTextList(display, &wmName, &list, &i);
        if (status >= Success && i && *list)
        {
            qDebug() << "Found window with name:" << (char*) *list;
        }

        status = XGetCommand(display, rootWindow, &list, &i);
        if (status >= Success && i && *list)
        {
            qDebug() << "... and Command:" << i << (char*) *list;
        }

        Window tf;
        status = XGetTransientForHint(display, rootWindow, &tf);
        if (status >= Success && tf)
        {
            qDebug() << "TF set!";
        }

        XWMHints *pHints = XGetWMHints(display, rootWindow);
        if (pHints)
        {
            qDebug() << "Flags:" << pHints->flags
                    << "Window group:" << pHints->window_group;
        }
    }

    status = XQueryTree(display, rootWindow, &rootWindow, &parent, &children, &nNumChildren);
    if (status == 0)
    {
        // Could not query window tree further, aborting
        return;
    }

    if (nNumChildren == 0)
    {
        // No more children found. Aborting
        return;
    }

    for (int i = 0; i < nNumChildren; i++)
    {
        enumerateWindows(display, children[i]);
    }

    XFree((char*) children);
}

enumerateWindows () вызывается изначально с корневым окном.

Это работает, поскольку выводит информацию о сотнях окон - мне нужно выяснить, какое свойство я могу запросить, чтобы определить, является ли данное Window верхним уровнем Окно рабочего стола (не знаю, какова официальная терминология) или нет.

Кто-нибудь может пролить свет на это? Вся справочная документация, которую я нашел для программирования X11, была ужасно сухой и трудной для понимания. Возможно, кто-то может указать на лучший ресурс?

Это было полезно?

Решение

У меня есть решение!

Ну, вроде как.

Если ваш оконный менеджер использует расширенные подсказки оконного менеджера (EWMH), вы можете запросить корневое окно с помощью " _NET_CLIENT_LIST " атом. Этот возвратный список клиентских окон, которыми управляет оконный менеджер. Для получения дополнительной информации см. здесь .

Однако с этим есть некоторые проблемы. Для начала используемый оконный менеджер должен поддерживать EWMH. KDE и GNOME делают, и я уверен, что некоторые другие тоже. Тем не менее, я уверен, что многие этого не делают. Также я заметил несколько проблем с KDE. В основном, некоторые не-KDE приложения не включаются в список. Например, если вы запустите xcalc под KDE, он не будет отображаться в этом списке.

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

    Atom a = XInternAtom(m_pDisplay, "_NET_CLIENT_LIST" , true);
    Atom actualType;
    int format;
    unsigned long numItems, bytesAfter;
    unsigned char *data =0;
    int status = XGetWindowProperty(m_pDisplay,
                                rootWindow,
                                a,
                                0L,
                                (~0L),
                                false,
                                AnyPropertyType,
                                &actualType,
                                &format,
                                &numItems,
                                &bytesAfter,
                                &data);

    if (status >= Success && numItems)
    {
        // success - we have data: Format should always be 32:
        Q_ASSERT(format == 32);
        // cast to proper format, and iterate through values:
        quint32 *array = (quint32*) data;
        for (quint32 k = 0; k < numItems; k++)
        {
            // get window Id:
            Window w = (Window) array[k];

            qDebug() << "Scanned client window:" << w;
        }
        XFree(data);
    }

Другие советы

Чтобы расширить предыдущее решение, если вы хотите получить имена окон:

// get window Id:
Window w = (Window) array[k];

char* name = '\0';
status = XFetchName(display, w, &name);
if (status >= Success)
{
    if (name == NULL)
        printf("Found: %ul  NULL\n", w);
    else
        printf("Found: %ul  %s\n", w, name);
}
XFree(name);

Если вам не нужно использовать Xlib, использование gdk_screen_get_window_stack () и gdk_window_get_window_type () в GDK может помочь вам в ваших потребностях.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top