packages feed

notifications-tray-icon-0.2.0.0: src/StatusNotifier/Item/Notifications/OverlayIcon.hs

module StatusNotifier.Item.Notifications.OverlayIcon where

import           Control.Concurrent
import           Control.Monad
import           Control.Monad.Trans.Class
import           Control.Monad.Trans.Except
import           DBus
import           DBus.Client
import           DBus.Proxy
import qualified DBus.TH as DBusTH
import qualified Data.ByteString as BS
import           Data.Int
import           Data.String
import qualified Data.Text as T
import           GI.Dbusmenu
import qualified GI.GLib as GLib
import qualified GI.Gio as Gio
import qualified StatusNotifier.Item.Client as I
import           StatusNotifier.Item.Notifications.Util
import qualified StatusNotifier.Watcher.Client as W
import           System.Log.Logger
import qualified GI.Gio.Objects.Cancellable

type UpdateNotifications = Int -> Menuitem -> IO ()

data OverlayIconParams = OverlayIconParams
  { iconName :: String
  , iconPath :: String
  , iconDBusName :: String
  , iconThemePath :: Maybe String
  , getOverlayName :: Int -> IO T.Text
  , runUpdater :: UpdateNotifications -> IO ()
  }

overlayLog = logM "StatusNotifier.Item.Notifications.OverlayIcon"

buildOverlayIcon OverlayIconParams
                   { iconName = name
                   , iconPath = path
                   , iconDBusName = dbusName
                   , iconThemePath = maybeThemePath
                   , getOverlayName = getOverlayIconName
                   , runUpdater = startNotifications
                   } = do
  let menuPathString = path ++ "/Menu"
      menuBusString = dbusName ++ ".Menu"
      menuPathText = T.pack menuPathString
      menuBusText = T.pack menuBusString
      iconObjectPath = objectPath_ path

  client <- connectSession

  notificationCount <- newMVar 0
  root <- menuitemNew
  currentRoot <- newMVar root

  connection <- Just <$> GI.Gio.Objects.Cancellable.cancellableNew >>=
                Gio.busGetSync Gio.BusTypeSession
  Gio.busOwnNameOnConnection connection menuBusText [] Nothing Nothing
  menuServer <- serverNew menuPathText

  mainLoop <- GLib.mainLoopNew Nothing False >>= GLib.mainLoopRef
  forkIO $ GLib.mainLoopRun mainLoop
  context <- GLib.mainLoopGetContext mainLoop

  let runOnMain action =
        GLib.mainContextInvokeFull (Just context) 4 $ action >> return False
      setRoot newRoot = runOnMain $ do
          overlayLog DEBUG "Setting new root"
          modifyMVar_ currentRoot $ const $ return newRoot
          serverSetRoot menuServer newRoot
          return False
      updateOverlayCount count = do
        modifyMVar_ notificationCount $ const $ return count
        I.emitNewOverlayIcon client iconObjectPath
      updateNotifications count newRoot = void $
        updateOverlayCount count >> setRoot newRoot
      proxyMenu =
        proxyAll client
                   (busName_ menuBusString)
                   (objectPath_ menuPathString)
                   (objectPath_ menuPathString)
      themePathProps = case maybeThemePath of
        Just tp -> [readOnlyProperty "IconThemePath" $ return tp]
        Nothing -> []
      clientInterface =
        Interface { interfaceName = "org.kde.StatusNotifierItem"
                  , interfaceMethods = []
                  , interfaceProperties =
                    [ readOnlyProperty "IconName" $ return name
                    , readOnlyProperty "OverlayIconName" $
                      readMVar notificationCount >>= getOverlayIconName
                    , readOnlyProperty "Menu" $ return $ objectPath_ menuPathString
                    ] ++ themePathProps
                  , interfaceSignals = []
                  }

  export client (fromString path) clientInterface
  requestName client (busName_ dbusName) []

  startNotifications updateNotifications
  proxyMenu

  void $ W.registerStatusNotifierItem client dbusName

sampleUpdater update = void $ forkIO $ forever $ do
  root <- menuitemNew
  child1 <- makeMenuItemWithLabel "child"
  menuitemChildAppend root child1
  update 3 root
  threadDelay 100000000