After some sweat and tears and frantic search for solutions I decided to use Cairo for rendering. This also has the advantage that the result of the rendering can be cached in memory, so the display can be refreshed very efficiently if the text is static. All we have to do is prepare an image for later rendering.
First we need a Cairo context. As part of my goal was to preferably use the same font as the rest of the interface, I also set it to a sans serif typeface:
cctx <- cairoCreateContext Nothing
fontDesc <- contextGetFontDescription cctx
fontDescriptionSetFamily fontDesc "Sans"
contextSetFontDescription cctx fontDesc
The next step towards consistency is to set the resolution to match that of the screen. This is very important to crazy people like me, who had to change their DPI setting.
screenGetDefault >>= \s -> case s of
Nothing -> return ()
Just scr -> do
res <- Gtk.get scr screenResolution
cairoContextSetResolution cctx res
Okay, the context is sufficiently prepared for our purposes, we can create the layout:
txt <- layoutText cctx "Hello world!"
Next, we need a pixel buffer that can hold the final render. We can easily find out its dimensions by asking for the pixel extents of the layout, and it’s probably better to use the logical extents that also include some padding:
Rectangle _ _ txtWidth txtHeight <- snd <$> layoutGetPixelExtents txt
textSurface <- createImageSurface FormatARGB32 txtWidth txtHeight
textSurfacePixbuf <- pixbufFromImageSurface textSurface
And everything’s ready for rendering, so let’s do it:
renderWith textSurface $ showLayout txt
From this moment the rendering of the text is available in the pixbuf. Rendering it is a piece of cake:
withGLDrawingArea glCanvas $ \glw -> do
-- various opengl commands
gc <- gcNew glw
drawPixbuf glw gc textSurfacePixbuf 0 0 textX textY txtWidth txtHeight RgbDitherNone 0 0
-- more opengl commands
When we know that we won’t need the image any more, we can free up the surface:
For more consistency we could look up the actual rendering settings (antialiasing, hinting) and fonts of the current theme and set everything before rendering. That’s left as an exercise to the reader. I’m too tired. ;)