aboutsummaryrefslogtreecommitdiffstats
path: root/XMonad/Util/Font.cpphs
blob: b6cf2adee709e84a26839c8c2c9ab6859d6ba08d (plain) (blame)
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
----------------------------------------------------------------------------
-- |
-- Module      :  XMonad.Util.Font
-- Copyright   :  (c) 2007 Andrea Rossato and Spencer Janssen
-- License     :  BSD-style (see xmonad/LICENSE)
--
-- Maintainer  :  andrea.rossato@unibz.it
-- Stability   :  unstable
-- Portability :  unportable
--
-- A module for abstracting a font facility over Core fonts and Xft
--
-----------------------------------------------------------------------------

module XMonad.Util.Font  (
                             -- * Usage:
                             -- $usage
                             XMonadFont(..)
                             , initXMF
                             , releaseXMF
                             , initCoreFont
                             , releaseCoreFont
                             , Align (..)
                             , stringPosition
                             , textWidthXMF
                             , textExtentsXMF
                             , printStringXMF
                             , stringToPixel
                            ) where


import XMonad
import Foreign
import Control.Applicative
import Data.Maybe

#ifdef XFT
import Data.List
import Graphics.X11.Xft
import Graphics.X11.Xrender
#endif

-- Hide the Core Font/Xft switching here
data XMonadFont = Core FontStruct
#ifdef XFT
                | Xft  XftFont
#endif

-- $usage
-- See "Xmonad.Layout.Tabbed" or "XMonad.Prompt" for usage examples

-- | Get the Pixel value for a named color: if an invalid name is
-- given the black pixel will be returned.
stringToPixel :: (Functor m, MonadIO m) => Display -> String -> m Pixel
stringToPixel d s = fromMaybe fallBack <$> liftIO getIt
    where getIt    = initColor d s
          fallBack = blackPixel d (defaultScreen d)


-- | Given a fontname returns the font structure. If the font name is
--  not valid the default font will be loaded and returned.
initCoreFont :: String -> X FontStruct
initCoreFont s = do
  d <- asks display
  io $ catch (getIt d) (fallBack d)
      where getIt    d = loadQueryFont d s
            fallBack d = const $ loadQueryFont d "-misc-fixed-*-*-*-*-10-*-*-*-*-*-*-*"

releaseCoreFont :: FontStruct -> X ()
releaseCoreFont fs = do
  d <- asks display
  io $ freeFont d fs

-- | When initXMF gets a font name that starts with 'xft:' it switchs to the Xft backend
-- Example: 'xft: Sans-10'
initXMF :: String -> X XMonadFont
initXMF s =
#ifdef XFT
  if xftPrefix `isPrefixOf` s then
     do
       dpy <- asks display
       xftdraw <- io $ xftFontOpen dpy (defaultScreenOfDisplay dpy) (drop (length xftPrefix) s)
       return (Xft xftdraw)
  else
#endif
      (initCoreFont s >>= (return . Core))
#ifdef XFT
  where xftPrefix = "xft:"
#endif

releaseXMF :: XMonadFont -> X ()
releaseXMF (Core fs) = releaseCoreFont fs
#ifdef XFT
releaseXMF (Xft xftfont) = do
  dpy <- asks display
  io $ xftFontClose dpy xftfont
#endif

textWidthXMF :: MonadIO m => Display -> XMonadFont -> String -> m Int
textWidthXMF _   (Core fs) s = return $ fi $ textWidth fs s
#ifdef XFT
textWidthXMF dpy (Xft xftdraw) s = liftIO $ do
    gi <- xftTextExtents dpy xftdraw s
    return $ xglyphinfo_width gi
#endif

textExtentsXMF :: MonadIO m => XMonadFont -> String -> m (FontDirection,Int32,Int32,CharStruct)
textExtentsXMF (Core fs) s = return $ textExtents fs s
#ifdef XFT
textExtentsXMF (Xft xftfont) _ = liftIO $ do
    ascent <- xftfont_ascent xftfont
    descent <- xftfont_descent xftfont
    return (error "Font direction touched", fi ascent, fi descent, error "Font overall size touched")
#endif

-- | String position
data Align = AlignCenter | AlignRight | AlignLeft

-- | Return the string x and y 'Position' in a 'Rectangle', given a
-- 'FontStruct' and the 'Align'ment
stringPosition :: XMonadFont -> Rectangle -> Align -> String -> X (Position,Position)
stringPosition fs (Rectangle _ _ w h) al s = do
  dpy <- asks display
  width <- io $ textWidthXMF dpy fs s
  (_,a,d,_) <- io $ textExtentsXMF fs s
  let y         = fi $ ((h - fi (a + d)) `div` 2) + fi a;
      x         = case al of
                     AlignCenter -> fi (w `div` 2) - fi (width `div` 2)
                     AlignLeft   -> 1
                     AlignRight  -> fi (w - (fi width + 1));
  return (x,y)


printStringXMF :: MonadIO m => Display -> Drawable -> XMonadFont -> GC -> String -> String
            -> Position -> Position -> String  -> m ()
printStringXMF d p (Core fs) gc fc bc x y s = liftIO $ do
         setFont d gc $ fontFromFontStruct fs
         [fc',bc'] <- mapM (stringToPixel d) [fc,bc]
         setForeground   d gc fc'
         setBackground   d gc bc'
         drawImageString d p gc x y s

#ifdef XFT
printStringXMF dpy drw (Xft font) _ fc _ x y s = do
  let screen = defaultScreenOfDisplay dpy;
      colormap = defaultColormapOfScreen screen;
      visual = defaultVisualOfScreen screen;
  liftIO $ withXftDraw dpy drw visual colormap $
         \draw -> withXftColorName dpy visual colormap fc $
                   \color -> xftDrawString draw color font x y s
#endif


-- | Short-hand for 'fromIntegral'
fi :: (Integral a, Num b) => a -> b
fi = fromIntegral