#
# xf866config.py - XFree86 configuration file generator for 3.3.x and 4.x
#
# Matt Wilson <msw@redhat.com>
# Brent Fox <bfox@redhat.com>
#
# Copyright 2001 Red Hat, Inc.
#
# This software may be freely redistributed under the terms of the GNU
# library public license.
#
# You should have received a copy of the GNU Library Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import sys
if __name__ == "__main__":
    sys.path.append ('kudzu')
    sys.path.append ('isys')
import string
import iutil
import kudzu
import isys
import time
import os
from kbd import Keyboard
from mouse import Mouse
from translate import _

XF86Config_template = """
# File generated by anaconda.
# **********************************************************************
# Refer to the XF86Config(4/5) man page for details about the format of 
# this file.
# **********************************************************************

# **********************************************************************
# Files section.  This allows default font and rgb paths to be set
# **********************************************************************

Section "Files"
%(files)s
EndSection

# **********************************************************************
# Server flags section.
# **********************************************************************

Section "ServerFlags"
    # Uncomment this to cause a core dump at the spot where a signal is 
    # received.  This may leave the console in an unusable state, but may
    # provide a better stack trace in the core dump to aid in debugging

    # NoTrapSignals

    # Uncomment this to disable the <Crtl><Alt><BS> server abort sequence
    # This allows clients to receive this key event.

    # DontZap

    # Uncomment this to disable the <Crtl><Alt><KP_+>/<KP_-> mode switching
    # sequences.  This allows clients to receive these key events.

    # DontZoom
EndSection

# Pointer section
# **********************************************************************

Section "Pointer"
    Protocol    "%(mouseProto)s"
    Device      "/dev/%(mouseDevice)s"

#    For wheel support - can not be used with Emulate3Buttons
#
#    ZAxisMapping 4 5

# When using XQUEUE, comment out the above two lines, and uncomment
# the following line.
#    Protocol	"Xqueue"

# Baudrate and SampleRate are only for some Logitech mice
#    BaudRate	9600
#    SampleRate	150

# Emulate3Buttons is an option for 2-button Microsoft mice
# Emulate3Timeout is the timeout in milliseconds (default is 50ms)
%(emulate3)s

# ChordMiddle is an option for some 3-button Logitech mice
#    ChordMiddle

EndSection

# **********************************************************************
# Keyboard section
# **********************************************************************

Section "Keyboard"
    Protocol    "Standard"

%(autorepeat)s

# when using XQUEUE, comment out the above line, and uncomment the
# following line
    # Protocol   "Xqueue"

# Let the server do the NumLock processing.  This should only be 
# required when using pre-R6 clients
    # ServerNumLock

# Specify which keyboard LEDs can be user-controlled (eg, with xset(1))
    # Xleds      1 2 3

# To set the LeftAlt to Meta, RightAlt key to ModeShift, 
# RightCtl key to Compose, and ScrollLock key to ModeLock:

    LeftAlt         Meta
    RightAlt        Meta
    ScrollLock      Compose
    RightCtl        Control

# To disable the XKEYBOARD extension, uncomment XkbDisable.
#    XkbDisable

# To customise the XKB settings to suit your keyboard, modify the
# lines below (which are the defaults).  For example, for a non-U.S.
# keyboard, you will probably want to use:
#    XkbModel    "pc102"
# If you have a US Microsoft Natural keyboard, you can use:
#    XkbModel    "microsoft"
#
# Then to change the language, change the Layout setting.
# For example, a german layout can be obtained with:
#    XkbLayout   "de"
# or:
#    XkbLayout   "de"
#    XkbVariant  "nodeadkeys"
#
# If you'd like to switch the positions of your capslock and
# control keys, use:
#    XkbOptions  "ctrl:swapcaps"
#
# If you'd like to disable the capslock key, use:
#    XkbOptions  "ctrl:nocaps"


     XkbRules    "%(XkbRules)s"
     XkbModel    "%(XkbModel)s"
     XkbLayout   "%(XkbLayout)s"     
     %(enableVariant)sXkbVariant  "%(XkbVariant)s"
     %(enableOptions)sXkbOptions  "%(XkbOptions)s"
EndSection

# **********************************************************************
# Monitor section
# **********************************************************************

# Any number of monitor sections may be present
Section "Monitor"
    Identifier  "Generic Monitor"
    VendorName  "Unknown"
    ModelName   "Unknown"
#    HorizSync   31.5
#    VertRefresh 60
    HorizSync   35.15
    VertRefresh 55-65

#    ModeLine  "640x480"   25.175  640 664 760 800
#                                  480 491 493 525

# 800x600 @ 56 Hz, 35.15 kHz hsync
    ModeLine "800x600"     36     800  824  896 1024
                                  600  601  603  625

EndSection

%(fbProbedMonitor)s

Section "Monitor"
    Identifier  "%(monitorID)s"
    VendorName  "Unknown"
    ModelName   "Unknown"

# HorizSync is in kHz unless units are specified.
# HorizSync may be a comma separated list of discrete values, or a
# comma separated list of ranges of values.
# NOTE: THE VALUES HERE ARE EXAMPLES ONLY.  REFER TO YOUR MONITOR'S
# USER MANUAL FOR THE CORRECT NUMBERS.

    HorizSync   %(monitorHoriz)s

# VertRefresh is in Hz unless units are specified.
# VertRefresh may be a comma separated list of discrete values, or a
# comma separated list of ranges of values.
# NOTE: THE VALUES HERE ARE EXAMPLES ONLY.  REFER TO YOUR MONITOR'S
# USER MANUAL FOR THE CORRECT NUMBERS.

    VertRefresh %(monitorVert)s

# Modes can be specified in two formats.  A compact one-line format, or
# a multi-line format.

# These two are equivalent

#    ModeLine "1024x768i" 45 1024 1048 1208 1264 768 776 784 817 Interlace

#    Mode "1024x768i"
#        DotClock	45
#        HTimings	1024 1048 1208 1264
#        VTimings	768 776 784 817
#        Flags		"Interlace"
#    EndMode

# This is a set of standard mode timings. Modes that are out of monitor spec
# are automatically deleted by the server (provided the HorizSync and
# VertRefresh lines are correct), so there's no immediate need to
# delete mode timings (unless particular mode timings don't work on your
# monitor). With these modes, the best standard mode that your monitor
# and video card can support for a given resolution is automatically
# used.

# Low-res Doublescan modes
# If your chipset does not support doublescan, you get a 'squashed'
# resolution like 320x400.

# --320x200--
# 320x200 @ 70 Hz, 31.5 kHz hsync, 8:5 aspect ratio
    Modeline "320x200"     12.588 320  336  384  400
                                  200  204  205  225 Doublescan
# 320x240 @ 60 Hz, 31.5 kHz hsync, 4:3 aspect ratio
    Modeline "320x240"     12.588 320  336  384  400
                                  240  245  246  262 Doublescan
# 320x240 @ 72 Hz, 36.5 kHz hsync
    Modeline "320x240"     15.750 320  336  384  400
                                  240  244  246  262 Doublescan
# --400x300--
# 400x300 @ 56 Hz, 35.2 kHz hsync, 4:3 aspect ratio
    ModeLine "400x300"     18     400  416  448  512
                                  300  301  302  312 Doublescan
# 400x300 @ 60 Hz, 37.8 kHz hsync
    Modeline "400x300"     20     400  416  480  528
                                  300  301  303  314 Doublescan
# 400x300 @ 72 Hz, 48.0 kHz hsync
    Modeline "400x300"     25     400  424  488  520
                                  300  319  322  333 Doublescan
# 480x300 @ 56 Hz, 35.2 kHz hsync, 8:5 aspect ratio
    ModeLine "480x300"     21.656 480  496  536  616
                                  300  301  302  312 Doublescan
# 480x300 @ 60 Hz, 37.8 kHz hsync
    Modeline "480x300"     23.890 480  496  576  632
                                  300  301  303  314 Doublescan
# 480x300 @ 63 Hz, 39.6 kHz hsync
    Modeline "480x300"     25     480  496  576  632
                                  300  301  303  314 Doublescan
# 480x300 @ 72 Hz, 48.0 kHz hsync
    Modeline "480x300"     29.952 480  504  584  624
                                  300  319  322  333 Doublescan

# Normal video modes

# -- 512x384
# 512x384 @ 78 Hz, 31.50 kHz hsync
    Modeline "512x384"    20.160 512  528  592  640
                                 384  385  388  404 -HSync -VSync
# 512x384 @ 85 Hz, 34.38 kHz hsync
    Modeline "512x384"    22     512  528  592  640
                                 384  385  388  404 -HSync -VSync

# -- 640x400 --
# 640x400 @ 70 Hz, 31.5 kHz hsync
    Modeline "640x400"     25.175 640  664  760  800
                                  400  409  411  450
# 640x400 @ 85 Hz, 37.86 kHz hsync
    Modeline "640x400"     31.5   640  672 736   832
                                  400  401  404  445 -HSync +VSync

# --- 640x480 ---
# 640x480 @ 60 Hz, 31.5 kHz hsync
    Modeline "640x480"     25.175 640  664  760  800
                                  480  491  493  525
# 640x480 @ 72 Hz, 36.5 kHz hsync
    Modeline "640x480"     31.5   640  680  720  864
                                  480  488  491  521
# 640x480 @ 75 Hz, 37.50 kHz hsync
    ModeLine  "640x480"    31.5   640  656  720  840
                                  480  481  484  500 -HSync -VSync
# 640x480 @ 85 Hz, 43.27 kHz hsync
    Modeline "640x480"     36     640  696  752  832
                                  480  481  484  509 -HSync -VSync
# 640x480 @ 100 Hz, 53.01 kHz hsync
    Modeline "640x480"     45.8   640  672  768  864
                                  480  488  494  530 -HSync -VSync

# --- 800x600 ---
# 800x600 @ 56 Hz, 35.15 kHz hsync
    ModeLine "800x600"     36     800  824  896 1024
                                  600  601  603  625
# 800x600 @ 60 Hz, 37.8 kHz hsync
    Modeline "800x600"     40     800  840  968 1056
                                  600  601  605  628 +hsync +vsync
# 800x600 @ 72 Hz, 48.0 kHz hsync
    Modeline "800x600"     50     800  856  976 1040
                                  600  637  643  666 +hsync +vsync
# 800x600 @ 85 Hz, 55.84 kHz hsync
    Modeline  "800x600"    60.75  800  864  928 1088
                                  600  616  621  657 -HSync -VSync
# 800x600 @ 100 Hz, 64.02 kHz hsync
    Modeline  "800x600"    69.65  800  864  928 1088
                                  600  604  610  640 -HSync -VSync

# --- 1024x768 ---
# 1024x768 @ 60 Hz, 48.4 kHz hsync
    Modeline "1024x768"    65    1024 1032 1176 1344
                                 768  771  777  806 -hsync -vsync
# 1024x768 @ 70 Hz, 56.5 kHz hsync
    Modeline "1024x768"    75    1024 1048 1184 1328
                                 768  771  777  806 -hsync -vsync
# 1024x768 @ 76 Hz, 62.5 kHz hsync
    Modeline "1024x768"    85    1024 1032 1152 1360
                                 768  784  787  823
# 1024x768 @ 85 Hz, 70.24 kHz hsync
    Modeline "1024x768"   98.9  1024 1056 1216 1408
                                768 782 788 822 -HSync -VSync
# 1024x768 @ 100Hz, 80.21 kHz hsync
    Modeline "1024x768"   115.5  1024 1056 1248 1440
                                 768  771  781  802 -HSync -VSync

# --- 1152x864 ---
# 1152x864 @ 60 Hz, 53.5 kHz hsync
    Modeline  "1152x864"   89.9  1152 1216 1472 1680
                                 864  868  876  892 -HSync -VSync
# 1152x864 @ 70 Hz, 62.4 kHz hsync
    Modeline  "1152x864"   92    1152 1208 1368 1474
                                 864  865  875  895
# 1152x864 @ 78 Hz, 70.8 kHz hsync
    Modeline "1152x864"   110   1152 1240 1324 1552
                                864  864  876  908
# 1152x864 @ 84 Hz, 76.0 kHz hsync
    Modeline "1152x864"   135    1152 1464 1592 1776
                                 864  864  876  908
# 1152x864 @ 100 Hz, 89.62 kHz hsync
    Modeline "1152x864"   137.65 1152 1184 1312 1536
                                 864  866  885  902 -HSync -VSync

# -- 1280x1024 --
# 1280x1024 @ 61 Hz, 64.2 kHz hsync
    Modeline "1280x1024"  110    1280 1328 1512 1712
                                 1024 1025 1028 1054
# 1280x1024 @ 70 Hz, 74.59 kHz hsync
    Modeline "1280x1024"  126.5 1280 1312 1472 1696
                                1024 1032 1040 1068 -HSync -VSync
# 1280x1024 @ 74 Hz, 78.85 kHz hsync
    Modeline "1280x1024"  135    1280 1312 1456 1712
                                 1024 1027 1030 1064
# 1280x1024 @ 76 Hz, 81.13 kHz hsync
    Modeline "1280x1024"  135    1280 1312 1416 1664
                                 1024 1027 1030 1064
# 1280x1024 @ 85 Hz, 91.15 kHz hsync
    Modeline "1280x1024"  157.5  1280 1344 1504 1728
                                 1024 1025 1028 1072 +HSync +VSync
# 1280x1024 @ 100 Hz, 107.16 kHz hsync
    Modeline "1280x1024"  181.75 1280 1312 1440 1696
                                 1024 1031 1046 1072 -HSync -VSync

# -- 1400x1050 --
# 1400x1050 @ 60Hz, 65.8 kHz hsync
    Modeline "1400x1050"  129   1400 1464 1656 1960
                              1050 1051 1054 1100 +HSync +VSync

# 1400x1050 @ 70Hz, 76.8 kHz hsync
    Modeline "1400x1050"  151   1400 1464 1656 1960
                              1050 1051 1054 1100 +HSync +VSync

# 1400x1050 @ 75Hz, 82.3 kHz hsync
    Modeline "1400x1050"  162   1400 1464 1656 1960
                              1050 1051 1054 1100 +HSync +VSync

# 1400x1050 @ 85Hz, 93.2 kHz hsync
    Modeline "1400x1050"  184   1400 1464 1656 1960
                              1050 1051 1054 1100 +HSync +VSync

# -- 1600x1200 --
# 1600x1200 @ 60Hz, 75.00 kHz hsync
    Modeline "1600x1200"  162   1600 1664 1856 2160
                                1200 1201 1204 1250 +HSync +VSync
# 1600x1200 @ 70 Hz, 87.50 kHz hsync
    Modeline "1600x1200"  189    1600 1664 1856 2160
                                 1200 1201 1204 1250 -HSync -VSync
# 1600x1200 @ 75 Hz, 93.75 kHz hsync
    Modeline "1600x1200"  202.5  1600 1664 1856 2160
                                 1200 1201 1204 1250 +HSync +VSync
# 1600x1200 @ 85 Hz, 105.77 kHz hsync
    Modeline "1600x1200"  220    1600 1616 1808 2080
                                 1200 1204 1207 1244 +HSync +VSync

# -- 1800x1400 -- 

# 1800x1440 @ 64Hz, 96.15 kHz hsync 
    ModeLine "1800X1440"  230    1800 1896 2088 2392
                                 1440 1441 1444 1490 +HSync +VSync
# 1800x1440 @ 70Hz, 104.52 kHz hsync 
    ModeLine "1800X1440"  250    1800 1896 2088 2392
                                 1440 1441 1444 1490 +HSync +VSync

# -- 1920x1200 --

# 1920x1200 @ 70Hz, 87.50 KHz hsync
    Modeline "1920x1200"  230    1920 1936 2096 2528
                                 1200 1201 1204 1250 +HSync +VSync

EndSection

# **********************************************************************
# Graphics device section
# **********************************************************************

Section "Device"
    Identifier        "Generic VGA Card"
    VendorName        "Unknown"
    BoardName         "Unknown"
    Chipset           "generic"
EndSection

%(acceleratedDevices)s

# **********************************************************************
# Screen section
# **********************************************************************

# The kernel framebuffer server
Section "Screen"
    Driver      "fbdev"
    Device      "Generic VGA Card"
    Monitor     "%(fbmonitorID)s"
    Subsection  "Display"
#        Depth       16
        Depth      %(fbDepth)s
        Modes       "default"
    EndSubsection
EndSection

# The 16-color VGA server
Section "Screen"
    Driver      "vga16"
    Device      "Generic VGA Card"
    Monitor     "%(monitorID)s"
    Subsection "Display"
        Modes       "640x480" "800x600"
        ViewPort    0 0
    EndSubsection
EndSection

# The Mono server
Section "Screen"
    Driver      "vga2"
    Device      "Generic VGA Card"
    Monitor     "%(monitorID)s"
    Subsection "Display"
        Modes       "640x480" "800x600"
        ViewPort    0 0
    EndSubsection
EndSection

%(acceleratedScreens)s
"""


