I have the PID for the process (and the name), I want to bring it to the front on linux (ubuntu). On mac I would simply do SetFrontProcess(pid)
, on windows I'd enumerate the windows, pick out the one I wanted, and call SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
but I'm at a loss of what to do on linux. I've looked at X Lib a bit, but most/all of those functions seem to operate on windows inside your process.
Edit: Using bdk's answer I added these helpers to my code to get the 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);
}
Now I get the window successfully, but when I do the following
if (getWindowFromPid(pid,display,window))
{
qDebug("Found window ID:%d", window);
int result = XRaiseWindow(display,window);
qDebug("XRaiseWindow returned:%d", result);
}
XRaiseWindow returns 1 (BadRequest). The documentation for XRaiseWindow does not mention the return code of BadRequest being a possible result. I'm not sure what is wrong. Am I not allowed to call it for windows in a different process? Is this focus steeling prevention hampering me? Any thoughts?
Edit edit:
So looking at what xwininfo.c does when you call it with -frame I changed my code as follows based on bdk's suggestion.
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");
At this point I do find the window frame ID, but I get a return code of "1" from both XChangeWindowAttributes and XRaiseWindow. Am I just not allowed to modify another process' window?
I haven't tried this myself, but putting these two methods together may work:
The XRaiseWindow API Call in xlib lets you raise a Window to the front if you know the Window ID.
http://www.unix.com/man-page/Linux/3/XRaiseWindow/
This stackoverflow answer explains how to get a Window ID from a PID:
How to get an X11 Window from a Process ID?
EDIT:
I've had limited success with XRaiseWindow. The Following program does work under twm window manager, but not ion which I usually use. The Window Manager must have ways of preventing applications from 'popping up'. To make this work, i also had to pass it the Window ID of the Window Manager's frame for the window, not the window itself. run xwininfo -frame and click on the window and you get the frame ID instead, compile this program with gcc test.c -lX and pass it that hexid on the command line and it will raise the window.
#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 );
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With