diff --git a/cairo-appbase.cabal b/cairo-appbase.cabal
--- a/cairo-appbase.cabal
+++ b/cairo-appbase.cabal
@@ -1,28 +1,87 @@
-Cabal-Version:   >= 1.6
-Name:            cairo-appbase
-Version:         0.2
-Synopsis:        Template code for an app using GTK, Glade and Cairo graphics
-Description:     This is a template for building new GUI applications. The
-                 GTK widget layout is done via a Glade XML file which can be
-                 edited visually using glade.
+Name:                cairo-appbase
 
-                 This template includes working callbacks to handle the File
-                 and Help menus and File Save/Open dialogs, with dummy
-                 handlers for selecting filenames and the Edit menu's
-                 cut/copy/paste.
+Version:             0.3
 
-                 The main canvas for this application uses Cairo for
-                 graphics rendering, and includes example code from the
-                 cairo package.
-License:         BSD3
-License-file:    LICENSE
-Author:          Conrad Parker, Johan Bockgård
-Maintainer:      conrad@metadecks.org
-Category:        GUI
-Build-Depends:   base < 5, glib, gtk, glade, cairo
-Build-Type:      Simple
-Data-Files:      data/main.glade
+Synopsis:            A template for building new GUI applications using GTK, Glade and Cairo.
 
