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.
1757 lines
71 KiB
1757 lines
71 KiB
15 years ago
|
#!/usr/bin/python
|
||
|
# -*- coding: UTF-8 -*-
|
||
|
###########################################################################
|
||
|
# displayconfig.py - description #
|
||
|
# ------------------------------ #
|
||
|
# begin : Fri Mar 26 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. #
|
||
|
# #
|
||
|
###########################################################################
|
||
|
|
||
|
from qt import *
|
||
|
from kdecore import *
|
||
|
from kdeui import *
|
||
|
import xorgconfig
|
||
|
import xf86misc
|
||
|
import string
|
||
|
import os
|
||
|
import select
|
||
|
import sys
|
||
|
import csv
|
||
|
import time
|
||
|
import signal
|
||
|
import shutil
|
||
|
from ktimerdialog import *
|
||
|
from displayconfigwidgets import *
|
||
|
from displayconfigabstraction import *
|
||
|
from execwithcapture import *
|
||
|
|
||
|
programname = "Display and Graphics Configuration"
|
||
|
version = "0.8.0"
|
||
|
DUAL_PREVIEW_SIZE = 240
|
||
|
|
||
|
# Are we running as a separate standalone application or in KControl?
|
||
|
standalone = __name__=='__main__'
|
||
|
|
||
|
# Running as the root user or not?
|
||
|
isroot = os.getuid()==0
|
||
|
|
||
|
############################################################################
|
||
|
class GfxCardDialog(KDialogBase):
|
||
|
video_ram_list = [256,512,1024,2048,4096,8192,16384,32768,65536]
|
||
|
|
||
|
def __init__(self,parent):
|
||
|
KDialogBase.__init__(self,parent,None,True,"Choose Graphics Card",
|
||
|
KDialogBase.Ok|KDialogBase.Cancel, KDialogBase.Cancel)
|
||
|
|
||
|
self.gfxcarddb = None
|
||
|
self.updatingGUI = True
|
||
|
self.card2listitem = {}
|
||
|
|
||
|
topbox = QVBox(self)
|
||
|
topbox.setSpacing(KDialog.spacingHint())
|
||
|
self.setMainWidget(topbox)
|
||
|
label = QLabel(topbox)
|
||
|
label.setText(i18n("Select Graphics Card:"))
|
||
|
self.listview = KListView(topbox)
|
||
|
self.listview.addColumn("")
|
||
|
self.listview.header().hide()
|
||
|
self.listview.setRootIsDecorated(True)
|
||
|
self.connect(self.listview,SIGNAL("selectionChanged(QListViewItem *)"),self.slotListClicked)
|
||
|
topbox.setStretchFactor(self.listview,1)
|
||
|
|
||
|
self.driver = KListViewItem(self.listview)
|
||
|
self.driver.setText(0,i18n("Drivers"))
|
||
|
self.driver.setSelectable(False)
|
||
|
|
||
|
self.manufacturer = KListViewItem(self.listview)
|
||
|
self.manufacturer.setText(0,i18n("Manufacturers"))
|
||
|
self.manufacturer.setSelectable(False)
|
||
|
|
||
|
hbox = QHBox(topbox)
|
||
|
topbox.setStretchFactor(hbox,0)
|
||
|
vbox = QVBox(hbox)
|
||
|
|
||
|
self.detected_label = QLabel("",vbox)
|
||
|
|
||
|
self.detected_button = KPushButton(vbox)
|
||
|
self.detected_button.setText(i18n("Select"))
|
||
|
self.connect(self.detected_button,SIGNAL("clicked()"),self.slotSelectDetectedClicked)
|
||
|
|
||
|
spacer = QWidget(vbox)
|
||
|
vbox.setStretchFactor(self.detected_button,0)
|
||
|
vbox.setStretchFactor(spacer,1)
|
||
|
|
||
|
hbox.setStretchFactor(vbox,0)
|
||
|
spacer = QWidget(hbox)
|
||
|
hbox.setStretchFactor(spacer,1)
|
||
|
|
||
|
drivergrid = QGrid(2,hbox)
|
||
|
drivergrid.setSpacing(KDialog.spacingHint())
|
||
|
QLabel(i18n("Driver:"),drivergrid)
|
||
|
self.standarddriverradio = QRadioButton(i18n("Standard"),drivergrid)
|
||
|
self.connect(self.standarddriverradio,SIGNAL("clicked()"),self.slotStandardDriverClicked)
|
||
|
QWidget(drivergrid)
|
||
|
self.proprietarydriverradio = QRadioButton(i18n("Proprietary"),drivergrid)
|
||
|
self.connect(self.proprietarydriverradio,SIGNAL("clicked()"),self.slotProprietaryDriverClicked)
|
||
|
|
||
|
QLabel(i18n("Video RAM:"),drivergrid)
|
||
|
self.videoramcombo = QComboBox(drivergrid)
|
||
|
for s in [i18n("256 kB"),
|
||
|
i18n("512 kB"),
|
||
|
i18n("1 MB"),
|
||
|
i18n("2 MB"),
|
||
|
i18n("4 MB"),
|
||
|
i18n("8 MB"),
|
||
|
i18n("16 MB"),
|
||
|
i18n("32 MB"),
|
||
|
i18n("64 MB or more")]:
|
||
|
self.videoramcombo.insertItem(s)
|
||
|
|
||
|
self.updatingGUI = False
|
||
|
self._setGfxCardDB(GetGfxCardModelDB())
|
||
|
|
||
|
def _setGfxCardDB(self,gfxcarddb):
|
||
|
self.updatingGUI = True
|
||
|
self.gfxcarddb = gfxcarddb
|
||
|
|
||
|
# Add the GfxCards under the Manufacturer item.
|
||
|
keys = gfxcarddb.vendordb.keys()
|
||
|
keys.sort()
|
||
|
for key in keys:
|
||
|
cardkeys = self.gfxcarddb.vendordb[key].keys()
|
||
|
vendoritem = KListViewItem(self.manufacturer)
|
||
|
vendoritem.setText(0,key)
|
||
|
vendoritem.setSelectable(False)
|
||
|
for cardkey in cardkeys:
|
||
|
item = KListViewItem(vendoritem)
|
||
|
item.setText(0,cardkey)
|
||
|
self.card2listitem[self.gfxcarddb.vendordb[key][cardkey]] = item
|
||
|
|
||
|
# Add the GfxCard _drivers_ under the Drivers item
|
||
|
drivers = gfxcarddb.driverdb.keys()
|
||
|
drivers.sort()
|
||
|
for driver in drivers:
|
||
|
driveritem = KListViewItem(self.driver)
|
||
|
driveritem.setText(0,driver)
|
||
|
self.card2listitem[gfxcarddb.driverdb[driver]] = driveritem
|
||
|
|
||
|
self.updatingGUI = False
|
||
|
|
||
|
def do(self,card,proprietarydriver,detected_card,video_ram):
|
||
|
self.updatingGUI = True
|
||
|
item = self.card2listitem[card]
|
||
|
self.listview.setSelected(item,True)
|
||
|
self.listview.ensureItemVisible(item)
|
||
|
|
||
|
self.selected_video_ram = video_ram
|
||
|
|
||
|
if detected_card is None:
|
||
|
self.detected_button.setEnabled(False)
|
||
|
self.detected_label.setText(i18n("Detected graphics card:\n(unknown)"))
|
||
|
else:
|
||
|
self.detected_button.setEnabled(True)
|
||
|
self.detected_label.setText(i18n("Detected graphics card:\n'%1'.").arg(detected_card.getName()))
|
||
|
|
||
|
self.__syncDriver(card,proprietarydriver,video_ram)
|
||
|
|
||
|
self.detected_card = detected_card
|
||
|
self.selected_card = card
|
||
|
self.updatingGUI = False
|
||
|
|
||
|
if self.exec_loop()==QDialog.Accepted:
|
||
|
return (self.selected_card,
|
||
|
self.proprietarydriverradio.isChecked() and (self.selected_card is not None),
|
||
|
self.video_ram_list[self.videoramcombo.currentItem()])
|
||
|
else:
|
||
|
return (card, proprietarydriver,video_ram)
|
||
|
|
||
|
def __syncDriver(self,card,proprietarydriver,videoram):
|
||
|
if card.getProprietaryDriver() is None:
|
||
|
self.standarddriverradio.setChecked(True)
|
||
|
self.standarddriverradio.setEnabled(False)
|
||
|
self.proprietarydriverradio.setEnabled(False)
|
||
|
else:
|
||
|
self.standarddriverradio.setEnabled(True)
|
||
|
self.proprietarydriverradio.setEnabled(True)
|
||
|
self.standarddriverradio.setChecked(not proprietarydriver)
|
||
|
self.proprietarydriverradio.setChecked(proprietarydriver)
|
||
|
|
||
|
self.videoramcombo.setEnabled(card.getNeedVideoRam())
|
||
|
if card.getNeedVideoRam():
|
||
|
self.videoramcombo.setCurrentItem(self.video_ram_list.index(videoram))
|
||
|
|
||
|
def slotSelectDetectedClicked(self):
|
||
|
self.updatingGUI = True
|
||
|
item = self.card2listitem[self.detected_card]
|
||
|
self.listview.setSelected(item,True)
|
||
|
self.listview.ensureItemVisible(item)
|
||
|
self.selected_card = self.detected_card
|
||
|
self.__syncDriver(self.selected_card, self.proprietarydriverradio.isChecked(), self.selected_video_ram)
|
||
|
self.updatingGUI = False
|
||
|
|
||
|
def slotListClicked(self,item):
|
||
|
if self.updatingGUI:
|
||
|
return
|
||
|
|
||
|
for key in self.card2listitem:
|
||
|
value = self.card2listitem[key]
|
||
|
if value is item:
|
||
|
self.selected_card = key
|
||
|
self.__syncDriver(self.selected_card, self.proprietarydriverradio.isChecked(), self.selected_video_ram)
|
||
|
|
||
|
def slotStandardDriverClicked(self):
|
||
|
self.proprietarydriverradio.setChecked(False)
|
||
|
self.standarddriverradio.setChecked(True)
|
||
|
|
||
|
def slotProprietaryDriverClicked(self):
|
||
|
self.standarddriverradio.setChecked(False)
|
||
|
self.proprietarydriverradio.setChecked(True)
|
||
|
|
||
|
############################################################################
|
||
|
class MonitorDialog(KDialogBase):
|
||
|
def __init__(self,parent):
|
||
|
KDialogBase.__init__(self,parent,None,True,"Choose Monitor",
|
||
|
KDialogBase.Ok|KDialogBase.Cancel, KDialogBase.Cancel)
|
||
|
|
||
|
self.monitordb = None
|
||
|
self.selectedmonitor = None
|
||
|
self.aspect = ModeLine.ASPECT_4_3
|
||
|
self.monitor2listitem = {}
|
||
|
self.updatingGUI = True
|
||
|
|
||
|
topbox = QVBox(self)
|
||
|
topbox.setSpacing(KDialog.spacingHint())
|
||
|
self.setMainWidget(topbox)
|
||
|
label = QLabel(topbox)
|
||
|
label.setText(i18n("Select Monitor:"))
|
||
|
self.listview = KListView(topbox)
|
||
|
self.listview.addColumn("")
|
||
|
self.listview.header().hide()
|
||
|
self.listview.setRootIsDecorated(True)
|
||
|
self.connect(self.listview,SIGNAL("selectionChanged(QListViewItem *)"),self.slotListClicked)
|
||
|
|
||
|
self.generic = KListViewItem(self.listview)
|
||
|
self.generic.setText(0,i18n("Generic"))
|
||
|
self.generic.setSelectable(False)
|
||
|
|
||
|
self.manufacturer = KListViewItem(self.listview)
|
||
|
self.manufacturer.setText(0,i18n("Manufacturers"))
|
||
|
self.manufacturer.setSelectable(False)
|
||
|
|
||
|
grid = QGroupBox(4,QGroupBox.Horizontal,topbox)
|
||
|
grid.setTitle(i18n("Details"))
|
||
|
|
||
|
label = QLabel(grid)
|
||
|
label.setText(i18n("Horizontal Range:"))
|
||
|
|
||
|
self.horizrange = KLineEdit(grid)
|
||
|
self.horizrange.setReadOnly(True)
|
||
|
|
||
|
label = QLabel(grid)
|
||
|
label.setText(i18n("Vertical Refresh:"))
|
||
|
|
||
|
self.vertrange = KLineEdit(grid)
|
||
|
self.vertrange.setReadOnly(True)
|
||
|
|
||
|
hbox = QHBox(topbox)
|
||
|
|
||
|
self.detectbutton = KPushButton(hbox)
|
||
|
self.detectbutton.setText(i18n("Detect Monitor")) # FIXME better label/text?
|
||
|
self.connect(self.detectbutton,SIGNAL("clicked()"),self.slotDetectClicked)
|
||
|
|
||
|
spacer = QWidget(hbox)
|
||
|
hbox.setStretchFactor(self.detectbutton,0)
|
||
|
hbox.setStretchFactor(spacer,1)
|
||
|
|
||
|
label = QLabel(hbox)
|
||
|
label.setText(i18n("Image format:"))
|
||
|
hbox.setStretchFactor(label,0)
|
||
|
|
||
|
self.aspectcombobox = KComboBox(hbox)
|
||
|
self.aspectcombobox.insertItem(i18n("Standard 4:3"))
|
||
|
self.aspectcombobox.insertItem(i18n("Widescreen 16:9"))
|
||
|
hbox.setStretchFactor(self.aspectcombobox,0)
|
||
|
|
||
|
self.updatingGUI = False
|
||
|
|
||
|
def setMonitorDB(self,monitordb):
|
||
|
self.monitordb = monitordb
|
||
|
|
||
|
# Add the Monitors
|
||
|
vendors = monitordb.vendordb.keys()
|
||
|
vendors.sort()
|
||
|
for vendor in vendors:
|
||
|
monitorkeys = self.monitordb.vendordb[vendor].keys()
|
||
|
vendoritem = KListViewItem(self.manufacturer)
|
||
|
vendoritem.setText(0,vendor)
|
||
|
vendoritem.setSelectable(False)
|
||
|
for monitorkey in monitorkeys:
|
||
|
item = KListViewItem(vendoritem)
|
||
|
item.setText(0,monitorkey)
|
||
|
self.monitor2listitem[self.monitordb.vendordb[vendor][monitorkey]] = item
|
||
|
|
||
|
generics = monitordb.genericdb.keys()
|
||
|
generics.sort()
|
||
|
for generic in generics:
|
||
|
genericitem = KListViewItem(self.generic)
|
||
|
genericitem.setText(0,generic)
|
||
|
self.monitor2listitem[monitordb.genericdb[generic]] = genericitem
|
||
|
|
||
|
customs = monitordb.getCustomMonitors().keys()
|
||
|
customs.sort()
|
||
|
for custom in customs:
|
||
|
customitem = KListViewItem(self.listview)
|
||
|
customitem.setText(0,custom)
|
||
|
self.monitor2listitem[monitordb.getCustomMonitors()[custom]] = customitem
|
||
|
|
||
|
def do(self,monitor,aspect,is_primary_monitor=True):
|
||
|
"""Run the monitor selection dialog.
|
||
|
|
||
|
Parameters:
|
||
|
|
||
|
monitor - Currently selected 'Monitor' object.
|
||
|
|
||
|
Returns the newly selected monitor object and aspect ratio as a tuple.
|
||
|
"""
|
||
|
if monitor is not None:
|
||
|
self.selectedmonitor = monitor
|
||
|
item = self.monitor2listitem[monitor]
|
||
|
|
||
|
self.listview.setSelected(item,True)
|
||
|
self.listview.ensureItemVisible(item)
|
||
|
|
||
|
else:
|
||
|
self.selectedmonitor = None
|
||
|
self.listview.clearSelection()
|
||
|
self.aspect = aspect
|
||
|
|
||
|
# Only the first/primary monitor can be detected. :-/
|
||
|
self.detectbutton.setEnabled(is_primary_monitor)
|
||
|
|
||
|
self.updatingGUI = True
|
||
|
self._syncGUI()
|
||
|
self.updatingGUI = False
|
||
|
|
||
|
if self.exec_loop()!=QDialog.Accepted:
|
||
|
# Dialog was cancelled. Return the original monitor.
|
||
|
self.selectedmonitor = monitor
|
||
|
else:
|
||
|
self.aspect = [ModeLine.ASPECT_4_3,ModeLine.ASPECT_16_9][self.aspectcombobox.currentItem()]
|
||
|
|
||
|
return (self.selectedmonitor,self.aspect)
|
||
|
|
||
|
def slotDetectClicked(self):
|
||
|
detectedmonitor = self.monitordb.detect()
|
||
|
if detectedmonitor is not None:
|
||
|
self.selectedmonitor = detectedmonitor
|
||
|
self._syncGUI()
|
||
|
else:
|
||
|
KMessageBox.error(self, i18n("Sorry, the model and capabilities of your\nmonitor couldn't be detected."),
|
||
|
i18n("Monitor detection failed"))
|
||
|
|
||
|
def slotListClicked(self,item):
|
||
|
if self.updatingGUI:
|
||
|
return
|
||
|
self.updatingGUI = True
|
||
|
for key in self.monitor2listitem:
|
||
|
value = self.monitor2listitem[key]
|
||
|
if value is item:
|
||
|
self.selectedmonitor = key
|
||
|
break
|
||
|
self._syncGUI()
|
||
|
self.updatingGUI = False
|
||
|
|
||
|
def _syncGUI(self):
|
||
|
if self.selectedmonitor is not None:
|
||
|
item = self.monitor2listitem[self.selectedmonitor]
|
||
|
self.listview.setSelected(item,True)
|
||
|
self.listview.ensureItemVisible(item)
|
||
|
self.vertrange.setText(self.selectedmonitor.getVerticalSync())
|
||
|
self.horizrange.setText(self.selectedmonitor.getHorizontalSync())
|
||
|
else:
|
||
|
self.vertrange.setText("-")
|
||
|
self.horizrange.setText("-")
|
||
|
|
||
|
self.aspectcombobox.setCurrentItem({ModeLine.ASPECT_4_3:0,ModeLine.ASPECT_16_9:1}[self.aspect])
|
||
|
|
||
|
############################################################################
|
||
|
if standalone:
|
||
|
programbase = KDialogBase
|
||
|
else:
|
||
|
programbase = KCModule
|
||
|
|
||
|
############################################################################
|
||
|
class DisplayApp(programbase):
|
||
|
########################################################################
|
||
|
def __init__(self,parent=None,name=None):
|
||
|
global standalone,isroot,kapp
|
||
|
KGlobal.locale().insertCatalogue("guidance")
|
||
|
|
||
|
if standalone:
|
||
|
KDialogBase.__init__(self,KJanusWidget.Tabbed,"Display Configuration",\
|
||
|
KDialogBase.Apply|KDialogBase.User1|KDialogBase.User2|KDialogBase.Close, KDialogBase.Close)
|
||
|
self.setButtonText(KDialogBase.User1,i18n("Reset"))
|
||
|
self.setButtonText(KDialogBase.User2,i18n("About"))
|
||
|
else:
|
||
|
KCModule.__init__(self,parent,name)
|
||
|
self.setButtons(KCModule.Apply|KCModule.Reset)
|
||
|
self.aboutdata = MakeAboutData()
|
||
|
|
||
|
# This line has the effect of hiding the "Admin only" message and also forcing
|
||
|
# the Apply/Reset buttons to be shown. Yippie! Only had to read the source
|
||
|
# to work that out.
|
||
|
self.setUseRootOnlyMsg(False)
|
||
|
|
||
|
# Create a configuration object.
|
||
|
self.config = KConfig("displayconfigrc")
|
||
|
|
||
|
# Compact mode means that we have to make the GUI
|
||
|
# much smaller to fit on low resolution screens.
|
||
|
self.compact_mode = kapp.desktop().height()<=600
|
||
|
|
||
|
KGlobal.iconLoader().addAppDir("guidance")
|
||
|
|
||
|
global imagedir
|
||
|
imagedir = unicode(KGlobal.dirs().findDirs("data","guidance/pics/displayconfig")[0])
|
||
|
|
||
|
self.imagedir = imagedir
|
||
|
|
||
|
self.xconfigchanged = False
|
||
|
self.xconfigtested = True
|
||
|
|
||
|
self.availabletargetgammas = [unicode(i18n('1.4')),unicode(i18n('1.6')),unicode(i18n('1.8')),unicode(i18n('2.0')),unicode(i18n('2.2')),unicode(i18n('2.4'))]
|
||
|
self.lightimages = []
|
||
|
self.mediumimages = []
|
||
|
self.darkimages = []
|
||
|
|
||
|
# X Server stuff
|
||
|
self.xf86server = xf86misc.XF86Server()
|
||
|
|
||
|
self.xconfigpath = self._findXorgConfig()
|
||
|
SetDataFileDir(unicode(KGlobal.dirs().findResourceDir("data","guidance/pcitable")) + "guidance/")
|
||
|
self.xsetup = XSetup(self.xconfigpath)
|
||
|
|
||
|
self.updatingGUI = True
|
||
|
self.gfxcarddb = GfxCardModelDB()
|
||
|
self.monitordb = GetMonitorModelDB()
|
||
|
self.monitormodedb = GetMonitorModeDB()
|
||
|
|
||
|
self._buildGUI()
|
||
|
|
||
|
# Work out if the currently running Gfxdriver is safe enough that we
|
||
|
# can test other drivers at the same time.
|
||
|
self.badfbrestore = self._badFbRestore()
|
||
|
self.testbutton.setEnabled(isroot and not self._badFbRestore())
|
||
|
if isroot and not self._badFbRestore():
|
||
|
self.testunavailablelabel.hide()
|
||
|
else:
|
||
|
self.testunavailablelabel.show()
|
||
|
|
||
|
# Load up some of our databases, and initialise our state variables.
|
||
|
if len(self.xsetup.getUsedScreens()):
|
||
|
self.currentsizescreen = self.xsetup.getUsedScreens()[0]
|
||
|
self.currentgammascreen = self.xsetup.getUsedScreens()[0]
|
||
|
else:
|
||
|
# FIXME
|
||
|
print "Houston, we have a problem: No screens found in configuration file, exiting. :("
|
||
|
sys.exit(1)
|
||
|
|
||
|
self.monitordialog.setMonitorDB(self.monitordb)
|
||
|
|
||
|
self.aboutus = KAboutApplication(self)
|
||
|
|
||
|
# For centering the timed Apply dialog.
|
||
|
self.applytimerdialog = None
|
||
|
self.connect(kapp.desktop(), SIGNAL("resized(int)"), self.slotDesktopResized)
|
||
|
self.applydialogscreenindex = 0
|
||
|
|
||
|
self.__loadImages()
|
||
|
self._loadConfig()
|
||
|
self._syncGUI()
|
||
|
|
||
|
if standalone:
|
||
|
self.enableButton(KDialogBase.User1,False) # Reset button
|
||
|
self.enableButtonApply(False) # Apply button
|
||
|
|
||
|
self.updatingGUI = False
|
||
|
|
||
|
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
|
||
|
|
||
|
def _buildGUI(self):
|
||
|
global standalone
|
||
|
if not standalone:
|
||
|
toplayout = QVBoxLayout( self, 0, KDialog.spacingHint() )
|
||
|
tabcontrol = QTabWidget(self)
|
||
|
toplayout.addWidget(tabcontrol)
|
||
|
toplayout.setStretchFactor(tabcontrol,1)
|
||
|
|
||
|
#--- Size, Orientation and Positioning ---
|
||
|
tabname = i18n("Size, Orientation && Positioning")
|
||
|
if standalone:
|
||
|
sopage = self.addGridPage(1,QGrid.Horizontal,tabname)
|
||
|
sopage.setSpacing(0)
|
||
|
self.SizePage = SizeOrientationPage(sopage,self.xsetup,self.compact_mode)
|
||
|
else:
|
||
|
self.SizePage = SizeOrientationPage(tabcontrol,self.xsetup,self.compact_mode)
|
||
|
self.SizePage.setMargin(KDialog.marginHint())
|
||
|
|
||
|
# Connect all PYSIGNALs from SizeOrientationPage Widget to appropriate actions.
|
||
|
self.connect(self.SizePage,PYSIGNAL("changedSignal()"),self._sendChangedSignal)
|
||
|
self.connect(self.SizePage,PYSIGNAL("resolutionChange(int)"),self.slotResolutionChange)
|
||
|
|
||
|
if not standalone:
|
||
|
tabcontrol.addTab(self.SizePage,tabname)
|
||
|
|
||
|
#--- Color & Gamma tab ---
|
||
|
tabname = i18n("Color && Gamma")
|
||
|
if standalone:
|
||
|
gammapage = self.addVBoxPage(tabname)
|
||
|
vbox = QVBox(gammapage)
|
||
|
else:
|
||
|
vbox = QVBox(tabcontrol)
|
||
|
vbox.setMargin(KDialog.marginHint())
|
||
|
vbox.setSpacing(KDialog.spacingHint())
|
||
|
|
||
|
hbox = QHBox(vbox)
|
||
|
hbox.setSpacing(KDialog.spacingHint())
|
||
|
vbox.setStretchFactor(hbox,0)
|
||
|
label = QLabel(hbox,"textLabel1")
|
||
|
label.setText(i18n("Screen:"))
|
||
|
hbox.setStretchFactor(label,0)
|
||
|
self.gammadisplaycombobox = QComboBox(0,hbox,"comboBox11")
|
||
|
hbox.setStretchFactor(self.gammadisplaycombobox,0)
|
||
|
spacer = QWidget(hbox)
|
||
|
hbox.setStretchFactor(spacer,1)
|
||
|
self.connect(self.gammadisplaycombobox,SIGNAL("activated(int)"),self.slotGammaScreenCombobox)
|
||
|
|
||
|
# fill the combobox.
|
||
|
for screen in self.xsetup.getUsedScreens():
|
||
|
self.gammadisplaycombobox.insertItem(screen.getName())
|
||
|
|
||
|
if not self.compact_mode:
|
||
|
# Create the colour matching pics
|
||
|
label = QLabel(vbox)
|
||
|
label.setText(i18n("Color calibration image:"))
|
||
|
vbox.setStretchFactor(label,0)
|
||
|
|
||
|
hbox = QWidget(vbox)
|
||
|
hboxlayout = QHBoxLayout(hbox)
|
||
|
hboxlayout.setSpacing(KDialog.spacingHint())
|
||
|
self.mediumpic = QLabel(hbox)
|
||
|
self.mediumpic.setFixedSize(305,105)
|
||
|
hboxlayout.addWidget(self.mediumpic,0,Qt.AlignTop)
|
||
|
|
||
|
label = QLabel(hbox)
|
||
|
label.setPixmap(SmallIcon('info'))
|
||
|
hboxlayout.addWidget(label,0,Qt.AlignTop)
|
||
|
|
||
|
label = QLabel(i18n("<qt><p>Gamma controls how your monitor displays colors.</p><p>For accurate color reproduction, adjust the gamma correction sliders until the squares blend into the background as much as possible.</p></qt>"),hbox)
|
||
|
label.setTextFormat(Qt.RichText)
|
||
|
hboxlayout.addWidget(label,1,Qt.AlignTop)
|
||
|
|
||
|
sliderspace = QWidget(vbox)
|
||
|
|
||
|
grid = QGridLayout(sliderspace, 9, 4, 0, KDialog.spacingHint())
|
||
|
grid.setSpacing(KDialog.spacingHint())
|
||
|
grid.setColStretch(0,0)
|
||
|
grid.setColStretch(1,0)
|
||
|
grid.setColStretch(2,0)
|
||
|
grid.setColStretch(3,1)
|
||
|
|
||
|
label = QLabel(i18n("Gamma correction:"),sliderspace)
|
||
|
grid.addWidget(label, 0, 0)
|
||
|
|
||
|
self.gammaradiogroup = QButtonGroup()
|
||
|
self.gammaradiogroup.setRadioButtonExclusive(True)
|
||
|
self.connect(self.gammaradiogroup,SIGNAL("clicked(int)"),self.slotGammaRadioClicked)
|
||
|
|
||
|
self.allradio = QRadioButton(sliderspace)
|
||
|
grid.addWidget(self.allradio, 0, 1, Qt.AlignTop)
|
||
|
|
||
|
label = QLabel(i18n("All:"),sliderspace)
|
||
|
grid.addWidget(label, 0, 2)
|
||
|
|
||
|
self.gammaslider = KDoubleNumInput(0.4, 3.5, 2.0, 0.05, 2, sliderspace, 'gammaslider')
|
||
|
grid.addMultiCellWidget(self.gammaslider,0,1,3,3)
|
||
|
self.gammaslider.setRange(0.5, 2.5, 0.05, True)
|
||
|
self.connect(self.gammaslider, SIGNAL("valueChanged(double)"), self.slotGammaChanged)
|
||
|
|
||
|
self.componentradio = QRadioButton(sliderspace)
|
||
|
grid.addWidget(self.componentradio, 2, 1, Qt.AlignTop)
|
||
|
|
||
|
label = QLabel(i18n("Red:"),sliderspace)
|
||
|
grid.addWidget(label, 2, 2)
|
||
|
|
||
|
self.redslider = KDoubleNumInput(self.gammaslider,0.4, 3.5, 2.0, 0.05, 2, sliderspace, 'redslider')
|
||
|
grid.addMultiCellWidget(self.redslider,2,3,3,3)
|
||
|
self.redslider.setRange(0.5, 2.5, 0.05, True)
|
||
|
self.connect(self.redslider, SIGNAL("valueChanged(double)"), self.slotRedChanged)
|
||
|
|
||
|
label = QLabel(i18n("Green:"),sliderspace)
|
||
|
grid.addWidget(label, 4, 2)
|
||
|
|
||
|
self.greenslider = KDoubleNumInput(self.redslider,0.4, 3.5, 2.0, 0.05, 2, sliderspace, 'greenslider')
|
||
|
grid.addMultiCellWidget(self.greenslider,4,5,3,3)
|
||
|
self.greenslider.setRange(0.5, 2.5, 0.05, True)
|
||
|
self.connect(self.greenslider, SIGNAL("valueChanged(double)"), self.slotGreenChanged)
|
||
|
|
||
|
label = QLabel(i18n("Blue:"),sliderspace)
|
||
|
grid.addWidget(label, 6, 2)
|
||
|
|
||
|
self.blueslider = KDoubleNumInput(self.greenslider,0.4, 3.5, 2.0, 0.05, 2, sliderspace, 'blueslider')
|
||
|
grid.addMultiCellWidget(self.blueslider,6,7,3,3)
|
||
|
self.blueslider.setRange(0.5, 2.5, 0.05, True)
|
||
|
self.connect(self.blueslider, SIGNAL("valueChanged(double)"), self.slotBlueChanged)
|
||
|
|
||
|
self.gammaradiogroup.insert(self.allradio,0)
|
||
|
self.gammaradiogroup.insert(self.componentradio,1)
|
||
|
|
||
|
if not self.compact_mode:
|
||
|
label = QLabel(i18n("Target gamma:"),sliderspace)
|
||
|
grid.addWidget(label, 8, 0)
|
||
|
|
||
|
hbox = QHBox(sliderspace)
|
||
|
self.targetgammacombo = KComboBox(False,hbox)
|
||
|
self.targetgammacombo.insertItem(i18n('1.4'))
|
||
|
self.targetgammacombo.insertItem(i18n('1.6'))
|
||
|
self.targetgammacombo.insertItem(i18n('1.8 Apple Macintosh standard'))
|
||
|
self.targetgammacombo.insertItem(i18n('2.0 Recommend'))
|
||
|
self.targetgammacombo.insertItem(i18n('2.2 PC standard, sRGB'))
|
||
|
self.targetgammacombo.insertItem(i18n('2.4'))
|
||
|
hbox.setStretchFactor(self.targetgammacombo,0)
|
||
|
spacer = QWidget(hbox)
|
||
|
hbox.setStretchFactor(spacer,1)
|
||
|
grid.addMultiCellWidget(hbox, 8, 8, 1, 3)
|
||
|
|
||
|
self.connect(self.targetgammacombo,SIGNAL("activated(int)"),self.slotTargetGammaChanged)
|
||
|
|
||
|
spacer = QWidget(vbox)
|
||
|
vbox.setStretchFactor(spacer,1)
|
||
|
|
||
|
if not standalone:
|
||
|
tabcontrol.addTab(vbox,tabname)
|
||
|
|
||
|
#--- Hardware tab ---
|
||
|
if standalone:
|
||
|
hardwarepage = self.addVBoxPage(i18n("Hardware"))
|
||
|
vbox = QVBox(hardwarepage)
|
||
|
else:
|
||
|
vbox = QVBox(tabcontrol)
|
||
|
vbox.setMargin(KDialog.marginHint())
|
||
|
self.gfxcarddialog = GfxCardDialog(None)
|
||
|
self.monitordialog = MonitorDialog(None)
|
||
|
|
||
|
self.xscreenwidgets = []
|
||
|
|
||
|
for gfxcard in self.xsetup.getGfxCards():
|
||
|
w = GfxCardWidget(vbox,self.xsetup, gfxcard, self.gfxcarddialog, self.monitordialog)
|
||
|
self.xscreenwidgets.append(w)
|
||
|
self.connect(w,PYSIGNAL("configChanged"),self.slotConfigChanged)
|
||
|
|
||
|
spacer = QWidget(vbox)
|
||
|
vbox.setStretchFactor(spacer,1)
|
||
|
|
||
|
if not self.xsetup.mayModifyXorgConfig():
|
||
|
QLabel(i18n("Changes on this tab require 'root' access."),vbox)
|
||
|
if not standalone:
|
||
|
QLabel(i18n("Click the \"Administrator Mode\" button to allow modifications on this tab."),vbox)
|
||
|
|
||
|
hbox = QHBox(vbox)
|
||
|
hbox.setSpacing(KDialog.spacingHint())
|
||
|
self.testbutton = KPushButton(i18n("Test"),hbox)
|
||
|
self.connect(self.testbutton,SIGNAL("clicked()"),self.slotTestClicked)
|
||
|
hbox.setStretchFactor(self.testbutton,0)
|
||
|
|
||
|
self.testunavailablelabel = QHBox(hbox)
|
||
|
self.testunavailablelabel.setSpacing(KDialog.spacingHint())
|
||
|
tmplabel = QLabel(self.testunavailablelabel)
|
||
|
self.testunavailablelabel.setStretchFactor(tmplabel,0)
|
||
|
tmplabel.setPixmap(SmallIcon('info'))
|
||
|
label = QLabel(i18n("This configuration cannot be safely tested."),self.testunavailablelabel)
|
||
|
self.testunavailablelabel.setStretchFactor(label,1)
|
||
|
self.testunavailablelabel.hide()
|
||
|
|
||
|
spacer = QWidget(hbox)
|
||
|
hbox.setStretchFactor(spacer,1)
|
||
|
vbox.setStretchFactor(hbox,0)
|
||
|
|
||
|
if not standalone:
|
||
|
tabcontrol.addTab(vbox,i18n("Hardware"))
|
||
|
|
||
|
#--- Display Power Saving ---
|
||
|
tabname = i18n("Power saving")
|
||
|
if standalone:
|
||
|
powerpage = self.addGridPage(1,QGrid.Horizontal,tabname)
|
||
|
self.dpmspage = DpmsPage(powerpage)
|
||
|
else:
|
||
|
self.dpmspage = DpmsPage(tabcontrol)
|
||
|
self.dpmspage.setMargin(KDialog.marginHint())
|
||
|
|
||
|
#self.SizePage.setScreens(self.xsetup.getScreens())
|
||
|
|
||
|
# Connect all PYSIGNALs from SizeOrientationPage Widget to appropriate actions.
|
||
|
#self.connect(self.SizePage,PYSIGNAL("dualheadEnabled(bool)"),self.slotDualheadEnabled)
|
||
|
self.connect(self.dpmspage,PYSIGNAL("changedSignal()"),self._sendChangedSignal)
|
||
|
|
||
|
if not standalone:
|
||
|
tabcontrol.addTab(self.dpmspage,tabname)
|
||
|
|
||
|
def save(self): # KCModule
|
||
|
xorg_config_changed = self.xsetup.isXorgConfigChanged()
|
||
|
restart_recommended = self.xsetup.getRestartHint()
|
||
|
|
||
|
# Check the Size & Orientation tab.
|
||
|
if self.applytimerdialog is None:
|
||
|
self.applytimerdialog = KTimerDialog(15000, KTimerDialog.CountDown, self, "mainKTimerDialog",
|
||
|
True, i18n("Confirm Display Setting Change"), KTimerDialog.Ok | KTimerDialog.Cancel, \
|
||
|
KTimerDialog.Cancel)
|
||
|
self.applytimerdialog.setButtonOK(KGuiItem(i18n("&Keep"), "button_ok"))
|
||
|
self.applytimerdialog.setButtonCancel(KGuiItem(i18n("&Cancel"), "button_cancel"))
|
||
|
label = KActiveLabel(i18n("Trying new screen settings. Keep these new settings? (Automatically cancelling in 15 seconds.)"),
|
||
|
self.applytimerdialog, "userSpecifiedLabel")
|
||
|
self.applytimerdialog.setMainWidget(label)
|
||
|
|
||
|
if self.xsetup.isLiveResolutionConfigChanged():
|
||
|
if self.xsetup.applyLiveResolutionChanges():
|
||
|
# running X server config has changed. Ask the user.
|
||
|
KDialog.centerOnScreen(self.applytimerdialog, 0)
|
||
|
if self.applytimerdialog.exec_loop():
|
||
|
self.xsetup.acceptLiveResolutionChanges()
|
||
|
else:
|
||
|
try:
|
||
|
self.xsetup.rejectLiveResolutionChanges()
|
||
|
except:
|
||
|
"""Workaround! FIXME: Use isGammaLive function in displayconfigabstraction when this is implemented"""
|
||
|
print "Live gamma change not supported"
|
||
|
return
|
||
|
else:
|
||
|
# Nothing really changed, just accept the changes.
|
||
|
self.xsetup.acceptLiveResolutionChanges()
|
||
|
|
||
|
|
||
|
self.xsetup.acceptLiveGammaChanges()
|
||
|
self.dpmspage.apply()
|
||
|
|
||
|
# Save the X server config.
|
||
|
if isroot and xorg_config_changed:
|
||
|
|
||
|
if not self.xconfigtested:
|
||
|
if self.badfbrestore or self._badFbRestore():
|
||
|
if KMessageBox.warningContinueCancel(self, \
|
||
|
i18n("The selected driver and monitor configuration can not be safely tested on this computer.\nContinue with this configuration?"),
|
||
|
i18n("Configuration not tested"))!=KMessageBox.Continue:
|
||
|
return
|
||
|
else:
|
||
|
if KMessageBox.warningContinueCancel(self,
|
||
|
i18n("The selected driver and monitor configuration has not been successfully tested on this computer.\nContinue with this configuration?"),
|
||
|
i18n("Configuration not tested"))!=KMessageBox.Continue:
|
||
|
return
|
||
|
|
||
|
try:
|
||
|
# Backup up the current config file.
|
||
|
i = 1
|
||
|
while os.path.exists("%s.%i" % (self.xconfigpath,i)):
|
||
|
i += 1
|
||
|
try:
|
||
|
shutil.copyfile(self.xconfigpath,"%s.%i" % (self.xconfigpath,i))
|
||
|
except IOError, errmsg:
|
||
|
print "IOError", errmsg, " - while trying to save new xorg.conf - trying to fix"
|
||
|
self.xconfigpath = "/etc/X11/xorg.conf"
|
||
|
xorgfile = open(self.xconfigpath, 'a')
|
||
|
xorgfile.close()
|
||
|
shutil.copyfile(self.xconfigpath,"%s.%i" % (self.xconfigpath,i))
|
||
|
|
||
|
# Write out the new config
|
||
|
tmpfilename = self.xconfigpath + ".tmp"
|
||
|
self.xsetup.writeXorgConfig(tmpfilename)
|
||
|
|
||
|
os.rename(tmpfilename,self.xconfigpath)
|
||
|
except (IOError,TypeError):
|
||
|
print "******* Bang"
|
||
|
raise
|
||
|
return
|
||
|
# FIXME error
|
||
|
|
||
|
# FIXME the instructions in these messages are probably not quite right.
|
||
|
if restart_recommended==XSetup.RESTART_X:
|
||
|
KMessageBox.information(self,
|
||
|
i18n("Some changes require that the X server be restarted before they take effect. Log out and select \"Restart X server\" from the menu button."),
|
||
|
i18n("X Server restart recommend"))
|
||
|
|
||
|
if restart_recommended==XSetup.RESTART_SYSTEM:
|
||
|
KMessageBox.information(self,
|
||
|
i18n("Some changes require that the entire system be restarted before they take effect. Log out and select \"Restart computer\" from the log in screen."),
|
||
|
i18n("System restart recommend"))
|
||
|
|
||
|
self._saveConfig()
|
||
|
self._sendChangedSignal()
|
||
|
|
||
|
# Called when the desktop is resized. Just center the confirm dialog.
|
||
|
def slotDesktopResized(self):
|
||
|
if self.applytimerdialog is not None:
|
||
|
KDialog.centerOnScreen(self.applytimerdialog, self.applydialogscreenindex)
|
||
|
|
||
|
def slotApply(self): # KDialogBase
|
||
|
self.save()
|
||
|
|
||
|
def slotClose(self): # KDialogBase
|
||
|
try:
|
||
|
self.xsetup.rejectLiveGammaChanges()
|
||
|
except:
|
||
|
"""Workaround! FIXME: Use isGammaLive function in displayconfigabstraction when this is implemented"""
|
||
|
print "Live gamma change not supported"
|
||
|
KDialogBase.slotClose(self)
|
||
|
|
||
|
def load(self): # KCModule
|
||
|
self.__reset()
|
||
|
self._sendChangedSignal()
|
||
|
|
||
|
def slotUser1(self): # Reset button, KDialogBase
|
||
|
self.load()
|
||
|
|
||
|
def slotUser2(self): # About button, KDialogBase
|
||
|
self.aboutus.show()
|
||
|
|
||
|
def slotResolutionChange(self,i):
|
||
|
self.currentsizescreen.setResolutionIndex(i)
|
||
|
self._sendChangedSignal()
|
||
|
|
||
|
def slotTargetGammaChanged(self,i):
|
||
|
self.targetgamma = i
|
||
|
self._selectGamma(self.targetgamma)
|
||
|
self._sendChangedSignal()
|
||
|
|
||
|
def slotGammaRadioClicked(self,i):
|
||
|
self.settingall = i==0
|
||
|
self.gammaslider.setDisabled(not self.settingall)
|
||
|
self.redslider.setDisabled(self.settingall)
|
||
|
self.greenslider.setDisabled(self.settingall)
|
||
|
self.blueslider.setDisabled(self.settingall)
|
||
|
try:
|
||
|
if self.settingall:
|
||
|
self.currentgammascreen.setAllGamma(self.currentgammascreen.getAllGamma())
|
||
|
else:
|
||
|
self.currentgammascreen.setRedGamma(self.currentgammascreen.getRedGamma())
|
||
|
self.currentgammascreen.setGreenGamma(self.currentgammascreen.getGreenGamma())
|
||
|
self.currentgammascreen.setBlueGamma(self.currentgammascreen.getBlueGamma())
|
||
|
except:
|
||
|
"""Workaround! FIXME: Use isGammaLive function in displayconfigabstraction when this is implemented"""
|
||
|
print "Live gamma change not supported"
|
||
|
self._sendChangedSignal()
|
||
|
|
||
|
def slotGammaChanged(self,value):
|
||
|
if self.updatingGUI:
|
||
|
return
|
||
|
try:
|
||
|
self.currentgammascreen.setAllGamma(value)
|
||
|
except:
|
||
|
"""Workaround! FIXME: Use isGammaLive function in displayconfigabstraction when this is implemented"""
|
||
|
print "Live gamma change not supported"
|
||
|
self._sendChangedSignal()
|
||
|
|
||
|
def slotRedChanged(self,value):
|
||
|
if self.updatingGUI:
|
||
|
return
|
||
|
try:
|
||
|
self.currentgammascreen.setRedGamma(value)
|
||
|
except:
|
||
|
"""Workaround! FIXME: Use isGammaLive function in displayconfigabstraction when this is implemented"""
|
||
|
print "Live gamma change not supported"
|
||
|
self._sendChangedSignal()
|
||
|
|
||
|
def slotGreenChanged(self,value):
|
||
|
if self.updatingGUI:
|
||
|
return
|
||
|
try:
|
||
|
self.currentgammascreen.setGreenGamma(value)
|
||
|
except:
|
||
|
"""Workaround! FIXME: Use isGammaLive function in displayconfigabstraction when this is implemented"""
|
||
|
print "Live gamma change not supported"
|
||
|
self._sendChangedSignal()
|
||
|
|
||
|
def slotBlueChanged(self,value):
|
||
|
if self.updatingGUI:
|
||
|
return
|
||
|
try:
|
||
|
self.currentgammascreen.setBlueGamma(value)
|
||
|
except:
|
||
|
"""Workaround! FIXME: Use isGammaLive function in displayconfigabstraction when this is implemented"""
|
||
|
print "Live gamma change not supported"
|
||
|
self._sendChangedSignal()
|
||
|
|
||
|
def slotGammaScreenCombobox(self,i):
|
||
|
self.currentgammascreen = self.xsetup.getUsedScreens()[i]
|
||
|
self._syncGUI()
|
||
|
self._sendChangedSignal()
|
||
|
|
||
|
def slotConfigChanged(self):
|
||
|
self.xconfigchanged = True
|
||
|
self.xconfigtested = False
|
||
|
|
||
|
# Check if the current X config can be tested.
|
||
|
self.SizePage._syncGUI()
|
||
|
for widget in self.xscreenwidgets:
|
||
|
widget.syncConfig()
|
||
|
self._syncTestButton()
|
||
|
self._sendChangedSignal()
|
||
|
|
||
|
def slotTestClicked(self):
|
||
|
self.xconfigtested = self.testX()
|
||
|
|
||
|
def testX(self):
|
||
|
|
||
|
self.xserverbin = "/usr/X11R6/bin/XFree86"
|
||
|
if not os.path.isfile(self.xserverbin):
|
||
|
self.xserverbin = "/usr/X11R6/bin/Xorg"
|
||
|
rc = False
|
||
|
|
||
|
# Remove an stale X server lock
|
||
|
try: os.remove("/tmp/.X9-lock")
|
||
|
except OSError: pass
|
||
|
|
||
|
# Try to find a safe tmp dir.
|
||
|
tmp_dir = None
|
||
|
if os.environ.get("TMPDIR") is not None:
|
||
|
tmp_dir = os.environ.get("TMPDIR")
|
||
|
if tmp_dir is None or not os.path.isdir(tmp_dir):
|
||
|
tmp_dir = os.path.join(os.environ.get("HOME"),"tmp")
|
||
|
if not os.path.isdir(tmp_dir):
|
||
|
tmp_dir = "/tmp"
|
||
|
working_tmp_dir = os.path.join(tmp_dir,"guidance."+str(os.getpid()))
|
||
|
error_filename = os.path.join(working_tmp_dir,"testserver.xoutput")
|
||
|
config_filename = os.path.join(working_tmp_dir,"testserver.config")
|
||
|
auth_filename = os.path.join(working_tmp_dir,"xauthority")
|
||
|
|
||
|
# Start the Xserver up with the new config file.
|
||
|
try:
|
||
|
# Create our private dir.
|
||
|
os.mkdir(working_tmp_dir,0700)
|
||
|
|
||
|
# Backup the XAUTHORITY environment variable.
|
||
|
old_xauthority = os.environ.get("XAUTHORITY",None)
|
||
|
|
||
|
# Write out the new config file.
|
||
|
self.xsetup.writeXorgConfig(config_filename)
|
||
|
|
||
|
os.system("xauth -f %s add :9 . `mcookie`" % (auth_filename,) )
|
||
|
# FIXME:: -xf86config is nowhere in man X ??
|
||
|
pid = os.spawnv(os.P_NOWAIT,"/bin/bash",\
|
||
|
["bash","-c","exec %s :9 -xf86config %s -auth %s &> %s" % \
|
||
|
(self.xserverbin, config_filename, auth_filename, error_filename)])
|
||
|
print "Got pid",pid
|
||
|
|
||
|
# Wait for the server to show up.
|
||
|
print str(os.waitpid(pid,os.WNOHANG))
|
||
|
|
||
|
# Use our private xauthority file.
|
||
|
os.environ["XAUTHORITY"] = auth_filename
|
||
|
|
||
|
time.sleep(1) # Wait a sec.
|
||
|
testserver = None
|
||
|
while True:
|
||
|
# Try connecting to the server.
|
||
|
try:
|
||
|
testserver = xf86misc.XF86Server(":9")
|
||
|
break
|
||
|
except xf86misc.XF86Error:
|
||
|
testserver = None
|
||
|
# Check if the server process is still alive.
|
||
|
if os.waitpid(pid,os.WNOHANG) != (0,0):
|
||
|
break
|
||
|
time.sleep(1) # Give the server some more time.
|
||
|
|
||
|
print "checkpoint 1"
|
||
|
print str(testserver)
|
||
|
|
||
|
if testserver is not None:
|
||
|
# Start the timed popup on the :9 display.
|
||
|
#servertestpy = str(KGlobal.dirs().findResource("data","guidance/servertestdialog.py"))
|
||
|
servertestpy = os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])),"servertestdialog.py")
|
||
|
pythonexe = unicode(KStandardDirs.findExe("python"))
|
||
|
|
||
|
testrc = os.system(pythonexe + " " + servertestpy + " '" + auth_filename+"' ")
|
||
|
rc = (rc >> 8) == 0 # Test is good if the return code was 0.
|
||
|
testserver = None
|
||
|
os.kill(pid,signal.SIGINT)
|
||
|
else:
|
||
|
# Server failed, read the error info.
|
||
|
msg = ""
|
||
|
try:
|
||
|
fhandle = open(error_filename,'r')
|
||
|
for line in fhandle.readlines():
|
||
|
if (line.startswith("(EE)") and ("Disabling" not in line)) or line.startswith("Fatal"):
|
||
|
msg += line
|
||
|
msg = unicode(i18n("Messages from the X server:\n")) + msg
|
||
|
except IOError:
|
||
|
msg += unicode(i18n("Sorry, unable to capture the error messages from the X server."))
|
||
|
KMessageBox.detailedSorry(self,i18n("Sorry, this configuration video card driver\nand monitor doesn't appear to work."),msg)
|
||
|
|
||
|
finally:
|
||
|
# Attempt some cleanup before we go.
|
||
|
try: os.remove(error_filename)
|
||
|
except OSError: pass
|
||
|
try: os.remove(config_filename)
|
||
|
except OSError: pass
|
||
|
try: os.remove(auth_filename)
|
||
|
except OSError: pass
|
||
|
try: os.rmdir(working_tmp_dir)
|
||
|
except OSError: pass
|
||
|
|
||
|
if old_xauthority is None:
|
||
|
del os.environ["XAUTHORITY"]
|
||
|
else:
|
||
|
os.environ["XAUTHORITY"] = old_xauthority
|
||
|
|
||
|
return rc
|
||
|
|
||
|
def _syncGUI(self):
|
||
|
self.SizePage._syncGUI()
|
||
|
|
||
|
for gfxcard_widget in self.xscreenwidgets:
|
||
|
gfxcard_widget.syncConfig()
|
||
|
|
||
|
# Sync the gamma tab.
|
||
|
if not self.compact_mode:
|
||
|
self.targetgammacombo.setCurrentItem(self.targetgamma)
|
||
|
self._selectGamma(self.targetgamma)
|
||
|
|
||
|
if self.currentgammascreen.isGammaEqual():
|
||
|
self.gammaradiogroup.setButton(0)
|
||
|
else:
|
||
|
self.gammaradiogroup.setButton(1)
|
||
|
|
||
|
self.gammaslider.setValue(self.currentgammascreen.getAllGamma())
|
||
|
self.redslider.setValue(self.currentgammascreen.getRedGamma())
|
||
|
self.greenslider.setValue(self.currentgammascreen.getGreenGamma())
|
||
|
self.blueslider.setValue(self.currentgammascreen.getBlueGamma())
|
||
|
|
||
|
self.settingall = self.currentgammascreen.isGammaEqual()
|
||
|
self.gammaslider.setDisabled(not self.settingall)
|
||
|
self.redslider.setDisabled(self.settingall)
|
||
|
self.greenslider.setDisabled(self.settingall)
|
||
|
self.blueslider.setDisabled(self.settingall)
|
||
|
self._syncTestButton()
|
||
|
|
||
|
def _syncTestButton(self):
|
||
|
currentbadfbrestore = self._badFbRestore()
|
||
|
self.testbutton.setEnabled(self.xsetup.mayModifyXorgConfig() and not (self.badfbrestore or currentbadfbrestore))
|
||
|
if not isroot or (self.xsetup.mayModifyXorgConfig() and not (self.badfbrestore or currentbadfbrestore)):
|
||
|
self.testunavailablelabel.hide()
|
||
|
else:
|
||
|
self.testunavailablelabel.show()
|
||
|
|
||
|
def _loadConfig(self):
|
||
|
self.config.setGroup("General")
|
||
|
t = self.config.readEntry("targetgamma",unicode(i18n("2.0")))
|
||
|
if t in self.availabletargetgammas:
|
||
|
t = unicode(i18n('2.0'))
|
||
|
self.targetgamma = self.availabletargetgammas.index(t)
|
||
|
|
||
|
def _saveConfig(self):
|
||
|
global isroot
|
||
|
if isroot:
|
||
|
return
|
||
|
self.config.setGroup("General")
|
||
|
self.config.writeEntry("targetgamma",self.availabletargetgammas[self.targetgamma])
|
||
|
for s in self.xsetup.getUsedScreens():
|
||
|
self.config.setGroup("Screen"+str(s.getScreenIndex()))
|
||
|
self._saveRandRConfig(s)
|
||
|
|
||
|
# Write out the gamma values.
|
||
|
if self.settingall:
|
||
|
self.config.writeEntry("redgamma", str(s.getAllGamma()))
|
||
|
self.config.writeEntry("greengamma", str(s.getAllGamma()))
|
||
|
self.config.writeEntry("bluegamma", str(s.getAllGamma()))
|
||
|
else:
|
||
|
self.config.writeEntry("redgamma", str(s.getRedGamma()))
|
||
|
self.config.writeEntry("greengamma", str(s.getGreenGamma()))
|
||
|
self.config.writeEntry("bluegamma", str(s.getBlueGamma()))
|
||
|
|
||
|
self.config.writeEntry("dpmsSeconds", self.dpmspage.seconds)
|
||
|
self.config.writeEntry("dpmsEnabled", ("off","on")[self.dpmspage.enabled])
|
||
|
self.config.sync()
|
||
|
|
||
|
def _saveRandRConfig(self,screen):
|
||
|
w,h = screen.getAvailableResolutions()[screen.getResolutionIndex()]
|
||
|
self.config.writeEntry("width",w)
|
||
|
self.config.writeEntry("height",h)
|
||
|
self.config.writeEntry("reflectX", int( (screen.getReflection() & screen.RR_Reflect_X)!=0) )
|
||
|
self.config.writeEntry("reflectY", int((screen.getReflection() & screen.RR_Reflect_Y)!=0) )
|
||
|
self.config.writeEntry("refresh", screen.getAvailableRefreshRates()[screen.getRefreshRateIndex()])
|
||
|
rotationmap = {screen.RR_Rotate_0: "0", screen.RR_Rotate_90: "90",
|
||
|
screen.RR_Rotate_180:"180", screen.RR_Rotate_270: "270"}
|
||
|
self.config.writeEntry("rotate", rotationmap[screen.getRotation()])
|
||
|
|
||
|
def _selectGamma(self,i):
|
||
|
self.mediumpic.setPixmap(self.mediumimages[i])
|
||
|
|
||
|
def __loadImages(self):
|
||
|
if not self.compact_mode:
|
||
|
for g in ['14','16','18','20','22','24']:
|
||
|
self.mediumimages.append( QPixmap(self.imagedir+'gammapics/MGam'+g+'.png') )
|
||
|
|
||
|
self.previewscreen = QPixmap(self.imagedir+'monitor_screen_1280x1024.png')
|
||
|
self.previewscreenportrait = QPixmap(self.imagedir+'monitor_screen_1024x1280.png')
|
||
|
|
||
|
def __reset(self):
|
||
|
# Reset the screen settings.
|
||
|
self.xsetup.reset()
|
||
|
self.dpmspage.reset()
|
||
|
self._syncGUI()
|
||
|
|
||
|
# Kcontrol expects updates about whether the contents have changed.
|
||
|
# Also we fake the Apply and Reset buttons here when running outside kcontrol.
|
||
|
def _sendChangedSignal(self):
|
||
|
global standalone
|
||
|
|
||
|
changed = False
|
||
|
for s in self.xsetup.getUsedScreens():
|
||
|
changed = changed or s.isResolutionSettingsChanged()
|
||
|
|
||
|
changed = changed or self.xsetup.isXorgConfigChanged()
|
||
|
changed = changed or self.dpmspage.isChanged()
|
||
|
|
||
|
if standalone:
|
||
|
self.enableButton(KDialogBase.User1,changed) # Reset button
|
||
|
self.enableButtonApply(changed) # Apply button
|
||
|
else:
|
||
|
self.emit(SIGNAL("changed(bool)"), (changed,) )
|
||
|
|
||
|
def _badFbRestore(self):
|
||
|
bad_fb_restore = False
|
||
|
for card in self.xsetup.getGfxCards():
|
||
|
bad_fb_restore = bad_fb_restore or \
|
||
|
((card.getGfxCardModel() is not None) and card.getGfxCardModel().getBadFbRestore(card.isProprietaryDriver()))
|
||
|
return bad_fb_restore
|
||
|
|
||
|
############################################################################
|
||
|
class SizeOrientationPage(QWidget):
|
||
|
"""
|
||
|
A TabPage with all the settings for Size and Orientation of the screens,
|
||
|
also features Refreshrates and Dualheadsettings.
|
||
|
|
||
|
Emits the following signals:
|
||
|
|
||
|
changeSignal()
|
||
|
|
||
|
...
|
||
|
|
||
|
TODO:
|
||
|
* Update __doc__ with emitted signals, connect these.
|
||
|
* Choose screen (more than one preview)
|
||
|
* Relative positioning.
|
||
|
* Call setRefreshCombo after switching screens.
|
||
|
"""
|
||
|
def __init__(self,parent,xsetup,compact):
|
||
|
QWidget.__init__(self,parent)
|
||
|
|
||
|
global imagedir
|
||
|
self.xsetup = xsetup
|
||
|
self.imagedir = imagedir
|
||
|
self.parent = parent
|
||
|
self.current_screen = self.xsetup.getPrimaryScreen()
|
||
|
self.current_is_primary = True
|
||
|
self.compact_mode = compact
|
||
|
|
||
|
self._buildGUI()
|
||
|
self._syncGUI()
|
||
|
|
||
|
def _syncGUI(self):
|
||
|
if self.current_is_primary:
|
||
|
self.current_screen = self.xsetup.getPrimaryScreen()
|
||
|
else:
|
||
|
self.current_screen = self.xsetup.getSecondaryScreen()
|
||
|
|
||
|
self._syncGUILayout()
|
||
|
self._syncGUIScreen()
|
||
|
|
||
|
def _syncGUILayout(self):
|
||
|
# Secondary monitor radios.
|
||
|
available_layouts = self.xsetup.getAvailableLayouts()
|
||
|
|
||
|
may = self.xsetup.mayModifyLayout()
|
||
|
|
||
|
self.secondary_clone_radio.setEnabled(may and available_layouts & self.xsetup.LAYOUT_CLONE)
|
||
|
self.secondary_clone_radio.setShown(available_layouts & self.xsetup.LAYOUT_CLONE)
|
||
|
|
||
|
self.secondary_dual_radio.setEnabled(may and available_layouts & self.xsetup.LAYOUT_DUAL)
|
||
|
self.secondary_dual_radio.setShown(available_layouts & self.xsetup.LAYOUT_DUAL)
|
||
|
|
||
|
self.secondary_position_combo.setEnabled(may and self.xsetup.getLayout()==self.xsetup.LAYOUT_DUAL)
|
||
|
self.secondary_position_combo.setShown(available_layouts & self.xsetup.LAYOUT_DUAL)
|
||
|
|
||
|
self.secondary_groupbox.setEnabled(may and available_layouts != self.xsetup.LAYOUT_SINGLE)
|
||
|
# If only the single layout is available, then we just hide the whole radio group
|
||
|
self.secondary_groupbox.setShown(available_layouts!=self.xsetup.LAYOUT_SINGLE)
|
||
|
|
||
|
if self.xsetup.getLayout()!=self.xsetup.LAYOUT_SINGLE:
|
||
|
self.secondary_radios.setButton(self.secondary_option_ids[self.xsetup.getLayout()])
|
||
|
else:
|
||
|
if available_layouts & XSetup.LAYOUT_CLONE:
|
||
|
self.secondary_radios.setButton(self.secondary_option_ids[XSetup.LAYOUT_CLONE])
|
||
|
else:
|
||
|
self.secondary_radios.setButton(self.secondary_option_ids[XSetup.LAYOUT_DUAL])
|
||
|
|
||
|
self.secondary_groupbox.setChecked(self.xsetup.getLayout() != self.xsetup.LAYOUT_SINGLE)
|
||
|
|
||
|
def _syncGUIScreen(self):
|
||
|
# Sync the size tab.
|
||
|
self.resize_slider.setScreen(self.current_screen)
|
||
|
|
||
|
if self.xsetup.getLayout()!=self.xsetup.LAYOUT_DUAL:
|
||
|
self.resize_slider.setTitle(i18n("Screen size"))
|
||
|
else:
|
||
|
self.resize_slider.setTitle(i18n("Screen size #%1").arg(self.xsetup.getUsedScreens().index(self.current_screen)+1))
|
||
|
|
||
|
if self.xsetup.getLayout()==self.xsetup.LAYOUT_DUAL:
|
||
|
if not self.compact_mode:
|
||
|
self.monitor_preview_stack.raiseWidget(self.dual_monitor_preview)
|
||
|
else:
|
||
|
if not self.compact_mode:
|
||
|
self.monitor_preview_stack.raiseWidget(self.monitor_preview)
|
||
|
|
||
|
# Sync the screen orientation.
|
||
|
width,height = self.current_screen.getAvailableResolutions()[self.current_screen.getResolutionIndex()]
|
||
|
|
||
|
if not self.compact_mode:
|
||
|
self.monitor_preview.setResolution(width,height)
|
||
|
|
||
|
if self.current_screen.getRotation()==Screen.RR_Rotate_0:
|
||
|
self.monitor_preview.setRotation(MonitorPreview.ROTATE_0)
|
||
|
elif self.current_screen.getRotation()==Screen.RR_Rotate_90:
|
||
|
self.monitor_preview.setRotation(MonitorPreview.ROTATE_90)
|
||
|
elif self.current_screen.getRotation()==Screen.RR_Rotate_270:
|
||
|
self.monitor_preview.setRotation(MonitorPreview.ROTATE_270)
|
||
|
else:
|
||
|
self.monitor_preview.setRotation(MonitorPreview.ROTATE_180)
|
||
|
|
||
|
self.monitor_preview.setReflectX(self.current_screen.getReflection() & Screen.RR_Reflect_X)
|
||
|
self.monitor_preview.setReflectY(self.current_screen.getReflection() & Screen.RR_Reflect_Y)
|
||
|
|
||
|
# Set the resolutions for the dual screen preview.
|
||
|
if self.xsetup.getAvailableLayouts() & XSetup.LAYOUT_DUAL:
|
||
|
for i in [0,1]:
|
||
|
screen = [self.xsetup.getPrimaryScreen(), self.xsetup.getSecondaryScreen()][i]
|
||
|
width,height = screen.getAvailableResolutions()[screen.getResolutionIndex()]
|
||
|
self.dual_monitor_preview.setScreenResolution(i,width,height)
|
||
|
self.dual_monitor_preview.setPosition(self.xsetup.getDualheadOrientation())
|
||
|
|
||
|
self._fillRefreshCombo()
|
||
|
|
||
|
self.orientation_radio_group.setButton( \
|
||
|
[Screen.RR_Rotate_0, Screen.RR_Rotate_90, Screen.RR_Rotate_270,
|
||
|
Screen.RR_Rotate_180].index(self.current_screen.getRotation()))
|
||
|
# This construct above just maps an rotation to a radiobutton index.
|
||
|
self.mirror_horizontal_checkbox.setChecked(self.current_screen.getReflection() & Screen.RR_Reflect_X)
|
||
|
self.mirror_vertical_checkbox.setChecked(self.current_screen.getReflection() & Screen.RR_Reflect_Y)
|
||
|
|
||
|
width,height = self.current_screen.getAvailableResolutions()[self.current_screen.getResolutionIndex()]
|
||
|
if not self.compact_mode:
|
||
|
self.monitor_preview.setResolution(width,height)
|
||
|
|
||
|
# Enable/disable the resolution/rotation/reflection widgets.
|
||
|
may_edit = self.xsetup.mayModifyResolution()
|
||
|
self.normal_orientation_radio.setEnabled(may_edit)
|
||
|
available_rotations = self.current_screen.getAvailableRotations()
|
||
|
|
||
|
# Hide the whole group box if there is only one boring option.
|
||
|
self.orientation_group_box.setShown(available_rotations!=Screen.RR_Rotate_0)
|
||
|
|
||
|
self.left_orientation_radio.setEnabled(available_rotations & Screen.RR_Rotate_90 and may_edit)
|
||
|
self.left_orientation_radio.setShown(available_rotations & Screen.RR_Rotate_90)
|
||
|
|
||
|
self.right_orientation_radio.setEnabled(available_rotations & Screen.RR_Rotate_270 and may_edit)
|
||
|
self.right_orientation_radio.setShown(available_rotations & Screen.RR_Rotate_270)
|
||
|
|
||
|
self.upside_orientation_radio.setEnabled(available_rotations & Screen.RR_Rotate_180 and may_edit)
|
||
|
self.upside_orientation_radio.setShown(available_rotations & Screen.RR_Rotate_180)
|
||
|
|
||
|
self.mirror_horizontal_checkbox.setEnabled(available_rotations & Screen.RR_Reflect_X and may_edit)
|
||
|
self.mirror_horizontal_checkbox.setShown(available_rotations & Screen.RR_Reflect_X)
|
||
|
|
||
|
self.mirror_vertical_checkbox.setEnabled(available_rotations & Screen.RR_Reflect_Y and may_edit)
|
||
|
self.mirror_vertical_checkbox.setShown(available_rotations & Screen.RR_Reflect_Y)
|
||
|
|
||
|
self.resize_slider.setEnabled(may_edit)
|
||
|
self.size_refresh_combo.setEnabled(may_edit)
|
||
|
|
||
|
# Set the dual orientation combo.
|
||
|
self.secondary_position_combo.setCurrentItem(
|
||
|
[XSetup.POSITION_LEFTOF,
|
||
|
XSetup.POSITION_RIGHTOF,
|
||
|
XSetup.POSITION_ABOVE,
|
||
|
XSetup.POSITION_BELOW].index(self.xsetup.getDualheadOrientation()))
|
||
|
|
||
|
def _fillRefreshCombo(self):
|
||
|
# Update refresh combobox
|
||
|
self.size_refresh_combo.clear()
|
||
|
for rate in self.current_screen.getAvailableRefreshRates():
|
||
|
self.size_refresh_combo.insertItem(i18n("%1 Hz").arg(rate))
|
||
|
self.size_refresh_combo.setCurrentItem(self.current_screen.getRefreshRateIndex())
|
||
|
self.current_screen.setRefreshRateIndex(self.size_refresh_combo.currentItem())
|
||
|
|
||
|
def slotMonitorFocussed(self,currentMonitor):
|
||
|
if currentMonitor==0:
|
||
|
self.current_screen = self.xsetup.getPrimaryScreen()
|
||
|
self.current_is_primary = True
|
||
|
else:
|
||
|
self.current_screen = self.xsetup.getSecondaryScreen()
|
||
|
self.current_is_primary = False
|
||
|
|
||
|
self._syncGUIScreen()
|
||
|
|
||
|
def _sendChangedSignal(self):
|
||
|
self.emit(PYSIGNAL("changedSignal()"),())
|
||
|
|
||
|
def _buildGUI(self):
|
||
|
""" Assemble all GUI elements """
|
||
|
# Layout stuff.
|
||
|
top_layout = QHBoxLayout(self,0,KDialog.spacingHint())
|
||
|
self.top_layout = top_layout
|
||
|
|
||
|
# -- Left column with orientation and dualhead box.
|
||
|
vbox = QVBox(self)
|
||
|
top_layout.addWidget(vbox,0)
|
||
|
|
||
|
# -- Orientation group
|
||
|
self.orientation_group_box = QVGroupBox(vbox)
|
||
|
self.orientation_group_box.setTitle(i18n("Monitor Orientation"))
|
||
|
self.orientation_group_box.setInsideSpacing(KDialog.spacingHint())
|
||
|
self.orientation_group_box.setInsideMargin(KDialog.marginHint())
|
||
|
self.orientation_radio_group = QButtonGroup()
|
||
|
self.orientation_radio_group.setRadioButtonExclusive(True)
|
||
|
|
||
|
self.normal_orientation_radio = QRadioButton(self.orientation_group_box)
|
||
|
self.normal_orientation_radio.setText(i18n("Normal"))
|
||
|
self.left_orientation_radio = QRadioButton(self.orientation_group_box)
|
||
|
self.left_orientation_radio .setText(i18n("Left edge on top"))
|
||
|
self.right_orientation_radio = QRadioButton(self.orientation_group_box)
|
||
|
self.right_orientation_radio.setText(i18n("Right edge on top"))
|
||
|
self.upside_orientation_radio = QRadioButton(self.orientation_group_box)
|
||
|
self.upside_orientation_radio.setText(i18n("Upsidedown"))
|
||
|
|
||
|
self.mirror_horizontal_checkbox = QCheckBox(self.orientation_group_box)
|
||
|
self.mirror_horizontal_checkbox.setText(i18n("Mirror horizontally"))
|
||
|
self.connect(self.mirror_horizontal_checkbox,SIGNAL("toggled(bool)"),self.slotMirrorHorizontallyToggled)
|
||
|
|
||
|
self.mirror_vertical_checkbox = QCheckBox(self.orientation_group_box)
|
||
|
self.mirror_vertical_checkbox.setText(i18n("Mirror vertically"))
|
||
|
self.connect(self.mirror_vertical_checkbox,SIGNAL("toggled(bool)"),self.slotMirrorVerticallyToggled)
|
||
|
|
||
|
self.orientation_radio_group.insert(self.normal_orientation_radio,0)
|
||
|
self.orientation_radio_group.insert(self.left_orientation_radio,1)
|
||
|
self.orientation_radio_group.insert(self.right_orientation_radio,2)
|
||
|
self.orientation_radio_group.insert(self.upside_orientation_radio,3)
|
||
|
self.connect(self.orientation_radio_group,SIGNAL("clicked(int)"),self.slotOrientationRadioClicked)
|
||
|
|
||
|
# -- Dualhead Box.
|
||
|
self.secondary_groupbox = QVGroupBox(vbox)
|
||
|
self.secondary_groupbox.setCheckable(True)
|
||
|
self.secondary_groupbox.setTitle(i18n("Second screen"))
|
||
|
self.connect(self.secondary_groupbox,SIGNAL("toggled(bool)"),self.slotSecondMonitorToggled)
|
||
|
|
||
|
self.secondary_radios = QVButtonGroup(None) # Invisible
|
||
|
self.connect(self.secondary_radios,SIGNAL("pressed(int)"),self.slotSecondMonitorRadioPressed)
|
||
|
|
||
|
self.secondary_options = {}
|
||
|
self.secondary_option_ids = {}
|
||
|
|
||
|
# Clone radio
|
||
|
self.secondary_clone_radio = QRadioButton(i18n("Clone primary screen"),self.secondary_groupbox)
|
||
|
radio_id = self.secondary_radios.insert(self.secondary_clone_radio)
|
||
|
self.secondary_options[radio_id] = self.xsetup.LAYOUT_CLONE
|
||
|
self.secondary_option_ids[self.xsetup.LAYOUT_CLONE] = radio_id
|
||
|
|
||
|
# Dual radio
|
||
|
self.secondary_dual_radio = QRadioButton(i18n("Dual screen"),self.secondary_groupbox)
|
||
|
radio_id = self.secondary_radios.insert(self.secondary_dual_radio)
|
||
|
self.secondary_options[radio_id] = self.xsetup.LAYOUT_DUAL
|
||
|
self.secondary_option_ids[self.xsetup.LAYOUT_DUAL] = radio_id
|
||
|
|
||
|
self.secondary_radios.setButton(radio_id)
|
||
|
|
||
|
hbox = QHBox(self.secondary_groupbox)
|
||
|
spacer = QWidget(hbox)
|
||
|
spacer.setFixedSize(20,1)
|
||
|
hbox.setStretchFactor(spacer,0)
|
||
|
|
||
|
self.secondary_position_combo = QComboBox(0,hbox,"")
|
||
|
self.secondary_position_combo.insertItem(i18n("1 left of 2"))
|
||
|
self.secondary_position_combo.insertItem(i18n("1 right of 2"))
|
||
|
self.secondary_position_combo.insertItem(i18n("1 above 2"))
|
||
|
self.secondary_position_combo.insertItem(i18n("1 below 2"))
|
||
|
self.connect(self.secondary_position_combo,SIGNAL("activated(int)"),self.slotSecondaryPositionChange)
|
||
|
|
||
|
spacer = QWidget(vbox)
|
||
|
vbox.setStretchFactor(spacer,1)
|
||
|
|
||
|
vbox = QVBox(self)
|
||
|
top_layout.addWidget(vbox,1)
|
||
|
|
||
|
if not self.compact_mode:
|
||
|
# -- Right columns with preview, size and refresh widgets.
|
||
|
|
||
|
# -- Preview Box.
|
||
|
self.monitor_preview_stack = QWidgetStack(vbox)
|
||
|
|
||
|
self.monitor_preview = MonitorPreview(self.monitor_preview_stack,self.imagedir)
|
||
|
self.monitor_preview_stack.addWidget(self.monitor_preview)
|
||
|
self.connect(self.monitor_preview,PYSIGNAL("focussed()"),self.slotMonitorFocussed)
|
||
|
|
||
|
self.dual_monitor_preview = DualMonitorPreview(self.monitor_preview_stack, DUAL_PREVIEW_SIZE, self.imagedir)
|
||
|
|
||
|
self.monitor_preview_stack.addWidget(self.dual_monitor_preview)
|
||
|
self.connect(self.dual_monitor_preview,PYSIGNAL("pressed()"),self.slotMonitorFocussed)
|
||
|
self.connect(self.dual_monitor_preview,PYSIGNAL("positionChanged()"),self.slotDualheadPreviewPositionChanged)
|
||
|
|
||
|
# -- Size & Refresh Box.
|
||
|
if not self.compact_mode:
|
||
|
hbox = QHBox(vbox)
|
||
|
else:
|
||
|
hbox = QVBox(vbox)
|
||
|
hbox.setSpacing(KDialog.spacingHint())
|
||
|
|
||
|
self.resize_slider = ResizeSlider(hbox)
|
||
|
self.connect(self.resize_slider,PYSIGNAL("resolutionChange(int)"),self.slotResolutionChange)
|
||
|
|
||
|
hbox2 = QHBox(hbox)
|
||
|
self.refresh_label = QLabel(hbox2,"RefreshLabel")
|
||
|
self.refresh_label.setText(i18n("Refresh:"))
|
||
|
|
||
|
self.size_refresh_combo = QComboBox(0,hbox2,"comboBox1") # gets filled in setRefreshRates()
|
||
|
self.connect(self.size_refresh_combo,SIGNAL("activated(int)"),self.slotRefreshRateChange)
|
||
|
if self.compact_mode:
|
||
|
spacer = QWidget(hbox2)
|
||
|
hbox2.setStretchFactor(spacer,1)
|
||
|
|
||
|
spacer = QWidget(vbox)
|
||
|
vbox.setStretchFactor(spacer,1)
|
||
|
|
||
|
self.clearWState(Qt.WState_Polished)
|
||
|
|
||
|
def setNotification(self,text):
|
||
|
self.notify.setText(text)
|
||
|
|
||
|
def slotOrientationRadioClicked(self,i):
|
||
|
self.current_screen.setRotation(
|
||
|
[Screen.RR_Rotate_0, Screen.RR_Rotate_90,Screen.RR_Rotate_270, Screen.RR_Rotate_180][i])
|
||
|
|
||
|
if self.current_screen.getRotation()==Screen.RR_Rotate_0:
|
||
|
self.monitor_preview.setRotation(MonitorPreview.ROTATE_0)
|
||
|
elif self.current_screen.getRotation()==Screen.RR_Rotate_90:
|
||
|
self.monitor_preview.setRotation(MonitorPreview.ROTATE_90)
|
||
|
elif self.current_screen.getRotation()==Screen.RR_Rotate_270:
|
||
|
self.monitor_preview.setRotation(MonitorPreview.ROTATE_270)
|
||
|
else:
|
||
|
self.monitor_preview.setRotation(MonitorPreview.ROTATE_180)
|
||
|
|
||
|
self._sendChangedSignal()
|
||
|
|
||
|
def slotMirrorHorizontallyToggled(self,flag):
|
||
|
# Bit flippin'
|
||
|
if flag:
|
||
|
self.current_screen.setReflection(self.current_screen.getReflection() | Screen.RR_Reflect_X)
|
||
|
else:
|
||
|
self.current_screen.setReflection(self.current_screen.getReflection() & ~Screen.RR_Reflect_X)
|
||
|
self.monitor_preview.setReflectX(flag)
|
||
|
self._sendChangedSignal()
|
||
|
|
||
|
def slotMirrorVerticallyToggled(self,flag):
|
||
|
# Bit flippin'
|
||
|
if flag:
|
||
|
self.current_screen.setReflection(self.current_screen.getReflection() | Screen.RR_Reflect_Y)
|
||
|
else:
|
||
|
self.current_screen.setReflection(self.current_screen.getReflection() & ~Screen.RR_Reflect_Y)
|
||
|
self.monitor_preview.setReflectY(flag)
|
||
|
self._sendChangedSignal()
|
||
|
|
||
|
def slotResolutionChange(self,i):
|
||
|
self.current_screen.setResolutionIndex(i)
|
||
|
width,height = self.current_screen.getAvailableResolutions()[i]
|
||
|
|
||
|
if not self.compact_mode:
|
||
|
self.monitor_preview.setResolution(width,height)
|
||
|
self.dual_monitor_preview.setScreenResolution(
|
||
|
self.xsetup.getUsedScreens().index(self.current_screen),
|
||
|
width,height)
|
||
|
|
||
|
self._fillRefreshCombo()
|
||
|
self._sendChangedSignal()
|
||
|
|
||
|
def slotRefreshRateChange(self,index):
|
||
|
self.current_screen.setRefreshRateIndex(index)
|
||
|
self._sendChangedSignal()
|
||
|
|
||
|
def setScreen(self,screen):
|
||
|
self.current_screen = screen
|
||
|
self._syncGUI()
|
||
|
|
||
|
def slotSecondMonitorToggled(self,enabled):
|
||
|
if enabled:
|
||
|
pressed_id = self.secondary_radios.selectedId()
|
||
|
self.xsetup.setLayout(self.secondary_options[pressed_id])
|
||
|
else:
|
||
|
self.xsetup.setLayout(self.xsetup.LAYOUT_SINGLE)
|
||
|
|
||
|
if self.xsetup.getLayout()!=self.xsetup.LAYOUT_DUAL:
|
||
|
self.current_screen = self.xsetup.getUsedScreens()[0]
|
||
|
|
||
|
self.secondary_position_combo.setEnabled(self.xsetup.getLayout()==XSetup.LAYOUT_DUAL)
|
||
|
|
||
|
self._syncGUIScreen()
|
||
|
self._sendChangedSignal()
|
||
|
|
||
|
def slotSecondMonitorRadioPressed(self,pressedId):
|
||
|
self.xsetup.setLayout(self.secondary_options[pressedId])
|
||
|
|
||
|
if self.xsetup.getLayout()!=XSetup.LAYOUT_DUAL:
|
||
|
self.current_screen = self.xsetup.getUsedScreens()[0]
|
||
|
|
||
|
self.secondary_position_combo.setEnabled(self.xsetup.getLayout()==XSetup.LAYOUT_DUAL)
|
||
|
|
||
|
if self.xsetup.getLayout()==XSetup.LAYOUT_DUAL:
|
||
|
if not self.compact_mode:
|
||
|
self.monitor_preview_stack.raiseWidget(self.dual_monitor_preview)
|
||
|
else:
|
||
|
if not self.compact_mode:
|
||
|
self.monitor_preview_stack.raiseWidget(self.monitor_preview)
|
||
|
|
||
|
self._syncGUIScreen()
|
||
|
self._sendChangedSignal()
|
||
|
|
||
|
def slotSecondaryPositionChange(self,index):
|
||
|
position = [XSetup.POSITION_LEFTOF,XSetup.POSITION_RIGHTOF,XSetup.POSITION_ABOVE,XSetup.POSITION_BELOW][index]
|
||
|
self.xsetup.setDualheadOrientation(position)
|
||
|
self.dual_monitor_preview.setPosition(position)
|
||
|
self._sendChangedSignal()
|
||
|
|
||
|
def slotDualheadPreviewPositionChanged(self,position):
|
||
|
self.xsetup.setDualheadOrientation(position)
|
||
|
index = {
|
||
|
XSetup.POSITION_LEFTOF:0,
|
||
|
XSetup.POSITION_RIGHTOF:1,
|
||
|
XSetup.POSITION_ABOVE:2,
|
||
|
XSetup.POSITION_BELOW:3
|
||
|
}[position]
|
||
|
self.secondary_position_combo.setCurrentItem(index)
|
||
|
self._sendChangedSignal()
|
||
|
|
||
|
def setMargin(self,margin):
|
||
|
self.top_layout.setMargin(margin)
|
||
|
|
||
|
def setSpacing(self,spacing):
|
||
|
self.top_layout.setSpacing(spacing)
|
||
|
|
||
|
############################################################################
|
||
|
class DpmsPage(QWidget):
|
||
|
|
||
|
# Mapping values in seconds to human-readable labels.
|
||
|
intervals = (
|
||
|
(60,i18n("1 minute")),
|
||
|
(120,i18n("2 minutes")),
|
||
|
(180,i18n("3 minutes")),
|
||
|
(300,i18n("5 minutes")),
|
||
|
(600,i18n("10 minutes")),
|
||
|
(900,i18n("15 minutes")),
|
||
|
(1200,i18n("20 minutes")),
|
||
|
(1500,i18n("25 minutes")),
|
||
|
(1800,i18n("30 minutes")),
|
||
|
(2700,i18n("45 minutes")),
|
||
|
(3600,i18n("1 hour")),
|
||
|
(7200,i18n("2 hours")),
|
||
|
(10800,i18n("3 hours")),
|
||
|
(14400,i18n("4 hours")),
|
||
|
(18000,i18n("5 hours")))
|
||
|
|
||
|
def __init__(self,parent = None,name = None,modal = 0,fl = 0):
|
||
|
global imagedir
|
||
|
QWidget.__init__(self,parent)
|
||
|
|
||
|
# Where to find xset.
|
||
|
self.xset_bin = os.popen('which xset').read()[:-1]
|
||
|
|
||
|
if not name:
|
||
|
self.setName("DPMSTab")
|
||
|
|
||
|
dpms_tab_layout = QVBoxLayout(self,0,0,"DPMSTabLayout")
|
||
|
self.top_layout = dpms_tab_layout
|
||
|
|
||
|
hbox = QHBox(self)
|
||
|
hbox.setSpacing(KDialog.spacingHint())
|
||
|
|
||
|
dpms_tab_layout.addWidget(hbox)
|
||
|
|
||
|
self.dpmsgroup = QHGroupBox(hbox,"dpmsgroup")
|
||
|
self.dpmsgroup.setInsideSpacing(KDialog.spacingHint())
|
||
|
self.dpmsgroup.setInsideMargin(KDialog.marginHint())
|
||
|
self.dpmsgroup.setTitle(i18n("Enable power saving"))
|
||
|
self.dpmsgroup.setCheckable(1)
|
||
|
|
||
|
self.connect(self.dpmsgroup,SIGNAL("toggled(bool)"),self.slotDpmsToggled)
|
||
|
|
||
|
hbox2 = QHBox(self.dpmsgroup)
|
||
|
hbox2.setSpacing(KDialog.spacingHint())
|
||
|
|
||
|
dpmstext = QLabel(hbox2,"dpmstext")
|
||
|
dpmstext.setText(i18n("Switch off monitor after:"))
|
||
|
|
||
|
self.dpmscombo = QComboBox(0,hbox2,"dpmscombo")
|
||
|
self.fillCombo(self.dpmscombo)
|
||
|
self.connect(self.dpmscombo,SIGNAL("activated(int)"),self.slotDpmsActivated)
|
||
|
|
||
|
spacer = QWidget(hbox2)
|
||
|
hbox2.setStretchFactor(spacer,1)
|
||
|
|
||
|
self.energystarpix = QLabel(hbox,"energystarpix")
|
||
|
self.energystarpix.setSizePolicy(QSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed,0,0,self.energystarpix.sizePolicy().hasHeightForWidth()))
|
||
|
self.energystarpix.setMinimumSize(QSize(150,77))
|
||
|
self.energystarpix.setPixmap(QPixmap(imagedir+"../energystar.png"))
|
||
|
self.energystarpix.setScaledContents(1)
|
||
|
|
||
|
bottomspacer = QSpacerItem(51,160,QSizePolicy.Minimum,QSizePolicy.Expanding)
|
||
|
dpms_tab_layout.addItem(bottomspacer)
|
||
|
|
||
|
self.clearWState(Qt.WState_Polished)
|
||
|
|
||
|
self.readDpms()
|
||
|
|
||
|
def fillCombo(self,combo):
|
||
|
""" Fill the combobox with the values from our list """
|
||
|
for interval in self.intervals:
|
||
|
combo.insertItem(interval[1])
|
||
|
|
||
|
def slotDpmsActivated(self,index):
|
||
|
""" Another dpms value has been chosen, update buttons at bottom. """
|
||
|
self.emit(PYSIGNAL("changedSignal()"), ())
|
||
|
|
||
|
def slotDpmsToggled(self,bool):
|
||
|
""" Dpms checkbox has been toggled, update buttons at bottom. """
|
||
|
self.emit(PYSIGNAL("changedSignal()"), ())
|
||
|
|
||
|
def readDpms(self):
|
||
|
# FIXME it is not the widget's job to read or change the values, just to present the GUI.
|
||
|
""" Read output from xset -q and parse DPMS settings from it. """
|
||
|
# FIXME: localisation problem running this command.
|
||
|
lines = ExecWithCapture(self.xset_bin,[self.xset_bin,'-q']).split('\n')
|
||
|
|
||
|
self.dpms_min = 1800
|
||
|
self.dpms_enabled = False
|
||
|
|
||
|
for line in lines:
|
||
|
if line.strip().startswith("Standby"):
|
||
|
self.dpms_min = int(line.strip().split()[5]) # TODO: More subtle exception handling. ;)
|
||
|
if line.strip().startswith("DPMS is"):
|
||
|
self.dpms_enabled = line.strip().split()[2]=="Enabled"
|
||
|
|
||
|
if self.dpms_min==0: # 0 also means don't use Standby mode.
|
||
|
self.dpms_enabled = False
|
||
|
self.dpms_min = 1800
|
||
|
|
||
|
self.dpmsgroup.setChecked(self.dpms_enabled)
|
||
|
|
||
|
for i in range(len(self.intervals)):
|
||
|
diff = abs(self.intervals[i][0] - self.dpms_min)
|
||
|
if i==0:
|
||
|
last_diff = diff
|
||
|
if (last_diff <= diff and i!=0) or (last_diff < diff):
|
||
|
i = i-1
|
||
|
break
|
||
|
last_diff = diff
|
||
|
self.dpmscombo.setCurrentItem(i)
|
||
|
|
||
|
def isChanged(self):
|
||
|
""" Check if something has changed since startup or last apply(). """
|
||
|
if self.dpmsgroup.isChecked():
|
||
|
if self.intervals[self.dpmscombo.currentItem()][0] != self.dpms_min:
|
||
|
return True
|
||
|
if self.dpmsgroup.isChecked() != self.dpms_enabled:
|
||
|
return True
|
||
|
return False
|
||
|
|
||
|
else:
|
||
|
# self.dpmsgroup.isChecked() is False
|
||
|
return self.dpms_enabled # self.dpms_enabled != False
|
||
|
|
||
|
def applyDpms(self):
|
||
|
""" Use xset to apply new dpms settings. """
|
||
|
self.enabled = self.dpmsgroup.isChecked()
|
||
|
self.seconds = self.intervals[self.dpmscombo.currentItem()][0]
|
||
|
if self.enabled:
|
||
|
# Switch dpms on and set timeout interval.
|
||
|
cmd_on = "%s +dpms" % self.xset_bin
|
||
|
cmd_set = "%s dpms %i %i %i" % (self.xset_bin, self.seconds,self.seconds,self.seconds)
|
||
|
print cmd_set
|
||
|
if os.system(cmd_set) != 0:
|
||
|
print "DPMS command failed: ", cmd_set
|
||
|
else:
|
||
|
# Switch dpms off.
|
||
|
cmd_on = "%s -dpms" % self.xset_bin
|
||
|
if os.system(cmd_on) != 0:
|
||
|
print "DPMS command failed: ", cmd_on
|
||
|
self.readDpms()
|
||
|
self.emit(PYSIGNAL("changedSignal()"), ())
|
||
|
|
||
|
def apply(self):
|
||
|
self.applyDpms()
|
||
|
|
||
|
def reset(self):
|
||
|
for i in range(len(self.intervals)):
|
||
|
if self.intervals[i][0] == self.dpms_min:
|
||
|
self.dpmscombo.setCurrentItem(i)
|
||
|
break
|
||
|
|
||
|
self.dpmsgroup.setChecked(self.dpms_enabled)
|
||
|
|
||
|
def setMargin(self,margin):
|
||
|
self.top_layout.setMargin(margin)
|
||
|
|
||
|
def setSpacing(self,spacing):
|
||
|
self.top_layout.setSpacing(spacing)
|
||
|
|
||
|
############################################################################
|
||
|
def create_displayconfig(parent,name):
|
||
|
""" Factory function for KControl """
|
||
|
global kapp
|
||
|
kapp = KApplication.kApplication()
|
||
|
return DisplayApp(parent, name)
|
||
|
|
||
|
############################################################################
|
||
|
def MakeAboutData():
|
||
|
aboutdata = KAboutData("guidance",programname,version, \
|
||
|
"Display and Graphics Configuration Tool", KAboutData.License_GPL, \
|
||
|
"Copyright (C) 2003-2007 Simon Edwards", \
|
||
|
"Thanks go to Phil Thompson, Jim Bublitz and David Boddie.")
|
||
|
aboutdata.addAuthor("Simon Edwards","Developer","simon@simonzone.com", \
|
||
|
"http://www.simonzone.com/software/")
|
||
|
aboutdata.addAuthor("Sebastian Kügler","Developer","sebas@kde.org", \
|
||
|
"http://vizZzion.org");
|
||
|
aboutdata.addCredit("Pete Andrews","Gamma calibration pictures/system",None, \
|
||
|
"http://www.photoscientia.co.uk/Gamma.htm")
|
||
|
return aboutdata
|
||
|
|
||
|
if standalone:
|
||
|
aboutdata = MakeAboutData()
|
||
|
KCmdLineArgs.init(sys.argv,aboutdata)
|
||
|
|
||
|
kapp = KApplication()
|
||
|
|
||
|
displayapp = DisplayApp()
|
||
|
displayapp.exec_loop()
|