Find window ID of a process ID in BASH script

Question

In a BASH script, I launched an application and use “$!” variable to grab it’s process ID. I would like to perform some action on the application’s main window (e.g. move or resize it). However, this requires knowing the application’s window ID. How do I find the application’s window ID, using only it’s process ID as a starting point?

The BASH script


#!/bin/bash

##################################################
# Get application's window ID
#	Input:
#		$1: application's process ID
#	Output:
#	 	$1: application's window ID
#	Return value:
#		success: 0
#		failed: 1
# Usage:
#	WID=`GetWID $PID`
#
GetWID() {
	APP=`ps --no-header -o comm -p $1`

	# Loop windows with application's executable name
	while read WID; do
		WID=`echo $WID | awk '{print $1}'`

		# Check window's PID is matching application's PID
		if [ `xprop -id $WID _NET_WM_PID | \
			awk '{print $3}'` -eq $1 ] ; then

			# Check is actual visible window
			if [ "`xwininfo -id $WID | \
				grep 'IsViewable'`" != '' ] ; then
				echo $WID
				return 0
			fi
		fi
	done < <( xwininfo -root -children 2>/dev/null | grep $APP )

	return 1
}

##################################################
# Example usage
#	1. Launch "Eye of GNOME" (EOG)
#	2. Move to top-left corner of screen
#	3. Resize to 800x600

while [ 1 ] ; do
	eog -n &
	PID=$!

	# It takes a few seconds to launch, hence retries 10 times
	for I in `seq 10` ; do
		WID=`GetWID $PID`
		if [ $? -eq 0 ] ; then
			xdotool windowmove $WID 0 0
			xdotool windowsize $WID 800 600
			exit 0
		fi
	done

	kill $PID
	zenity --question --title='Error' \
		--text='Failed to match PID and WID.' \
		--ok-label='Retry' --cancel-label='Abort program'
	if [ $? -eq 1 ] ; then
		# Abort (or Error prompt was closed)
		exit 1
	fi
done

exit 0

Pre-requisites

I tested this script on an Ubuntu Intrepid Ibex 8.10 system (with GNOME 2.24.1 and Compiz Fusion 0.7.8). While I am fairly confident this would work on most Linux systems, I don’t have proof otherwise. I would love to hear from you if you got this script working on other Linux systems.

The following programs are used by “GetWID” function:

xwininfo
xprop

The following programs are used by the example usage:

xdotool
zenity

How it works

1.
The “GetWID” function receives the process ID via parameter “$1″.

APP=`ps --no-header -o comm -p $1`

Grabs the application’s executable name.

The executable name is assigned to the “WM_CLASS” property of the application. We use this fact to speed up the search for window ID later.

2.

while read WID; do
	.
	.
done < <( xwininfo -root -children 2>/dev/null | grep $APP )

Get the list of all running processes, starting from the root window. Using the application’s executable name, we downsize the list. Hence, we loop through a list of a few processes only, instead of hundreds.

3.

WID=`echo $WID | awk '{print $1}'`

Each line output from “xwininfo -root -children” contains various information, separated by spaces. however, we are interested in the first item/field only, which is the window ID.

4.

if [ `xprop -id $WID _NET_WM_PID | awk '{print $3}'` -eq $1 ] ; then

For each window ID, we use “xprop” to get it’s “_NET_WM_PID” property, which is the process ID associated to that window ID. The actual information we need is the third field of this “xprop” output.

We then compare this process ID to the application’s process ID.

5.
However, there could be several matches, only one which is the actual application’s main window.

if [ "`xwininfo -id $WID | grep 'IsViewable'`" != '' ] ; then

To find the application’s main window, we use “xwininfo” again to look for “IsViewable” attribute.

6.

echo $WID
return 0

The window ID is found and returned by the function via “STDOUT”. We exit the function by “return 0″, indicating success.

7.

return 1

Finally, if the function failed, we “return 1″.

Example usage

8.

eog -n &
PID=$!

Launch “Eye of GNOME” (EOG). Grab the process ID from “$!”.

9.

for I in `seq 10` ; do
	.
	.
done

It takes a few seconds to launch, hence retries 10 times.

10.

WID=`GetWID $PID`

Function call. Pass the input parameter (process ID) as “$1″. Get the output parameter (window ID) from “STDOUT”.

11.

if [ $? -eq 0 ] ; then
	xdotool windowmove $WID 0 0
	xdotool windowsize $WID 800 600
	exit 0
fi
.
.

If return value is zero (indicating success), we are now able to perform the action on the window, and end the script. Else, error recovery is optional.


Post a Comment

Your email is never published nor shared. Required fields are marked *