1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
|
-----------------------------------------------------------------------------
-- |
-- Module : XMobar
-- Copyright : (c) Andrea Rossato
-- License : BSD-style (see LICENSE)
--
-- Maintainer : Andrea Rossato <andrea.rossato@unibz.it>
-- Stability : unstable
-- Portability : unportable
--
-- A status bar for the Xmonad Window Manager
--
-----------------------------------------------------------------------------
module Main ( -- * Configuration
-- $config
Config (..),
-- * Main Stuff
-- $main
main
, eventLoop
, createWin
, drawInWin
-- * Printing
-- $print
, printStrings
-- * Parsing
-- $parser
, stringParse
, stringParser
, defaultColors
, colorsAndText
-- * Unmamaged Windows
-- $unmanwin
, mkUnmanagedWindow
-- * Useful Utilities
, readConfig
, initColor
) where
import Graphics.X11.Xlib
import Graphics.X11.Xlib.Misc
import Text.ParserCombinators.Parsec
import Control.Monad
import System.Environment
-- $config
-- Configuration data type and default configuration
-- | The configuration data type
data Config =
Config { fonts :: String -- ^ Fonts
, bgColor :: String -- ^ Backgroud color
, fgColor :: String -- ^ Default font color
, xPos :: Int -- ^ x Window position (origin in the upper left corner)
, yPos :: Int -- ^ y Window position
, width :: Int -- ^ Window width
, hight :: Int -- ^ Window hight
} deriving (Eq, Show, Read, Ord)
defaultConfig :: Config
defaultConfig =
Config { fonts = "-misc-fixed-*-*-*-*-*-*-*-*-*-*-*-*"
, bgColor = "#000000"
, fgColor = "#ffffff"
, xPos = 0
, yPos = 0
, width = 1024
, hight = 15
}
-- $main
-- | The main entry point
main :: IO ()
main =
do args <- getArgs
config <-
if length args /= 1
then do putStrLn ("No configuration file specified. Using default settings.")
return defaultConfig
else readConfig (args!!0)
eventLoop config
-- | The event loop
eventLoop :: Config -> IO ()
eventLoop c =
do i <- getLine
ps <- stringParse c i
w <- createWin c
drawInWin c w ps
-- | The function to create the initial window
createWin :: Config -> IO (Display, Window)
createWin config =
do dpy <- openDisplay ""
let dflt = defaultScreen dpy
rootw <- rootWindow dpy dflt
win <- mkUnmanagedWindow dpy (defaultScreenOfDisplay dpy) rootw
(fromIntegral $ xPos config)
(fromIntegral $ yPos config)
(fromIntegral $ width config)
(fromIntegral $ hight config)
mapWindow dpy win
return (dpy,win)
-- | Draws and updates the window
drawInWin :: Config -> (Display, Window) -> [(String, String)] -> IO ()
drawInWin config (dpy, win) str = do
-- get win bgcolor
bgcolor <- initColor dpy $ bgColor config
-- set window background
gc <- createGC dpy win
setForeground dpy gc bgcolor
fillRectangle dpy win gc 0 0
(fromIntegral $ width config)
(fromIntegral $ hight config)
-- let's get the fonts
fontst <- loadQueryFont dpy (fonts config)
setFont dpy gc (fontFromFontStruct fontst)
-- print what you need to print
let strWithLenth = map (\(s,c) -> (s,c,textWidth fontst s)) str
printStrings dpy win gc fontst 1 strWithLenth
-- refreesh, fre, resync... do what you gotta do
freeGC dpy gc
sync dpy True
-- back again: we are never ending
eventLoop config
-- $print
-- | An easy way to print the stuff we need to print
printStrings :: Display
-> Drawable
-> GC
-> FontStruct
-> Position
-> [(String, String, Position)]
-> IO ()
printStrings _ _ _ _ _ [] = return ()
printStrings dpy win gc fontst offset ((s,c,l):xs) =
do let (_,asc,_,_) = textExtents fontst s
color <- initColor dpy c
setForeground dpy gc color
drawString dpy win gc offset asc s
printStrings dpy win gc fontst (offset + l) xs
{- $parser
This is suppose do be a parser. Don't trust him.
-}
-- | Run the actual parsers
stringParse :: Config -> String -> IO [(String, String)]
stringParse config s =
case (parse (stringParser config) "" s) of
Left _ -> return [("Sorry, if I were a decent parser you now would be starring at something meaningful..."
, (fgColor config))]
Right x -> return x
-- | Get the string and combine the needed parsers
stringParser :: Config -> Parser [(String, String)]
stringParser c = manyTill (choice [colorsAndText c,defaultColors c]) eof
-- | parses a string with default color (no color set)
defaultColors :: Config -> Parser (String, String)
defaultColors config =
do { s <- many $ noneOf "^"
; notFollowedBy (char '#')
; return (s,(fgColor config))
}
<|> colorsAndText config
-- | parses a string with a color set
colorsAndText :: Config -> Parser (String, String)
colorsAndText config =
do { string "^#"
; n <- count 6 hexDigit
; s <- many $ noneOf "^"
; notFollowedBy (char '#')
; return (s,"#"++n)
}
<|> defaultColors config
{- $unmanwin
This is a way to create unmamaged window. It was a mistery in Haskell.
Till I've found out...;-)
-}
-- | Creates a window with the attribute override_redirect set to True.
-- Windows Managers should not touch this kind of windows.
mkUnmanagedWindow :: Display
-> Screen
-> Window
-> Position
-> Position
-> Dimension
-> Dimension
-> IO Window
mkUnmanagedWindow dpy scr rw x y w h = do
let visual = defaultVisualOfScreen scr
attrmask = cWOverrideRedirect
window <- allocaSetWindowAttributes $
\attributes -> do
set_override_redirect attributes True
createWindow dpy rw x y w h 0 (defaultDepthOfScreen scr)
inputOutput visual attrmask attributes
return window
{- $utility
Utilities, aka stollen without givin' credit stuff.
-}
-- | Reads the configuration files or quits with an error
readConfig :: FilePath -> IO Config
readConfig f =
do s <- readFile f
case reads s of
[(config,_)] -> return config
[] -> error ("Corrupt config file: " ++ f)
_ -> error ("Some problem occured. Aborting...")
-- | Get the Pixel value for a named color
initColor :: Display -> String -> IO Pixel
initColor dpy c = (color_pixel . fst) `liftM` allocNamedColor dpy colormap c
where colormap = defaultColormap dpy (defaultScreen dpy)
|