web-dev-qa-db-fra.com

Existe-t-il une commande linux pour déterminer les ID de fenêtre associés à un ID de processus donné?

Étant donné un iD de processus de XX, j'aimerais avoir une liste de tout identifiant de fenêtre où _NET_WM_PID = XX. Encore mieux serait le plus ancien identifiant de fenêtre toujours actif si possible.

Je suis très nouveau sur Linux, mais ce que j'essaie de faire est de créer un script qui prendrait une ligne de commande et de voir s'il y a déjà une fenêtre ouverte appartenant à un processus appelé avec cette même ligne de commande. Si c'est le cas, définissez simplement le focus sur cette fenêtre, sinon exécutez la ligne de commande pour lancer un nouveau processus. Mon intention est de l'utiliser sur mon bureau ubuntu, où je connecterai ce script à mes commandes gestuelles de souris easystroke, de sorte que, par exemple, chaque fois que je fais un geste pour gmail, je n'ai pas de nouvelle session gmail, je viens être amené à ma gmail existante chrome. Peut-être y a-t-il un moyen beaucoup plus simple de procéder, mais je n'y ai pas encore trouvé mon chemin.

Avec l'aide, j'ai compris comment trouver un PID pour une ligne de commande avec pgrep et comment définir le focus sur un handle de fenêtre avec wmctrl, mais je suis coincé sur le passage du PID à l'ID de fenêtre.

38
David Korn

xwininfo et xprop permettent de récupérer ce que vous voulez, mais c'est un peu délicat.

xwininfo permet de récupérer toutes les fenêtres connues et xprop d'interroger X sur un ID de fenêtre unique pour votre paramètre _NET_WM_PID.

Jusqu'à présent, une manière hacky de le faire serait:

#!/bin/sh

findpid=$1

known_windows=$(xwininfo -root -children|sed -e 's/^ *//'|grep -E "^0x"|awk '{ print $1 }')

for id in ${known_windows}
do
    xp=$(xprop -id $id _NET_WM_PID)
    if test $? -eq 0; then
        pid=$(xprop -id $id _NET_WM_PID|cut -d'=' -f2|tr -d ' ')

        if test "x${pid}" = x${findpid}
        then
            echo "Windows Id: $id"
        fi
    fi
done

Résultat:

mycroft:~ $ ./find_windows.sh 1919
Windows Id: 0x1800748
Windows Id: 0x181b221
Windows Id: 0x1803ad5
Windows Id: 0x181f681
Windows Id: 0x181f658
Windows Id: 0x180006d
Windows Id: 0x1800003
Windows Id: 0x1800001
Windows Id: 0x180001e

Comme vous le verrez, un seul processus peut avoir un certain nombre de fenêtres connues, même si vous n'en voyez qu'une sur votre écran.

Vous devriez peut-être obtenir ces sources d'outils afin de faire ce que vous voulez.

38
Patrick

vous pouvez également rechercher des PID avec wmctrl, en fait, et je pense que c'est une meilleure façon de le faire. xwininfo retournera toutes sortes d'entités qui semblent être des fenêtres, mais vous ne les trouverez pas vraiment sur votre bureau.

Si vous faites man wmctrl, vous constaterez que wmctrl -l répertorie toutes les fenêtres qui sont réellement visibles sur votre bureau avec (surtout) leur identifiants des fenêtres et titres . - p ajoute PID et - x ajoutera classes de fenêtres .

Comme le dit le manuel (RTFM, n'est-ce pas?: D), wmctrl peut également rechercher parmi certains d'entre eux et activer une fenêtre qui correspond à la recherche. Cependant, je n'ai aucune idée de ce qui détermine laquelle de toutes les correspondances possibles sera retournée. D'autre part, vous pouvez utiliser la fonction de liste fournie pour écrire un wrapper qui effectue la recherche mieux et éventuellement en fonction d'autres propriétés (telles que l'horodatage du dernier accès à la fenêtre) que vous pouvez obtenir en interrogeant le fourni win id à xprop, par exemple.

