data IState = forall s. IS
{ window :: Gtk.Window
+ , buffer :: IORef Cairo.Surface
, postponed :: IORef [Request]
, usrState :: IORef s
, usrProg :: TinaStep s
runTina Main {..} = do
usrState <- newIORef initialState
postponed <- newIORef (GfxText (rgb 0 0 0) (pt 50 50) "foo" : GfxClear :initialRequests)
- let state = IS { window = undefined, usrProg = eventHandler, .. }
+ let state = IS { window = undefined, buffer = undefined, usrProg = eventHandler, .. }
runGUI windowWidth windowHeight state
runGUI :: Int -> Int -> IState -> IO ()
-runGUI w h s = do
+runGUI w h (IS { .. }) = do
-- Init GTK.
Gtk.initGUI
, Gtk.windowDefaultHeight := h
]
Gtk.onDestroy window Gtk.mainQuit
-
- -- Add the window to the state
- let state = s { window = window }
+ -- Create a buffer to draw on (name the actual buffer buffer', so we
+ -- can use IS { .. } syntax below to pack the state. Using a record update
+ -- wouldn't work, probably because Cairo.Surface contains an existential
+ -- type...
+ -- We put the buffer in an IORef, so we can change it for a new one
+ -- later on (on window resizes).
+ buffer' <- Cairo.createImageSurface Cairo.FormatARGB32 w h
+ buffer <- newIORef buffer'
+
+ -- Register the expose event
+ Gtk.on window Gtk.exposeEvent $ onExpose buffer
+
+ -- Repack state
+ let state = IS { .. }
+
-- Show the window and start the Gtk mainloop.
Gtk.widgetShowAll window
Gtk.mainGUI
+-- | Copy the given surface to the exposed window on an expose event.
+onExpose :: IORef Cairo.Surface -> EventM.EventM EventM.EExpose Bool
+onExpose buffer = do
+ current_buffer <- liftIO $ readIORef buffer
+ dw <- EventM.eventWindow
+ -- Copy the buffer to the window
+ liftIO $ Gtk.renderWithDrawable dw $ do
+ Cairo.setSourceSurface current_buffer 0 0
+ Cairo.paint
+ return True -- No clue what this means
{-
runGUI s IS {..} = do