#!/usr/bin/env python

##############################################################################
#                                IcePref
#
# This is (or will be) the best IceWM configuration utility
# known to man.  It requires a recent version of python as well as Gtk ( >
# 1.2.0) and PyGtk.  It should work well with versions of icewm around
# 1.2. You may place it anywhere in your path. You are free to copy,
# change, and distribute this program under the terms of the GNU GPL.  You
# can obtain the latest version of this script from via http at
# http://www.goots.org/ice.html.  Please report all bugs
# to Nick at nick@goots.org.  Please include IcePref in the subject line.
#
# Copyright 1999, David Mortensen
# Updated 2002 to IceWM 1.2 by R. N. Cross
#
# This work comes with no warranty regarding its suitability for any purpose.
# The author is not responsible for any damages caused by the use of this
# program.
##############################################################################

from gtk import *
from string import *

# the user module is no longer imported as it is said to introduce security
# risks (9/28/1999)

import re
import sys
import os
import commands
import glob

##############################################################################
# Constants in a Changing World
##############################################################################

VERSION = "1.2.1"
ICE_VERSION = "1.2"

DEBUG = TRUE # Turns debugging on / off

# these define the types of configuration widgets

TOGGLE = 0	#done
RANGE = 1 	#done
FILE = 2	#done
PATH = 3	#done
COLOR = 4 	#done
FONT = 5	#done
ENTRY = 6 	#done
KEYSTROKE = 7	#done
MULTI = 8 	#done
THEME = 9 	#done
BITMASK = 10	#done
MOUSEBUTTON = 11 #done

# these define the indexes for the data in DEFAULTS and self.settings

COMMENTED = -1
TYPE = 0
VALUE = 1
TITLE = 2
MIN = 3
MAX = 4
NUM = 3

# the standard spacing and border width, respectively

SP = 5
BD = 5

# some environmental variables -- more than are needed, really.

if os.environ.has_key('OSTYPE'):
    OSTYPE   = os.environ['OSTYPE']
else:
    OSTYPE   = os.uname()[0]

if os.environ.has_key('MACHTYPE'):
    MACHTYPE = os.environ['MACHTYPE']
else:
    MACHTYPE = 'i386-pc-linux-gnu'

if os.environ.has_key('HOME'):
    HOME     = os.environ['HOME']
else:
    import user
    HOME     = user.home

if os.environ.has_key('USER'):
    USER     = os.environ['USER']
else:
    USER = os.uname()[1]

if os.environ.has_key('PATH'):
    PATH     = os.environ['PATH']
else:
    PATH = ''

if DEBUG:
    print 'OSTYPE=%s' % OSTYPE
    print 'MACHTYPE=%s' % MACHTYPE
    print 'HOME=%s' % HOME
    print 'USER=%s' % USER
    print 'PATH=%s' % PATH

# finally, the file we're editing

CONFIG_FILE = HOME + '/.icewm/preferences'

# and the paths to all your themes
# (If the path to your themes is not here, simply add it.  Just follow the
# example of the other paths!)

THEME_PATH = [	'/usr/local/lib/X11/icewm/themes/*',
                '/usr/local/share/icewm/themes/*',
		'/usr/X11R6/lib/X11/icewm/themes/*',
		'/usr/X11R6/share/icewm/themes/*',
		HOME + '/.icewm/themes/*'	]

SAMPLE_TEXT = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz'
ERROR_TEXT = 'Invalid Font'

##############################################################################
# Cofiguration Options Data
#
# In order to add a new item, it must be added to each of the following two
# data structures.  DEFAULTS is a dictionary containing information about the
# widget to be used, the parameter's default value (as a string), the title/label
# and the min and max for range type controls.  The keys are, of course, the
# name of the variables in the preferences file.
##############################################################################

