Существует ли команда linux для определения идентификаторов окон, связанных с данным идентификатором процесса? - PullRequest
35 голосов
/ 12 февраля 2010

Учитывая iD процесса XX, я хотел бы иметь список любых оконных идентификаторов, где _NET_WM_PID = XX. Еще лучше, если это возможно, самый старый еще активный идентификатор окна.

Я очень новичок в Linux, но я пытаюсь создать сценарий, который будет принимать командную строку, и посмотреть, есть ли уже открытые окна, принадлежащие процессу, вызываемому с той же командной строкой. Если это так, просто установите фокус на это окно, в противном случае выполните командную строку, чтобы запустить новый процесс. Я собираюсь использовать это на своем рабочем столе Ubuntu, где я подключу этот сценарий к своим командам жестов мыши с простым нажатием, чтобы, например, каждый раз, когда я делаю жест для Gmail, я не получал новый сеанс Gmail, я просто попасть в мое существующее окно приложения Gmail Chrome. Возможно, есть гораздо более простой способ сделать все это, но я еще не нашел свой путь к этому.

С помощью я выяснил, как найти PID для командной строки с pgrep и как установить фокус на дескриптор окна с помощью wmctrl, но я застрял при переходе от PID к идентификатору окна.

Ответы [ 4 ]

37 голосов
/ 12 февраля 2010

xwininfo и xprop позволяют получать то, что вы хотите, но это немного сложно.

xwininfo позволяет извлекать все известные окна, а xprop - запрашивать X об одном идентификаторе окна для вашего параметра _NET_WM_PID.

Пока хакерский способ сделать это будет:

#!/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

Результат:

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

Как вы увидите, у одного процесса может быть определенное количество известных окон, даже если вы видите только одно на вашем экране.

Может быть, вы должны получить эти инструменты, чтобы делать то, что вы хотите.

25 голосов
/ 18 сентября 2012

Вы также можете искать PID с помощью wmctrl , и я думаю, что это лучший способ сделать это. xwininfo вернет все виды сущностей, которые выглядят как окна, но вы не найдете их на рабочем столе.

Если вы делаете man wmctrl вы обнаружите, что wmctrl -l перечисляет все окна, которые фактически видны на вашем рабочем столе, с (самое главное) их идентификаторами окон и заголовками . -p добавляет PID и -x добавит классы окон .

Как сказано в руководстве (RTFM, верно?: D), wmctrl также может выполнять поиск по некоторым из них и активировать окно, соответствующее поиску. Однако я понятия не имею, что определяет, какое из возможных совпадений будет возвращено. С другой стороны, вы можете использовать предоставленную функцию листинга, чтобы написать оболочку, которая делает поиск лучше и, возможно, основанную на некоторых других свойствах (таких как отметка времени последнего доступа к окну), которые вы можете получить, запросив предоставленный win id в xprop, например.

Эти строки кода ниже возвращают самый последний экземпляр окна класса сопряженного терминала:

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

Во всяком случае, для того, что вы описываете, вы создаете - на вашем месте я бы выяснил, какой класс окон генерирует ваша желаемая команда, а затем основал бы мой поиск на этом, а не на PID. В качестве альтернативы можно предположить, что команда CMD, возможно, сгенерирует окна с именем класса, включающим CMD.

После того, как вы нашли свою линию, вы должны использовать идентификатор окна
активировать окно через wmctrl.

Надеюсь, это поможет.

Примечание: я обнаружил, что xdotool может выполнять поиск по именам классов и заголовкам окон, но это крайне медленно . На моем компьютере этот bash-скрипт (который вызывает довольно много внешних утилит) работает в 10 раз быстрее, чем скомпилированная альтернатива xdotool: P.

3 голосов
/ 18 мая 2017

Здесь - несколько решений для управления окнами X11 (включая одно для этой проблемы).

Xwininfo и xprop - хорошие инструменты для получения идентификаторов всех окон, но не самые простые инструменты для получения идентификатора основного окна, связанного с PID (если это возможно даже для них) Чтобы получить идентификатор основного окна, используйте wmctrl следующим образом:

#!/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

Пример:

user ~ $  getwindidbypid 37248
0x05a00012

Это решение напечатает несколько идентификаторов окон, если wmctrl обнаружит более одного основного окна. Чтобы вернуть только первое, просто измените [@] на [0] в echo "${WIND_IDS[@]}".

2 голосов
/ 11 апреля 2017

Вы можете использовать:

xdotool getwindowfocus getwindowname

(Как есть: вам не нужно заменять эти хорошо звучащие имена на что-либо.)

...