Pregunta

En Linux, mi aplicación C ++ está usando fork () y execv () para lanzar varias instancias de OpenOffice para ver algunas presentaciones de diapositivas de PowerPoint. Esta parte funciona.

A continuación, quiero poder mover las ventanas de OpenOffice a ubicaciones específicas en la pantalla. Puedo hacerlo con la función XMoveResizeWindow () pero necesito encontrar la ventana para cada instancia.

Tengo el ID de proceso de cada instancia, ¿cómo puedo encontrar la ventana X11 a partir de eso?


ACTUALIZACIÓN - Gracias a la sugerencia de Andy, he logrado esto. Estoy publicando el código aquí para compartirlo con la comunidad de Stack Overflow.

Desafortunadamente, Open Office no parece establecer la propiedad _NET_WM_PID, por lo que esto en última instancia no resuelve mi problema pero sí responde la pregunta.

// Attempt to identify a window by name or attribute.
// by Adam Pierce <adam@doctort.org>

#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;
}
¿Fue útil?

Solución

La única forma en que sé hacer esto es atravesar el árbol de ventanas hasta que encuentre lo que está buscando. Recorrer no es difícil (solo vea lo que hace xwininfo -root -tree mirando xwininfo.c si necesita un ejemplo).

Pero, ¿cómo identificas la ventana que estás buscando? Algunas aplicaciones establecen una propiedad de ventana llamada _NET_WM_PID.

Creo que OpenOffice es una de las aplicaciones que establece esa propiedad (como lo hacen la mayoría de las aplicaciones de Gnome), así que estás de suerte.

Otros consejos

Verifique si / proc / PID / environmental contiene una variable llamada WINDOWID

Un poco tarde para la fiesta. Sin embargo: En 2004, Harald Welte publicó un fragmento de código que envuelve la llamada XCreateWindow () a través de LD_PRELOAD y almacena la identificación del proceso en _NET_WM_PID. Esto asegura que cada ventana creada tenga una entrada PID.

http://www.mail-archive.com/devel@xfree86.org/msg05806 .html

Intente instalar xdotool , luego:

#!/bin/bash
# --any and --name present only as a work-around, see: https://github.com/jordansissel/xdotool/issues/14
ids=$(xdotool search --any --pid "$1" --name "dummy")

Tengo muchos identificadores. Lo uso para configurar una ventana de terminal como urgente cuando se hace con un comando largo, con el programa seturgent . Simplemente recorro todos los identificadores que obtengo de xdotool y ejecuto seturgent en ellos.

