Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F1726592
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Size
12 KB
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
rMD monitorDaemon
Event Timeline
Log In to Comment