我有进程的PID(和名称),我想把它带到linux(ubuntu)的前面.在Mac上,我只是这样做SetFrontProcess(pid),在Windows上我会枚举窗口,选择我想要的那个,然后打电话,SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);但我不知道在linux上做什么.我已经看了一下X Lib,但是大多数/所有这些函数似乎都在你进程中的窗口上运行.
编辑:使用bdk的答案我将这些助手添加到我的代码中以获取Window
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);
}
Run Code Online (Sandbox Code Playgroud)
现在我成功地获得了窗口,但是当我执行以下操作时
if (getWindowFromPid(pid,display,window))
{
qDebug("Found window ID:%d", window);
int result = XRaiseWindow(display,window);
qDebug("XRaiseWindow returned:%d", result);
}
Run Code Online (Sandbox Code Playgroud)
XRaiseWindow返回1(BadRequest).XRaiseWindow的文档没有提到BadRequest的返回代码是可能的结果.我不确定是什么问题.我不允许在不同的进程中为它调用它吗?这种重点钢铁预防是否会妨碍我?有什么想法吗?
编辑编辑:
所以看看xwininfo.c在用-frame调用它时的作用我根据bdk的建议改变了我的代码如下.
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");
Run Code Online (Sandbox Code Playgroud)
此时我确实找到了窗口框架ID,但是我从XChangeWindowAttributes和XRaiseWindow获得了返回码"1".我不允许修改另一个进程的窗口吗?
我的应用程序中也有这个问题,所以这是解决方案.
要抬高窗口,您不仅需要提高窗口,还需要通知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 );
Run Code Online (Sandbox Code Playgroud)
我自己没有尝试过,但将这两种方法放在一起可能有效:
如果您知道窗口ID,则xlib中的XRaiseWindow API调用允许您将窗口提升到前面.
http://www.unix.com/man-page/Linux/3/XRaiseWindow/
此stackoverflow答案解释了如何从PID获取窗口ID:
编辑:
我在XRaiseWindow上的成功有限.以下程序在twm窗口管理器下工作,但不是我通常使用的离子.窗口管理器必须有办法阻止应用程序"弹出".为了使这个工作,我还必须传递窗口管理器的窗口的窗口ID,而不是窗口本身.运行xwininfo -frame并单击窗口,然后获取帧ID,使用gcc test.c -lX编译该程序,并在命令行上传递该hexid,它将引发窗口.
#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 );
}
Run Code Online (Sandbox Code Playgroud)