Sous Linux, mon application C++ utilise fork () et execv () pour lancer plusieurs instances d'OpenOffice afin d'afficher certains diaporamas PowerPoint. Cette partie fonctionne.
Ensuite, je veux pouvoir déplacer les fenêtres OpenOffice vers des emplacements spécifiques sur l'écran. Je peux le faire avec la fonction XMoveResizeWindow () mais je dois trouver la fenêtre pour chaque instance.
J'ai l'ID de processus de chaque instance, comment puis-je trouver la fenêtre X11 à partir de cela?
MISE À JOUR - Grâce à la suggestion d'Andy, j'ai réussi cela. Je poste le code ici pour le partager avec la communauté Stack Overflow.
Malheureusement, Open Office ne semble pas définir la propriété _NET_WM_PID, donc cela ne résout pas mon problème, mais il répond à la 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;
}
La seule façon que je sache de faire est de parcourir l'arborescence des fenêtres jusqu'à ce que vous trouviez ce que vous cherchez. La traversée n'est pas difficile (voyez ce que fait xwininfo -root -tree en regardant xwininfo.c si vous avez besoin d'un exemple).
Mais comment identifiez-vous la fenêtre que vous recherchez? Certains les applications définissent une propriété de fenêtre appelée _NET_WM_PID.
Je crois que OpenOffice est l'une des applications qui définit cette propriété (comme le font la plupart des applications Gnome), donc vous avez de la chance.
Vérifiez si/proc/PID/environ contient une variable appelée WINDOWID
Un peu tard pour la fête. Cependant: en 2004, Harald Welte a publié un extrait de code qui encapsule l'appel XCreateWindow () via LD_PRELOAD et stocke l'ID de processus dans _NET_WM_PID. Cela garantit que chaque fenêtre créée a une entrée PID.
Essayez d'installer xdotool
, puis:
#!/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")
Je reçois beaucoup d'identifiants. Je l'utilise pour définir une fenêtre de terminal comme urgente lorsqu'elle est effectuée avec une commande longue, avec le programme seturgent
. Je viens de parcourir tous les identifiants que j'obtiens de xdotool
et d'exécuter seturgent
dessus.
Il n'y a pas de bon moyen. Les seules vraies options que je vois sont:
Êtes-vous sûr de disposer de l'ID de processus de chaque instance? Mon expérience avec OOo a consisté à essayer d'exécuter une deuxième instance de OOo ne fait que converser avec la première instance d'OOo, et lui dit d'ouvrir le fichier supplémentaire .
Je pense que vous allez avoir besoin d'utiliser les capacités d'envoi de messages de X pour lui demander gentiment sa fenêtre. J'espère que OOo documente ses couvertures quelque part.
Si vous utilisez python, j'ai trouvé un moyen ici , l'idée vient de BurntSushi
Si vous avez lancé l'application, vous devez connaître sa chaîne cmd, avec laquelle vous pouvez réduire les appels à xprop
, vous pouvez toujours parcourir tous les xids et vérifier si le pid est le même que le pid que vous voulez
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
J'ai pris la liberté de réimplémenter le code de l'OP en utilisant certaines fonctionnalités C++ modernes. Il conserve les mêmes fonctionnalités mais je pense qu'il se lit un peu mieux. De plus, il ne fuit pas même si l'insertion de vecteur se produit.
// Attempt to identify a window by name or attribute.
// originally written by Adam Pierce <[email protected]>
// revised by Dario Pellegrini <[email protected]>
#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;
}