packages feed

systranything-0.1.3.0: lib/Model/Indicator.hs

{-# LANGUAGE TemplateHaskell #-}

module Model.Indicator (Indicator (..), newIndicator) where

import Control.Monad (void, when)
import Data.Aeson.TH (deriveJSON)
import Data.Foldable (traverse_)
import Data.IORef (newIORef, readIORef, writeIORef)
import Data.Text (Text)
import GHC.Generics (Generic)
import GI.AyatanaAppIndicator3 qualified as AI
import GI.Gdk qualified as Gdk
import GI.Gtk qualified as Gtk
import Model.Command (Command, periodicallyUpdateIcon)
import Model.Common (runCommand)
import Model.Internal (options)

data Indicator = MkIndicator
  { inIcon :: Text,
    inCommand :: Maybe Command,
    inOnScrollUp :: Maybe Text,
    inOnScrollDown :: Maybe Text
  }
  deriving stock (Eq, Generic, Show)

$(deriveJSON options ''Indicator)

newIndicator :: Bool -> Indicator -> Maybe Gtk.Menu -> IO AI.Indicator
newIndicator verbose indicator@MkIndicator {..} menu = do
  gtkIndicator <-
    AI.indicatorNew
      "systranything"
      inIcon
      AI.IndicatorCategorySystemServices

  -- The indicator beeing not active by default means it is hidden
  AI.indicatorSetStatus gtkIndicator AI.IndicatorStatusActive
  AI.indicatorSetMenu gtkIndicator menu

  traverse_ (periodicallyUpdateIcon False gtkIndicator inIcon) inCommand

  onScrollEvent verbose gtkIndicator indicator

  pure gtkIndicator

onScrollEvent :: Bool -> AI.Indicator -> Indicator -> IO ()
onScrollEvent verbose indicator (MkIndicator {..}) = do
  -- GTK sends one scroll up or down event followed by smooth events. Getting
  -- the actual direction from smooth requires to access the scroll event
  -- itself which doesn't seem possible with the current version of
  -- libayarana-appindicator

  refDirection <- newIORef Gdk.ScrollDirectionDown

  void $ Gtk.on indicator #scrollEvent $ \_ direction -> do
    when (direction /= Gdk.ScrollDirectionSmooth) $ do
      writeIORef refDirection direction

    lastDirection <- readIORef refDirection

    traverse_ (runCommand verbose) $
      if lastDirection == Gdk.ScrollDirectionDown
        then inOnScrollDown
        else inOnScrollUp