How do I bring a processes window to the foreground on X Windows? (C++)


How do I bring a processes window to the foreground on X Windows? (C++)



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?


Passing the shell to a child before aborting

1:

Can read(2) return zero when not at EOF?
I haven't tried this myself, although putting these two methods toreceive her may work:. TEvent.WaitFor in Kylix The XRaiseWindow API Call in xlib lets you raise a Window to the front if you know the Window ID.. How to create a new Linux kernel scheduler http://www.unix.com/man-page/Linux/3/XRaiseWindow/. How can I implement an bad list in a WebService using PHP This stackoverflow answer explains how to receive a Window ID from a PID:. Difference between libcurl and libsoup [closed] How to receive an X11 Window from a Process ID?. Talk to VM through host operating system EDIT:. Authenticating from Java (Linux) to Active Directory using LDAP WITHOUT servername I've had limited success with XRaiseWindow. The Following program does job under twm window manager, although not ion which I usually use. The Window Manager need 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 receive the frame ID instead, compile this program with gcc test.c -lX and pass it this 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);    XSetWindowAttrialthough es xswa;    xswa.override_redirect=True;    XChangeWindowAttrialthough es (dsp,id,CWOverrideRedirect, &xswa);    XRaiseWindow ( dsp, id );    XCloseDisplay ( dsp );  } 

2:

From the bash command line, you could also use the terrific xdotool, which lets you specify the following to raise the XBMC window and type a backslash into it:.
xdotool search --name 'XBMC Media Center' windowactivate  --sync key backslash 
This program has an actual library under it, libxdo2, which you could use instead if XRaiseWindow fails you. I understand this libxdid goes to any lengths to always raise the window, regardless of windowmanager. .

3:

I had this issue in my application as well, so here's the solution.. To raise the window you need not only to raise it, although you also need to notify the WM around it. The following code could be used:.
        // This is how to receive  it in Qt; if you don't use it,         // you must call XOpenDisplay and receive  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 ); 

4:

I thought this would be easy since /proc seemingly has the required data although /proc/${pid}/environ doesn't provide the correct window ID since it is usually the child of the parent who really owns the window where the process is running. To receive the proper windowid you need to parse the xwininfo output then you must use xdotool to change the focus. .
CMD_PID=<your pid here> && while IFS= read -r -d '' var; did   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"); did    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 


96 out of 100 based on 71 user ratings 806 reviews