XF86Config_4_template = """
# File generated by anaconda.

Section "ServerLayout"
        Identifier     "Anaconda Configured"
        Screen      0  "Screen0" 0 0
        InputDevice    "Mouse0" "CorePointer"
        InputDevice    "Keyboard0" "CoreKeyboard"
EndSection

Section "Files"
%(files)s
EndSection

Section "Module"
        Load  "GLcore"
        Load  "dbe"
        Load  "extmod"%(nonSparcMods)s%(pex5Mod)s%(driMod)s
        Load  "glx"
        Load  "pex5"
        Load  "record"
        Load  "xie"
EndSection

Section "InputDevice"
        Identifier  "Keyboard0"
        Driver      "keyboard"

%(autorepeat)s

# when using XQUEUE, comment out the above line, and uncomment the
# following line
#	Option	"Protocol"	"Xqueue"

# Specify which keyboard LEDs can be user-controlled (eg, with xset(1))
#	Option	"Xleds"		"1 2 3"

# To disable the XKEYBOARD extension, uncomment XkbDisable.
#	Option	"XkbDisable"

# To customise the XKB settings to suit your keyboard, modify the
# lines below (which are the defaults).  For example, for a non-U.S.
# keyboard, you will probably want to use:
#	Option	"XkbModel"	"pc102"
# If you have a US Microsoft Natural keyboard, you can use:
#	Option	"XkbModel"	"microsoft"
#
# Then to change the language, change the Layout setting.
# For example, a german layout can be obtained with:
#	Option	"XkbLayout"	"de"
# or:
#	Option	"XkbLayout"	"de"
#	Option	"XkbVariant"	"nodeadkeys"
#
# If you'd like to switch the positions of your capslock and
# control keys, use:
#	Option	"XkbOptions"	"ctrl:nocaps"
	Option	"XkbRules"	"%(XkbRules)s"
	Option	"XkbModel"	"%(XkbModel)s"
	Option	"XkbLayout"	"%(XkbLayout)s"
	%(enableVariant)sOption	"XkbVariant"	"%(XkbVariant)s"
	%(enableOptions)sOption	"XkbOptions"	"%(XkbOptions)s"
EndSection

Section "InputDevice"
        Identifier  "Mouse0"
        Driver      "mouse"
        Option      "Protocol" "%(mouseProto)s"
        Option      "Device" "/dev/%(mouseDevice)s"
        Option      "ZAxisMapping" "4 5"
        Option      "Emulate3Buttons" "%(emulate3)s"
EndSection

Section "Monitor"
        Identifier   "Monitor0"
        VendorName   "Monitor Vendor"
        ModelName    "Monitor Model"
        HorizSync   %(monitorHoriz)s
        VertRefresh %(monitorVert)s
        Option "dpms"

        # -- 1400x1050 --
        # 1400x1050 @ 60Hz, 65.8 kHz hsync
        Modeline "1400x1050"  129   1400 1464 1656 1960
                              1050 1051 1054 1100 +HSync +VSync

        # 1400x1050 @ 70Hz, 76.8 kHz hsync
        Modeline "1400x1050"  151   1400 1464 1656 1960
                              1050 1051 1054 1100 +HSync +VSync

        # 1400x1050 @ 75Hz, 82.3 kHz hsync
        Modeline "1400x1050"  162   1400 1464 1656 1960
                              1050 1051 1054 1100 +HSync +VSync

        # 1400x1050 @ 85Hz, 93.2 kHz hsync
        Modeline "1400x1050"  184   1400 1464 1656 1960
                              1050 1051 1054 1100 +HSync +VSync

EndSection

Section "Device"
%(cardsOptions)s
	Identifier   "%(cardID)s"
        Driver       "%(cardDriver)s"
        VendorName   "%(cardVendor)s"
        BoardName     "%(cardBoardName)s"
%(videoRam)s        
        #BusID
EndSection

Section "Screen"
	Identifier   "Screen0"
        Device       "%(cardID)s"
        Monitor      "Monitor0"%(defaultDepth)s
%(screenModes)s
EndSection

Section "DRI"
	Mode 0666
EndSection
"""

