Created
November 21, 2018 01:16
-
-
Save elfsternberg/aedb823462514353c89d08220c6bef86 to your computer and use it in GitHub Desktop.
Dual-Monitor Setup For A Modern Laptop and An Old Desktop Monitor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# This is the current script I use to configure my laptop and my old | |
# desktop monitor. My old monitor is an Acer H243, released in 2009, | |
# maximum resolution 1920x1200. The laptop is crazy modern huge, | |
# 3840x2160. This script picks out the identities of the monitors in | |
# xrandr, and their maximal resolutions, and then rescales the content | |
# so that the two monitors are displaying their best output. | |
# This code makes a lot of assumptions. It assumes that your external | |
# monitor is OLD; it's maximal resolution is less than the laptop | |
# monitor, but that it's more than half the maximal resolution of the | |
# laptop monitor. It also assumes you want the external monitor | |
# *above* the laptop monitor. The assumptions hold true for my | |
# set-up. | |
import os | |
import re | |
import sys | |
import subprocess | |
from collections import namedtuple | |
Monitor = namedtuple('Monitor', ['name', 'width', 'height']) | |
Details = namedtuple('Details', ['buffer_width', 'buffer_height', 'monitors']) | |
# This is very fragile, and probably not very smart. When it | |
# encounters a connected monitor, it then scans for the current | |
# resolution and keeps it. | |
# TODO: Use the maximal resolution, not the current. | |
def get_details(): | |
lines = subprocess.check_output(['xrandr', '--current']).splitlines() | |
res = [] | |
mon = None | |
mat = None | |
for line in lines: | |
pmon = re.search(r'maximum (\d+) x (\d+)', line) | |
if pmon and not mon: | |
mon = (int(pmon.group(1), 10), int(pmon.group(2), 10)) | |
continue | |
if line.find(r' connected') != -1: | |
mat = line.split(' ')[0] | |
continue | |
if mat and re.search(r'\d+\.\d+\*', line): | |
g = re.search(r'(\d+)+x(\d+)', line) | |
if g: | |
res.append(Monitor(mat, int(g.group(1), 10), int(g.group(2), 10))) | |
mat = None | |
return Details(mon[0], mon[1], res) | |
details = get_details() | |
if len(details.monitors) > 2: | |
print("Can't handle more than two monitors") | |
# A fallback, in case things go sideways. | |
if len(details.monitors) == 1: | |
os.system('xrandr -s 0') | |
sys.exit() | |
smaller = sorted(details.monitors, key=lambda x: x.height)[0] | |
larger = sorted(details.monitors, key=lambda x: x.height)[1] | |
# This is also fragile. The assumption is that the laptop monitor's | |
# width is smaller than twice the larger monitor's. If this | |
# assumption is false, I have no idea what will happen. | |
# If case this is true, though, the frame buffer has to be twice the smaller | |
# monitor plus the larger. | |
fb_height = smaller.height * 2 + larger.height | |
if fb_height > details.buffer_height: | |
print("The requested frame buffer size is greater than the available memory.") | |
sys.exit() | |
# For the old monitor with the smaller resolution, we're doubling the | |
# scaling (which actually *halves* the scaling), setting the | |
# resolution to the maximal relationship we can establish, and build | |
# the new framebuffer to the new height for *both* monitors, one above | |
# the other, and the maximal width which, again, we're assuming is | |
# twice that of the lower resolution monitors. | |
os.system('xrandr --output {} --scale 2x2 --mode {}x{} --fb {}x{} --pos 0x0' | |
.format(smaller.name, smaller.width, smaller.height, | |
smaller.width * 2, fb_height)) | |
# For the laptop monitor, the scale is defaulted. The position's | |
# height is double the lower resolution monitor so it's *just below* | |
# that monitor; the left position of the laptop monitor is centered in | |
# its relationship with the external monitor. | |
os.system('xrandr --output {} --scale 1x1 --pos {}x{}' | |
.format(larger.name, | |
int(((smaller.width * 2) - larger.width) / 2), | |
smaller.height * 2)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment