如何将进程窗口带到X Windows的前台? (C ++)

我有过程(和名称)的PID,我想把它带到Linux(Ubuntu的)前面。 在Mac上,我只需要做SetFrontProcess(pid) ,在窗口上我将列举窗口,挑选出我想要的,然后调用SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); 但是我在linux上不知所措。 我已经看了一下X Lib,但是大多数/所有这些函数似乎在你的进程中的窗口上运行。


编辑:使用bdk的答案我将这些助手添加到我的代码来获取窗口

 bool searchHelper(Display* display, Window w, Atom& atomPID, unsigned long pid, Window& result) { bool ret = false; Atom atomType; int format; unsigned long nItems; unsigned long bytesAfter; unsigned char* propPID = 0; if (Success == XGetWindowProperty(display,w,atomPID,0,1,False,XA_CARDINAL,&atomType,&format,&nItems,&bytesAfter,&propPID)) { if (propPID != 0) { if (pid == *((unsigned long *)propPID)) { result = w; ret = true; } XFree(propPID); } } if (ret) return ret; //we found we can stop //check the children of the window Window wRoot; Window wParent; Window *wChild=NULL; unsigned nChildren=0; if (XQueryTree(display, w, &wRoot, &wParent, &wChild, &nChildren) != 0 ) { for (unsigned i=0; i<nChildren; ++i) { ret = searchHelper(display, wChild[i], atomPID, pid, result); if (ret) break; } } return ret; } bool getWindowFromPid(unsigned long pid, Display* display, Window& result) { Window window = XDefaultRootWindow(display); Atom atomPID = XInternAtom(display, "_NET_WM_PID", true); if (atomPID == None) { qDebug("XInternAtom failure"); return false; } return searchHelper(display, window, atomPID, pid, result); } 

现在,我成功地看到了窗口,但是当我做了以下

 if (getWindowFromPid(pid,display,window)) { qDebug("Found window ID:%d", window); int result = XRaiseWindow(display,window); qDebug("XRaiseWindow returned:%d", result); } 

XRaiseWindow返回1(BadRequest)。 XRaiseWindow的文档没有提到BadRequest的返回码是一个可能的结果。 我不知道什么是错的。 我不允许在不同的过程中打电话给窗户吗? 这种重点防止钢材会妨碍我吗? 有什么想法吗?

编辑编辑:

所以当你用-frame调用xwininfo.c的时候,我会根据bdk的build议改变我的代码。

 if (getWindowFromPid(pid,display,window)) { qDebug("Found window ID:%d", window); //Need the windowmanger frame (or parent) id not window id Window root, parent; Window *childlist; unsigned int ujunk; int status = XQueryTree(display, window, &root, &parent, &childlist, &ujunk); if (status && parent && parent != root) { qDebug("Found frame window ID:%d",parent); window = parent; } XSetWindowAttributes xswa; xswa.override_redirect=True; int result = XChangeWindowAttributes (display,window,CWOverrideRedirect,&xswa); qDebug("XChangeWindowAttributes returned:%d", result); result = XRaiseWindow(display,window); qDebug("XRaiseWindow returned:%d", result); } else qDebug("unable to find the window for the pid"); 

在这一点上,我find了窗口框架ID,但是我从XChangeWindowAttributes和XRaiseWindow都得到了一个“1”的返回码。 我只是不允许修改另一个进程的窗口?

Solutions Collecting From Web of "如何将进程窗口带到X Windows的前台? (C ++)"

我还没有尝试过,但将这两种方法结合起来可能会起作用:

如果您知道窗口ID,xlib中的XRaiseWindow API调用可以让您将窗口拉到最前面。

http://www.unix.com/man-page/Linux/3/XRaiseWindow/

这个计算器的答案解释了如何从一个PID获得一个窗口ID:

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

编辑:

我用XRaiseWindow取得了有限的成功。 下面的程序在twm窗口管理器下工作,但不是我通常使用的离子。 窗口管理器必须有防止应用程序“弹出”的方法。 为了使这个工作,我也不得不将窗口管理器窗口的窗口ID,而不是窗口本身。 运行xwininfo -frame,然后点击窗口,然后得到框架ID,用gcc test.c -lX编译这个程序,并在命令行上传递给它,它会引发窗口。

  #include <stdio.h> #include <stdlib.h> #include <X11/Xlib.h> int main(int argc, char **argv) { Display *dsp = XOpenDisplay(NULL); long id = strtol(argv[1], NULL, 16); XSetWindowAttributes xswa; xswa.override_redirect=True; XChangeWindowAttributes (dsp,id,CWOverrideRedirect, &xswa); XRaiseWindow ( dsp, id ); XCloseDisplay ( dsp ); } 

在bash命令行中,您也可以使用非常棒的xdotool ,它可以让您指定以下内容来引发XBMC窗口并在其中输入反斜杠:

 xdotool search --name 'XBMC Media Center' windowactivate --sync key backslash 

这个程序下面有一个实际的库, libxdo2 ,如果XRaiseWindow失败,你可以使用它。 我知道,libxdo会不惜一切代价来不断提高窗口,而不管windowmanager。

我的应用程序中也有这个问题,所以这里是解决方案。

为了提高窗口,不仅需要提高窗口,还需要通知WM。 可以使用下面的代码:

  // This is how to get it in Qt; if you don't use it, // you can call XOpenDisplay and get it from there; Display * display = x11Info().display(); // Main window identifier of your application WId win = winId(); XEvent event = { 0 }; event.xclient.type = ClientMessage; event.xclient.serial = 0; event.xclient.send_event = True; event.xclient.message_type = XInternAtom( display, "_NET_ACTIVE_WINDOW", False); event.xclient.window = win; event.xclient.format = 32; XSendEvent( display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &event ); XMapRaised( display, win ); 

我认为这很容易,因为/ proc似乎有所需的数据,但/proc/${pid}/environ没有提供正确的窗口ID,因为它通常是真正拥有窗口的父进程运行。 为了得到正确的windowid你需要解析xwininfo输出,然后你可以使用xdotool来改变焦点。

 CMD_PID=<your pid here> && while IFS= read -r -d '' var; do if grep -q "^WINDOWID=" <<< "$var"; then winid=$(printf '0x%x\n' $(sed 's/WINDOWID=//' <<< "${var}")) child_cnt=0 && IFS=$(echo -en "\n\b") && for a in $(xwininfo -root -tree | tac | sed -n "/${winid}/,\$p"); do grep -q -i "children" <<< "${a}" && let child_cnt+=1 ((${child_cnt} == 2)) && real_winid=$(grep -o '0x[^ ]*' <<< "${last_line}") && break last_line="${a}" done xdotool windowraise ${real_winid} break fi done < /proc/${CMD_PID}/environ