You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tde-guidance/displayconfig/displayconfig-restore.py

325 lines
15 KiB

#!/usr/bin/python
###########################################################################
# displayconfig-restore.py - description #
# ------------------------------ #
# begin : Wed Dec 15 2004 #
# copyright : (C) 2004-2006 by Simon Edwards #
# email : simon@simonzone.com #
# #
###########################################################################
# #
# This program is free software; you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation; either version 2 of the License, or #
# (at your option) any later version. #
# #
###########################################################################
import os
import os.path
import subprocess
import ixf86misc
import xf86misc
from execwithcapture import *
############################################################################
def FindXorgConfig(self):
# Lookup location of X configfile
for line in ExecWithCapture("xset", ["xset","q"],True).split('\n'):
if line.strip().startswith("Config file"):
return line.split(":")[1].strip()
# Sometimes, xset doesn't know about the configfile location, hence ...
if os.path.isfile("/etc/X11/xorg.conf"):
return "/etc/X11/xorg.conf"
return None
############################################################################
# FixXorgDPI
# ==========
# The idea here is to ensure that applications use a sensible DPI setting
# for fonts. When Xorg starts up it tries to detect the size of the attached
# monitor and calculate the real DPI from there and use that. Problems are:
#
# * if the monitor size can not be detect then Xorg uses 75dpi. This is
# usually far too low.
#
# * if the monitor size is not accurately detected then you get bad a DPI.
#
# * most fonts are optimised to work at a handful of standard DPIs. 96dpi,
# 120dpi and printer resolution 300dpi and 600dpi. Fonts rendered in
# non-standard DPIs often look bad and jagged. This is a real problem
# when rendering fonts on low resolution devices. (i.e. a computer
# monitor).
#
# Although it is desirable in theory to use the real DPI of the monitor, in
# practice it is more important to ensure that fonts are well rendered even
# if the DPI in use is not correct.
#
# What this function does is read the display size from the X server and
# if it is lower than 140dpi then 'round' it to either 96dpi or 120dpi.
# (A dpi greater or equal to 140 is assumed to be high enough to render fonts
# well.) The new dpi is then loaded with the xrdb command into the X server
# resource database. Most X applications (Qt and GTK apps at least) will then
# use this DPI for font rendering.
#
def FixXorgDPI(desiredDPI):
# dpi is:
# None - round the DPI.
# xserver - Use the X server's DPI.
# <number> - DPI to use.
if desiredDPI=="xserver":
return
dpi = 96
try:
if desiredDPI is not None:
dpi = int(desiredDPI)
except ValueError:
desiredDPI = None
if desiredDPI is None:
xserver = xf86misc.XF86Server()
if len(xserver.getScreens())!=0:
(width,height,width_mm,height_mm) = xserver.getScreens()[0].getDimensions()
if not float(width_mm) == 0:
w_dpi = float(width)/(float(width_mm)/25.4)
else:
w_dpi = 96
if not float(height_mm) == 0:
h_dpi = float(height)/(float(height_mm)/25.4)
else:
h_dpi = 96
dpi = (w_dpi+h_dpi)/2.0 # Average the two possible DPIs.
if dpi >= 140: # Anything above 140 is ok.
dpi = int(dpi)
else:
if abs(96-dpi) < abs(120-dpi): # Rounding to 96 is best.
dpi = 96
else:
dpi = 120
# work around for LP beastie 151311
if ((w_dpi < 200) and (h_dpi > 900)):
dpi = 96
try:
xrdb = subprocess.Popen(["xrdb","-nocpp","-merge"],stdin=subprocess.PIPE)
xrdb.communicate("Xft.dpi: %i\n" % dpi)
xrdb.wait()
except OSError:
pass
# Other common, but now used settingsfor xrdb:
# Xft.antialias:
# Xft.hinting:
# Xft.hintstyle:
# Xft.rgba:
############################################################################
def ReadDisplayConfigRC():
screens = None
dpi = None
dpms_seconds = None
dpms_enabled = None
configpath = ExecWithCapture("kde-config",['kde-config','--path','config'],True)
# Hunt down the user's displayconfigrc file and adjust the resolution
# on the fly to match. (Non-root Users can independantly specify their own settings.)
dirs = configpath.strip().split(":")
for dir in dirs:
if dir!="":
configpath = os.path.join(dir,"displayconfigrc")
if os.path.exists(configpath):
# Parse the config file.
fhandle = open(configpath)
screens = []
currentscreen = None
for line in fhandle.readlines():
line = line.strip()
if line.startswith("[Screen"):
# Screen, width, height, refresh, reflectx, reflecty, rotate, redgamma, greengamma,bluegamma
currentscreen = [int(line[7:-1]), None, None, None, False, False, "0", None, None, None]
screens.append(currentscreen)
elif line.startswith("["):
currentscreen = None
elif line.startswith("dpi="):
dpi = line[4:]
elif currentscreen is not None:
if line.startswith("width="):
currentscreen[1] = int(line[6:])
elif line.startswith("height="):
currentscreen[2] = int(line[7:])
elif line.startswith("refresh="):
currentscreen[3] = int(line[8:])
elif line.startswith("reflectX="):
currentscreen[4] = line[9:]=="1"
elif line.startswith("reflectY="):
currentscreen[5] = line[9:]=="1"
elif line.startswith("rotate="):
currentscreen[6] = line[7:]
elif line.startswith("redgamma="):
currentscreen[7] = line[9:]
elif line.startswith("greengamma="):
currentscreen[8] = line[11:]
elif line.startswith("bluegamma="):
currentscreen[9] = line[10:]
elif line.startswith("dpmsEnabled"):
dpms_enabled = line.split("=")[1]
elif line.startswith("dpmsSeconds"):
dpms_seconds = int(line.split("=")[1])
fhandle.close()
break
return (screens,dpi,dpms_enabled,dpms_seconds)
############################################################################
def main():
(screens,dpi,dpms_enabled,dpms_seconds) = ReadDisplayConfigRC()
if dpms_enabled:
if dpms_enabled == "on":
if not dpms_seconds:
dpms_seconds = 900
cmd = "xset dpms %i %i %i" % (dpms_seconds,dpms_seconds,dpms_seconds)
os.system(cmd)
else:
cmd = "xset -dpms"
os.system(cmd)
if screens is not None:
# Set the X server.
try:
xserver = xf86misc.XF86Server()
if len(screens)!=0:
for screen in screens:
(id,width,height,refresh,reflectx,reflecty,rotate,redgamma,greengamma,bluegamma) = screen
# Convert the stuff into RandR's rotation bitfield thingy.
if rotate=="0":
rotation = xf86misc.XF86Screen.RR_Rotate_0
elif rotate=="90":
rotation = xf86misc.XF86Screen.RR_Rotate_90
elif rotate=="180":
rotation = xf86misc.XF86Screen.RR_Rotate_180
elif rotate=="270":
rotation = xf86misc.XF86Screen.RR_Rotate_270
if reflectx:
rotation |= xf86misc.XF86Screen.RR_Reflect_X
if reflecty:
rotation |= xf86misc.XF86Screen.RR_Reflect_Y
if id<len(xserver.getScreens()):
xscreen = xserver.getScreens()[id]
if xscreen.resolutionSupportAvailable():
available_sizes = xscreen.getAvailableSizes()
# Find the closest matching resolution
best_score = 1000000
best_size_id = 0
for size_id in range(len(available_sizes)):
size = available_sizes[size_id]
score = abs(size[0]-width)+abs(size[1]-height)
if score < best_score:
best_size_id = size_id
best_score = score
# Now find the best refresh for this resolution
best_score = 1000000
best_refresh = 50
for available_refresh in xscreen.getAvailableRefreshRates(best_size_id):
score = abs(refresh-available_refresh)
if score < best_score:
best_refresh = available_refresh
best_score = score
# Mask out any unsupported rotations.
rotation &= xscreen.getAvailableRotations()
xscreen.setScreenConfigAndRate(best_size_id, rotation, best_refresh)
# Restore the gamma settings.
if redgamma is not None and greengamma is not None and bluegamma is not None:
try:
xscreen.setGamma( (float(redgamma), float(greengamma), float(bluegamma)) )
except ValueError,e:
pass
FixXorgDPI(dpi)
except xf86misc.XF86Error,err:
print err
return
else:
# Ensure that the xorgs virtual screen size matches the default resolution
# of the server. Why does this matter? When Xorg starts up it reads its
# config file chooses the first mode in the "modes" line of the active
# Screen section and uses it as the virtual screen size and as the
# screen resolution (ie 1024x768 resolution screen showing a 1024x768 gfx
# buffer). But, this means that you can't use RandR to get to any higher
# screen resolutions (ie 1280x1024) because Xorg requires that the virtual
# screen size 'cover' the screen resolution being displayed.
#
# So, to get around this problem and make it possible for people to select
# a lower resolution screen *and* still have the option later to use
# RandR/displayconfig to switch to higher resolution, displayconfig
# explicitly sets the virtual screen size in xorg.conf to the largest
# resoluution that the monitor/gfx card can support. The down side to
# this is that the X server and tdm get the correct resolution but the
# wrong (virtual) screen size. The user can now scroll around on the
# greater virtual screen. Kind of annoying for tdm, unacceptable once
# the user has logged in.
#
# What we do now as the user's KDE session is being started up is check
# what the real virtual screen size is meant to be (=same as the real
# resolution being used) and then use the RandR extension to explicitly
# set the correct resolution. This has the effect of changing the virtual
# screeen size to what we really want. (RandR can change the virtual
# screen size, thankfully)
import displayconfigabstraction
try:
xserver = xf86misc.XF86Server()
for xscreen in xserver.getScreens():
if xscreen.resolutionSupportAvailable():
mode_line = ixf86misc.XF86VidModeGetModeLine(xserver.getDisplay(),xscreen.getScreenId())
hdisplay = mode_line[1]
vdisplay = mode_line[5]
live_refresh_rate = xscreen.getRefreshRate()
try:
(live_width,live_height,x,x) = xscreen.getAvailableSizes()[xscreen.getSizeID()]
except IndexError, errmsg:
print "IndexError:", errmsg, "in displayconfig-restore getting live screen size - trying screen 0."
(live_width,live_height,x,x) = xscreen.getAvailableSizes()[0]
if (hdisplay,vdisplay) != (live_width,live_height):
# The screen resolution doesn't match the virtual screen size.
screen_sizes = xscreen.getAvailableSizes()
for size_id in range(len(screen_sizes)):
screen_size = screen_sizes[size_id]
if screen_size[0]==hdisplay and screen_size[1]==vdisplay:
# Find the closest matching refresh rate.
best_refresh = 0
best_score = 1000000
for rate in xscreen.getAvailableRefreshRates(size_id):
score = abs(rate-live_refresh_rate)
if score < best_score:
best_refresh = rate
best_score = score
# Reset the screen mode and virtual screen size.
xscreen.setScreenConfigAndRate(size_id,xscreen.getRotation(),best_refresh)
break
FixXorgDPI(dpi)
except (xf86misc.XF86Error,TypeError),err:
print err
main()