58 votes

Comment obtenir une fenêtre X11 à partir d'un ID de processus ?

Sous Linux, mon application C++ utilise fork() et execv() pour lancer plusieurs instances d'OpenOffice afin de visualiser des diaporamas Powerpoint. Cette partie fonctionne.

Ensuite, je veux pouvoir déplacer les fenêtres OpenOffice à des endroits spécifiques de l'écran. Je peux le faire avec la fonction XMoveResizeWindow() mais je dois trouver la fenêtre pour chaque instance.

J'ai l'ID du processus de chaque instance, comment puis-je trouver la fenêtre X11 à partir de cela ?


UPDATE - Grâce à la suggestion d'Andy, j'ai réussi à le faire. 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. Cela ne résout donc pas mon problème, mais répond à ma question.

// 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;
}

1 votes

Je pense qu'il manque ceci #include <stdlib.h> pour le atoi utilisée dans main .

4 votes

Cinq ans de retard, mais je pense qu'il vous manque un XFree lorsque vous appelez XQueryTree.

24voto

andy Points 3302

La seule façon que je connaisse de le faire est de parcourir l'arbre de Windows jusqu'à ce que vous trouviez ce que vous cherchez. Traverser n'est pas difficile (il suffit de voir ce que fait xwininfo -Root -tree en regardant xwininfo.c si vous avez besoin d'un exemple).

Mais comment identifier la fenêtre que vous recherchez ? Quelques définissent une propriété de fenêtre appelée _NET_WM_PID.

Je crois qu'OpenOffice es est l'une des applications qui définit cette propriété (comme la plupart des applications Gnome), vous avez donc de la chance.

0 votes

L'échappement des underscores avec des backslashes a fonctionné pour moi l'autre jour

0 votes

Ah, merci. L'échappement des underscores fonctionne en effet. Je suppose que c'est un peu plus que du HTML.

15voto

hoho Points 41

Vérifier si /proc/PID/environ contient une variable appelée WINDOWID

4 votes

Ce site WINDOWID est défini par le parent du processus (ou l'un des parents), et non par le processus lui-même. C'est à un enfant de déterminer le WINDOWID de son parent.

12voto

Raphael Wimmer Points 71

Un peu tard pour la fête. Cependant : En 2004, Harald Welte a publié un extrait de code qui enveloppe l'appel XCreateWindow() via LD_PRELOAD et stocke l'identifiant du processus dans _NET_WM_PID. Cela permet de s'assurer que chaque fenêtre créée possède une entrée PID.

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

0 votes

Ce code fonctionne toujours, il faut juste le diviser en fichiers .c/.h, compiler avec : gcc -nostartfiles -fPIC -shared -Wl,-soname,xwrap.so -ldl -lX11 -o xwrap.so xwrap.c (avec quelques modifications mineures pour les noms de propriétés)

2 votes

Il s'agit d'une solution incroyablement bonne (bien que peu pratique), si l'on considère que X11 semble avoir été conçu pour rendre la vie des gestionnaires de fenêtres aussi misérable que possible...

2voto

wnoise Points 6448

Il n'y a pas de bon moyen. Les seules vraies options que je vois, sont :

  1. Vous pouvez chercher dans l'espace d'adressage du processus pour trouver les informations de connexion et l'ID de la fenêtre.
  2. Vous pouvez essayer d'utiliser netstat ou lsof ou ipcs pour mapper les connexions au serveur X, puis (d'une manière ou d'une autre ! vous aurez besoin de Root au moins) regarder ses informations de connexion pour les trouver.
  3. Lorsque vous générez une instance, vous pouvez attendre qu'une autre fenêtre soit mappée, supposer que c'est la bonne, et "passer à autre chose".

1voto

Tanktalus Points 7940

Etes-vous sûr d'avoir l'ID du processus de chaque instance ? Mon expérience avec OOo m'a appris qu'en essayant d'exécuter une seconde instance d'OOo, on ne fait que dialoguer avec la première instance d'OOo, et on lui demande d'ouvrir le fichier supplémentaire.

Je pense que vous allez devoir utiliser les capacités d'envoi de messages de X pour lui demander gentiment sa fenêtre. J'espère qu'OOo documente ses couvertures quelque part.

0 votes

J'étudie actuellement l'API d'OOo pour voir s'il existe une fonction permettant d'obtenir les données dont j'ai besoin.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X