DEFAULTS = {	'ClickToFocus': [TOGGLE, '1', 'Focus windows by clicking', COMMENTED ],
		'RaiseOnFocus': [TOGGLE, '1', 'Raise windows when focused', COMMENTED ],
		'FocusOnClickClient': [TOGGLE, '1', 'Focus window when client area clicked', COMMENTED ],
		'RaiseOnClickClient': [TOGGLE, '1', 'Raise window when client area clicked', COMMENTED ],
		'RaiseOnClickTitleBar': [TOGGLE, '1', 'Raise window when title bar is clicked', COMMENTED ],
		'RaiseOnClickButton': [TOGGLE, '1', 'Raise when frame button is clicked', COMMENTED ],
		'LowerOnClickWhenRaised': [TOGGLE, '0', 'Lower the active window when clicked again', COMMENTED ],
		'RaiseOnClickFrame': [TOGGLE, '1', 'Raise when frame border is clicked', COMMENTED ],
		'PassFirstClickToClient': [TOGGLE, '1', 'Pass focusing click on client area to client', COMMENTED ],
		'FocusOnMap': [TOGGLE, '1', 'Focus normal window when initially mapped', COMMENTED ],
		'FocusOnMapTransient': [TOGGLE, '1', 'Focus dialog window when initally mapped', COMMENTED ],
		'FocusOnMapTransientActive': [TOGGLE, '1', 'Focus dialog window when initially mapped only if parent frame focused', COMMENTED ],
		'FocusOnMapTransientActive': [TOGGLE, '1', 'Focus dialog window when initially mapped only if parent frame focused', COMMENTED ],
		'DontRotateMenuPointer': [TOGGLE, '0', 'Do not rotate the cursor for popup menus', COMMENTED ],
		'PointerColormap': [TOGGLE, '1', 'Colormap follows pointer', COMMENTED ],
		'LimitSize': [TOGGLE, '1', 'Limit initial size of windows to screen', COMMENTED ],
		'LimitPosition': [TOGGLE, '1', 'Limit initial position of windows to screen', COMMENTED ],
		'LimitByDockLayer': [TOGGLE, '1', 'Let the Dock layer limit the workspace (incompatible with GNOME Panel)', COMMENTED ],
		'ConsiderHBorder': [TOGGLE, '1', 'Consider border frames when maximizing horizontally', COMMENTED ],
		'ConsiderVBorder': [TOGGLE, '1', 'Consider border frames when maximizing vertically', COMMENTED ],
		'CenterMaximizedWindows': [TOGGLE, '1', 'Center maximized windows which can not fit the screen (like terminals)', COMMENTED ],
		'SizeMaximized': [TOGGLE, '0', 'Maximized windows can be resized', COMMENTED ],
		'ShowMoveSizeStatus': [TOGGLE, '1', 'Show position status window during move/resize', COMMENTED ],
		'ShowWorkspaceStatus': [TOGGLE, '1', 'Show name of current workspace while switching', COMMENTED ],
		'MinimizeToDesktop': [TOGGLE, '0', 'Display mini-icons on desktop for minimized windows', COMMENTED ],
		'StrongPointerFocus': [TOGGLE, '0', 'Always maintain focus under mouse window (makes some keyboard support non-functional)', COMMENTED ],
		'OpaqueMove': [TOGGLE, '1', 'Opaque window move', COMMENTED ],
		'OpaqueResize': [TOGGLE, '1', 'Opaque window resize', COMMENTED ],
		'ManualPlacement': [TOGGLE, '0', 'Windows initially placed manually by user', COMMENTED ],
		'SmartPlacement': [TOGGLE, '1', 'Smart window placement (minimize overlap)', COMMENTED ],
		'CenterTransientsOnOwner': [TOGGLE, '1', 'Center dialogs on owner window', COMMENTED ],
		'MenuMouseTracking': [TOGGLE, '0', 'Menus track mouse even with no mouse buttons held', COMMENTED ],
		'AutoRaise': [TOGGLE, '0', 'Auto raise windows after delay', COMMENTED ],
		'DelayPointerFocus': [TOGGLE, '0', 'Delay pointer focusing when mouse moves', COMMENTED ],
		'Win95Keys': [TOGGLE, '0', 'Support win95 keyboard keys', COMMENTED ],
		'ModMetaIsCtrlAlt': [TOGGLE, '1', 'Treat Penguin/Meta/Win modifer as Ctrl+Alt', COMMENTED ],
		'UseMouseWheel': [TOGGLE, '0', 'Support mouse wheel', COMMENTED ],
		'ShowPopupsAbovePointer': [TOGGLE, '1', 'Show popup menus above mouse pointer', COMMENTED ],
		'ReplayMenuCancelClick': [TOGGLE, '0', 'Send the clicks outside menus to target window', COMMENTED ],
		'QuickSwitch': [TOGGLE, '1', 'Alt+Tab window switching', COMMENTED ],
		'QuickSwitchToMinimized': [TOGGLE, '1', 'Alt+Tab to minimized windows', COMMENTED ],
		'QuickSwitchToHidden': [TOGGLE, '0', 'Alt-Tab to hidden windows', COMMENTED ],
		'QuickSwitchToAllWorkspaces': [TOGGLE, '0', 'Alt+Tab to windows on other workspaces', COMMENTED ],
		'QuickSwitchAllIcons': [TOGGLE, '1', 'Show all reachable icons when quick switching', COMMENTED ],
		'QuickSwitchTextFirst': [TOGGLE, '1', 'Show the window title above (all reachable) icons', COMMENTED ],
		'QuickSwitchSmallWindow': [TOGGLE, '0', 'Attempt to create a small QuickSwitch window (1/3 instead of 3/5 of screen width)', COMMENTED ],
		'QuickSwitchHugeIcon': [TOGGLE, '0', 'Show the huge (48x48) of the window icon for the active window', COMMENTED ],
                'QuickSwitchFillSelection': [TOGGLE, '1', 'Fill the rectangle highlighting the current icon', COMMENTED ],
                'GrabRootWindow': [TOGGLE, '1', 'Manage root window', COMMENTED ],
		'SnapMove': [TOGGLE, '1', 'Snap to nearest screen edge/window when moving windows', COMMENTED ],
		'EdgeSwitch': [TOGGLE, '0', 'Workspace switches by moving mouse to left/right screen edge', COMMENTED ],
                'HorizontalEdgeSwitch': [TOGGLE, '1', 'Workspace switches by moving mouse to left/right screen edge', COMMENTED ],
                'VerticalEdgeSwitch': [TOGGLE, '0', 'Workspace switches by moving mouse to top/bottom screen edge', COMMENTED ],
                'ContinuousEdgeSwitch': [TOGGLE, '0', 'Workspace switches continuously', COMMENTED ],
		'DesktopBackgroundCenter': [TOGGLE, '0', 'Display desktop background centered and not tiled', COMMENTED ],
		'SupportSemitransparency': [TOGGLE, '0', 'Support for semitransparent terminals like Eterm or gnome-terminal', COMMENTED ],
		'AutoReloadMenus': [TOGGLE, '1', 'Reload menu files automatically', COMMENTED ],
		'ShowMenuButtonIcon': [TOGGLE, '1', 'Show application icon over menu button', COMMENTED ],
		'ShowTaskBar': [TOGGLE, '1', 'Show task bar', COMMENTED ],
		'TaskBarAtTop': [TOGGLE, '0', 'Task bar at top of the screen', COMMENTED ],
		'TaskBarKeepBelow': [TOGGLE, '0', 'Keep the task bar below regular windows', COMMENTED ],
		'TaskBarAutoHide': [TOGGLE, '0', 'Auto hide task bar after delay', COMMENTED ],
		'TaskBarShowClock': [TOGGLE, '1', 'Show clock on task bar', COMMENTED ],
		'TaskBarShowAPMStatus': [TOGGLE, '0', 'Show automatic power management (APM) status on task bar', COMMENTED ],
		'TaskBarShowAPMTime': [TOGGLE, '1', 'Show APM status on task bar in time-format', COMMENTED ],
		'TaskBarClockLeds': [TOGGLE, '1', 'Task bar clock uses nice pixmapped LCD display', COMMENTED ],
		'TaskBarShowMailboxStatus': [TOGGLE, '1', 'Show mailbox status on the task bar', COMMENTED ],
		'TaskBarMailboxStatusBeepOnNewMail': [TOGGLE, '0', 'Beep when new mail arrives', COMMENTED ],
		'TaskBarMailboxStatusCountMessages': [TOGGLE, '0', 'Count messages in mailbox', COMMENTED ],
		'TaskBarShowWorkspaces': [TOGGLE, '1', 'Show workspace switching buttons on task bar', COMMENTED ],
		'TaskBarShowWindows': [TOGGLE, '1', 'Show windows on the taskbar', COMMENTED ],
		'TaskBarShowTray': [TOGGLE, '1', 'Show windows in the tray', COMMENTED ],
		'TrayDrawBevel': [TOGGLE, '0', 'Surround the tray with plastic border', COMMENTED ],
		'TrayShowAllWindows': [TOGGLE, '0', 'Show windows from all workspaces on tray', COMMENTED ],
		'TaskBarShowAllWindows': [TOGGLE, '0', 'Show windows from all workspaces on task bar', COMMENTED ],
		'TaskBarShowWindowIcons': [TOGGLE, '1', 'Show icons of windows on the task bar', COMMENTED ],
		'TaskBarShowStartMenu': [TOGGLE, '1', 'Show "Start" menu on task bar', COMMENTED ],
		'TaskBarShowWindowListMenu': [TOGGLE, '1', 'Show "window list" menu on task bar', COMMENTED ],
		'TaskBarShowCPUStatus': [TOGGLE, '1', 'Show CPU status on task bar', COMMENTED ],
		'TaskBarShowNetStatus': [TOGGLE, '1', 'Show network status on task bar', COMMENTED ],
		'TaskBarDoubleHeight': [TOGGLE, '0', 'Use double height task bar', COMMENTED ],
		'TaskBarLaunchOnSingleClick': [TOGGLE, '0', 'Execute taskbar applet commands (like MailCommand, ClockCommand) on single click', COMMENTED ],
		'WarpPointer': [TOGGLE, '0', 'Move mouse when doing focusing in pointer focus mode', COMMENTED ],
		'ClientWindowMouseActions': [TOGGLE, '0', 'Allow mouse actions on client windows (buggy with some programs)', COMMENTED ],
		'TitleBarJoinLeft': [TOGGLE, '0', 'Join title*S and title*T', COMMENTED ],
		'TitleBarJoinRight': [TOGGLE, '0', 'Join title*T and title*B', COMMENTED ],
		'ShowThemesMenu': [TOGGLE, '1', 'Show the submenu for selecting themes', COMMENTED ],
		'ShowLogoutMenu': [TOGGLE, '1', 'Show logout submenu', COMMENTED ],
		'ShowHelp': [TOGGLE, '1', 'Show the help menu item', COMMENTED ],
		'AutoDetectGNOME': [TOGGLE, '1', 'Automatically disable some functions when running under GNOME', COMMENTED ],
		'GNOMEAppsMenuAtToplevel': [TOGGLE, '0', 'Create GNOME application menu at toplevel', COMMENTED ],
		'GNOMEUserMenuAtToplevel': [TOGGLE, '0', 'Create GNOME user menu at toplevel', COMMENTED ],
		'KDEMenuAtToplevel': [TOGGLE, '0', 'Create KDE menu at toplevel', COMMENTED ],
		'ShowGnomeAppsMenu': [TOGGLE, '0', 'Show GNOME application menu when possible', COMMENTED ],
		'ShowGnomeUserMenu': [TOGGLE, '0', 'Show GNOME user menu when possible', COMMENTED ],
		'ShowKDEMenu': [TOGGLE, '0', 'Show KDE menu when possible', COMMENTED ],
		'GNOMEFolderIcon': [TOGGLE, '0', 'Show GNOMEs folder icon in GNOME menus', COMMENTED ],
		'DisableImlibCaches': [TOGGLE, '0', 'Disable Imlibs image/pixmap caches', COMMENTED ],
                'ShowAddressBar': [TOGGLE, '0', 'Show address bar in task bar', COMMENTED ],
		'MultiByte': [TOGGLE, '0', 'Overrides automatic multiple byte detection', COMMENTED ],
		'XFreeType': [TOGGLE, '0', 'Overrides automatic Xrender detection', COMMENTED ],
		'ConfirmLogout': [TOGGLE, '1', 'Ask for confirmation on logout', COMMENTED ],
		'ShapesProtectClientWindow': [TOGGLE, '1', 'Do not cut client windows by shapes set trough frame corner pixmap', COMMENTED ],
		'BorderSizeX': [RANGE, '6', 'Horizontal window border', 0, 128, COMMENTED ],
		'BorderSizeY': [RANGE, '6', 'Veritical window border', 0, 128, COMMENTED ],
		'DlgBorderSizeX': [RANGE, '2', 'Horizontal dialog window border', 0, 128, COMMENTED ],
		'DlgBorderSizeY': [RANGE, '2', 'Vertical dialog window border', 0, 128, COMMENTED ],
		'CornerSizeX': [RANGE, '24', 'Resize corner width', 0, 64, COMMENTED ],
		'CornerSizeY': [RANGE, '24', 'Resize corner height', 0, 64, COMMENTED ],
		'TitleBarHeight': [RANGE, '20', 'Title bar height', 0, 128, COMMENTED ],
		'TitleBarJustify': [RANGE, '50', 'Justification of the window title', 0, 100, COMMENTED ],
		'TitleBarHorzOffset': [RANGE, '0', 'Horizontal offset for the window title', -128, 128, COMMENTED ],
		'TitleBarVertOffset': [RANGE, '0', 'Vertical offset for the window title text', -128, 128, COMMENTED ],
		'ScrollBarX': [RANGE, '0', 'Scrollbar width', 0, 64, COMMENTED ],
		'ScrollBarY': [RANGE, '0', 'Scrollbar (button) height', 0, 64, COMMENTED ],
		'ClickMotionDistance': [RANGE, '4', 'Pointer motion distance before click gets interpreted as drag', 0, 32, COMMENTED ],
		'ClickMotionDelay': [RANGE, '200', 'Delay before click gets interpreted as drag', 0, 2000, COMMENTED ],
		'MultiClickTime': [RANGE, '400', 'Multiple click time', 0, 5000, COMMENTED ],
		'MenuActivateDelay': [RANGE, '10', 'Delay before activating menu items', 0, 5000, COMMENTED ],
		'SubmenuMenuActivateDelay': [RANGE, '300', 'Delay before activating menu submenus', 0, 5000, COMMENTED ],
		'MenuMaximalWidth': [RANGE, '0', 'Maximal width of popup menus,  2/3 of the screens width if set to zero', 0, 16384, COMMENTED ],
		'ToolTipDelay': [RANGE, '1000', 'Delay before tooltip window is displayed', 0, 5000, COMMENTED ],
                'ToolTipTime': [RANGE, '1000', 'Time before tooltip is hidden', 0, 5000, COMMENTED ],
		'AutoHideDelay': [RANGE, '300', 'Delay before task bar is automatically hidden', 0, 5000, COMMENTED ],
		'AutoRaiseDelay': [RANGE, '400', 'Delay before windows are auto raised', 0, 5000, COMMENTED ],
		'EdgeResistance': [RANGE, '32', 'Resistance in pixels when trying to move windows off the screen', 0, 10000, COMMENTED ],
		'PointerFocusDelay': [RANGE, '200', 'Delay for pointer focus switching', 0, 1000, COMMENTED ],
		'SnapDistance': [RANGE, '8', 'Distance in pixels before windows snap together', 0, 128, COMMENTED ],
		'EdgeSwitchDelay': [RANGE, '600', 'Screen edge workspace switching delay', 0, 5000, COMMENTED ],
		'ScrollBarStartDelay': [RANGE, '500', 'Initial scrollbar autoscroll delay', 0, 5000, COMMENTED ],
		'ScrollBarDelay': [RANGE, '300', 'Scroll bar delay', 0, 5000, COMMENTED ],
		'AutoScrollStartDelay': [RANGE, '1000', 'Autoscroll start delay', 0, 5000, COMMENTED ],
		'AutoScrollDelay': [RANGE, '60', 'Auto scroll delay', 0, 5000, COMMENTED ],
		'WorkspaceStatusTime': [RANGE, '2500', 'Time before workspace status window is hidden', 0, 2500, COMMENTED ],
		'UseRootButtons': [BITMASK, '255', 'Bitmask of root window button click to use in window manager', 0, 255, COMMENTED ],
		'ButtonRaiseMask': [BITMASK, '1', 'Bitmask of buttons that raise the window when pressed', 0, 255, COMMENTED ],
		'DesktopWinMenuButton': [MOUSEBUTTON, '1', 'Mouse-button clicked on desktop to show window list menu', 0, 5, COMMENTED ],
		'DesktopWinListButton': [MOUSEBUTTON, '2', 'Mouse-button clicked on desktop to show window list', 0, 5, COMMENTED ],
		'DesktopMenuButton': [MOUSEBUTTON, '3', 'Mouse-button clicked on desktop to show menu', 0, 5, COMMENTED ],
		'TitleBarMaximizeButton': [MOUSEBUTTON, '1', 'Mouse-button clicked on titlebar to maximize window', 0, 8, COMMENTED ],
		'TitleBarRollupButton': [MOUSEBUTTON, '2', 'Mouse-button clicked on titlebar to roll up window', 0, 8, COMMENTED ],
		'MsgBoxDefaultAction': [TOGGLE, '0', 'Preselect to Cancel (0) or the OK (1) button in message boxes', COMMENTED ],
		'MailCheckDelay': [RANGE, '30', 'Delay between new-mail checks in seconds', 0, 3600, COMMENTED ],
		'QuickSwitchHorzMargin': [RANGE, '3', 'Horizontal margin of the quickswitch window', 0, 64, COMMENTED ],
		'QuickSwitchVertMargin': [RANGE, '3', 'Vertical margin of the quickswitch window', 0, 64, COMMENTED ],
		'QuickSwitchIconMargin': [RANGE, '4', 'Distance between icon and margin in quickswitch window', 0, 64, COMMENTED ],
		'QuickSwitchIconBorder': [RANGE, '2', 'Distance between the active icon and itīs border', 0, 64, COMMENTED ],
		'QuickSwitchSeparatorSize': [RANGE, '6', 'Height of the separator between (all reachable) icons and text, 0 to avoid it', 0, 64, COMMENTED ],
		'TaskBarCPUSamples': [RANGE, '20', 'Width of CPU Monitor', 2, 1000, COMMENTED ],
		'MoveSizeInterior': [RANGE, '4', 'Bitmask for inner decorations (1: border style, 2: titlebar, 4/8/16: grid)', 0, 31, COMMENTED ],
		'MoveSizeDimensionLines': [RANGE, '1', 'Bitmask for dimension lines (1/2/4: top left/center/right, 8/16/32: left top/middle/bottom, ...)', 0, 4095, COMMENTED ],
		'MoveSizeGaugeLines': [RANGE, '1', 'Bitmask for gauge lines (1/2/4/8: top/left/right/bottom)', 0, 15, COMMENTED ],
		'MoveSizeDimensionLabels': [RANGE, '0', 'Bitmask for dimension labels (1/2/4: top left/center/right, 8/16/32: left top/middle/bottom, ...)', 0, 4095, COMMENTED ],
		'MoveSizeGeometryLabels': [RANGE, '8', 'Bitmask for geometry labels (1/2/4: top left/center/right, 8: center, ...)', 0, 127, COMMENTED ],
		'TitleButtonsLeft': [ENTRY, '"s"', 'Titlebar buttons from left to right (x=close, m=max, i=min, h=hide, r=rollup, s=sysmenu)', COMMENTED ],
		'TitleButtonsRight': [ENTRY, '"xmi"', 'Titlebar buttons from right to left (x=close, m=max, i=min, h=hide, r=rollup, s=sysmenu)', COMMENTED ],
		'TitleButtonsSupported' : [ENTRY, '"xmis"', 'Titlebar buttons supported by theme (x, m, i, r, h, s, d)', COMMENTED ],
		'IconPath': [PATH, '"/usr/share/icons:/usr/share/icons/mini:/usr/share/icons/locolr/16x16/apps/:/usr/share/icons/hicolor/16x16/apps/:/usr/X11R6/lib/X11/icewm/icons"', 'Icon search path (colon separated)', COMMENTED ],
		'KDEDataDir': [FILE, '"/usr/X11R6/share"', 'Root directory for KDE data', COMMENTED ],
		'MailBoxPath': [FILE, '""', 'Mailbox path ($MAIL is used if no value is specified)', COMMENTED ],
		'MailCommand': [FILE, '""', 'Command to run on mailbox', COMMENTED ],
		'MailClassHint': [ENTRY, '"pine.XTerm"', 'WM_CLASS to allow runonce for MailCommand', COMMENTED ],
		'NewMailCommand': [FILE, '""', 'Command to run when new mail arrives', COMMENTED ],
		'LockCommand': [FILE, '"xlock"', 'Command to lock display or show screensaver', COMMENTED ],
		'ClockClassHint': [ENTRY, '"icewm.XClock"', 'WM_CLASS to allow runonce for ClockCommand', COMMENTED ],
		'ClockCommand': [FILE, '"xclock"', 'Command to run on clock', COMMENTED ],
		'RunCommand': [FILE, '""', 'Command to select and run a program', COMMENTED ],
		'OpenCommand': [FILE, '""', 'Open command', COMMENTED ],
		'TerminalCommand': [FILE, '"xterm"', 'Terminal emulator (must accept -e option)', COMMENTED ],
		'LogoutCommand': [FILE, '""', 'Command to start logout', COMMENTED ],
		'LogoutCancelCommand': [FILE, '""', 'Command to cancel logout', COMMENTED ],
		'ShutdownCommand' : [FILE, '"shutdown -h now"', 'Command to shut down the system', COMMENTED ],
		'RebootCommand' : [FILE, '"shutdown -r now"', 'Command to reboot the system', COMMENTED ],
		'CPUStatusCommand' : [FILE, '""', 'Command to run when CPU status monitor is clicked', COMMENTED ],
		'CPUStatusClassHint': [ENTRY, '"top.XTerm"', 'WM_CLASS to allow runonce for CPUStatusCommand', COMMENTED ],
		'NetStatusCommand' : [FILE, '""', 'Command to run when net status monitor is clicked', COMMENTED ],
		'NetStatusClassHint': [ENTRY, '"netstat.XTerm"', 'WM_CLASS to allow runonce for NetStatusCommand', COMMENTED ],
		'OpenCommand': [FILE, '""', 'Open command', COMMENTED ],
		'AddressBarCommand' : [FILE, '""', 'Command to run for address bar entries', COMMENTED ],
		'NetworkStatusDevice': [ENTRY, '"ppp0"', 'Network device for which to show status', COMMENTED ],
		'TimeFormat': [ENTRY, '"%H:%M:%S"', 'Clock time format (strftime format string)', COMMENTED ],
		'TimeFormatAlt': [ENTRY, '"%H:%M:%S"', 'Alternate Clock Time format (e.g. for blinking effects)', COMMENTED ],
		'DateFormat': [ENTRY, '"%A %d/%m/%Y %H:%M:%S %Z"', 'Clock date format for tooltip (strftime format string)', COMMENTED ],
		'Theme': [THEME, '"warp3/default.theme"', 'Theme (theme_directory/default.theme)', COMMENTED ],
		'ThemeAuthor': [ENTRY, '""', 'Theme author', COMMENTED ],
		'ThemeDescription': [ENTRY, '""', 'Theme description', COMMENTED ],
		'TitleFontName': [FONT, '"-b&h-lucida-bold-r-*-*-*-120-*-*-*-*-*-*"', 'Title bar font', COMMENTED ],
		'MenuFontName': [FONT, '"-b&h-lucida-bold-r-*-*-*-120-*-*-*-*-*-*"', 'Menu font', COMMENTED ],
		'FxFontName': [FONT, '"-adobe-courier-bold-r-*-*-*-120-*-*-*-*-*-*"', 'Fx Font', COMMENTED ],
		'StatusFontName': [FONT, '"-b&h-lucidatypewriter-bold-r-*-*-*-120-*-*-*-*-*-*"', 'Status font', COMMENTED ],
		'QuickSwitchFontName': [FONT, '"-b&h-lucidatypewriter-bold-r-*-*-*-120-*-*-*-*-*-*"', 'Quick switch font', COMMENTED ],
		'NormalButtonFontName': [FONT, '"-b&h-lucida-medium-r-*-*-*-120-*-*-*-*-*-*"', 'Normal button font', COMMENTED ],
		'ActiveButtonFontName': [FONT, '"-b&h-lucida-bold-r-*-*-*-120-*-*-*-*-*-*"', 'Active button font', COMMENTED ],
		'NormalTaskBarFontName': [FONT, '"-b&h-lucida-medium-r-*-*-*-120-*-*-*-*-*-*"', 'Normal taskbar font', COMMENTED ],
                'ActiveTaskBarFontName': [FONT, '"-b&h-lucida-bold-r-*-*-*-120-*-*-*-*-*-*"', 'Active taskbar font', COMMENTED ],
		'MinimizedWindowFontName': [FONT, '"-b&h-lucida-medium-r-*-*-*-120-*-*-*-*-*-*"', 'Minimized window font', COMMENTED ],
		'ListBoxFontName': [FONT, '"-b&h-lucida-medium-r-*-*-*-120-*-*-*-*-*-*"', 'List box font', COMMENTED ],
		'ToolTipFontName': [FONT, '"-b&h-lucida-medium-r-*-*-*-120-*-*-*-*-*-*"', 'Tooltip font', COMMENTED ],
		'ClockFontName': [FONT, '"-b&h-lucidatypewriter-medium-r-*-*-*-140-*-*-*-*-*-*"', 'Clock font', COMMENTED ],
		'ApmFontName': [FONT, '"-adobe-courier-medium-r-*-*-*-140-*-*-*-*-*-*"', 'APM font', COMMENTED ],
		'LabelFontName': [FONT, '"-b&h-lucida-medium-r-*-*-*-140-*-*-*-*-*-*"', 'Label font', COMMENTED ],
		'moveSizeFontName': [FONT, '"-adobe-helvetica-bold-r-*-*-*-100-*-*-*-*-*-*"', 'MoveSize font', COMMENTED ],
		'ColorDialog': [COLOR, '"rgb:C0/C0/C0"', 'Dialog color', COMMENTED ],
		'ColorNormalBorder': [COLOR,'"rgb:C0/C0/C0"', 'Normal border color', COMMENTED ],
		'ColorActiveBorder': [COLOR, '"rgb:C0/C0/C0"', 'Active border color', COMMENTED ],
		'ColorNormalButton': [COLOR, '"rgb:C0/C0/C0"', 'Normal button color', COMMENTED ],
		'ColorNormalButtonText': [COLOR, '"rgb:00/00/00"', 'Normal button text color', COMMENTED ],
		'ColorActiveButton': [COLOR, '"rgb:E0/E0/E0"', 'Active button color', COMMENTED ],
		'ColorActiveButtonText': [COLOR, '"rgb:00/00/00"', 'Active button text color', COMMENTED ],
		'ColorNormalTitleButton': [COLOR, '"rgb:C0/C0/C0"', 'Normal title button color', COMMENTED ],
		'ColorNormalTitleButtonText': [COLOR, '"rgb:00/00/00"', 'Normal title button text color', COMMENTED ],
		'ColorToolButton': [COLOR, '""', 'Background of toolbar buttons, ColorNormalButton is used if empty', COMMENTED ],
		'ColorToolButtonText': [COLOR, '""', 'Textcolor of toolbar buttons, ColorNormalButtonText is used if empty', COMMENTED ],
		'ColorNormalWorkspaceButton': [COLOR, '""', 'Background of workspace buttons, ColorNormalButton is used if empty', COMMENTED ],
		'ColorNormalWorkspaceButtonText': [COLOR, '""', 'Textcolor of workspace buttons, ColorNormalButtonText is used if empty', COMMENTED ],
		'ColorActiveWorkspaceButton': [COLOR, '""', 'Background of the active workspace button, ColorActiveButton is used if empty', COMMENTED ],
		'ColorActiveWorkspaceButtonText': [COLOR, '""', 'Textcolor of the active workspace button, ColorActiveButtonText is used if empty', COMMENTED ],
                'ColorNormalTitleBar': [COLOR, '"rgb:80/80/80"', 'Normal title bar color', COMMENTED ],
		'ColorNormalTitleBarText': [COLOR, '"rgb:00/00/00"', 'Normal title bar text color', COMMENTED ],
		'ColorActiveTitleBar': [COLOR, '"rgb:00/00/A0"', 'Active title bar color', COMMENTED ],
		'ColorActiveTitleBarText': [COLOR, '"rgb:FF/FF/FF"', 'Active title bar text color', COMMENTED ],
		'ColorNormalMinimizedWindow': [COLOR, '"rgb:C0/C0/C0"', 'Normal minimized window color', COMMENTED ],
		'ColorNormalMinimizedWindowText': [COLOR, '"rgb:00/00/00"', 'Normal minimized winodw text color', COMMENTED ],
		'ColorActiveMinimizedWindow': [COLOR, '"rgb:E0/E0/E0"', 'Active minimized window color', COMMENTED ],
		'ColorActiveMinimizedWindowText': [COLOR, '"rgb:00/00/00"', 'Active minimized window text color', COMMENTED ],
		'ColorNormalMenu': [COLOR, '"rgb:C0/C0/C0"', 'Normal menu color', COMMENTED ],
		'ColorNormalMenuItemText': [COLOR, '"rgb:00/00/00"', 'Normal menu item text color', COMMENTED ],
		'ColorActiveMenuItem': [COLOR, '"rgb:A0/A0/A0"', 'Active menu item color', COMMENTED ],
		'ColorActiveMenuItemText': [COLOR, '"rgb:00/00/00"', 'Active menu item text color', COMMENTED ],
                'ColorDisabledMenuItemText': [COLOR, '"rgb:80/80/80"', 'Disabled menu item text color', COMMENTED ],
		'ColorDisabledMenuItemShadow': [COLOR, '""', 'Shadow of regular menu items', COMMENTED ],
		'ColorMoveSizeStatus': [COLOR, '"rgb:C0/C0/C0"', 'Move/size status color', COMMENTED ],
		'ColorMoveSizeStatusText': [COLOR, '"rgb:00/00/00"', 'Move/size status text color', COMMENTED ],
		'ColorQuickSwitch': [COLOR, '"rgb:C0/C0/C0"', 'Quick switch color', COMMENTED ],
		'ColorQuickSwitchText': [COLOR, '"rgb:00/00/00"', 'Quick switch text color', COMMENTED ],
		'ColorQuickSwitchActive': [COLOR, '""', 'Rectangle arround the active icon in the quick switch window', COMMENTED ],
		'ColorDefaultTaskBar': [COLOR, '"rgb:C0/C0/C0"', 'Default taskbar color', COMMENTED ],
		'ColorNormalTaskBarApp': [COLOR, '"rgb:C0/C0/C0"', 'Normal taskbar color', COMMENTED ],
		'ColorNormalTaskBarAppText': [COLOR, '"rgb:00/00/00"', 'Normal taskbar app text color', COMMENTED ],
		'ColorActiveTaskBarApp': [COLOR, '"rgb:E0/E0/E0"', 'Active taskbar app color', COMMENTED ],
		'ColorActiveTaskBarAppText': [COLOR, '"rgb:00/00/00"', 'Active taskbar app text color', COMMENTED ],
		'ColorMinimizedTaskBarApp': [COLOR, '"rgb:A0/A0/A0"', 'Minimized taskbar app color', COMMENTED ],
		'ColorMinimizedTaskBarAppText': [COLOR, '"rgb:00/00/00"', 'Minimized taskbar app text', COMMENTED ],
		'ColorInvisibleTaskBarApp': [COLOR, '"rgb:80/80/80"', 'Invisible taskbar app color', COMMENTED ],
		'ColorInvisibleTaskBarAppText': [COLOR, '"rgb:00/00/00"', 'Invisible taskbar app text', COMMENTED ],
		'ColorScrollBarButton': [COLOR, '"rgb:C0/C0/C0"', 'Background of the arrow buttons in scrollbars', COMMENTED ],
		'ColorScrollBarButtonArrow': [COLOR, '"rgb:00/00/00"', 'Color of active arrows on scrollbar buttons', COMMENTED ],
		'ColorScrollBarInactiveArrow': [COLOR, '"rgb:80/80/80"', 'Color of inactive arrows on scrollbar buttons', COMMENTED ],
		'ColorScrollBar': [COLOR, '"rgb:A0/A0/A0"', 'Scroll bar color', COMMENTED ],
		'ColorScrollBarArrow': [COLOR, '"rgb:C0/C0/C0"', 'Scroll bar arrow color', COMMENTED ],
		'ColorScrollBarSlider': [COLOR, '"rgb:C0/C0/C0"', 'Scroll bar slider color', COMMENTED ],
		'ColorListBox': [COLOR, '"rgb:C0/C0/C0"', 'List box color', COMMENTED ],
		'ColorListBoxText': [COLOR, '"rgb:00/00/00"', 'List box text color', COMMENTED ],
		'ColorListBoxSelection': [COLOR, '"rgb:80/80/80"', 'List box selection color', COMMENTED ],
		'ColorListBoxSelectionText': [COLOR, '"rgb:00/00/00"', 'List box selection text color', COMMENTED ],
		'ColorToolTip': [COLOR, '"rgb:E0/E0/00"', 'Tooltip color', COMMENTED ],
		'ColorToolTipText': [COLOR, '"rgb:00/00/00"', 'Tooltip text color', COMMENTED ],
		'ColorLabel': [COLOR, '"rgb:C0/C0/C0"', 'Label color', COMMENTED ],
		'ColorLabelText': [COLOR, '"rgb:00/00/00"', 'Label text color', COMMENTED ],
		'ColorInput': [COLOR, '"rgb:FF/FF/FF"', 'Input color', COMMENTED ],
		'ColorInputText': [COLOR, '"rgb:00/00/00"', 'Input text color', COMMENTED ],
		'ColorInputSelection': [COLOR, '"rgb:80/80/80"', 'Input selection color', COMMENTED ],
		'ColorInputSelectionText': [COLOR, '"rgb:00/00/00"', 'Input selection text color', COMMENTED ],
		'ColorClock': [COLOR, '"rgb:00/00/00"', 'Clock color', COMMENTED ],
		'ColorClockText': [COLOR, '"rgb:00/FF/00"', 'Clock text color', COMMENTED ],
		'ColorApm': [COLOR, '"rgb:00/00/00"', 'APM color', COMMENTED ],
		'ColorApmText': [COLOR, '"rgb:00/FF/00"', 'APM text color', COMMENTED ],
		'ColorCPUStatusUser': [COLOR, '"rgb:00/FF/00"', 'User CPU usage color', COMMENTED ],
		'ColorCPUStatusSystem': [COLOR, '"rgb:FF/00/00"', 'System CPU usage color', COMMENTED ],
		'ColorCPUStatusNice': [COLOR, '"rgb:00/00/FF"', 'Nice CPU usage color', COMMENTED ],
		'ColorCPUStatusIdle': [COLOR, '"rgb:00/00/00"', 'CPU Idle color', COMMENTED ],
		'ColorNetSend': [COLOR, '"rgb:FF/FF/00"', 'Color of sent data on net monitor', COMMENTED ],
		'ColorNetReceive': [COLOR, '"rgb:FF/00/FF"', 'Color of received data on net monitor', COMMENTED ],
		'ColorNetIdle': [COLOR, '"rgb:00/00/00"', 'Color representing idle on net monitor', COMMENTED ],
		'DesktopBackgroundColor': [COLOR, '"rgb:00/50/60"', 'Desktop background color', COMMENTED ],
		'DesktopBackgroundImage': [FILE, '""', 'Desktop background image', COMMENTED ],
		'DesktopTransparencyColor': [COLOR, '""', 'Color to announce for semi-transparent windows', COMMENTED ],
		'DesktopTransparencyImage': [FILE, '""', 'Image to announce for semi-transparent windows', COMMENTED ],
		'KeyWinRaise': [KEYSTROKE, '"Alt+F1"', '"Raise window" shortcut', COMMENTED ],
		'KeyWinOccupyAll': [KEYSTROKE, '"Alt+F2"', '"Occupy all" shortcut', COMMENTED ],
		'KeyWinLower': [KEYSTROKE, '"Alt+F3"', '"Lower window" shortcut', COMMENTED ],
		'KeyWinClose': [KEYSTROKE, '"Alt+F4"', '"Close window" shortcut', COMMENTED ],
		'KeyWinRestore': [KEYSTROKE, '"Alt+F5"', '"Restory window" shortcut', COMMENTED ],
		'KeyWinPrev': [KEYSTROKE, '"Alt+Shift+F6"', '"Previous window" shortcut', COMMENTED ],
		'KeyWinNext': [KEYSTROKE, '"Alt+F6"', '"Next window" shortcut', COMMENTED ],
		'KeyWinMove': [KEYSTROKE, '"Alt+F7"', '"Move window" shortcut', COMMENTED ],
		'KeyWinSize': [KEYSTROKE, '"Alt+F8"', '"Size window" shortcut', COMMENTED ],
		'KeyWinMinimize': [KEYSTROKE, '"Alt+F9"', '"Minimize window" shortcut', COMMENTED ],
		'KeyWinMaximize': [KEYSTROKE, '"Alt+F10"', '"Maximize window" shortcut', COMMENTED ],
		'KeyWinMaximizeVert': [KEYSTROKE, '"Alt+Shift+F10"', '"Maximize window vertically" shortcut', COMMENTED ],
		'KeyWinHide': [KEYSTROKE, '"Alt+F11"', '"Hide window" shortcut', COMMENTED ],
		'KeyWinRollup': [KEYSTROKE, '"Alt+F12"', '"Rollup window" shortcut', COMMENTED ],
		'KeyWinMenu': [KEYSTROKE, '"Alt+Space"', '"Window menu" shortcut', COMMENTED ],
		'KeySysSwitchNext': [KEYSTROKE, '"Alt+Tab"', '"Next item" shortcut', COMMENTED ],
		'KeySysSwitchLast': [KEYSTROKE, '"Alt+Shift+Tab"', '"Last item" shortcut', COMMENTED ],
		'KeySysWinNext': [KEYSTROKE, '"Alt+Esc"', '"Next sys window" shortcut', COMMENTED ],
		'KeySysWinPrev': [KEYSTROKE, '"Alt+Shift+Esc"', '"Previous sys window" shortcut', COMMENTED ],
		'KeySysWinMenu': [KEYSTROKE, '"Shift+Esc"', '"Window menu" shortcut', COMMENTED ],
		'KeySysDialog': [KEYSTROKE, '"Alt+Ctrl+Del"', '"Logout / screenlock dialog" shortcut', COMMENTED ],
		'KeySysMenu': [KEYSTROKE, '"Ctrl+Esc"', '"Program menu" shortcut', COMMENTED ],
		'KeySysRun': [KEYSTROKE, '"Alt+Ctrl+R"', '"Run" shortcut', COMMENTED ],
		'KeySysWindowList': [KEYSTROKE, '"Alt+Ctrl+Esc"', '"Window list" shortcut', COMMENTED ],
		'KeySysAddressBar': [KEYSTROKE, '"Alt+Ctrl+Space"', '"Address bar" shortcut', COMMENTED ],
		'KeySysWorkspacePrev': [KEYSTROKE, '"Alt+Ctrl+Left"', '"Previous workspace" shortcut', COMMENTED ],
		'KeySysWorkspaceNext': [KEYSTROKE, '"Alt+Ctrl+Right"', '"Next workspace" shortcut', COMMENTED ],
		'KeySysWorkspacePrevTakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+Left"', '"Take window to previous workspace" shortcut', COMMENTED ],
		'KeySysWorkspaceNextTakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+Right"', '"Take window to next workspace" shortcut', COMMENTED ],
		'KeySysWorkspace1': [KEYSTROKE, '"Alt+Ctrl+1"', '"Workspace 1" shortcut', COMMENTED ],
		'KeySysWorkspace2': [KEYSTROKE, '"Alt+Ctrl+2"', '"Workspace 2" shortcut', COMMENTED ],
		'KeySysWorkspace3': [KEYSTROKE, '"Alt+Ctrl+3"', '"Workspace 3" shortcut', COMMENTED ],
		'KeySysWorkspace4': [KEYSTROKE, '"Alt+Ctrl+4"', '"Workspace 4" shortcut', COMMENTED ],
		'KeySysWorkspace5': [KEYSTROKE, '"Alt+Ctrl+5"', '"Workspace 5" shortcut', COMMENTED ],
		'KeySysWorkspace6': [KEYSTROKE, '"Alt+Ctrl+6"', '"Workspace 6" shortcut', COMMENTED ],
		'KeySysWorkspace7': [KEYSTROKE, '"Alt+Ctrl+7"', '"Workspace 7" shortcut', COMMENTED ],
		'KeySysWorkspace8': [KEYSTROKE, '"Alt+Ctrl+8"', '"Workspace 8" shortcut', COMMENTED ],
		'KeySysWorkspace9': [KEYSTROKE, '"Alt+Ctrl+9"', '"Workspace 9" shortcut', COMMENTED ],
		'KeySysWorkspace10': [KEYSTROKE, '"Alt+Ctrl+0"', '"Workspace 10" shortcut', COMMENTED ],
                'KeySysWorkspace11': [KEYSTROKE, '"Alt+Ctrl+["', '"Workspace 10" shortcut', COMMENTED ],
                'KeySysWorkspace12': [KEYSTROKE, '"Alt+Ctrl+]"', '"Workspace 10" shortcut', COMMENTED ],
		'KeySysWorkspace1TakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+1"', '"Take window to workspace 1" shortcut', COMMENTED ],
		'KeySysWorkspace2TakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+2"', '"Take window to workspace 2" shortcut', COMMENTED ],
		'KeySysWorkspace3TakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+3"', '"Take window to workspace 3" shortcut', COMMENTED ],
		'KeySysWorkspace4TakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+4"', '"Take window to workspace 4" shortcut', COMMENTED ],
		'KeySysWorkspace5TakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+5"', '"Take window to workspace 5" shortcut', COMMENTED ],
		'KeySysWorkspace6TakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+6"', '"Take window to workspace 6" shortcut', COMMENTED ],
		'KeySysWorkspace7TakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+7"', '"Take window to workspace 7" shortcut', COMMENTED ],
		'KeySysWorkspace8TakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+8"', '"Take window to workspace 8" shortcut', COMMENTED ],
		'KeySysWorkspace9TakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+9"', '"Take window to workspace 9" shortcut', COMMENTED ],
		'KeySysWorkspace10TakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+0"', '"Take window to workspace 10" shortcut', COMMENTED ],
                'KeySysWorkspace11TakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+["', '"Take window to workspace 10" shortcut', COMMENTED ],
                'KeySysWorkspace12TakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+]"', '"Take window to workspace 10" shortcut', COMMENTED ],
		'WorkspaceNames': [MULTI, '" 1 ", " 2 ", " 3 ", " 4 "', 'Names of the Workspaces', 10, COMMENTED]
	}


