@hackage reflex-gi-gtk0.2.0.1

Helper functions to use reflex with gi-gtk

reflex-gi-gtk

This package provides the necessary plumbing to write reactive GUI applications using GTK3+ (based on gi-gtk) and reflex.

While this packes should make working with gi-gtk and reflex together much easier than using them together without any kind of glue code, it doesn't provide a lot of abstraction on top of either GTK or reflex. People familiar with both gi-gtk and reflex separately should have no trouble using reflex-gi-gtk successfully to build awesome applications.

Installation

reflex-gi-gtk is a regular cabal library and can be added to your project by listing reflex-gi-gtk in your project's build-depends.

Quick start

To start writing your reactive GUI application using reflex-gi-gtk, you will farst want to start the reactive part of your application using runReflexGtk, something like this:

{-# LANGUAGE OverloadedStrings, OverloadedLabels, FlexibleContexts #-}

import Control.Applicative (liftA2)
import GI.Gtk hiding (main)
import Reflex.GI.Gtk
import System.Environment
import System.Exit

main :: IO ()
main = do
  argv <- (:) <$> getProgName <*> getArgs
  Just gtkApplication <- applicationNew (Just "org.example.MyAwesomeApp") []
  rc <- runReflexGtk gtkApplication (Just argv) $ myReactiveCode gtkApplication
  case rc of
    0 -> exitSuccess
    n -> exitWith $ ExitFailure $ fromIntegral n

Inside the call to runReflexGtk you can assume that GTK has been initialized and start creating GTK widgets:

myReactiveCode :: (MonadReflexGtk t m) => Application -> m ()
myReactiveCode gtkApplication = do
  window <- runGtk $ applicationWindowNew gtkApplication
  box <- runGtk $ boxNew OrientationVertical 0
  containerAdd window box
  input1 <- runGtk entryNew
  input2 <- runGtk entryNew
  output <- runGtk $ labelNew Nothing
  runGtk $ boxPackStart box input1 False False 0
  runGtk $ boxPackStart box input2 False False 0
  runGtk $ boxPackStart box output False False 0

Note that we use runGtk to execute GTK functions instead of relying on liftIO. This is because GTK functions are required to be run with the correct thread local context. reflex-gi-gtk internally uses multiple threads in a way that makes it hard to predict in which thread a given piece of code will run. runGtk will ensure that the lifted IO action is always run in the appropriate threading context for GTK functions.

You can also start obtaining reactive inputs from widget signals:

  text1 <- dynamicOnSignal "" input1 #changed $ \fire -> entryGetText input1 >>= fire
  text2 <- dynamicOnAttribute input2 #text

This creates to Dynamics containing texts. text1 is constructed based on the #changed event of the first input Entry while text2 is bound to the attribute #text of input2, but overall the effect will be the same. Both text1 and text2 will always contain the text entered into their respective input Entry.

Once we have obtained reactive inputs, we can of course manipulate them just as any other reactive values:

  let combinedText = liftA2 (<>) text1 text2

In the end, we can also render dynamic values to attributes of GTK widgets:

  sink output [#label :== combinedText]

Don't forget to call widgetShowAll on your window at an appropriate time:

  _ <- gtkApplication `on` #activate $ widgetShowAll window
  pure ()

When you compile and run your program above, you should see your two input boxes and the appropriate, dynamically updated output label.

This is of course a very basic example. For more information you can look at a more elaborate example in the example directory or at the haddock documentation on hackage.