11{-# OPTIONS_GHC -Wall #-}
22
3- {-# LANGUAGE ScopedTypeVariables #-}
3+ {-# LANGUAGE LambdaCase, ScopedTypeVariables, TypeApplications #-}
44
55module Main (main ) where
66
@@ -10,7 +10,6 @@ import Control.Monad
1010import Control.Monad.IO.Class
1111import Data.Fixed
1212import Data.Foldable
13- import Text.Printf (printf )
1413
1514-- cairo
1615import qualified Graphics.Rendering.Cairo as Cairo
@@ -31,18 +30,45 @@ import qualified Data.Time as Time
3130-- unix
3231import qualified System.Posix.Signals as Signals
3332
33+ data DisplayTime a =
34+ DisplayTime
35+ { displayHour :: a
36+ , displayMinute :: a
37+ , displaySecond :: a
38+ }
39+ deriving Eq
40+
41+ twoDigits :: Int -> String
42+ twoDigits x | x < 0 = " ??"
43+ twoDigits x =
44+ case (show @ Int x) of
45+ [a] -> [' 0' , a]
46+ [a, b] -> [a, b]
47+ _ -> " ??"
48+
49+ showDisplayTime :: DisplayTime Int -> String
50+ showDisplayTime (DisplayTime x y z) =
51+ twoDigits x <> " :" <>
52+ twoDigits y <> " :" <>
53+ twoDigits z
54+
3455main :: IO ()
3556main =
3657 do
37- displayVar <- STM. newTVarIO " "
58+ displayVar <- STM. atomically ( STM. newTVar Nothing )
3859 _ <- Gtk. initGUI
3960 window :: Gtk. Window <- Gtk. windowNew
4061 Gtk. windowSetDefaultSize window 300 100
4162 drawingArea :: Gtk. DrawingArea <- Gtk. drawingAreaNew
4263
64+ frame <- Gtk. frameNew
65+ Gtk. frameSetLabel frame " What time is it"
66+
67+ Gtk. set frame [ Gtk. containerChild := drawingArea ]
68+
4369 Gtk. set window
4470 [ Gtk. windowTitle := " Clock"
45- , Gtk. containerChild := drawingArea
71+ , Gtk. containerChild := frame
4672 ]
4773
4874 _ <- Gtk. on window Gtk. deleteEvent $
5581
5682 fontDescription :: Pango. FontDescription <- createFontDescription
5783
58- _ <- Gtk. on drawingArea Gtk. draw
59- (render displayVar fontDescription drawingArea)
84+ _ <- Gtk. on drawingArea Gtk. draw (render displayVar fontDescription)
6085
6186 Gtk. widgetShowAll window
6287
@@ -78,33 +103,35 @@ createFontDescription =
78103 Pango. fontDescriptionSetSize fd 40
79104 return fd
80105
81- render :: Gtk. WidgetClass w
82- => STM. TVar String
83- -- ^ Variable containing the text to display
106+ render
107+ :: STM. TVar ( Maybe ( DisplayTime Int ))
108+ -- ^ Variable containing the text to display
84109 -> Pango. FontDescription
85- -- ^ Font to display the text in
86- -> w
87- -- ^ Widget we're rendering to (needed to get the size of it)
110+ -- ^ Font to display the text in
88111 -> Cairo. Render ()
89- render displayVar fontDescription widget =
112+
113+ render displayVar fontDescription =
90114 do
91- displayString <- liftIO (STM. atomically (STM. readTVar displayVar))
92- Gtk. Rectangle _ _ w h <- liftIO (Gtk. widgetGetAllocation widget)
93- Cairo. setSourceRGB 1 0.9 1
94- Cairo. paint
95- layout <- Pango. createLayout displayString
96- liftIO (Pango. layoutSetFontDescription layout (Just fontDescription))
97- liftIO (Pango. layoutSetAlignment layout Pango. AlignCenter )
98- (_, (PangoRectangle x' y' x'' y'')) <-
99- liftIO (Pango. layoutGetExtents layout)
100- Cairo. moveTo ((fromIntegral w) / 2 - x'' / 2 - x')
101- ((fromIntegral h) / 2 - y'' / 2 - y')
102- Cairo. setSourceRGB 0.2 0.1 0.2
103- Pango. showLayout layout
115+ displayTimeMaybe <- liftIO (STM. atomically (STM. readTVar displayVar))
116+ Gtk. getClipRectangle >>= \ case
117+ Nothing -> return ()
118+ Just (Gtk. Rectangle x y w h) ->
119+ do
120+ Cairo. setSourceRGB 1 0.9 1
121+ Cairo. paint
122+ layout <- Pango. createLayout (maybe " " showDisplayTime displayTimeMaybe)
123+ liftIO (Pango. layoutSetFontDescription layout (Just fontDescription))
124+ liftIO (Pango. layoutSetAlignment layout Pango. AlignCenter )
125+ (_, (PangoRectangle x' y' x'' y'')) <-
126+ liftIO (Pango. layoutGetExtents layout)
127+ Cairo. moveTo ((fromIntegral (x + w)) / 2 - x'' / 2 - x')
128+ ((fromIntegral (y + h)) / 2 - y'' / 2 - y')
129+ Cairo. setSourceRGB 0.2 0.1 0.2
130+ Pango. showLayout layout
104131
105132-- | @'runClock' t@ is an IO action that runs forever, keeping the value of @t@
106133-- equal to the current time.
107- runClock :: STM. TVar String -> IO ()
134+ runClock :: STM. TVar ( Maybe ( DisplayTime Int )) -> IO ()
108135runClock displayVar =
109136 forever $
110137 do
@@ -113,11 +140,14 @@ runClock displayVar =
113140 let
114141 (clockSeconds :: Int , remainderSeconds :: Pico ) =
115142 properFraction (Time. todSec time)
116- s =
117- printf " %02d:%02d:%02d"
118- (Time. todHour time) (Time. todMin time) clockSeconds
119-
120- liftIO (STM. atomically (STM. writeTVar displayVar s))
143+ displayTime =
144+ DisplayTime
145+ { displayHour = Time. todHour time
146+ , displayMinute = Time. todMin time
147+ , displaySecond = clockSeconds
148+ }
149+
150+ liftIO (STM. atomically (STM. writeTVar displayVar (Just displayTime)))
121151 threadDelaySeconds (1 - remainderSeconds)
122152
123153-- | Get the current time of day in the system time zone.
@@ -131,23 +161,24 @@ getLocalTimeOfDay =
131161-- | @'watchClock' t w@ is an IO action that runs forever. Each time the value
132162-- of @t@ changes, it invalidates the drawing area @w@, thus forcing it to
133163-- redraw and update the display.
134- watchClock :: Gtk. WidgetClass w => STM. TVar String -> w -> IO ()
164+ watchClock :: Gtk. WidgetClass w
165+ => STM. TVar (Maybe (DisplayTime Int )) -> w -> IO ()
135166watchClock displayVar drawingArea =
136- go " "
167+ go Nothing
137168 where
138- go :: String -> IO ()
169+ go :: Maybe ( DisplayTime Int ) -> IO ()
139170 go s =
140171 do
141- s' <- STM. atomically (mfilter (s /= ) $ STM. readTVar displayVar)
172+ s' <- STM. atomically (mfilter (s /= ) ( STM. readTVar displayVar) )
142173 Gtk. postGUIAsync (invalidate drawingArea)
143174 go s'
144175
145176-- | Invalidate (force the redrawing of) an entire widget.
146177invalidate :: Gtk. WidgetClass w => w -> IO ()
147178invalidate widget =
148179 do
149- Gtk. Rectangle x y w h <- Gtk. widgetGetAllocation widget
150- Gtk. widgetQueueDrawArea widget x y w h
180+ Gtk. Rectangle _x _y w h <- Gtk. widgetGetAllocation widget
181+ Gtk. widgetQueueDrawArea widget 0 0 w h
151182
152183-- | Block for some fixed number of seconds.
153184threadDelaySeconds :: RealFrac n => n -> IO ()
0 commit comments