tags:

views:

200

answers:

1

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.

Thanks in advanced.

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?

+2  A: 

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:

http://stackoverflow.com/questions/151407/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 );
 return 0;
 }
bdk
So using that code to enumerate the windows and match for the PID got me the Window no problems. When I pass the window int XRaiseWindow it does nothing and returns 1. 1 == BadRequest.... I'm not sure how that applies as the doc for xRaiseWindow sugest it can return BadWindow (3) but mention nothing of BadRequest.
Lorenz03Tx
I've edited my answer above. I think I've gotten past the point where you were hitting trouble, but XRaiseWindow behaviour seems dependant on the Window Manager, so your milage may vary.
bdk
Yeah, even with the frame window ID I'm still getting the return code of 1. I'm guessing my window manager isn't letting me muck with other windows... how do I circumvent that? I get focus steeling is bad, but this is actually focus giving. Shouldn't that be allowed?
Lorenz03Tx
My window manager is metacity, I guess I'll try changing that and see if I get any different results.
Lorenz03Tx
As per this: http://www.redhat.com/docs/en-US/Red_Hat_Enterprise_Linux/5.5/html/Technical_Notes/metacity.html Looks like Metacity does not permit XRaiseWindow from outside the application. It does appear to support _NET_ACTIVE_WINDOW however, which might work for you: http://standards.freedesktop.org/wm-spec/1.3/ar01s03.html
bdk