Ces lignes de code ci-dessous renvoient à l'instance la plus récente une fenêtre de classe mate-terminal:

XTIME="_NET_WM_USER_TIME" #a shorter name for xprop query that shoul return timestamps
export TMPDIR=/dev/shm    #save tmp files to memory to make it faster
LST=`mktemp`              #tmp file to store our listing 
wmctrl -lx |  awk -F' ' '{printf("%s\t%s    \t",$1,$3); for(i=5;i<=NF;i++) printf("%s",$i); printf("\n")  }'  > $LST #pretty-print our listing of windows into the tmp file
 #To each line of listing, prepend a timestamp acquired via an xprop call
 #Use awk to find a line whose 3rd column (winclass) matches the window class "mate-terminal.Mate-terminal" and among those that do, find the one whose timestamp is the largest
while read LINE; do ID=`echo "$LINE"|cut -f 1`; TIME=`xprop -id $ID $XTIME`;  TIME="${TIME/* = /}"; echo -e "$TIME\t$LINE" ; done <$LST ) | awk -v s="mate-terminal.Mate-terminal" '$3 == s {if($1>max){max=$1;line=$0};};END{print line}'
rm $LST  #delete tmp file

Quoi qu'il en soit, pour la chose que vous décrivez, vous construisez - si j'étais vous, je trouverais quelle classe de fenêtres votre commande souhaitée génère et puis baserais ma recherche sur cela, plutôt que sur les PID. Alternativement, vous pouvez supposer que la commande CMD générera éventuellement des fenêtres avec un nom de classe qui inclut CMD.

Après avoir trouvé votre ligne, vous devez utiliser l'ID de fenêtre
pour activer la fenêtre via wmctrl.

J'espère que cela t'aides.

Remarque: j'ai découvert que xdotool peut également effectuer des recherches en fonction des noms de classe et des titres de fenêtre, mais c'est extrêmement lent . Sur mon ordinateur, ce script bash (qui appelle plusieurs utilitaires externes) est 10 fois plus rapide que l'alternative compilée qu'est xdotool: P.

27
PSkocik

Ici sont plusieurs solutions de gestion de fenêtres X11 (dont une à ce problème).

Xwininfo et xprop sont de bons outils pour obtenir les ID de toutes les fenêtres mais pas les outils les plus simples pour obtenir l'ID de la fenêtre principale associée à un PID (si cela est même possible avec eux). Pour obtenir l'ID de la fenêtre principale, utilisez wmctrl de la manière suivante:

#!/usr/bin/env bash
# getwindidbypid
# 
# Get the ID of a window by PID (if the process has a window).
# 
# Usage:
#   getwindidbypid <PID>
# 

while IFS= read line; do
  if [[ "${line}" =~ (0x)([0-9a-z]+)([ ][- ][0-9]+[ ])([0-9]*) ]]; then
    winId="${BASH_REMATCH[1]}${BASH_REMATCH[2]}"
    pid="${BASH_REMATCH[4]}"
    if [[ "${pid}" -eq "${1}" ]]; then
      WIND_IDS+=("${winId}")
    fi
  fi
done < <(wmctrl -lp)

if [ "${#WIND_IDS[@]}" -gt 0 ]; then
  echo "${WIND_IDS[@]}"
fi

Exemple:

user ~ $  getwindidbypid 37248
0x05a00012

Cette solution imprimera plusieurs ID de fenêtre si plus d'une fenêtre principale est trouvée par wmctrl. Pour renvoyer uniquement le premier, modifiez simplement [@] à [0] dans echo "${WIND_IDS[@]}".

4
Adrian Bartyczak

Vous pouvez utiliser:

xdotool getwindowfocus getwindowname

(En l'état: vous n'avez pas besoin de remplacer ces noms au son agréable par quoi que ce soit.)

3
Richard