Bash script for automatic viewport changing and other WM stuff (works with compiz)
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Bash script for automatic viewport changing and other WM stuff (works with compiz)
I had to make for work a collectd based network monitoring system which displays data for each server in a fullscreen conky on different compiz viewports. I have to switch viewports automatically when the machine isn't operated (sorta screensaver) and also if i had to call attention in the case something bad happens, autoswitching should stop and the relevant viewport be showed up.
This requires an interface to talk dynamically to the WM, which i've implemented in bash with support of the widely available "wmctrl" program.
#!/bin/bash
# BASICS ***************************************************************
# enable extended globbing
shopt -qs extglob
# VARS *****************************************************************
scriptName="${0##*/}"
scriptDir=$(readlink -f "${0%/*}")
scriptVersion=1.1
scriptLock="$scriptDir/$scriptName.pid"
scriptPipe="$scriptDir/$scriptName.fifo"
# FUNCS ****************************************************************
getScreenConfig() {
local wmctrld=$(wmctrl -d | sed 's/\*//g')
# desktop geometry
dX=${wmctrld##*DG: } && dX=${dX%%x*}
dY=${wmctrld#*x} && dY=${dY%% *}
# viewport geometry
vX=${wmctrld##*WA: } && vX=${vX#* } && vX=${vX%%x*}
vY=${wmctrld##*x} && vY=${vY%% *}
# viewport config
(( vRows=dX/vX , vCols=dY/vY, vTotal=vRows*vCols ))
# current viewport
cvX=${wmctrld##*VP: } && cvY=${cvX#*,}
cvX=${cvX%%,*} && cvY=${cvY%% *}
# verbosity
[[ "$1" == "-v" ]] && {
echo "Geometry: desktop $dX"x"$dY, viewport: $vX"x"$vY"
echo "Viewports: $vRows"h \* "$vCols"v = "$vTotal total"
echo "Current viewport: "$(getV $cvX $cvY)" ($cvX,$cvY)"
}
}
getX() {
echo $(( (($1 - 1) % vRows) * vX ))
}
getY() {
echo $(( (($1 - 1) / vRows) * (vY + 1) ))
}
getV() {
echo $(( ($1 / vX) + (( $2 / (vY + 1) ) * vRows) + 1 ))
}
gotoViewport() {
(( $1 > 0 && $1 <= vTotal )) && {
echo "$FUNCNAME: switching to viewport $1 ("$(getX $1),$(getY $1)")"
wmctrl -o $(getX $1),$(getY $1)
return $?
}
echo "$FUNCNAME: parameter may be an integer between 1 and $vTotal, got $1"
return 1
}
gotoWindow() {
wmctrl -a "$1" && {
echo "$FUNCNAME: switching to window \"$1\" - viewport "$(getV $cvX $cvY)" ($cvX,$cvY)"
return $?
}
echo "$FUNCNAME: couldn't find a window named \"$1\""
return 1
}
cmdGoto() {
! (( $# )) && echo "$FUNCNAME: need parameters, accepting \$1=viewport|(+|-)viewport|windowname" && return 1
(( $# > 1 )) && echo "$FUNCNAME: extra parameters, accepting \$1=viewport|(+|-)viewport|windowname" && return 1
case "$1" in
# viewport
+([[:digit:]])) gotoViewport "$1" ;;
# viewport offset
@(-|+)+([[:digit:]]))
getScreenConfig
local remainder=$(( ($(getV $cvX $cvY) + ($1)) % vTotal ))
gotoViewport $(( (remainder ? 0 : vTotal) + remainder ))
;;
# window
*) gotoWindow "$1" ;;
esac
return $?
}
cmdRotate() {
! (( $# )) && echo "$FUNCNAME: need parameters, accepting \$1=delay \$2=(+|-)step" && return 1
(( $# > 2 )) && echo "$FUNCNAME: extra parameters, accepting \$1=delay \$2=(+|-)step" && return 1
[[ "${1//*([[:digit:]])}" ]] && echo "$FUNCNAME: \"$1\" is not a positive integer" && return 1
[[ "${2//@(-|+)*([[:digit:]])}" ]] && echo "$FUNCNAME: \"$2\" is not a positive step" && return 1
echo "$FUNCNAME: setting rotation interval to $1 seconds"
# if there is a rotation loop running, finish it
[[ "${rotPID+defined}" ]] && cmdStop
doRotate "$@" &
rotPID=$!
return $?
}
cmdStop() {
[[ ! "${rotPID+defined}" ]] && echo "$FUNCNAME: there isn't any rotation loop running" && return 1
(($#>1)) && echo "$FUNCNAME: extra parameters, accepting \$1=viewport|(+|-)viewport|nombre-ventana" && return 1
# if there is a rotation loop running, finish it
echo "$FUNCNAME: finishing rotation $rotPID"
kill -15 $rotPID &
unset rotPID
# we have a goto
[[ $1 ]] && cmdGoto "$1"
return $?
}
doRotate() {
echo "$FUNCNAME ($BASHPID): starting rotation..."
trap "trap - TERM && echo $FUNCNAME \($BASHPID\): exiting... && exit 0" TERM
while sleep $1; do cmdGoto ${2-+1}; done
}
doInit() {
echo "$FUNCNAME: initializing..."
# lock
(set -o noclobber; echo "$$" > "$scriptLock") &>/dev/null || {
# lock found
echo "$FUNCNAME: found lockfile, checking if the process is alive..."
# here goes a check using "cmd pid"
kill -0 $(cat "$scriptLock") &>/dev/null && \
echo "$FUNCNAME: found a running proceess with ID " $(cat "$scriptLock")", saliendo..." && exit 0
# dead pid: clean up
rm -f $scriptPipe &>/dev/null
echo "$$" >| "$scriptLock"
}
# pipe (connect stdin too)
mknod "$scriptPipe" p
# traps
trap "doExit" INT TERM EXIT
}
doExit() {
echo "$FUNCNAME: exiting..."
# if there is a rotation loop running, finish it
[[ "${rotPID+defined}" ]] && cmdStop
# delete lock and exit
rm -fv "$scriptLock" "$scriptPipe"
exit $?
}
getInput() {
echo "$scriptName: waiting for commands"
# while read -ep"-> " line; do
while true; do
read line < "$scriptPipe"
case "$line" in
@(goto|rotate|stop)*(+([[:space:]])*)) cmd${line^} ;;
quit) doExit ;;
pid) echo $$ ;;
*) echo "$scriptName: unknown command: $line" ;;
esac
done
}
# MAIN *****************************************************************
doInit
getScreenConfig -v
getInput
the script can be saved with any name, and i suggest you to run it in the background:
Code:
scriptname &
It opens a pipe, and listens for commands on that pipe, so you can command it with
Code:
echo "command" > pipe
or
Code:
cat>pipe
and start typing away.
Accepted commands:
goto ViewportNumber (1 < ViewportNumber < MaxAvailableViewport)
go to the specified viewport
goto +ViewportOffset
go as many viewports "next", wrapping around as needed (i.e. you can use any positive integer).
goto -ViewportOffset
same as before, but in the "previous" direction
goto WindowName
go to the viewport where WindowName is, and bring it to front. This is simply a direct call to "wmctrl -a" and hence it follows its semantics, i encourage you to read and test it.
rotate Interval
start iterating over all viewports, with a delay of Interval seconds in between
rotate Interval +Step
same as before, but jumping Step viewports on each iteration
rotate Interval -Step
same as before, but in the opposite direction
If there is any rotation already running, rotate will stop it and start a new one with the new parameters.
stop
stop any running rotations. Can accept the same arguments as "goto", which will cause the specified action to take place after stop.
pid
print the script's PID
quit
exit the script and delete the command pipe (can handle soft kill signals sent to it's process, i.e. ctrl-C).
That's it!
This is a work in progresss so i'm asking you to test it and help me to add this features please:
first of all: use dbus for comm with compiz
run rotations as coprocs
command line arguments and send commands to a running process if it detects one
better detection of a running instance
more commands
input via readline
ability to handle other WM configs (not only viewports)
Reqs: bash 4, wmctrl, a WM using Viewports (tested only with compiz)
Tell me if you have corrections/code to add/requests/whatever. Enjoy!
Last edited by Juako; 01-04-2011 at 05:17 PM.
Reason: code update
Anyway, i recently found that more powerful results (with compiz) can be obtained by directly talking to its dbus interface, which allows querying/setting config values, and sending control messages to plugins, etc. I'll soon modify the script to use that interface.
I didn't thought the script was that long, but i'll have the pastebin into account for the next one, thanks!
Don't misunderstand, I said "looks useful", not "is useful". I can't say that because I can't read it, nor do I think I have a WM it will work on. It's actually the width, not the length that is causing me a problem -- the best compromise is Opera at 140%, that gives just over half the screen to the "Code:" block & I can readably see 57 columns.
I wish you would reconsider putting this one in a pastebin.
Finally, don't take the above as lessening my thanks for taking the time to write, test, document, post, share your script.
Fair enough! it looks fine on my screen, but then again perhaps if you have a 4:3 or other type it sure can look different.
So sed -i $lastpost "s/I didn't thought the script was that long, but i'll have the pastebin into account for the next one, thanks!/I didn't thought the script was that wide, but i'm having the pastebin into account for this one, thanks!"
Ah, gotcha! I've update the pastebin too, though my doubts persist on how available it'll be over time. Does LQ have its own area/way to post formatted code? Thought of posting the code in my LQ "blog" and link there... but when posting i realized the editor is the same as here, so same story
Thanks for thinking to update the pastebin. I share your doubts about its long tern availability. LQ does not have its own area/way to post formatted code. Feel free to suggest one in LQ S&F, I would support you.
Putting code in one's blog (I've considered that too) at least puts in a separate tab for the reader, but does nothing for using the full width of everyone's screens.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.