reflex-gi-gtk: Helper functions to use reflex with gi-gtk

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

[maintain] [Publish]

This package provides a a reflex host and helper functions to create reactive GUI applications using gi-gtk and reflex.

[Skip to Readme]


Change log
Dependencies async (>=2.2.2 && <2.3), base (>=4.13 && <4.14), containers (>=0.6.2 && <0.7), dependent-sum (>=0.7.1 && <0.8), exception-transformers (>=0.4 && <0.5), gi-gdk (>=3.0 && <3.1), gi-glib (>=2.0 && <2.1), gi-gtk (>=3.0 && <3.1), haskell-gi-base (>=0.24.5 && <0.25), mtl (>=2.2.2 && <2.3), patch (>=0.0 && <0.1), primitive (>=0.7 && <0.8), ref-tf (>=0.4 && <0.5), reflex (>=0.8 && <0.9), reflex-gi-gtk, semialign (>=1.1 && <1.2), stm (>=2.5 && <2.6), text (>=1.2.4 && <1.3), these (>=1.1.1 && <1.2), witherable (>=0.3.5 && <0.4) [details]
License MPL-2.0
Copyright 2020 Sven Bartscher
Author Sven Bartscher
Category FRP
Home page
Source repo head: git clone
Uploaded by Kritzefitz at 2021-01-05T21:00:45Z


[Index] [Quick Jump]


Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Readme for reflex-gi-gtk-

[back to package description]


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.


The package can be compiled with stack using the shipped stack.yaml as follows:

$ stack install

The build process has mostly been tested using stack, but it should also work using cabal-install or other standard Cabal-based package managers.

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 -> labelGetText 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.