summaryrefslogtreecommitdiffstats
path: root/displayconfig/displayconfigabstraction.py
diff options
context:
space:
mode:
Diffstat (limited to 'displayconfig/displayconfigabstraction.py')
-rw-r--r--displayconfig/displayconfigabstraction.py3230
1 files changed, 3230 insertions, 0 deletions
diff --git a/displayconfig/displayconfigabstraction.py b/displayconfig/displayconfigabstraction.py
new file mode 100644
index 0000000..f59b2ff
--- /dev/null
+++ b/displayconfig/displayconfigabstraction.py
@@ -0,0 +1,3230 @@
+#!/usr/bin/env python
+
+import os
+import sys
+import string
+import math
+import subprocess
+import xf86misc
+import xorgconfig
+import ScanPCI
+import csv
+import re
+from execwithcapture import *
+
+"""Classes for dealing with X.org configuration in a sane way.
+
+The object model used here is fairly simple. An XSetup object represents
+the complete configuration of the server. The XSetup object contains one or
+more GfxCard objects. One for each graphics card present in the machine.
+Each GfxCard has one or more Screen objects with each Screen representing
+one 'output' on the graphics card.
+
+Each GfxCard object is also associated with a GfxCardModel object which
+describes the model of graphics card.
+
+Each Screen object is associated with a MonitorModel object which
+describes the model of monitor attached.
+
+"""
+
+FALLBACK_RESOLUTION = (800,600)
+
+# FIXME updating /etc/modules for fglrx.
+data_file_dir = "."
+def SetDataFileDir(dir_name):
+ global data_file_dir
+ data_file_dir = dir_name
+
+var_data_dir = "/var/lib/guidance-backends"
+def SetVarDataDir(dir_name):
+ global var_data_dir
+ var_data_dir = dir_name
+
+############################################################################
+class XSetup(object):
+ """Represents the current configuration of the X.org X11 server.
+
+
+ """
+ # Map positions
+ ABOVE = 0
+ UNDER = 1
+ LEFTOF = 2
+ RIGHTOF = 3
+
+ RESTART_NONE = 0
+ RESTART_X = 1
+ RESTART_SYSTEM = 2
+
+ LAYOUT_SINGLE = 1 # These are bit flags.
+ LAYOUT_CLONE = 2
+ LAYOUT_DUAL = 4
+ LAYOUT_SINGLE_XINERAMA = 256 # For internal use.
+ LAYOUT_CLONE_XINERAMA = 512 # For internal use.
+
+ POSITION_LEFTOF = 0
+ POSITION_RIGHTOF = 1
+ POSITION_ABOVE = 2
+ POSITION_BELOW = 3
+
+ ROLE_UNUSED = 0
+ ROLE_PRIMARY = 1
+ ROLE_SECONDARY = 2
+
+ def __init__(self,xorg_config_filename='/etc/X11/xorg.conf',debug_scan_pci_filename=None,secondtry=False):
+ self.screens = []
+ self.gfxcards = []
+ self.xorg_config, self.hasxorg = xorgconfig.readConfig(xorg_config_filename, check_exists=True)
+ if not secondtry:
+ self.xorg_config_filename = xorg_config_filename
+ if self.xorg_config_filename == None:
+ self.xorg_config_filename = '/etc/X11/xorg.conf';
+ self.x_live_info = xf86misc.XF86Server()
+
+ self.primary_screen = None
+ self.secondary_screen = None
+
+ pci_bus = ScanPCI.PCIBus(data_file_dir)
+ if debug_scan_pci_filename is None:
+ pci_bus.detect()
+ else:
+ pci_bus.loadFromFile(debug_scan_pci_filename)
+
+ # First thing. Scan the PCI bus and find out how many Gfx cards we have.
+ found_list = self._detectGfxCards(pci_bus)
+ # list of (PCI_ID, PCIDevice, GfxCard) tuples
+
+ found_list.sort()
+
+ # Prepare some useful data structures.
+ self.layout = self.LAYOUT_SINGLE
+ self.xinerama = False
+ self.orientation = self.POSITION_LEFTOF
+
+ # Maps screen section names to xorg screens section objects.
+ xorg_screen_name_dict = {}
+ xorg_unused_screen_sections = self.xorg_config.getSections("Screen")
+ for screen in xorg_unused_screen_sections:
+ xorg_screen_name_dict[screen.identifier] = screen
+
+ # Maps device sections names to xorg device sections
+ xorg_device_name_dict = {}
+ xorg_unused_device_sections = self.xorg_config.getSections("Device")
+ for device in xorg_unused_device_sections:
+ xorg_device_name_dict[device.identifier] = device
+
+ # Maps device sections names to xorg device sections
+ xorg_monitor_name_dict = {}
+ xorg_monitor_sections = self.xorg_config.getSections("Monitor")
+ for monitor in xorg_monitor_sections:
+ xorg_monitor_name_dict[monitor.identifier] = monitor
+
+ # Maps GfxCard objects to ScanPCI.PCIDevice objects.
+ gfx_card_pcidevice_dict = {}
+
+ #-------------------------------------------------------------------
+ # Decode the server layout.
+ server_layouts = self.xorg_config.getSections("ServerLayout")
+ if len(server_layouts)==0:
+ print "*** Error: couldn't find any ServerLayout sections"
+ return
+ layout = server_layouts[0] # Grab the first ServerLayout
+
+ if len(layout.screen)==0:
+ print "*** Error: no screens were specified in the ServerLayout section"
+
+ # Handle leftof rightof below and above.
+ (primary_name, secondary_name, layout, self.orientation) = self._decodeServerLayoutScreens(layout.screen)
+
+ screen_list = [primary_name]
+ if secondary_name is not None:
+ screen_list.append(secondary_name)
+
+ for screen_name in screen_list:
+ if screen_name in xorg_screen_name_dict:
+ screen_section = xorg_screen_name_dict[screen_name]
+ if screen_section.device in xorg_device_name_dict:
+
+ device_section = xorg_device_name_dict[screen_section.device]
+
+ # Ok, we've now got a screen section and its device.
+ gfx_card = None
+
+ if device_section.busid is not None:
+ # Try to match this device to a gfxcard by using the PCI bus ID.
+ bus_id = self._canonicalPCIBusID(device_section.busid)
+
+ # See if there is already a known gfxcard at this PCI ID.
+ gfx_card = self.getGfxCardByPCIBusID(bus_id)
+ if gfx_card is not None:
+ # Let the gfxcard know that we have another device section for it to manage.
+ gfx_card._addXDevice(device_section)
+ try:
+ xorg_unused_device_sections.remove(device_section)
+ except ValueError:
+ pass
+ else:
+ # Not known, look for a matching pci device instead.
+ for pci_device_tuple in found_list:
+ if pci_device_tuple[0]==bus_id:
+ # Got a hit, create a gfxcard object.
+ gfx_card = GfxCard( self, pci_id=bus_id, \
+ x_device=device_section, \
+ detected_model=pci_device_tuple[2])
+
+ self.gfxcards.append(gfx_card)
+ gfx_card_pcidevice_dict[gfx_card] = pci_device_tuple[1]
+ xorg_unused_device_sections.remove(device_section)
+ found_list.remove(pci_device_tuple)
+ break
+
+ else:
+
+ # OK, no PCI ID, try matching to a PCI device by X driver name,
+ # or if there is one only gfx card then just grab it.
+ driver_name = device_section.driver
+ for pci_device_tuple in found_list:
+ if pci_device_tuple[2].getDriver()==driver_name \
+ or pci_device_tuple[2].getProprietaryDriver()==driver_name \
+ or len(found_list)==1:
+ # Got a hit, create a gfxcard object.
+ gfx_card = GfxCard( self, pci_id=pci_device_tuple[0], \
+ x_device=device_section, \
+ detected_model=pci_device_tuple[2])
+
+ self.gfxcards.append(gfx_card)
+ gfx_card_pcidevice_dict[gfx_card] = pci_device_tuple[1]
+ xorg_unused_device_sections.remove(device_section)
+ found_list.remove(pci_device_tuple)
+ break
+
+ if gfx_card is not None:
+ # Look up the monitor section from the monitor name.
+ monitor_section = None
+ monitor_model = None
+ if screen_section.monitor in xorg_monitor_name_dict:
+ monitor_section = xorg_monitor_name_dict[screen_section.monitor]
+ monitor_model = self._matchMonitor(monitor_section)
+
+ screen = Screen(x_config_screen=screen_section, gfx_card=gfx_card, \
+ x_config_monitor=monitor_section, monitor_model=monitor_model, \
+ x_config=self.xorg_config)
+ gfx_card._addScreen(screen)
+
+ if self.primary_screen is None:
+ self.primary_screen = screen
+ elif self.secondary_screen is None:
+ self.secondary_screen = screen
+
+ xorg_unused_screen_sections.remove(screen_section)
+
+ if self.primary_screen is not None and self.secondary_screen is not None:
+ self.layout = layout
+
+ #-------------------------------------------------------------------
+ # Dualhead hardware detection.
+ gfx_cards_needing_second_heads = []
+
+ # Detect dualhead ATI cards
+ for pci_device in pci_bus.devices:
+ if pci_device.text is not None and pci_device.text.find("Secondary")!=-1:
+
+ pci_device_id = "PCI:%i:%i:%i" % (pci_device.pci_bus, pci_device.pci_device, pci_device.pci_function)
+
+ for gfx_card in self.gfxcards:
+ if gfx_card.getPCIBusID() != pci_device_id:
+ # Compare the first two numbers that make up a PCI bus id (e.g. middle part of PCI:1:0:0)
+ if gfx_card.getPCIBusID().split(":")[1:-1] == [str(pci_device.pci_bus),str(pci_device.pci_device)]:
+ if len(gfx_card.getScreens())<2:
+ gfx_cards_needing_second_heads.append(gfx_card)
+ found_list = [x for x in found_list if x[0]!=pci_device_id]
+ break
+
+ # Detect dualhead Intel cards
+ for gfx_card in self.gfxcards:
+ if gfx_card._getDetectedGfxCardModel().getDriver() in ['i740','i810', 'intel']:
+ gfx_card_pci_id = gfx_card.getPCIBusID().split(":")[1:]
+ base_pci_id = gfx_card_pci_id[:-1]
+
+ for pci_device in pci_bus.devices:
+ if gfx_card_pci_id != [str(pci_device.pci_bus),str(pci_device.pci_device),str(pci_device.pci_function)]:
+ if base_pci_id == [str(pci_device.pci_bus),str(pci_device.pci_device)]:
+ pci_device_id = "PCI:%i:%i:%i" % (pci_device.pci_bus, pci_device.pci_device, pci_device.pci_function)
+ found_list = [x for x in found_list if x[0]!=pci_device_id]
+ # Try to configure a second head later if not yet available
+ if len(gfx_card.getScreens()) < 2:
+ gfx_cards_needing_second_heads.append(gfx_card)
+ break
+
+ # Detect dualhead nVidia cards
+ for gfx_card in self.gfxcards:
+ if gfx_card._getDetectedGfxCardModel().getDriver() in ['nv','nvidia']:
+ if self._isNVidiaCardDualhead(gfx_card_pcidevice_dict[gfx_card]):
+ if len(gfx_card.getScreens())<2:
+ if gfx_card not in gfx_cards_needing_second_heads:
+ gfx_cards_needing_second_heads.append(gfx_card)
+ continue
+
+ # Detect dualhead Matrox cards. This info is from the Cards+ db.
+ for gfx_card in self.gfxcards:
+ if (gfx_card._getDetectedGfxCardModel().getMultiHead()>1) and (len(gfx_card.getScreens())<2):
+ if gfx_card not in gfx_cards_needing_second_heads:
+ gfx_cards_needing_second_heads.append(gfx_card)
+
+ # Detect laptops. Dualhead/clone mode is standard functionality on laptops.
+ # (but can be hard to detect).
+ if os.path.isfile('/usr/sbin/laptop-detect'):
+ if subprocess.call(['/usr/sbin/laptop-detect'])==0:
+ if len(self.gfxcards)!=0:
+ gfx_card = self.gfxcards[0]
+ if gfx_card not in gfx_cards_needing_second_heads and \
+ len(gfx_card.getScreens())<2:
+ gfx_cards_needing_second_heads.append(gfx_card)
+
+ # Match up the second heads with any loose sections in xorg.conf.
+ for gfx_card in gfx_cards_needing_second_heads:
+ screens = gfx_card.getScreens()
+ # Try to find a loose xorg.conf Screen section that also
+ # references this gfx card. That is probably the config
+ # for the second screen.
+ for screen_section in xorg_unused_screen_sections:
+ if screen_section.device in xorg_device_name_dict:
+ device_section = xorg_device_name_dict[screen_section.device]
+
+ # Is this the second screen for the same PCI device aka gfxcard?
+
+ # Note: even though the second head shows up as a separate PCI ID, the screen
+ # section in xorg.conf still uses the primary PCI ID.
+ if str(device_section.screen)=="1" and \
+ self._canonicalPCIBusID(device_section.busid)==gfx_card.getPCIBusID():
+
+ # Look up the monitor section from the monitor name.
+ monitor_section = None
+ monitor_model = None
+ if screen_section.monitor in xorg_monitor_name_dict:
+ monitor_section = xorg_monitor_name_dict[screen_section.monitor]
+ monitor_model = self._matchMonitor(monitor_section)
+
+ gfx_card._addXDevice(device_section)
+ xorg_unused_device_sections.remove(device_section)
+
+ screen = Screen(x_config_screen=screen_section, gfx_card=gfx_card, \
+ x_config_monitor=monitor_section, monitor_model=monitor_model, \
+ x_config=self.xorg_config)
+ gfx_card._addScreen(screen)
+ self.secondary_screen = screen
+ xorg_unused_screen_sections.remove(screen_section)
+ break
+ else:
+ # Couldn't anything in xorg.conf, just make an empty screen
+ screen = Screen(gfx_card=gfx_card, x_config=self.xorg_config)
+ gfx_card._addScreen(screen)
+
+ #-------------------------------------------------------------------
+ # Handle loose gfx card devices. Check that all PCI gfxcards are accounted for.
+ for pci_device_tuple in found_list:
+
+ bus_id = pci_device_tuple[0]
+ for device_section in xorg_unused_device_sections:
+ if bus_id == self._canonicalPCIBusID(device_section.busid):
+ xorg_unused_device_sections.remove(device_section)
+ break
+ else:
+ device_section = None
+
+ # Got a hit, create a gfxcard object.
+ gfx_card = GfxCard( self, pci_id=pci_device_tuple[0], \
+ x_device=device_section, \
+ detected_model=pci_device_tuple[2])
+
+ gfx_card_pcidevice_dict[gfx_card] = pci_device_tuple[1]
+ self.gfxcards.append(gfx_card)
+
+ screen = None
+ # See if this device section is referenced by a screen section.
+ # if so, then we grab the screen section.
+ if device_section is not None:
+ for screen_section in xorg_unused_screen_sections:
+ if screen_section.device==device_section.identifier:
+
+ # Ok, we have found the screen section, monitor?
+ monitor_section = None
+ monitor_model = None
+ if screen_section.monitor in xorg_monitor_name_dict:
+ monitor_section = xorg_monitor_name_dict[screen_section.monitor]
+ monitor_model = self._matchMonitor(monitor_section)
+
+ screen = Screen(x_config_screen=screen_section, gfx_card=gfx_card, \
+ x_config_monitor=monitor_section, monitor_model=monitor_model, \
+ x_config=self.xorg_config)
+ gfx_card._addScreen(screen)
+ xorg_unused_screen_sections.remove(screen_section)
+ break
+
+ if screen is None:
+ # Manually add a screen.
+ screen = Screen(gfx_card=gfx_card, x_config=self.xorg_config)
+ gfx_card._addScreen(screen)
+
+ #-------------------------------------------------------------------
+ # Sort the gfx cards by PCI id.
+ def gfxcard_pci_sort(a,b): return cmp(a.getPCIBusID(),b.getPCIBusID())
+ self.gfxcards.sort(gfxcard_pci_sort)
+
+ # Hand out some randr live screens
+ x_live_screens = self.x_live_info.getScreens()
+ i = 0
+ for gfx_card in self.gfxcards:
+ for screen in gfx_card.getScreens():
+ if i<len(x_live_screens) and self.getScreenRole(screen)!=XSetup.ROLE_UNUSED:
+ screen._setXLiveScreen(x_live_screens[i])
+ i += 1
+
+ # Ensure that all of the screen roles have been handed out.
+ if self.primary_screen is None:
+ for screen in self.getAllScreens():
+ if screen is not self.secondary_screen:
+ self.primary_screen = screen
+ break
+ if self.secondary_screen is None:
+ for screen in self.getAllScreens():
+ if screen is not self.primary_screen:
+ self.secondary_screen = screen
+ break
+
+ self._finalizeInit()
+
+ if not self.hasxorg and not secondtry:
+ """No xorg.conf, so we need to write a temporary one and reload from that one"""
+ self.writeXorgConfig('/tmp/xorg.conf.displayconfig')
+ self.__init__(xorg_config_filename='/tmp/xorg.conf.displayconfig',secondtry=True)
+ return
+
+ def _finalizeInit(self):
+ for gfxcard in self.gfxcards:
+ gfxcard._finalizeInit()
+
+ # Check the 'layout' on the gfx cards to detect optimised configs.
+ gfxcard = self.primary_screen._getGfxCard()
+ if gfxcard._getDetectedLayout()!=XSetup.LAYOUT_SINGLE:
+ # Something interesting is going on on this gfx card. The
+ # secondary screen is in this case going to actually be the
+ # other 'head' on this gfx card.
+ if gfxcard.getScreens()[0] is not self.primary_screen:
+ self.secondary_screen = gfxcard.getScreens()[0]
+ else:
+ self.secondary_screen = gfxcard.getScreens()[1]
+
+ self.orientation = gfxcard._getDetectedDualheadOrientation()
+ self.setLayout(gfxcard._getDetectedLayout())
+
+ self.setLayout(self.layout) # Propogate any XINERAMA_SINGLE stuff out to the gfxcards.
+ self.original_layout = self.layout
+ self.original_orientation = self.orientation
+ self.original_primary_screen = self.primary_screen
+ self.original_secondary_screen = self.secondary_screen
+
+ def _matchMonitor(self,monitor_section):
+ monitor_model_db = GetMonitorModelDB()
+
+ model_name = monitor_section.modelname
+ if monitor_model_db.getMonitorByName(model_name) is not None:
+ monitor_model = monitor_model_db.getMonitorByName(model_name)
+ else:
+
+ if monitor_section.getRow('horizsync') is not None and monitor_section.getRow('vertrefresh') is not None:
+ # Create a monitor object for the monitor in the xconfig.
+ # It is probably a Plug N Play monitor and as such doesn't
+ # appear in our monitor DB.
+ monitor_model = monitor_model_db.newCustomMonitor(name=model_name)
+ monitor_model.setType(MonitorModel.TYPE_PLUGNPLAY)
+
+ if monitor_section.vendorname is not None:
+ monitor_model.setManufacturer(monitor_section.vendorname)
+
+ monitor_model.setHorizontalSync(' '.join(monitor_section.getRow('horizsync')))
+ monitor_model.setVerticalSync(' '.join(monitor_section.getRow('vertrefresh')))
+
+ else:
+ # Try detecting the monitor.
+ monitor_model = monitor_model_db.detect()
+
+ monitor_model.setDpms("dpms" in monitor_section.option)
+
+ return monitor_model
+
+ def _decodeServerLayoutScreens(self,screens_lines):
+ primary_name = None
+ secondary_name = None
+ layout = XSetup.LAYOUT_SINGLE
+ position = XSetup.POSITION_LEFTOF
+
+ for line in screens_lines:
+ try:
+ i = 1
+ if line._row[i].isdigit(): # Skip any screen ID number.
+ i += 1
+
+ screen_name1 = line._row[i]
+ if primary_name is None:
+ primary_name = screen_name1
+ elif secondary_name is None:
+ secondary_name = screen_name1
+ layout = XSetup.LAYOUT_CLONE
+ i += 1
+
+ if line._row[i].isdigit():
+ # Skip absolute coords.
+ i += 2
+ else:
+ if line._row[i].lower()=='absolute':
+ # Skip the absolute keyword and coords
+ i += 3
+
+ screen_name2 = line._row[i+1]
+ secondary_name = screen_name2
+
+ position = {
+ 'leftof': XSetup.POSITION_LEFTOF,
+ 'rightof': XSetup.POSITION_RIGHTOF,
+ 'above': XSetup.POSITION_ABOVE,
+ 'below': XSetup.POSITION_BELOW
+ }[line._row[i].lower()]
+
+ layout = XSetup.LAYOUT_DUAL
+
+ if screen_name1!=primary_name:
+ # Swap the screens around. The primary wasn't given first on this
+ # dualhead screen line.
+ secondary_name = screen_name1
+ position = {
+ XSetup.POSITION_LEFTOF: XSetup.POSITION_RIGHTOF,
+ XSetup.POSITION_RIGHTOF: XSetup.POSITION_LEFTOF,
+ XSetup.POSITION_ABOVE: XSetup.POSITION_BELOW,
+ XSetup.POSITION_BELOW: XSetup.POSITION_ABOVE
+ }[position]
+
+ except IndexError:
+ pass
+ except KeyError:
+ pass
+
+ return (primary_name, secondary_name, layout, position)
+
+ def _detectGfxCards(self,pci_bus):
+ """Scans the PCI bus for graphics cards.
+
+ Returns a list of (PCI_ID, PCIDevice, GfxCard) tuples."""
+ self.gfx_card_db = GetGfxCardModelDB()
+ vesa_model = "VESA driver (generic)"
+
+ # Look for a gfxcard.
+ found_list = []
+ for pci_device in pci_bus.devices:
+ if pci_device.isGfxCard():
+ pci_id = "PCI:%i:%i:%i" % (pci_device.pci_bus, pci_device.pci_device, pci_device.pci_function)
+ model = None
+ try:
+ cardname = pci_device.getModule()
+ if not pci_device.isModuleXorgDriver():
+ cardname = vesa_model
+ model = self.gfx_card_db.getGfxCardModelByName(cardname)
+ except KeyError:
+ model = self.gfx_card_db.getGfxCardModelByName(vesa_model)
+ found_list.append( (pci_id,pci_device,model) )
+
+ return found_list
+
+ def _canonicalPCIBusID(self,bus_id):
+ try:
+ parts = bus_id.split(":")
+ if parts[0].lower()!="pci":
+ return None
+ bus = int(parts[1])
+ device = int(parts[2])
+ function = int(parts[3])
+ return "PCI:%i:%i:%i" % (bus,device,function)
+ except IndexError:
+ return None
+ except ValueError:
+ return None
+ except AttributeError:
+ return None
+
+ def _isNVidiaCardDualhead(self,PCIDeviceObject):
+ """
+ PCIDevice - ScanPCI.PCIDevice
+
+ Returns true if the given nVidia PCI device ID supports dualhead.
+ """
+ # From Xorg source xc/programs/Xserver/hw/xfree86/drivers/nv/nv_setup.c
+ # See line "pNv->twoHeads = "
+ #
+ NV_ARCH_04 = 0x4
+ NV_ARCH_10 = 0x10
+ NV_ARCH_20 = 0x20
+ NV_ARCH_30 = 0x30
+ NV_ARCH_40 = 0x40
+
+ pci_device = PCIDeviceObject.device
+
+ if pci_device & 0xfff0 == 0x00f0:
+ return True # FIXME PCIXpress chipsets
+
+ # These IDs come from the Xorg source.
+ # xc/programs/Xserver/hw/xfree86/drivers/nv/nv_driver.c
+ # And should be periodically updated.
+ chipset = pci_device & 0x0ff0
+ if chipset in [
+ 0x0100, # GeForce 256
+ 0x0110, # GeForce2 MX
+ 0x0150, # GeForce2
+ 0x0170, # GeForce4 MX
+ 0x0180, # GeForce4 MX (8x AGP)
+ 0x01A0, # nForce
+ 0x01F0]:# nForce2
+ architecture = NV_ARCH_10
+ elif chipset in [
+ 0x0200, # GeForce3
+ 0x0250, # GeForce4 Ti
+ 0x0280]:# GeForce4 Ti (8x AGP)
+ architecture = NV_ARCH_20
+ elif chipset in [
+ 0x0300, # GeForceFX 5800
+ 0x0310, # GeForceFX 5600
+ 0x0320, # GeForceFX 5200
+ 0x0330, # GeForceFX 5900
+ 0x0340]:# GeForceFX 5700
+ architecture = NV_ARCH_30
+ elif chipset in [
+ 0x0040,
+ 0x00C0,
+ 0x0120,
+ 0x0130,
+ 0x0140,
+ 0x0160,
+ 0x01D0,
+ 0x0090,
+ 0x0210,
+ 0x0220,
+ 0x0230,
+ 0x0290,
+ 0x0390]:
+ architecture = NV_ARCH_40
+ else:
+ architecture = NV_ARCH_04
+
+ return (architecture >= NV_ARCH_10) and \
+ (chipset != 0x0100) and \
+ (chipset != 0x0150) and \
+ (chipset != 0x01A0) and \
+ (chipset != 0x0200)
+
+ def _syncXorgConfig(self):
+
+ xinerama_clone = (self.layout==XSetup.LAYOUT_CLONE) and \
+ not ((self.secondary_screen._getGfxCard() is self.primary_screen._getGfxCard()) \
+ and (self.primary_screen._getGfxCard()._getAvailableLayouts() & XSetup.LAYOUT_CLONE))
+
+ if xinerama_clone:
+ # For clone mode with xinerama we copy the screen settings from the primary screen
+ # to the secondary screen.
+ primary_screen = self.getPrimaryScreen()
+ secondary_screen = self.getSecondaryScreen()
+
+ resolution = primary_screen.getAvailableResolutions()[primary_screen.getResolutionIndex()]
+ secondary_resolution_index = secondary_screen.getAvailableResolutions().index(resolution)
+ secondary_screen.setResolutionIndex(secondary_resolution_index)
+ secondary_rates = secondary_screen.getAvailableRefreshRatesForResolution(secondary_resolution_index)
+ primary_rate = primary_screen.getAvailableRefreshRates()[primary_screen.getRefreshRateIndex()]
+
+ best_rate_index = 0
+ best_score = 1000000
+ for i in range(len(secondary_rates)):
+ rate = secondary_rates[i]
+ score = abs(rate-primary_rate)
+ if score < best_score:
+ best_score = score
+ best_rate_index = i
+
+ secondary_screen.setRefreshRateIndex(best_rate_index)
+
+ # Sync up the graphics cards.
+ for gfxcard in self.gfxcards:
+ gfxcard._syncXorgConfig()
+
+ server_flags_sections = self.xorg_config.getSections("ServerFlags")
+ if len(server_flags_sections)!=0:
+ server_flags = server_flags_sections[0]
+ server_flags.option.removeOptionByName("Xinerama")
+ else:
+ server_flags = self.xorg_config.makeSection(None,["Section","ServerFlags"])
+ self.xorg_config.append(server_flags)
+
+ # Delete any old screen entries in the serverlayout section.
+ server_layout = self.xorg_config.getSections("ServerLayout")[0]
+ for screen in server_layout.screen[:]:
+ server_layout.screen.remove(screen)
+
+ # Add the first Screen row
+ screen_id_1 = self.primary_screen._getXorgScreenSection().identifier
+ server_layout.screen.append(server_layout.screen.makeLine(None,
+ ["0",screen_id_1,"0","0"]))
+
+ # FIXME server_flags -> Option "DefaultServerLayout" "???"
+ if self.layout==XSetup.LAYOUT_DUAL or xinerama_clone:
+ server_flags.option.append( server_flags.option.makeLine(None,["Xinerama","true"]) )
+
+ # Add the second screen row. This one also has the dual screen
+ # orientation info.
+ screen_id_2 = self.secondary_screen._getXorgScreenSection().identifier
+
+ if not xinerama_clone:
+
+ position = {XSetup.POSITION_LEFTOF:"RightOf",
+ XSetup.POSITION_RIGHTOF:"LeftOf",
+ XSetup.POSITION_ABOVE:"Below",
+ XSetup.POSITION_BELOW:"Above"}[self.orientation]
+
+ server_layout.screen.append(server_layout.screen.makeLine(None,
+ ["1",screen_id_2,position,screen_id_1]))
+ else:
+ # Xinerama clone mode. Place the second screen directly on top of the
+ # primary screen.
+ server_layout.screen.append(server_layout.screen.makeLine(None,
+ ["1",screen_id_2,"0","0"]))
+
+ self.original_layout = self.layout
+ self.original_orientation = self.orientation
+ self.original_primary_screen = self.primary_screen
+ self.original_secondary_screen = self.secondary_screen
+
+ def writeXorgConfig(self,filename):
+ self._syncXorgConfig()
+ self.xorg_config.writeConfig(filename)
+
+ def xorgConfigToString(self):
+ return self.xorg_config.toString()
+
+ def getUsedScreens(self):
+ """Returns the list of Screen objects that the current setup is using."""
+ if self.layout==XSetup.LAYOUT_SINGLE:
+ return [self.primary_screen]
+ else:
+ return [self.primary_screen, self.secondary_screen]
+
+ def getAllScreens(self):
+ """Returns a list of all Screen object."""
+ screens = []
+ for card in self.gfxcards:
+ for screen in card.getScreens():
+ screens.append(screen)
+ return screens
+
+ def getScreen(self,screenindex):
+ return self.getUsedScreens()[screenindex]
+
+ def getGfxCards(self):
+ return self.gfxcards[:] # No messin' with the gfx card list.
+
+ def getGfxCardByPCIBusID(self,bus_id):
+ for gfxcard in self.gfxcards:
+ if gfxcard.getPCIBusID()==bus_id:
+ return gfxcard
+ return None
+
+ def getPrimaryScreen(self):
+ return self.primary_screen
+
+ def getSecondaryScreen(self):
+ return self.secondary_screen
+
+ def getScreenRole(self,screen):
+ if screen is self.primary_screen:
+ return XSetup.ROLE_PRIMARY
+ if screen is self.secondary_screen:
+ return XSetup.ROLE_SECONDARY
+ return XSetup.ROLE_UNUSED
+
+ def setScreenRole(self,screen,role):
+ if role==XSetup.ROLE_PRIMARY:
+ if screen is self.secondary_screen:
+ # Swap the roles around.
+ self.secondary_screen = self.primary_screen
+ self.primary_screen = screen
+ else:
+ self.primary_screen = screen
+
+ elif role==XSetup.ROLE_SECONDARY:
+ if screen is self.primary_screen:
+ # Swap the roles around.
+ self.primary_screen = self.secondary_screen
+ self.secondary_screen = screen
+ else:
+ self.secondary_screen = screen
+ else:
+ # ROLE_UNUSED
+ if screen is not self.primary_screen and screen is not self.secondary_screen:
+ return
+
+ # Find the first screen unused.
+ for unused_screen in self.getAllScreens():
+ if screen is not self.primary_screen and screen is not self.secondary_screen:
+ if screen is self.primary_screen:
+ self.primary_screen = unused_screen
+ else:
+ self.secondary_screen = unused_screen
+ return
+
+ def mayModifyXorgConfig(self):
+ """Check if the current user may modify the xorg.conf file
+
+ Returns True or False
+ """
+ return os.access(self.xorg_config_filename, os.W_OK|os.R_OK)
+
+ def mayModifyGamma(self):
+ """Check if the current user may modify the gamma settings.
+
+ Returns True or False.
+ """
+ return self.isGammaLive() or self.mayModifyXorgConfig()
+
+ def mayModifyResolution(self):
+ """Check if the current user may modify the screen resolution.
+
+ Returns True or False.
+ """
+ for screen in self.x_live_info.getScreens():
+ if screen.resolutionSupportAvailable():
+ return True
+
+ return self.mayModifyXorgConfig()
+
+ def isGammaLive(self):
+ """Check if gamma changes are done immediately.
+
+ Returns True or False.
+ """
+ return True # FIXME depends on the xvid extension and if86misc.
+
+ def isLiveResolutionConfigChanged(self):
+ """Check if the live server configuration is changed
+
+ Checks if the configuration has been modified with changes that can be
+ pushed to the running X server.
+
+ Returns True or False.
+ """
+ # XRandR tends to break Xinerama
+ if self.primary_screen._getGfxCard().getLayout() in \
+ (XSetup.LAYOUT_SINGLE_XINERAMA, XSetup.LAYOUT_DUAL):
+ return False
+ for screen in self.getAllScreens():
+ if screen.isLive() and screen.isResolutionSettingsChanged():
+ return True
+
+ return False
+
+ def applyLiveResolutionChanges(self):
+ """Apply any changes that can be done live
+
+ Returns True if running server resolution has been changed.
+ """
+ rc = False
+ for s in self.getUsedScreens():
+ if s.isResolutionSettingsChanged():
+ s.applyResolutionSettings()
+ rc = rc or s.isResolutionLive()
+ return rc
+
+ def acceptLiveResolutionChanges(self):
+ """
+
+
+ """
+ for s in self.getUsedScreens():
+ s.acceptResolutionSettings()
+
+ def rejectLiveResolutionChanges(self):
+ """Rejects and reverts the last live server resolution changes
+
+ Rejects the last resolution changes that were made to the live server
+ and reverts it back to the previous configuration.
+ """
+ for s in self.getUsedScreens():
+ s.revertResolutionSettings()
+
+ def isLiveGammaConfigChanged(self):
+ """Check if the live server gamma configuration is changed
+
+ Checks if the configuration has been modified with changes that can be
+ pushed to the running X server.
+
+ Returns True or False.
+ """
+ for screen in self.getAllScreens():
+ if screen.isLive() and screen.isGammaSettingsChanged():
+ return True
+
+ return False
+
+ def applyLiveGammaChanges(self):
+ """Apply any changes that can be done live
+
+ Returns True if running server gamma has been changed.
+ """
+ rc = False
+ for s in self.getUsedScreens():
+ if s.isGammaSettingsChanged():
+ s.applyGammaSettings()
+ rc = rc or s.isGammaLive()
+ return rc
+
+ def acceptLiveGammaChanges(self):
+ """
+
+
+ """
+ for s in self.getUsedScreens():
+ s.acceptGammaSettings()
+
+ def rejectLiveGammaChanges(self):
+ """Rejects and reverts the last live server gamma changes
+
+ Rejects the last gamma changes that were made to the live server
+ and reverts it back to the previous configuration.
+ """
+ for s in self.getUsedScreens():
+ s.revertGammaSettings()
+
+ def isXorgConfigChanged(self):
+ """Check if the xorg.config needs to updated
+
+ Returns True if the xorg.config file needs to updated to reflect new changes.
+ """
+ changed = self.original_layout!=self.layout or \
+ self.original_orientation!=self.orientation or \
+ self.original_primary_screen!=self.primary_screen or \
+ self.original_secondary_screen!=self.secondary_screen
+
+ for gfxcard in self.gfxcards:
+ changed = changed or gfxcard.isXorgConfigChanged()
+ for screen in self.getAllScreens():
+ changed = changed or screen.isXorgConfigChanged()
+ return changed
+
+ def getRestartHint(self):
+ hint = XSetup.RESTART_NONE
+ if self.original_layout!= self.layout or self.original_orientation != self.orientation:
+ hint = XSetup.RESTART_X
+ return max(hint,max( [gfxcard.getRestartHint() for gfxcard in self.gfxcards] ))
+
+ def reset(self):
+ for card in self.gfxcards:
+ card.reset()
+
+ self.layout = self.original_layout
+ self.orientation = self.original_orientation
+ self.primary_screen = self.original_primary_screen
+ self.secondary_screen = self.original_secondary_screen
+
+ # Dualhead and secondary monitor support ----------
+ def getLayout(self):
+ return self.layout
+
+ def setLayout(self,layout):
+ """
+
+ Keyword arguments:
+ layout - XSetup.LAYOUT_SINGLE, XSetup.LAYOUT_CLONE or XSetup.LAYOUT_DUAL.
+ """
+ self.layout = layout
+
+ if self.layout==XSetup.LAYOUT_SINGLE:
+ for gfxcard in self.gfxcards:
+ gfxcard.setLayout(XSetup.LAYOUT_SINGLE)
+ self.xinerama = False
+ elif self.layout==XSetup.LAYOUT_DUAL:
+ # 'xinerama' screens can be combined by the ServerLayout xorg.conf
+ # sections into a multihead configurations. Gfxcard objects just
+ # have to output xinerama friendly xorg.conf device and screen
+ # sections.
+ self.xinerama = True
+ for gfxcard in self.gfxcards:
+ gfxcard.setLayout(XSetup.LAYOUT_SINGLE_XINERAMA)
+
+ # Check if the primary and secondary screen are on the same gfx card.
+ # If so then see if the gfxcard can directly (read: accelarated) support
+ # the layout we want.
+ if self.primary_screen._getGfxCard() is self.secondary_screen._getGfxCard():
+ if self.primary_screen._getGfxCard().getAvailableLayouts() & self.layout:
+ self.primary_screen._getGfxCard().setLayout(self.layout)
+ self.xinerama = False
+
+ elif self.layout==XSetup.LAYOUT_CLONE:
+
+ # If the graphics card itself has both heads and it can offer a better clone
+ # mode, then we use that instead of faking it with xinerama.
+ if (self.secondary_screen._getGfxCard() is self.primary_screen._getGfxCard()) \
+ and (self.primary_screen._getGfxCard()._getAvailableLayouts() & XSetup.LAYOUT_CLONE):
+ self.xinerama = False
+ for gfxcard in self.gfxcards:
+ gfxcard.setLayout(XSetup.LAYOUT_CLONE)
+ else:
+ self.xinerama = True
+ for gfxcard in self.gfxcards:
+ gfxcard.setLayout(XSetup.LAYOUT_SINGLE_XINERAMA)
+
+ def mayModifyLayout(self):
+ return self.mayModifyXorgConfig()
+
+ def getAvailableLayouts(self):
+ if self.secondary_screen is not None:
+ return XSetup.LAYOUT_SINGLE | XSetup.LAYOUT_DUAL | XSetup.LAYOUT_CLONE
+ else:
+ return XSetup.LAYOUT_SINGLE
+
+ def setDualheadOrientation(self,orientation):
+ """ Sets orientation of monitor to one of
+ XSetup.ABOVE, XSetup.UNDER, XSetup.LEFTOF, XSetup.RIGHTOF
+ """
+ self.orientation = orientation
+
+ def getDualheadOrientation(self):
+ """ Returns the current orientation, one of
+ XSetup.ABOVE, XSetup.UNDER, XSetup.LEFTOF, XSetup.RIGHTOF
+ """
+ return self.orientation
+
+ def isHWAccelerated(self):
+ # FIXME:
+ # if twinview-alike and screen[0].res = screen[1].res
+ # else: if primary screen
+ return True
+
+ # Internal ----------
+ def _addScreen(self,screen):
+ self.screens.append(screen)
+
+ def _addGfxCard(self,gfxcard):
+ self.gfxcards.append(gfxcard)
+
+ def _getColorDepth(self):
+ return min([s._getColorDepth() for s in self.getUsedScreens()])
+
+ def __str__(self):
+ string = "XSetup:\n"
+ string += " Layout: %s\n" % ({self.LAYOUT_SINGLE: "Single",
+ self.LAYOUT_CLONE: "Clone",
+ self.LAYOUT_DUAL: "Dual"
+ }[self.getLayout()])
+
+ i = 1
+ for gfxcard in self.gfxcards:
+ string += " Gfxcard %i: %s\n" % (i,str(gfxcard))
+ i += 1
+ return string
+
+############################################################################
+class GfxCard(object):
+ """Represents a graphics card that is present in this computer."""
+
+ def __init__(self, setup, pci_id=None, x_device=None, detected_model=None, proprietary_driver=False):
+ self.setup = setup
+ self.x_config = self.setup.xorg_config
+ self.layout = XSetup.LAYOUT_SINGLE
+ self.pci_id = pci_id
+ self.screens = []
+
+ self.detected_model = detected_model
+ self.proprietary_driver = proprietary_driver
+
+ self.video_ram = 1024
+
+ # The (optimised) layout that was detected in xorg.conf on device level.
+ self.detected_layout = XSetup.LAYOUT_SINGLE
+ self.detected_orientation = XSetup.POSITION_LEFTOF
+
+ self.x_device = [] # This can be a list of xorg device sections
+ if x_device is not None:
+ self.x_device.append(x_device)
+
+ def _addScreen(self,screen):
+ self.screens.append(screen)
+
+ def _addXDevice(self,x_device):
+ self.x_device.append(x_device)
+
+ def _finalizeInit(self):
+ # Finish initalisation.
+
+ if len(self.x_device)!=0:
+
+ # Try to find a gfx card model.
+ self.gfxcard_model = None
+ if self.x_device[0].boardname is not None:
+ # Look up the model by boardname.
+ try:
+ self.gfxcard_model = GetGfxCardModelDB().getGfxCardModelByName(self.x_device[0].boardname)
+ except KeyError:
+ pass
+
+ if self.gfxcard_model is None:
+ # OK, try looking it up by driver.
+ try:
+ self.gfxcard_model = GetGfxCardModelDB().getGfxCardModelByDriverName(self.x_device[0].driver)
+ except KeyError:
+ self.gfxcard_model = self.detected_model
+
+ # Write the current driver in the model
+ if self.x_device[0].driver:
+ self.gfxcard_model.setDriver(self.x_device[0].driver)
+
+ self.proprietary_driver = self.gfxcard_model.getProprietaryDriver()==self.x_device[0].driver
+
+ if self.x_device[0].videoram is not None:
+ self.video_ram = int(self.x_device[0].videoram)
+
+ # Detect layout
+ if len(self.screens)>=2:
+ # Xorg ATI driver.
+ if self._getCurrentDriver() in ['ati','r128','radeon']:
+ merged = self.x_device[0].option.getOptionByName('mergedfb')
+ if merged is not None and xorgconfig.toBoolean(merged._row[2]):
+ self.detected_layout = XSetup.LAYOUT_CLONE
+ # ATI proprietary driver
+ elif self._getCurrentDriver()=='fglrx':
+ desktopsetup = self.x_device[0].option.getOptionByName('desktopsetup')
+ if desktopsetup is not None and desktopsetup._row[2]=='c':
+ self.detected_layout = XSetup.LAYOUT_CLONE
+ # nVidia proprietary driver
+ elif self._getCurrentDriver()=='nvidia':
+ twinview = self.x_device[0].option.getOptionByName('twinview')
+ if twinview is not None:
+ desktopsetup = self.x_device[0].option.getOptionByName('twinvieworientation')
+ if desktopsetup is not None and desktopsetup._row[2].lower()=='clone':
+ self.detected_layout = XSetup.LAYOUT_CLONE
+ # i810 driver
+ elif self._getCurrentDriver() in ['i810', 'intel']:
+ clone = self.x_device[0].option.getOptionByName('clone')
+ if clone is not None:
+ if xorgconfig.toBoolean(clone._row[2]):
+ self.detected_layout = XSetup.LAYOUT_CLONE
+
+ else:
+ self.gfxcard_model = self.detected_model
+
+ self.original_gfxcard_model = self.gfxcard_model
+ self.original_proprietary_driver = self.proprietary_driver
+ self.original_layout = self.layout
+
+ # Give the screens a chance to finish initialisation.
+ for screen in self.screens:
+ screen._finalizeInit()
+ for screen in self.screens:
+ screen._resyncResolution()
+
+ def _getDetectedLayout(self):
+ return self.detected_layout
+
+ def _getDetectedDualheadOrientation(self):
+ return self.detected_orientation
+
+ def _getDetectedGfxCardModel(self):
+ return self.detected_model
+
+ def getScreens(self):
+ return self.screens[:]
+
+ def getGfxCardModel(self):
+ return self.gfxcard_model
+
+ def setGfxCardModel(self,gfx_card_model):
+ self.gfxcard_model = gfx_card_model
+
+ for screen in self.screens:
+ screen._resyncResolution()
+
+ def getXorgDeviceSection(self,index):
+ return self.x_device[index]
+
+ def isProprietaryDriver(self):
+ return self.proprietary_driver
+
+ def setProprietaryDriver(self,proprietary_driver):
+ self.proprietary_driver = proprietary_driver
+
+ def getDetectedGfxCardModel(self):
+ return self.detected_model
+
+ def getPCIBusID(self):
+ return self.pci_id
+
+ def isXorgConfigChanged(self):
+ return self.original_gfxcard_model is not self.gfxcard_model or \
+ self.original_proprietary_driver != self.proprietary_driver or \
+ self.original_layout != self.layout
+
+ def reset(self):
+ for screen in self.screens:
+ screen.reset()
+
+ self.gfxcard_model = self.original_gfxcard_model
+ self.proprietary_driver = self.original_proprietary_driver
+
+ def isAGP(self):
+ return self.pci_id=='PCI:1:0:0' # FIXME this might not be accurate.
+
+ def getLayout(self):
+ return self.layout
+
+ def setLayout(self,layout):
+ self.layout = layout
+ for screen in self.screens:
+ screen._resyncResolution()
+
+ def getAvailableLayouts(self):
+ layouts = XSetup.LAYOUT_SINGLE
+ if len(self.screens)==2:
+ if self._getCurrentDriver() in ['fglrx', 'nvidia', 'i810']:
+ layouts |= XSetup.LAYOUT_CLONE | XSetup.LAYOUT_DUAL
+ return layouts
+
+ def getVideoRam(self):
+ """
+ Get the amount of video ram that this card has.
+
+ The values returned have the following meanings:
+ 256 => 256 kB
+ 512 => 512 kB
+ 1024 => 1 MB
+ 2048 => 2 MB
+ 4096 => 4 MB
+ 8192 => 8 MB
+ 16384 => 16 MB
+ 32768 => 32 MB
+ 65536 => 64 MB or more
+
+ The video ram setting is only used if the selected graphics card model requires
+ that the amount of video ram be explicitly specified. That is to say that
+ gfxcard.getGfxCardModel().getNeedVideoRam() returns true.
+
+ Returns an integer from the list above.
+ """
+ return self.video_ram
+
+ def setVideoRam(self,ram):
+ self.video_ram = ram
+
+ for screen in self.screens:
+ screen._resyncResolution()
+
+ def _getCurrentDriver(self):
+ if self.proprietary_driver:
+ return self.gfxcard_model.getProprietaryDriver()
+ else:
+ return self.gfxcard_model.getDriver()
+
+ def getRestartHint(self):
+ # The ATI propreitary drivers need a special AGP kernel module to be loaded.
+ # The best, and often only way to get this module loaded is to reboot.
+ # The same applies for removing the module.
+ hint = XSetup.RESTART_NONE
+
+ if self.original_proprietary_driver:
+ original_gfx_driver = self.original_gfxcard_model.getProprietaryDriver()
+ else:
+ original_gfx_driver = self.original_gfxcard_model.getDriver()
+
+ current_gfx_driver = self._getCurrentDriver()
+
+ if current_gfx_driver!=original_gfx_driver:
+ # Restart X if the driver is different.
+ hint = XSetup.RESTART_X
+
+ # Layout changes also require an X server restart.
+ if self.original_layout!=self.layout:
+ hint = XSetup.RESTART_X
+
+ if original_gfx_driver=='fglrx' and current_gfx_driver in ['ati','r128','radeon']:
+ hint = XSetup.RESTART_SYSTEM
+
+ # If a different kernel module is needed, then restart the system.
+ kernel_module_list = self._getLoadedKernelModules()
+ if self._needATIFglrx() and 'fglrx' not in kernel_module_list:
+ hint = XSetup.RESTART_SYSTEM
+ else:
+ if 'fglrx' in kernel_module_list:
+ hint = XSetup.RESTART_SYSTEM
+
+ hintlist = [hint]
+ hintlist.extend([screen.getRestartHint() for screen in self.screens])
+ return max(hintlist)
+
+ def _needATIFglrx(self):
+ """Work out if the current configuration require the ATI fglrx kernel module."""
+ return self.isAGP() and self.getGfxCardModel() is not None and \
+ self.getGfxCardModel().getProprietaryDriver()=='fglrx' and self.isProprietaryDriver()
+
+ def _getLoadedKernelModules(self):
+ return [line.split()[0] for line in open('/proc/modules')]
+
+ def _getAvailableLayouts(self):
+ if len(self.screens)>=2:
+ drv = self._getCurrentDriver()
+ layouts = XSetup.LAYOUT_SINGLE | XSetup.LAYOUT_DUAL
+ if drv in ['fglrx', 'nvidia', 'i810']:
+ layouts |= XSetup.LAYOUT_CLONE
+ elif drv in ['ati', 'radeon', 'r128', 'intel']:
+ layouts = XSetup.LAYOUT_SINGLE
+ return layouts
+ else:
+ return XSetup.LAYOUT_SINGLE
+
+ def __str__(self):
+ screen_string = ",".join([str(s) for s in self.screens])
+ driver = self._getCurrentDriver()
+ return "GfxCard: {model:"+str(self.gfxcard_model)+", driver:"+driver+", screens:"+screen_string+"}"
+
+ def _syncXorgConfig(self):
+ if self.proprietary_driver and self.gfxcard_model.getProprietaryDriver() is not None:
+ driver = self.gfxcard_model.getProprietaryDriver()
+ else:
+ driver = self.gfxcard_model.getDriver()
+
+ # FIXME maybe this module stuff should migrate into XSetup.
+
+ # --- Fix the module section ---
+
+ # $raw_X->set_devices($card, @{$card->{cards} || []});
+ # $raw_X->get_ServerLayout->{Xinerama} = { commented => !$card->{Xinerama}, Option => 1 }
+ #if defined $card->{Xinerama};
+ module_sections = self.x_config.getSections("Module")
+ if len(module_sections) > 0:
+ module = module_sections[0]
+ else:
+ module = self.x_config.makeSection(None, ["Section", "Module"])
+ self.x_config.append(module)
+
+ module.removeModule('GLcore')
+ module.removeModule('glx')
+ module.removeModule('dbe')
+
+ # Mandriva
+ #module.removeModule("/usr/X11R6/lib/modules/extensions/libglx.so")
+
+ if driver=='nvidia':
+ module.addModule("glx")
+
+ # Mandriva
+ # This loads the NVIDIA GLX extension module.
+ # IT IS IMPORTANT TO KEEP NAME AS FULL PATH TO libglx.so ELSE
+ # IT WILL LOAD XFree86 glx module and the server will crash.
+
+ # module.addModule("/usr/X11R6/lib/modules/extensions/libglx.so")
+ # FIXME lib64
+ elif self.gfxcard_model.getProprietaryDriver()!='fglrx':
+ module.addModule('glx')
+ module.addModule('GLcore')
+
+ #module.removeModule("/usr/X11R6/lib/modules/extensions/libglx.a")
+ if driver=='fglrx':
+ module.addModule("glx")
+ module.addModule("dbe")
+ #elif driver!='nvidia':
+ # module.addModule("/usr/X11R6/lib/modules/extensions/libglx.a")
+
+ # DRI
+ module.removeModule('dri')
+ if self.gfxcard_model.getDriGlx():
+ module.addModule('dri')
+
+ module.removeModule('v4l')
+ if not (self.gfxcard_model.getDriGlx() and self.gfxcard_model.getDriver()=='r128'):
+ module.addModule('v4l')
+
+ # --- Fix all of the Device sections ---
+ for i in range(len(self.screens)):
+
+ if i==len(self.x_device):
+ new_device = self.x_config.makeSection('',['section','device'])
+ self.x_config.append(new_device)
+ self.x_device.append(new_device)
+ new_device.identifier = self.x_config.createUniqueIdentifier("device")
+
+ identifier = self.x_device[i].identifier
+ busid = self.x_device[i].busid
+
+ self.x_device[i].clear()
+
+ # Create a new Device section in the Xorg config file.
+ self.x_device[i].identifier = identifier
+ self.x_device[i].boardname = self.gfxcard_model.getName()
+ self.x_device[i].busid = self.pci_id
+ self.x_device[i].driver = driver
+ self.x_device[i].screen = str(i)
+
+ if self.gfxcard_model.getVendor() is not None:
+ self.x_device[i].vendorname = self.gfxcard_model.getVendor()
+
+ if self.gfxcard_model.getNeedVideoRam():
+ self.x_device[i].videoram = self.video_ram
+
+ # Setup Clone mode for second heads.
+ if driver in ["ati","r128","radeon"]: # Xorg ATI driver
+ merged_value = {
+ XSetup.LAYOUT_CLONE: "on",
+ XSetup.LAYOUT_SINGLE: "off",
+ XSetup.LAYOUT_DUAL: "on",
+ XSetup.LAYOUT_SINGLE_XINERAMA: "off"
+ }[self.layout]
+
+ merged_option = self.x_device[i].option.makeLine(None,["MergedFB",merged_value])
+ self.x_device[i].option.append(merged_option)
+
+ if self.layout==XSetup.LAYOUT_CLONE:
+ monitor_model = self.setup.getSecondaryScreen().getMonitorModel()
+ if monitor_model is not None:
+ if monitor_model.getHorizontalSync() is not None:
+ hsyncline = self.x_device[i].option.makeLine(None,['CRT2HSync',monitor_model.getHorizontalSync()])
+ self.x_device[i].option.append(hsyncline)
+
+ if monitor_model.getVerticalSync() is not None:
+ vsyncline = self.x_device[i].option.makeLine(None,['CRT2VRefresh',monitor_model.getVerticalSync()])
+ self.x_device[i].option.append(vsyncline)
+
+ # FIXME option "CloneMode" "off"
+
+ if driver=='fglrx': # ATI proprietary driver.
+ if self.layout==XSetup.LAYOUT_CLONE:
+ new_option = self.x_device[i].option.makeLine(None,["DesktopSetup","c"])
+ self.x_device[i].option.append(new_option)
+
+ # FIXME this probably won't work on laptops and DVI. The user will probably
+ # have to manually select the monitor types.
+
+ # We do this to make sure that the driver starts up in clone mode even
+ # if it can't detect the second monitor.
+ new_option = self.x_device[i].option.makeLine(None,["ForceMonitors","crt1,crt2"])
+ self.x_device[i].option.append(new_option)
+
+ monitor_model = self.setup.getSecondaryScreen().getMonitorModel()
+ if monitor_model is not None:
+ if monitor_model.getHorizontalSync() is not None:
+ hsyncline = self.x_device[i].option.makeLine(None,['HSync2',monitor_model.getHorizontalSync()])
+ self.x_device[i].option.append(hsyncline)
+
+ if monitor_model.getVerticalSync() is not None:
+ vsyncline = self.x_device[i].option.makeLine(None,['VRefresh2',monitor_model.getVerticalSync()])
+ self.x_device[i].option.append(vsyncline)
+
+ if driver=='nvidia': # nVidia proprietary driver.
+ if self.layout==XSetup.LAYOUT_CLONE:
+ new_option = self.x_device[i].option.makeLine(None,["TwinView","on"])
+ self.x_device[i].option.append(new_option)
+ new_option = self.x_device[i].option.makeLine(None,["TwinViewOrientation","clone"])
+ self.x_device[i].option.append(new_option)
+
+ monitor_model = self.setup.getSecondaryScreen().getMonitorModel()
+ if monitor_model is not None:
+ if monitor_model.getHorizontalSync() is not None:
+ hsyncline = self.x_device[i].option.makeLine(None,['SecondMonitorHorizSync',monitor_model.getHorizontalSync()])
+ self.x_device[i].option.append(hsyncline)
+
+ if monitor_model.getVerticalSync() is not None:
+ vsyncline = self.x_device[i].option.makeLine(None,['SecondMonitorVertRefresh',monitor_model.getVerticalSync()])
+ self.x_device[i].option.append(vsyncline)
+
+ if driver in ['i810']: # i810 driver
+ if self.layout in (XSetup.LAYOUT_SINGLE_XINERAMA,
+ XSetup.LAYOUT_DUAL,
+ XSetup.LAYOUT_CLONE):
+ new_option = self.x_device[i].option.makeLine(None,["MonitorLayout", "CRT,LFP"])
+ self.x_device[i].option.append(new_option)
+ if self.layout==XSetup.LAYOUT_CLONE:
+ new_option = self.x_device[i].option.makeLine(None,["Clone","on"])
+ self.x_device[i].option.append(new_option)
+
+ # Find the closest matching refresh rate for the second monitor.
+ primary_screen = self.setup.getPrimaryScreen()
+ secondary_screen = self.setup.getSecondaryScreen()
+ resolution = primary_screen.getAvailableResolutions()[primary_screen.getResolutionIndex()]
+ secondary_resolution_index = secondary_screen.getAvailableResolutions().index(resolution)
+ secondary_rates = secondary_screen.getAvailableRefreshRatesForResolution(secondary_resolution_index)
+ primary_rate = primary_screen.getAvailableRefreshRates()[primary_screen.getRefreshRateIndex()]
+
+ best_rate = 50
+ best_score = 1000000
+ for rate in secondary_rates:
+ score = abs(rate-primary_rate)
+ if score < best_score:
+ best_score = score
+ best_rate = rate
+
+ # Specify a working refresh rate for the second monitor.
+ new_option = self.x_device[i].option.makeLine(None,["CloneRefresh",str(best_rate)])
+ self.x_device[i].option.append(new_option)
+
+ self._insertRawLinesIntoConfig(self.x_device[i], self.gfxcard_model.getLines())
+
+ self.screens[i]._syncXorgConfig(self.x_device[i])
+
+ self.original_gfxcard_model = self.gfxcard_model
+ self.original_proprietary_driver = self.proprietary_driver
+ self.original_layout = self.layout
+
+ def _insertRawLinesIntoConfig(self,section,lines):
+ reader = csv.reader(lines,delimiter=' ')
+ for row in reader:
+ if len(row)>=2:
+ if row[0].lower()=="option":
+ option = section.option.makeLine(None,row[1:])
+ section.option.append(option)
+
+############################################################################
+class Screen(object):
+ """Represents a single output/screen/monitor on a graphics card.
+
+ Changes to the screen resolution, refresh rate, rotation and reflection
+ settings are not made active until the method applyResolutionSettings() is
+ called. After calling applyResolutionSettings(), changes can be backed out
+ of with the revertResolutionSettings() method. If you, should I say the user,
+ is satisfied with the new settings then call the acceptResolutionSettings()
+ method.
+
+ Gamma correction settings take effect immediately, and don't take part in the
+ apply, revert and accept mechanism above.
+ """
+
+ RR_Rotate_0 = xf86misc.XF86Screen.RR_Rotate_0
+ RR_Rotate_90 = xf86misc.XF86Screen.RR_Rotate_90
+ RR_Rotate_180 = xf86misc.XF86Screen.RR_Rotate_180
+ RR_Rotate_270 = xf86misc.XF86Screen.RR_Rotate_270
+ RR_Reflect_X = xf86misc.XF86Screen.RR_Reflect_X
+ RR_Reflect_Y = xf86misc.XF86Screen.RR_Reflect_Y
+
+ def __init__(self, gfx_card=None, x_config_screen=None, x_config_monitor=None, \
+ monitor_model=None, x_config=None):
+ """Create a Screen object.
+
+ This method is private to this module.
+ """
+ self.gfx_card = gfx_card
+ self.x_config_screen = x_config_screen
+
+ self.x_config_monitor = x_config_monitor
+ self.monitor_model = monitor_model
+ self.monitor_aspect = ModeLine.ASPECT_4_3
+ self.original_monitor_model = monitor_model
+ self.x_config = x_config
+
+ # Cookup some sensible screen sizes.
+ self.standard_sizes = GetMonitorModeDB().getAllResolutions()
+
+ self.x_live_screen = None
+
+ # Intialise the gamma settings with defaults.
+ self.redgamma = 1.0
+ self.greengamma = 1.0
+ self.bluegamma = 1.0
+ self.allgamma = 1.0
+ self.settingall = True
+
+ # If there is a monitor xorg.conf section then look there for gamma info.
+ if self.x_config_monitor is not None:
+ gamma_row = self.x_config_monitor.getRow('gamma')
+ if gamma_row is not None:
+ # Read the gamma info out of xorg.conf
+ try:
+ if len(gamma_row)==3:
+ self.redgamma = float(gamma_row[0])
+ self.greengamma = float(gamma_row[1])
+ self.bluegamma = float(gamma_row[2])
+ self.allgamma = self.redgamma
+ elif len(gamma_row)==1:
+ self.allgamma = float(gamma_row[0])
+ self.redgamma = self.allgamma
+ self.greengamma = self.allgamma
+ self.bluegamma = self.allgamma
+ except ValueError:
+ pass
+
+ # Try to work out if this monitor is setup for 4:3 modes or 16:9.
+ aspect_43_count = 0
+ aspect_169_count = 0
+ # Count the number of 4:3 modelines compared to 16:9 modes.
+ for mode in self.x_config_monitor.modeline:
+ try:
+ # Don't count the fallback resolution. It is also present
+ # if the monitor is widescreen. Just ignore it.
+ if (mode._row[2],mode._row[6])!=FALLBACK_RESOLUTION:
+ if MonitorModeDB.aspectRatio(mode._row[2],mode._row[6])==ModeLine.ASPECT_4_3:
+ aspect_43_count += 1
+ else:
+ aspect_169_count += 1
+ except IndexError:
+ pass
+
+ if aspect_43_count >= aspect_169_count:
+ self.monitor_aspect = ModeLine.ASPECT_4_3
+ else:
+ self.monitor_aspect = ModeLine.ASPECT_16_9
+
+ # Backup the settings
+ (self.originalredgamma, self.originalgreengamma, self.originalbluegamma) = (
+ self.redgamma, self.greengamma, self.bluegamma)
+ self.originalallgamma = self.allgamma
+ self.originalsettingall = self.settingall
+ self.original_monitor_aspect = self.monitor_aspect
+
+ def _setXLiveScreen(self,x_live_screen):
+ self.x_live_screen = x_live_screen
+
+ def _finalizeInit(self):
+
+ if self.x_live_screen is not None and self.x_live_screen.resolutionSupportAvailable():
+ self._computeSizesFromXorg()
+
+ (cw,ch,x,x) = self.x_live_screen.getSize()
+ i = 0
+ self.currentsizeindex = 0
+ for size in self.available_sizes:
+ if (cw,ch)==size:
+ self.currentsizeindex = i
+ break
+ i += 1
+
+ self.currentrefreshrate = self.x_live_screen.getRefreshRate()
+ self.currentrotation = self.x_live_screen.getRotation() & (
+ Screen.RR_Rotate_0 | Screen.RR_Rotate_90 | Screen.RR_Rotate_180 | Screen.RR_Rotate_270)
+ self.currentreflection = self.x_live_screen.getRotation() & (
+ Screen.RR_Reflect_X | Screen.RR_Reflect_Y)
+
+ else:
+ # There is no live info, so try to collect some info out
+ # of xorg.conf itself.
+
+ # Cookup some reasonable screen resolutions based on what we know about the monitor.
+ self._computeSizesFromMonitor()
+
+ (cw,ch) = self.available_sizes[0]
+ self.currentrefreshrate = None
+
+ # Dig through the Display sections in the xorg.conf Screen section
+ # and try to find the first resolution/mode.
+ if self.x_config_screen is not None:
+ default_depth = self.x_config_screen.defaultdepth
+
+ current_mode_name = None
+
+ for display_section in self.x_config_screen.getSections('display'):
+ if default_depth is None or display_section.depth==default_depth:
+ modes_row = display_section.getRow('modes')
+ if modes_row is not None and len(modes_row)>=1:
+ current_mode_name = modes_row[0]
+ break
+
+ if current_mode_name is not None:
+ for mode in self.mode_list:
+ if mode.getName()==current_mode_name:
+ cw = mode.getWidth()
+ ch = mode.getHeight()
+ self.currentrefreshrate = mode.getVRefresh()
+ break
+
+ # Work out the index of the current resolution
+ i = 0
+ for size in self.available_sizes:
+ if (cw,ch)==size:
+ self.currentsizeindex = i
+ break
+ i += 1
+
+ if self.currentrefreshrate is None:
+ self.currentrefreshrate = self.getAvailableRefreshRates()[0]
+
+ self.currentrotation = Screen.RR_Rotate_0 # FIXME
+ self.currentreflection = 0 # FIXME
+
+ # Gamma settings
+ if self.x_live_screen is not None:
+ try:
+ (self.redgamma, self.greengamma, self.bluegamma, self.allgama,
+ self.settingall) = self._getGammaFromLiveScreen()
+ except:
+ (self.redgamma, self.greengamma, self.bluegamma, self.allgama,
+ self.settingall) = self._getGammaFromXorg()
+ else:
+ (self.redgamma, self.greengamma, self.bluegamma, self.allgama,
+ self.settingall) = self._getGammaFromXorg()
+
+ self.originalsizeindex = self.currentsizeindex
+ self.original_size = self.getAvailableResolutions()[self.currentsizeindex]
+ self.originalrefreshrate = self.currentrefreshrate
+ self.originalrotation = self.currentrotation
+ self.originalreflection = self.currentreflection
+
+ self.originalredgamma = self.redgamma
+ self.originalgreengamma = self.greengamma
+ self.originalbluegamma = self.bluegamma
+
+ self.originalallgamma = self.allgamma
+ self.originalsettingall = self.settingall
+
+ def _getGammaFromLiveScreen(self):
+ """Reads the gamma information from the x server"""
+ # Read the current gamma settings directly from X.
+ (redgamma, greengamma, bluegamma) = self.x_live_screen.getGamma()
+
+ # Round the values off to 2 decimal places.
+ redgamma = round(self.redgamma,2)
+ greengamma = round(self.greengamma,2)
+ bluegamma = round(self.bluegamma,2)
+
+ allgamma = redgamma
+ settingall = redgamma==greengamma==bluegamma
+ return (redgamma, greengamma, bluegamma, allgamma, settingall)
+
+ def _getGammaFromXorg(self):
+ """Extracts the gamma information from the xorg configuration"""
+ # Set some gamma defaults
+ redgamma = greengamma = bluegamma = allgamma = 1.0
+ settingall = True
+
+ # Look for gamma information in xorg.conf
+ if self.x_config_monitor is not None:
+ gamma_row = self.x_config_monitor.getRow('gamma')
+ if gamma_row is not None:
+ try:
+ if len(gamma_row)==1:
+ allgamma = float(gamma_row[0])
+ redgamma = greengamma = bluegamma = allgamma
+ self.settingall = True
+ elif len(gamma_row.row)==3:
+ redgamma = float(gamma_row[0])
+ greengamma = float(gamma_row[1])
+ bluegamma = float(gamma_row[2])
+ allgamma = self.redgamma
+ settingall = False
+ except ValueError:
+ pass
+ return (redgamma, greengamma, bluegamma, allgamma, settingall)
+
+ def _computeSizesFromXorg(self):
+ all_sizes = self.x_live_screen.getAvailableSizes()
+ self.available_sizes = []
+
+ # Some dualhead setups repolonger sizelists, those are unlikely
+ # to be standard zes, we still want to be able to use them.s
+ for i in range(len(all_sizes)):
+ if len(all_sizes[i]) > 2:
+ self.available_sizes.append(all_sizes[i][:2])
+ elif len(alls_sizes[i]) == 2:
+ if (size[0],size[1]) in self.standard_sizes:
+ self.available_sizes.append(all_sizes[i])
+ self.available_sizes.sort()
+
+ def _computeSizesFromMonitor(self):
+ monitor_model = self.monitor_model
+
+ if monitor_model is None:
+ # If there is no monitor model selected, then just use a default
+ # model so that we at least get some fairly safe resolutions.
+ monitor_model = GetMonitorModelDB().getMonitorByName("Monitor 800x600")
+
+ self.mode_list = GetMonitorModeDB().getAvailableModes(monitor_model,self.monitor_aspect)
+ resolutions = set()
+ for mode in self.mode_list:
+ pw = mode.getWidth()
+ ph = mode.getHeight()
+ if (pw,ph) in self.standard_sizes and pw>=640 and ph>=480:
+ resolutions.add( (pw,ph) )
+
+ # Filter the sizes by the amount of video ram that we have.
+ color_bytes = self._getColorDepth()/8
+ if self.gfx_card.getGfxCardModel().getNeedVideoRam():
+ video_memory = self.gfx_card.getVideoRam()
+ else:
+ video_memory = 65536 # Big enough.
+ video_memory *= 1024 # Convert to bytes.
+
+ # Filter the list of modes according to available memory.
+ self.available_sizes = [mode for mode in resolutions if mode[0]*mode[1]*color_bytes <= video_memory]
+
+ self.available_sizes.sort()
+
+ def _getColorDepth(self):
+ if self.gfx_card.getGfxCardModel().getNeedVideoRam():
+ # If this card has limited memory then we fall back to 16bit colour.
+ if self.gfx_card.getVideoRam() <= 4096:
+ return 16 # 16bit colour
+ else:
+ return 24 # 24bit colour
+ else:
+ return 24
+
+ def getName(self):
+ try:
+ return "Screen %i" % (self.gfx_card.setup.getUsedScreens().index(self)+1)
+ except ValueError:
+ return "Screen ?"
+
+ def isLive(self):
+ """Returns True if this screen is currently being used by the X server.
+ """
+ return self.x_live_screen is not None
+
+ def getMonitorModel(self):
+ """
+
+ Returns a MonitorModel object or None.
+ """
+ return self.monitor_model
+
+ def setMonitorModel(self,monitor_model):
+ """
+
+ Setting the monitor also changes the resolutions that are available.
+
+ """
+ self.monitor_model = monitor_model
+ self._resyncResolution()
+
+ def getMonitorAspect(self):
+ """
+ Get the aspect ratio for the monitor
+
+ Returns one of ModeLine.ASPECT_4_3 or ModeLine.ASPECT_16_9.
+ """
+ return self.monitor_aspect
+
+ def setMonitorAspect(self,aspect):
+ """Specify the aspect ratio of the monitor.
+
+ Keyword arguments:
+ aspect -- Aspect ratio. Either the constant ModeLine.ASPECT_4_3 or ModeLine.ASPECT_16_9.
+
+ Setting this also changes the resolutions that are available.
+ """
+ self.monitor_aspect = aspect
+ self._resyncResolution()
+
+ def _resyncResolution(self):
+ try:
+ (preferred_width,preferred_height) = self.getAvailableResolutions()[self.getResolutionIndex()]
+ except IndexError:
+ print self.getAvailableResolutions()
+ (preferred_width,preferred_height) = self.getAvailableResolutions()[-1]
+
+ if self.isResolutionLive():
+ self._computeSizesFromXorg()
+ else:
+ # The list of resolutions needs to be updated.
+ self._computeSizesFromMonitor()
+
+ if self.gfx_card.setup.getLayout()==XSetup.LAYOUT_CLONE:
+ if self.gfx_card.setup.getPrimaryScreen() is self:
+ # Filter the list of resolutions based on what the secondary screen can show.
+ secondary_screen = self.gfx_card.setup.getSecondaryScreen()
+ primary_set = set(self.available_sizes)
+ secondary_set = set(secondary_screen.available_sizes)
+
+ common_set = primary_set.intersection(secondary_set)
+
+ suitable_resolutions = []
+ # Make sure that each resolution also has a common refresh rate.
+ for resolution in common_set:
+ primary_rates = self.getAvailableRefreshRatesForResolution(self.available_sizes.index(resolution))
+ secondary_rates = secondary_screen.getAvailableRefreshRatesForResolution(secondary_screen.available_sizes.index(resolution))
+
+ if len(set(primary_rates).intersection(set(secondary_rates)))!=0:
+ suitable_resolutions.append(resolution)
+
+ suitable_resolutions.sort()
+ self.available_sizes = suitable_resolutions
+
+ # Now we select a resolution that closely matches the previous resolution.
+ best_score = 2000000 # big number.
+ best_index = 0
+ resolution_list = self.getAvailableResolutions()
+ for i in range(len(resolution_list)):
+ (width,height) = resolution_list[i]
+ new_score = abs(width-preferred_width) + abs(height-preferred_height)
+
+ if new_score < best_score:
+ best_index = i
+ best_score = new_score
+ self.setResolutionIndex(best_index)
+
+ if self.gfx_card.setup.getLayout()==XSetup.LAYOUT_CLONE:
+ if self.gfx_card.setup.getSecondaryScreen() is self:
+ self.gfx_card.setup.getPrimaryScreen()._resyncResolution()
+
+ def isXorgConfigChanged(self):
+ isroot = os.getuid()==0
+ return self.original_monitor_model is not self.monitor_model \
+ or self.original_monitor_aspect != self.monitor_aspect \
+ or self.isGammaSettingsChanged() \
+ or (self.isResolutionSettingsChanged() and (not self.isResolutionLive() or isroot))
+
+ def getRedGamma(self):
+ """Get the current red gamma value.
+ """
+ return self.redgamma
+
+ def setRedGamma(self,value):
+ """Set gamma correction value for red
+
+ This method takes effect immediately on the X server if possible.
+
+ Keyword arguments:
+ value -- gamma correction value (float)
+ """
+ self.redgamma = value
+ if self.x_live_screen is not None:
+ self.x_live_screen.setGamma( (self.redgamma,self.greengamma,self.bluegamma) )
+ self.settingall = False
+
+ def getGreenGamma(self):
+ """Get the current green gamma value
+ """
+ return self.greengamma
+
+ def setGreenGamma(self,value):
+ """Set gamma correction value for green
+
+ This method takes effect immediately on the X server if possible.
+
+ Keyword arguments:
+ value -- gamma correction value (float)
+ """
+ self.greengamma = value
+ if self.x_live_screen is not None:
+ self.x_live_screen.setGamma( (self.redgamma,self.greengamma,self.bluegamma) )
+ self.settingall = False
+
+ def getBlueGamma(self):
+ """Get the current blue gamma value
+ """
+ return self.bluegamma
+
+ def setBlueGamma(self,value):
+ """Set gamma correction value for blue
+
+ This method takes effect immediately on the X server if possible.
+
+ Keyword arguments:
+ value -- gamma correction value (float)
+ """
+ self.bluegamma = value
+ if self.x_live_screen is not None:
+ self.x_live_screen.setGamma( (self.redgamma,self.greengamma,self.bluegamma) )
+ self.settingall = False
+
+ def getAllGamma(self):
+ """Get the gamma correction value for all colours.
+
+ Returns a float.
+
+ See isGammaEqual()
+ """
+ return self.allgamma
+
+ def setAllGamma(self,value):
+ """Set the gamma correction value for all colours.
+
+ Keyword arguments:
+ value -- gamma correction value (float)
+ """
+ self.allgamma = value
+ if self.x_live_screen is not None:
+ self.x_live_screen.setGamma( (self.allgamma,self.allgamma,self.allgamma) )
+ self.settingall = True
+
+ def isGammaLive(self):
+ """Returns true if modifications to the gamma are immediately visible.
+ """
+ return self.x_live_screen is not None
+
+ def isGammaEqual(self):
+ """Test whether each colour is using the same gamma correction value.
+
+ Returns True if the gamma value is the same for all colours
+ """
+ return self.getRedGamma()==self.getGreenGamma()==self.getBlueGamma()
+
+ def getScreenIndex(self):
+ return self.gfx_card.getScreens().index(self)
+
+ # Size and resolution
+ def getResolutionIndex(self):
+ """Get the current resolution of this screen.
+
+ Returns an index into the list of available resolutions. See
+ getAvailableResolutions().
+ """
+ return self.currentsizeindex
+
+ def setResolutionIndex(self,index):
+ """Set the resolution for this screen.
+
+ This method does not take effect immediately, only after applyResolutionSetttings()
+ has been called.
+
+ Keyword arguments:
+ index -- The index of the resolution to use. See getAvailableResolutions().
+ """
+ self.currentsizeindex = index
+
+ def getAvailableResolutions(self):
+ """Get the list of available resolutions.
+
+ Returns a list of screen (width,height) tuples. width and height are in
+ pixels.
+ """
+ return self.available_sizes[:]
+
+ # Rotation
+ def getRotation(self):
+ """Get the current rotation settings for this screen.
+
+ Returns one of Screen.RR_Rotate_0, Screen.RR_Rotate_90,
+ Screen.RR_Rotate_180 or Screen.RR_Rotate_270
+ """
+ return self.currentrotation
+
+ def setRotation(self,rotation):
+ """Set the rotation for this screen
+
+ This method does not take effect immediately, only after
+ applyResolutionSetttings() has been called. See getAvailableRotations()
+ for how to find out which rotations are supported.
+
+ Keyword arguments:
+ rotation -- One of Screen.RR_Rotate_0, Screen.RR_Rotate_90,
+ Screen.RR_Rotate_180 or Screen.RR_Rotate_270
+ """
+ self.currentrotation = rotation
+
+ def getAvailableRotations(self):
+ """Get the supported rotations for this screen.
+
+ Returns a bitmask of support rotations for this screen. The returned
+ integer is the bitwise OR of one or more of the constants here below.
+ * Screen.RR_Rotate_0
+ * Screen.RR_Rotate_90
+ * Screen.RR_Rotate_180
+ * Screen.RR_Rotate_270
+ """
+ if self.x_live_screen is not None and self.x_live_screen.resolutionSupportAvailable():
+ return self.x_live_screen.getAvailableRotations() & \
+ (self.RR_Rotate_0 | self.RR_Rotate_90 | self.RR_Rotate_180 | self.RR_Rotate_270)
+ else:
+ return self.RR_Rotate_0 # FIXME
+
+
+ # Reflection
+ def getReflection(self):
+ """Get the current reflection settings for this screen.
+
+ Returns the reflection settings as a bit string. Use Screen.RR_Reflect_X
+ and Screen.RR_Reflect_Y as bitmasks to determine which reflections are
+ in use.
+ """
+ return self.currentreflection
+
+ def setReflection(self,reflection):
+ """Set the reflection settings for this screen.
+
+ This method does not take effect immediately, only after
+ applyResolutionSetttings() has been called. See getAvailableReflections()
+ for how to find out which rotations are supported.
+
+ Keyword arguments:
+ reflection -- Bit string (Python integer) of desired reflections.
+ Bitwise OR Screen.RR_Reflect_X and Screen.RR_Reflect_Y
+ to construct the string.
+ """
+ self.currentreflection = reflection
+
+ def getAvailableReflections(self):
+ """Get the supported reflections for this screen.
+
+ Returns a bit string (Python integer) of supported reflections. Use
+ Screen.RR_Reflect_X and Screen.RR_Reflect_Y as bitmasks to determine
+ which reflections are available.
+ """
+ if self.x_live_screen is not None and self.x_live_screen.resolutionSupportAvailable():
+ return self.x_live_screen.getAvailableRotations() & (self.RR_Reflect_X | self.RR_Reflect_Y)
+ else:
+ return 0 # FIXME
+
+ # Refresh rates
+ def getRefreshRateIndex(self):
+ """Get the current refresh rate index for this screen.
+
+ Returns an index into the list of refresh rates. See getAvailableRefreshRates().
+ """
+ rates = self.getAvailableRefreshRates()
+ i = 0
+ for r in rates:
+ if r>=self.currentrefreshrate:
+ return i
+ i += 1
+ return len(rates)-1
+
+ def setRefreshRateIndex(self,index):
+ """Set the refresh rate for this screen.
+
+ Keyword arguments:
+ index -- Index into the list of refresh rates. See getAvailableRefreshRates().
+ """
+ self.currentrefreshrate = self.getAvailableRefreshRates()[index]
+
+ def getAvailableRefreshRates(self):
+ """Get the list of available refresh rates
+
+ Get the list of available refresh rates for the currently selected
+ resolution. See setResolutionIndex() and getAvailableRefreshRatesForResolution()
+
+ Returns a list of integers in Hz.
+ """
+ return self.getAvailableRefreshRatesForResolution(self.currentsizeindex)
+
+ def getAvailableRefreshRatesForResolution(self,resolution_index):
+ """Get the list of available refresh rates for the given resolution
+
+ Get the list of available refresh rates for the given resolution.
+
+ Keyword arguments:
+ resolution_index -- Index into the list of resolutions.
+
+ Returns a list of integers in Hz.
+ """
+ isize = self.available_sizes[resolution_index]
+ if self.isResolutionLive():
+ j = 0
+ for size in self.x_live_screen.getAvailableSizes():
+ (sw,sh,wm,hm) = size
+ if isize==(sw,sh):
+ rates = self.x_live_screen.getAvailableRefreshRates(j)
+ rates.sort()
+ return rates
+ j += 1
+ assert False,"Can't find matching screen resolution"
+ else:
+ #
+ rates = []
+ for mode in self.mode_list:
+ if isize==(mode.getWidth(),mode.getHeight()):
+ rates.append(mode.getVRefresh())
+
+ rates.sort()
+ return rates
+
+ # Applying changes.
+
+ def isResolutionLive(self):
+ return self.x_live_screen is not None and \
+ self.x_live_screen.resolutionSupportAvailable() and \
+ self.original_monitor_model is self.monitor_model and \
+ self.original_monitor_aspect==self.monitor_aspect
+
+ def isResolutionSettingsChanged(self):
+ try:
+ current_size = self.getAvailableResolutions()[self.currentsizeindex]
+ except IndexError:
+ #FIXME: why does this happen?
+ return False
+ return current_size != self.original_size or \
+ self.currentrefreshrate != self.originalrefreshrate or \
+ self.currentrotation != self.originalrotation or \
+ self.currentreflection != self.originalreflection
+
+ def applyResolutionSettings(self):
+ """Apply any tending resolution changes on the X server if possible.
+
+
+ """
+ if self.isResolutionSettingsChanged() and self.isResolutionLive():
+ # Work out what the correct index is for randr.
+ (width,height) = self.available_sizes[self.currentsizeindex]
+ sizeindex = 0
+ for size in self.x_live_screen.getAvailableSizes():
+ (pw,ph,wm,hm) = size
+ if pw==width and ph==height:
+ break
+ sizeindex += 1
+
+ rc = self.x_live_screen.setScreenConfigAndRate(sizeindex, \
+ self.currentrotation | self.currentreflection, self.currentrefreshrate)
+
+ # FIXME this can fail if the config on the server has been updated.
+
+ def acceptResolutionSettings(self):
+ """Accept the last resolution change
+ """
+ self.originalsizeindex = self.currentsizeindex
+ self.original_size = self.getAvailableResolutions()[self.currentsizeindex]
+ self.originalrefreshrate = self.currentrefreshrate
+ self.originalrotation = self.currentrotation
+ self.originalreflection = self.currentreflection
+
+ def revertResolutionSettings(self):
+ """Revert the last resolution change on the X server
+
+ """
+ if self.x_live_screen is not None and self.x_live_screen.resolutionSupportAvailable():
+ # Work out what the correct index is for randr.
+ (width,height) = self.available_sizes[self.originalsizeindex]
+ sizeindex = 0
+ for size in self.x_live_screen.getAvailableSizes():
+ (pw,ph,wm,hm) = size
+ if pw==width and ph==height:
+ break
+ sizeindex += 1
+
+ self.x_live_screen.setScreenConfigAndRate(sizeindex, \
+ self.originalrotation | self.originalreflection, self.originalrefreshrate)
+ # FIXME this can fail if the config on the server has been updated.
+
+ def resetResolutionSettings(self):
+ """Reset the resolution settings to the last accepted state
+
+ """
+ # Restore the resolution settings to their original state.
+ self.currentsizeindex = self.originalsizeindex
+ self.currentrefreshrate = self.originalrefreshrate
+ self.currentrotation = self.originalrotation
+ self.currentreflection = self.originalreflection
+
+ def isGammaSettingsChanged(self):
+ return self.redgamma != self.originalredgamma or \
+ self.greengamma != self.originalgreengamma or \
+ self.bluegamma != self.originalbluegamma or \
+ self.allgamma != self.originalallgamma or \
+ self.settingall != self.originalsettingall
+
+ def acceptGammaSettings(self):
+ (self.originalredgamma, self.originalgreengamma, self.originalbluegamma) = (
+ self.redgamma, self.greengamma, self.bluegamma)
+ self.originalallgamma = self.allgamma
+ self.originalsettingall = self.settingall
+
+ def revertGammaSettings(self):
+ (self.redgamma, self.greengamma, self.bluegamma) = (
+ self.originalredgamma, self.originalgreengamma, self.originalbluegamma)
+ self.allgamma = self.originalallgamma
+ self.settingall = self.originalsettingall
+
+ if self.x_live_screen is not None:
+ if self.settingall:
+ self.x_live_screen.setGamma( (self.allgamma,self.allgamma,self.allgamma) )
+ else:
+ self.x_live_screen.setGamma( (self.redgamma,self.greengamma,self.bluegamma) )
+
+ def isGammaSettingsChanged(self):
+ if self.settingall:
+ return self.originalallgamma != self.allgamma
+ else:
+ return self.originalredgamma != self.redgamma or \
+ self.originalgreengamma != self.greengamma or \
+ self.originalbluegamma != self.bluegamma
+
+ def reset(self):
+ if self.isLive():
+ self.revertGammaSettings()
+ self.resetResolutionSettings()
+
+ self.monitor_model = self.original_monitor_model
+ self.monitor_aspect = self.original_monitor_aspect
+
+ def getRestartHint(self):
+ if self.original_monitor_model is not self.monitor_model \
+ or self.original_monitor_aspect != self.monitor_aspect \
+ or (self.isResolutionSettingsChanged() and not self.isResolutionLive()):
+ return XSetup.RESTART_X
+ return XSetup.RESTART_NONE
+
+ def _syncXorgConfig(self,x_device):
+ layout = self.gfx_card.getLayout()
+
+ if self.x_config_screen is None:
+ self.x_config_screen = self.x_config.makeSection('',['section','screen'])
+ self.x_config.append(self.x_config_screen)
+ self.x_config_screen.identifier = self.x_config.createUniqueIdentifier("screen")
+ self.x_config_screen.device = x_device.identifier
+
+ bit_depth = self.gfx_card.setup._getColorDepth()
+ self.x_config_screen.defaultdepth = bit_depth
+
+ # Maybe we don't have a X config monitor section.
+ if self.x_config_monitor is None:
+ # Make a monitor section.
+ self.x_config_monitor = self.x_config.makeSection('',['section','monitor'])
+ self.x_config.append(self.x_config_monitor)
+ self.x_config_monitor.identifier = self.x_config.createUniqueIdentifier("monitor")
+ self.x_config_screen.monitor = self.x_config_monitor.identifier
+
+ # Empty the monitor section and fill it in again.
+ monitor_identifier = self.x_config_monitor.identifier
+ self.x_config_monitor.clear()
+ self.x_config_monitor.identifier = monitor_identifier
+
+ if self.monitor_model is not None:
+ if self.monitor_model.getManufacturer() is not None:
+ self.x_config_monitor.vendorname = self.monitor_model.getManufacturer()
+
+ self.x_config_monitor.modelname = self.monitor_model.getName()
+
+ if self.monitor_model.getType()!=MonitorModel.TYPE_PLUGNPLAY:
+ if self.monitor_model.getHorizontalSync() is not None:
+ hsyncline = self.x_config_monitor.makeLine(None,['HorizSync',self.monitor_model.getHorizontalSync()])
+ self.x_config_monitor.append(hsyncline)
+
+ if self.monitor_model.getVerticalSync() is not None:
+ vsyncline = self.x_config_monitor.makeLine(None,['VertRefresh',self.monitor_model.getVerticalSync()])
+ self.x_config_monitor.append(vsyncline)
+
+ # Add a bunch of standard mode lines.
+ mode_list = GetMonitorModeDB().getAvailableModes(self.monitor_model,self.monitor_aspect)
+
+ if mode_list is not None:
+
+ # Filter the mode list by video memory.
+ color_bytes = bit_depth/8
+ if self.gfx_card.getGfxCardModel().getNeedVideoRam():
+ video_memory = self.gfx_card.getVideoRam()
+ else:
+ video_memory = 65536 # Big enough.
+ video_memory *= 1024 # Convert to bytes.
+ mode_list = [mode for mode in mode_list if mode.getWidth()*mode.getHeight()*color_bytes <= video_memory]
+
+ def mode_cmp(a,b): return cmp(a.getWidth(),b.getWidth())
+ mode_list.sort(mode_cmp)
+
+ for mode in mode_list:
+ modeline = self.x_config_monitor.modeline.makeLine(None,mode.getXorgModeLineList())
+ self.x_config_monitor.modeline.append(modeline)
+
+ # Specify the preferred resolution.
+
+ # Get rid of any old display subsections.
+ for display_section in self.x_config_screen.getSections('display'):
+ self.x_config_screen.remove(display_section)
+
+ try:
+ (preferred_width, preferred_height) = self.getAvailableResolutions()[self.currentsizeindex]
+ preferred_rate = self.getAvailableRefreshRates()[self.getRefreshRateIndex()]
+ except IndexError, errmsg:
+ # This is presumed to be better than a crash:
+ print "Failed to get preferred width, height, or rate - Assuming none. IndexError: ", errmsg
+ preferred_width = 0
+ preferred_height = 0
+ preferred_rate = 0
+
+ # Find the monitor supported mode that best matches what the user has selected.
+ best_score = 2000000 # big number.
+ best_index = 0
+ for i in range(len(mode_list)):
+ mode = mode_list[i]
+ new_score = abs(mode.getWidth()-preferred_width) + \
+ abs(mode.getHeight()-preferred_height) + \
+ abs(mode.getVRefresh()-preferred_rate)
+ if new_score < best_score:
+ best_index = i
+ best_score = new_score
+
+ # This is all about putting the list of resolutions into a
+ # sensible preferred order starting with what the user has chosen
+ # and then the rest of the resolutions.
+ lower = best_index - 1
+ higher = best_index + 1
+ len_modes = len(mode_list)
+
+ mode_indexes = []
+ mode_indexes.append(best_index)
+ while lower>=0 or higher<len_modes: # interlace the two sets of indexes.
+ if higher<len_modes:
+ mode_indexes.append(higher)
+ higher += 1
+ if lower>=0:
+ mode_indexes.append(lower)
+ lower -= 1
+
+ # Convert the list of resolution indexes into monitor mode names and a modes line for xorg.conf.
+ mode_list_line = ['modes']
+ mode_list_line.extend([ mode_list[mode_index].getName() for mode_index in mode_indexes ])
+
+ # Create the Display subsections in the Screen section.
+ display_section = self.x_config_screen.makeSection(None,['SubSection','Display'])
+ display_section.depth = bit_depth
+
+ # The virtual screen size hack should not be used in combination
+ # with Xinerama (RandR doesn't work with Xinerama).
+ if layout!=XSetup.LAYOUT_SINGLE_XINERAMA and self.isLive():
+ # Find the largest monitor supported mode. We need this info
+ # to set the size of the virtual screen. See the big comment
+ # in displayconfig-restore.py.
+ virtual_width = max([mode_list[mode_index].getWidth() for mode_index in mode_indexes])
+ virtual_height = max([mode_list[mode_index].getHeight() for mode_index in mode_indexes])
+ display_section.append(display_section.makeLine(None,["virtual",virtual_width,virtual_height]))
+
+ display_section.append(display_section.makeLine(None,mode_list_line))
+
+ self.x_config_screen.append(display_section)
+
+ # Set the gamma info too.
+ if self.settingall:
+ gamma_row = self.x_config_monitor.makeLine(None,['gamma',str(self.allgamma)])
+ else:
+ gamma_row = self.x_config_monitor.makeLine(None,['gamma',str(self.redgamma),str(self.greengamma),str(self.bluegamma)])
+ self.x_config_monitor.append(gamma_row)
+
+ # If resolution changes were not live because the monitor has been changed
+ # then we also stop them from being live from now on too.
+ if not self.isResolutionLive():
+ self.x_live_screen = None
+ self.acceptResolutionSettings()
+
+ # The orignal monitor model is now the selected one. => no changes need to be applied now.
+ self.original_monitor_model = self.monitor_model
+ self.original_monitor_aspect = self.monitor_aspect
+
+ def _getXorgScreenSection(self):
+ return self.x_config_screen
+
+ def _getGfxCard(self):
+ return self.gfx_card
+
+ def __str__(self):
+ # FIXME string = str(self.getIdentifier()) + " {"
+ string = " {"
+ if self.isLive():
+ string += "Size: "
+ string += str(self.getAvailableResolutions()[self.getResolutionIndex()])
+ string += " "
+ else:
+ string += "Not live, "
+ if self.monitor_model is not None:
+ string += "Monitor:" + str(self.monitor_model)
+ string += "}"
+ return string
+
+############################################################################
+class GfxCardModel(object):
+ """Describes the properties of a particular model of graphics card.
+
+ """
+ def __init__(self,name):
+ self.name = name
+ self.vendor = None
+ self.server = None
+ self.driver = None
+ self.proprietarydriver = None
+ self.lines = []
+ self.seeobj = None
+ self.noclockprobe = None
+ self.unsupported = None
+ self.driglx = None
+ self.utahglx = None
+ self.driglxexperimental = None
+ self.utahglxexperimental = None
+ self.badfbrestore = None
+ self.badfbrestoreexf3 = None
+ self.multihead = None
+ self.fbtvout = None
+ self.needvideoram = None
+
+ def getName(self): return self.name
+
+ def setVendor(self,vendor): self.vendor = vendor
+ def getVendor(self): return self._get(self.vendor,"getVendor",None)
+ def setServer(self,server): self.server = server
+ def getServer(self): return self._get(self.server,"getServer",None)
+ def setDriver(self,driver): self.driver = driver
+ def getDriver(self): return self._get(self.driver,"getDriver",None)
+ def setProprietaryDriver(self,proprietarydriver): self.proprietarydriver = proprietarydriver
+ def getProprietaryDriver(self): return self._get(self.proprietarydriver,"getProprietaryDriver",None)
+ def addLine(self,line): self.lines.append(line)
+ def getLines(self):
+ if (len(self.lines)==0) and (self.seeobj is not None):
+ return self.seeobj.getLines()
+ else:
+ return self.lines[:] # Copy
+
+ def setNoClockProbe(self,noprobe): self.noclockprobe = noprobe
+ def getNoClockProbe(self): return self._get(self.noclockprobe,"getNoClockProbe",False)
+ def setUnsupported(self,unsupported): self.unsupported = unsupported
+ def getUnsupported(self): return self._get(self.unsupported,"getUnsupported",False)
+ def setDriGlx(self,on): self.driglx = on
+ def getDriGlx(self): return self._get(self.driglx,"getDriGlx",False)
+ def setUtahGlx(self,on): self.utahglx = on
+ def getUtahGlx(self): return self._get(self.utahglx,"getUtahGlx",False)
+ def setDriGlxExperimental(self,on): self.driglxexperimental = on
+ def getDriGlxExperimental(self): return self._get(self.driglxexperimental,"getDriGlxExperimental",False)
+ def setUtahGlxExperimental(self,on): self.utahglxexperimental = on
+ def getUtahGlxExperimental(self): return self._get(self.utahglxexperimental,"getUtahGlxExperimental",False)
+ def setBadFbRestore(self,on): self.badfbrestore = on
+ def getBadFbRestore(self,proprietary=False):
+ if proprietary:
+ driver = self.getProprietaryDriver()
+ else:
+ driver = self.getDriver()
+ if driver in ['i810','intel','fbdev','nvidia','vmware']:
+ return True
+ if self.badfbrestore is not None:
+ return self.badfbrestore
+ if self.seeobj is not None:
+ return self.seeobj.getBadFbRestore(proprietary)
+ return False
+ def setBadFbRestoreXF3(self,on): self.badfbrestoreexf3 = on
+ def getBadFbRestoreXF3(self): return self._get(self.badfbrestoreexf3,"getBadFbRestoreXF3",False)
+ def setMultiHead(self,n): self.multihead = n
+ def getMultiHead(self): return self._get(self.multihead,"getMultiHead",1)
+ def setFbTvOut(self,on): self.fbtvout = on
+ def getFbTvOut(self): return self._get(self.fbtvout,"getFbTvOut",False)
+ def setNeedVideoRam(self,on): self.needvideoram = on
+ def getNeedVideoRam(self): return self._get(self.needvideoram,"getNeedVideoRam",False)
+ def setSee(self,seeobj): self.seeobj = seeobj
+
+ # If the seeobj is set, then all attributes that are not filled in for this
+ # instance are inheritted from seeobj.
+ def _get(self,attr,meth,default):
+ if attr is not None:
+ return attr
+ if self.seeobj is not None:
+ return getattr(self.seeobj,meth)()
+ else:
+ return default
+
+ def __str__(self):
+ return self.getName()
+
+############################################################################
+gfxcard_model_db_instance = None # Singleton.
+
+def GetGfxCardModelDB():
+ """Returns a GfxCardModelDB instance.
+ """
+ global gfxcard_model_db_instance
+ # Lazy instantiation.
+ if gfxcard_model_db_instance is None:
+ gfxcard_model_db_instance = GfxCardModelDB()
+ return gfxcard_model_db_instance
+
+############################################################################
+class GfxCardModelDB(object):
+ def __init__(self):
+ # List of gfx card databases, if order of preference.
+ filename = '/usr/share/ldetect-lst/Cards+'
+ if not os.path.exists(filename):
+ filename = os.path.join(data_file_dir,"Cards+")
+
+ # The card DB. A dict mapping card names to card objects.
+ self.db = {}
+ # The keys in this dict will be vendor names, values are dicts mapping card names to objects.
+ self.vendordb = {}
+ self.driverdb = {}
+
+ self.drivers = self._getAvailableDrivers()
+
+ self.proprietary_drivers = []
+
+ self._checkProprietaryDrivers()
+ self._loadDrivers(self.drivers, self.proprietary_drivers)
+ self._loadDB(filename)
+
+ def getGfxCardModelByName(self,name):
+ return self.db[name]
+
+ def getGfxCardModelByDriverName(self,driver_name):
+ return self.driverdb[driver_name]
+
+ def getAllGfxCardModelNames(self):
+ return self.db.keys()
+
+ def _getDriverDirs(self):
+ "Returns a list of directories where X driver files may be located"
+
+ # Fallback dir:
+ defaultDirs = ["/usr/lib/xorg/modules/drivers/"]
+
+ # Get display number:
+ display_number = 0
+ if "DISPLAY" in os.environ:
+ display_name = os.environ["DISPLAY"]
+ displayRE = re.compile("^.*:(\d+)\.\d+$")
+ m = displayRE.match(display_name)
+ if m:
+ display_number = int(m.group(1))
+ else:
+ print "failed to parse display number from '%s' - falling back to default (%d)" % (display_name, display_number)
+ else:
+ print "$DISPLAY not set - falling back to default number (%d)" % display_number
+
+ # Get the list of module paths from the Xorg log file:
+ XLogfile = "/var/log/Xorg.%d.log" % display_number
+ cmd = "awk -F \" ModulePath set to \" '/^\(..\) ModulePath set to (.*)/ {print $2}' %s" % XLogfile
+
+ baseList = os.popen(cmd).readline().strip().strip('"')
+ if baseList == "":
+ print "warning: failed to get module paths from '%s' - falling back to default" % XLogfile
+ return defaultDirs
+
+ pathList = []
+ for basePath in baseList.split(","):
+ pathList.append("%s/drivers/" % basePath)
+
+ return pathList
+
+ def _getAvailableDrivers(self):
+ """
+ Returns the list of available X graphics drivers.
+ Algorithm taken from Xorg source (see GenerateDriverlist() in xf86Config.C).
+ """
+
+ # These are drivers that cannot actually be used in xorg.conf, hence they are hidden:
+ hiddenDrivers = (
+ "atimisc", # seems to be just the internal implementation for ati driver
+ "dummy", # dummy driver without any output
+ "v4l", # not an actual video device driver, but just the v4l module
+ "ztv" # seems to be the TV output module for AMD Geode
+ )
+
+ drivers = []
+ driverDirectories = self._getDriverDirs()
+
+ driverNameRE = re.compile("^(.+)_drv.(s)?o$")
+ for ddir in driverDirectories:
+ try:
+ driverFiles = os.listdir(ddir)
+ except OSError:
+ print "error reading directory '%s'" % ddir
+ continue
+ for f in driverFiles:
+ m = driverNameRE.match(f)
+ if m:
+ driverName = m.group(1)
+ if driverName in drivers:
+ print "ignoring duplicate driver '%s/%s'" % (ddir, f)
+ else:
+ if driverName in hiddenDrivers:
+ #print "ignoring hidden driver '%s'" % driverName
+ pass
+ else:
+ drivers.append(driverName)
+ else:
+ #print "ignoring driver file with invalid name '%s'" % f
+ pass
+ #print "found %d drivers" % len(drivers)
+ return drivers
+
+ def _checkProprietaryDrivers(self):
+ # Check for the NVidia driver.
+ # FIXME x86_64 => 'lib64'
+
+ if (os.path.exists("/usr/X11R6/lib/modules/drivers/nvidia_drv.o") and \
+ os.path.exists("/usr/X11R6/lib/modules/extensions/libglx.so")) \
+ or \
+ (os.path.exists("/usr/lib/xorg/modules/drivers/nvidia_drv.o") and \
+ os.path.exists("/usr/lib/xorg/modules/libglx.so")) \
+ or \
+ (os.path.exists("/usr/lib/xorg/modules/drivers/nvidia_drv.so") and \
+ os.path.exists("/usr/lib/xorg/modules/extensions/libglx.so")):
+ self.proprietary_drivers.append("nvidia")
+
+ # Check for the ATI driver
+ if (os.path.exists("/usr/X11R6/lib/modules/dri/fglrx_dri.so") and \
+ os.path.exists("/usr/X11R6/lib/modules/drivers/fglrx_drv.o")) or \
+ (os.path.exists("/usr/lib/dri/fglrx_dri.so") and \
+ os.path.exists("/usr/lib/xorg/modules/drivers/fglrx_drv.so")):
+ self.proprietary_drivers.append("fglrx")
+
+ # FIXME MATROX_HAL?
+
+ def _loadDrivers(self, drivers, proprietary_drivers):
+ # Insert the Driver entries.
+ for drivername in drivers:
+ cardobj = GfxCardModel(drivername)
+ cardobj.setDriver(drivername)
+ self.db[drivername] = cardobj
+ self.driverdb[drivername] = cardobj
+
+ if drivername=="nv" and "nvidia" in proprietary_drivers:
+ cardobj.setProprietaryDriver("nvidia")
+ self.driverdb["nvidia"] = cardobj
+ elif drivername=="ati" and "fglrx" in proprietary_drivers:
+ cardobj.setProprietaryDriver("fglrx")
+ self.driverdb["fglrx"] = cardobj
+
+ def _loadDB(self,filename):
+ vendors = ['3Dlabs', 'AOpen', 'ASUS', 'ATI', 'Ark Logic', 'Avance Logic',
+ 'Cardex', 'Chaintech', 'Chips & Technologies', 'Cirrus Logic', 'Compaq',
+ 'Creative Labs', 'Dell', 'Diamond', 'Digital', 'ET', 'Elsa', 'Genoa',
+ 'Guillemot', 'Hercules', 'Intel', 'Leadtek', 'Matrox', 'Miro', 'NVIDIA',
+ 'NeoMagic', 'Number Nine', 'Oak', 'Orchid', 'RIVA', 'Rendition Verite',
+ 'S3', 'Silicon Motion', 'STB', 'SiS', 'Sun', 'Toshiba', 'Trident',
+ 'VideoLogic']
+
+ cardobj = None
+ # FIXME the file might be compressed.
+ fhandle = open(filename,'r')
+ for line in fhandle.readlines():
+ line = line.strip()
+ if len(line)!=0:
+ if not line.startswith("#"):
+ if line.startswith("NAME"):
+ cardobj = GfxCardModel(line[4:].strip())
+ cardname = cardobj.getName()
+ self.db[cardname] = cardobj
+
+ # Try to extract a vendor name from the card's name.
+ for vendor in vendors:
+ if vendor in cardname:
+ cardobj.setVendor(vendor)
+ if vendor not in self.vendordb:
+ self.vendordb[vendor] = {}
+ self.vendordb[vendor][cardname] = cardobj
+ break
+ else:
+ if "Other" not in self.vendordb:
+ self.vendordb["Other"] = {}
+ self.vendordb["Other"][cardname] = cardobj
+
+ elif line.startswith("SERVER"):
+ cardobj.setServer(line[6:].strip())
+ elif line.startswith("DRIVER2"):
+ driver = line[7:].strip()
+ if driver in self.proprietary_drivers:
+ cardobj.setProprietaryDriver(driver)
+ elif line.startswith("DRIVER"):
+ cardobj.setDriver(line[6:].strip())
+ elif line.startswith("LINE"):
+ cardobj.addLine(line[4:].strip())
+ elif line.startswith("SEE"):
+ try:
+ cardobj.setSee(self.db[line[3:].strip()])
+ except KeyError:
+ pass
+ elif line.startswith("NOCLOCKPROBE"):
+ cardobj.setNoClockProbe(True)
+ elif line.startswith("UNSUPPORTED"):
+ cardobj.setUnsupported(True)
+ elif line.startswith("DRI_GLX"):
+ cardobj.setDriGlx(True)
+ elif line.startswith("UTAH_GLX"):
+ cardobj.setUtahGlx(True)
+ elif line.startswith("DRI_GLX_EXPERIMENTAL"):
+ cardobj.setDriGlxExperimental(True)
+ elif line.startswith("UTAH_GLX_EXPERIMENTAL"):
+ cardobj.setUtahGlxExperimental(True)
+ elif line.startswith("BAD_FB_RESTORE"):
+ cardobj.setBadFbRestore(True)
+ elif line.startswith("BAD_FB_RESTORE_XF3"):
+ cardobj.setBadFbRestoreXF3(True)
+ elif line.startswith("MULTI_HEAD"):
+ cardobj.setMultiHead(int(line[10:].strip()))
+ elif line.startswith("FB_TVOUT"):
+ cardobj.setFbTvOut(True)
+ elif line.startswith("NEEDVIDEORAM"):
+ cardobj.setNeedVideoRam(True)
+ fhandle.close()
+
+############################################################################
+class MonitorModel(object):
+ TYPE_NORMAL = 0
+ TYPE_PLUGNPLAY = 1
+ TYPE_CUSTOM = 2
+
+ def __init__(self):
+ self.name = None
+ self.manufacturer = None
+ self.eisaid = None
+ self.horizontalsync = None
+ self.verticalsync = None
+ self.dpms = False
+ self.type = MonitorModel.TYPE_NORMAL
+
+ def copy(self):
+ newmonitor = MonitorModel()
+ newmonitor.name = self.name
+ newmonitor.manufacturer = self.manufacturer
+ newmonitor.eisaid = self.eisaid
+ newmonitor.horizontalsync = self.horizontalsync
+ newmonitor.verticalsync = self.verticalsync
+ newmonitor.dpms = self.dpms
+ return newmonitor
+
+ def getName(self): return self.name
+ def setName(self,name): self.name = name
+ def getManufacturer(self): return self.manufacturer
+ def setManufacturer(self,manufacturer): self.manufacturer = manufacturer
+ def setEisaId(self,eisaid): self.eisaid = eisaid
+ def getEisaId(self): return self.eisaid
+ def setDpms(self,on): self.dpms = on
+ def getDpms(self): return self.dpms
+ def getHorizontalSync(self): return self.horizontalsync
+ def setHorizontalSync(self,horizontalsync): self.horizontalsync = horizontalsync
+ def getVerticalSync(self): return self.verticalsync
+ def setVerticalSync(self,verticalsync): self.verticalsync = verticalsync
+ def setType(self,flag): self.type = flag
+ def getType(self): return self.type
+ def __str__(self):
+ return "{Name:"+self.name+"}"
+
+############################################################################
+class PlugNPlayMonitorModel(MonitorModel):
+ def __init__(self,monitor_model_db):
+ MonitorModel.__init__(self)
+ self.monitor_detected = False
+ self.monitor_model_db = monitor_model_db
+
+ def getEisaId(self):
+ self._detectMonitor()
+ return self.eisaid
+
+ def getHorizontalSync(self):
+ self._detectMonitor()
+ return self.horizontalsync
+
+ def getVerticalSync(self):
+ self._detectMonitor()
+ return self.verticalsync
+
+ def _detectMonitor(self):
+ if not self.monitor_detected:
+ (eisaid, horizontalsync, verticalsync) = self.monitor_model_db._detectMonitor()
+ if eisaid is not None:
+ self.eisaid = eisaid
+ if horizontalsync is not None:
+ self.horizontalsync = horizontalsync
+ if verticalsync is not None:
+ self.verticalsync = verticalsync
+
+ self.monitor_detected = True
+
+############################################################################
+monitor_model_db_instance = None # Singleton
+
+def GetMonitorModelDB(force=False):
+ """Returns a GetMonitorModelDB instance.
+ """
+ global monitor_model_db_instance
+ if monitor_model_db_instance is None or force == True:
+ monitor_model_db_instance = MonitorModelDB()
+ return monitor_model_db_instance
+
+############################################################################
+class MonitorModelDB(object):
+ def __init__(self):
+ self.db = {}
+ self.vendordb = {}
+ self.genericdb = {}
+ self.customdb = {}
+ self.custom_counter = 1
+ self.monitor_detect_run = False
+
+ # Plug'n Play is a kind of fake entry for monitors that are detected but unknown.
+ # It's frequency info is filled in by hardware detection or from the X server config.
+ self._plugnplay = PlugNPlayMonitorModel(self)
+ self._plugnplay.setName("Plug 'n' Play")
+ self._plugnplay.setManufacturer(self._plugnplay.getName())
+ self._plugnplay.setType(MonitorModel.TYPE_PLUGNPLAY)
+ # This default is what Xorg claims to use when there is no
+ # horizontal sync info in the a monitor section.
+ self._plugnplay.setHorizontalSync("28.0-33.0")
+ # This default is what Xorg claims to use when there is no
+ # vertical sync info in the a monitor section.
+ self._plugnplay.setVerticalSync("43-72")
+ self.customdb[self._plugnplay.getName()] = self._plugnplay
+ self.db[self._plugnplay.getName()] = self._plugnplay
+
+ # Load monitors from the shipped database
+ filename = "/usr/share/ldetect-lst/MonitorsDB"
+ if not os.path.exists(filename):
+ filename = os.path.join(data_file_dir,"MonitorsDB")
+ self.load(filename)
+ # Load monitors from the custom database
+ filename = os.path.join(var_data_dir, "CustomMonitorsDB")
+ if os.path.exists(filename):
+ self.load(filename)
+
+ def load(self,filename,split=";"):
+ fhandle = open(filename,'r')
+ for line in fhandle.readlines():
+ line = line.strip()
+ if len(line)!=0:
+ if not line.startswith("#"):
+ try:
+ parts = line.split(split)
+ monitorobj = MonitorModel()
+ monitorobj.setManufacturer(parts[0].strip())
+ monitorobj.setName(parts[1].strip())
+ monitorobj.setEisaId(parts[2].strip().upper())
+ monitorobj.setHorizontalSync(parts[3].strip())
+ monitorobj.setVerticalSync(parts[4].strip())
+ if len(parts)>=6:
+ monitorobj.setDpms(parts[5].strip()=='1')
+ self.db[monitorobj.getName()] = monitorobj
+
+ if monitorobj.getManufacturer() in \
+ ["Generic LCD Display", "Generic CRT Display"]:
+ self.genericdb[monitorobj.getName()] = monitorobj
+ else:
+ if monitorobj.getManufacturer() not in self.vendordb:
+ self.vendordb[monitorobj.getManufacturer()] = {}
+ self.vendordb[monitorobj.getManufacturer()]\
+ [monitorobj.getName()] = monitorobj
+
+ except IndexError:
+ print "Bad monitor line:",line
+ fhandle.close()
+
+ def getMonitorByName(self,name):
+ return self.db.get(name,None)
+
+ def newCustomMonitor(self,name=None):
+ custom_model = MonitorModel()
+ if name is None:
+ name = "Custom %i" % self.custom_counter
+ custom_model.setName(name)
+ self.db[custom_model.getName()] = custom_model
+ self.customdb[name] = custom_model
+ self.custom_counter += 1
+ return custom_model
+
+ def getCustomMonitors(self):
+ return self.customdb
+
+ def detect(self):
+ """Detect the attached monitor.
+
+ Returns a 'monitor' object on success, else None.
+ """
+ (eisaid,hrange,vrange) = self._detectMonitor()
+
+ # Look up the EISAID in our database.
+ if eisaid is not None:
+ for monitor in self.db:
+ if eisaid==self.db[monitor].getEisaId():
+ return self.db[monitor]
+
+ return self._plugnplay
+
+ def _detectMonitor(self):
+ if not self.monitor_detect_run:
+ eisaid = None
+ hrange = None
+ vrange = None
+
+ if os.path.isfile("/usr/sbin/monitor-edid"):
+ # This utility appeared in Mandriva 2005 LE
+ output = ExecWithCapture("/usr/sbin/monitor-edid",["monitor-edid","-v"])
+ for line in output.split("\n"):
+ if "HorizSync" in line:
+ hrange = line.split()[1]
+ elif "VertRefresh" in line:
+ vrange = line.split()[1]
+ elif line.startswith("EISA ID:"):
+ eisaid = line[9:].upper()
+
+ elif os.path.isfile("/usr/sbin/ddcxinfos"):
+ # This utility _was_ standard on Mandrake 10.1 and earlier.
+ output = ExecWithCapture("/usr/sbin/ddcxinfos",["ddcxinfos"])
+ for line in output.split("\n"):
+ if "HorizSync" in line:
+ hrange = line.split()[0]
+ elif "VertRefresh" in line:
+ vrange = line.split()[0]
+ elif "EISA ID=" in line:
+ eisaid = line[line.find("EISA ID=")+8:].upper()
+
+ elif os.path.isfile("/usr/sbin/ddcprobe"):
+ # on Debian
+ """
+ ddcprobe's output looks like this:
+
+ ...
+ eisa: SAM00b1
+ ...
+ monitorrange: 30-81, 56-75
+ ...
+ """
+ output = ExecWithCapture("/usr/sbin/ddcprobe",["ddcprobe"])
+ for line in output.split("\n"):
+ if line.startswith("eisa:"):
+ parts = line.split(":")
+ if len(parts)>=2:
+ eisaid = parts[1].strip().upper()
+ elif line.startswith("monitorrange:"):
+ parts = line.replace(',','').split()
+ if len(parts)==3:
+ hrange = parts[1].strip()
+ vrange = parts[2].strip()
+
+ self.detected_eisa_id = eisaid
+ self.detected_h_range = hrange
+ self.detected_v_range = vrange
+ self.monitor_detect_run = True
+
+ return (self.detected_eisa_id, self.detected_h_range, self.detected_v_range)
+
+############################################################################
+
+SYNC_TOLERANCE = 0.01 # 1 percent
+class ModeLine(object):
+ ASPECT_4_3 = 0
+ ASPECT_16_9 = 1
+
+ XF86CONF_PHSYNC = 0x0001
+ XF86CONF_NHSYNC = 0x0002
+ XF86CONF_PVSYNC = 0x0004
+ XF86CONF_NVSYNC = 0x0008
+ XF86CONF_INTERLACE = 0x0010
+ XF86CONF_DBLSCAN = 0x0020
+ XF86CONF_CSYNC = 0x0040
+ XF86CONF_PCSYNC = 0x0080
+ XF86CONF_NCSYNC = 0x0100
+ XF86CONF_HSKEW = 0x0200 # hskew provided
+ XF86CONF_BCAST = 0x0400
+ XF86CONF_CUSTOM = 0x0800 # timing numbers customized by editor
+ XF86CONF_VSCAN = 0x1000
+ flags = {"interlace": XF86CONF_INTERLACE,
+ "doublescan": XF86CONF_DBLSCAN,
+ "+hsync": XF86CONF_PHSYNC,
+ "-hsync": XF86CONF_NHSYNC,
+ "+vsync": XF86CONF_PVSYNC,
+ "-vsync": XF86CONF_NVSYNC,
+ "composite": XF86CONF_CSYNC,
+ "+csync": XF86CONF_PCSYNC,
+ "-csync": XF86CONF_NCSYNC }
+
+ # Thanks go out to Redhat for this code donation. =)
+ def __init__(self, elements):
+ self.name = elements[1].strip('"')
+ self.clock = float(elements[2])
+ self.hdisp = int(elements[3])
+ self.hsyncstart = int(elements[4])
+ self.hsyncend = int(elements[5])
+ self.htotal = int(elements[6])
+ self.vdisp = int(elements[7])
+ self.vsyncstart = int(elements[8])
+ self.vsyncend = int(elements[9])
+ self.vtotal = int(elements[10])
+
+ self.flags = 0
+ for i in range(11, len(elements)):
+ try:
+ self.flags |= ModeLine.flags[string.lower(elements[i])]
+ except KeyError:
+ pass
+
+ def getWidth(self):
+ return self.hdisp
+
+ def getHeight(self):
+ return self.vdisp
+
+ def getName(self):
+ return self.name
+
+ def getVRefresh(self):
+ vrefresh = self.clock * 1000000.0 / float(self.htotal * self.vtotal)
+ if self.flags & ModeLine.XF86CONF_INTERLACE:
+ vrefresh = vrefresh * 2.0
+ if self.flags & ModeLine.XF86CONF_DBLSCAN:
+ vrefresh = vrefresh / 2.0
+ return int(round(vrefresh))
+
+ # Basically copied from xf86CheckModeForMonitor
+ def supports(self, monitor_hsync, monitor_vsync):
+ hsync = self.clock * 1000 / self.htotal
+ for freq in monitor_hsync:
+ if hsync > freq[0] * (1.0 - SYNC_TOLERANCE) and hsync < freq[1] * (1.0 + SYNC_TOLERANCE):
+ break
+ else:
+ return False
+
+ vrefresh = self.getVRefresh()
+ for freq in monitor_vsync:
+ if vrefresh > freq[0] * (1.0 - SYNC_TOLERANCE) and vrefresh < freq[1] * (1.0 + SYNC_TOLERANCE):
+ return True
+ return False
+
+ def getXorgModeLineList(self):
+ row = [self.name, str(self.clock), str(self.hdisp), str(self.hsyncstart), str(self.hsyncend),
+ str(self.htotal), str(self.vdisp), str(self.vsyncstart), str(self.vsyncend), str(self.vtotal)]
+
+ for (flag_name,flag_bit) in ModeLine.flags.iteritems():
+ if self.flags & flag_bit:
+ row.append(flag_name)
+ return row
+
+ def __str__(self):
+ return "ModeLine:"+self.name
+
+############################################################################
+monitor_mode_db_instance = None # Singleton
+
+
+def GetMonitorModeDB():
+ """Returns a GetMonitorModeDB instance.
+ """
+ global monitor_mode_db_instance
+ if monitor_mode_db_instance is None:
+ monitor_mode_db_instance = MonitorModeDB()
+ return monitor_mode_db_instance
+
+############################################################################
+class MonitorModeDB(object):
+ def __init__(self):
+ self.db = {}
+ self.db169 = {}
+
+ module_dir = os.path.dirname(os.path.join(os.getcwd(),__file__))
+ self.load(os.path.join(data_file_dir,"vesamodes"))
+ self.load(os.path.join(data_file_dir,"extramodes"))
+ self.load(os.path.join(data_file_dir,"widescreenmodes"))
+
+ # Make a list of screen sizes for the getAllResolutions() method.
+ self.all_resolutions = []
+ for mode in self.db.values()+self.db169.values():
+ size = (mode.getWidth(),mode.getHeight())
+ if size not in self.all_resolutions:
+ self.all_resolutions.append(size)
+
+ self.all_resolutions.sort()
+
+ def load(self,filename):
+ fd = open(filename, 'r')
+ lines = fd.readlines()
+ fd.close()
+
+ for line in lines:
+ if line[0] != "#" and line[0] != '/':
+ line = line.strip()
+ elements = line.split()
+ if line!="":
+ if len(elements) < 11 or string.lower(elements[0]) != "modeline":
+ print "Bad modeline found:",line
+ continue
+ name = elements[1][1:-1]
+ new_mode = ModeLine(elements)
+
+ width = new_mode.getWidth()
+ height = new_mode.getHeight()
+ if self.aspectRatio(width, height)==ModeLine.ASPECT_4_3:
+ self.db[name] = new_mode
+ else:
+ self.db169[name] = new_mode
+
+ if (width,height)==FALLBACK_RESOLUTION:
+ # We grab these modes and use them a fallbacks in the widescreen list.
+ self.db169[name] = new_mode
+
+ @staticmethod
+ def aspectRatio(width,height):
+ ratio = float(width)/float(height)
+ # 4/3 is 1.333333
+ # 16/9 is 1.777777
+ # We will just consider anything below 1.45 to be standard.
+ if ratio < 1.45:
+ return ModeLine.ASPECT_4_3
+ else:
+ return ModeLine.ASPECT_16_9
+
+ def getAvailableModes(self,monitor,aspect):
+ """
+ Get the list of video modes that this monitor supports.
+
+ Returns a list of modeline objects or None if the available modes for this monitor are unknown.
+ """
+ if monitor.horizontalsync is None or monitor.verticalsync is None:
+ return None
+
+ result = []
+
+ hsync_list = self._list_from_string(monitor.getHorizontalSync())
+ vsync_list = self._list_from_string(monitor.getVerticalSync())
+
+ if aspect==ModeLine.ASPECT_4_3:
+ db = self.db
+ else:
+ db = self.db169
+
+ for modeline in db.values():
+ if modeline.supports(hsync_list, vsync_list):
+ result.append(modeline)
+ return result
+
+ def getAllResolutions(self):
+ return self.all_resolutions
+
+ def _list_from_string(self,src):
+ l = []
+ pieces = src.split(",")
+ for piece in pieces:
+ tmp = string.split(piece, "-")
+ if len(tmp) == 1:
+ l.append( (float(tmp[0].strip()), float(tmp[0].strip())) )
+ else:
+ l.append( (float(tmp[0].strip()), float(tmp[1].strip())) )
+ return l
+
+############################################################################
+
+def ranges_to_string(array, length):
+ stringobj = ""
+ for i in range(length):
+ r = array[i]
+ if stringobj != "":
+ stringobj = stringobj + ","
+ if r[0] == r[1]:
+ stringobj = stringobj + repr(r[0])
+ else:
+ stringobj = stringobj + repr(r[0]) + "-" + repr(r[1])
+ return stringobj
+
+
+def main():
+ # FIXME: turns this into a real set of unit tests.
+ SetDataFileDir("ldetect-lst")
+
+ #xs = XSetup()
+ #xs = XSetup('xorg.conf.test')
+ xs = XSetup(xorg_config_filename='bug_data/tonio_intel/xorg.conf',
+ debug_scan_pci_filename="bug_data/tonio_intel/PCIbus.txt")
+ print str(xs)
+ return
+
+ #screen1 = xs.getGfxCards()[0].getScreens()[0]
+ #monitor_db = GetMonitorModelDB()
+ #new_model = monitor_db.getMonitorByName('Samsung SyncMaster 15GL')
+ #print new_model
+ #screen1.setMonitorModel(new_model)
+
+ #screen2 = xs.getGfxCards()[0].getScreens()[1]
+ #screen2.setMonitorModel(new_model)
+
+ print "getAvailableLayouts(): ",xs.getAvailableLayouts()
+ xs.getGfxCards()[0].setProprietaryDriver(True)
+ print str(xs)
+ xs.setLayout(XSetup.LAYOUT_CLONE) # XSetup.LAYOUT_DUAL.
+ print "getAvailableLayouts(): ",xs.getAvailableLayouts()
+ print str(xs)
+
+ #gfxcard_db = GetGfxCardModelDB()
+ #new_gfxcard_model = gfxcard_db.getGfxCardModelByName('NVIDIA GeForce FX (generic)')
+ ##'ATI Radeon 8500'
+ ##'NVIDIA GeForce FX (generic)'
+ #print new_gfxcard_model
+ #gfx_card = xs.getGfxCards()[0]
+ #gfx_card.setProprietaryDriver(False)
+ #gfx_card.setGfxCardModel(new_gfxcard_model)
+ xs.writeXorgConfig('xorg.conf.test')
+
+if __name__=='__main__':
+ main()