通过Xlib枚举指定进程下所有窗体

在windows系统下如果想要枚举指定进程的窗体,我们可以通过EnumWindows加上自己实现的回调函数进行实现,那么在linux下该如何做呢?

其实也很简单,在linux下,我们可以通过xlib中提供的API进行实现,关于xlib后面会专门写一篇文章讲解。

一、实现思路

从root窗体开始逐层遍历每一个窗体,将这些窗体所属进程与给定进程比较从而进行筛选。

二、实现代码

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <QList>

class WindowsMatchingPid
{
public:
    WindowsMatchingPid(Display *display, Window wRoot, unsigned long pid)
        : _display(display)
        , _pid(pid)
    {
        _atomPID = XInternAtom(display, "_NET_WM_PID", True);
        if(_atomPID == None)
        {
            return;
        }

        search(wRoot);
    }

    const QList<Window> result() const { return _result; }

private:
    unsigned long  _pid;
    Atom           _atomPID;
    Display       *_display;
    QList<Window>   _result;

    void search(Window w)
    {
        Atom           type;
        int            format;
        unsigned long  nItems;
        unsigned long  bytesAfter;
        unsigned char *propPID = 0;
        if(Success == XGetWindowProperty(_display, w, _atomPID, 0, 1, False, XA_CARDINAL,
                                         &type, &format, &nItems, &bytesAfter, &propPID))
        {
            if(propPID != 0)
            {
                if(_pid == *((unsigned long *)propPID))
                    _result.append(w);
                XFree(propPID);
            }
        }

        Window    wRoot;
        Window    wParent;
        Window   *wChild;
        unsigned  nChildren;
        if(0 != XQueryTree(_display, w, &wRoot, &wParent, &wChild, &nChildren))
        {
            for(unsigned i = 0; i < nChildren; i++)
                search(wChild[i]);
        }
    }
};

这里主要使用XGetWindowProperty和XQueryTree进行窗体树遍历以及窗体属性获取。

XGetWindowProperty:获取目标窗体属性信息

XQueryTree:获取目标窗体的窗体树结构

接着就利用这个类去获取进程窗体

int pid = getpid();
Display *display = XOpenDisplay(0);
WindowsMatchingPid match(display, XDefaultRootWindow(display), pid);
const QList<Window> result = match.result();
for(int i=0; i<result.count();i++)
{
    unsigned long winId = (unsigned long)(result.at(i));
    QWidget* win = QWidget::find(winId);
    if(win!=NULL&&win->isWindow()&&win->isVisible()){
        m_pformList->append((QObject*)win);
    }
}
XCloseDisplay(display);

PS:每次调用XOpenDisplay获取x-server连接之后要记得调用XCloseDisplay关闭连接,否则连接泄露会导致程序异常退出。

 

 

posted @ 2020-02-17 19:00  阿拉懒神灯  阅读(1310)  评论(0编辑  收藏  举报