class XF86Config:
    def __init__ (self, videocard, monitor, mouse, resolution = None):

        if videocard:
            self.setVideoCard(videocard)
        else:
            raise RuntimeError, "no videocard specified in XF86Config __init__"

        if monitor:
            self.setMonitor(monitor)
        else:
            raise RuntimeError, "no monitor specified in XF86Config __init__"

        if mouse:
            self.setMouse(mouse)
        else:
            raise RuntimeError, "no mouse specified in XF86Config __init__"

        self.skip = 0
        self.res = resolution
        self.manualModes = {}
        self.fallbackModes = {}

        monsyncknown = (self.monitor.getMonitorHorizSync() != None) and (self.monitor.getMonitorVertSync() != None)

        if self.res == "640x480":
            self.modes = { "8" :  ["640x480"] }
            if not monsyncknown:
                self.monitor.setSpecs("31.5-35.5", "50-61")
        else:
            self.modes = { "16" :  ["800x600"] }
            if not monsyncknown:
                self.monitor.setSpecs("31.5-48.5", "50-70")

        self.fallbackModes = self.modes
        
	self.device = None
        self.keyRules = "xfree86"
        self.keyModel = "pc101"
        self.keyLayout = "us"
	kbd = Keyboard()
	if kbd.type == 'Sun':
	    self.keyRules = "sun"
	    self.keyModel = kbd.model
	    self.keyLayout = kbd.layout
        self.keyVariant = ""
        self.keyOptions = ""
        self.monlist = {}
        self.monids = {}

        # if skipx is TRUE user has selected to not configure X
        self.skipx = 0

        if isys.fbinfo() != None:
            (x, y, depth) = isys.fbinfo()
            self.fbDepth = depth
        else:
            self.fbDepth = 16

        self.files = """
# The location of the RGB database.  Note, this is the name of the
# file minus the extension (like ".txt" or ".db").  There is normally
# no need to change the default.

    RgbPath	"/usr/X11R6/lib/X11/rgb"

# Multiple FontPath entries are allowed (they are concatenated together)
# By default, Red Hat 6.0 and later now use a font server independent of
# the X server to render fonts.

    FontPath   "unix/:7100"
"""
        
        
    def setKeyboard(self, rules, model, layout, variant, options):
        self.keyRules = rules
        self.keyModel = model
        self.keyLayout = layout
        self.keyVariant = variant
        self.keyOptions = options

    def getKeyboard(self):
        return (self.keyRules, self.keyModel, self.keyLayout,
                self.keyVariant, self.keyOptions)

    def setMouse(self, mouse):
        self.mouse = mouse

    def setVideoCard(self, videocard):
        self.videocard = videocard

    def setMonitor(self, monitor):
        self.monitor = monitor

    def areaCompare (self, first, second):
        (sx1, sy1) = string.split (first, 'x')
        (sx2, sy2) = string.split (second, 'x')

        x1 = string.atoi (sx1)
        y1 = string.atoi (sy1)
        x2 = string.atoi (sx2)
        y2 = string.atoi (sy2)

        if ((x1 * y1) > (x2 * y2)):
            return -1
        elif ((x1 * y1) < (x2 * y2)):
            return 1
        return 0

    def availableModes (self):
        modes = { "8" : [ "640x480" ] }

        if not self.videocard:
            return modes

        vidRam = self.videocard.getVideoRam()

        if not vidRam:
            return modes
        if string.atoi(vidRam) >= 8192:
            modes["8"] = ["640x480", "800x600", "1024x768","1152x864",
                          "1280x1024", "1400x1050", "1600x1200"]
            modes["16"] = ["640x480", "800x600", "1024x768", "1152x864",
                           "1280x1024", "1400x1050", "1600x1200"]
            modes["32"] = ["640x480", "800x600", "1024x768", "1152x864",
                           "1280x1024", "1400x1050", "1600x1200"]
        elif string.atoi(vidRam) >= 6144:
            modes["8"] = ["640x480", "800x600", "1024x768", "1152x864",
                          "1280x1024", "1400x1050", "1600x1200"]
            modes["16"] = ["640x480", "800x600", "1024x768", "1152x864",
                           "1280x1024", "1400x1050", "1600x1200"]
            modes["32"] = ["640x480", "800x600", "1024x768", "1152x864",
                           "1280x1024"]
        elif string.atoi(vidRam) >= 4096:
            modes["8"] = ["640x480", "800x600", "1024x768", "1152x864",
                          "1280x1024"]
            modes["16"] = ["640x480", "800x600", "1024x768", "1152x864",
                           "1280x1024"]
            modes["32"] = ["640x480", "800x600", "1024x768", "1152x864"]
        elif string.atoi(vidRam) >= 2048:
            modes["8"] = ["640x480", "800x600", "1024x768", "1152x864",
                          "1280x1024"]
            modes["16"] = ["640x480", "800x600", "1024x768", "1152x864"]
            modes["32"] = ["640x480", "800x600"]
        elif string.atoi(vidRam) >= 1024:
            modes["8"] = ["640x480", "800x600", "1024x768", "1152x864"]
            modes["16"] = ["640x480", "800x600"]
            modes["32"] = []
        elif string.atoi(vidRam) >= 512:
            modes["8"] = ["640x480", "800x600"]
            modes["16"] = ["640x480"]
            modes["32"] = []
        elif string.atoi(vidRam) >= 256:
            modes["8"] = ["640x480"]

        return modes

    def filterModesByMemory (self):
        self.modes = self.availableModes()

    def setModes(self, modes):
        self.modes = modes

    def getModes(self):
        return self.modes

    def setManualModes(self, modes):
        self.manualModes = modes

    def getManualModes(self):
        return self.manualModes

    def setFallBackModes(self, modes):
        self.fallbackModes = modes

    def getFallBackModes(self):
        return self.fallbackModes

    def cards (self, thecard = None):
        cards = {}
        # all the straight servers
        for server in [ "3DLabs", "8514", "FBDev", "Mach8", "Mach32", "Mach64",
                        "Mono", "P9000", "S3", "S3V", "SVGA", "W32", "VGA16" ]:
            cards["Generic " + server] = { "SERVER" : server,
                                           "NAME"   : "Generic " + server }
        
        db = open ('/usr/X11R6/lib/X11/Cards')
        lines = db.readlines ()
        db.close ()
        card = {}
        name = None
        for line in lines:
            line = string.strip (line)
            if not line and name:
                cards[name] = card
                card = {}
                name = None
                continue
            
            if line and line[0] == '#':
                continue
            
            if len (line) > 4 and line[0:4] == 'NAME':
                name = line[5:]
                
            info = string.splitfields (line, ' ')
            if card.has_key (info[0]):
                card[info[0]] = card[info[0]] + '\n' + (string.joinfields (info[1:], ' '))
            else:
                card[info[0]] = string.joinfields (info[1:], ' ')

        if thecard:
            card = cards[thecard]
            # XXX set a max depth here to avoid infinite loops
            while card.has_key ("SEE"):
                card = cards[card["SEE"]]
            return card
        return cards

    def monitors (self, lines = None):
        if self.monlist:
            return self.monlist
        if not lines:
            db = open ('/usr/X11R6/share/Xconfigurator/MonitorsDB')
            lines = db.readlines ()
            db.close ()

        for line in lines:
            line = string.strip (line)
            if not line:
                continue
            if line and line[0] == '#':
                continue
            fields = string.split (line, ';')
            man = string.strip(fields[0])
            model = string.strip(fields[1])
            eisa = string.lower(string.strip(fields[2]))
            horiz = string.strip(fields[3])
            vert = string.strip(fields[4])
            if self.monlist.has_key(man):
                self.monlist[man].append((model, eisa, vert, horiz))
            else:
                self.monlist[man] = [(model, eisa, vert, horiz)]
            self.monids[eisa] = (man, model, eisa, vert, horiz)
        return self.monlist


    def probeReport (self):
        probe = ""
        if self.videocard:
            primary = self.videocard
            vidCards = primary.getCardData()
            
        if vidCards:
            probe = probe + _("Video Card") + ": " + vidCards["NAME"] + "\n"
            if primary.getVideoRam():
                probe = probe + "\t" + _("Video Ram") + ": " + primary.getVideoRam() + " kb\n"
        if primary.getXServer():
            time.sleep(5)
            probe = probe + "\t" + _("X server") + ": " + primary.getXServer() + "\n"
        else:
            time.sleep(5)
            probe = probe + "\t" + _("Unable to detect video card")

        return probe
        # disable monitor report
