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