packages feed

helic-0.6.0.0: lib/Helic/GtkMain.hs

-- |API for the GTK main loop.
module Helic.GtkMain where

import Conc (withAsync_)
import Exon (exon)
import qualified Log

import qualified Helic.Effect.Gtk as Gtk
import Helic.Effect.Gtk (Gtk)
import qualified Helic.Effect.GtkMain as GtkMain
import Helic.Effect.GtkMain (GtkMain)

-- |Run the GTK main loop.
-- Before that, initialize the GTK client environment, store the default display in the state of 'GtkMain', and execute
-- the user-supplied initialization action.
gtkMain ::
  Members [Scoped_ (Gtk s), GtkMain s, Resource] r =>
  Sem r () ->
  Sem r ()
gtkMain onInit =
  scoped_ do
    GtkMain.running =<< Gtk.resource
    raise onInit
    Gtk.main

-- |Run the GTK main loop in an infinite loop, recovering from errors by logging them.
-- After the loop has failed or was terminated, the default implementation waits for 10 seconds before restarting it,
-- but can be forced to start when a consumer tries to use it.
loopGtkMain ::
  Members [Scoped_ (Gtk s) !! Text, GtkMain s, Resource, Log] r =>
  Sem r () ->
  Sem r ()
loopGtkMain onInit =
  forever do
    GtkMain.run do
      gtkMain @_ @(Scoped_ (Gtk _) : _) (raise onInit) !! \ e ->
        Log.error [exon|Gtk main loop failed: #{e}|]

-- |Acquire a GTK resource by first examining the value currently stored in 'GtkMain', and if there is none, requesting
-- the GTK main loop to be started.
gtkResource ::
  Members [GtkMain s, Log, Stop Text] r =>
  Sem r s
gtkResource =
  GtkMain.access do
    Log.info "Gtk main loop inactive, requesting restart"
    GtkMain.request (stop "Gtk main loop didn't start") <* Log.info "Gtk main loop started"

-- |Run 'loopGtkMain' in a thread.
gtkMainLoop ::
  Members [Scoped_ (Gtk s) !! Text, GtkMain s, Log, Race, Resource, Async] r =>
  Sem r () ->
  Sem r a ->
  Sem r a
gtkMainLoop onInit =
  withAsync_ (loopGtkMain onInit)