# This list controls how the various configuration options are distributed
# on the tabs of the note book.  It is a list of two item sublists.  Each of
# these sublists contains the label of a tab and a list of the configuration
# options associated with that tab.
TABS = [
		['Behavior',
			[
			'RaiseOnFocus',
			'RaiseOnClickClient',
			'RaiseOnClickTitleBar',
			'RaiseOnClickButton',
			'RaiseOnClickFrame',
			'PassFirstClickToClient',
                        'LowerOnClickWhenRaised',
			'PointerColormap',
			'LimitSize',
			'LimitPosition',
                        'LimitByDockLayer',
                        'ConsiderHBorder',
                        'ConsiderVBorder',
                        'CenterMaximizedWindows',
                        'SizeMaximized',
			'MinimizeToDesktop',
			'OpaqueMove',
			'OpaqueResize',
			'MenuMouseTracking',
			'AutoRaise',
			'ShowPopupsAbovePointer',
			'GrabRootWindow',
			'SnapMove',
			'EdgeSwitch',
                        'MsgBoxDefaultAction',
                        'HorizontalEdgeSwitch',
                        'VerticalEdgeSwitch',
                        'ContinuousEdgeSwitch',
			'UseMouseWheel',
			'WarpPointer',
			'ClientWindowMouseActions',
			'ConfirmLogout',
			'ShowMoveSizeStatus',
                        'ShowWorkspaceStatus',
                        'SupportSemitransparency',
                        'MultiByte',
                        'XFreeType',
                        'DontRotateMenuPointer'
			]],
		['Focus',
		        [
		        'FocusOnClickClient',
			'ClickToFocus',
			'FocusOnMap',
			'FocusOnMapTransient',
			'FocusOnMapTransientActive',
			'DelayPointerFocus',
			'StrongPointerFocus',
			'QuickSwitch',
			'QuickSwitchToMinimized',
			'QuickSwitchToHidden',
			'QuickSwitchToAllWorkspaces',
                        'QuickSwitchAllIcons',
                        'QuickSwitchTextFirst',
                        'QuickSwitchSmallWindow',
                        'QuickSwitchHugeIcon',
                        'QuickSwitchFillSelection'
		        ]],
		['Window Placement',
		        [
			'ManualPlacement',
			'SmartPlacement',
			'CenterTransientsOnOwner'
			]],
		['Menus',
			[
			'AutoReloadMenus',
			'ShowMenuButtonIcon',
			'ShowThemesMenu',
			'ShowHelp',
			'ShowAddressBar',
                        'ShowLogoutMenu',
			'ReplayMenuCancelClick',
                        'MenuMaximalWidth',
                        'MenuActivateDelay',
			'SubmenuMenuActivateDelay'
                        ]],
		['Taskbar',
			[
			'ShowTaskBar',
			'TaskBarAtTop',
                        'TaskBarKeepBelow',
                        'TaskBarAutoHide',
			'TaskBarShowClock',
			'TaskBarShowAPMStatus',
                        'TaskBarShowAPMTime',
                        'TaskBarClockLeds',
			'TaskBarShowMailboxStatus',
			'TaskBarMailboxStatusBeepOnNewMail',
			'TaskBarMailboxStatusCountMessages',
			'TaskBarShowWorkspaces',
			'TaskBarShowWindows',
                        'TaskBarShowWindowIcons',
                        'TaskBarShowAllWindows',
			'TaskBarShowStartMenu',
			'TaskBarShowWindowListMenu',
			'TaskBarShowCPUStatus',
			'TaskBarShowNetStatus',
			'TaskBarDoubleHeight',
                        'TaskBarLaunchOnSingleClick',
                        'TaskBarShowTray',
                        'TrayDrawBevel',
                        'TrayShowAllWindows',
			'MailCheckDelay',
			'TaskBarCPUSamples',
			'NetworkStatusDevice'
                        ]],
		['Borders',
			[
                        'ShapesProtectClientWindow',
                        'TitleBarJoinLeft',
                        'TitleBarJoinRight',
                        'TitleBarJustify',
                        'TitleBarHorzOffset',
                        'TitleBarVertOffset',
                        'BorderSizeX',
			'BorderSizeY',
			'DlgBorderSizeX',
			'DlgBorderSizeY',
			'TitleBarHeight',
			'CornerSizeX',
			'CornerSizeY',
                        'ScrollBarX',
                        'ScrollBarY',
                        'QuickSwitchHorzMargin',
                        'QuickSwitchVertMargin',
                        'QuickSwitchIconMargin',
                        'QuickSwitchIconBorder',
                        'QuickSwitchSeparatorSize',
                        'MoveSizeInterior',
                        'MoveSizeDimensionLines',
                        'MoveSizeGaugeLines',
                        'MoveSizeDimensionLabels',
                        'MoveSizeGeometryLabels'
                        ]],
		['Timings',
			[
			'ClickMotionDelay',
			'MultiClickTime',
			'ToolTipDelay',
                        'ToolTipTime',
                        'WorkspaceStatusTime',
                        'AutoHideDelay',
			'AutoRaiseDelay',
			'PointerFocusDelay',
			'EdgeSwitchDelay',
			'ScrollBarDelay',
			'ScrollBarStartDelay',
			'AutoScrollDelay',
			'AutoScrollStartDelay'
			]],
		['Thresholds',
			[
			'ClickMotionDistance',
			'EdgeResistance',
			'SnapDistance'
                        ]],
		['Mouse Buttons',
			[
			'UseRootButtons',
			'ButtonRaiseMask',
			'DesktopWinMenuButton',
			'DesktopWinListButton',
			'DesktopMenuButton',
			'TitleBarMaximizeButton',
			'TitleBarRollupButton'
			]],
		['Title Buttons',
			[
			'TitleButtonsSupported',
			'TitleButtonsLeft',
			'TitleButtonsRight'
			]],
		['Paths',
			[
			'IconPath',
			'MailBoxPath'
			]],
		['Commands',
			[
			'MailCommand',
			'NewMailCommand',
                        'MailClassHint',
                        'LockCommand',
			'ClockCommand',
			'ClockClassHint',
			'RunCommand',
			'OpenCommand',
			'TerminalCommand',
			'LogoutCommand',
			'LogoutCancelCommand',
			'CPUStatusCommand',
                        'CPUStatusClassHint',
			'NetStatusCommand',
			'NetStatusClassHint',
                        'RebootCommand',
			'ShutdownCommand',
			'AddressBarCommand'
			]],
		['Formats',
			[
			'TimeFormat',
                        'TimeFormatAlt',
			'DateFormat'
			]],
		['Theme',
			[
			'Theme',
			'ThemeAuthor',
			'ThemeDescription'
			]],
		['Fonts',
			[
			'TitleFontName',
			'MenuFontName',
			'StatusFontName',
                        'FxFontName',
			'QuickSwitchFontName',
			'NormalButtonFontName',
			'ActiveButtonFontName',
			'NormalTaskBarFontName',
			'ActiveTaskBarFontName',
			'MinimizedWindowFontName',
			'ListBoxFontName',
			'ToolTipFontName',
			'ClockFontName',
			'ApmFontName',
			'LabelFontName',
                        'moveSizeFontName'
			]],
		['Colors',
			[
			'ColorDialog',
			'ColorNormalBorder',
			'ColorActiveBorder',
			'ColorNormalButton',
			'ColorNormalButtonText',
			'ColorActiveButton',
			'ColorActiveButtonText',
			'ColorNormalTitleButton',
			'ColorNormalTitleButtonText',
                        'ColorToolButton',
                        'ColorToolButtonText',
                        'ColorNormalWorkspaceButton',
                        'ColorNormalWorkspaceButtonText',
                        'ColorActiveWorkspaceButton',
                        'ColorActiveWorkspaceButtonText',
			'ColorNormalTitleBar',
			'ColorActiveTitleBar',
			'ColorNormalTitleBarText',
			'ColorActiveTitleBarText',
			'ColorNormalMinimizedWindow',
			'ColorNormalMinimizedWindowText',
			'ColorActiveMinimizedWindow',
			'ColorActiveMinimizedWindowText',
			'ColorNormalMenu',
			'ColorActiveMenuItem',
			'ColorActiveMenuItemText',
			'ColorNormalMenuItemText',
			'ColorDisabledMenuItemText',
                        'ColorDisabledMenuItemShadow',
                        'ColorMoveSizeStatus',
			'ColorMoveSizeStatusText',
			'ColorQuickSwitch',
			'ColorQuickSwitchText',
                        'ColorQuickSwitchActive',
			'ColorDefaultTaskBar',
			'ColorNormalTaskBarApp',
			'ColorNormalTaskBarAppText',
			'ColorActiveTaskBarApp',
			'ColorActiveTaskBarAppText',
			'ColorMinimizedTaskBarApp',
			'ColorMinimizedTaskBarAppText',
			'ColorInvisibleTaskBarApp',
			'ColorInvisibleTaskBarAppText',
                        'ColorScrollBarButton',
                        'ColorScrollBarButtonArrow',
                        'ColorScrollBarInactiveArrow',
			'ColorScrollBar',
			'ColorScrollBarArrow',
			'ColorScrollBarSlider',
			'ColorListBox',
			'ColorListBoxText',
			'ColorListBoxSelection',
			'ColorListBoxSelectionText',
			'ColorToolTip',
			'ColorToolTipText',
			'ColorClock',
			'ColorClockText',
			'ColorApm',
			'ColorApmText',
			'ColorLabel',
			'ColorLabelText',
			'ColorInput',
			'ColorInputText',
			'ColorInputSelection',
			'ColorInputSelectionText',
			'ColorCPUStatusUser',
			'ColorCPUStatusSystem',
			'ColorCPUStatusNice',
			'ColorCPUStatusIdle',
			'ColorNetSend',
			'ColorNetReceive',
			'ColorNetIdle'
			]],
		['Background',
			[
                        'DisableImlibCaches',
			'DesktopBackgroundCenter',
			'DesktopBackgroundColor',
			'DesktopBackgroundImage',
                        'DesktopTransparencyColor',
                        'DesktopTransparencyImage'
			]],
		['Keybindings',
			[
			'Win95Keys',
			'ModMetaIsCtrlAlt',
			'KeyWinRaise',
			'KeyWinOccupyAll',
			'KeyWinLower',
			'KeyWinClose',
			'KeyWinRestore',
			'KeyWinPrev',
			'KeyWinNext',
			'KeyWinMove',
			'KeyWinSize',
			'KeyWinMinimize',
			'KeyWinMaximize',
			'KeyWinMaximizeVert',
			'KeyWinHide',
			'KeyWinRollup',
			'KeyWinMenu',
			'KeySysSwitchNext',
			'KeySysSwitchLast',
			'KeySysWinNext',
			'KeySysWinPrev',
			'KeySysWinMenu',
			'KeySysDialog',
			'KeySysMenu',
			'KeySysRun',
			'KeySysWindowList',
			'KeySysAddressBar',
			'KeySysWorkspacePrev',
			'KeySysWorkspaceNext',
			'KeySysWorkspacePrevTakeWin',
			'KeySysWorkspaceNextTakeWin',
			'KeySysWorkspace1',
			'KeySysWorkspace2',
			'KeySysWorkspace3',
			'KeySysWorkspace4',
			'KeySysWorkspace5',
			'KeySysWorkspace6',
			'KeySysWorkspace7',
			'KeySysWorkspace8',
			'KeySysWorkspace9',
			'KeySysWorkspace10',
			'KeySysWorkspace11',
			'KeySysWorkspace12',
			'KeySysWorkspace1TakeWin',
			'KeySysWorkspace2TakeWin',
			'KeySysWorkspace3TakeWin',
			'KeySysWorkspace4TakeWin',
			'KeySysWorkspace5TakeWin',
			'KeySysWorkspace6TakeWin',
			'KeySysWorkspace7TakeWin',
			'KeySysWorkspace8TakeWin',
			'KeySysWorkspace9TakeWin',
			'KeySysWorkspace10TakeWin',
			'KeySysWorkspace11TakeWin',
			'KeySysWorkspace12TakeWin'
			]],
		['Workspaces',
			[
			'WorkspaceNames'
			]],
		['GNOME/KDE',
			[
                        'AutoDetectGNOME',
                        'GNOMEAppsMenuAtToplevel',
                        'GNOMEUserMenuAtToplevel',
                        'KDEMenuAtToplevel',
                        'ShowGnomeAppsMenu',
                        'ShowGnomeUserMenu',
                        'ShowKDEMenu',
                        'GNOMEFolderIcon',
                        'KDEDataDir'
			]],
	]

