X-Git-Url: https://oss.titaniummirror.com/gitweb?a=blobdiff_plain;f=configure-displays;fp=configure-displays;h=dac120459922366d8d02846cb0d2bad06672df5d;hb=a9138c7b3c404300706b43741875f3eec7203b09;hp=0000000000000000000000000000000000000000;hpb=8f54067720ffa7f2457ed77ee9a8fc78b3d3611a;p=dispcfg.git diff --git a/configure-displays b/configure-displays new file mode 100755 index 0000000..dac1204 --- /dev/null +++ b/configure-displays @@ -0,0 +1,196 @@ +#!/usr/bin/python +""" +Configure displays by looking at xrandr information + +Select the best 1 or 2 xrandr outputs to use as displays, based on xrandr +information, then reconfigure outputs via xrandr. +""" + +import sys +import subprocess +import re + +dry_run = False + +class OutputInfo(): + def __init__(self): + self.clear() + + def clear(self): + self.name = None + self.connected = False + self.enabled = False + self.width = -1 + self.height = -1 + self.posx = -1 + self.posy = -1 + + def complete(self): + if self.name and (self.connected == False or self.width != -1): + return True + else: + return False + + def asDict(self): + if self.complete(): + return {'name':self.name, 'enabled':self.enabled, + 'connected':self.connected, 'width':self.width, + 'height':self.height, 'posx':self.posx, 'posy':self.posy, + 'use':False, 'done':False} + else: + raise ValueError + + def parse(self, line): + tokens = line.split() + if len(tokens): + if tokens[1] == 'connected' or tokens[1] == 'disconnected': + self.clear() + self.name = tokens[0] + if tokens[1] == 'connected': + self.connected = True + token = 2 + size = [] + while token < len(tokens) and len(size) != 4: + # skip other tokens like 'primary' + size = re.split('[x+]', tokens[token]) + token += 1 + if len(size) == 4: + self.enabled = True + #self.width = int(size[0]) + #self.height = int(size[1]) + #self.posx = int(size[2]) + #self.posy = int(size[3]) + elif self.connected and self.width < 0: + size = re.split('x', tokens[0]) + if len(size) == 2: + self.width = int(size[0]) + self.height = int(size[1]) + + +def parse(): + outputs = [] + output = OutputInfo() + p = subprocess.check_output('xrandr') + for line in p.split('\n'): + output.parse(line) + if output.complete(): + outputs.append(output.asDict()) + output.clear() + return outputs + + +def xrandr_on(output): + command = ['xrandr', '--output', output['name'], '--auto', '--pos', + '%dx0' % output['posx']] + if output['posx'] == 0: + command += ['--primary'] + if not dry_run: + print 'xrandr_on:', command + subprocess.call(command) + else: + print '(dry-run) xrandr_on:', command + + +def xrandr_off(output): + command = ['xrandr', '--output', output['name'], '--off'] + if not dry_run: + subprocess.call(command) + print 'xrandr_off:', command + else: + print '(dry-run) xrandr_off:', command + + +def output_by_name(outputs, name): + for output in outputs: + if output['name'] == name: + return output + return None + + +def print_outputs(header, outputs): + print '%s:' % header + for output in outputs: + print_output(output) + print + + +def all_done(outputs): + for output in outputs: + if not output['done']: + return False + return True + + +def disable_an_entry(outputs): + for output in outputs: + if not output['done'] and not output['use'] and output['enabled']: + xrandr_off(output) + output['done'] = True + return 1 + return 0 + + +def enable_an_entry(outputs, new_enable): + enables = 0 + for output in reversed(outputs): + if not output['done'] and output['use']: + if new_enable or output['connected']: + xrandr_on(output) + output['done'] = True + return 1 + return 0 + + +if __name__ == '__main__': + def print_output(output): + print 'name:%s connected:%r enabled:%r width:%d height:%d pos:%dx%d' % ( + output['name'], output['connected'], output['enabled'], + output['width'], output['height'], output['posx'], + output['posy']) + + def main(argv): + global dry_run + if len(argv) >= 2 and argv[1] == '--dry-run': + dry_run = True + + outputs = parse() + print_outputs('Outputs', outputs) + + # Find the first two connected devices, in reverse list order. On the + # Thinkpad X201, the reversed list order is the preferred order of + # precedence, highest quality external display first, down to internal + # LVDS panel used as a last resort. Also find new posx values. + use_count = 0 + posx = 0 + for output in reversed(outputs): + if output['connected']: + print 'use', output['name'] + output['use'] = True + output['posx'] = posx + posx += output['width'] + use_count += 1 + if use_count >= 2: + break + + # How many outputs are currently enabled? + enabled_count = 0 + for output in outputs: + if output['enabled']: + enabled_count += 1 + + # Mark outputs that receive no change as done + for output in outputs: + if not output['use'] and not output['enabled']: + # Nothing to do for this output, mark as done + output['done'] = True + + while not all_done(outputs): + if enabled_count > 1: + enabled_count -= disable_an_entry(outputs) + enabled_count += enable_an_entry(outputs, enabled_count < 2) + + # A hack to set Control/Win key mapping + subprocess.call('/usr/local/bin/setctrl') + + + main(sys.argv)