diff options
Diffstat (limited to 'displayconfig/displayconfigabstraction.py')
-rw-r--r-- | displayconfig/displayconfigabstraction.py | 3230 |
1 files changed, 0 insertions, 3230 deletions
diff --git a/displayconfig/displayconfigabstraction.py b/displayconfig/displayconfigabstraction.py deleted file mode 100644 index f59b2ff..0000000 --- a/displayconfig/displayconfigabstraction.py +++ /dev/null @@ -1,3230 +0,0 @@ -#!/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() |