############################################################################
# Classes used in the general IcePref user interface
#
# These are placed at the beginning so that they may be inherited from by
# all other classes
############################################################################


# This class defines the standard style of labels used in many other classes
# of IcePref

#
# Set up the different colours for commented and uncommented text. I could also
# have set it using
#    copy the current widget style
#    new_style = label.get_style().copy()
#    change the style attributes
#    new_style.fg[STATE_NORMAL] = label.get_colormap().alloc(65535, 0, 0)
#    fill out the new style by attaching it to the label
#    label.set_style(new_style)
# but this is neater! (Use KColorChooser to determine hex number)
rc_parse_string('''
        style "normalText" {
                fg[NORMAL] = "#437901"
        }
        widget "*.normal" style "normalText"
        style "commentedText" {
                fg[NORMAL] = "#EB120A"
        }
        widget "*.comment" style "commentedText"
''')

class Label(GtkLabel):
	def __init__(self, title):
		GtkLabel.__init__(self, title)
		self.set_line_wrap(TRUE)
		self.set_alignment(JUSTIFY_LEFT, 0)
		self.set_padding(2,2)

# This is a somewhat generic class for dialogs

class Dialog(GtkWindow):
	def __init__(self, titlebar, title):
		GtkWindow.__init__(self, title=titlebar)
		self.set_modal(TRUE)
		self.init_widgets(title)
		self.init_buttons()
		self.show()

	def init_widgets(self, title):
		vbox = GtkVBox(spacing = SP)
		vbox.set_border_width(BD)
		self.add(vbox)
		vbox.show()

		label = Label(title)
		label.set_alignment(JUSTIFY_FILL, 0)
		vbox.pack_start(label)
		label.show()

		self.bbox = GtkHButtonBox()
		vbox.pack_start(self.bbox)
		self.bbox.show()

	def init_buttons(self):
		self.ok_button = GtkButton('Ok')
		self.ok_button.grab_focus()
		self.ok_button.connect('clicked', self.button_cb, 1)
		self.bbox.pack_start(self.ok_button)
		self.ok_button.show()

	def button_cb(self, object=None, data=None):
		ret = data
		self.hide()
		self.destroy()

