# Cairo Integration

Despite cairo not being a GObject based library, PyGObject provides special cairo integration through pycairo. Functions returning and taking cairo data types get automatically converted to pycairo objects and vice versa.

Some distros ship the PyGObject cairo support in a separate package. If you’ve followed the instructions on “Getting Started” you should have everything installed.

If your application requires the cairo integration you can use `gi.require_foreign()`:

    try:
        gi.require_foreign("cairo")
    except ImportError:
        print("No pycairo integration :(")

Note that PyGObject currently does not support cairocffi, only pycairo.

## Demo

The following example shows a `Gtk.Window` with a custom drawing in Python using pycairo.

      1#!/usr/bin/env python
      2"""
      3Based on cairo-demo/X11/cairo-demo.c
      4"""
      5
      6import cairo
      7import gi
      8gi.require_version("Gtk", "3.0")
      9from gi.repository import Gtk
     10
     11SIZE = 30
     12
     13
     14def triangle(ctx):
     15    ctx.move_to(SIZE, 0)
     16    ctx.rel_line_to(SIZE, 2 * SIZE)
     17    ctx.rel_line_to(-2 * SIZE, 0)
     18    ctx.close_path()
     19
     20
     21def square(ctx):
     22    ctx.move_to(0, 0)
     23    ctx.rel_line_to(2 * SIZE, 0)
     24    ctx.rel_line_to(0, 2 * SIZE)
     25    ctx.rel_line_to(-2 * SIZE, 0)
     26    ctx.close_path()
     27
     28
     29def bowtie(ctx):
     30    ctx.move_to(0, 0)
     31    ctx.rel_line_to(2 * SIZE, 2 * SIZE)
     32    ctx.rel_line_to(-2 * SIZE, 0)
     33    ctx.rel_line_to(2 * SIZE, -2 * SIZE)
     34    ctx.close_path()
     35
     36
     37def inf(ctx):
     38    ctx.move_to(0, SIZE)
     39    ctx.rel_curve_to(0, SIZE, SIZE, SIZE, 2 * SIZE, 0)
     40    ctx.rel_curve_to(SIZE, -SIZE, 2 * SIZE, -SIZE, 2 * SIZE, 0)
     41    ctx.rel_curve_to(0, SIZE, -SIZE, SIZE, - 2 * SIZE, 0)
     42    ctx.rel_curve_to(-SIZE, -SIZE, - 2 * SIZE, -SIZE, - 2 * SIZE, 0)
     43    ctx.close_path()
     44
     45
     46def draw_shapes(ctx, x, y, fill):
     47    ctx.save()
     48
     49    ctx.new_path()
     50    ctx.translate(x + SIZE, y + SIZE)
     51    bowtie(ctx)
     52    if fill:
     53        ctx.fill()
     54    else:
     55        ctx.stroke()
     56
     57    ctx.new_path()
     58    ctx.translate(3 * SIZE, 0)
     59    square(ctx)
     60    if fill:
     61        ctx.fill()
     62    else:
     63        ctx.stroke()
     64
     65    ctx.new_path()
     66    ctx.translate(3 * SIZE, 0)
     67    triangle(ctx)
     68    if fill:
     69        ctx.fill()
     70    else:
     71        ctx.stroke()
     72
     73    ctx.new_path()
     74    ctx.translate(3 * SIZE, 0)
     75    inf(ctx)
     76    if fill:
     77        ctx.fill()
     78    else:
     79        ctx.stroke()
     80
     81    ctx.restore()
     82
     83
     84def fill_shapes(ctx, x, y):
     85    draw_shapes(ctx, x, y, True)
     86
     87
     88def stroke_shapes(ctx, x, y):
     89    draw_shapes(ctx, x, y, False)
     90
     91
     92def draw(da, ctx):
     93    ctx.set_source_rgb(0, 0, 0)
     94
     95    ctx.set_line_width(SIZE / 4)
     96    ctx.set_tolerance(0.1)
     97
     98    ctx.set_line_join(cairo.LINE_JOIN_ROUND)
     99    ctx.set_dash([SIZE / 4.0, SIZE / 4.0], 0)
    100    stroke_shapes(ctx, 0, 0)
    101
    102    ctx.set_dash([], 0)
    103    stroke_shapes(ctx, 0, 3 * SIZE)
    104
    105    ctx.set_line_join(cairo.LINE_JOIN_BEVEL)
    106    stroke_shapes(ctx, 0, 6 * SIZE)
    107
    108    ctx.set_line_join(cairo.LINE_JOIN_MITER)
    109    stroke_shapes(ctx, 0, 9 * SIZE)
    110
    111    fill_shapes(ctx, 0, 12 * SIZE)
    112
    113    ctx.set_line_join(cairo.LINE_JOIN_BEVEL)
    114    fill_shapes(ctx, 0, 15 * SIZE)
    115    ctx.set_source_rgb(1, 0, 0)
    116    stroke_shapes(ctx, 0, 15 * SIZE)
    117
    118
    119def main():
    120    win = Gtk.Window()
    121    win.connect('destroy', lambda w: Gtk.main_quit())
    122    win.set_default_size(450, 550)
    123
    124    drawingarea = Gtk.DrawingArea()
    125    win.add(drawingarea)
    126    drawingarea.connect('draw', draw)
    127
    128    win.show_all()
    129    Gtk.main()
    130
    131
    132if __name__ == '__main__':
    133    main()