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.
325 lines
15 KiB
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()
|