#!/usr/bin/env python

##############################################################################
#                                IcePref 1.0
#
# 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
# 0.9.54. 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://members.xoom.com/SaintChoj/icepref.html.  Please report all bugs
# to Dave at SLQTN@cc.usu.edu.  Please include IcePref in the subject line.
#
# Copyright 1999, David Mortensen
#
# 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.1"
ICE_VERSION = "0.9.54"

DEBUG = FALSE # 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

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 three
# 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'],
		'RaiseOnFocus': [TOGGLE, '1', 'Raise windows when focused'],
		'FocusOnClickClient': [TOGGLE, '1', 'Focus window when client area clicked'],
		'RaiseOnClickClient': [TOGGLE, '1', 'Raise window when client area clicked'],
		'RaiseOnClickTitleBar': [TOGGLE, '1', 'Raise window when title bar is clicked'],
		'RaiseOnClickButton': [TOGGLE, '1', 'Raise when frame button is clicked'],
		'RaiseOnClickFrame': [TOGGLE, '1', 'Raise when frame border is clicked'],
		'PassFirstClickToClient': [TOGGLE, '1', 'Pass focusing click on client area to client'],
		'FocusOnMap': [TOGGLE, '1', 'Focus normal window when initially mapped'],
		'FocusOnMapTransient': [TOGGLE, '1', 'Focus dialog window when initally mapped'],
		'FocusOnMapTransientActive': [TOGGLE, '1', 'Focus dialog window when initially mapped only if parent frame focused'],
		'PointerColormap': [TOGGLE, '1', 'Colormap follows pointer'],
		'LimitSize': [TOGGLE, '1', 'Limit initial size of windows to screen'],
		'LimitPosition': [TOGGLE, '1', 'Limit initial position of windows to screen'],
		'SizeMaximized': [TOGGLE, '0', 'Maximized windows can be resized'],
		'ShowMoveSizeStatus': [TOGGLE, '1', 'Show position status window during move/resize'],
		'MinimizeToDesktop': [TOGGLE, '0', 'Display mini-icons on desktop for minimized windows'],
		'StrongPointerFocus': [TOGGLE, '0', 'Always maintain focus under mouse window (makes some keyboard support non-functional)'],
		'OpaqueMove': [TOGGLE, '1', 'Opaque window move'],
		'OpaqueResize': [TOGGLE, '1', 'Opaque window resize'],
		'ManualPlacement': [TOGGLE, '0', 'Windows initially placed manually by user'],
		'SmartPlacement': [TOGGLE, '1', 'Smart window placement (minimize overlap)'],
		'CenterTransientsOnOwner': [TOGGLE, '1', 'Center dialogs on owner window'],
		'MenuMouseTracking': [TOGGLE, '0', 'Menus track mouse even with no mouse buttons held'],
		'AutoRaise': [TOGGLE, '0', 'Auto raise windows after delay'],
		'DelayPointerFocus': [TOGGLE, '0', 'Delay pointer focusing when mouse moves'],
		'Win95Keys': [TOGGLE, '0', 'Support win95 keyboard keys'],
		'ModMetaIsCtrlAlt': [TOGGLE, '1', 'Treat Penguin/Meta/Win modifer as Ctrl+Alt'],
		'UseMouseWheel': [TOGGLE, '0', 'Support mouse wheel'],
		'ShowPopupsAbovePointer': [TOGGLE, '1', 'Show popup menus above mouse pointer'],
		'ReplayMenuCancelClick': [TOGGLE, '0', 'Send the clicks outside menus to target window'],
		'QuickSwitch': [TOGGLE, '1', 'Alt+Tab window switching'],
		'QuickSwitchToMinimized': [TOGGLE, '1', 'Alt+Tab to minimized windows'],
		'QuickSwitchToHidden': [TOGGLE, '0', 'Alt-Tab to hidden windows'],
		'QuickSwitchToAllWorkspaces': [TOGGLE, '0', 'Alt+Tab to windows on other workspaces'],
		'GrabRootWindow': [TOGGLE, '1', 'Manage root window'],
		'SnapMove': [TOGGLE, '1', 'Snap to nearest screen edge/window when moving windows'],
		'EdgeSwitch': [TOGGLE, '0', 'Workspace switches by moving mouse to left/right screen edge'],
		'DesktopBackgroundCenter': [TOGGLE, '0', 'Display desktop background centered and not tiled'],
		'AutoReloadMenus':[TOGGLE, '1', 'Reload menu files automatically'],
		'ShowMenuButtonIcon':[TOGGLE, '1', 'Show application icon over menu button'],
		'AutoDetectGNOME': [TOGGLE, '1', 'Automatically disable some functions when running under GNOME'],
		'ShowTaskBar': [TOGGLE, '1', 'Show task bar'],
		'TaskBarAtTop': [TOGGLE, '0', 'Task bar at top of the screen'],
		'TaskBarAutoHide': [TOGGLE, '0', 'Auto hide task bar after delay'],
		'TaskBarShowClock': [TOGGLE, '1', 'Show clock on task bar'],
		'TaskBarShowAPMStatus': [TOGGLE, '0', 'Show automatic power management (APM) status on task bar'],
		'TaskBarClockLeds': [TOGGLE, '1', 'Task bar clock uses nice pixmapped LCD display'],
		'TaskBarShowMailboxStatus': [TOGGLE, '1', 'Show mailbox status on the task bar'],
		'TaskBarMailboxStatusBeepOnNewMail': [TOGGLE, '0', 'Beep when new mail arrives'],
		'TaskBarMailboxStatusCountMessages': [TOGGLE, '0', 'Count messages in mailbox'],
		'TaskBarShowWorkspaces': [TOGGLE, '1', 'Show workspace switching buttons on task bar'],
		'TaskBarShowWindows':[TOGGLE, '1', 'Show windows on the taskbar'],
		'TaskBarShowAllWindows': [TOGGLE, '0', 'Show windows from all workspaces on task bar'],
		'TaskBarShowStartMenu': [TOGGLE, '1', 'Show "Start" menu on task bar'],
		'TaskBarShowWindowListMenu': [TOGGLE, '1', 'Show "window list" menu on task bar'],
		'TaskBarShowCPUStatus': [TOGGLE, '1', 'Show CPU status on task bar'],
		'TaskBarShowNetStatus': [TOGGLE, '1', 'Show network status on task bar'],
		'TaskBarDoubleHeight': [TOGGLE, '0', 'Use double height task bar'],
		'WarpPointer': [TOGGLE, '0', 'Move mouse when doing focusing in pointer focus mode'],
		'ClientWindowMouseActions': [TOGGLE, '0', 'Allow mouse actions on client windows (buggy with some programs)'],
		'TitleBarCentered': [TOGGLE, '0', 'Draw window title centered'],
		'ShowThemesMenu': [TOGGLE, '1', 'Show the submenu for selecting themes'],
                'MultiByte': [TOGGLE, '0', 'Multibyte internationalization support'],
		'ConfirmLogout': [TOGGLE, '1', 'Ask for confirmation on logout'],
		'BorderSizeX': [RANGE, '6', 'Horizontal window border', 0, 128],
		'BorderSizeY': [RANGE, '6', 'Veritical window border', 0, 128],
		'DlgBorderSizeX': [RANGE, '2', 'Horizontal dialog window border', 0, 128],
		'DlgBorderSizeY': [RANGE, '2', 'Vertical dialog window border', 0, 128],
		'TitleBarHeight': [RANGE, '20', 'Title bar height', 0, 128],
		'CornerSizeX': [RANGE, '24', 'Resize corner width', 0, 64],
		'CornerSizeY': [RANGE, '24', 'Resize corner height', 0, 64],
		'ClickMotionDistance': [RANGE, '4', 'Pointer motion distance before click gets interpreted as drag', 0, 32],
		'ClickMotionDelay': [RANGE, '200', 'Delay before click gets interpreted as drag', 0, 2000],
		'MultiClickTime': [RANGE, '400', 'Multiple click time', 0, 5000],
		'MenuActivateDelay': [RANGE, '10', 'Delay before activating menu items', 0, 5000],
		'SubmenuMenuActivateDelay': [RANGE, '300', 'Delay before activating menu submenus', 0, 5000],
		'ToolTipDelay': [RANGE, '1000', 'Delay before tooltip window is displayed', 0, 5000],
                'ToolTipTime': [RANGE, '1000', 'Time before tooltip is hidden', 0, 5000],
		'AutoHideDelay': [RANGE, '300', 'Delay before task bar is automatically hidden', 0, 5000],
		'AutoRaiseDelay': [RANGE, '400', 'Delay before windows are auto raised', 0, 5000],
		'EdgeResistance': [RANGE, '32', 'Resistance in pixels when trying to move windows off the screen', 0, 10000],
		'PointerFocusDelay': [RANGE, '200', 'Delay for pointer focus switching', 0, 1000],
		'SnapDistance': [RANGE, '8', 'Distance in pixels before windows snap together', 0, 128],
		'EdgeSwitchDelay': [RANGE, '600', 'Screen edge workspace switching delay', 0, 5000],
		'ScrollBarStartDelay': [RANGE, '500', 'Initial scrollbar autoscroll delay', 0, 5000],
		'ScrollBarDelay': [RANGE, '300', 'Scroll bar delay', 0, 5000],
		'AutoScrollStartDelay': [RANGE, '1000', 'Autoscroll start delay', 0, 5000],
		'AutoScrollDelay': [RANGE, '60', 'Auto scroll delay', 0, 5000],
		'UseRootButtons': [BITMASK, '0', 'Bitmask of root window button click to use in window manager', 0, 255],
		'ButtonRaiseMask': [BITMASK, '1', 'Bitmask of buttons that raise the window when pressed', 0, 255],
		'DesktopWinMenuButton': [MOUSEBUTTON, '1', 'Mouse-button clicked on desktop to show window list menu', 0, 5],
		'DesktopWinListButton': [MOUSEBUTTON, '2', 'Mouse-button clicked on desktop to show window list', 0, 5],
		'DesktopMenuButton': [MOUSEBUTTON, '3', 'Mouse-button clicked on desktop to show menu', 0, 5],
		'TitleBarMaximizeButton': [MOUSEBUTTON, '1', 'Mouse-button clicked on titlebar to maximize window', 0, 8],
		'TitleBarRollupButton': [MOUSEBUTTON, '2', 'Mouse-button clicked on titlebar to roll up window', 0, 8],
		'MailCheckDelay': [RANGE, '30', 'Delay between new-mail checks in seconds', 0, 3600],
		'TaskBarCPUSamples': [RANGE, '20', 'Width of CPU Monitor', 2, 1000,],
		'TitleButtonsLeft': [ENTRY, '"s"', 'Titlebar buttons from left to right (x=close, m=max, i=min, h=hide, r=rollup, s=sysmenu)'],
		'TitleButtonsRight': [ENTRY, '"xmi"', 'Titlebar buttons from right to left (x=close, m=max, i=min, h=hide, r=rollup, s=sysmenu)'],
		'TitleButtonsSupported' : [ENTRY, '"xmis"', 'Titlebar buttons supported by theme (x, m, i, r, h, s, d)'],
		'IconPath': [PATH, '""', 'Icon search path (colon separated)'],
		'MailBoxPath': [FILE, '""', 'Mailbox path ($MAIL is used if no value is specified)'],
		'MailCommand': [FILE, '""', 'Command to run on mailbox'],
		'NewMailCommand': [FILE, '""', 'Command to run when new mail arrives'],
		'LockCommand': [FILE, '"xlock"', 'Command to lock display or show screensaver'],
		'ClockCommand': [FILE, '"xclock"', 'Command to run on clock'],
		'RunCommand': [FILE, '""', 'Command to select and run a program'],
		'OpenCommand': [FILE, '""', 'Open command'],
		'TerminalCommand': [FILE, '"xterm"', 'Terminal emulator (must accept -e option)'],
		'LogoutCommand': [FILE, '""', 'Command to start logout'],
		'LogoutCancelCommand': [FILE, '""', 'Command to cancel logout'],
		'ShutdownCommand' : [FILE, '"shutdown -h now"', 'Command to shut down the system'],
		'RebootCommand' : [FILE, '"shutdown -r now"', 'Command to reboot the system'],
		'CPUStatusCommand' : [FILE, '""', 'Command to run when CPU status monitor is clicked'],
		'NetStatusCommand' : [FILE, '""', 'Command to run when net status monitor is clicked'],
		'AddressBarCommand' : [FILE, '""', 'Command to run for address bar entries'],
		'NetworkStatusDevice': [ENTRY, '"ppp0"', 'Network device for which to show status'],
		'TimeFormat': [ENTRY, '"%H:%M:%S"', 'Clock time format (strftime format string)'],
		'DateFormat': [ENTRY, '"%B %A %Y/%m/%d %H:%M:%S %Z"', 'Clock date format for tooltip (strftime format string)'],
		'Theme': [THEME, '"nice/default.theme"', 'Theme (theme_directory/default.theme)'],
		'ThemeAuthor': [ENTRY, '""', 'Theme author'],
		'ThemeDescription': [ENTRY, '""', 'Theme description'],
		'TitleFontName': [FONT, '"-b&h-lucida-bold-r-*-*-*-120-*-*-*-*-*-*"', 'Title bar font'],
		'MenuFontName': [FONT, '"-b&h-lucida-bold-r-*-*-*-120-*-*-*-*-*-*"', 'Menu font'],
		'StatusFontName': [FONT, '"-b&h-lucidatypewriter-bold-r-*-*-*-120-*-*-*-*-*-*"', 'Status font'],
		'QuickSwitchFontName': [FONT, '"-b&h-lucidatypewriter-bold-r-*-*-*-120-*-*-*-*-*-*"', 'Quick switch font'],
		'NormalButtonFontName': [FONT, '"-b&h-lucida-medium-r-*-*-*-120-*-*-*-*-*-*"', 'Normal button font'],
		'ActiveButtonFontName': [FONT, '"-b&h-lucida-bold-r-*-*-*-120-*-*-*-*-*-*"', 'Active button font'],
		'NormalTaskBarFontName': [FONT, '"-b&h-lucida-medium-r-*-*-*-120-*-*-*-*-*-*"', 'Normal taskbar font'],
		'ActiveTaskBarFontName': [FONT, '"-b&h-lucida-bold-r-*-*-*-120-*-*-*-*-*-*"', 'Active taskbar font'],
		'MinimizedWindowFontName': [FONT, '"-b&h-lucida-medium-r-*-*-*-120-*-*-*-*-*-*"', 'Minimized window font'],
		'ListBoxFontName': [FONT, '"-b&h-lucida-medium-r-*-*-*-120-*-*-*-*-*-*"', 'List box font'],
		'ToolTipFontName': [FONT, '"-b&h-lucida-medium-r-*-*-*-120-*-*-*-*-*-*"', 'Tooltip font'],
		'ClockFontName': [FONT, '"-b&h-lucidatypewriter-medium-r-*-*-*-140-*-*-*-*-*-*"', 'Clock font'],
		'ApmFontName': [FONT, '"-adobe-courier-medium-r-*-*-*-140-*-*-*-*-*-*"', 'APM font'],
		'LabelFontName': [FONT, '"-b&h-lucida-medium-r-*-*-*-140-*-*-*-*-*-*"', 'Label font'],
		'ColorDialog': [COLOR, '"rgb:C0/C0/C0"', 'Dialog color'],
		'ColorActiveBorder': [COLOR, '"rgb:C0/C0/C0"', 'Active border color'],
		'ColorNormalBorder': [COLOR,'"rgb:C0/C0/C0"', 'Normal border color'],
		'ColorNormalTitleButton': [COLOR, '"rgb:C0/C0/C0"', 'Normal title button color'],
		'ColorNormalTitleButtonText': [COLOR, '"rgb:00/00/00"', 'Normal title button text color'],
		'ColorNormalButton': [COLOR, '"rgb:C0/C0/C0"', 'Normal button color'],
		'ColorNormalButtonText': [COLOR, '"rgb:00/00/00"', 'Normal button text color'],
		'ColorActiveButton': [COLOR, '"rgb:E0/E0/E0"', 'Active button color'],
		'ColorActiveButtonText': [COLOR, '"rgb:00/00/00"', 'Active button text color'],
		'ColorActiveTitleBar': [COLOR, '"rgb:00/00/A0"', 'Active title bar color'],
		'ColorNormalTitleBar': [COLOR, '"rgb:80/80/80"', 'Normal title bar color'],
		'ColorActiveTitleBarText': [COLOR, '"rgb:FF/FF/FF"', 'Active title bar text color'],
		'ColorNormalTitleBarText': [COLOR, '"rgb:00/00/00"', 'Normal title bar text color'],
		'ColorNormalMinimizedWindow': [COLOR, '"rgb:C0/C0/C0"', 'Normal minimized window color'],
		'ColorNormalMinimizedWindowText': [COLOR, '"rgb:00/00/00"', 'Normal minimized winodw text color'],
		'ColorActiveMinimizedWindow': [COLOR, '"rgb:E0/E0/E0"', 'Active minimized window color'],
		'ColorActiveMinimizedWindowText': [COLOR, '"rgb:00/00/00"', 'Active minimized window text color'],
		'ColorNormalMenu': [COLOR, '"rgb:C0/C0/C0"', 'Normal menu color'],
		'ColorActiveMenuItem': [COLOR, '"rgb:A0/A0/A0"', 'Active menu item color'],
		'ColorActiveMenuItemText': [COLOR, '"rgb:00/00/00"', 'Active menu item text color'],
		'ColorNormalMenuItemText': [COLOR, '"rgb:00/00/00"', 'Normal menu item text color'],
		'ColorDisabledMenuItemText': [COLOR, '"rgb:80/80/80"', 'Disabled menu item text color'],
		'ColorMoveSizeStatus': [COLOR, '"rgb:C0/C0/C0"', 'Move/size status color'],
		'ColorMoveSizeStatusText': [COLOR, '"rgb:00/00/00"', 'Move/size status text color'],
		'ColorQuickSwitch': [COLOR, '"rgb:C0/C0/C0"', 'Quick switch color'],
		'ColorQuickSwitchText': [COLOR, '"rgb:00/00/00"', 'Quick switch text color'],
		'ColorDefaultTaskBar': [COLOR, '"rgb:C0/C0/C0"', 'Default taskbar color'],
		'ColorNormalTaskBarApp': [COLOR, '"rgb:C0/C0/C0"', 'Normal taskbar color'],
		'ColorNormalTaskBarAppText': [COLOR, '"rgb:00/00/00"', 'Normal taskbar app text color'],
		'ColorActiveTaskBarApp': [COLOR, '"rgb:E0/E0/E0"', 'Active taskbar app color'],
		'ColorActiveTaskBarAppText': [COLOR, '"rgb:00/00/00"', 'Active taskbar app text color'],
		'ColorMinimizedTaskBarApp': [COLOR, '"rgb:A0/A0/A0"', 'Minimized taskbar app color'],
		'ColorMinimizedTaskBarAppText': [COLOR, '"rgb:00/00/00"', 'Minimized taskbar app text'],
		'ColorInvisibleTaskBarApp': [COLOR, '"rgb:80/80/80"', 'Invisible taskbar app color'],
		'ColorInvisibleTaskBarAppText': [COLOR, '"rgb:00/00/00"', 'Invisible taskbar app text'],
		'ColorScrollBar': [COLOR, '"rgb:A0/A0/A0"', 'Scroll bar color'],
		'ColorScrollBarArrow': [COLOR, '"rgb:C0/C0/C0"', 'Scroll bar arrow color'],
		'ColorScrollBarSlider': [COLOR, '"rgb:C0/C0/C0"', 'Scroll bar slider color'],
		'ColorListBox': [COLOR, '"rgb:C0/C0/C0"', 'List box color'],
		'ColorListBoxText': [COLOR, '"rgb:00/00/00"', 'List box text color'],
		'ColorListBoxSelection': [COLOR, '"rgb:80/80/80"', 'List box selection color'],
		'ColorListBoxSelectionText': [COLOR, '"rgb:00/00/00"', 'List box selection text color'],
		'ColorToolTip': [COLOR, '"rgb:E0/E0/00"', 'Tooltip color'],
		'ColorToolTipText': [COLOR, '"rgb:00/00/00"', 'Tooltip text color'],
		'ColorClock': [COLOR, '"rgb:00/00/00"', 'Clock color'],
		'ColorClockText': [COLOR, '"rgb:00/FF/00"', 'Clock text color'],
		'ColorApm': [COLOR, '"rgb:00/00/00"', 'APM color'],
		'ColorApmText': [COLOR, '"rgb:00/FF/00"', 'APM text color'],
		'ColorLabel': [COLOR, '"rgb:C0/C0/C0"', 'Label color'],
		'ColorLabelText': [COLOR, '"rgb:00/00/00"', 'Label text color'],
		'ColorInput': [COLOR, '"rgb:FF/FF/FF"', 'Input color'],
		'ColorInputText': [COLOR, '"rgb:00/00/00"', 'Input text color'],
		'ColorInputSelection': [COLOR, '"rgb:80/80/80"', 'Input selection color'],
		'ColorInputSelectionText': [COLOR, '"rgb:00/00/00"', 'Input selection text color'],
		'DesktopBackgroundColor': [COLOR, '"rgb:00/50/60"', 'Desktop background color'],
		'DesktopBackgroundImage': [FILE, '""', 'Desktop background image'],
		'ColorCPUStatusUser': [COLOR, '"rgb:00/FF/00"', 'User CPU usage color'],
		'ColorCPUStatusSystem': [COLOR, '"rgb:FF/00/00"', 'System CPU usage color'],
		'ColorCPUStatusNice': [COLOR, '"rgb:00/00/FF"', 'Nice CPU usage color'],
		'ColorCPUStatusIdle': [COLOR, '"rgb:00/00/00"', 'CPU Idle color'],
		'ColorNetSend': [COLOR, '"rgb:FF/FF/00"', 'Color of sent data on net monitor'],
		'ColorNetReceive': [COLOR, '"rgb:FF/00/FF"', 'Color of received data on net monitor'],
		'ColorNetIdle': [COLOR, '"rgb:00/00/00"', 'Color representing idle on net monitor'],
		'KeyWinRaise': [KEYSTROKE, '"Alt+F1"', '"Raise window" shortcut'],
		'KeyWinOccupyAll': [KEYSTROKE, '"Alt+F2"', '"Occupy all" shortcut'],
		'KeyWinLower': [KEYSTROKE, '"Alt+F3"', '"Lower window" shortcut'],
		'KeyWinClose': [KEYSTROKE, '"Alt+F4"', '"Close window" shortcut'],
		'KeyWinRestore': [KEYSTROKE, '"Alt+F5"', '"Restory window" shortcut'],
		'KeyWinPrev': [KEYSTROKE, '"Alt+Shift+F6"', '"Previous window" shortcut'],
		'KeyWinNext': [KEYSTROKE, '"Alt+F6"', '"Next window" shortcut'],
		'KeyWinMove': [KEYSTROKE, '"Alt+F7"', '"Move window" shortcut'],
		'KeyWinSize': [KEYSTROKE, '"Alt+F8"', '"Size window" shortcut'],
		'KeyWinMinimize': [KEYSTROKE, '"Alt+F9"', '"Minimize window" shortcut'],
		'KeyWinMaximize': [KEYSTROKE, '"Alt+F10"', '"Maximize window" shortcut'],
		'KeyWinMaximizeVert': [KEYSTROKE, '"Alt+Shift+F10"', '"Maximize window vertically" shortcut'],
		'KeyWinHide': [KEYSTROKE, '"Alt+F11"', '"Hide window" shortcut'],
		'KeyWinRollup': [KEYSTROKE, '"Alt+F12"', '"Rollup window" shortcut'],
		'KeyWinMenu': [KEYSTROKE, '"Alt+Space"', '"Window menu" shortcut'],
		'KeySysSwitchNext': [KEYSTROKE, '"Alt+Tab"', '"Next item" shortcut'],
		'KeySysSwitchLast': [KEYSTROKE, '"Alt+Shift+Tab"', '"Last item" shortcut'],
		'KeySysWinNext': [KEYSTROKE, '"Alt+Esc"', '"Next sys window" shortcut'],
		'KeySysWinPrev': [KEYSTROKE, '"Alt+Shift+Esc"', '"Previous sys window" shortcut'],
		'KeySysWinMenu': [KEYSTROKE, '"Shift+Esc"', '"Window menu" shortcut'],
		'KeySysDialog': [KEYSTROKE, '"Alt+Ctrl+Del"', '"Logout / screenlock dialog" shortcut'],
		'KeySysMenu': [KEYSTROKE, '"Ctrl+Esc"', '"Program menu" shortcut'],
		'KeySysRun': [KEYSTROKE, '"Alt+Ctrl+R"', '"Run" shortcut'],
		'KeySysWindowList': [KEYSTROKE, '"Alt+Ctrl+Esc"', '"Window list" shortcut'],
		'KeySysAddressBar': [KEYSTROKE, '"Alt+Ctrl+Space"', '"Address bar" shortcut'],
		'KeySysWorkspacePrev': [KEYSTROKE, '"Alt+Ctrl+Left"', '"Previous workspace" shortcut'],
		'KeySysWorkspaceNext': [KEYSTROKE, '"Alt+Ctrl+Right"', '"Next workspace" shortcut'],
		'KeySysWorkspacePrevTakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+Left"', '"Take window to previous workspace" shortcut'],
		'KeySysWorkspaceNextTakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+Right"', '"Take window to next workspace" shortcut'],
		'KeySysWorkspace1': [KEYSTROKE, '"Alt+Ctrl+1"', '"Workspace 1" shortcut'],
		'KeySysWorkspace2': [KEYSTROKE, '"Alt+Ctrl+2"', '"Workspace 2" shortcut'],
		'KeySysWorkspace3': [KEYSTROKE, '"Alt+Ctrl+3"', '"Workspace 3" shortcut'],
		'KeySysWorkspace4': [KEYSTROKE, '"Alt+Ctrl+4"', '"Workspace 4" shortcut'],
		'KeySysWorkspace5': [KEYSTROKE, '"Alt+Ctrl+5"', '"Workspace 5" shortcut'],
		'KeySysWorkspace6': [KEYSTROKE, '"Alt+Ctrl+6"', '"Workspace 6" shortcut'],
		'KeySysWorkspace7': [KEYSTROKE, '"Alt+Ctrl+7"', '"Workspace 7" shortcut'],
		'KeySysWorkspace8': [KEYSTROKE, '"Alt+Ctrl+8"', '"Workspace 8" shortcut'],
		'KeySysWorkspace9': [KEYSTROKE, '"Alt+Ctrl+9"', '"Workspace 9" shortcut'],
		'KeySysWorkspace10': [KEYSTROKE, '"Alt+Ctrl+0"', '"Workspace 10" shortcut'],
                'KeySysWorkspace11': [KEYSTROKE, '"Alt+Ctrl+["', '"Workspace 10" shortcut'],
                'KeySysWorkspace12': [KEYSTROKE, '"Alt+Ctrl+]"', '"Workspace 10" shortcut'],
		'KeySysWorkspace1TakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+1"', '"Take window to workspace 1" shortcut'],
		'KeySysWorkspace2TakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+2"', '"Take window to workspace 2" shortcut'],
		'KeySysWorkspace3TakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+3"', '"Take window to workspace 3" shortcut'],
		'KeySysWorkspace4TakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+4"', '"Take window to workspace 4" shortcut'],
		'KeySysWorkspace5TakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+5"', '"Take window to workspace 5" shortcut'],
		'KeySysWorkspace6TakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+6"', '"Take window to workspace 6" shortcut'],
		'KeySysWorkspace7TakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+7"', '"Take window to workspace 7" shortcut'],
		'KeySysWorkspace8TakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+8"', '"Take window to workspace 8" shortcut'],
		'KeySysWorkspace9TakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+9"', '"Take window to workspace 9" shortcut'],
		'KeySysWorkspace10TakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+0"', '"Take window to workspace 10" shortcut'],
                'KeySysWorkspace11TakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+["', '"Take window to workspace 10" shortcut'],
                'KeySysWorkspace12TakeWin': [KEYSTROKE, '"Alt+Ctrl+Shift+]"', '"Take window to workspace 10" shortcut'],
		'WorkspaceNames': [MULTI, '" 1 ", " 2 ", " 3 ", " 4 "', 'Names of the Workspaces', 10]
	}
		
# This list defines the order in which options will be output to the
# '.icewm/preferences' file.

ORDER = [ 	'ClickToFocus',
			'RaiseOnFocus',
			'FocusOnClickClient',
			'RaiseOnClickClient',
			'RaiseOnClickTitleBar',
			'RaiseOnClickButton',
			'RaiseOnClickFrame',
			'PassFirstClickToClient',
			'FocusOnMap',
			'FocusOnMapTransient',
			'FocusOnMapTransientActive',
			'PointerColormap',
			'LimitSize',
			'LimitPosition',
			'SizeMaximized',
			'ShowMoveSizeStatus',
			'MinimizeToDesktop',
			'StrongPointerFocus',
			'OpaqueMove',
			'OpaqueResize',
			'ManualPlacement',
			'SmartPlacement',
			'CenterTransientsOnOwner',
			'MenuMouseTracking',
			'AutoRaise',
			'DelayPointerFocus',
			'Win95Keys',
			'ModMetaIsCtrlAlt',
			'UseMouseWheel',
			'ShowPopupsAbovePointer',
			'ReplayMenuCancelClick',
			'QuickSwitch',
			'QuickSwitchToMinimized',
			'QuickSwitchToHidden',
			'QuickSwitchToAllWorkspaces',
			'GrabRootWindow',
			'SnapMove',
			'EdgeSwitch',
			'DesktopBackgroundCenter',
			'AutoReloadMenus',
			'ShowMenuButtonIcon',
			'AutoDetectGNOME',
			'ShowTaskBar',
			'TaskBarAtTop',
			'TaskBarAutoHide',
			'TaskBarShowClock',
			'TaskBarShowAPMStatus',
			'TaskBarClockLeds',
			'TaskBarShowMailboxStatus',
			'TaskBarMailboxStatusBeepOnNewMail',
			'TaskBarMailboxStatusCountMessages',
			'TaskBarShowWorkspaces',
			'TaskBarShowWindows',
			'TaskBarShowAllWindows',
			'TaskBarShowStartMenu',
			'TaskBarShowWindowListMenu',
			'TaskBarShowCPUStatus',
			'TaskBarShowNetStatus',
			'TaskBarDoubleHeight',
			'WarpPointer',
			'ClientWindowMouseActions',
			'TitleBarCentered',
			'ShowThemesMenu',
                        'MultiByte',
			'ConfirmLogout',
			'BorderSizeX',
			'BorderSizeY',
			'DlgBorderSizeX',
			'DlgBorderSizeY',
			'TitleBarHeight',
			'CornerSizeX',
			'CornerSizeY',
			'ClickMotionDistance',
			'ClickMotionDelay',
			'MultiClickTime',
			'MenuActivateDelay',
			'SubmenuMenuActivateDelay',
			'ToolTipDelay',
                        'ToolTipTime',
			'AutoHideDelay',
			'AutoRaiseDelay',
			'EdgeResistance',
			'PointerFocusDelay',
			'SnapDistance',
			'EdgeSwitchDelay',
			'ScrollBarStartDelay',
			'ScrollBarDelay',
			'AutoScrollStartDelay',
			'AutoScrollDelay',
			'UseRootButtons',
			'ButtonRaiseMask',
			'DesktopWinMenuButton',
			'DesktopWinListButton',
			'DesktopMenuButton',
			'TitleBarMaximizeButton',
			'TitleBarRollupButton',
			'MailCheckDelay',
			'TaskBarCPUSamples',
			'TitleButtonsLeft',
			'TitleButtonsRight',
			'TitleButtonsSupported',
			'IconPath',
			'MailBoxPath',
			'MailCommand',
			'NewMailCommand',
			'LockCommand',
			'ClockCommand',
			'RunCommand',
			'OpenCommand',
			'TerminalCommand',
			'LogoutCommand',
			'LogoutCancelCommand',
			'ShutdownCommand',
			'RebootCommand',
			'CPUStatusCommand',
			'NetStatusCommand',
			'AddressBarCommand',
			'NetworkStatusDevice',
			'TimeFormat',
			'DateFormat',
			'Theme',
			'ThemeAuthor',
			'ThemeDescription',
			'TitleFontName',
			'MenuFontName',
			'StatusFontName',
			'QuickSwitchFontName',
			'NormalButtonFontName',
			'ActiveButtonFontName',
			'NormalTaskBarFontName',
			'ActiveTaskBarFontName',
			'MinimizedWindowFontName',
			'ListBoxFontName',
			'ToolTipFontName',
			'ClockFontName',
			'ApmFontName',
			'LabelFontName',
			'ColorDialog',
			'ColorActiveBorder',
			'ColorNormalBorder',
			'ColorNormalTitleButton',
			'ColorNormalTitleButtonText',
			'ColorNormalButton',
			'ColorNormalButtonText',
			'ColorActiveButton',
			'ColorActiveButtonText',
			'ColorActiveTitleBar',
			'ColorNormalTitleBar',
			'ColorActiveTitleBarText',
			'ColorNormalTitleBarText',
			'ColorNormalMinimizedWindow',
			'ColorNormalMinimizedWindowText',
			'ColorActiveMinimizedWindow',
			'ColorActiveMinimizedWindowText',
			'ColorNormalMenu',
			'ColorActiveMenuItem',
			'ColorActiveMenuItemText',
			'ColorNormalMenuItemText',
			'ColorDisabledMenuItemText',
			'ColorMoveSizeStatus',
			'ColorMoveSizeStatusText',
			'ColorQuickSwitch',
			'ColorQuickSwitchText',
			'ColorDefaultTaskBar',
			'ColorNormalTaskBarApp',
			'ColorNormalTaskBarAppText',
			'ColorActiveTaskBarApp',
			'ColorActiveTaskBarAppText',
			'ColorMinimizedTaskBarApp',
			'ColorMinimizedTaskBarAppText',
			'ColorInvisibleTaskBarApp',
			'ColorInvisibleTaskBarAppText',
			'ColorScrollBar',
			'ColorScrollBarArrow',
			'ColorScrollBarSlider',
			'ColorListBox',
			'ColorListBoxText',
			'ColorListBoxSelection',
			'ColorListBoxSelectionText',
			'ColorToolTip',
			'ColorToolTipText',
			'ColorClock',
			'ColorClockText',
			'ColorApm',
			'ColorApmText',
			'ColorLabel',
			'ColorLabelText',
			'ColorInput',
			'ColorInputText',
			'ColorInputSelection',
			'ColorInputSelectionText',
			'DesktopBackgroundColor',
			'DesktopBackgroundImage',
			'ColorCPUStatusUser',
			'ColorCPUStatusSystem',
			'ColorCPUStatusNice',
			'ColorCPUStatusIdle',
			'ColorNetSend',
			'ColorNetReceive',
			'ColorNetIdle',
			'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',
			'WorkspaceNames'
	]

# 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',
			'PointerColormap',
			'LimitSize',
			'LimitPosition',
			'SizeMaximized',
			'ShowMoveSizeStatus',
			'MinimizeToDesktop',
			'OpaqueMove',
			'OpaqueResize',
			'MenuMouseTracking',
			'AutoRaise',
			'ShowPopupsAbovePointer',
			'GrabRootWindow',
			'SnapMove',
			'EdgeSwitch',
			'UseMouseWheel',
			'WarpPointer',
			'ClientWindowMouseActions',
			'ConfirmLogout',
                        'MultiByte'
			]],
		['Focus',
		        [
		        'FocusOnClickClient',
			'ClickToFocus',
			'FocusOnMap',
			'FocusOnMapTransient',
			'FocusOnMapTransientActive',
			'DelayPointerFocus',
			'StrongPointerFocus',
			'QuickSwitch',
			'QuickSwitchToMinimized',
			'QuickSwitchToHidden',
			'QuickSwitchToAllWorkspaces'
		        ]],
		['Window Placement',
		        [
			'ManualPlacement',
			'SmartPlacement',
			'CenterTransientsOnOwner'
			]],
		['Menus',
			[
			'AutoReloadMenus',
			'ShowMenuButtonIcon',
			'ShowThemesMenu',
			'MenuActivateDelay',
			'SubmenuMenuActivateDelay',
			'ReplayMenuCancelClick'
			]],
		['Taskbar',
			[
			'ShowTaskBar',
			'TaskBarAtTop',
			'TaskBarAutoHide',
			'TaskBarShowClock',
			'TaskBarShowAPMStatus',
			'TaskBarClockLeds',
			'TaskBarShowMailboxStatus',
			'TaskBarMailboxStatusBeepOnNewMail',
			'TaskBarMailboxStatusCountMessages',
			'MailCheckDelay',
			'TaskBarShowWorkspaces',
			'TaskBarShowWindows',
			'TaskBarShowAllWindows',
			'TaskBarShowStartMenu',
			'TaskBarShowWindowListMenu',
			'TaskBarShowCPUStatus',
			'TaskBarCPUSamples',
			'TaskBarShowNetStatus',
			'NetworkStatusDevice',
			'TaskBarDoubleHeight',
			'AutoDetectGNOME',
			]],
		['Borders',
			[
			'TitleBarCentered',
			'BorderSizeX',
			'BorderSizeY',
			'DlgBorderSizeX',
			'DlgBorderSizeY',
			'TitleBarHeight',
			'CornerSizeX',
			'CornerSizeY'
			]],
		['Timings',
			[
			
			'ClickMotionDelay',
			'MultiClickTime',
			'ToolTipDelay',
                        'ToolTipTime',
			'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',
			'LockCommand',
			'ClockCommand',
			'RunCommand',
			'OpenCommand',
			'TerminalCommand',
			'LogoutCommand',
			'LogoutCancelCommand',
			'CPUStatusCommand',
			'NetStatusCommand',
			'RebootCommand',
			'ShutdownCommand',
			'AddressBarCommand'
			]],
		['Formats',
			[
			'TimeFormat',
			'DateFormat'
			]],
		['Theme',
			[
			'Theme',
			'ThemeAuthor',
			'ThemeDescription'
			]],
		['Fonts',
			[
			'TitleFontName',
			'MenuFontName',
			'StatusFontName',
			'QuickSwitchFontName',
			'NormalButtonFontName',
			'ActiveButtonFontName',
			'NormalTaskBarFontName',
			'ActiveTaskBarFontName',
			'MinimizedWindowFontName',
			'ListBoxFontName',
			'ToolTipFontName',
			'ClockFontName',
			'ApmFontName',
			'LabelFontName'
			]],
		['Colors',
			[
			'ColorDialog',
			'ColorActiveBorder',
			'ColorNormalBorder',
			'ColorNormalTitleButton',
			'ColorNormalTitleButtonText',
			'ColorNormalButton',
			'ColorNormalButtonText',
			'ColorActiveButton',
			'ColorActiveButtonText',
			'ColorActiveTitleBar',
			'ColorNormalTitleBar',
			'ColorActiveTitleBarText',
			'ColorNormalTitleBarText',
			'ColorNormalMinimizedWindow',
			'ColorNormalMinimizedWindowText',
			'ColorActiveMinimizedWindow',
			'ColorActiveMinimizedWindowText',
			'ColorNormalMenu',
			'ColorActiveMenuItem',
			'ColorActiveMenuItemText',
			'ColorNormalMenuItemText',
			'ColorDisabledMenuItemText',
			'ColorMoveSizeStatus',
			'ColorMoveSizeStatusText',
			'ColorQuickSwitch',
			'ColorQuickSwitchText',
			'ColorDefaultTaskBar',
			'ColorNormalTaskBarApp',
			'ColorNormalTaskBarAppText',
			'ColorActiveTaskBarApp',
			'ColorActiveTaskBarAppText',
			'ColorMinimizedTaskBarApp',
			'ColorMinimizedTaskBarAppText',
			'ColorInvisibleTaskBarApp',
			'ColorInvisibleTaskBarAppText',
			'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',
			[
			'DesktopBackgroundCenter',
			'DesktopBackgroundColor',
			'DesktopBackgroundImage'
			]],
		['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',
			'KeySysWorkspace1TakeWin',
			'KeySysWorkspace2TakeWin',
			'KeySysWorkspace3TakeWin',
			'KeySysWorkspace4TakeWin',
			'KeySysWorkspace5TakeWin',
			'KeySysWorkspace6TakeWin',
			'KeySysWorkspace7TakeWin',
			'KeySysWorkspace8TakeWin',
			'KeySysWorkspace9TakeWin',
			'KeySysWorkspace10TakeWin'
			]],
		['Workspaces',
			[
			'WorkspaceNames'
			]]
	]
	
