Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

  1. #1
    Rédacteur

    [Xlib] Récupérer le display sur lequel a été créée une fenêtre
    Salut

    J'utilise la Xlib pour faire quelques manips de fenêtrage sous Linux, et je cherche à récupérer le couple display/écran sur lequel a été créée une fenêtre. Je ne les connais pas car ce n'est pas mon code qui crée la fenêtre, je reçois juste son identificateur.

    J'ai fouillé la documentation mais je n'ai vraiment rien trouvé. Est-ce que c'est possible ?

  2. #2
    Expert éminent sénior
    Il y a plusieurs possibilités, mais d'abord quelques questions :

    1) utilises-tu une Window Manager ?
    2) utilises-tu Xt ou juste la Xlib ?
    3) sais-tu si c'est sur le même display que ton appli ou non ?
    "Un homme sage ne croit que la moitié de ce qu’il lit. Plus sage encore, il sait laquelle".

    Consultant indépendant.
    Architecture systèmes complexes. Programmation grosses applications critiques. Ergonomie.
    C, Fortran, XWindow/Motif, Java

    Je ne réponds pas aux MP techniques

  3. #3
    Rédacteur

    Content d'avoir une réponse

    Tout d'abord je tiens à préciser que ça ne fait que quelques jours que je me suis penché sur la Xlib (et sur Linux en général), mais j'ai une connaissance suffisante des bibliothèques de fenêtrage bas niveau pour savoir de quoi il retourne. Mais si mes propos sont imprécis ou erronés, merci de me corriger

    1) utilises-tu une Window Manager ?
    Pas dans mon programme.

    2) utilises-tu Xt ou juste la Xlib ?
    J'utilise juste la Xlib.

    3) sais-tu si c'est sur le même display que ton appli ou non ?
    Il peut y avoir plusieurs cas de figure :
    • Mon appli ne reçoit que des fenêtres externes et donc n'ouvre pas de display pour elle-même
    • Mon appli doit créer des fenêtres elle-même, et là je ne suis pas sûr de la méthode à utiliser. Est-ce qu'il vaut mieux réutiliser le même display que les éventuelles fenêtres externes déjà créées ? Avoir plusieurs display implique quoi exactement, dans une même appli ?

  4. #4
    Expert éminent sénior
    ok je crois qu'il y a une chose fondamentale que tu n'as pas comprise...

    Le Display est l'ensemble consitué par une MACHINE + N écrans.

    Donc si tu tournes sur une machine linux, le display X est une table associée à la machine... Unique pour cette machine (associée à l'adresse IP).

    Donc toute fenêtre créée sur cette machine a le même display.


    Ensuite, comme son nom l'indique, le Screen est l'écran. Si par exemple tu as 2 écrans distincts sur ta machine, l'un sera "écran 0" et l'autre "écran 1".
    Si tu n'en as qu'un, toutes les fenêtres auront le même écran.

    Pour une application, avoir plusieurs display simultanés implique qu'elle affiche simultanément sur plusieurs machines (noeuds d'un réseau par exemple).

    Quand une fenêtre est affichée sur un écran, elle a automatiquement associé un display (la machine) et un screen (l'écran sur lequel elle est affichée).


    Donc ton programme ne CHOISIS pas. Quand il crée une fenêtre, le serveur X regarde la variable globale (shell) display (commande "export DISPLAY=..."). Si cette variable est non itinialisée, cela se fait par défaut sur la machine en question. Si la variable est initialisée à "réseau:noeud:ecran" alors le serveur X "forwardera" la demande au serveur X de la machine en question et la fenêtre tentera de s'afficher sur l'écran de la machine en question.

    Par conséquent, par défaut, que tu crées une fenêtre ou que tu cherches une fenêtre sur ton écran, c'est la même chose : elles partagent toutes le même display et le même screen.

    Ce qui est (difficilement) faisable et ce que je pensais que tu demandais, c'était si il était possible de récupérer une fenêtre sur un autre écran sur une autre machine....

    Je pense qu'avant toute chose il faut lire à fond les premiers chapitres de la bible X ( "XWindow System" , Scheiffler, Gettys, Newman).

    Sinon je peux donner un cours
    "Un homme sage ne croit que la moitié de ce qu’il lit. Plus sage encore, il sait laquelle".

    Consultant indépendant.
    Architecture systèmes complexes. Programmation grosses applications critiques. Ergonomie.
    C, Fortran, XWindow/Motif, Java

    Je ne réponds pas aux MP techniques

  5. #5
    Rédacteur

    A vrai dire c'est ce que je croyais avoir compris. A chaque fois que je voulais une fenêtre, interne ou externe (à mon appli), j'ouvrais une connexion sur le display par défaut (XOpenDevice(NULL)) en pensant récupérer toujours le même. Mais je me suis rendu compte que les changement que j'effectuais sur les fenêtres externes échouaient tout le temps, ce qui semblait venir du fait que mon pointeur Display* était différent de celui qui avait servi à créer la fenêtre.

    Donc en fait ma question est : quelle est le rapport entre le display en lui-même (identifié par son nom "host:ecran" -- toujours le même dans mon cas) et le pointeur que l'on reçoit en ouvrant ce display avec XOpenDisplay (toujours différent dans mon cas) ?

  6. #6
    Expert éminent sénior
    Citation Envoyé par Laurent Gomila
    A vrai dire c'est ec que je croyais avoir compris. A chaque fois que je voulais une fenêtre, interne ou externe (à mon appli), j'ouvrais une connexion sur le display par défaut (XOpenDevice(NULL)) en pensant récupérer toujours le même. Mais je me suis rendu compte que les changement que j'effectuais sur les fenêtres externes échouaient tout le temps, ce qui semblait venir du fait que mon pointeur Display* était différent de celui qui avait servi à créer la fenêtre.

    Donc en fait ma question est : quelle est le rapport entre le display en lui-même (identifié par son nom "host:ecran" -- toujours le même dans mon cas) et le pointeur que l'on reçoit en ouvrant ce display avec XOpenDisplay (toujours différent dans mon cas) ?
    D'abord pourquoi ouvrir avec OpenDevice ??

    Tu fais juste OpenDisplay ça suffit..

    Le rapport est un numéro dans une table par process, c'est tout..

    En fait, ce qu'il faut faire c'est :

    Au démarrage du programme ouvrir UNE SEULE FOIS le display, et le screen.


    Puis créer toutes les fenêtres avec ce display et ce screen.

    Quant aux autres fenêtres, la technique est un peu pernicieuse.. Il faut partir de la RootWindow, puis chercher ses enfants (XQueryTree). Parmi ces enfants, il faut descendre jusqu'à l'étape où il n'y a plus de fenêtre de même dismension que la Root (en général 1 ou 2 étages : ce sont les fenêtres utilisées par le WM). Et là, il faut explorer les enfants et chercher ce que tu veux (XGetWindowAttributes) . Ou alors il faut passer par les ATOM et aller chercher dans le Window Manager... Mais c'est plus complexe.

    Cela dépend si tu connais le nom (ou le positionnement) de la fenêtre.
    "Un homme sage ne croit que la moitié de ce qu’il lit. Plus sage encore, il sait laquelle".

    Consultant indépendant.
    Architecture systèmes complexes. Programmation grosses applications critiques. Ergonomie.
    C, Fortran, XWindow/Motif, Java

    Je ne réponds pas aux MP techniques

  7. #7
    Rédacteur

    D'abord pourquoi ouvrir avec OpenDevice ??
    Tu fais juste OpenDisplay ça suffit..
    Oups, une petite faute de frappe. C'était bien sûr XOpenDisplay.

    Au démarrage du programme ouvrir UNE SEULE FOIS le display, et le screen.
    Puis créer toutes les fenêtres avec ce display et ce screen.
    C'est justement là mon problème : j'ai potentiellement à gérer en même temps des fenêtres créées par moi, et des fenêtres créées par l'utilisateur de ma bibliothèque. Et je ne peux pas faire en sorte que seul l'un des deux ouvre le display et le fournisse à l'autre. En gros, pour préciser les choses, voilà ce qu'on doit pouvoir faire avec ma bibliothèque :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    // On peut créer une fenêtre et passer son identifiant à la bibliothèque
    Window Win = XCreateWindow(...);
    MyLibWindow External(Win);
     
    // On peut aussi demander à la bibliothèque de créer elle-même la fenêtre
    MyLibWindow Internal(width, height, title, ...);

    La raison pour laquelle je ne peux communiquer que l'identifiant de la fenêtre à la bibliothèque, est que celle-ci est multi-plateforme, et que seul l'identifiant de la fenêtre est une donnée commune (il n'y a pas de display ni de screen sous Windows par exemple).
    Je pensais qu'il serait possible de se débrouiller uniquement avec l'identifiant de la fenêtre, d'ailleurs les bibliothèques de GUI multiplateformes (wxWidgets, Qt, ...) le font apparemment très bien.

  8. #8
    Expert éminent sénior
    ben t'as bien une fonction init quelquepart, non ?
    "Un homme sage ne croit que la moitié de ce qu’il lit. Plus sage encore, il sait laquelle".

    Consultant indépendant.
    Architecture systèmes complexes. Programmation grosses applications critiques. Ergonomie.
    C, Fortran, XWindow/Motif, Java

    Je ne réponds pas aux MP techniques

  9. #9
    Rédacteur

    Non, je n'en n'ai pas. Ca m'avancerait à quoi dans le cas présent ?

  10. #10
    Expert éminent sénior
    ben :

    XOpenDisplay
    XDefaultScreen
    XDefaultVisual
    XDefaultGC

    En structure statique....
    "Un homme sage ne croit que la moitié de ce qu’il lit. Plus sage encore, il sait laquelle".

    Consultant indépendant.
    Architecture systèmes complexes. Programmation grosses applications critiques. Ergonomie.
    C, Fortran, XWindow/Motif, Java

    Je ne réponds pas aux MP techniques

  11. #11
    Expert éminent sénior
    ou alors même pas besoin d'init...

    Tu fais un flag global "PassageInit = 0".

    Si (! PassageInit) alors tu fais les trucs ci-dessus dans les 2 fonctions...
    "Un homme sage ne croit que la moitié de ce qu’il lit. Plus sage encore, il sait laquelle".

    Consultant indépendant.
    Architecture systèmes complexes. Programmation grosses applications critiques. Ergonomie.
    C, Fortran, XWindow/Motif, Java

    Je ne réponds pas aux MP techniques

  12. #12
    Rédacteur

    XOpenDisplay
    XDefaultScreen
    XDefaultVisual
    XDefaultGC

    En structure statique....
    Citation Envoyé par souviron34
    ou alors même pas besoin d'init...
    Tu fais un flag global "PassageInit = 0".
    Si (! PassageInit) alors tu fais les trucs ci-dessus dans les 2 fonctions...
    C'est exactement ce que je fais
    Mais ça ne change rien au problème, si l'utilisateur appelle lui-même XOpenDisplay (et il est censé pouvoir le faire) j'aurais deux pointeurs Display différents et je serais incapable d'agir sur ses fenêtres.

  13. #13
    Expert éminent sénior
    ben si je pense...

    Le chiffre du display est le pointeur sur la structure interne ... Même si à chaque OpenDisplay il crée une nouvelle structure, les paramètres à l'intérieur de la structure doivent être les mêmes... Kifkif pour le screen.

    En fait en général quand je fais ce genre de truc, j'inclue une routine "init_Biblio" qui ressort un pointeur sur une structure contenant le display etc... à appeler dans les 2 cas de figure...

    Disons que c'est comme X : tu fais une bibliothèque. Tu donnes les instructions pour s'en servir. Si quelqu'un ne s'en sert pas suivant les instructions, tant pis pour lui.

    Par contre pour toi, tu devrais refuser de démarrer si l'init n'est pas fait.

    Ce qui fait qu'en interne, tu auras un et un seul display, 1 et 1 seul screen.

    [EDIT]

    Je n'ai pas utilisé, mais par exemple GTK et Qt n'ont-ils pas un "GTK init" ou "Qt Init" ??

    [/EDIT]
    "Un homme sage ne croit que la moitié de ce qu’il lit. Plus sage encore, il sait laquelle".

    Consultant indépendant.
    Architecture systèmes complexes. Programmation grosses applications critiques. Ergonomie.
    C, Fortran, XWindow/Motif, Java

    Je ne réponds pas aux MP techniques

  14. #14
    Rédacteur

    Le chiffre du display est le pointeur sur la structure interne ... Même si à chaque OpenDisplay il crée une nouvelle structure, les paramètres à l'intérieur de la structure doivent être les mêmes... Kifkif pour le screen.
    Pourtant il semblerait qu'il faille carrément le même pointeur (que celui avec lequel la fenêtre a été créée) pour que les fonctions n'échouent pas.

    Sinon, je ne suis pas sûr de bien comprendre ce que tu m'expliques. Tu veux en gros qu'au lieu d'avoir son display via XOpenDisplay, le client l'ait via ma fonction InitBiblio ?

  15. #15
    Expert éminent sénior
    Citation Envoyé par Laurent Gomila
    Sinon, je ne suis pas sûr de bien comprendre ce que tu m'expliques. Tu veux en gros qu'au lieu d'avoir son display via XOpenDisplay, le client l'ait via ma fonction InitBiblio ?
    Absolument...

    Regarde, ci-dessous un exemple que j'ai dans une de mes bibliothèques :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
     
      if ( (JS_IFInitialize ( "MonAppli", argc, argv, &CoreData )) == ERROR )


    Et par exemple dans le CoreData voici ce que j'ai :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    typedef struct _XParams {
     
    	Display	       *dpy;
    	Screen	       *screen;
    	Visual	       *vis;
    	GC		gc;
    	Colormap	cmap;
     
    } XParams ;
     
     
    typedef struct {
     
    /* Parametres correspondants a X */
    	XParams		        GUI_Params ;
     
    ......
     
    /* Divers Widgets */
    ......
     
    } CoreData ;



    (Bon c'est pas tout à fait ça parce que j'avais un étage d'indirection en plus, mais c'est le principe)..


    Quant à ta remarque sur les pointeurs de display, si c'est le cas, alors tu ne dois pas te servir du Window tel qu'il est passé. Tu dois récupérer ses infos (largeur, hauteur, emplacement, etc..) et comme je disais descendre l'arbre des fenêtres avec TON display pour en récupérer le nouvel ID dans TON système..

    C'est pour cette raison que GTK, Qt, Motif, Xt, utilisent des Widgets, qui sont uniquement des créations mémoire, et fournissent des fonctions ensuite comme XtDisplayOfWidget() dans la XToolkit..
    "Un homme sage ne croit que la moitié de ce qu’il lit. Plus sage encore, il sait laquelle".

    Consultant indépendant.
    Architecture systèmes complexes. Programmation grosses applications critiques. Ergonomie.
    C, Fortran, XWindow/Motif, Java

    Je ne réponds pas aux MP techniques

  16. #16
    Rédacteur

    Ok je vois, mais cette solution n'est pas réalisable dans mon cas. Comme je l'ai dit je développe une bibliothèque multi-plateformes, et rien de spécifique à l'un ou l'autre OS ne doit apparaître dans l'interface publique.
    Autre chose : l'initialisation n'est pas explicite dans ma bibliothèque, elle est réalisée au bon moment automatiquement. Et je ne veux pas qu'elle devienne explicite, car c'est justement l'un des points importants de la bibliothèque.

    Quant à ta remarque sur les pointeurs de display, si c'est le cas, alors tu ne dois pas te servir du Window tel qu'il est passé. Tu dois récupérer ses infos (largeur, hauteur, emplacement, etc..) et comme je disais descendre l'arbre des fenêtres avec TON display pour en récupérer le nouvel ID dans TON système..
    Donc tu veux dire que la fenêtre existe bien sous mon display côté bibliothèque, mais avec un identificateur différent qu'il faut que je retrouve en parcourant les fenêtres ?

  17. #17
    Expert éminent sénior
    Citation Envoyé par Laurent Gomila
    Ok je vois, mais cette solution n'est pas réalisable dans mon cas. Comme je l'ai dit je développe une bibliothèque multi-plateformes, et rien de spécifique à l'un ou l'autre OS ne doit apparaître dans l'interface publique.
    Ya pas de pbe de multi...

    C'est juste du X..

    Et d'après ce que je vois de tes routines, elle s'occupent de X....

    Par contre, si tu ne veux pas ça, c'est ce dont je parlais quand je disais "une indirection au-dessus".

    Ce que j'avais fait c'était du multi-outils graphique.

    Donc le CoreData en question n'était pas celui-là, mais un "enfant" avec un pointeur "vide" sur le père, qui lui était déterminé par l'outil (X ou ...).

    Et donc pour l'appli c'était transparent, et juste au link tu mettais la bonne biblothèque..

    Mais ok ..

    Citation Envoyé par Laurent Gomila
    Autre chose : l'initialisation n'est pas explicite dans ma bibliothèque, elle est réalisée au bon moment automatiquement. Et je ne veux pas qu'elle devienne explicite, car c'est justement l'un des points importants de la bibliothèque.
    OK, mais il y a toujours le mécanisme cité plus haut..



    Citation Envoyé par Laurent Gomila
    Donc tu veux dire que la fenêtre existe bien sous mon display côté bibliothèque, mais avec un identificateur différent qu'il faut que je retrouve en parcourant les fenêtres ?
    Absolument oui..

    TOUTES les fenêtres présentes existent comme enfants de la RootWindow.
    "Un homme sage ne croit que la moitié de ce qu’il lit. Plus sage encore, il sait laquelle".

    Consultant indépendant.
    Architecture systèmes complexes. Programmation grosses applications critiques. Ergonomie.
    C, Fortran, XWindow/Motif, Java

    Je ne réponds pas aux MP techniques

  18. #18
    Expert éminent sénior
    Tiens comme base d'exemple, si tu connais le nom de la fenêtre :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
     
    Boolean	JS_ChecksIfWindowExists (  Display *Station,
    				   Window   Base,
    				   char    *Nom)
    {
       Window	 Generale, Parent, *Enfants=(Window *)NULL ;
       int	 i ;
       unsigned int Nb_Enfants ;
       XClassHint *Hint=(XClassHint *)NULL;
     
    /*
    --- Checks the name of the base
    */
       Hint = XAllocClassHint ();
       if ( Hint == (XClassHint *)NULL )
           return False ;
     
       i = XGetClassHint (Station, Base, Hint );
     
       if ( i != 0 )
         {
    	if ( ((Hint->res_name != (char *)NULL) && (strstr (Hint->res_name, Nom) != (char *)NULL)) ||
    	     ((Hint->res_class != (char *)NULL) && (strstr (Hint->res_class, Nom) != (char *)NULL)) )
    	  {
    	     XFree ( Hint );
    	     return True ;
    	  }
         }
       XFree ( Hint);
     
    /*
    --- If it is not the right name, gets which windows are children and tests them iteratively
    */
       XQueryTree ( Station, Base, &Generale,
    		&Parent, &Enfants, &Nb_Enfants );
     
       if ( Nb_Enfants == 0 )
          return False ;
     
       for ( i = (Nb_Enfants-1) ; i >= 0 ; i-- )
          if ( JS_ChecksIfWindowExists (Station, Enfants[i], Nom) )
            {
    	   XFree ( Enfants );
    	   return True ;
    	}
     
       XFree ( Enfants );
     
       return False ;
    }
    "Un homme sage ne croit que la moitié de ce qu’il lit. Plus sage encore, il sait laquelle".

    Consultant indépendant.
    Architecture systèmes complexes. Programmation grosses applications critiques. Ergonomie.
    C, Fortran, XWindow/Motif, Java

    Je ne réponds pas aux MP techniques

  19. #19
    Rédacteur

    Je comprends bien ce que tu suggères, je sais qu'en ajoutant un niveau d'indirection je peux casser la dépendance directe du truc avec X, mais c'est une solution qui ne convient pas au design actuel de ma bibliothèque. En clair, je ne veux pas que les utilisateurs ni même ma bibliothèque aient à faire ça :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    CoreData* Data = InitLib();
    XCodeData* XData = (XCoreData*)Data; // Ou Data.XData, ou autre...
    Window W = XCreateWindow(XData.Display, ...);

    Bon on pourrait parler des heures de ce choix, mais j'aimerais n'en arriver là que s'il n'y a aucune autre solution

    Je te remercie pour le bout de code, c'est exactement ce dont j'ai besoin, mais... je ne connais pas le nom de la fenêtre, ni aucun autre de ses attributs
    J'ai seulement son identificateur (de type Window donc), est-ce qu'il y a moyen de faire avec seulement ça ?

    En tout cas merci pour ta patience et tes réponses toujours très rapides

  20. #20
    Expert éminent sénior
    Citation Envoyé par Laurent Gomila

    mais... je ne connais pas le nom de la fenêtre, ni aucun autre de ses attributs
    J'ai seulement son identificateur (de type Window donc), est-ce qu'il y a moyen de faire avec seulement ça ?
    Aucune idée.. Mais as-tu réellement essayé de passer TON display avec ce window id et de faire une manip (par exemple RaiseWindow ou LowerWindow) voir si ça marche ?

    Sinon, je ne vois pas d'autres solutions, en restant au niveau de X... Je te dis éventuellement descendre l'arbre comme ci-dessus. Sauf que si tu ne connais ni le nom, ni l'emplacement, ni la dimension, ça me semble impossible si les opérations de test ci-dessus ne marchent pas.

    Il faut au moins connaître quelque chose (le nom, l'emplacement, ...) pour pouvoir la retrouver, si le Window Id ne marche pas avec ton display.. Mais ça m'étonne que ça ne marche pas...
    "Un homme sage ne croit que la moitié de ce qu’il lit. Plus sage encore, il sait laquelle".

    Consultant indépendant.
    Architecture systèmes complexes. Programmation grosses applications critiques. Ergonomie.
    C, Fortran, XWindow/Motif, Java

    Je ne réponds pas aux MP techniques