tags:

views:

5653

answers:

5

Under Linux, my C++ application is using fork() and execv() to launch multiple instances of OpenOffice so as to view some powerpoint slide shows. This part works.

Next I want to be able to move the OpenOffice windows to specific locations on the display. I can do that with the XMoveResizeWindow() function but I need to find the Window for each instance.

I have the process ID of each instance, how can I find the X11 Window from that ?


UPDATE - Thanks to Andy's suggestion, I have pulled this off. I'm posting the code here to share it with the Stack Overflow community.

Unfortunately Open Office does not seem to set the _NET_WM_PID property so this doesn't ultimately solve my problem but it does answer the question.

// Attempt to identify a window by name or attribute.
// by Adam Pierce <[email protected]>

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <iostream>
#include <list>

using namespace std;

class WindowsMatchingPid
{
public:
    WindowsMatchingPid(Display *display, Window wRoot, unsigned long pid)
     : _display(display)
     , _pid(pid)
    {
    // Get the PID property atom.
     _atomPID = XInternAtom(display, "_NET_WM_PID", True);
     if(_atomPID == None)
     {
      cout << "No such atom" << endl;
      return;
     }

     search(wRoot);
    }

    const list<Window> &result() const { return _result; }

private:
    unsigned long  _pid;
    Atom           _atomPID;
    Display       *_display;
    list<Window>   _result;

    void search(Window w)
    {
    // Get the PID for the current Window.
     Atom           type;
     int            format;
     unsigned long  nItems;
     unsigned long  bytesAfter;
     unsigned char *propPID = 0;
     if(Success == XGetWindowProperty(_display, w, _atomPID, 0, 1, False, XA_CARDINAL,
                                      &type, &format, &nItems, &bytesAfter, &propPID))
     {
      if(propPID != 0)
      {
      // If the PID matches, add this window to the result set.
       if(_pid == *((unsigned long *)propPID))
        _result.push_back(w);

       XFree(propPID);
      }
     }

    // Recurse into child windows.
     Window    wRoot;
     Window    wParent;
     Window   *wChild;
     unsigned  nChildren;
     if(0 != XQueryTree(_display, w, &wRoot, &wParent, &wChild, &nChildren))
     {
      for(unsigned i = 0; i < nChildren; i++)
       search(wChild[i]);
     }
    }
};

int main(int argc, char **argv)
{
    if(argc < 2)
     return 1;

    int pid = atoi(argv[1]);
    cout << "Searching for windows associated with PID " << pid << endl;

// Start with the root window.
    Display *display = XOpenDisplay(0);

    WindowsMatchingPid match(display, XDefaultRootWindow(display), pid);

// Print the result.
    const list<Window> &result = match.result();
    for(list<Window>::const_iterator it = result.begin(); it != result.end(); it++)
     cout << "Window #" << (unsigned long)(*it) << endl;

    return 0;
}
+1  A: 

Are you sure you have the process ID of each instance? My experience with OOo has been that trying to run a second instance of OOo merely converses with the first instance of OOo, and tells that to open the additional file.

I think you're going to need to use the message-sending capabilities of X to ask it nicely for its window. I would hope that OOo documents its coversations somewhere.

Tanktalus
I'm currently looking into the OOo API to see if there is any function to get me the data I need.
Adam Pierce
A: 

There is no good way. The only real options I see, are:

  1. You could look around in the process's address space to find the connection information and window ID.
  2. You could try to use netstat or lsof or ipcs to map the connections to the Xserver, and then (somehow! you'll need root at least) look at its connection info to find them.
  3. When spawning an instance you can wait until another window is mapped, assume it's the right one, and `move on.
wnoise
A: 

You might be able to see the window id if you ltrace ooo and grep that for XCreateWindow.

dicroce
+3  A: 
andy
Escaping underscores with backslashes worked for me the other day…
andrew
Ah, thanks. Escaping underscores does indeed work. I guess it is a little more than just HTML-like.
andy
A: 

Check if /proc/PID/environ contains a variable called WINDOWID

hoho