packages feed

gi-gtk-declarative-app-simple 0.2.0 → 0.3.0

raw patch · 3 files changed

+34/−17 lines, 3 filesdep ~base

Dependency ranges changed: base

Files

CHANGELOG.md view
@@ -1,3 +1,5 @@+* 0.3.0+    - Return last state from `run` and `runLoop` * 0.2.0     - Require GTK+ windows as top-level widget * 0.1.0
gi-gtk-declarative-app-simple.cabal view
@@ -1,5 +1,5 @@ name:                 gi-gtk-declarative-app-simple-version:              0.2.0+version:              0.3.0 synopsis:             Declarative GTK+ programming in Haskell in the style of Pux. description:          Experimental application architecture in the style of                       PureScript Pux, built on top of gi-gtk-declarative. Learn@@ -13,10 +13,11 @@ build-type:           Simple cabal-version:        >=1.10 extra-source-files:   CHANGELOG.md+tested-with:          GHC == 8.6.3  library   exposed-modules:      GI.Gtk.Declarative.App.Simple-  build-depends:        base                    >=4.10    && <4.12+  build-depends:        base                    >=4.10    && <5                       , async                       , gi-gobject              >= 2      && <3                       , gi-glib
src/GI/Gtk/Declarative/App/Simple.hs view
@@ -1,4 +1,6 @@-{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE LambdaCase       #-}+{-# LANGUAGE RecordWildCards  #-}  -- | A simple application architecture style inspired by PureScript's Pux -- framework.@@ -12,26 +14,28 @@ where  import           Control.Concurrent-import           Control.Concurrent.Async       (async)+import qualified Control.Concurrent.Async       as Async+import           Control.Exception              (Exception, throw) import           Control.Monad import           Data.Typeable import qualified GI.Gdk                         as Gdk import qualified GI.GLib.Constants              as GLib import qualified GI.Gtk                         as Gtk import           GI.Gtk.Declarative+import           GI.Gtk.Declarative.Bin import           GI.Gtk.Declarative.EventSource import           GI.Gtk.Declarative.State import           Pipes import           Pipes.Concurrent  -- | Describes an state reducer application.-data App state event =+data App window state event =   App     { update       :: state -> event -> Transition state event     -- ^ The update function of an application reduces the current state and     -- a new event to a 'Transition', which decides if and how to transition     -- to the next state.-    , view         :: state -> AppView event+    , view         :: state -> AppView window event     -- ^ The view renders a state value as a window, parameterized by the     -- 'App's event type.     , inputs       :: [Producer event IO ()]@@ -42,7 +46,7 @@  -- | The top-level widget for the 'view' function of an 'App', -- requiring a GTK+ 'Window'.-type AppView event = Bin Gtk.Window Widget event+type AppView window event = Bin window Widget event  -- | The result of applying the 'update' function, deciding if and how to -- transition to the next state.@@ -53,20 +57,30 @@   -- | Exit the application.   | Exit +-- | An exception thrown by the 'run' function when gtk's main loop exits+-- before event/state handling which should never happen but can be caused+-- by user code calling 'Gtk.mainQuit'+data GtkMainExitedException =+  GtkMainExitedException String deriving (Typeable, Show)++instance Exception GtkMainExitedException+ -- | Initialize GTK and run the application in it. This is a -- convenience function that is highly recommended. If you need more -- flexibility, e.g. to set up GTK+ yourself, use 'runLoop' instead. run-  :: Typeable event-  => App state event      -- ^ Application to run-  -> IO ()+  :: (Typeable event, BinChild window Widget)+  => App window state event      -- ^ Application to run+  -> IO state run app = do   void $ Gtk.init Nothing-  void . async $ do-    runLoop app-    -- In case the run loop exits, quit the main GTK loop.-    Gtk.mainQuit-  Gtk.main+  Async.withAsync (runLoop app <* Gtk.mainQuit) $ \lastState -> do+    Gtk.main+    Async.poll lastState >>= \case+      Nothing -> throw $+        GtkMainExitedException "gtk's main loop exited unexpectedly"+      Just (Right state) -> return state+      Just (Left exception) -> throw exception  -- | Run an 'App'. This IO action will loop, so run it in a separate thread -- using 'async' if you're calling it before the GTK main loop.@@ -79,7 +93,7 @@ --       Gtk.mainQuit --     Gtk.main -- @-runLoop :: Typeable event => App state event -> IO ()+runLoop :: (Typeable event, BinChild window Widget) => App window state event -> IO state runLoop App {..} = do   let firstMarkup = view initialState   events                  <- newChan@@ -124,7 +138,7 @@            -- Finally, we loop.           loop newState newMarkup events sub newModel-        Exit -> return ()+        Exit -> return oldModel  publishEvent :: Chan event -> event -> IO () publishEvent mvar = void . writeChan mvar