{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MonoLocalBinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ImpredicativeTypes #-}
module System.Taffybar.Context
(
TaffybarConfig(..)
, defaultTaffybarConfig
, appendHook
, BarConfig(..)
, BarConfigGetter
, showBarId
, Taffy
, TaffyIO
, Context(..)
, buildContext
, buildEmptyContext
, getState
, getStateDefault
, putState
, refreshTaffyWindows
, exitTaffybar
, runX11
, runX11Def
, subscribeToAll
, subscribeToPropertyEvents
, unsubscribe
, taffyFork
) where
import Control.Arrow ((&&&), (***))
import Control.Concurrent (forkIO)
import qualified Control.Concurrent.MVar as MV
import Control.Exception.Enclosed (catchAny)
import Control.Monad
import Control.Monad.IO.Class
import Control.Monad.Trans.Class
import Control.Monad.Trans.Maybe
import Control.Monad.Trans.Reader
import qualified DBus.Client as DBus
import Data.Data
import Data.Default (Default(..))
import Data.GI.Base.ManagedPtr (unsafeCastTo)
import Data.Int
import Data.List
import qualified Data.Map as M
import qualified Data.Text as T
import Data.Tuple.Select
import Data.Tuple.Sequence
import Data.Unique
import qualified GI.Gdk
import qualified GI.GdkX11 as GdkX11
import GI.GdkX11.Objects.X11Window
import qualified GI.Gtk as Gtk
import Graphics.UI.GIGtkStrut
import StatusNotifier.TransparentWindow
import System.Log.Logger (Priority(..), logM)
import System.Taffybar.Information.SafeX11
import System.Taffybar.Information.X11DesktopInfo
import System.Taffybar.Util
import System.Taffybar.Widget.Util
import Text.Printf
import Unsafe.Coerce
logIO :: Priority -> String -> IO ()
logIO :: Priority -> String -> IO ()
logIO = String -> Priority -> String -> IO ()
logM String
"System.Taffybar.Context"
logC :: MonadIO m => Priority -> String -> m ()
logC :: forall (m :: * -> *). MonadIO m => Priority -> String -> m ()
logC Priority
p = IO () -> m ()
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (String -> IO ()) -> String -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Priority -> String -> IO ()
logIO Priority
p
type Taffy m v = ReaderT Context m v
type TaffyIO v = ReaderT Context IO v
type Listener = Event -> Taffy IO ()
type SubscriptionList = [(Unique, Listener)]
data Value = forall t. Typeable t => Value t
fromValue :: forall t. Typeable t => Value -> Maybe t
fromValue :: forall t. Typeable t => Value -> Maybe t
fromValue (Value t
v) =
if t -> TypeRep
forall a. Typeable a => a -> TypeRep
typeOf t
v TypeRep -> TypeRep -> Bool
forall a. Eq a => a -> a -> Bool
== Proxy t -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy t
forall {k} (t :: k). Proxy t
Proxy :: Proxy t) then
t -> Maybe t
forall a. a -> Maybe a
Just (t -> Maybe t) -> t -> Maybe t
forall a b. (a -> b) -> a -> b
$ t -> t
forall a b. a -> b
unsafeCoerce t
v
else
Maybe t
forall a. Maybe a
Nothing
data BarConfig = BarConfig
{
BarConfig -> StrutConfig
strutConfig :: StrutConfig
, BarConfig -> Int32
widgetSpacing :: Int32
, BarConfig -> [TaffyIO Widget]
startWidgets :: [TaffyIO Gtk.Widget]
, BarConfig -> [TaffyIO Widget]
centerWidgets :: [TaffyIO Gtk.Widget]
, BarConfig -> [TaffyIO Widget]
endWidgets :: [TaffyIO Gtk.Widget]
, BarConfig -> Unique
barId :: Unique
}
instance Eq BarConfig where
BarConfig
a == :: BarConfig -> BarConfig -> Bool
== BarConfig
b = BarConfig -> Unique
barId BarConfig
a Unique -> Unique -> Bool
forall a. Eq a => a -> a -> Bool
== BarConfig -> Unique
barId BarConfig
b
type BarConfigGetter = TaffyIO [BarConfig]
data TaffybarConfig = TaffybarConfig
{
TaffybarConfig -> Maybe Client
dbusClientParam :: Maybe DBus.Client
, TaffybarConfig -> TaffyIO ()
startupHook :: TaffyIO ()
, TaffybarConfig -> BarConfigGetter
getBarConfigsParam :: BarConfigGetter
, TaffybarConfig -> [String]
cssPaths :: [FilePath]
, TaffybarConfig -> Maybe String
errorMsg :: Maybe String
}
appendHook :: TaffyIO () -> TaffybarConfig -> TaffybarConfig
appendHook :: TaffyIO () -> TaffybarConfig -> TaffybarConfig
appendHook TaffyIO ()
hook TaffybarConfig
config = TaffybarConfig
config
{ startupHook = startupHook config >> hook }
defaultTaffybarConfig :: TaffybarConfig
defaultTaffybarConfig :: TaffybarConfig
defaultTaffybarConfig = TaffybarConfig
{ dbusClientParam :: Maybe Client
dbusClientParam = Maybe Client
forall a. Maybe a
Nothing
, startupHook :: TaffyIO ()
startupHook = () -> TaffyIO ()
forall a. a -> ReaderT Context IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
, getBarConfigsParam :: BarConfigGetter
getBarConfigsParam = [BarConfig] -> BarConfigGetter
forall a. a -> ReaderT Context IO a
forall (m :: * -> *) a. Monad m => a -> m a
return []
, cssPaths :: [String]
cssPaths = []
, errorMsg :: Maybe String
errorMsg = Maybe String
forall a. Maybe a
Nothing
}
instance Default TaffybarConfig where
def :: TaffybarConfig
def = TaffybarConfig
defaultTaffybarConfig
data Context = Context
{
Context -> MVar X11Context
x11ContextVar :: MV.MVar X11Context
, Context -> MVar SubscriptionList
listeners :: MV.MVar SubscriptionList
, Context -> MVar (Map TypeRep Value)
contextState :: MV.MVar (M.Map TypeRep Value)
, Context -> MVar [(BarConfig, Window)]
existingWindows :: MV.MVar [(BarConfig, Gtk.Window)]
, Context -> Client
sessionDBusClient :: DBus.Client
, Context -> Client
systemDBusClient :: DBus.Client
, Context -> BarConfigGetter
getBarConfigs :: BarConfigGetter
, Context -> Maybe BarConfig
contextBarConfig :: Maybe BarConfig
}
buildContext :: TaffybarConfig -> IO Context
buildContext :: TaffybarConfig -> IO Context
buildContext TaffybarConfig
{ dbusClientParam :: TaffybarConfig -> Maybe Client
dbusClientParam = Maybe Client
maybeDBus
, getBarConfigsParam :: TaffybarConfig -> BarConfigGetter
getBarConfigsParam = BarConfigGetter
barConfigGetter
, startupHook :: TaffybarConfig -> TaffyIO ()
startupHook = TaffyIO ()
startup
} = do
Priority -> String -> IO ()
logIO Priority
DEBUG String
"Building context"
dbusC <- IO Client -> (Client -> IO Client) -> Maybe Client -> IO Client
forall b a. b -> (a -> b) -> Maybe a -> b
maybe IO Client
DBus.connectSession Client -> IO Client
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Client
maybeDBus
sDBusC <- DBus.connectSystem
_ <- DBus.requestName dbusC "org.taffybar.Bar"
[DBus.nameAllowReplacement, DBus.nameReplaceExisting]
listenersVar <- MV.newMVar []
state <- MV.newMVar M.empty
x11Context <- getX11Context def >>= MV.newMVar
windowsVar <- MV.newMVar []
let context = Context
{ x11ContextVar :: MVar X11Context
x11ContextVar = MVar X11Context
x11Context
, listeners :: MVar SubscriptionList
listeners = MVar SubscriptionList
listenersVar
, contextState :: MVar (Map TypeRep Value)
contextState = MVar (Map TypeRep Value)
state
, sessionDBusClient :: Client
sessionDBusClient = Client
dbusC
, systemDBusClient :: Client
systemDBusClient = Client
sDBusC
, getBarConfigs :: BarConfigGetter
getBarConfigs = BarConfigGetter
barConfigGetter
, existingWindows :: MVar [(BarConfig, Window)]
existingWindows = MVar [(BarConfig, Window)]
windowsVar
, contextBarConfig :: Maybe BarConfig
contextBarConfig = Maybe BarConfig
forall a. Maybe a
Nothing
}
_ <- runMaybeT $ MaybeT GI.Gdk.displayGetDefault >>=
(lift . GI.Gdk.displayGetDefaultScreen) >>=
(lift . flip GI.Gdk.afterScreenMonitorsChanged
(runReaderT forceRefreshTaffyWindows context))
flip runReaderT context $ do
logC DEBUG "Starting X11 Handler"
startX11EventHandler
logC DEBUG "Running startup hook"
startup
logC DEBUG "Queing build windows command"
refreshTaffyWindows
logIO DEBUG "Context build finished"
return context
buildEmptyContext :: IO Context
buildEmptyContext :: IO Context
buildEmptyContext = TaffybarConfig -> IO Context
buildContext TaffybarConfig
forall a. Default a => a
def
showBarId :: BarConfig -> String
showBarId :: BarConfig -> String
showBarId = Int -> String
forall a. Show a => a -> String
show (Int -> String) -> (BarConfig -> Int) -> BarConfig -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Unique -> Int
hashUnique (Unique -> Int) -> (BarConfig -> Unique) -> BarConfig -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BarConfig -> Unique
barId
buildBarWindow :: Context -> BarConfig -> IO Gtk.Window
buildBarWindow :: Context -> BarConfig -> IO Window
buildBarWindow Context
context BarConfig
barConfig = do
let thisContext :: Context
thisContext = Context
context { contextBarConfig = Just barConfig }
Priority -> String -> IO ()
forall (m :: * -> *). MonadIO m => Priority -> String -> m ()
logC Priority
INFO (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$
String -> String -> String -> String
forall r. PrintfType r => String -> r
printf String
"Building window for Taffybar(id=%s) with %s"
(BarConfig -> String
showBarId BarConfig
barConfig)
(StrutConfig -> String
forall a. Show a => a -> String
show (StrutConfig -> String) -> StrutConfig -> String
forall a b. (a -> b) -> a -> b
$ BarConfig -> StrutConfig
strutConfig BarConfig
barConfig)
window <- WindowType -> IO Window
forall (m :: * -> *).
(HasCallStack, MonadIO m) =>
WindowType -> m Window
Gtk.windowNew WindowType
Gtk.WindowTypeToplevel
void $ Gtk.onWidgetDestroy window $ do
let bId = BarConfig -> String
showBarId BarConfig
barConfig
logC INFO $ printf "Window for Taffybar(id=%s) destroyed" bId
MV.modifyMVar_ (existingWindows context) (pure . filter ((/=) window . sel2))
logC DEBUG $ printf "Window for Taffybar(id=%s) unregistered" bId
box <- Gtk.boxNew Gtk.OrientationHorizontal $ fromIntegral $
widgetSpacing barConfig
_ <- widgetSetClassGI box "taffy-box"
centerBox <- Gtk.boxNew Gtk.OrientationHorizontal $
fromIntegral $ widgetSpacing barConfig
_ <- widgetSetClassGI centerBox "center-box"
Gtk.widgetSetVexpand centerBox True
Gtk.setWidgetValign centerBox Gtk.AlignFill
Gtk.setWidgetHalign centerBox Gtk.AlignCenter
Gtk.boxSetCenterWidget box (Just centerBox)
setupStrutWindow (strutConfig barConfig) window
Gtk.containerAdd window box
_ <- widgetSetClassGI window "taffy-window"
let addWidgetWith Int -> Widget -> IO ()
widgetAdd (Int
count, TaffyIO Widget
buildWidget) =
TaffyIO Widget -> Context -> IO Widget
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT TaffyIO Widget
buildWidget Context
thisContext IO Widget -> (Widget -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Int -> Widget -> IO ()
widgetAdd Int
count
addToStart Int
count Widget
widget = do
_ <- Widget -> Text -> IO Widget
forall b (m :: * -> *). (IsWidget b, MonadIO m) => b -> Text -> m b
widgetSetClassGI Widget
widget (Text -> IO Widget) -> Text -> IO Widget
forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ String -> Int -> String
forall r. PrintfType r => String -> r
printf String
"left-%d" (Int
count :: Int)
Gtk.boxPackStart box widget False False 0
addToEnd Int
count Widget
widget = do
_ <- Widget -> Text -> IO Widget
forall b (m :: * -> *). (IsWidget b, MonadIO m) => b -> Text -> m b
widgetSetClassGI Widget
widget (Text -> IO Widget) -> Text -> IO Widget
forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ String -> Int -> String
forall r. PrintfType r => String -> r
printf String
"right-%d" (Int
count :: Int)
Gtk.boxPackEnd box widget False False 0
addToCenter Int
count Widget
widget = do
_ <- Widget -> Text -> IO Widget
forall b (m :: * -> *). (IsWidget b, MonadIO m) => b -> Text -> m b
widgetSetClassGI Widget
widget (Text -> IO Widget) -> Text -> IO Widget
forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ String -> Int -> String
forall r. PrintfType r => String -> r
printf String
"center-%d" (Int
count :: Int)
Gtk.boxPackStart centerBox widget False False 0
logIO DEBUG "Building start widgets"
mapM_ (addWidgetWith addToStart) $ zip [1..] (startWidgets barConfig)
logIO DEBUG "Building center widgets"
mapM_ (addWidgetWith addToCenter) $ zip [1..] (centerWidgets barConfig)
logIO DEBUG "Building end widgets"
mapM_ (addWidgetWith addToEnd) $ zip [1..] (endWidgets barConfig)
makeWindowTransparent window
logIO DEBUG "Showing window"
Gtk.widgetShow window
Gtk.widgetShow box
Gtk.widgetShow centerBox
runX11Context context () $ void $ runMaybeT $ do
gdkWindow <- MaybeT $ Gtk.widgetGetWindow window
xid <- GdkX11.x11WindowGetXid =<< liftIO (unsafeCastTo X11Window gdkWindow)
logC DEBUG $ printf "Lowering X11 window %s" $ show xid
lift $ doLowerWindow (fromIntegral xid)
return window
refreshTaffyWindows :: TaffyIO ()
refreshTaffyWindows :: TaffyIO ()
refreshTaffyWindows = (IO () -> IO ()) -> TaffyIO () -> TaffyIO ()
forall (m :: * -> *) a (n :: * -> *) b r.
(m a -> n b) -> ReaderT r m a -> ReaderT r n b
mapReaderT IO () -> IO ()
postGUIASync (TaffyIO () -> TaffyIO ()) -> TaffyIO () -> TaffyIO ()
forall a b. (a -> b) -> a -> b
$ do
Priority -> String -> TaffyIO ()
forall (m :: * -> *). MonadIO m => Priority -> String -> m ()
logC Priority
DEBUG String
"Refreshing windows"
ctx <- ReaderT Context IO Context
forall (m :: * -> *) r. Monad m => ReaderT r m r
ask
windowsVar <- asks existingWindows
let rebuildWindows [(BarConfig, Window)]
currentWindows = (ReaderT Context IO [(BarConfig, Window)]
-> Context -> IO [(BarConfig, Window)])
-> Context
-> ReaderT Context IO [(BarConfig, Window)]
-> IO [(BarConfig, Window)]
forall a b c. (a -> b -> c) -> b -> a -> c
flip ReaderT Context IO [(BarConfig, Window)]
-> Context -> IO [(BarConfig, Window)]
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT Context
ctx (ReaderT Context IO [(BarConfig, Window)]
-> IO [(BarConfig, Window)])
-> ReaderT Context IO [(BarConfig, Window)]
-> IO [(BarConfig, Window)]
forall a b. (a -> b) -> a -> b
$
do
barConfigs <- ReaderT Context IO BarConfigGetter -> BarConfigGetter
forall (m :: * -> *) a. Monad m => m (m a) -> m a
join (ReaderT Context IO BarConfigGetter -> BarConfigGetter)
-> ReaderT Context IO BarConfigGetter -> BarConfigGetter
forall a b. (a -> b) -> a -> b
$ (Context -> BarConfigGetter) -> ReaderT Context IO BarConfigGetter
forall (m :: * -> *) r a. Monad m => (r -> a) -> ReaderT r m a
asks Context -> BarConfigGetter
getBarConfigs
let currentConfigs = ((BarConfig, Window) -> BarConfig)
-> [(BarConfig, Window)] -> [BarConfig]
forall a b. (a -> b) -> [a] -> [b]
map (BarConfig, Window) -> BarConfig
forall a b. Sel1 a b => a -> b
sel1 [(BarConfig, Window)]
currentWindows
newConfs = (BarConfig -> Bool) -> [BarConfig] -> [BarConfig]
forall a. (a -> Bool) -> [a] -> [a]
filter (BarConfig -> [BarConfig] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [BarConfig]
currentConfigs) [BarConfig]
barConfigs
(remainingWindows, removedWindows) =
partition ((`elem` barConfigs) . sel1) currentWindows
setPropertiesFromPair (BarConfig
barConf, Window
window) =
StrutConfig -> Window -> m ()
forall (m :: * -> *).
(MonadFail m, MonadIO m) =>
StrutConfig -> Window -> m ()
setupStrutWindow (BarConfig -> StrutConfig
strutConfig BarConfig
barConf) Window
window
newWindowPairs <- lift $ do
logIO DEBUG $ printf "removedWindows: %s" $
show $ map (strutConfig . sel1) removedWindows
logIO DEBUG $ printf "remainingWindows: %s" $
show $ map (strutConfig . sel1) remainingWindows
logIO DEBUG $ printf "newWindows: %s" $
show $ map strutConfig newConfs
logIO DEBUG $ printf "barConfigs: %s" $
show $ map strutConfig barConfigs
logIO DEBUG "Removing windows"
mapM_ (Gtk.widgetDestroy . sel2) removedWindows
logIO DEBUG "Updating strut properties for existing windows"
mapM_ setPropertiesFromPair remainingWindows
logIO DEBUG "Constructing new windows"
mapM (sequenceT . ((return :: a -> IO a) &&& buildBarWindow ctx))
newConfs
return $ newWindowPairs ++ remainingWindows
lift $ MV.modifyMVar_ windowsVar rebuildWindows
logC DEBUG "Finished refreshing windows"
return ()
removeTaffyWindows :: TaffyIO ()
removeTaffyWindows :: TaffyIO ()
removeTaffyWindows = (Context -> MVar [(BarConfig, Window)])
-> ReaderT Context IO (MVar [(BarConfig, Window)])
forall (m :: * -> *) r a. Monad m => (r -> a) -> ReaderT r m a
asks Context -> MVar [(BarConfig, Window)]
existingWindows ReaderT Context IO (MVar [(BarConfig, Window)])
-> (MVar [(BarConfig, Window)]
-> ReaderT Context IO [(BarConfig, Window)])
-> ReaderT Context IO [(BarConfig, Window)]
forall a b.
ReaderT Context IO a
-> (a -> ReaderT Context IO b) -> ReaderT Context IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IO [(BarConfig, Window)]
-> ReaderT Context IO [(BarConfig, Window)]
forall a. IO a -> ReaderT Context IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO [(BarConfig, Window)]
-> ReaderT Context IO [(BarConfig, Window)])
-> (MVar [(BarConfig, Window)] -> IO [(BarConfig, Window)])
-> MVar [(BarConfig, Window)]
-> ReaderT Context IO [(BarConfig, Window)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MVar [(BarConfig, Window)] -> IO [(BarConfig, Window)]
forall a. MVar a -> IO a
MV.readMVar ReaderT Context IO [(BarConfig, Window)]
-> ([(BarConfig, Window)] -> TaffyIO ()) -> TaffyIO ()
forall a b.
ReaderT Context IO a
-> (a -> ReaderT Context IO b) -> ReaderT Context IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= [(BarConfig, Window)] -> TaffyIO ()
deleteWindows
where
deleteWindows :: [(BarConfig, Window)] -> TaffyIO ()
deleteWindows = ((BarConfig, Window) -> ReaderT Context IO ((), ()))
-> [(BarConfig, Window)] -> TaffyIO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ ((TaffyIO (), TaffyIO ()) -> ReaderT Context IO ((), ())
forall a b. SequenceT a b => a -> b
sequenceT ((TaffyIO (), TaffyIO ()) -> ReaderT Context IO ((), ()))
-> ((BarConfig, Window) -> (TaffyIO (), TaffyIO ()))
-> (BarConfig, Window)
-> ReaderT Context IO ((), ())
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (BarConfig -> TaffyIO ()
msg (BarConfig -> TaffyIO ())
-> (Window -> TaffyIO ())
-> (BarConfig, Window)
-> (TaffyIO (), TaffyIO ())
forall b c b' c'. (b -> c) -> (b' -> c') -> (b, b') -> (c, c')
forall (a :: * -> * -> *) b c b' c'.
Arrow a =>
a b c -> a b' c' -> a (b, b') (c, c')
*** Window -> TaffyIO ()
del))
msg :: BarConfig -> TaffyIO ()
msg :: BarConfig -> TaffyIO ()
msg BarConfig
barConfig = Priority -> String -> TaffyIO ()
forall (m :: * -> *). MonadIO m => Priority -> String -> m ()
logC Priority
INFO (String -> TaffyIO ()) -> String -> TaffyIO ()
forall a b. (a -> b) -> a -> b
$
String -> String -> String
forall r. PrintfType r => String -> r
printf String
"Destroying window for Taffybar(id=%s)" (BarConfig -> String
showBarId BarConfig
barConfig)
del :: Gtk.Window -> TaffyIO ()
del :: Window -> TaffyIO ()
del = Window -> TaffyIO ()
forall (m :: * -> *) a.
(HasCallStack, MonadIO m, IsWidget a) =>
a -> m ()
Gtk.widgetDestroy
forceRefreshTaffyWindows :: TaffyIO ()
forceRefreshTaffyWindows :: TaffyIO ()
forceRefreshTaffyWindows = TaffyIO ()
removeTaffyWindows TaffyIO () -> TaffyIO () -> TaffyIO ()
forall a b.
ReaderT Context IO a
-> ReaderT Context IO b -> ReaderT Context IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> TaffyIO ()
refreshTaffyWindows
exitTaffybar :: Context -> IO ()
exitTaffybar :: Context -> IO ()
exitTaffybar Context
ctx = do
IO () -> IO ()
postGUIASync (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ TaffyIO () -> Context -> IO ()
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT TaffyIO ()
removeTaffyWindows Context
ctx
IO ()
forall (m :: * -> *). (HasCallStack, MonadIO m) => m ()
Gtk.mainQuit
asksContextVar :: (r -> MV.MVar b) -> ReaderT r IO b
asksContextVar :: forall r b. (r -> MVar b) -> ReaderT r IO b
asksContextVar r -> MVar b
getter = (r -> MVar b) -> ReaderT r IO (MVar b)
forall (m :: * -> *) r a. Monad m => (r -> a) -> ReaderT r m a
asks r -> MVar b
getter ReaderT r IO (MVar b)
-> (MVar b -> ReaderT r IO b) -> ReaderT r IO b
forall a b.
ReaderT r IO a -> (a -> ReaderT r IO b) -> ReaderT r IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IO b -> ReaderT r IO b
forall (m :: * -> *) a. Monad m => m a -> ReaderT r m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO b -> ReaderT r IO b)
-> (MVar b -> IO b) -> MVar b -> ReaderT r IO b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MVar b -> IO b
forall a. MVar a -> IO a
MV.readMVar
runX11 :: X11Property a -> TaffyIO a
runX11 :: forall a. X11Property a -> TaffyIO a
runX11 X11Property a
action =
(Context -> MVar X11Context) -> ReaderT Context IO X11Context
forall r b. (r -> MVar b) -> ReaderT r IO b
asksContextVar Context -> MVar X11Context
x11ContextVar ReaderT Context IO X11Context
-> (X11Context -> ReaderT Context IO a) -> ReaderT Context IO a
forall a b.
ReaderT Context IO a
-> (a -> ReaderT Context IO b) -> ReaderT Context IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= IO a -> ReaderT Context IO a
forall (m :: * -> *) a. Monad m => m a -> ReaderT Context m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO a -> ReaderT Context IO a)
-> (X11Context -> IO a) -> X11Context -> ReaderT Context IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. X11Property a -> X11Context -> IO a
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT X11Property a
action
runX11Def :: a -> X11Property a -> TaffyIO a
runX11Def :: forall a. a -> X11Property a -> TaffyIO a
runX11Def a
dflt X11Property a
prop = X11Property a -> TaffyIO a
forall a. X11Property a -> TaffyIO a
runX11 (X11Property a -> TaffyIO a) -> X11Property a -> TaffyIO a
forall a b. (a -> b) -> a -> b
$ X11Property a -> a -> X11Property a
forall a. X11Property a -> a -> X11Property a
postX11RequestSyncProp X11Property a
prop a
dflt
runX11Context :: MonadIO m => Context -> a -> X11Property a -> m a
runX11Context :: forall (m :: * -> *) a.
MonadIO m =>
Context -> a -> X11Property a -> m a
runX11Context Context
context a
dflt X11Property a
prop =
IO a -> m a
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO a -> m a) -> IO a -> m a
forall a b. (a -> b) -> a -> b
$ ReaderT Context IO a -> Context -> IO a
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT (a -> X11Property a -> ReaderT Context IO a
forall a. a -> X11Property a -> TaffyIO a
runX11Def a
dflt X11Property a
prop) Context
context
getState :: forall t. Typeable t => Taffy IO (Maybe t)
getState :: forall t. Typeable t => Taffy IO (Maybe t)
getState = do
stateMap <- (Context -> MVar (Map TypeRep Value))
-> ReaderT Context IO (Map TypeRep Value)
forall r b. (r -> MVar b) -> ReaderT r IO b
asksContextVar Context -> MVar (Map TypeRep Value)
contextState
let maybeValue = TypeRep -> Map TypeRep Value -> Maybe Value
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup (Proxy t -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy t
forall {k} (t :: k). Proxy t
Proxy :: Proxy t)) Map TypeRep Value
stateMap
return $ maybeValue >>= fromValue
getStateDefault :: Typeable t => Taffy IO t -> Taffy IO t
getStateDefault :: forall t. Typeable t => Taffy IO t -> Taffy IO t
getStateDefault Taffy IO t
defaultGetter =
Taffy IO (Maybe t)
forall t. Typeable t => Taffy IO (Maybe t)
getState Taffy IO (Maybe t) -> (Maybe t -> Taffy IO t) -> Taffy IO t
forall a b.
ReaderT Context IO a
-> (a -> ReaderT Context IO b) -> ReaderT Context IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Taffy IO t -> (t -> Taffy IO t) -> Maybe t -> Taffy IO t
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Taffy IO t -> Taffy IO t
forall t. Typeable t => Taffy IO t -> Taffy IO t
putState Taffy IO t
defaultGetter) t -> Taffy IO t
forall a. a -> ReaderT Context IO a
forall (m :: * -> *) a. Monad m => a -> m a
return
putState :: forall t. Typeable t => Taffy IO t -> Taffy IO t
putState :: forall t. Typeable t => Taffy IO t -> Taffy IO t
putState Taffy IO t
getValue = do
contextVar <- (Context -> MVar (Map TypeRep Value))
-> ReaderT Context IO (MVar (Map TypeRep Value))
forall (m :: * -> *) r a. Monad m => (r -> a) -> ReaderT r m a
asks Context -> MVar (Map TypeRep Value)
contextState
ctx <- ask
lift $ MV.modifyMVar contextVar $ \Map TypeRep Value
contextStateMap ->
let theType :: TypeRep
theType = Proxy t -> TypeRep
forall {k} (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy t
forall {k} (t :: k). Proxy t
Proxy :: Proxy t)
currentValue :: Maybe Value
currentValue = TypeRep -> Map TypeRep Value -> Maybe Value
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup TypeRep
theType Map TypeRep Value
contextStateMap
insertAndReturn :: t -> (Map TypeRep Value, t)
insertAndReturn t
value =
(TypeRep -> Value -> Map TypeRep Value -> Map TypeRep Value
forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert TypeRep
theType (t -> Value
forall t. Typeable t => t -> Value
Value t
value) Map TypeRep Value
contextStateMap, t
value)
in (ReaderT Context IO (Map TypeRep Value, t)
-> Context -> IO (Map TypeRep Value, t))
-> Context
-> ReaderT Context IO (Map TypeRep Value, t)
-> IO (Map TypeRep Value, t)
forall a b c. (a -> b -> c) -> b -> a -> c
flip ReaderT Context IO (Map TypeRep Value, t)
-> Context -> IO (Map TypeRep Value, t)
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT Context
ctx (ReaderT Context IO (Map TypeRep Value, t)
-> IO (Map TypeRep Value, t))
-> ReaderT Context IO (Map TypeRep Value, t)
-> IO (Map TypeRep Value, t)
forall a b. (a -> b) -> a -> b
$ ReaderT Context IO (Map TypeRep Value, t)
-> (t -> ReaderT Context IO (Map TypeRep Value, t))
-> Maybe t
-> ReaderT Context IO (Map TypeRep Value, t)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
(t -> (Map TypeRep Value, t)
insertAndReturn (t -> (Map TypeRep Value, t))
-> Taffy IO t -> ReaderT Context IO (Map TypeRep Value, t)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Taffy IO t
getValue)
((Map TypeRep Value, t) -> ReaderT Context IO (Map TypeRep Value, t)
forall a. a -> ReaderT Context IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ((Map TypeRep Value, t)
-> ReaderT Context IO (Map TypeRep Value, t))
-> (t -> (Map TypeRep Value, t))
-> t
-> ReaderT Context IO (Map TypeRep Value, t)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Map TypeRep Value
contextStateMap,))
(Maybe Value
currentValue Maybe Value -> (Value -> Maybe t) -> Maybe t
forall a b. Maybe a -> (a -> Maybe b) -> Maybe b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Value -> Maybe t
forall t. Typeable t => Value -> Maybe t
fromValue)
taffyFork :: ReaderT r IO () -> ReaderT r IO ()
taffyFork :: forall r. ReaderT r IO () -> ReaderT r IO ()
taffyFork = ReaderT r IO ThreadId -> ReaderT r IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (ReaderT r IO ThreadId -> ReaderT r IO ())
-> (ReaderT r IO () -> ReaderT r IO ThreadId)
-> ReaderT r IO ()
-> ReaderT r IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (IO () -> IO ThreadId) -> ReaderT r IO () -> ReaderT r IO ThreadId
forall (m :: * -> *) a (n :: * -> *) b r.
(m a -> n b) -> ReaderT r m a -> ReaderT r n b
mapReaderT IO () -> IO ThreadId
forkIO
startX11EventHandler :: Taffy IO ()
startX11EventHandler :: TaffyIO ()
startX11EventHandler = TaffyIO () -> TaffyIO ()
forall r. ReaderT r IO () -> ReaderT r IO ()
taffyFork (TaffyIO () -> TaffyIO ()) -> TaffyIO () -> TaffyIO ()
forall a b. (a -> b) -> a -> b
$ do
c <- ReaderT Context IO Context
forall (m :: * -> *) r. Monad m => ReaderT r m r
ask
lift $ withX11Context def $ eventLoop
(\Event
e -> TaffyIO () -> Context -> IO ()
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT (Event -> TaffyIO ()
handleX11Event Event
e) Context
c)
unsubscribe :: Unique -> Taffy IO ()
unsubscribe :: Unique -> TaffyIO ()
unsubscribe Unique
identifier = do
listenersVar <- (Context -> MVar SubscriptionList)
-> ReaderT Context IO (MVar SubscriptionList)
forall (m :: * -> *) r a. Monad m => (r -> a) -> ReaderT r m a
asks Context -> MVar SubscriptionList
listeners
lift $ MV.modifyMVar_ listenersVar $ return . filter ((== identifier) . fst)
subscribeToAll :: Listener -> Taffy IO Unique
subscribeToAll :: (Event -> TaffyIO ()) -> Taffy IO Unique
subscribeToAll Event -> TaffyIO ()
listener = do
identifier <- IO Unique -> Taffy IO Unique
forall (m :: * -> *) a. Monad m => m a -> ReaderT Context m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift IO Unique
newUnique
listenersVar <- asks listeners
let
addListener :: SubscriptionList -> SubscriptionList
addListener = ((Unique
identifier, Event -> TaffyIO ()
listener)(Unique, Event -> TaffyIO ())
-> SubscriptionList -> SubscriptionList
forall a. a -> [a] -> [a]
:)
lift $ MV.modifyMVar_ listenersVar (return . addListener)
return identifier
subscribeToPropertyEvents :: [String] -> Listener -> Taffy IO Unique
subscribeToPropertyEvents :: [String] -> (Event -> TaffyIO ()) -> Taffy IO Unique
subscribeToPropertyEvents [String]
eventNames Event -> TaffyIO ()
listener = do
eventAtoms <- (String -> ReaderT Context IO Atom)
-> [String] -> ReaderT Context IO [Atom]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM (X11Property Atom -> ReaderT Context IO Atom
forall a. X11Property a -> TaffyIO a
runX11 (X11Property Atom -> ReaderT Context IO Atom)
-> (String -> X11Property Atom)
-> String
-> ReaderT Context IO Atom
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> X11Property Atom
getAtom) [String]
eventNames
let filteredListener event :: Event
event@PropertyEvent { ev_atom :: Event -> Atom
ev_atom = Atom
atom } =
Bool -> TaffyIO () -> TaffyIO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Atom
atom Atom -> [Atom] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Atom]
eventAtoms) (TaffyIO () -> TaffyIO ()) -> TaffyIO () -> TaffyIO ()
forall a b. (a -> b) -> a -> b
$
TaffyIO () -> (SomeException -> TaffyIO ()) -> TaffyIO ()
forall (m :: * -> *) a.
MonadBaseControl IO m =>
m a -> (SomeException -> m a) -> m a
catchAny (Event -> TaffyIO ()
listener Event
event) (TaffyIO () -> SomeException -> TaffyIO ()
forall a b. a -> b -> a
const (TaffyIO () -> SomeException -> TaffyIO ())
-> TaffyIO () -> SomeException -> TaffyIO ()
forall a b. (a -> b) -> a -> b
$ () -> TaffyIO ()
forall a. a -> ReaderT Context IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ())
filteredListener Event
_ = () -> TaffyIO ()
forall a. a -> ReaderT Context IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
subscribeToAll filteredListener
handleX11Event :: Event -> Taffy IO ()
handleX11Event :: Event -> TaffyIO ()
handleX11Event Event
event =
(Context -> MVar SubscriptionList)
-> ReaderT Context IO SubscriptionList
forall r b. (r -> MVar b) -> ReaderT r IO b
asksContextVar Context -> MVar SubscriptionList
listeners ReaderT Context IO SubscriptionList
-> (SubscriptionList -> TaffyIO ()) -> TaffyIO ()
forall a b.
ReaderT Context IO a
-> (a -> ReaderT Context IO b) -> ReaderT Context IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ((Unique, Event -> TaffyIO ()) -> TaffyIO ())
-> SubscriptionList -> TaffyIO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (Unique, Event -> TaffyIO ()) -> TaffyIO ()
applyListener
where applyListener :: (Unique, Listener) -> Taffy IO ()
applyListener :: (Unique, Event -> TaffyIO ()) -> TaffyIO ()
applyListener (Unique
_, Event -> TaffyIO ()
listener) = TaffyIO () -> TaffyIO ()
forall r. ReaderT r IO () -> ReaderT r IO ()
taffyFork (TaffyIO () -> TaffyIO ()) -> TaffyIO () -> TaffyIO ()
forall a b. (a -> b) -> a -> b
$ Event -> TaffyIO ()
listener Event
event