如何从进程ID获取X11窗口?

在Linux下,我的C ++应用程序使用fork()和execv()来启动多个OpenOffice实例,以便查看一些幻灯片幻灯片。 这部分工作。

接下来,我希望能够将OpenOffice窗口移动到显示屏上的特定位置。 我可以用XMoveResizeWindow()函数做到这一点,但我需要find每个实例的窗口。

我有每个实例的进程ID,我怎么能从那里findX11窗口?


更新 – 感谢安迪的build议,我已经把它取消了。 我在这里发布代码与Stack Overflow社区分享。

不幸的是,Open Office似乎没有设置_NET_WM_PID属性,所以这并不能最终解决我的问题,但它确实回答了这个问题。

// Attempt to identify a window by name or attribute. // by Adam Pierce <adam@doctort.org> #include <X11/Xlib.h> #include <X11/Xatom.h> #include <iostream> #include <list> using namespace std; 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) { cout << "No such atom" << endl; return; } search(wRoot); } const list<Window> &result() const { return _result; } private: unsigned long _pid; Atom _atomPID; Display *_display; 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; if(Success == XGetWindowProperty(_display, w, _atomPID, 0, 1, False, XA_CARDINAL, &type, &format, &nItems, &bytesAfter, &propPID)) { if(propPID != 0) { // If the PID matches, add this window to the result set. if(_pid == *((unsigned long *)propPID)) _result.push_back(w); 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]); } } }; int main(int argc, char **argv) { if(argc < 2) return 1; int pid = atoi(argv[1]); cout << "Searching for windows associated with PID " << pid << endl; // Start with the root window. Display *display = XOpenDisplay(0); WindowsMatchingPid match(display, XDefaultRootWindow(display), pid); // Print the result. const list<Window> &result = match.result(); for(list<Window>::const_iterator it = result.begin(); it != result.end(); it++) cout << "Window #" << (unsigned long)(*it) << endl; return 0; } 

我知道这样做的唯一方法是遍历窗口的树,直到你find你要找的东西。 遍历不难(只要看看xwininfo -root -tree通过查看xwininfo.c来做什么,如果你需要一个例子的话)。

但是,你如何识别你正在寻找的窗口? 某些应用程序设置了一个名为_NET_WM_PID的窗口属性。

我相信OpenOffice 设置该属性的应用程序之一(就像大多数Gnome应用程序一样),所以你很幸运。

检查/ proc / PID / environ是否包含一个名为WINDOWID的variables

晚会晚了。 不过:2004年,Harald Welte发布了一个代码片断,它通过LD_PRELOAD封装了XCreateWindow()调用,并将进程ID存储在_NET_WM_PID中。 这确保每个创build的窗口都有一个PID条目。

http://www.mail-archive.com/devel@xfree86.org/msg05806.html

尝试安装xdotool ,然后:

 #!/bin/bash # --any and --name present only as a work-around, see: https://github.com/jordansissel/xdotool/issues/14 ids=$(xdotool search --any --pid "$1" --name "dummy") 

我得到了很多IDS。 我用这个来设置一个terminal窗口,当它用一个长命令完成的时候,使用程序seturgent 。 我只是通过所有我从xdotool得到的id来运行seturgent

没有好的方法。 我看到的唯一真正的select是:

  1. 您可以在进程的地址空间中查看连接信息和窗口标识。
  2. 您可以尝试使用netstat或lsof或ipcs将连接映射到Xserver,然后(以某种方式,至less需要root)查看其连接信息以find它们。
  3. 当产生一个实例时,你可以等到另一个窗口被映射,假设它是正确的,然后继续。

你确定你有每个实例的进程ID吗? 我与OOo的经验是,尝试运行第二个OOo实例只是与OOo的第一个实例进行对话,并告诉打开这个额外的文件。

我想你将需要使用X的消息发送function来很好地问它的窗口。 我希望OOo在某处logging其封面。

如果你使用python,我在这里find了一个方法,这个想法来自于BurntSushi

如果你启动了应用程序,那么你应该知道它的cmdstring,你可以用它来减less对xprop调用,你总是可以遍历所有的xid,并检查pid是否与你想要的pid相同

 import subprocess import re import struct import xcffib as xcb import xcffib.xproto def get_property_value(property_reply): assert isinstance(property_reply, xcb.xproto.GetPropertyReply) if property_reply.format == 8: if 0 in property_reply.value: ret = [] s = '' for o in property_reply.value: if o == 0: ret.append(s) s = '' else: s += chr(o) else: ret = str(property_reply.value.buf()) return ret elif property_reply.format in (16, 32): return list(struct.unpack('I' * property_reply.value_len, property_reply.value.buf())) return None def getProperty(connection, ident, propertyName): propertyType = eval(' xcb.xproto.Atom.%s' % propertyName) try: return connection.core.GetProperty(False, ident, propertyType, xcb.xproto.GetPropertyType.Any, 0, 2 ** 32 - 1) except: return None c = xcb.connect() root = c.get_setup().roots[0].root _NET_CLIENT_LIST = c.core.InternAtom(True, len('_NET_CLIENT_LIST'), '_NET_CLIENT_LIST').reply().atom raw_clientlist = c.core.GetProperty(False, root, _NET_CLIENT_LIST, xcb.xproto.GetPropertyType.Any, 0, 2 ** 32 - 1).reply() clientlist = get_property_value(raw_clientlist) cookies = {} for ident in clientlist: wm_command = getProperty(c, ident, 'WM_COMMAND') cookies[ident] = (wm_command) xids=[] for ident in cookies: cmd = get_property_value(cookies[ident].reply()) if cmd and spref in cmd: xids.append(ident) for xid in xids: pid = subprocess.check_output('xprop -id %s _NET_WM_PID' % xid, shell=True) pid = re.search('(?<=\s=\s)\d+', pid).group() if int(pid) == self.pid: print 'found pid:', pid break print 'your xid:', xid