linux下根据进程pid获取对应的window id的方法

发布于:2024-04-10 ⋅ 阅读:(157) ⋅ 点赞:(0)

有时候我们需要在一个图形化进程中抓取另外一个进程的窗口以嵌入到当前进程的界面里。比如,在QT开发中,在当前的进程界面里启动另外一个进程并将其窗口嵌入到当前进程的界面内。下面的代码示例了如何根据进程的id获取其对应的UI窗口ID(基于x11框架)。

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <iostream>
#include <list>
#include <stdlib.h>
#include <QMainWindow>

class WindowsMatchingPid
{
public:
    WindowsMatchingPid(Display *display, Window wRoot, unsigned long pid)
        : _display(display)
    {
        _pid = pid;
        // Get the PID property atom.
        _atomPID = XInternAtom(display, "_NET_WM_PID", True);
        if(_atomPID == None)
        {
            std::cout << "No such atom" << std::endl;
            return;
        }

        search(wRoot);
    }

    const std::list<Window> &result() const { return _result; }
    bool hasBadWinId = false;
private:
    unsigned long  _pid = 0;
    Atom           _atomPID;
    Display       *_display = NULL;
    std::list<Window>   _result;
    void
    search(Window w)
    {
        // Get the PID for the current Window.
        Atom           type;
        int            format;
        unsigned long  nItems;
        unsigned long  bytesAfter;
        unsigned char *propPID = 0;
//        printf("win id: %x\n",w);
        if(Success == XGetWindowProperty(
                    _display,
                    w,
                    _atomPID,
                    0,
                    1,
                    False,
                    XA_CARDINAL,
                    &type,
                    &format,
                    &nItems,
                    &bytesAfter,
                    &propPID))
        {
            //printf("got one,pid:%d\n", propPID);
            if(propPID != 0)
            {
                // If the PID matches, add this window to the result set.
                if(_pid == *((unsigned long *)propPID))
                {
                    XWindowAttributes attr;
                    XGetWindowAttributes(_display, w, &attr);
                    printf("mapstate:%d\n", attr.map_state);
                    if(attr.map_state == 2)
                    _result.push_back(w);
                    else
                        hasBadWinId = true;
                }

                XFree(propPID);
            }
        }

        // Recurse into child windows.
        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]);
        }

        //XFree(propPID);
    }

};


unsigned long
get_win_id_from_pid(unsigned long pid, int* hasBad)
{
//    std::cout << "Searching for windows associated with PID == " << pid << std::endl;

    // Start with the root window.
    Display *display = XOpenDisplay(0);
    printf("display--------,----------pid----------%lld\n",pid);

    WindowsMatchingPid match(display, XDefaultRootWindow(display), pid);

    // Print the result.
    const std::list<Window> &result = match.result();
    //std::cout << "list size ===== " << result.size() << std::endl;
    long win_id = 0;
    for(std::list<Window>::const_iterator pos = result.begin(); pos != result.end(); pos++)
    {
        std::cout << "Window #" << (unsigned long)(*pos) << std::endl;
        if((win_id == 0)||(win_id != 0 && (unsigned long)win_id > (unsigned long)(*pos)))
        win_id = (unsigned long)(*pos);
    }
    XCloseDisplay(display);
    if(match.hasBadWinId)
        *hasBad = 1;
    return win_id;
}