mac - ¿Cómo obtener una ventana X11 desde una identificación de proceso?
x11 windows (7)
En Linux, mi aplicación C ++ está utilizando fork () y execv () para iniciar varias instancias de OpenOffice a fin de ver algunas presentaciones 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 Stack Overflow.
Desafortunadamente, Open Office no parece configurar la propiedad _NET_WM_PID, por lo que no soluciona mi problema en última instancia, pero responde la pregunta.
// 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;
}
¿Estás seguro de que tienes el ID de proceso de cada instancia? Mi experiencia con OOo ha sido que tratar de ejecutar una segunda instancia de OOo simplemente conversa con la primera instancia de OOo y le dice que abra el archivo adicional.
Creo que vas a necesitar usar las capacidades de envío de mensajes de X para preguntarle muy bien por su ventana. Espero que OOo documente sus coversations en alguna parte.
La única forma en que sé hacer esto es atravesar el árbol de las ventanas hasta que encuentres lo que estás buscando. Atravesar no es difícil (simplemente vea lo que hace xwininfo -root -tree mirando xwininfo.c si necesita un ejemplo).
¿Pero cómo identifica la ventana que está buscando? Algunas aplicaciones establecen una propiedad de ventana llamada _NET_WM_PID.
Creo que OpenOffice es una de las aplicaciones que establece esa propiedad (al igual que la mayoría de las aplicaciones de Gnome), por lo que estás de suerte.
No hay una buena manera. Las únicas opciones reales que veo son:
- Puede buscar en el espacio de direcciones del proceso para encontrar la información de conexión y la identificación de la ventana.
- Puedes intentar usar netstat o lsof o ipcs para mapear las conexiones al Xserver, y luego (de alguna manera, necesitarás root al menos) mira su información de conexión para encontrarlas.
- Al generar una instancia, puede esperar hasta que se asigne otra ventana, asumir que es la correcta y `seguir adelante.
Compruebe si / proc / PID / environ 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 a 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.
Intenta 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")
Obtengo muchos identificadores. Lo uso para establecer una ventana de terminal como urgente cuando se hace con un comando largo, con el programa seturgent
. xdotool
todos los ID que obtengo de xdotool
y ejecuto seturgent
sobre ellos.
Si usas Python, encontré un camino hasta aquí , la idea es de BurntSushi
Si lanzó la aplicación, entonces debe conocer su cadena de cmd, con la que puede reducir las llamadas a xprop
, siempre puede recorrer todos los xids y comprobar si el pid es el mismo que el pid que desea
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