#          probe = probe + "\n"

#          if self.monName:
#              probe = probe + _("Monitor") + ": " + self.monName + "\n"
#          elif self.monEisa:
#              probe = probe + _("Monitor") + ": " + _("Plug and Play Monitor") + "\n"
#          if self.monHoriz:
#              probe = probe + "\t" + _("Horizontal frequency range") + ": " + self.monHoriz + " kHz\n"
#          if self.monHoriz:
#              probe = probe + "\t" + _("Vertical frequency range") + ": " + self.monVert + " Hz\n"

#          return probe

    def write (self, path):
        config = open (path + "/XF86Config", 'w')
        config.write (self.Version3Config ())
        config.close ()
        try:
            config4 = self.Version4Config (self.videocard)
        except RuntimeError:
            return
        config = open (path + "/XF86Config-4", 'w')
        config.write (config4)
        config.close ()

    def writeKS (self, f):
        if self.skipx:
            f.write("skipx\n")
            return
        
        xmodes = self.getManualModes()

        if len(xmodes) == 0:
            f.write("skipx\n")
            return
        
        f.write("xconfig")

        for arg in self.getArgList(xmodes):
            f.write(" " + arg)
        f.write("\n")

    def getArgList(self, xmodes):
        args = []
        vc = self.videocard

        args = args + [ "--card", '"' + vc.shortDescription() + '"' ]
        args = args + [ "--videoram", vc.getVideoRam() ]
        args = args + [ "--hsync", self.monitor.getMonitorHorizSync() ]
        args = args + [ "--vsync", self.monitor.getMonitorVertSync() ]

        # XXX this isn't really quite right, but it works for the way
        # things are now
        depths = xmodes.keys()
        args = args + [ "--resolution", xmodes[depths[0]][0] ]
        args = args + [ "--depth", depths[0] ]

        return args

    def test (self, serverflags=None, spawn=0, root='/'):

        if self.videocard == None:
            return None

        servername = self.videocard.getXServer()

        if not servername:
            return None

        files = self.files

        # if we're forcing framebuffer, use those modes if available
        fbmonsect = None
        if self.videocard.isFrameBuffer():
            if self.monitor:
                fbmonsect = self.monitor.getFBMonitorSection()

                if fbmonsect:
                    self.manualModes = self.monitor.getFBMonitorMode()
                elif self.videocard.hasFixedMode():
                    self.manualModes = self.videocard.FixedMode()
                else:
                    raise RuntimeError, "trying frame buffer but no valid modes to try..."
        elif self.videocard.hasFixedMode():
            self.manualModes = self.videocard.FixedMode()

        # save current manually selected mode, override if non-existant
        manmodes = self.manualModes
        if not manmodes:
            if self.fallbackModes:
                self.manualModes = self.fallbackModes
            else:
                self.manualModes = self.modes

        self.files = """
    RgbPath	"/usr/X11R6/lib/X11/rgb"
    FontPath	"/usr/X11R6/lib/X11/fonts/misc:unscaled"
    FontPath	"/usr/X11R6/lib/X11/fonts/Type1/"
    FontPath	"/usr/X11R6/lib/X11/fonts/Speedo/"
    FontPath	"/usr/X11R6/lib/X11/fonts/75dpi:unscaled"
    FontPath	"/usr/X11R6/lib/X11/fonts/100dpi:unscaled"
    FontPath    "/usr/X11R6/lib/X11/fonts/cyrillic:unscaled"
    FontPath    "/usr/share/fonts/ISO8859-2/misc:unscaled"
    FontPath    "/usr/share/fonts/ISO8859-2/75dpi:unscaled"
    FontPath    "/usr/share/fonts/ISO8859-2/100dpi:unscaled"
    FontPath    "/usr/share/fonts/ISO8859-9/misc:unscaled"
    FontPath    "/usr/share/fonts/ISO8859-9/75dpi:unscaled"
    FontPath    "/usr/share/fonts/ISO8859-9/100dpi:unscaled"
    FontPath    "/usr/share/fonts/KOI8-R/misc:unscaled"
    FontPath    "/usr/share/fonts/KOI8-R/75dpi:unscaled"
"""
        f = open ('%s/tmp/XF86Config.test' %(root), 'w')
            
        if servername == "XFree86":
            f.write(self.Version4Config(self.videocard, 1))
        else:
            f.write(self.Version3Config(1))

        f.close ()

        self.files = files

        # restore manualmodes
        self.manualModes = manmodes
        serverPath = "/usr/X11R6/bin/" + servername
        
        serverpid = os.fork()

        if (not serverpid):
            if (root and root != '/'): 
                isys.chroot (root)
                os.chdir("/")

            args = [serverPath, '-xf86config', '/tmp/XF86Config.test' ]
	    logFile = "/tmp/X.log"
            if servername == "XFree86":
                args = args + [ "-logfile", "/dev/null" ]
            if serverflags:
                args = args + serverflags
            else:
                args = args +  [ ":9", "vt6" ]
		logFile = "/tmp/X-Test.log"

	    try:
		err = os.open(logFile, os.O_RDWR | os.O_CREAT)
		if err < 0:
		    sys.stderr.write("error opening /tmp/X.log\n")
		else:
		    os.dup2(err, 2)
		    os.close(err)
	    except:
		# oh well
		pass

            os.execv(args[0], args)
     	    sys.exit (1)

        if spawn:
            return serverpid
            
        child = os.fork()
        if (not child):
            if (root and root != '/'): 
                isys.chroot (root)
                os.chdir("/")

            os.environ["DISPLAY"] = ":9"
            os.execv("/usr/X11R6/bin/Xtest", ["Xtest", "--nostart", "--norunlevel"])
        else:
            failed = 0
            status = -1
            try:
                pid, status = os.waitpid(child, 0)
                os.kill (serverpid, 15)
                os.waitpid(serverpid, 0)
                if not os.WIFEXITED (status) or os.WEXITSTATUS (status):
                    if os.WEXITSTATUS (status) not in [ 0, 1, 2 ]:
                        failed = 1
            except OSError:
                failed = 1
            if failed:
                raise RuntimeError, "X startup failed %d" % (status,)
            return

    def Version3Config (self, test=0):
        info = {}
        devices = ""
        screens = ""

        monitor = self.monitor
        card = self.videocard
        carddata = card.getCardData()
        devices = devices + """
Section "Device"
    Identifier         "%(NAME)s"
""" % carddata
        if carddata.has_key ("VENDOR"):
            devices = devices + '    VendorName         "%(VENDOR)s"\n' % carddata
        if carddata.has_key ("BOARDNAME"):
            devices = devices + '    BoardName          "%(BOARD)s"\n' % carddata
        if carddata.has_key ("RAMDAC"):
            devices = devices + '    Ramdac             "%(RAMDAC)s"\n' % carddata
        if carddata.has_key ("LINE"):
            devices = devices + carddata["LINE"] + "\n"
        if card.getVideoRam():
            devices = devices + '    VideoRam           %s\n' % (card.getVideoRam(),) 
        devices = devices + "EndSection\n"

        if card.getDevID():
            screens = ""
            tmp = {}
            maxdepth = -1
            xmodes = self.manualModes
            
            for (depth, modes) in xmodes.items ():
                modes.sort (self.areaCompare)
                if len(modes) > 0 and string.atoi(depth) > maxdepth:
                    maxdepth = string.atoi(depth)

