Skip to content

Instantly share code, notes, and snippets.

@stettberger
Created October 26, 2012 08:34
Show Gist options
  • Save stettberger/3957643 to your computer and use it in GitHub Desktop.
Save stettberger/3957643 to your computer and use it in GitHub Desktop.
Monitor configuration script for using with herbstluftwm
#!/usr/bin/python
import optparse
import os
from subprocess import *
import pipes
import sys
def quote_args(args):
if len(args) == 1 and type(args[0]) == dict:
ret = {}
for k,v in args[0].items():
ret[k] = pipes.quote(v)
return ret
elif type(args) == list or type(args) == tuple:
args = tuple([pipes.quote(x) for x in args])
else:
assert False
return args
def shell(command, *args):
os.environ["LC_ALL"] = "C"
args = quote_args(args)
command = command % args
p = Popen(command, stdout=PIPE, stderr=STDOUT, shell=True)
(stdout, _) = p.communicate() # ignore stderr
p.wait()
if len(stdout) > 0 and stdout[-1] == '\n':
stdout = stdout[:-1]
return (stdout.__str__().rsplit('\n'), p.returncode)
def get_monitors(only_names = False):
(xrandr, ret) = shell("xrandr")
if ret != 0:
print "`xrandr' failed"
sys.exit(-1)
monitor = None
monitors = []
screen = None
for line in xrandr:
if line.startswith("Screen "):
screen = line.split(" ")[1][:-1]
if monitor != None:
monitors.append(monitor)
screen = int(screen)
elif not line[0] in (" ", "\t"):
if monitor != None:
monitors.append(monitor)
monitor = dict([("screen", screen)])
if "disconnected" in line:
monitor = None
continue
monitor["name"] = line.split(" ")[0]
monitor["available-res"] = []
if only_names:
continue
monitor["current-config"] = line.split(" ")[2]
monitor["current-res"] = monitor["current-config"].split("+")[0]
(w, h) = parse_resolution(monitor["current-res"])
monitor["pixel-count"] = w * h
elif monitor:
monitor["available-res"].append(line.strip().split(" ")[0])
if monitor != None:
monitors.append(monitor)
return monitors
def parse_resolution(res):
pixels = res.split("x")
assert(len(pixels) == 2)
return (int(pixels[0]), int(pixels[1]))
if __name__ == "__main__":
parser = optparse.OptionParser()
parser.add_option("--monitors-left-to-right", dest="monitor_list",
default = "VGA1",
help="comma seperated list of monitors (left-to-right)")
parser.add_option("", "--big-monitors-left",
action="store_true", dest="big_monitor_left", default=False)
parser.add_option("", "--big-monitors-right",
action="store_true", dest="big_monitor_right", default=False)
parser.add_option("", "--monitor-split-threshold",
type=int, dest="split_threshold", default=1600,
help="Split big monitors into different screens")
parser.add_option("", "--pad-all",
type=int, dest="pad_all", default=None,
help="Pad all monitors")
(options, args) = parser.parse_args()
monitors = get_monitors(only_names = True)
# Use for all monitors XRandR auto-configuration
for monitor in monitors:
(_, ret) = shell("xrandr --output %s --auto", monitor["name"])
assert(ret == 0)
monitors = get_monitors()
monitor_list = options.monitor_list.split(",")
if options.big_monitor_left:
monitors = list(reversed(sorted(monitors, key=lambda x: x['pixel-count'])))
elif options.big_monitor_right:
monitors = list(sorted(monitors, key=lambda x: x['pixel-count']))
else:
m = []
for i in monitor_list:
for x in monitors:
if x['name'] == i:
m.append(x)
assert(len(m) == len(monitors))
monitors = m
# Place Monitors
for i in range(0, len(monitors)-1):
left = monitors[i]["name"]
right = monitors[i+1]["name"]
shell("xrandr --output %s --left-of %s", left, right)
current_x_offset = 0
vmonitors = []
for monitor in monitors:
(w,height) = parse_resolution(monitor["current-res"])
if w > options.split_threshold:
vmons = (w + 1) / options.split_threshold + 1
width = w / vmons
while w > 0:
vmon_width = width
if vmon_width > w:
vmon_width = w
vmonitors.append((vmon_width, height, current_x_offset, 0))
current_x_offset += vmon_width
w -= vmon_width
else:
vmonitors.append((w, height, current_x_offset, 0))
current_x_offset += w
old_vmon_count = len(shell("herbstclient list_monitors")[0])
shell("herbstclient lock")
for i in range(0, len(vmonitors)):
config = vmonitors[i]
if i >= old_vmon_count:
shell("herbstclient add_monitor %dx%d+%d+%d" % config)
else:
shell("herbstclient move_monitor %%s %dx%d+%d+%d" % config, str(i))
if options.pad_all != None:
shell("herbstclient pad %s %s", str(i), str(options.pad_all))
for i in reversed(range(len(vmonitors), old_vmon_count)):
shell("herbstclient remove_monitor %d" % i)
shell("herbstclient unlock")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment