#!/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 = 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 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, ''], ['/File/tearoff1', None, None, 0, ''], ['/File/_Reload', 'O', self.set_file_settings, 0, ''], ['/File/_Defaults', 'D', self.set_default_settings, 0, ''], ['/File/_Save', 'S', self.save_current_settings, 0, ''], ['/File/sep1', None, None, 0, ''], ['/File/_Restart IceWM', 'R', self.restart, 0, ''], ['/File/sep2', None, None, 0, ''], ['/File/_Close', 'Q', mainquit, 0, ''], ['/_Help', None, None, 0, ''], ['/Help/_About', None, self.about_cb, 0, ''] ] ag = GtkAccelGroup() itemf = GtkItemFactory(GtkMenuBar, '
', ag) self.add_accel_group(ag) itemf.create_items(menu_items) self.menubar = itemf.get_widget('
') 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()