{-# LANGUAGE ScopedTypeVariables #-} -- | Examples is meant to contain examples of using events which -- are too small to go into their own module. module Events.Examples( EventSet, -- These encode a set of events emptyEventSet, -- :: EventSet a addToEventSet, -- :: EventSet a -> Event a -> EventSet a fromEventSet, -- :: EventSet a -> Event (a,EventSet a) isEmptyEventSet, -- :: EventSet a -> Bool watch, -- :: Event a -> IO (Event a,IO ()) -- watch is used for events which can be dropped occasionally. spawnRepeatedEvent, -- :: Event () -> IO (IO ()) -- spawnRepeatedEvent concurrently syncs on the event until the -- given action is used; it is somewhat safer than spawnEvent. ) where import qualified Data.IntMap as IntMap import Events.Events import Events.Channels -- ------------------------------------------------------------------ -- Event Sets -- ------------------------------------------------------------------ data EventSet a = EventSet Int (IntMap.IntMap (Event a)) emptyEventSet :: EventSet a emptyEventSet = EventSet 0 IntMap.empty addToEventSet :: EventSet a -> Event a -> EventSet a addToEventSet (EventSet next fmap) event = EventSet (next+1) (IntMap.insert next event fmap) fromEventSet :: EventSet a -> Event (a,EventSet a) -- fromEventSet turns the event set into an event which -- waits for one of the events to happen, and then returns -- the value, plus the event set containing the remaining events. fromEventSet (EventSet next fmap) = choose (map (\ (key,event) -> event >>>= (\ a -> return (a,EventSet next (IntMap.delete key fmap))) ) (IntMap.toList fmap) ) isEmptyEventSet :: EventSet a -> Bool isEmptyEventSet (EventSet _ fmap) = IntMap.null fmap -- ------------------------------------------------------------------ -- Watchers -- ------------------------------------------------------------------ -- | watch is used for events like mouse motion events where -- if we can\'t find time we don\'t want them queued. -- The event returned waits until the original event next happens and -- returns it. A worker thread is needed to run this; the attached action -- should be used to stop that thread when we are no longer interested. watch :: Event a -> IO (Event a,IO ()) watch (event :: Event a) = do channel <- newChannel dieChannel <- newChannel let die = receive dieChannel waitForNext :: Event () waitForNext = do next <- event passOn next +> die passOn :: a -> Event () passOn val = waitForNext +> (do send channel val waitForNext ) +> die _ <- spawnEvent waitForNext return (receive channel,sync(send dieChannel ())) -- | spawnRepeatedEvent concurrently syncs on the event until the -- given action is used; it is somewhat safer than spawnEvent. -- It also never interrupts the handler event attached to -- the event. spawnRepeatedEvent :: Event () -> IO (IO ()) spawnRepeatedEvent event = do dieChannel <- newChannel let die = receive dieChannel handleEvent = die +> (do event handleEvent ) _ <- spawnEvent handleEvent return (sync(noWait(send dieChannel ())))