# This derivative of Dialog is used to confirm or cancel choices

class ConfirmDialog(Dialog):
	def init_buttons(self):
		self.ok_button = GtkButton('Ok')
		self.ok_button.connect('clicked', button_cb, 1)
		self.bbox.pack_start(self.ok_button)
		self.ok_button.show()

		self.cancel_button = GtkButton('Cancel')
		self.cancel_button.connect('clicked', button_cb, 0)
		self.bbox.pack_start(self.cancel_button)
		self.cancel_button.show()

##############################################################################
# The configuration option classes
#
# These classes are designed to implement the configuration user interface in
# generic way.  All of them (at least all of them that are directly used
# by the Application class) have the methods set_value and get_value, the
# function of which should be self evident.  To facilitate interaction with
# the text configuration file, set_value always takes a string argument and
# get_value always returns a string value.
##############################################################################

# The Entry class describes the text entries.
# title = the text of the label
# value = the intial value

class Entry(GtkVBox):
	def __init__(self, title='', value='', commented=FALSE):
		GtkVBox.__init__(self, spacing=SP)
		self.set_border_width(BD)
		self.init_widgets(title, commented)
		self.set_value(value)
		self.show()

	def init_widgets(self, title, commented=FALSE):
		label = Label(title)
		label.show()
                label.set_name ('normal')
                if commented == TRUE:
                        label.set_name ('comment')
		self.pack_start(label, FALSE, FALSE)

		self.entry = GtkEntry()
		self.entry.show()
		self.pack_start(self.entry, FALSE, FALSE)

	def set_value(self, value):
		value = value[1 : len(value) - 1]
		self.entry.set_text(value)

	def get_value(self):
		value = self.entry.get_text()
		value = '"' + value + '"'
		return value

