{- Copyright 2016 Markus Ongyerth This file is part of Monky. Monky is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Monky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with Monky. If not, see . -} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleInstances #-} {-| Module : Monky.Examples.Combine Description: Combine multiple modules into one (to avoid seperators) Maintainer: ongy Stability: testing Portability: linux The functions in this module can be used to avoid printing seperators between modules. Nearly equivalend example (image is missing): @ pollPack 1 $ getCPUHandle' ScalingCur pollPack 1 $ (getFreqHandle ScalingCur) `combine` getRawCPU `combine` getTempHandle' @ The main function exported by this module are: * 'combine' * 'combineD' * 'combineE' * 'combineF' They are mainly overloads of the same concept, for combinations of 'EvtModule' and 'PollModule' The mixed functions ('combineD' and 'combineF') create a 'PollModule'. The 'EvtModule' will update a cache in the new module and output will be updated when the 'PollModule' is asked to do so. NOTE: because of this, the event will be handled when it is detected, but the output will not update until the 'PollModule' wrapper ticks once. -} module Monky.Examples.Combine ( CombiHandle , combine , EvtCombi , combineE , EPCombi , combineF , PECombi , combineD ) where import Monky.Modules import Control.Concurrent (forkIO) import Control.Concurrent.MVar (MVar, withMVar, newMVar) import Data.IORef (IORef, readIORef, atomicWriteIORef, newIORef) -- |Wrapper type for 'PollModule's data (PollModule a, PollModule b) => CombiHandle a b = C a b instance (PollModule a, PollModule b) => PollModule (CombiHandle a b) where getOutput (C a b) = do c <- getOutput a d <- getOutput b return (c ++ d) initialize (C a b) = initialize a >> initialize b -- |Combine two 'PollModule's. The first arguments output will be printed first combine :: (PollModule a, PollModule b) => IO a -> IO b -> IO (CombiHandle a b) combine a b = do c <- a d <- b return $ C c d -- Module handle a, b. IORef for caching a, b. MVar to implement boolean, containing value doesn't matter -- |Wrapper type for 'EvtModule's data (EvtModule a, EvtModule b) => EvtCombi a b = EC a b (IORef [MonkyOut]) (IORef [MonkyOut]) (MVar Bool) instance (EvtModule a, EvtModule b) => EvtModule (EvtCombi a b) where startEvtLoop (EC a b r1 r2 m) act = do _ <- forkIO $ startEvtLoop a (\out -> withMVar m $ \_ -> do atomicWriteIORef r1 out other <- readIORef r2 act (out ++ other)) startEvtLoop b (\out -> withMVar m $ \_ -> do atomicWriteIORef r2 out other <- readIORef r1 act (other ++ out)) -- |Combine two 'EvtModule's. The first argument will be printed first. combineE :: (EvtModule a, EvtModule b) => IO a -> IO b -> IO (EvtCombi a b) combineE a b = do m1 <- a m2 <- b r1 <- newIORef [] r2 <- newIORef [] m <- newMVar True return $ EC m1 m2 r1 r2 m -- |Wrapper type for mixed combination. data (EvtModule a, PollModule b) => EPCombi a b = EP a b (IORef [MonkyOut]) instance (EvtModule a, PollModule b) => PollModule (EPCombi a b) where initialize (EP a b r) = do startEvtLoop a (atomicWriteIORef r) initialize b getOutput (EP _ b r) = do o1 <- readIORef r o2 <- getOutput b return (o1 ++ o2) -- |Combine a 'EvtModule' with a 'PollModule'. This will alwasy create a 'PollModule'. -- |Event updates will not be displayed until the poll modules ticks once. combineF :: (EvtModule a, PollModule b) => IO a -> IO b -> IO (EPCombi a b) combineF a b = do m1 <- a m2 <- b r <- newIORef [] return $ EP m1 m2 r -- |Wrapper type for mixed combination. data (PollModule a, EvtModule b) => PECombi a b = PE a b (IORef [MonkyOut]) instance (PollModule a, EvtModule b) => PollModule (PECombi a b) where initialize (PE a b r) = do startEvtLoop b (atomicWriteIORef r) initialize a getOutput (PE a _ r) = do o1 <- getOutput a o2 <- readIORef r return (o1 ++ o2) -- |Look at 'combineF' for documentation combineD :: (PollModule a, EvtModule b) => IO a -> IO b -> IO (PECombi a b) combineD a b = do m1 <- a m2 <- b r <- newIORef [] return $ PE m1 m2 r