############################################################################
# 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

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)
		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=''):
		GtkVBox.__init__(self, spacing=SP)
		self.set_border_width(BD)
		self.init_widgets(title)
		self.set_value(value)
		self.show()
		
	def init_widgets(self, title):
		label = Label(title)
		label.show()
		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=''):
		GtkHBox.__init__(self, spacing=SP)
		self.set_border_width(BD)
		self.init_widgets(title)
		self.set_value(value)
		self.show()
		
	def init_widgets(self, title):
		self.button = GtkCheckButton()
		self.button.show()
		self.pack_start(self.button, FALSE, FALSE, 0)
		
		label = Label(title)
		label.show()
		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):
		GtkVBox.__init__(self, spacing=SP)
		self.set_border_width(BD)
		self.init_widgets(title, min, max)
		self.set_value(value)
		self.show()
		
	def init_widgets(self, title, min, max):
		hbox = GtkHBox(FALSE, SP)
		hbox.set_border_width(BD)
		hbox.show()
		self.pack_start(hbox, FALSE, FALSE, 0)
		label = Label(title)
		label.show()
		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):
		GtkVBox.__init__(self)
		self.set_border_width(BD)
		self.init_constants()
		self.init_widgets(title)
		self.set_value(value)
		self.show()
		
	def init_constants(self):
		self.mods=[
					['Alt', 'Alt+'],
					['Ctrl', 'Ctrl+'],
					['Shift', 'Shift+']
					
				]
		
	def init_widgets(self, title):
		label = Label(title)
		self.pack_start(label)
		label.show()
		
		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=''):
		GtkVBox.__init__(self, FALSE, SP)
		self.set_border_width(BD)
		self.init_widgets(title)
		self.set_value(value)
		self.show()
		
	def init_widgets(self, title):
		label = Label(title)
		label.show()
		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):
		label = Label(title)
		label.show()
		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):
		GtkVBox.__init__(self, spacing = SP)
		self.num = num
		self.set_border_width(BD)
		self.init_widgets(title)
		self.set_value(value)
		self.show()
		
	def init_widgets(self, title):
		label = Label(title)
		label.show()
		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=''):
	    GtkVBox.__init__(self)
	    self.set_border_width(BD)
	    self.set_spacing(SP)
	    self.init_theme_list()
	    self.set_value(value)
	    self.init_widgets(title)
	    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):
		label = Label(title)
		self.pack_start(label)
		label.show()
		
		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=''):
		GtkVBox.__init__(self)
		self.set_border_width(BD)
		self.init_widgets(title)
		self.set_value(value)
		self.show()
		
	def init_widgets(self, title):
		label = Label(title)
		self.pack_start(label)
		label.show()
		
		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()
		
	def mainloop(self):
		mainloop()
	
	# 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 ORDER:
			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):
	    
	    whole_options = re.findall('[\w]*="[^#]*"|[\w]*=[0-9]+', string)
	    
	    all_options = {}

	    for option in whole_options:
		option = re.split('=', option)
		option_name = option[0]
		option_value = option[1]
		if DEBUG:
		    print option_name, option_value
		all_options[option_name] = option_value

	    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.analyze() 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]
		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)
			for name in ORDER:
				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):
					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('About', 'This is IcePref %s by David Mortensen--a pythonated configuration utility for IceWM.  It is optimized for use with IceWM %s.  Visit the IcePref website at http://members.xoom.com/SaintChoj/icepref.html.' % (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(400, 400)
			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
				# if the y counter is greater than or equal to half
				# the number of widgets in a two column page,
				# move to the second column
				if y >= ((num_widgets / 2.0) - 1) and x == 0 and cols == 2:
					y = 0
					x = x + 1
				else:
					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])
		elif type == RANGE:
			widget = Range(		self.settings[item][TITLE],
						self.settings[item][MIN],
						self.settings[item][MAX],
						self.settings[item][VALUE])
		elif type == FILE:
			widget = File(		self.settings[item][TITLE],
						self.settings[item][VALUE])
		elif type == PATH:
			widget = Path(		self.settings[item][TITLE],
						self.settings[item][VALUE])
		elif type == COLOR:
			widget = Color(		self.settings[item][TITLE],
						self.settings[item][VALUE])
		elif type == FONT:
			widget = Font(		self.settings[item][TITLE],
						self.settings[item][VALUE])
		elif type == ENTRY:
			widget = Entry(		self.settings[item][TITLE],
						self.settings[item][VALUE])
		elif type == KEYSTROKE:
			widget = Keystroke(	self.settings[item][TITLE],
						self.settings[item][VALUE])
		elif type == MULTI:
			widget = Multi(		self.settings[item][TITLE],
						self.settings[item][VALUE],
						self.settings[item][NUM])
		elif type == THEME:
			widget = ThemeSel(	self.settings[item][TITLE],
						self.settings[item][VALUE])
					
		elif type == BITMASK:
			widget = BitMask(	self.settings[item][TITLE],
						self.settings[item][VALUE])
							
		elif type == MOUSEBUTTON:
			widget = MouseButton( 	self.settings[item][TITLE],
						self.settings[item][VALUE])
		
		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 __name__ == '__main__':		
	app = Application(sys.argv)
	app.mainloop()
