]> oss.titaniummirror.com Git - dispcfg.git/commitdiff
Initial commit
authorR. Steve McKown <rsmckown@gmail.com>
Fri, 23 Jan 2015 07:38:17 +0000 (00:38 -0700)
committerR. Steve McKown <rsmckown@gmail.com>
Fri, 23 Jan 2015 07:38:17 +0000 (00:38 -0700)
xrandr_configure_outputs.py [new file with mode: 0644]

diff --git a/xrandr_configure_outputs.py b/xrandr_configure_outputs.py
new file mode 100644 (file)
index 0000000..fcd67f1
--- /dev/null
@@ -0,0 +1,216 @@
+#!/usr/bin/python
+"""
+Parse xrandr current information
+
+TODO:
+* Cannot seem to undock notebook then recover displays without causing a logout
+  event.  Could it be that i3 is finding there are no displays?
+"""
+
+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}
+        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 not self.enabled:
+                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
+
+
+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 print_outputs(header, outputs):
+        print '%s:' % header
+        for output in outputs:
+            print_output(output)
+        print
+
+    def main(argv):
+        global dry_run
+        if len(argv) >= 2 and argv[1] == '--dry-run':
+            dry_run = True
+
+        outputs = parse()
+        #outputs[1]['connected'] = False
+        #outputs[2]['connected'] = False
+        print_outputs('Raw outputs', outputs)
+
+        preferred_order = list(reversed([output['name'] for output in outputs]))
+        print 'preferred order:', preferred_order
+        print
+
+        tmp = outputs
+        outputs = []
+        for name in preferred_order:
+            output = output_by_name(tmp, name)
+            if output:
+                outputs.append(output)
+        print_outputs('Sorted outputs', outputs)
+
+        connected_outputs = [output for output in outputs if output['connected']]
+        print_outputs('Connected outputs', connected_outputs)
+
+        enabled_outputs = [output for output in outputs if output['enabled']]
+        print_outputs('Enabled outputs', enabled_outputs)
+
+        # The outputs to use will be a subset of connected outputs
+        touse_outputs = connected_outputs
+
+        # If there are more then 2 connected outputs, start removing them by
+        # order of desirability.  The LCD panel is least desirable under the
+        # assumption that having more than two means the LCD panel shouldn't be
+        # used.
+        while len(touse_outputs) > 2:
+            print 'trim', touse_outputs[-1]['name']
+            touse_outputs = touse_outputs[:-1]
+        print_outputs('To use outputs', touse_outputs)
+
+        if touse_outputs == enabled_outputs:
+            # If the touse_outputs list is the same as the enabled_outputs
+            # list, then presumably there is no change made
+            print 'Identical'
+        else:
+            # Determine which outputs to turn off, and which to turn on
+            off_outputs = [output for output in enabled_outputs if output not in
+                    touse_outputs]
+            print_outputs('Turn these off', off_outputs)
+            on_outputs = [output for output in touse_outputs if output not in
+                    enabled_outputs]
+            print_outputs('Turn these on', on_outputs)
+
+            if len(enabled_outputs) < 1 or len(enabled_outputs) > 2 or \
+                    len(touse_outputs) < 1 or len(touse_outputs) > 2:
+                print 'Something is wrong; doing nothing'
+                return
+
+            # Compute positions for final outputs
+            posx = 0
+            for output in touse_outputs:
+                output['posx'] = posx
+                output['posy'] = 0
+                posx += output['width']
+            print_outputs('touse, with positions', touse_outputs)
+
+            # Remove all enabled outputs save one
+            while len(enabled_outputs) > 1:
+                output = enabled_outputs[0]
+                enabled_outputs = enabled_outputs[1:]
+                xrandr_off(output)
+
+            # Move the remaining output to a safe position
+            last_old_output = enabled_outputs[0]
+            tmp = last_old_output['posx']
+            last_old_output['posx'] = posx # from above
+            xrandr_on(last_old_output)
+            last_old_output['posx'] = tmp
+
+            # Add the first touse output
+            first_new_output = touse_outputs[0]
+            touse_outputs = touse_outputs[1:]
+            xrandr_on(first_new_output)
+
+            # If last old is not to be used, remove it
+            if not output_by_name(touse_outputs, last_old_output['name']):
+                xrandr_off(last_old_output)
+
+            # Now add the remaining touse outputs
+            for output in touse_outputs:
+                xrandr_on(output)
+
+
+    main(sys.argv)