What is the difference between gi-cairo and cairo libraries

329 views Asked by At

I making a program to draw some vector graphics on top of a GTK program written with Haskell.

I upgraded my program to the gi-gtk library in replacement of Gtk2Hs to benefit of Gtk3 and when I see tutorial/example about drawing in Gtk windows with cairo and/or diagram, both gi-cairo and cairo (from Gtk2Hs) are needed at the same time.

For an example I can see :

import           GI.Gtk  
import qualified GI.Cairo (Context(..))

import qualified Graphics.Rendering.Cairo as Cairo
import qualified Graphics.Rendering.Cairo.Internal as Cairo (Render(runRender))
import qualified Graphics.Rendering.Cairo.Types as Cairo (Cairo(Cairo))

and I don't understand why GI.Cairo (gi-cairo) and Graphics.Rendering.Cairo (cairo) must be imported at the same time.

Does GI.Cairo aim to replace Graphics.Rendering.Cairo or to complete it ?

Is Graphics.Rendering.Cairo still updated or is it a good idea to use another library ?

Any information/explanations about these two libraries would be helpful

1

There are 1 answers

0
Paul Johnson On BEST ANSWER

TL;DR: treat anything based on GTK2HS as deprecated. Use things with the gi- prefix instead.

Originally there were the GTK2HS libraries, which were a manually written binding to GTK (I think, not sure about the details).

Part of this effort was a binding to the Cairo library. The Cairo functions all take a Cairo context object as an argument, which is used to carry state like the current colour and line style. The Haskell binding wraps this up using a Reader monad inside the Render newtype so you don't have to worry about the context object.

However maintaining this was slow and mandraulic, and there was an obvious better way: GTK has built-in support for other language bindings provided by metadata embedded in the source code. So it is perfectly possible to generate all the GTK bindings automatically, and also to extend this to other libraries which use the GTK metadata system. This is what gi-gtk and its relatives do.

Unfortunately Cairo doesn't work like that. It doesn't include the GTK metadata for the actual drawing API, so the gi-cairo interface is no use for anything.

For some time the only way around this was a manual bodge to bridge the gap between the gi-gtk family and the GTK2HS Cairo library, but no longer. Now there is a complete solution:

  • The gi-cairo-render library, which is essentially the same as the old GTK2HS library but using the gi-cairo version of the context object.

  • The associated gi-cairo-connector library which lets you switch between functions that require an explicit Cairo context object and functions that work in the Render monad.

You most often need an explicit Cairo context for drawing text using Pango. The Pango library has its own Context object (confusingly, both types are called Context and you have to import them qualified to disambiguate). You get the Pango context from a Cairo context using createContext, and to do this in the middle of a Render action you have to extract the current context from the Render monad using one of the Connector functions.

The code you have quoted is using the old manual bodge; the Render and runRender internal functions are used get at the Cairo context in the GTK2HS version of the Cairo binding. If you look at the code that calls these functions you will probably see it doing something unsafe with pointers to coerce between the GI.Cairo.Context type and Graphics.Rendering.Cairo.Types.Cairo context type, which both point to the same thing under the hood.