#            if monitor.getFBMonitorSection():
#                monitorname = "Probed Monitor"

            monitorname = monitor.getMonitorID()

            for driver in [ "svga", "accel" ]:
                tmp["driver"] = driver
                tmp["devID"] = card.getDevID()
                tmp["monitorID"] = monitorname
                screens = screens + """
# The %(driver)s server
Section "Screen"
    Driver      "%(driver)s"
    Device      "%(devID)s"
    Monitor     "%(monitorID)s"
""" % tmp

                # see if 16 bpp is available, and if it should be the
                # default depth
                if self.res == "640x480":
                    screens = screens + "    DefaultColorDepth 8\n"
                elif maxdepth > 0:
                    if maxdepth > 16 and '16' in xmodes.keys() and xmodes['16']:
                        screens = screens + "    DefaultColorDepth 16\n"
                    else:
                        screens = screens + "    DefaultColorDepth %d\n" % maxdepth
                        
                for depth in xmodes.keys ():
                    if not xmodes[depth]: continue
                    screens = screens + """
    Subsection "Display"
        Depth       %s
        Modes       """ % depth
                    for res in xmodes[depth]:
                        screens = screens + '"' + res + '" '
                    screens = screens + """
        ViewPort    0 0
    EndSubsection
"""
                screens = screens + "EndSection\n"

        # XXX if we're going to be using IMPS/2 on
        # reboot, but we're using PS/2 now, we'll need
        # to temporarily use PS/2 so we don't frob the
        # intellimouse into IMPS/2 mode (if we did, we'll
        # loose the mouse cursor in the install)
        if test and self.mouse.info["XMOUSETYPE"] == "IMPS/2":
            mouseProto = "PS/2"
        else:
            mouseProto = self.mouse.info['XMOUSETYPE']

        fbprobemon = monitor.getFBMonitorSection()
        if fbprobemon != "":
            fbmonid = "Probed Monitor"
        else:
            fbmonid = monitor.getMonitorID()
            
        info = { "acceleratedDevices" : devices,
                 "acceleratedScreens" : screens,
                 "devID"              : card.getDevID(),
                 "mouseProto"         : mouseProto,
                 "mouseDevice"        : self.mouse.device,
                 "XkbRules"           : self.keyRules,
                 "XkbModel"           : self.keyModel,
                 "XkbLayout"          : self.keyLayout,
                 "XkbVariant"         : self.keyVariant,
                 "enableVariant"      : "#",
                 "XkbOptions"         : self.keyOptions,
                 "enableOptions"      : "#",
                 "monitorID"	      : monitor.getMonitorID(),
                 "monitorHoriz"       : monitor.getMonitorHorizSync(),
                 "monitorVert"        : monitor.getMonitorVertSync(),
                 "fbProbedMonitor"    : fbprobemon,
                 "fbmonitorID"        : fbmonid,
                 "files"              : self.files,
                 }

        # HACK if no frame buffer running just wing it