# The Toggled class describes the check buttons (for boolean options).
# title = text of the label
# value = initial value

class Toggled(GtkHBox):
	def __init__(self, title='', value='', commented=FALSE):
		GtkHBox.__init__(self, spacing=SP)
		self.set_border_width(BD)
		self.init_widgets(title, commented)
		self.set_value(value)
		self.show()

	def init_widgets(self, title, commented=FALSE):
		self.button = GtkCheckButton()
		self.button.show()
		self.pack_start(self.button, FALSE, FALSE, 0)

		label = Label(title)
		label.show()
                label.set_name ('normal')

                if commented == TRUE:
                        label.set_name ('comment')
                self.pack_start(label, FALSE, FALSE, 0)

	def set_value(self, value):
		self.button.set_active(eval(value))

	def get_value(self):
		value = self.button.get_active()
		return str(value)

# The Range class describes the range widget.
# Currently, it includes both a GtkAdjustment
# widget and a spinbutton. This could, of
# course, be changed if it is found to be
# unsatisfactory.  title = text of the label
# min = bottom of the allowed range max = top
# of the allowed range value = initial value

class Range(GtkVBox):
	def __init__(self, title='', min=0, max=100, value=0, commented=FALSE):
		GtkVBox.__init__(self, spacing=SP)
		self.set_border_width(BD)
		self.init_widgets(title, min, max, commented)
		self.set_value(value)
		self.show()

	def init_widgets(self, title, min, max, commented=FALSE):
		hbox = GtkHBox(FALSE, SP)
		hbox.set_border_width(BD)
		hbox.show()
		self.pack_start(hbox, FALSE, FALSE, 0)
		label = Label(title)
		label.show()
                label.set_name ('normal')
                if commented == TRUE:
                        label.set_name ('comment')
		hbox.pack_start(label, FALSE, FALSE, 0)
		adj = GtkAdjustment(lower=min, upper=max, step_incr=1)
		self.spin = GtkSpinButton(adj)
		self.spin.set_digits(0)
		self.spin.show()
		hbox.pack_end(self.spin, FALSE, FALSE, 0)
		scale = GtkHScale(adj)
		scale.set_draw_value(FALSE)
		scale.show()
		self.pack_start(scale, FALSE, FALSE, 0)

	def set_value(self, value):
		self.spin.set_value(eval(value))

	def get_value(self):
		ret = self.spin.get_value_as_int()
		return str(ret)

# The keystroke may not present the best
# possible way to configure key strokes in a
# window manager, but it seems to work--for
# that and only that.

class Keystroke(GtkVBox):
	def __init__(self, title, value, commented=FALSE):
		GtkVBox.__init__(self)
		self.set_border_width(BD)
		self.init_constants()
		self.init_widgets(title, commented)
		self.set_value(value)
		self.show()

	def init_constants(self):
		self.mods=[
					['Alt', 'Alt+'],
					['Ctrl', 'Ctrl+'],
					['Shift', 'Shift+']

				]

	def init_widgets(self, title, commented=FALSE):
		label = Label(title)
		self.pack_start(label)
		label.show()
                label.set_name ('normal')
                if commented == TRUE:
                        label.set_name ('comment')
		hbox = GtkHBox()
		self.pack_start(hbox)
		hbox.show()

		self.mod_buttons = []

		for item in self.mods:
			button = GtkToggleButton(item[0])
			hbox.pack_start(button)
			self.mod_buttons.append(button)
			button.show()

		self.entry = GtkEntry()
		hbox.pack_start(self.entry)
		self.entry.show()

	def set_value(self, value):
		value = replace(value, '"', '')
		for i in range(len(self.mods)):
			if count(value, self.mods[i][1]) == 1:
				self.mod_buttons[i].set_active(TRUE)
				value = replace(value, self.mods[i][1], '')
			else:
				self.mod_buttons[i].set_active(FALSE)
				value = replace(value, self.mods[i][1], '')

		self.entry.set_text(value)

	def get_value(self):
		value = ''

		for i in range(len(self.mods)):
			if self.mod_buttons[i].get_active():
				value = value + self.mods[i][1]

		entry_text = self.entry.get_text()
		value = '"' + value + entry_text + '"'

		return value

# The ButtonEntry class is a relatively generic class for metawidgets that
# contain both a text entry and a button to call up a dialog box.  Color,
# Font, and File all inherit from this class.  Path inherits from File.
# title = label text
# value = initial value

class ButtonEntry(GtkVBox):
	def __init__(self, title='', value='', commented=FALSE):
		GtkVBox.__init__(self, FALSE, SP)
		self.set_border_width(BD)
		self.init_widgets(title, commented)
		self.set_value(value)
		self.show()

	def init_widgets(self, title, commented=FALSE):
		label = Label(title)
		label.show()
                label.set_name ('normal')
                if commented == TRUE:
                        label.set_name ('comment')
		self.pack_start(label, FALSE, FALSE, 0)

		hbox = GtkHBox(FALSE, SP)
		hbox.show()
		self.pack_start(hbox, FALSE, FALSE, 0)

		self.entry = GtkEntry()
		self.entry.show()
		hbox.pack_start(self.entry, TRUE, TRUE, 0)

		button = GtkButton('...')
		button.connect('clicked', self.select)
		button.show()
		hbox.pack_start(button, FALSE, FALSE, 0)

	def set_value(self, value):
		value = value[1 : len(value) - 1]
		self.entry.set_text(value)

	def get_value(self):
		value = '"' + self.entry.get_text() + '"'
		return value

	def cancel(self, data=None):
		self.win.hide()
		self.win.destroy()

# The Color class is used for configuring (obviously) options which require
# the rgb value for a color.  It is a derivative of the ButtonEntry class and
# therefore accepts the same options.

class Color(ButtonEntry):
	def select(self, data=None):
		value = self.entry.get_text()
		self.win = GtkColorSelectionDialog(name='Select Color')
		self.win.colorsel.set_opacity(FALSE)
		self.win.colorsel.set_update_policy(UPDATE_CONTINUOUS)
		self.win.set_position(WIN_POS_MOUSE)
		self.win.ok_button.connect('clicked', self.ok)
		self.win.cancel_button.connect('clicked', self.cancel)
		self.win.help_button.destroy()
		if value != '':
			r = atoi(value[4:6], 16) / 255.0
			g = atoi(value[7:9], 16) / 255.0
			b = atoi(value[10:12], 16) / 255.0
			self.win.colorsel.set_color((r, g, b))
		self.win.set_modal(TRUE)
		self.win.show()

	def ok(self, data=None):
		raw_values = self.win.colorsel.get_color()
		r,g,b = raw_values
		color = [r, g, b]
		for i in range(0,3):
			color[i] = hex(int(color[i] * 255.0))[2:]
			if len(color[i]) == 1:
				color[i] = '0' + color[i]

		r,g,b = color[0], color[1], color[2]

		value = 'rgb:' + r + '/' + g + '/' + b
		self.entry.set_text(value)
		self.win.hide()
		self.win.destroy()

# Font class is used (wonder of wonders) to select a font and returns an X
# font descriptor, which coincidentally is just what icewm demands.  It is
# a derivative of the ButtonEntry superclass and takes the same options.

class Font(ButtonEntry):

	def init_widgets(self, title, commented=FALSE):
		label = Label(title)
		label.show()
                label.set_name ('normal')
                if commented == TRUE:
                        label.set_name ('comment')
		self.pack_start(label, FALSE, FALSE, 0)

		self.sample = GtkText()
		self.sample.set_editable(FALSE)
		self.sample.set_usize(50,50)
		self.pack_start(self.sample)
		self.sample.show()

		hbox = GtkHBox(FALSE, SP)
		hbox.show()
		self.pack_start(hbox, FALSE, FALSE, 0)

		self.entry = GtkEntry()
		self.entry.connect('changed', self.update)
		self.entry.show()
		hbox.pack_start(self.entry, TRUE, TRUE, 0)

		button = GtkButton('...')
		button.connect('clicked', self.select)
		button.show()
		hbox.pack_start(button, FALSE, FALSE, 0)

	def set_value(self, value):
		value = value[1 : len(value) - 1]
		self.entry.set_text(value)
		self.set_sample(value)

	def set_sample(self, value):
		length = self.sample.get_length()
		if length > 0:
			self.sample.delete_text(0, length)
		# The structure catches errors which are caused by invalid
		# font specifications.
		try:
			font = load_font(value)
			self.sample.insert(fg=None, bg=None, font=font, string=SAMPLE_TEXT)
		# If the font is invalid, it should trigger this little wonder
		except RuntimeError:
			self.sample.insert(fg=None, bg=None, font=None, string=ERROR_TEXT)

	def select(self, data=None):
		self.win = GtkFontSelectionDialog('Select Font')
		self.win.ok_button.connect('clicked', self.ok)
		self.win.cancel_button.connect('clicked', self.cancel)
		value = self.entry.get_text()
		if value !='':
			self.win.fontsel.set_font_name(value)
		self.win.set_modal(TRUE)
		self.win.show()

	def ok(self, data=None):
		value = self.win.fontsel.get_font_name()
		self.win.hide()
		self.win.destroy()
		self.entry.set_text(value)
		self.set_sample(value)

	def update(self, widget, data=None):
		value = self.entry.get_text()
		self.set_sample(value)

# The File class is used for options that require a file name and path.  It is
# a derivative of the Button Entry class and takes the same options.

class File(ButtonEntry):

	def select(self, data=None):
		self.win = GtkFileSelection()
		self.win.ok_button.connect('clicked', self.ok)
		self.win.cancel_button.connect('clicked', self.cancel)
		value = self.entry.get_text()
		if value != '""':
			self.win.set_filename(value)
		self.win.set_modal(TRUE)
		self.win.show()

	def ok(self, data=None):
		value = self.win.get_filename()
		self.win.hide()
		self.win.destroy()
		self.entry.set_text(value)

# The class Path is used to configure options that require a path but no file
# name.  It is a derivative of File and accepts the same options.