-Executable:      cairo-appbase
-Main-Is:         cairo-appbase.hs
-Hs-Source-Dirs:  src
+Description:
+    This template includes working callbacks to handle the File and Help
+    menus and File Save/Open dialogs, with dummy handlers for selecting
+    filenames and the Edit menu's Cut, Copy, and Paste. The main canvas uses
+    Cairo for graphics rendering, and includes example code from the cairo
+    package.
+    .
+    To build your own application on top of this, first grab the code. You
+    can either grab it from hackage with @cabal unpack cairo-appbase@, or
+    clone the git repo:
+    .
+    >   git clone git://github.com/kfish/cairo-appbase.git
+    .
+    To add widgets, install glade from your distro system and run
+    @glade data/main.glade@
+    .
+    Note that you must run @cabal install@ to put the glade file in the correct
+    place for your application to pick it up. To modify the code, edit
+    @src/cairo-appbase.hs@. Hooking up functions to widgets is very simple: get
+    a widget by name (which you set in glade file), and hook one of its
+    signals (which you found in the Signals tab in glade) to an @IO ()@ action:
+    .
+    > cut1 <- get G.castToMenuItem "cut1"
+    > G.onActivateLeaf cut1 $ myCut
+    .
+    The template code includes a trivial definition of myCut:
+    .
+    > myCut :: IO ()
+    > myCut = putStrLn "Cut"
+    .
+    A real application will want to pass data to the callback. In C, this is
+    fairly tedious as you only have a single void * to pass to callbacks as
+    @user_data@, and applications typically do lots of marshalling and
+    unmarshalling to pass data around. In Haskell however, you can make
+    yourself a more complex callback handler and use a curried version of it
+    in each instance:
+    .
+    > cut1 <- get G.castToMenuItem "cut1"
+    > G.onActivateLeaf cut1 $ myComplexCut project phase 7
+    >
+    > ...
+    >
+    > myCut :: Project -> MoonPhase -> LuckyNumber -> IO ()
+    > myCut project phase num = do
+    >     let selection = currentSelection project
+    >     when (phase == Full) howl
+    >     when (num /= 7) fail
+    >     doActualCut selection
+    .
+
+License:             BSD3
+License-file:        LICENSE
+Author:              Conrad Parker, Johan Bockgård
+Maintainer:          conrad@metadecks.org
+Category:            Development
+
+Cabal-Version:       >= 1.8
+Build-type:          Simple
+Data-Files:          data/main.glade
+
+flag splitBase
+  description: Use the split-up base package.
+
+Executable cairo-appbase
+  if flag(splitBase)
+    build-depends:
+      base >= 3 && < 6
+  else
+    build-depends:
+      base < 3
+
+  Main-Is:             cairo-appbase.hs
+  Hs-Source-Dirs:      src
+  Build-Depends:       glib, gtk, glade, cairo
+
+------------------------------------------------------------------------
+-- Git repo
+--
+source-repository head
+  type: git
+  location: git://github.com/kfish/cairo-appbase.git
diff --git a/src/cairo-appbase.hs b/src/cairo-appbase.hs
--- a/src/cairo-appbase.hs
+++ b/src/cairo-appbase.hs
@@ -1,3 +1,4 @@
+{-# OPTIONS -Wall #-}
 --
 -- Based on Gtk2Hs/demo/cairo/Drawing2.hs 
 -- Author: Johan Bockgård <bojohan@dd.chalmers.se>
@@ -5,6 +6,7 @@
 -- This code is in the public domain.
 --
 
+import Control.Monad (replicateM_)
 import qualified System.Glib.Types as GTypes
 import qualified Graphics.UI.Gtk as G
 import qualified Graphics.UI.Gtk.Glade as Glade
@@ -18,8 +20,8 @@
 windowHeight  = 500
 
 -- Write image to file
-writePng :: IO ()
-writePng =
+_writePng :: IO ()
+_writePng =
   C.withImageSurface C.FormatARGB32 width height $ \ result -> do
       C.renderWith result $ example width height
       C.surfaceWriteToPNG result "Draw.png"
@@ -27,8 +29,9 @@
         height = windowHeight
 
 -- Display image in window
+main :: IO ()
 main = do
-  G.initGUI
+  _ <- G.initGUI
 
   -- load up the glade file
   filename <- My.getDataFileName "data/main.glade"
@@ -44,37 +47,37 @@
 
   -- set up File->New
   new1 <- get G.castToMenuItem "new1"
-  G.onActivateLeaf new1 $ myNew
+  _ <- G.onActivateLeaf new1 $ myNew
 
   -- set up the File->Open dialog
   open1 <- get G.castToMenuItem "open1"
   openDialog <- get G.castToFileChooserDialog "opendialog"
-  G.onActivateLeaf open1 $ G.widgetShow openDialog
-  G.onResponse openDialog $ myFileOpen openDialog
+  _ <- G.onActivateLeaf open1 $ G.widgetShow openDialog
+  _ <- G.onResponse openDialog $ myFileOpen openDialog
 
   -- set up the File->Save_As dialog
   save1 <- get G.castToMenuItem "save1"
   save_as1 <- get G.castToMenuItem "save_as1"
   saveDialog <- get G.castToFileChooserDialog "savedialog"
-  G.onActivateLeaf save_as1 $ G.widgetShow saveDialog
-  G.onActivateLeaf save1 $ G.widgetShow saveDialog
-  G.onResponse saveDialog $ myFileSave saveDialog
+  _ <- G.onActivateLeaf save_as1 $ G.widgetShow saveDialog
+  _ <- G.onActivateLeaf save1 $ G.widgetShow saveDialog
+  _ <- G.onResponse saveDialog $ myFileSave saveDialog
 
   -- set up Edit menu
   cut1 <- get G.castToMenuItem "cut1"
-  G.onActivateLeaf cut1 $ myCut
+  _ <- G.onActivateLeaf cut1 $ myCut
   copy1 <- get G.castToMenuItem "copy1"
-  G.onActivateLeaf copy1 $ myCopy
+  _ <- G.onActivateLeaf copy1 $ myCopy
   paste1 <- get G.castToMenuItem "paste1"
-  G.onActivateLeaf paste1 $ myPaste
+  _ <- G.onActivateLeaf paste1 $ myPaste
   delete1 <- get G.castToMenuItem "delete1"
-  G.onActivateLeaf delete1 $ myDelete
+  _ <- G.onActivateLeaf delete1 $ myDelete
 
   -- set up the Help->About dialog
   about1 <- get G.castToMenuItem "about1"
   aboutdialog1 <- get G.castToAboutDialog "aboutdialog1"
-  G.onActivateLeaf about1 $ G.widgetShow aboutdialog1
-  G.onResponse aboutdialog1 $ const $ G.widgetHide aboutdialog1
+  _ <- G.onActivateLeaf about1 $ G.widgetShow aboutdialog1
+  _ <- G.onResponse aboutdialog1 $ const $ G.widgetHide aboutdialog1
 
   -- fix size
   --   G.windowSetResizable window False
@@ -82,12 +85,12 @@
 
   -- quit on File->Quit menu selection
   quit1 <- get G.castToMenuItem "quit1"
-  G.onActivateLeaf quit1 $ G.widgetDestroy window
-  G.onDestroy window G.mainQuit
+  _ <- G.onActivateLeaf quit1 $ G.widgetDestroy window
+  _ <- G.onDestroy window G.mainQuit
 
   -- set up the canvas
   canvas <- get G.castToDrawingArea "drawingarea1"
-  G.onExpose canvas $ const (updateCanvas canvas)
+  _ <- G.onExpose canvas $ const (updateCanvas canvas)
   G.widgetShowAll window
   G.mainGUI
 
@@ -102,6 +105,7 @@
     G.ResponseCancel -> putStrLn "Cancelled!"
     G.ResponseDeleteEvent -> putStrLn "FileChooserDialog Deleted!"
     G.ResponseClose -> putStrLn "Closed!"
+    _ -> return ()
   G.widgetHide fcdialog
 
 myFileSave :: G.FileChooserDialog -> G.ResponseId -> IO ()
@@ -121,8 +125,8 @@
 
 updateCanvas :: G.DrawingArea -> IO Bool
 updateCanvas canvas = do
-  win <- G.drawingAreaGetDrawWindow canvas
-  (width, height) <- G.drawingAreaGetSize canvas
+  win <- G.widgetGetDrawWindow canvas
+  (width, height) <- G.widgetGetSize canvas
   G.renderWithDrawable win $
       example width height
   return True
@@ -132,24 +136,29 @@
 foreach :: (Monad m) => [a] -> (a -> m b) -> m [b]
 foreach = flip mapM
 
+keepState :: C.Render t -> C.Render ()
 keepState render = do
   C.save
-  render
+  _ <- render
   C.restore
 
+drawCircle :: Double -> Double -> Double -> C.Render ()
 drawCircle x y r = do
   C.arc x y r 0 (2 * pi)
   fillStroke
 
+drawRectangle :: Double -> Double -> Double -> Double -> C.Render ()
 drawRectangle x y w h = do
   C.rectangle x y w h
   fillStroke
 
+stroke :: C.Render ()
 stroke =
   keepState $ do
   C.setSourceRGBA 0 0 0 0.7
   C.stroke
 
+fillStroke :: C.Render ()
 fillStroke = do
   C.fillPreserve
   stroke
@@ -158,11 +167,13 @@
 
 -- Example
 
+example :: Int -> Int -> C.Render ()
 example width height = do
   prologue width height
   example1
 
 -- Set up stuff
+prologue :: Int -> Int -> C.Render ()
 prologue wWidth wHeight = do
   let width   = 10
       height  = 10
@@ -191,6 +202,7 @@
 
 
 -- Grid and axes
+grid :: Double -> Double -> Double -> Double -> C.Render ()
 grid xmin xmax ymin ymax =
   keepState $ do
   C.setSourceRGBA 0 0 0 0.7
@@ -204,20 +216,22 @@
          C.lineTo x ymax
          C.stroke
 
+example1 :: C.Render ()
 example1 = do
   -- circles
   drawCircle 0 0 1
   drawCircle 2 2 3
   -- a bunch of rectangles
   keepState $
-    foreach [1 .. 5] $ \ _ ->
-        do drawRectangle 0 1 2 3
-           C.rotate (pi/8)
+    replicateM_ 5 $ do
+        drawRectangle 0 1 2 3
+        C.rotate (pi/8)
   -- some cute stuff
   thought
   apple
   snake
 
+thought :: C.Render ()
 thought =
   keepState $ do
   C.scale 0.04 0.04
@@ -274,6 +288,7 @@
         c 146 424 144 422 143 422
         z
 
+apple :: C.Render ()
 apple =
   keepState $ do
   C.scale 0.05 0.05
@@ -309,6 +324,7 @@
         c 1153 249 1152 249 1151 249
         z
 
+snake :: C.Render ()
 snake =
   keepState $ do
   C.scale 0.04 0.04