#        if card.getFBBpp():
#            info["fbDepth"] = card.getFBBpp()
#        else:
#            info["fbDepth"] = 8

        info["fbDepth"] = self.fbDepth
        
        if self.keyVariant:
            info["enableVariant"] = ""
        if self.keyOptions:
            info["enableOptions"] = ""
        if self.mouse.get()[1]:
            info["emulate3"] = "    Emulate3Buttons\n    Emulate3Timeout    50"
        else:
            info["emulate3"] = "#   Emulate3Buttons\n    Emulate3Timeout    50"
	if iutil.getArch() == "sparc":
	    info["autorepeat"] = "#   AutoRepeat	200 20"
        else:
            info["autorepeat"] = "    AutoRepeat	500 5"

        return XF86Config_template % info
        
    def Version4Config(self, card, test=0):
        if not card:
            raise RuntimeError, "No known video cards"
        screens = ""
        maxdepth = -1
        xmodes = self.manualModes

        for depth in xmodes.keys ():
            if not xmodes[depth]: continue
            if depth == "32":
                depth = "24"
                xmodes["24"] = xmodes["32"]
            if maxdepth < string.atoi(depth):
                maxdepth = string.atoi(depth)
            screens = screens + """
	Subsection "Display"
        	Depth       %s
                Modes       """ % depth
            
            modes = xmodes[depth]
            modes.sort (self.areaCompare)
            for res in modes:
                screens = screens + '"' + res + '" '
            screens = screens + """
	EndSubsection
"""
            if depth == "24":
                del xmodes["24"]
                
        # XXX if we're going to be using IMPS/2 on
        # reboot, but we're using PS/2 now, we'll need
        # to temporarily use PS/2 so we don't frob the
        # intellimouse into IMPS/2 mode (if we did, we'll
        # loose the mouse cursor in the install)
        if test and self.mouse.info["XMOUSETYPE"] == "IMPS/2":
            mouseProto = "PS/2"
        else:
            mouseProto = self.mouse.info['XMOUSETYPE']
	if mouseProto == 'sun':
	    mouseProto = 'BusMouse'
        if self.mouse.get()[1]:
            emulate3 = "yes"
        else:
            emulate3 = "no"

        carddata = card.getCardData()
        monitor = self.monitor

        # set cardsoptions if unambiguous what version of XFree86 they
        # apply to
        cardoptions = "	# no known options"
        if carddata.has_key("DRIVER") and not carddata.has_key("SERVER"):
            if carddata.has_key("LINE"):
                cardoptions = carddata["LINE"]
        
        data = { "mouseProto"   : mouseProto,
                 "mouseDevice"  : self.mouse.device,
                 "cardsOptions" : cardoptions,
                 "cardID"       : carddata["NAME"],
                 "cardVendor"   : carddata["NAME"],
                 "cardBoardName": carddata["NAME"],
                 "monitorHoriz" : monitor.getMonitorHorizSync(),
                 "monitorVert"  : monitor.getMonitorVertSync(),
                 "files"        : self.files,
                 "screenModes"  : screens,
		 "nonSparcMods" : '\n\tLoad "fbdevhw"',
		 "pex5Mod"	: '\n\tLoad "pex5"',
		 "driMod"	: '\n\tLoad "dri"',
                 "XkbRules"     : self.keyRules,
                 "XkbModel"     : self.keyModel,
                 "XkbLayout"    : self.keyLayout,
                 "XkbVariant"   : self.keyVariant,
                 "enableVariant": "#",
                 "XkbOptions"   : self.keyOptions,
                 "enableOptions": "#",
                 "defaultDepth" : "",
                 "emulate3"     : emulate3,
                 "videoRam"     : "" }