class Path(File):

	def ok(self, data=None):
		value = self.win.get_filename()
		value = value[: rfind(value, '/') + 1]
		self.win.hide()
		self.win.destroy()
		self.entry.set_text(value)

# The Multi class is used to configure options that consist of multiple
# strings in comma seperated lists.  Right now, this is limited to the desktop
# names.
# title = label text
# value = initial value
# num = number of text entries to be displayed

class Multi(GtkVBox):
	def __init__(self, title, value, num, commented=FALSE):
		GtkVBox.__init__(self, spacing = SP)
		self.num = num
		self.set_border_width(BD)
		self.init_widgets(title, commented)
		self.set_value(value)
		self.show()

	def init_widgets(self, title, commented=FALSE):
		label = Label(title)
		label.show()
                label.set_name ('normal')
                if commented == TRUE:
                        label.set_name ('comment')
		self.pack_start(label)

		self.entries = []
		for i in range(0, self.num):
			entry = GtkEntry()
			entry.show()
			self.pack_start(entry)
			self.entries.append(entry)

	def divide(self, string):
		list = []
		while count(string, '"') > 0:
			f_quote = find(string, '"')
			l_quote = find(string[f_quote + 1 :], '"') + (len(string) - len(string[f_quote + 1:]))
			item = string[f_quote : l_quote + 1]
			string = string[l_quote + 1 :]
			list.append(item)
		return list

	def set_value(self, value):
		for i in range(0, self.num):
			self.entries[i].set_text('')
		values = self.divide(value)
		if len(values) > self.num: values = values[:self.num]
		for i in range(0, len(values)):
			trimmed = values[i][1 : len(values[i]) - 1]
			self.entries[i].set_text(trimmed)

	def get_value(self):
		values = []
		for entry in self.entries:
			text = entry.get_text()
			if text != '':
				values.append(text)
		value = ''
		for item in values:
			value = value + '"' + item + '"' + ','
		value = value[:len(value) - 1]
		return value

# The ThemeData class, when passed the whole path of a theme, sets its members
# to the values required by the ThemeSel class.

class ThemeData:
	def __init__(self, full_path):
		self.full_path = full_path
		self.init_vars(full_path)

	def init_vars(self, full_path):
		slash_1 = rfind(full_path, '/')
		slash_2 = rfind(full_path[:slash_1], '/')
		self.name = full_path[slash_2 + 1 : slash_1]
		self.theme_file = full_path[slash_1 + 1:]
		self.full_name = self.name + ' (' + self.theme_file + ')'
		self.path = self.name + '/' + self.theme_file

# This class creates a CList which can be used to select a theme.  It is quite
# specialized at this point.  Perhaps it could later be generalized to handle
# other options.

class ThemeSel(GtkVBox):
	def __init__(self, title='', value='', commented=FALSE):
	    GtkVBox.__init__(self)
	    self.set_border_width(BD)
	    self.set_spacing(SP)
	    self.init_theme_list()
	    self.set_value(value)
	    self.init_widgets(title, commented)
	    self.show()

	def init_theme_list(self):
	    self.theme_list = []
	    for path in THEME_PATH:
		subdir_list = glob.glob(path)
		self.extract_theme_files(subdir_list)

	def extract_theme_files(self, subdir_list):
	    for subdir in subdir_list:
			contents = glob.glob(subdir + '/*.theme')
			if contents != []:
				for file in contents:
					theme = ThemeData(file)
					self.append_theme(theme)
					# self.theme_list.append(theme)

	def append_theme(self, theme):
	    in_list = FALSE
	    for entry in self.theme_list:
		if theme.full_name == entry.full_name:
		    in_list = TRUE
	    if not in_list:
		self.theme_list.append(theme)

	def set_value(self, value):
	    self.value = value[1 : len(value) - 1]
	    if self.value == '':
		self.value = self.theme_list[0].path

	def get_value(self):
	    value = '"' + self.value + '"'
	    return value

	def init_widgets(self, title, commented=FALSE):
		label = Label(title)
		self.pack_start(label)
		label.show()
                label.set_name ('normal')
                if commented == TRUE:
                        label.set_name ('comment')
		swin = GtkScrolledWindow()
		swin.set_policy(POLICY_AUTOMATIC, POLICY_AUTOMATIC)
		swin.set_usize(150, 150)
		self.pack_start(swin)
		swin.show()

		clist = GtkCList(2, ['Theme', 'File'])
		clist.connect('select_row', self.clist_cb)
		swin.add(clist)
		clist.show()

		clist.freeze()
		row_count = 0
		for item in self.theme_list:
			row = [item.name, item.theme_file]
			clist.append(row)
			clist.set_row_data(row_count, item.path)
			if item.path == self.value:
				clist.select_row(row_count,0)
			row_count = row_count + 1
		clist.sort()
		clist.columns_autosize()
		clist.thaw()

	def clist_cb(self, widget, row, col, event):
		self.value = widget.get_row_data(row)

# The OptionMenu class is a generic class for numerically coded options with a small, fixed
# number of possible options.

class OptionMenu(GtkVBox):
	def __init__(self, title='', value='', commented=FALSE):
		GtkVBox.__init__(self)
		self.set_border_width(BD)
		self.init_widgets(title, commented)
		self.set_value(value)
		self.show()

	def init_widgets(self, title, commented=FALSE):
		label = Label(title)
		self.pack_start(label)
		label.show()
                label.set_name ('normal')
                if commented == TRUE:
                        label.set_name ('comment')
		self.option_menu = GtkOptionMenu()
		self.option_menu.set_menu(self.create_menu())
		self.pack_start(self.option_menu)
		self.option_menu.show()

	def init_options(self):
		self.options = [['Null', '0']]

	def create_menu(self):
		self.init_options()
		menu = GtkMenu()
		group = None
		self.all_items = []
		for option in self.options:
			menuitem = GtkRadioMenuItem(group, option[0])
			menuitem.connect('activate', self.menu_cb, option[1])
			group = menuitem
			menu.append(menuitem)
			self.all_items.append(menuitem)
			menuitem.show()

		return menu

	def menu_cb(self, widget, data):
		self.value = str(data)

	def set_value(self, value):
		if eval(value) > 7:
			value = str(7)
		if eval(value) < 0:
			value = str(0)
		self.value = value
		for i in range(len(self.options)):
			if value == self.options[i][1]:
				self.all_items[i].set_active(TRUE)
				self.option_menu.set_history(i)

	def get_value(self):
		return self.value

# This special class is used to configure options which use a bitmask to control
# the behavior of the three mouse buttons.

class BitMask(OptionMenu):
	def init_options(self):
		self.options = [['No mouse buttons', '0'],
                                ['First button only', '1'],
                                ['Second button only', '2'],
                                ['Third button only', '4'],
                                ['First and second buttons', '3'],
                                ['First and third buttons', '5'],
                                ['Second and third buttons', '6'],
                                ['All three buttons', '7']]

# This child of OptionMenu (MouseButton) is used to configure options which call for a particular
# mouse button by number.

class MouseButton(OptionMenu):
	def init_options(self):
		self.options = [['No mouse button', '0'],
                                ['First mouse button', '1'],
                                ['Second mouse button', '2'],
                                ['Third mouse button', '3'],
                                ['Fourth mouse button', '4'],
                                ['Fifth mouse button', '5']]

##############################################################################
# The Application class -- mother of all IcePref classes
#
# The Application class is the main class of this little utility.  It is
# confusing and I don't feel like commenting it right now.
##############################################################################

