Linux Multimonitor Madness

I’m addicted to having two monitors. It drives me crazy to go back to just one. Well yesterday one of my 19″ panels went white and stayed that way. Luckily with black Friday sales going on I was able to replace it on the cheap. However, most monitors these days are widescreen, so it takes a little getting used to. I replaced both monitors so they’d match (they were cheap) so my X screen is effectively 3200×900 now.

With all that real estate, I wanted some way to manage windows so they could be tiled effectively on one monitor (which is basically how I use two monitors; one app on one screen and another on the other screen). I’ve talked before about using wmctrl to script windows so I dusted off my shell programming skills and wrote “place”.It assumes your monitors are sitting next to each other (not stacked).

Place chops your screen up into 8 zones:

ABCD
EFGH

So your left screen is ABEF and your right screen is CDGH. You can also use 1 for the left screen and 2 for the right screen

How to use it: Run the script (hint: assign it a global shortcut key). It will prompt you to press OK and then click on a window. Click on the window you want to adjust, and the script  will prompt you to enter the grid letters. Enter them in order.

So you might enter A to get it at the top left or GH to get a double wide window at the bottom right. Or DH to get a double high window (the acronym is coincidental).If you enter CDGH or 2 the app will jump to the 2nd screen

What you need:

Stuff you can get out of the repos:  Bash (duh), zenity, xwininfo, gawk, and wmctrl. You also need to use a window manager that works with wmctrl (most do). The script picks up the reported size of your screens automatically. This could be a problem if you have two mismatched screens since I know at least TwinView (NVidia) reports a bigger size (so if your screens are 1600×900 and 1600×1024, TwinView reports 3200×1024.

Options (all optional):

-w 10 – Set width trim to 10 (adjusts the width down to account for decor)

-t 40 – Set height trim to 40

-i 0x4942 – Use window ID instead of prompting for window

-n ‘mywin’ – Identify window by title instead of prompting

Note: -n doesn’t work well when 2 windows have same title! Also, use -i -n or nothing but do not use -i and -n together

-x 1600 – Override screen width to 1600

-y 900 – Override screen height to 900

-s ABEF – Use placer string and don’t prompt

-r – Do not raise window

-q – Quiet (do not show intro dialog)

Here’s the script (or download it from .

#!/bin/bash
# Dual Monitor Window placement script -- Williams alw@al-williams.com
# Version Beta 1, November 28 2009 - http://www.hotsolder.com

## This little script chops your screen up into 8 zones:
#  ABCD
#  EFGH
# (Obviously I'm assuming you have two monitors horizontally)
# So your left screen is ABEF and your right screen is CDGH
# You can also use 1 for the left screen and 2 for the right screen
#
# How to use it: Run this script (hint: assign it a global shortcut key)
# It will prompt you to press OK and then click on a window
# Then it will prompt you to enter the grid letters. Enter them in order.
# So you might enter A to get it at the top left or GH to get a double
# wide window at the bottom right. Or DH to get a double high window.
# if you enter CDGH or 2 the app will jump to the 2nd screen
#
# What you need:
# Stuff you can get out of the repos:
# Bash (duh), zenity, xwininfo, gawk, wmctrl
# You also need to use a window manager that works with wmctrl (most do)
#
# The script picks up the reported size of your screens automatically
# This could be a problem if you have two mismatched screens since
#  know at least TwinView (NVidia) reports a bigger size (so if your
#  screens are 1600x900 and 1600x1024, TwinView reports 3200x1024
# So you may want to override
# Also, you will want to trim down the exact values so the window edges
# and all fit. You can adjust WTRIM and HTRIM below or use the options

# Options (all optional)
# -w 10 - Set width trim to 10
# -t 40 - Set height trim to 40
# -i 0x4942 - Use window ID instead of prompting for window
# -n 'mywin' - Identify window by title instead of prompting
# Note: -n doesn't work well when 2 windows have same title!
# Note: Use -i -n or nothing but do not use -i and -n together
# -x 1600 - Override screen width to 1600
# -y 900 - Override screen height to 900
# -s ABEF - Use placer string and don't prompt
# -r - Do not raise window
# -q - Quiet (do not show intro dialog)

# TODO: Custom grid dialog to pick on a 4x2 grid
# I may do this with kdialog and/or pick zenity or kdialog depending on
# which is available

# max width and height trim down (adjust to suit)
WTRIM=40
HTRIM=40
PROMPTCMD=zenity
XWIOPT=
XWIARG=
CELLS=
NORAISE=0

# Max Width and Height
MW=`xwininfo -root | awk ' /^[ \\t]*Width:/ { print $2 }' `
MH=`xwininfo -root | awk ' /^[ \\t]*Height:/ { print $2 }' `

# process options
while getopts hw:t:i:n:qx:y:s:r o
do
	case "$o" in
	r) NORAISE=1 ;;
	w) WTRIM="$OPTARG" ;;
	t) HTRIM="$OPTARG" ;;
	i) XWIOPT="-i" ; XWIARG="$OPTARG"  ;;
	n) XWIOPT="-name" ; XWIARG="$OPTARG" ;;
	x) MW="$OPTARG" ;;
	y) MH="$OPTARG" ;;
	s) CELLS="$OPTARG" ;;
	q) PROMPTCMD=false ;;
	[?]|h) echo "Usage $0 [-x screen_width] [-y screen_height] [-w width_trim] [-h height_trim] [-i window_id] [-n window_name] -q" 1>&2
	exit 1 ;;
    esac