#        self.vidCards[self.primary]["DRIVER"] = "vga"
        # see if 16 bpp is available, and if it should be the
        # default depth

        if self.keyVariant:
            data["enableVariant"] = ""
        if self.keyOptions:
            data["enableOptions"] = ""

        if maxdepth > 0:
            if maxdepth > 16 and '16' in xmodes.keys() and xmodes['16']:
                data["defaultDepth"] = "\n\tDefaultDepth\t16"
            else:
                data["defaultDepth"] = "\n\tDefaultDepth\t%d" % maxdepth
	if test:
	    data["pex5Mod"] = ""
	if iutil.getArch() == "sparc":
	    data["nonSparcMods"] = ""
	    data["autorepeat"] = '#	Option	"AutoRepeat"	"200 20"'
        else:
            data["autorepeat"] = '#	Option	"AutoRepeat"	"500 5"'
        if carddata.has_key ("DRIVER"):
            data["cardDriver"] = carddata["DRIVER"]
            if data["cardDriver"] == "i810":
                data["videoRam"] = "\tVideoRam %s\n" % card.getVideoRam()
	    # DRI HACK!
	    #if data["cardDriver"] == "r128" or data["cardDriver"] == "mga":
	    #	data["driMod"] = '\n\t#Load "dri"'
        else:
            raise RuntimeError, "Don't know which XFree86-4.0 video driver to use!"
	return XF86Config_4_template % data

if __name__ == "__main__":
    sys.path.append ("kudzu")
    x = XF86Config ()
    print x.cards ("ATI Mach64 3D RAGE II")
    x.probe ()
#    print x.Version3Config()    
    print x.Version4Config()
    sys.exit (0)
    x.filterModesByMemory ()

#    print self.modes
#    time.sleep (5)
    
    print x.preludeSection ()
    print x.keyboardSection ()
    print x.mouseSection ()
    print x.monitorSection ()
    print x.deviceSection ()
#    x.modes["8"] = [ "640x480" ]
#    x.modes["16"] = [ "640x480" ]
#    x.modes["32"] = [ "640x480" ]
    print x.screenSection ()