[Haskell-cafe] Re: How to use dyre relaunch/restore State of Gtk2hs Object?

Andy Stewart lazycat.manatee at gmail.com
Mon Aug 31 10:44:59 EDT 2009


Will Donnelly <will.donnelly at gmail.com> writes:

HI Will,

First, thanks for your detail explain.
> Hi Andy,
>
> Your program didn't compile as given, so I cut out some of the event handling fanciness you were
> doing. Also, my modified version restarts whenever the 'r'
> key is pressed. I figure those changes aren't important to the problem at hand.
>
> Anyway, I don't think it's ever going to be possible to define a Binary instance for a TextView,
> since all of the functions which can yield information
> about it are impure. I would recommend extracting the relevant data beforehand, and then persisting
> it in a tuple. You could use some 'marshal<WIDGET>' and
> 'recreate<WIDGET>' functions if you need to persist many different widget types. Saving just the
> text can be done as follows:
Before your mail, i thinking long time to integrate dyre with gtk2hs
program.

I have three need to dynamic reconfigure gtk2hs program.
1-> Entry new version master binary if recompile successful. (dyre have
implement this with relaunchMaster)
2-> Recompile new module dynamic for update algorithms. (dyre
have implement this)
3-> Keep gtk2hs object state through reboot.

Now just point (3) need solve.

To keep GTK widget state, it's un-necessary to define a Binary instance for
Gtk2hs object (and not possible), we just need extract relevant data
from widget ( for TextView, we can extract text, iter, etc. ), then
recreate widget with states after we relaunch master binary.

Then we can keep gtk2hs state through reboot.
 
Below is my analysis that how to keep gtk2hs object state:

gtk2hs use c2hs binding Haskell to C, c2hs will use Ptr point to C struct
address when it found current type is C struct. So we can't save pointer
address for restore, because pointer address will not valid after
relaunch master binary.

Second solution, we can use Haskell define pure state model, then use
gtk2hs rendering data. Example, we can use Haskell define "data
HaskellTextBuffer" for keep Buffer information for TextView.
But this solution have it's disadvantage, we need do duplicate work in
HaskellTextBuffer that TextBuffer have do. And between TextBuffer and
TextView have many relevant C functions need handle, and this solution
is not neat.

Third solution, we just need define new type that store necessary
information to recreate widget, example like below:

  data TextViewState  
----------------------
| TextBuffer -> Text |
| TextBuffer -> Iter |
----------------------

Save TextViewState => Dyre recompile => Restore TextViewState => Recreate widget with TextViewState

>
> <code>
> module DyreExample where
>
> import Graphics.UI.Gtk hiding (get)
> import qualified Graphics.UI.Gtk.Gdk.Events as E
>
> import qualified Config.Dyre as Dyre
> import Config.Dyre.Relaunch
>
> import System.IO
> import Data.Binary
>
> data Config = Config { message :: String, errorMsg :: Maybe String }
>
> defaultConfig :: Config
> defaultConfig = Config "Dyre Example v0.1" Nothing
>
> showError :: Config -> String -> Config
> showError cfg msg = cfg { errorMsg = Just msg }
>
> realMain Config{message = message, errorMsg = errorMsg } = do
>   initGUI
>
>   textView <- textViewNew
>   textBuffer <- textViewGetBuffer textView
>   text <- restoreBinaryState ""
>   putStrLn $ "Restored state: " ++ text
>   textBufferSetText textBuffer text
>
>   rootWindow <- windowNew
>   rootWindow `onDestroy` mainQuit
>   windowFullscreen rootWindow
>
>   rootWindow `containerAdd` textView
>
>   widgetShowAll rootWindow
>
>   rootWindow `onKeyPress` (\event -> dyreKeyTest event textView)
>
>   mainGUI
>
> dyreExample = Dyre.wrapMain $ Dyre.defaultParams
>     { Dyre.projectName = "Main"
>     , Dyre.realMain = realMain
>     , Dyre.showError = showError
>     }
>
> dyreKeyTest :: E.Event -> TextView -> IO Bool
> dyreKeyTest ev textView = do
>     case E.eventKeyName ev of
>          "r" -> do textBuffer <- textViewGetBuffer textView
>                    sI <- textBufferGetStartIter textBuffer
>                    eI <- textBufferGetEndIter textBuffer
>                    text <- textBufferGetText textBuffer sI eI True
>                    putStrLn $ "Relaunching with state: " ++ text
>                    relaunchWithBinaryState text Nothing
>                    return True
>          _ -> return False
> </code>
>
> Other comments:
>   1. It isn't necessary to explicitly tell Dyre to do a custom compile. It will take care of
> figuring that out once you restart it.
>   2. Instead of manually setting paths in the code, you can use the '--dyre-debug' command-line
> flag, which will cause Dyre to look for configurations in
> the current directory, and store temporary files in a 'cache' subdirectory.
>   3. Giving a project name of 'Main' causes Dyre to see the file 'Main.hs' as a custom
> configuration. I'm not sure if that's what you intended, but it will
> make testing custom configurations harder than it needs to be.
>   4. Good luck with the rest of your project!
Thanks for your suggestions! :)

  -- Andy

>
> - Will Donnelly
>
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe



More information about the Haskell-Cafe mailing list