done

# Calculate Trimmed sizes
MWT=`expr $MW - $WTRIM`
MHT=`expr $MH - $HTRIM`

# Calculate 1 cell width and height and their trimmed versions
W1=`expr $MW / 4`
H1=`expr $MH / 2`
W1T=`expr $MWT / 4`
H1T=`expr $MHT / 2`

# prompt user so as not to confuse
if [ "$XWIOPT" == "" ]
then $PROMPTCMD --info --text 'Press OK and then select a window' --title 'Window Placer'
fi

# find out ID of window selected
if [ "$XWIOPT" != "" ]
then WID=`xwininfo $XWIOPT "$XWIARG" | awk '/xwininfo: Window id:/ { print $4 } ' `
else WID=`xwininfo | awk '/xwininfo: Window id:/ { print $4 } ' `
fi
if [ "$WID" == "" ]
then
	echo  "Unknown window" 1>&2
	exit 2
fi

# get position requested
if [ "$CELLS" == "" ]
then CELLS=`zenity --title 'Window Placer' --entry --text 'Your screens are divided into a 4x2 grid.
The top 4 cells are ABCD and the
bottom cells are EFGH. Or pick a screen (1 or 2).
Pick which cells you wouldd like for this window to occupy.

ABCD    -or-   12
EFGH' `
  if [ $? -ne 0 ]
  then
    echo Cancelled
    exit 3
  fi
fi

# Do the processing
case $CELLS in
[aA])
	X=0
	Y=0
	W=$W1T
	H=$H1T
;;
[bB])
	X=$W1
	Y=0
	W=$W1T
	H=$H1T
;;

[cC])
	X=`expr 2 \* $W1`
	Y=0
	W=$W1T
	H=$H1T

;;
[dD])
	X=`expr 3 \* $W1`
	Y=0
	W=$W1T
	H=$H1T

;;
[eE])
	X=0
	Y=$H1
	W=$W1T
	H=$H1T
;;
[fF])
	X=$W1
	Y=$H1
	W=$W1T
	H=$H1T
;;

[gG])
	X=`expr 2 \* $W1`
	Y=$H1
	W=$W1T
	H=$H1T

;;
[hH])
	X=`expr 3 \* $W1`
	Y=$H1
	W=$W1T
	H=$H1T

;;

[aA][bB])
	X=0
	Y=0
	W=`expr 2 \* $W1T`
	H=$H1T
;;

[bB][cC])
	X=$W1
	Y=0
	W=`expr 2 \* $W1T`
	H=$H1T
;;
[cC][dD])
	X=`expr 2 \* $W1`
	Y=0
	W=`expr 2 \* $W1T`
	H=$H1T
;;
[eE][fF])
	X=0
	Y=$H1
	W=`expr 2 \* $W1T`
	H=$H1T
;;

[fF][gG])
	X=$W1
	Y=$H1
	W=`expr 2 \* $W1T`
	H=$H1T
;;
[gG][hH])
	X=`expr 2 \* $W1`
	Y=$H1
	W=`expr 2 \* $W1T`
	H=$H1T
;;
[aA][bB][cC])
	X=0
	Y=0
	W=`expr 3 \* $W1T`
	H=$H1T
;;

[bB][cC][dD])
	X=$W1
	Y=0
	W=`expr 3 \* $W1T`
	H=$H1T
;;
[eE][fF][gG])
	X=0
	Y=$H1
	W=`expr 3 \* $W1T`
	H=$H1T

;;

[fF][gG][hH])
	X=$W1
	Y=$H1
	W=`expr 3 \* $W1T`
	H=$H1T
;;
[aA][bB][cC][dD])
	X=0
	Y=0
	W=$MWT
	H=$H1T
;;
[eE][fF][gG][hH])
	X=0
	Y=$H1
	W=$MWT
	H=$H1T
;;

[aA][eE])
	X=0
	Y=0
	W=$W1T
	H=$MHT
;;
[bB][fF])
	X=$W1
	Y=0
	W=$W1T
	H=$MHT
;;
[cC][gG])
	X=`expr 2 \* $W1`
	Y=0
	W=$W1T
	H=$MHT
;;
[dD][hH])
	X=`expr 3 \* $W1`
	Y=0
	W=$W1T
	H=$MHT
;;

[aA][bB][eE][fF]|1)
	X=0
	Y=0
	W=`expr 2 \* $W1T`
	H=$MHT
;;
[bB][cC][fF][gG])
	X=$W1
	Y=0
	W=`expr 2 \* $W1T`
	H=$MHT
;;
[cC][dD][gG][hH]|2)

	X=`expr 2 \* $W1`
	Y=0
	W=`expr 2 \* $W1T`
	H=$MHT
;;

*)
	zenity  --title 'Window Placer' --error --text 'Unknown position command'
	exit 5
;;  

esac

if [ $NORAISE -eq 0 ]
then wmctrl -i -R $WID
fi
wmctrl -i -r $WID -e 0,$X,$Y,$W,$H
exit $?

One thought on “Linux Multimonitor Madness

Leave a Reply