class Application(GtkWindow):

	def __init__(self, argv):
		GtkWindow.__init__(self, title='IcePref')
		self.connect('destroy', mainquit)
		self.determine_os()
		self.find_global_preferences()
		self.find_local_preferences()
		self.init_settings()
		self.get_current_settings()

		self.vbox = GtkVBox(spacing = SP)
		self.vbox.set_border_width(BD)
		self.vbox.show()
		self.add(self.vbox)
		self.init_menu()
		self.widget_dict = {}
		self.init_notebook()
		self.init_buttons()
		self.show()

	# The determine_os() method will tell what operating system is running
	# so that calls to the shell, for example, may be issued correctly.
	# This is not currently used very much, and it is implemented in an extremely
	# ugly fashion.  It messes things up for users of recent versions of Redhat
        # and Mandrake.  Also, it will, as it stands, assume that any distribution of
        # linux is Debian (not a terrible thing, but . . .)

	def determine_os(self):
	    os_list = { 'freebsd'  : ['FreeBSD',  'BSD'],
	                'pc-linux-gnu': ['Debian',   'Linux'],
			'mandrake' : ['Mandrake', 'Linux'],
			'redhat'   : ['RedHat',   'Linux'],
			'solaris'  : ['Solaris',  'Unix'] }
	    self.os = 'Linux'
	    self.distribution = 'Generic'
	    for os_type in os_list.keys():
		if find( MACHTYPE, os_type ) != -1:
		    self.distribution = os_list[os_type][0]
		    self.os = os_list[os_type][1]
	    if DEBUG:
		print 'OS type is %s' % self.os
		print 'Distributions is %s' % self.distribution

	# find_global_preferences will replace part of check for dir.
	# The rest of the responsibilities of that function will be
	# assumed by a new function called find_local_preferences.

	def find_global_preferences(self):

	    # make list of possibilities for various operating systems
	    possibilities = [ '/usr/local/lib/X11/icewm/',
	                      '/usr/X11R6/lib/X11/icewm/',
			      '/etc/X11/icewm/',
			      '/usr/X11R6/share/icewm/',
			      '/usr/lib/X11/icewm/' ]

	    # get any additional possibilites from the PATH env variable.
	    path_dirs = re.split(':', PATH)
	    for directory in path_dirs:
		directory = directory + '/lib/X11/icewm/'
		possibilities.append( directory )

	    if DEBUG:
		print 'Directories to be searched for configuration files:'
		for directory in possibilities:
		    print directory

	    # find the location of the icewm exectuable.  Add an addition
	    # to _possibilities_ based upon this path.

	    # This probably isn't that useful anymore.

	    exec_path = commands.getoutput('whereis icewm')
	    exec_path = split(exec_path) # split output of whereis into tokens at whitespace
	    exec_path = exec_path[1] # get second token (should be executable)

	    if DEBUG:
		print 'The icewm execuatable is located at %s' % exec_path

	    if find(exec_path, '/bin/icewm') != -1:
		path = exec_path[:-10] + '/X11/lib/icewm/'
		possibilities.append( path )
	    else:
		if DEBUG:
		    print 'The path %s is somehow odd . . . can\'t seem to make it out . . .' % exec_path
		pass

	    # search through _possibilities_ until a valid file is found.
	    # set self.global_preferences to this value.
	    # if none is found, set self.global_preferences to "".

	    self.global_preferences = ''

	    for location in possibilities:
		location = location + 'preferences'
		if os.path.isfile( location ):
		    self.global_preferences = location
		    if DEBUG:
			print 'The global preferences file is located at %s' % location

	# find_local_preferences is to replace the byzantine check_for_dir
	# function which makes little sense and behaves badly.

	def find_local_preferences(self):
	    # check to see if the directory ~/.icewm exists.  If not, create
	    # it.
	    if not os.path.isdir(HOME + '/.icewm'):
		os.mkdir(HOME + '/.icewm')
		if DEBUG:
		    print 'No ~/.icewm directory.  Creating it.'

	    # check to see if the file ~/.icewm/preferences exists.  If it
	    # does, exit.
	    if os.path.isfile(CONFIG_FILE):
		if DEBUG:
		    print 'Local preferences file exists.'

	    # if not, and if the self.global_preferences contains a path,
	    # copy the file at that path to ~/.icewm.
	    elif self.global_preferences != '':
		if DEBUG:
		    print 'Copying global preferences file to ~/.icewm'
		preferences = ''
		try:
		    f = open( self.global_preferences, 'r')
		    preferences = f.read()
		    f.close()
		except IOError:
		    print 'Cannot read global preferences file'

		if preferences != '':
		    try:
			f = open( CONFIG_FILE, 'w' )
			f.write( preferences )
			f.close()
		    except IOError:
			print 'Cannot write local preferences file'

	# Makes a copy of DEFAULTS in self.settings.

	def init_settings(self):
		self.settings = {}
		for key in DEFAULTS.keys():
			self.settings[key] = DEFAULTS[key][:]

	# Goes through each of the configuration options and forces the widgets
	# to conform to the data in self.settings

	def update_widgets(self, data=None):
		for widget in DEFAULTS.keys():
			self.widget_dict[widget].set_value(self.settings[widget][VALUE])

	# Takes a line from the configuration file and returns the name of the
	# configuration option (name) and its value (value) as a tuple. This whole
	# thing could be dramatically simplified by the use of regex stuff (of which
	# I was ignorant at the time I originally wrote it.  Also, it is possible that
	# options which are commented out should still be read as the new default
	# preferences file for IceWM has _all_ options commented out.

	def analyze(self, string):
            # This is the only change we need to do if we're removing comment tags in
            # front of options. The defaulting of the COMMENTED tag below solves it
            # for everything else.
            if removecomment == FALSE:
                    # Find #, space, or a-zA-Z0-9_ then equals
                    # then quote stuff but not # or \n then quote
                    whole_options = re.findall('[# \w]*="[^#^\n]*"|[# \w]*=[0-9]+', string)
            else:
                    whole_options = re.findall('[\w]*="[^#^\n]*"|[\w]*=[0-9]+', string)
            all_options = {}

	    for option in whole_options:
                comment = FALSE
                if option.startswith('#'):
                        comment = TRUE
                        # Now remove the comment.
                        option = (re.split ('^#[ ]*', option))[1]
		option = re.split('=', option)
                option_name = option[0]
		option_value = option[1]
		if DEBUG:
		    print 'Set options with %s & %s ' % (option_name, option_value)
		all_options[option_name] = option_value, comment

	    return all_options

	# This is a replacement for the old get current settings.  It is designed to use the self.analyze()
	# method rather than the primitive and clumsy self.trim() method.

	def get_current_settings(self, data=None):

	    # try to open preferences file.  Read whole file into variable and close.

	    try:
		f = open(CONFIG_FILE, 'r')
		contents = f.read()
		f.close()
	    except IOError:
		win = Dialog('Warning', 'Unable to read local preferences file!')
		contents = ''
	    # pass contents of preferences file to self.anayze() and store the result
	    # in current.

	    current = self.analyze( contents )

	    # for each of the options in the dictionary current,
	    # check for a matching option in self.settings.  If there
	    # is no matching option, report it and record it.  If there is a matching option,
	    # set that option in self.settings to the value from current.

	    for option in current.keys():
		if self.settings.has_key( option ):
		    self.settings[option][VALUE] = current[option][0]
                    self.settings[option][COMMENTED] = current[option][1]
                else:
		    print '%s=%s does not seem to be a valid option' % (option, current[option])

	    if DEBUG:
		for option in self.settings.keys():
		    if not current.has_key(option):
			print 'preferences file contains no setting for %s' % option

	# writes the contents of self.settings to the preferences file

	def save_current_settings(self, *data):
		# this stuff is to make a backup file
		# win = Dialog('Attention', "Backing up 'preferences' file . . .")
		try:
			f = open(CONFIG_FILE, 'r')
			old_pref = f.read()
			f.close()

			backup = CONFIG_FILE + '~'
			f = open(backup, 'w')
			f.write(old_pref)
			f.close()
		except:
			win = Dialog('Attention', 'Oh!  I guess you had no preferences file to backup!')
		# this stuff saves the actual info
		try:
			f = open(CONFIG_FILE, 'w')
			f.write('# This configuration file automatically generated by %s--your friendly pythonated config util.\n\n' % VERSION)
                        keys = DEFAULTS.keys()
                        keys.sort()
			for name in keys:
				string =''
				# this adds some descriptors depending upon the type of
				# option
				if self.settings[name][TYPE] == TOGGLE:
					string =' # 0 / 1'
				elif self.settings[name][TYPE] == RANGE:
					min = self.settings[name][MIN]
					max = self.settings[name][MAX]
					string = ' # ' + str(min) + '-' + str(max)
				# this sets up the comment descriptor, which is the same
				# as the label text.
				comment = '# ' + self.settings[name][TITLE] + '\n'
				if self.widget_dict.has_key(name):
                                        if self.settings[name][COMMENTED] == TRUE:
                                                line = '# ' + name + '=' + self.widget_dict[name].get_value() + string + '\n'
					else:
                                                line = name + '=' + self.widget_dict[name].get_value() + string + '\n'
				else:
					print 'Warning!  No widget for option %s' % name
				f.write(comment)
				f.write(line)
				f.write('\n')
                        f.close()
                except IOError:
                        win = Dialog('Warning', "Argh! I can't write to your silly 'preferences' file.")

	def restart(self, widget=None, data=None):

		# restart icewm.  Note that this is experimental and I have no idea
		# if it will work on all systems.  It definitely doesn't work on FreeBSD--
		# the signal HUP doesn't have the desired effect upon IceWM--but it may
		# work on other non Linux systems.  Under Debian, this function requires
		# the installation of the psmisc package.

		os.system('killall -HUP -q icewm')
		os.system('killall -HUP -q icewm-gnome')

	# this is the callback for the OK button

	def ok(self, data=None):
		# save and exit
		print 'OK'
		self.save_current_settings()
		mainquit()

	# callback for the `about' menu option

	def about_cb(self, *data):
		win = Dialog('Help', 'This is IcePref %s, a pythonated configuration utility for use with IceWM %s.\nWritten by David Mortensen maintained by Nick Cross. It may be found at http://www.goots.org/ice\nOptions appear in red if they are commented out in the preferences file - run with -removecomment to remove the comment tag.' % (VERSION, ICE_VERSION))

	# reloads the preferences file and sets all of the config widgets to
	# corresponding values.

	def set_file_settings(self, *data):
		self.get_current_settings()
		self.update_widgets()

	# returns self.settings to the default values--doesn't work quite right

	def set_default_settings(self, *data):
		self.init_settings()
		self.update_widgets()

	# creates the menubar

	def init_menu(self):
		menu_items = [
				['/_File', None, None, 0, '<Branch>'],
				['/File/tearoff1', None, None, 0, '<Tearoff>'],
				['/File/_Reload', '<control>O', self.set_file_settings, 0, ''],
				['/File/_Defaults', '<control>D', self.set_default_settings, 0, ''],
				['/File/_Save', '<control>S', self.save_current_settings, 0, ''],
				['/File/sep1', None, None, 0, '<Separator>'],
				['/File/_Restart IceWM', '<control>R', self.restart, 0, ''],
				['/File/sep2', None, None, 0, '<Separator>'],
				['/File/_Close', '<control>Q', mainquit, 0, ''],
				['/_Help', None, None, 0, '<LastBranch>'],
				['/Help/_About', None, self.about_cb, 0, '']
					]

		ag = GtkAccelGroup()
		itemf = GtkItemFactory(GtkMenuBar, '<main>', ag)
		self.add_accel_group(ag)
		itemf.create_items(menu_items)
		self.menubar = itemf.get_widget('<main>')
		self.vbox.pack_start(self.menubar, expand=FALSE)
		self.menubar.show()

	# creates the notebook and its friends.

	def init_notebook(self):
		notebook = GtkNotebook()
		notebook.set_tab_pos(POS_LEFT)
		notebook.set_scrollable(TRUE)
		notebook.show()
		self.vbox.pack_start(notebook)
		sep = GtkHSeparator()
		sep.show()
		self.vbox.pack_start(sep, expand = FALSE)
		# sets up each of the tabs (one for each categorie of
		# configuration options
		for tab in TABS:
			label = GtkLabel(tab[0])
			widgets = tab[1]
			# creates a scrolled window within the notepad page
			# for each tab.
			scroll = GtkScrolledWindow()
			scroll.set_usize(750, 700)
			scroll.set_policy(POLICY_AUTOMATIC, POLICY_AUTOMATIC)
			scroll.show()
			notebook.append_page(scroll, label)

			vbox = GtkVBox(spacing=SP)
			vbox.show()

			# Determines whether to use one column or two.
			# If there are more than 4 widgets, two columns
			# are used.

			num_widgets = len( widgets )

			if num_widgets > 4:
				rows = ( int( num_widgets / 2 ) + 1)
				cols = 2
			else:
				rows = num_widgets
				cols = 1
			if rows < 2: rows = 2

			# Creates a table for the widgets

			table = GtkTable(	rows = rows,
							cols = cols,
							homogeneous=FALSE)
			table.show()
			vbox.pack_start(table, FALSE, FALSE)
			scroll.add_with_viewport(vbox)

			# Add the widgets to the table.

			x, y = 0, 0 # x and y counters for the table
			for item in widgets:
                            widget = self.widget_chooser(item)
                            table.attach(widget, x, x+1, y, y+1)
                            self.widget_dict[item] = widget
                            # Pack by rows
                            if cols > 1 and x == 0:
                                x = x + 1
                            else:
                                x = 0
                                y = y + 1

	# accepts a configuration option as its argument and returns the
	# appropriate widget.  If a new type of widget is added, it will have
	# to be added here as well.

	def widget_chooser(self, item):
		type = self.settings[item][TYPE]
		if type == TOGGLE:
			widget = Toggled(	self.settings[item][TITLE],
						self.settings[item][VALUE],
                                                self.settings[item][COMMENTED])
		elif type == RANGE:
			widget = Range(		self.settings[item][TITLE],
						self.settings[item][MIN],
						self.settings[item][MAX],
						self.settings[item][VALUE],
                                                self.settings[item][COMMENTED])
		elif type == FILE:
			widget = File(		self.settings[item][TITLE],
						self.settings[item][VALUE],
                                                self.settings[item][COMMENTED])
		elif type == PATH:
			widget = Path(		self.settings[item][TITLE],
						self.settings[item][VALUE],
                                                self.settings[item][COMMENTED])
		elif type == COLOR:
			widget = Color(		self.settings[item][TITLE],
						self.settings[item][VALUE],
                                                self.settings[item][COMMENTED])
		elif type == FONT:
			widget = Font(		self.settings[item][TITLE],
						self.settings[item][VALUE],
                                                self.settings[item][COMMENTED])
		elif type == ENTRY:
			widget = Entry(		self.settings[item][TITLE],
						self.settings[item][VALUE],
                                                self.settings[item][COMMENTED])
		elif type == KEYSTROKE:
			widget = Keystroke(	self.settings[item][TITLE],
						self.settings[item][VALUE],
                                                self.settings[item][COMMENTED])
		elif type == MULTI:
			widget = Multi(		self.settings[item][TITLE],
						self.settings[item][VALUE],
						self.settings[item][NUM],
                                                self.settings[item][COMMENTED])
		elif type == THEME:
			widget = ThemeSel(	self.settings[item][TITLE],
						self.settings[item][VALUE],
                                                self.settings[item][COMMENTED])

		elif type == BITMASK:
			widget = BitMask(	self.settings[item][TITLE],
						self.settings[item][VALUE],
                                                self.settings[item][COMMENTED])

		elif type == MOUSEBUTTON:
			widget = MouseButton( 	self.settings[item][TITLE],
						self.settings[item][VALUE],
                                                self.settings[item][COMMENTED])

		return widget

	# creates the buttons at the bottom of the window

	def init_buttons(self):

		buttons = [
					['Save', self.save_current_settings],
					['Defaults', self.set_default_settings],
					['Reload', self.set_file_settings],
					['Restart', self.restart],
					['Close', mainquit]
				]

		bbox = GtkHButtonBox()
		bbox.set_layout(BUTTONBOX_SPREAD)
		bbox.show()
		self.vbox.pack_start(bbox, FALSE, FALSE, 0)
		for item in buttons:
			button = GtkButton(item[0])
			button.connect('clicked', item[1])
			button.show()

			# Disable the Restart button in the OS is BSD or the user is root
			if item[0] == 'Restart' and ( self.os == 'BSD' or USER == 'root'):
			    button.set_sensitive(FALSE)

			bbox.pack_start(button, TRUE, FALSE, 0)

# makes the whole show run


if len(sys.argv) > 1:
        if sys.argv[1] == '-removecomment':
                removecomment = TRUE
        elif sys.argv[1] == '-h':
                print 'Usage %s [-removecomment (to remove comment tags from options)]' % sys.argv[0]
                sys.exit(0)
        else:
                print 'Usage %s [-removecomment (to remove comment tags from options)]' % sys.argv[0]
                sys.exit(0)
else:
        removecomment = FALSE
app = Application(sys.argv)
mainloop()
