aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--xorg-server/Makefile6
-rwxr-xr-xxorg-server/setkeys154
-rw-r--r--xorg-xrandr/Makefile7
-rw-r--r--xorg-xrandr/setres/Makefile17
-rwxr-xr-xxorg-xrandr/setres/__main__.py225
-rw-r--r--xorg-xrandr/setres/get.py248
-rw-r--r--xorg-xrandr/setres/set.py68
7 files changed, 725 insertions, 0 deletions
diff --git a/xorg-server/Makefile b/xorg-server/Makefile
index 81bc9d8..29edef7 100644
--- a/xorg-server/Makefile
+++ b/xorg-server/Makefile
@@ -12,9 +12,15 @@ install:
if test ! -L ~/.config/background && test ! -e ~/.config/background; then \
ln -s backgrounds/default ~/.config/background; \
fi
+ $(CHECK_INSTALLED) asroot
+ $(CHECK_INSTALLED) xorg-setxkbmap
+ $(CHECK_INSTALLED) xorg-xmodmap
+ mkdir -p -- ~/.local/bin
+ ln -sf -- ~/.dotfiles/xorg-server/setkeys ~/.local/bin/
uninstall:
-unlink -- ~/.config/backgrounds
-unlink -- ~/.config/background
+ -unlink -- ~/.local/bin/setkeys
.PHONY: install uninstall
diff --git a/xorg-server/setkeys b/xorg-server/setkeys
new file mode 100755
index 0000000..5837607
--- /dev/null
+++ b/xorg-server/setkeys
@@ -0,0 +1,154 @@
+#!/bin/dash
+
+load_layout () {
+ if test -f "${XDG_RUNTIME_DIR}/.setkeys_layout"; then
+ cat "${XDG_RUNTIME_DIR}/.setkeys_layout"
+ fi
+}
+
+save_layout () {
+ printf '%s\n' "$1" > "${XDG_RUNTIME_DIR}/.setkeys_layout"
+}
+
+if test "$1" = "greek"; then
+ layout=gr
+elif test "$1" = "swedish"; then
+ layout=se
+elif test "$1" = "english"; then
+ layout=en_US
+elif test "$1" = "toggle"; then
+ layout="$(load_layout)"
+ if test "$layout" = se; then
+ layout=gr
+ else
+ layout=se
+ fi
+elif test $# = 0; then
+ layout="$(load_layout)"
+else
+ layout="$1"
+fi
+if test -z "$layout"; then
+ layout=se
+fi
+save_layout "$layout"
+
+setxkbmap \
+ -rules evdev \
+ -model pc105 \
+ -layout "$layout" \
+ -variant '' \
+ -option '' \
+ -option terminate:ctrl_alt_bksp,compose:rwin,keypad:future \
+ -types complete \
+ -compat complete \
+ -synch
+
+{
+ # Assign LeftCtrl to CapsLock
+ printf '%s\n' 'keycode 66 = Control_L Control_L Control_L Control_L'
+
+ # Assign LeftHyper to LeftCtrl
+ printf '%s\n' 'keycode 37 = Hyper_L Hyper_L Hyper_L Hyper_L'
+
+ # Assign remove layout switch from LeftShift
+ printf '%s\n' 'keycode 50 = Shift_L Shift_L Shift_L Shift_L'
+
+ if test -z "${NO_UNICOMP}"; then
+ # Unicomp's newer versions of New Model M swapped AltGr and RSuper
+ # making it a torture device for even someone with as big hands as mine
+ if cat /sys/class/input/*/name | grep Unicomp > /dev/null; then
+ # Assign Compose to AltGr
+ printf '%s\n' 'keycode 108 = Multi_key Multi_key Multi_key Multi_key'
+
+ # Assign AltGr to RightSuper
+ printf '%s\n' 'keycode 134 = ISO_Level3_Shift ISO_Level3_Shift ISO_Level3_Shift ISO_Level3_Shift'
+ fi
+ fi
+
+ cat <<EOF
+clear Shift
+clear Lock
+clear Control
+clear mod1
+clear Mod2
+clear Mod3
+clear Mod4
+clear Mod5
+add Shift = Shift_L Shift_R
+add Control = Control_L Control_R
+add Mod1 = Alt_L Meta_L
+add Mod2 = Num_Lock
+add Mod3 = Hyper_L
+add Mod4 = Super_L
+add Mod5 = ISO_Level3_Shift
+EOF
+} | xmodmap -
+
+if cat /sys/class/input/*/name | grep Unicomp > /dev/null; then
+ # Turn off numlock LED
+ input="$(grep Unicomp /sys/class/input/*/name | sed 's|^/sys/class/input/\(.*\)/name:.*$|\1|g' | sed 1q)"
+ if ! echo 0 | sponge "/sys/class/leds/${input}::numlock/brightness" 2>/dev/null; then
+ if isfg; then
+ # TODO do at boot
+ asroot chown ${USER}:${USER} "/sys/class/leds/${input}::numlock/brightness"
+ echo 0 | sponge "/sys/class/leds/${input}::numlock/brightness"
+ fi
+ fi
+fi
+
+# Esc = 9
+# F1…F10 = 67…76
+# F11…F12 = 95…96
+# § = 49
+# 1…9 = 10…18
+# 0+´ = 19…21
+# Backspace = 22
+# Tab = 23
+# qwertyuiopå¨ = 24…35
+# Enter = 36
+# CapsLock = 66
+# asdfghjklöä = 38…48
+# ' = 51
+# LeftShift = 50
+# < = 94
+# zxcvbnm,.- = 52…61
+# RightShift = 62
+# LeftCtrl = 37
+# LeftSuper = 133
+# Alt = 64
+# Space = 65
+# AltGr = 108
+# RightSuper = 134
+# Menu = 135
+# RightCtrl = 105
+# SysReq = 107
+# ScrlLock = 78
+# Break = 127
+# Insert = 118
+# Home = 110
+# PageUp = 112
+# Delete = 119
+# End = 115
+# PageDown = 117
+# Up = 111
+# Left = 113
+# Down = 116
+# Right = 114
+# NumLock = 77
+# Num/ = 106
+# Num* = 63
+# Num- = 82
+# Num7 = 79
+# Num8 = 80
+# Num9 = 81
+# Num+ = 86
+# Num4 = 83
+# Num5 = 84
+# Num6 = 85
+# Num1 = 87
+# Num2 = 88
+# Num3 = 89
+# NumEnter = 104
+# Num0 = 90
+# Num, = 91
diff --git a/xorg-xrandr/Makefile b/xorg-xrandr/Makefile
index b35df78..d135e27 100644
--- a/xorg-xrandr/Makefile
+++ b/xorg-xrandr/Makefile
@@ -4,16 +4,23 @@ include ../common.mk
XINITRC_ORDER = 15
# Testing that xwallpaper is installed because setres calls it
+# Testing that python3 is installed because setres is written in it
install:
$(CHECK_INSTALLED) xwallpaper
+ $(CHECK_INSTALLED) python3
mkdir -p -- ~/.config/X11/xinit/xinitrc.d
test ! -d ~/.config/X11/xinit/xinitrc.d/$(XINITRC_ORDER)-xorg-xrandr
ln -sf -- ~/.dotfiles/xorg-xrandr/xinit ~/.config/X11/xinit/xinitrc.d/$(XINITRC_ORDER)-xorg-xrandr
+ mkdir -p -- ~/.local/bin
+ make -C setres
+ ln -sf -- ~/.dotfiles/xorg-xrandr/setres/setres ~/.local/bin
uninstall:
-unlink -- ~/.config/X11/xinit/xinitrc.d/$(XINITRC_ORDER)-xorg-xrandr
-rmdir -- ~/.config/X11/xinit/xinitrc.d
-rmdir -- ~/.config/X11/xinit
-rmdir -- ~/.config/X11
+ -rmdir -- ~/.local/bin/setres
+ -make -C setres reallyclean
.PHONY: install uninstall
diff --git a/xorg-xrandr/setres/Makefile b/xorg-xrandr/setres/Makefile
new file mode 100644
index 0000000..770d45d
--- /dev/null
+++ b/xorg-xrandr/setres/Makefile
@@ -0,0 +1,17 @@
+all: setres
+
+setres.zip: __main__.py get.py set.py
+ zip $@ $^
+
+setres: setres.zip
+ echo '#!/usr/bin/python3' > $@
+ cat setres.zip >> $@
+ chmod a+x $@
+
+clean:
+ -rm -r *.zip *.pyc __pycache__/ *~
+
+reallyclean: clean
+ -rm setres
+
+.PHONY: all clean reallyclean
diff --git a/xorg-xrandr/setres/__main__.py b/xorg-xrandr/setres/__main__.py
new file mode 100755
index 0000000..26f6f65
--- /dev/null
+++ b/xorg-xrandr/setres/__main__.py
@@ -0,0 +1,225 @@
+#!/usr/bin/env python3
+
+import sys, os, pwd
+from subprocess import Popen, PIPE
+
+from get import *
+from set import *
+
+args = sys.argv[1:]
+home = os.environ['HOME'] if 'HOME' in os.environ else pwd.getpwuid(os.getuid()).pw_dir
+session_ = os.environ['SESSION_'] if 'SESSION_' in os.environ else ''
+hostname = os.uname().nodename.lower()
+
+t = lambda lopt, sopt : any(arg in args for arg in (lopt, '-' + lopt, '--' + lopt, sopt, '-' + sopt))
+
+mirror = t('mirror', 'm')
+swap = t('swap', 's')
+tv = t('tv', 't')
+wide = t('wide', 'w')
+crt = t('crt', 'c')
+large = t('large', 'l')
+single = t('single', '1')
+pretend = t('pretend', 'P')
+
+[screen] = get_setup()
+ok = False
+
+if pretend:
+ def apply_setup(display):
+ print(repr(display.to_xrandr()))
+ return True
+
+
+
+### Configurations
+
+
+if hostname == 'zenith':
+ prime = screen['DisplayPort-2' if not swap else 'DisplayPort-1']
+ sec = screen['DisplayPort-1' if not swap else 'DisplayPort-2']
+ embed = None
+
+ prime_alt = None
+ sec_alt = None
+
+ prime.want_mode = '1920x1200'
+ sec.want_mode = '1920x1200'
+
+
+else:
+ print('%s: no configurations found for this machine' % sys.argv[0], file = sys.stderr)
+ sys.exit(1)
+
+if not prime.connected and prime_alt is not None:
+ prime, prime_alt = prime_alt, prime
+if not sec.connected and sec_alt is not None:
+ sec, sec_alt = sec_alt, sec
+
+
+if large:
+ prime.want_mode = '1792x1344'
+ sec.want_mode = '1792x1344'
+
+if crt:
+ prime.want_mode = '800x600'
+ sec.want_mode = '800x600'
+
+if wide:
+ prime.want_mode = '1920x1080'
+ sec.want_mode = '1920x1080'
+
+if tv:
+ sec.want_mode = '1920x1080'
+
+
+if prime is not None:
+ prime.want_rate = prime.best_rate(prime.want_mode)
+if sec is not None:
+ sec.want_rate = sec.best_rate(sec.want_mode)
+if embed is not None:
+ embed.want_rate = embed.best_rate(embed.want_mode)
+
+
+
+
+if '+prime' in args:
+ prime.connected = True
+if '+sec' in args:
+ sec.connected = True
+if '+embed' in args:
+ embed.connected = True
+
+if '-prime' in args:
+ prime.connected = False
+if '-sec' in args:
+ sec.connected = False
+if '-embed' in args:
+ embed.connected = False
+
+
+
+
+### Apply
+
+if prime.connected and sec.connected and not single:
+ display = Display()
+ ok = True
+
+ output = Output(prime.name)
+ display.outputs.append(output)
+ output.mode = prime.want_mode
+ output.rate = prime.want_rate
+ output.primary = True
+ output.relpos = None
+ output.relto = None
+
+ output = Output(sec.name)
+ display.outputs.append(output)
+ output.mode = sec.want_mode
+ output.rate = sec.want_rate
+ output.primary = False
+ output.relpos = 'left-of' if not mirror else 'same-as'
+ output.relto = prime.name
+
+ if embed is not None:
+ output = Output(embed.name)
+ display.outputs.append(output)
+ output.off = True
+
+
+elif prime.connected:
+ display = Display()
+ ok = True
+
+ output = Output(prime.name)
+ display.outputs.append(output)
+ output.mode = prime.want_mode
+ output.rate = prime.want_rate
+ output.primary = True
+
+ output = Output(sec.name)
+ display.outputs.append(output)
+ output.off = True
+
+ if embed is not None:
+ output = Output(embed.name)
+ display.outputs.append(output)
+ output.off = True
+
+
+elif sec.connected:
+ display = Display()
+ ok = True
+
+ output = Output(sec.name)
+ display.outputs.append(output)
+ output.mode = sec.want_mode
+ output.rate = sec.want_rate
+ output.primary = True
+
+ output = Output(prime.name)
+ display.outputs.append(output)
+ output.off = True
+
+ if embed is not None:
+ output = Output(embed.name)
+ display.outputs.append(output)
+ output.off = True
+
+
+elif embed is None or not embed.connected:
+ print('%s: don\'t know how to configure' % sys.argv[0], file = sys.stderr)
+
+
+else:
+ display = Display()
+ ok = True
+
+ output = Output(embed.name)
+ display.outputs.append(output)
+ output.mode = embed.want_mode
+ output.rate = embed.want_rate
+ output.primary = True
+
+ output = Output(prime.name)
+ display.outputs.append(output)
+ output.off = True
+
+ output = Output(sec.name)
+ display.outputs.append(output)
+ output.off = True
+
+if ok:
+ if prime_alt is not None:
+ output = Output(prime_alt.name)
+ display.outputs.append(output)
+ output.off = True
+
+ if sec_alt is not None:
+ output = Output(sec_alt.name)
+ display.outputs.append(output)
+ output.off = True
+
+ ok = apply_setup(display)
+
+
+
+### Epilogue
+
+if not ok:
+ sys.exit(1)
+if pretend:
+ sys.exit(0)
+
+[screen] = get_setup()
+prime = screen[True]
+if prime.position[0] > 0:
+ print(prime.position[0], flush = True)
+
+for file in ('%s/.config/background.%s' % (home, session_), '%s/.config/background' % home):
+ if os.path.exists(file):
+ try:
+ os.execlp('xwallpaper', 'xwallpaper', '--zoom', file)
+ except:
+ pass
diff --git a/xorg-xrandr/setres/get.py b/xorg-xrandr/setres/get.py
new file mode 100644
index 0000000..47a6428
--- /dev/null
+++ b/xorg-xrandr/setres/get.py
@@ -0,0 +1,248 @@
+class XScreen:
+ def __init__(self, line):
+ self.number = int(line.split(':')[0].split(' ')[1])
+ self.minimum = None
+ self.current = None
+ self.maximum = None
+ self.connectors = []
+ for part in line.split(':')[1][1:].split(', '):
+ words = part.split(' ')
+ if words[0] == 'minimum':
+ self.minimum = (int(words[1]), int(words[3]))
+ elif words[0] == 'current':
+ self.minimum = (int(words[1]), int(words[3]))
+ elif words[0] == 'maximum':
+ self.minimum = (int(words[1]), int(words[3]))
+
+ def __getitem__(self, value):
+ if isinstance(value, str):
+ for connector in self.connectors:
+ if connector.name == value:
+ return connector
+ elif value is True:
+ for connector in self.connectors:
+ if connector.primary:
+ return connector
+ else:
+ return self.connectors[value]
+ return None
+
+
+class XConnector:
+ def __init__(self, line):
+ line = line.split(' ')
+ self.name = line[0]
+ self.connected = line[1] == 'connected'
+ self.primary = False
+ self.size = None
+ self.position = None
+ self.mode = None
+ self.rr = None
+ self.physsize = None
+ self.modes = []
+ self.identifier = None
+ self.timestamp = None
+ self.subpixel = None
+ self.gamma = None
+ self.brightness = None
+ self.clones = None
+ self.crtc = None
+ self.crtcs = None
+ self.transform = None
+ self.filter = None # TODO
+ self.edid = None
+ # TODO BACKLIGHT
+ # TODO Backlight
+ # TODO scaling mode
+ # TODO Broadcast RGB
+ # TODO audio
+
+ if not self.connected:
+ return
+ i = 2
+
+ if i == len(line):
+ return
+ if line[i] == 'primary':
+ self.primary = True
+ i += 1
+
+ if i == len(line):
+ return
+ word = line[i].replace('-', '+-').replace('+--', '+-')
+ if len(word.replace('+', '')) + 2 == len(word) and len(word.replace('x', '')) + 1 == len(word):
+ if word.replace('+', '').replace('x', '').isdigit():
+ i += 1
+ words = word.split('+')
+ self.position = (int(words[1]), int(words[2]))
+ words = words[0].split('x')
+ self.size = (int(words[0]), int(words[1]))
+
+ if i == len(line):
+ return
+ if line[i].startswith('(0x') and line[i].endswith(')'):
+ self.mode = int(line[i][3 : -1], 16)
+ i += 1
+
+ while not line[i].startswith('('):
+ if self.rr is None:
+ self.rr = line[i]
+ else:
+ self.rr += ' ' + line[i]
+ i += 1
+ while not line[i].endswith(')'):
+ i += 1
+ i += 1
+
+ line = [word[:-2] for word in line[i:] if word.endswith('mm')]
+ if len(line) == 2:
+ self.physsize = (int(line[0]), int(line[1]))
+
+ def __getitem__(self, name):
+ for mode in self.modes:
+ if mode.name == name:
+ return mode
+ return None
+
+ def best_rate(self, mode):
+ best = None
+ if isinstance(mode, str):
+ mode = tuple(int(x) for x in mode.split('x'))
+ for m in self.modes:
+ if m.size == mode:
+ cand = m.vclock
+ if cand is None:
+ continue
+ if best is None or float(cand) > float(best):
+ best = cand
+ return best
+
+
+class XMode:
+ def __init__(self, line):
+ line = line.split(' ')
+ [w, h] = line[0].split('x')
+ self.size = (int(w), int(h))
+ self.name = int(line[1][3 : -1], 16)
+ self.tclock = line[2][:-3] # MHz
+ self.hsync = None
+ self.vsync = None
+ self.current = False
+ self.preferred = False
+ for word in line[3]:
+ if word.endswith('HSync'):
+ self.hsync = word[0]
+ elif word.endswith('VSync'):
+ self.vsync = word[0]
+ elif word == '*current':
+ self.current = True
+ elif word == '+preferred':
+ self.preferred = True
+
+ def set_h(self, line):
+ line = line.split(' ')
+ self.width = int(line[2])
+ self.hstart = int(line[4])
+ self.hend = int(line[6])
+ self.htotal = int(line[8])
+ self.hskew = int(line[10])
+ self.hclock = line[12][:-3] # KHz
+
+ def set_v(self, line):
+ line = line.split(' ')
+ self.height = int(line[2])
+ self.vstart = int(line[4])
+ self.vend = int(line[6])
+ self.vtotal = int(line[8])
+ self.vclock = line[10][:-2] # Hz
+
+
+def get_setup():
+ from subprocess import Popen, PIPE
+
+ def is_screen_line(line):
+ if ':' not in line:
+ return False
+ line = line.split(':')[0].split(' ')
+ if len(line) != 2:
+ return False
+ return line[0] == 'Screen' and line[1].isdigit()
+
+ def is_connector_line(line):
+ return ' ' in line and line.split(' ')[1] in ('connected', 'disconnected')
+
+ def is_mode_line(line):
+ words = line.split(' ')
+ if len(words) < 2:
+ return False
+ if len(words[0]) - 1 != len(words[0].replace('x', '')):
+ return False
+ if not words[0].replace('x', '').isdigit():
+ return False
+ if words[0][0] == 'x' or words[0][-1] == 'x':
+ return False
+ if not words[1].startswith('(0x'):
+ return False
+ return words[1].endswith(')')
+
+ screens = []
+ screen = None
+ connector = None
+ mode = None
+ transx = None
+ on_edid = False
+
+ xrandr_output = Popen('env LANG=C xrandr --verbose'.split(' '), stdout = PIPE)
+ xrandr_output = xrandr_output.communicate()[0].decode('utf-8', 'strict').split('\n')
+
+ for line in xrandr_output:
+ if on_edid and line.startswith('\t\t') and ':' not in line:
+ connector.edid += line.replace(' ', '')
+ on_edid = None
+ elif transx is not None:
+ transx.append(line.strip())
+ if len(transx) == 3:
+ connector.transform = tuple(tuple(float(x) for x in r.split(' ')) for r in transx)
+ transx = None
+ elif is_screen_line(line):
+ screen = XScreen(line)
+ screens.append(screen)
+ elif is_connector_line(line):
+ connector = XConnector(line)
+ screen.connectors.append(connector)
+ else:
+ line = line.replace('\t', ' ').strip()
+ while ' ' in line:
+ line = line.replace(' ', ' ')
+ words = line.split(' ')
+ if is_mode_line(line):
+ mode = XMode(line)
+ connector.modes.append(mode)
+ elif line.startswith('h: '):
+ mode.set_h(line)
+ elif line.startswith('v: '):
+ mode.set_v(line)
+ elif line.startswith('Identifier:'):
+ connector.identifier = int(words[1][2:], 16)
+ elif line.startswith('Timestamp:'):
+ connector.timestamp = int(words[1])
+ elif line.startswith('Subpixel:'):
+ connector.subpixel = ' '.join(words[1:])
+ elif line.startswith('Gamma:'):
+ connector.gamma = tuple(float(x) for x in words[1].split(':'))
+ elif line.startswith('Brightness:'):
+ connector.brightness = float(words[1])
+ elif line.startswith('Clones:'):
+ connector.clones = words[1:]
+ elif line.startswith('CRTCs:'):
+ connector.crtc = int(words[1])
+ elif line.startswith('CRTCs:'):
+ connector.crtcs = tuple(int(x) for x in words[1:])
+ elif line.startswith('Transform:'):
+ transx = [' '.join(words[1:])]
+ elif line.startswith('EDID:'):
+ connector.edid = ''.join(words[1:])
+ on_edid = None
+ on_edid = on_edid is None
+
+ return screens
diff --git a/xorg-xrandr/setres/set.py b/xorg-xrandr/setres/set.py
new file mode 100644
index 0000000..27533bc
--- /dev/null
+++ b/xorg-xrandr/setres/set.py
@@ -0,0 +1,68 @@
+class Display:
+ def __init__(self, display = None, deepclone = False):
+ self.outputs = []
+ self.fb = None
+ self.fbmm = None ## TODO automatically
+ self.dpi = None ## TODO automatically
+ if display is not None:
+ self.outputs = [Output(output) if deepclone else output for output in display.outputs]
+ self.fb = display.fb
+ self.fbmm = display.fbmm
+ self.dpi = display.dpi
+
+ def to_xrandr(self):
+ ret = ['xrandr']
+ if self.fb is not None: ret += ['--fb', self.mode]
+ if self.fbmm is not None: ret += ['--fbmm', self.pos]
+ if self.dpi is not None: ret += ['--dpi', self.rate]
+ for output in self.outputs:
+ ret += output.to_xrandr()
+ return ret
+
+
+class Output:
+ def __init__(self, output):
+ isnew = not isinstance(output, Output)
+ self.output = output if isnew else output.output
+ self.mode = None if isnew else output.mode
+ self.pos = None if isnew else output.pos
+ self.rate = None if isnew else output.rate
+ self.reflect = None if isnew else output.reflect
+ self.rotate = None if isnew else output.rotate
+ self.off = False if isnew else output.off
+ self.crtc = None if isnew else output.crtc
+ self.gamma = None if isnew else output.gamma
+ self.brightness = None if isnew else output.brightness
+ self.panning = None if isnew else output.panning
+ self.transform = None if isnew else output.transform
+ self.scale = None if isnew else output.scale
+ self.scale_from = None if isnew else output.scale_from
+ self.relpos = None if isnew else output.relpos
+ self.relto = None if isnew else output.relto
+ self.primary = False if isnew else output.primary
+
+ def to_xrandr(self):
+ ret = ['--output', self.output]
+ if self.mode is not None: ret += ['--mode', self.mode]
+ if self.pos is not None: ret += ['--pos', self.pos]
+ if self.rate is not None: ret += ['--rate', self.rate]
+ if self.reflect is not None: ret += ['--reflect', self.reflect]
+ if self.rotate is not None: ret += ['--rotate', self.rate]
+ if self.crtc is not None: ret += ['--crtc', self.crtc]
+ if self.gamma is not None: ret += ['--gamma', self.gamma]
+ if self.brightness is not None: ret += ['--brightness', self.brightness]
+ if self.panning is not None: ret += ['--panning', self.panning]
+ if self.transform is not None: ret += ['--transform', self.transform]
+ if self.scale is not None: ret += ['--scale', self.scale]
+ if self.scale_from is not None: ret += ['--scale-from', self.scale_from]
+ if self.primary: ret += ['--primary']
+ if self.relpos is not None and self.relto is not None:
+ ret += ['--' + self.relpos, self.relto]
+ return ret if not self.off else ['--output', self.output, '--off']
+
+
+def apply_setup(display):
+ import sys
+ from subprocess import Popen
+ p = Popen(display.to_xrandr(), stdin = sys.stdin, stdout = sys.stdout, stderr = sys.stderr)
+ return p.wait() == 0