No hay una buena manera. Las únicas opciones reales que veo son:

  1. Puede buscar en el espacio de direcciones del proceso para encontrar la información de conexión y la ID de la ventana.
  2. Podría intentar usar netstat o lsof o ipcs para asignar las conexiones al servidor X, y luego (de alguna manera necesitará root al menos) ver su información de conexión para encontrarlas.
  3. Al generar una instancia, puede esperar hasta que se asigne otra ventana, asumir que es la correcta y `seguir adelante.

¿Está seguro de que tiene el ID de proceso de cada instancia? Mi experiencia con OOo ha sido que intentar ejecutar una segunda instancia de OOo simplemente conversa con la primera instancia de OOo y le dice que abra el archivo adicional.

Creo que necesitará usar las capacidades de envío de mensajes de X para pedirle su ventana. Espero que OOo documente sus cubiertas en alguna parte.

Si usa Python, encontré una manera aquí , la idea es de BurntSushi

Si inició la aplicación, entonces debe conocer su cadena cmd, con la que puede reducir las llamadas a xprop , siempre puede recorrer todos los xids y verificar si el pid es el mismo que el pid que quieras

import subprocess
import re

import struct
import xcffib as xcb
import xcffib.xproto

def get_property_value(property_reply):
    assert isinstance(property_reply, xcb.xproto.GetPropertyReply)

    if property_reply.format == 8:
        if 0 in property_reply.value:
            ret = []
            s = ''
            for o in property_reply.value:
                if o == 0:
                    ret.append(s)
                    s = ''
                else:
                    s += chr(o)
        else:
            ret = str(property_reply.value.buf())

        return ret
    elif property_reply.format in (16, 32):
        return list(struct.unpack('I' * property_reply.value_len,
                                  property_reply.value.buf()))

    return None

def getProperty(connection, ident, propertyName):

    propertyType = eval(' xcb.xproto.Atom.%s' % propertyName)

    try:
        return connection.core.GetProperty(False, ident, propertyType,
                                        xcb.xproto.GetPropertyType.Any,
                                        0, 2 ** 32 - 1)
    except:
        return None


c = xcb.connect()
root = c.get_setup().roots[0].root

_NET_CLIENT_LIST = c.core.InternAtom(True, len('_NET_CLIENT_LIST'),
                                     '_NET_CLIENT_LIST').reply().atom


raw_clientlist = c.core.GetProperty(False, root, _NET_CLIENT_LIST,
                                    xcb.xproto.GetPropertyType.Any,
                                    0, 2 ** 32 - 1).reply()

clientlist = get_property_value(raw_clientlist)

cookies = {}

for ident in clientlist:
    wm_command = getProperty(c, ident, 'WM_COMMAND')
    cookies[ident] = (wm_command)

xids=[]

for ident in cookies:
    cmd = get_property_value(cookies[ident].reply())
    if cmd and spref in cmd:
        xids.append(ident)

for xid in xids:
    pid = subprocess.check_output('xprop -id %s _NET_WM_PID' % xid, shell=True)
    pid = re.search('(?<=\s=\s)\d+', pid).group()

    if int(pid) == self.pid:
        print 'found pid:', pid
        break

print 'your xid:', xid

Me tomé la libertad de volver a implementar el código del OP usando algunas características modernas de C ++. Mantiene las mismas funcionalidades pero creo que se lee un poco mejor. Además, no se filtra incluso si la inserción del vector se produce.

// Attempt to identify a window by name or attribute.
// originally written by Adam Pierce <adam@doctort.org>
// revised by Dario Pellegrini <pellegrini.dario@gmail.com>

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


std::vector<Window> pid2windows(pid_t pid, Display* display, Window w) {
  struct implementation {
    struct FreeWrapRAII {
      void * data;
      FreeWrapRAII(void * data): data(data) {}
      ~FreeWrapRAII(){ XFree(data); }
    };

    std::vector<Window> result;
    pid_t pid;
    Display* display;
    Atom atomPID;

    implementation(pid_t pid, Display* display): pid(pid), display(display) {
      // Get the PID property atom
      atomPID = XInternAtom(display, "_NET_WM_PID", True);
      if(atomPID == None) {
        throw std::runtime_error("pid2windows: no such atom");
      }
    }

    std::vector<Window> getChildren(Window w) {
      Window    wRoot;
      Window    wParent;
      Window   *wChild;
      unsigned  nChildren;
      std::vector<Window> children;
      if(0 != XQueryTree(display, w, &wRoot, &wParent, &wChild, &nChildren)) {
        FreeWrapRAII tmp( wChild );
        children.insert(children.end(), wChild, wChild+nChildren);
      }
      return children;
    }

    void emplaceIfMatches(Window w) {
      // Get the PID for the given 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) {
          FreeWrapRAII tmp( propPID );
          if(pid == *reinterpret_cast<pid_t*>(propPID)) {
            result.emplace_back(w);
          }
        }
      }
    }

    void recurse( Window w) {
      emplaceIfMatches(w);
      for (auto & child: getChildren(w)) {
        recurse(child);
      }
    }

    std::vector<Window> operator()( Window w ) {
      result.clear();
      recurse(w);
      return result;
    }
  };
  //back to pid2windows function
  return implementation{pid, display}(w);
}

std::vector<Window> pid2windows(const size_t pid, Display* display) {
  return pid2windows(pid, display, XDefaultRootWindow(display));
}


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

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

  // Start with the root window.
  Display *display = XOpenDisplay(0);
  auto res = pid2windows(pid, display);

  // Print the result.
  for( auto & w: res) {
    std::cout << "Window #" << static_cast<unsigned long>(w) << std::endl;
  }

  XCloseDisplay(display);
  return 0;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top