diff options
Diffstat (limited to 'displayconfig/displayconfig-restore.py')
-rwxr-xr-x | displayconfig/displayconfig-restore.py | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/displayconfig/displayconfig-restore.py b/displayconfig/displayconfig-restore.py new file mode 100755 index 0000000..8c44a48 --- /dev/null +++ b/displayconfig/displayconfig-restore.py @@ -0,0 +1,324 @@ +#!/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 kdm 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 kdm, 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() |