{-# LANGUAGE OverlappingInstances, ScopedTypeVariables #-} module Main where import Graphics.UI.Gtk (initGUI, mainGUI) import System.Gnome.GConf import Control.Monad (when) import System.Exit (exitFailure) import Data.List (intersperse) main = do -- connect to gconf conf <- gconfGetDefault -- for the purposes of this demo check for key and display usage message exists <- conf `gconfDirExists` "/apps/gtk2hs-gconf-demo" when (not exists) (do putStrLn usageMessage exitFailure) -- get and print initial values (intValue :: Int) <- conf `gconfGet` "/apps/gtk2hs-gconf-demo/intValue" (boolValue :: Maybe Bool) <- conf `gconfGet` "/apps/gtk2hs-gconf-demo/boolValue" (floatValue :: Double) <- conf `gconfGet` "/apps/gtk2hs-gconf-demo/floatValue" (stringValue :: String) <- conf `gconfGet` "/apps/gtk2hs-gconf-demo/stringValue" (pairValue :: (Int,Bool)) <- conf `gconfGet` "/apps/gtk2hs-gconf-demo/pairValue" (listValue :: [Int]) <- conf `gconfGet` "/apps/gtk2hs-gconf-demo/listValue" print intValue print boolValue print floatValue print stringValue print pairValue print listValue -- register for notification of changes conf `gconfAddDir` "/apps/gtk2hs-gconf-demo" -- using the prefered API which allows you to specify the key/dir of interest. -- This is usuall what you want because you'll do different things in response -- to changes in different keys. Also, it allows you to use native types rather -- than converting from a dynamic type. gconfNotifyAdd conf "/apps/gtk2hs-gconf-demo/intValue" doSomethingWhenIntValueChanges gconfNotifyAdd conf "/apps/gtk2hs-gconf-demo/boolValue" doSomethingWhenBoolValueChanges gconfNotifyAdd conf "/apps/gtk2hs-gconf-demo/floatValue" doSomethingWhenFloatValueChanges gconfNotifyAdd conf "/apps/gtk2hs-gconf-demo/stringValue" doSomethingWhenStringValueChanges gconfNotifyAdd conf "/apps/gtk2hs-gconf-demo/pairValue" doSomethingWhenPairValueChanges gconfNotifyAdd conf "/apps/gtk2hs-gconf-demo/listValue" doSomethingWhenListValueChanges -- and the other API (which gives you notifications on everything) conf `afterValueChanged` doSomethingWhenAnyKeyChanges -- run the glib main loop otherwise we wouldn't wait for changes putStrLn $ "waiting for any changes in the gconf dir" ++ "\"/apps/gtk2hs-gconf-demo\"" initGUI mainGUI -- Our various doSomething* functions -- doSomethingWhenIntValueChanges :: String -> Int -> IO () doSomethingWhenIntValueChanges key value = putStrLn $ "[method1] intValue changed to " ++ show value -- This one is designed to cope with the key being unset doSomethingWhenBoolValueChanges :: String -> Maybe Bool -> IO () doSomethingWhenBoolValueChanges key (Just value) = putStrLn $ "[method1] boolValue changed to " ++ show value doSomethingWhenBoolValueChanges key Nothing = putStrLn $ "[method1] boolValue was unset" doSomethingWhenFloatValueChanges :: String -> Double -> IO () doSomethingWhenFloatValueChanges key value = putStrLn $ "[method1] floatValue changed to " ++ show value doSomethingWhenStringValueChanges :: String -> String -> IO () doSomethingWhenStringValueChanges key value = putStrLn $ "[method1] stringValue changed to " ++ show value doSomethingWhenPairValueChanges :: String -> (Int, Bool) -> IO () doSomethingWhenPairValueChanges key value = putStrLn $ "[method1] pairValue changed to " ++ show value doSomethingWhenListValueChanges :: String -> [Int] -> IO () doSomethingWhenListValueChanges key value = putStrLn $ "[method1] listValue changed to " ++ show value doSomethingWhenAnyKeyChanges :: String -> Maybe GConfValueDyn -> IO () doSomethingWhenAnyKeyChanges key (Just value) = putStrLn $ "[method2] the key " ++ key ++ " changed to " ++ showGConfValue value doSomethingWhenAnyKeyChanges key Nothing = putStrLn $ "[method2] the key " ++ key ++ " was unset" -- Helper function to display a value and its type -- This is not an important part of the demo -- showGConfValue :: GConfValueDyn -> String showGConfValue value = showGConfValue_ValueOnly value ++ " :: " ++ showGConfValue_Type value showGConfValue_ValueOnly :: GConfValueDyn -> String showGConfValue_ValueOnly (GConfValueString s) = show s showGConfValue_ValueOnly (GConfValueInt n) = show n showGConfValue_ValueOnly (GConfValueBool b) = show b showGConfValue_ValueOnly (GConfValueFloat f) = show f showGConfValue_ValueOnly (GConfValueList as) = "[" ++ (concat $ intersperse "," $ map showGConfValue_ValueOnly as) ++ "]" showGConfValue_ValueOnly (GConfValuePair (a,b)) = "(" ++ showGConfValue_ValueOnly a ++ ", " ++ showGConfValue_ValueOnly b ++ ")" showGConfValue_Type :: GConfValueDyn -> String showGConfValue_Type (GConfValueString s) = "String" showGConfValue_Type (GConfValueInt n) = "Int" showGConfValue_Type (GConfValueBool b) = "Bool" showGConfValue_Type (GConfValueFloat f) = "Double" -- gconf does type empty lists too but our GConfValueDyn cannot represent -- them using the GConfValueClass is preferable in this sense as it can type -- all the GConfValue stuff exactly (so long as that type is known statically) showGConfValue_Type (GConfValueList []) = "[unknown]" showGConfValue_Type (GConfValueList (a:_)) = "[" ++ showGConfValue_Type a ++ "]" showGConfValue_Type (GConfValuePair (a,b)) = "(" ++ showGConfValue_Type a ++ ", " ++ showGConfValue_Type b ++ ")" usageMessage = "To use this gconf demo program, first create the required gconf entrys.\n" ++ "Use the following commands:\n" ++ " gconftool-2 --set /apps/gtk2hs-gconf-demo/intValue --type int 3\n" ++ " gconftool-2 --set /apps/gtk2hs-gconf-demo/boolValue --type bool false\n" ++ " gconftool-2 --set /apps/gtk2hs-gconf-demo/floatValue --type float 3.141592\n" ++ " gconftool-2 --set /apps/gtk2hs-gconf-demo/stringValue --type string foo\n" ++ " gconftool-2 --set /apps/gtk2hs-gconf-demo/pairValue --type pair \\\n" ++ " --car-type int --cdr-type bool \"(3,false)\"\n" ++ " gconftool-2 --set /apps/gtk2hs-gconf-demo/listValue --type list \\\n" ++ " --list-type int \"[0,1,2,3,4]\"\n" ++ "This demo will display the values of these keys and then watch them for\n" ++ "changes. Use the gconf-editor program to change the values of these keys.\n" ++ "Hit ^C when you get bored.\n" ++ "To delete the keys when you're finnished with this demo use:\n" ++ " gconftool-2 --recursive-unset /apps/gtk2hs-gconf-demo"