Page MenuHomePhabricator

No OneTemporary

diff --git a/monitorDaemon.py b/monitorDaemon.py
--- a/monitorDaemon.py
+++ b/monitorDaemon.py
@@ -1,295 +1,310 @@
#!/usr/bin/env python
import subprocess
import os
import hashlib
import binascii
import re
import sys
import configparser
from Xlib import X, display, Xutil
from Xlib.ext import randr
+# TODO: We could move away from outputs completely
+# and make configuration EDID-based only
+
class xrandrInterface:
def __init__(self):
self.display = display.Display()
self.screen = self.display.screen()
- self.window = self.screen.root.create_window(50, 50, 300, 200, 2,
+ self.window = self.screen.root.create_window(0, 0, 1, 1, 1,
self.screen.root_depth,
event_mask = (X.ExposureMask |
X.StructureNotifyMask |
X.ButtonPressMask |
X.ButtonReleaseMask |
X.Button1MotionMask)
)
#self.window.xrandr_select_input(
# randr.RRScreenChangeNotifyMask
# | randr.RRCrtcChangeNotifyMask
# | randr.RROutputChangeNotifyMask
# | randr.RROutputPropertyNotifyMask
# )
self.outputStatus = {}
self.crtcStatus = {}
self.getScreenInformation()
def getScreenInformation(self):
resources = self.window.xrandr_get_screen_resources()._data
outputs = resources['outputs']
self.outputStatus = {}
self.crtcStatus = {}
for crtc in resources['crtcs']:
crtcinfo = self.display.xrandr_get_crtc_info(crtc, resources['config_timestamp'])._data
self.crtcStatus[crtc] = {}
#self.crtcStatus[crtc]['width'] = crtcinfo['width']
#self.crtcStatus[crtc]['height'] = crtcinfo['height']
self.crtcStatus[crtc]['x'] = crtcinfo['x']
self.crtcStatus[crtc]['y'] = crtcinfo['y']
self.crtcStatus[crtc]['mode'] = crtcinfo['mode']
self.crtcStatus[crtc]['outputs'] = crtcinfo['outputs']
self.crtcStatus[crtc]['possible_outputs'] = crtcinfo['possible_outputs']
modedata = self.parseModes(resources['mode_names'], resources['modes'])
#print(self.crtcStatus)
for output in outputs:
info = self.display.xrandr_get_output_info(output, resources['config_timestamp'])._data
#print(info)
if info['connection'] != 0:
continue
edid = self.get_edid(output)
name = info['name']
crtc = info['crtc']
if crtc == 0:
continue
else:
mode = self.crtcStatus[crtc]['mode']
modename = modedata[mode]['name']
posx = self.crtcStatus[crtc]['x']
posy = self.crtcStatus[crtc]['y']
self.outputStatus[name] = {}
self.outputStatus[name]['edid'] = edid
self.outputStatus[name]['crtc'] = crtc
self.outputStatus[name]['modename'] = modename
self.outputStatus[name]['posx'] = posx
self.outputStatus[name]['posy'] = posy
#print(self.display.xrandr_list_output_properties(output)._data)
"""
print(self.outputStatus)
op = self.getOutputForOutputname('eDP1')
print(op)
md = self.findModeByName(op, '1920x1080')
print(md)
cr = self.getUsableCrtcForOutput(op)
if not cr:
#print('Disabling CRTC')
cr = self.getCurrentCrtcForOutput(op)
self.disableCrtc(cr)
else:
#print('Enabling CRTC')
print(cr)
self.configureCrtcForOutputAndMode(cr, op, md, 0, 0)
"""
def applyConfiguration(self, config):
- # Get list of all outputs
- # Disable all outputs not in the config
- # Check if an output already has a CRTC
- # If yes, reconfigure the current CRTC
- # If not, find a new CRTC and configure it accordingly
- print('FIXME')
- pass
+ # FIXME:
+ # Rework to use getOutputForEdid and applying
+ # configuration based on EDID only
+ resources = self.window.xrandr_get_screen_resources()._data
+ outputs = resources['outputs']
+ for output in outputs:
+ info = self.display.xrandr_get_output_info(output, resources['config_timestamp'])._data
+ name = info['name']
+ found = False
+ for nm in config:
+ if nm == name and config[nm]['modename'] != '0':
+ found = True
+
+ if not found:
+ crtc = self.getCurrentCrtcForOutput(output)
+ if crtc:
+ self.disableCrtc(crtc)
+
+ for nm in config:
+ if config[nm]['modename'] != '0':
+ output = self.getOutputForOutputname(nm)
+ crtc = self.getCurrentCrtcForOutput(output)
+ if not crtc:
+ crtc = self.getUsableCrtcForOutput(output)
+ mode = self.findModeByName(output, config[nm]['modename'])
+ self.configureCrtcForOutputAndMode(crtc, output, mode, config[nm]['posx'], config[nm]['posy'])
def getScreenConfiguration(self):
return self.outputStatus
def disableCrtc(self, crtc):
resources = self.window.xrandr_get_screen_resources()._data
- self.display.xrandr_set_crtc_config(65, resources['config_timestamp'], 0, 0, 0, randr.Rotate_0, [])
+ self.display.xrandr_set_crtc_config(crtc, resources['config_timestamp'], 0, 0, 0, randr.Rotate_0, [])
def getCurrentCrtcForOutput(self, output):
resources = self.window.xrandr_get_screen_resources()._data
info = self.display.xrandr_get_output_info(output, resources['config_timestamp'])._data
return info['crtc']
def configureCrtcForOutputAndMode(self, crtc, output, mode, posx, posy):
resources = self.window.xrandr_get_screen_resources()._data
self.display.xrandr_set_crtc_config(crtc, resources['config_timestamp'], posx, posy, mode, randr.Rotate_0, [output])
def getOutputForOutputname(self, name):
resources = self.window.xrandr_get_screen_resources()._data
for output in resources['outputs']:
info = self.display.xrandr_get_output_info(output, resources['config_timestamp'])._data
if info['name'] == name:
return output
return None
def getUsableCrtcForOutput(self, output):
resources = self.window.xrandr_get_screen_resources()._data
for crtc in resources['crtcs']:
crtcinfo = self.display.xrandr_get_crtc_info(crtc, resources['config_timestamp'])._data
if len(crtcinfo['outputs']) == 0:
if output in crtcinfo['possible_outputs']:
return crtc
return None
def findModeByName(self, output, modename):
resources = self.window.xrandr_get_screen_resources()._data
modedata = self.parseModes(resources['mode_names'], resources['modes'])
info = self.display.xrandr_get_output_info(output, resources['config_timestamp'])._data
modes = info['modes']
for mode in modes:
if modedata[mode]['name'] == modename:
return mode
return None
def parseModes(self, mode_names, modes):
lastIdx = 0
modedatas = dict()
for mode in modes:
modedata = dict(mode._data)
modedata['name'] = mode_names[lastIdx:lastIdx + modedata['name_length']]
modedatas[modedata['id']] = modedata
lastIdx += modedata['name_length']
return modedatas
+
+ def getOutputForEdid(self, edid):
+ resources = self.window.xrandr_get_screen_resources()._data
+ for output in resources['outputs']:
+ medid = self.get_edid(output)
+ if edid == medid:
+ return output
+ return 0
# query the edid module for output_nr
def get_edid(self, output_nr):
PROPERTY_EDID = self.display.intern_atom("EDID", 0)
INT_TYPE = 19
props = self.display.xrandr_list_output_properties(output_nr)
if PROPERTY_EDID in props.atoms:
try:
rawedid = self.display.xrandr_get_output_property(output_nr, PROPERTY_EDID, INT_TYPE, 0, 400)
except:
print("Error loading EDID data of output ", output_nr)
return None
edidstream = rawedid._data['value']
hx = bytearray()
hx.extend(edidstream)
hs = hashlib.sha1(hx).hexdigest()
return hs
else:
return None
class ConfigManager:
def __init__(self, cfgfile):
self.cfgfile = cfgfile
if not os.path.exists(cfgfile):
self.recreateCfg()
self.dic = {}
self.cfg2dic()
def getDic(self):
return self.dic
def recreateCfg(self):
print('Creating new config file: ' + self.cfgfile)
config = configparser.ConfigParser()
config.add_section('General')
config.set('General', 'numEntries', '0')
with open(self.cfgfile, 'w') as configfile:
config.write(configfile)
def cfg2dic(self):
dic = {}
config = configparser.ConfigParser()
config.read(self.cfgfile)
for section in config.sections():
dic[section] = {}
for key in config[section]:
dic[section][key] = config.get(section, key)
self.dic = dic
return dic
def dic2cfg(self):
config = configparser.ConfigParser()
for section in self.dic:
config.add_section(section)
for key in self.dic[section]:
config.set(section, key, self.dic[section][key])
with open(self.cfgfile, 'w') as configfile:
config.write(configfile)
def getConfig(self, screenConfiguration):
ne = int(self.dic['General']['numentries'])
for ii in range(0, ne):
name = 'Config' + str(ii+1)
if int(self.dic[name]['edidcount']) != len(screenConfiguration):
continue
found = True
for outputName in screenConfiguration:
lFound = False
for jj in range(0, len(screenConfiguration)):
if self.dic[name]['edid' + str(jj+1)] == screenConfiguration[outputName]['edid']:
lFound = True
if lFound and found:
found = True
else:
found = False
if found:
for jj in range(0, len(screenConfiguration)):
return self.dic[name]
return None
def saveConfiguration(self, screenConfiguration):
ne = int(self.dic['General']['numentries'])
ne += 1
self.dic['General']['numentries'] = str(ne)
name = 'Config' + str(ne)
self.dic[name] = {}
self.dic[name]['edidcount'] = str(len(screenConfiguration))
cnt = 1
for outputName in screenConfiguration.keys():
self.dic[name]['edid'+str(cnt)] = screenConfiguration[outputName]['edid']
self.dic[name]['output'+str(cnt)] = outputName
self.dic[name]['mode'+str(cnt)] = screenConfiguration[outputName]['modename']
self.dic[name]['posx'+str(cnt)] = str(screenConfiguration[outputName]['posx'])
self.dic[name]['posy'+str(cnt)] = str(screenConfiguration[outputName]['posy'])
cnt += 1
- self.dic2cfg(cfgfile)
- return True
-
- def loadAndApplyConfig(self, dic, edids):
- cfg = getConfig(dic, edids)
- print(cfg)
- for edid in cfg:
- #FIXME: This does not work with negative numbers!
- if edid[2] == '0':
- subprocess.call(['xrandr', '--output', edid[1], '--off'])
- continue
- modepos = re.findall(r'\d+', edid[2])
- mode = modepos[0] + 'x' + modepos[1]
- pos = modepos[2] + 'x' + modepos[3]
- print(pos)
- subprocess.call(['xrandr', '--output', edid[1], '--mode', mode, '--pos', pos])
+ self.dic2cfg()
return True
settingsdir = os.path.join(os.environ['HOME'], '.config')
cfgfile = os.path.join(settingsdir, 'monitorDaemon.ini')
cm = ConfigManager(cfgfile)
cfg = cm.getDic()
#print(cfg)
xri = xrandrInterface()
screenConfig = xri.getScreenConfiguration()
#print(screenConfig)
storedConfig = cm.getConfig(screenConfig)
if storedConfig:
print('LoadAndApply')
xri.applyConfiguration(screenConfig)
else:
print('SaveConfig')
cm.saveConfiguration(screenConfig)
sys.exit(0)

File Metadata

Mime Type
text/x-diff
Expires
Thu, Dec 5, 12:53 AM (3 h, 25 m ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
531947
Default Alt Text
(12 KB)

Event Timeline