Cairo Integration — PyGObject

# 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 python3
      2"""
      3Based on cairo-demo/X11/cairo-demo.c
      4"""
      5
      6import cairo
      7import gi
      8
      9gi.require_version('Gtk', '4.0')
     10from gi.repository import Gtk
     11
     12SIZE = 30
     13
     14
     15class Application(Gtk.Application):
     16
     17    def do_activate(self):
     18        window = Gtk.ApplicationWindow(application=self, default_width=450, default_height=600)
     19
     20        drawing_area = Gtk.DrawingArea()
     21        drawing_area.set_draw_func(self.draw)
     22        window.set_child(drawing_area)
     23
     24        window.present()
     25
     26    def triangle(self, ctx):
     27        ctx.move_to(SIZE, 0)
     28        ctx.rel_line_to(SIZE, 2 * SIZE)
     29        ctx.rel_line_to(-2 * SIZE, 0)
     30        ctx.close_path()
     31
     32    def square(self, ctx):
     33        ctx.move_to(0, 0)
     34        ctx.rel_line_to(2 * SIZE, 0)
     35        ctx.rel_line_to(0, 2 * SIZE)
     36        ctx.rel_line_to(-2 * SIZE, 0)
     37        ctx.close_path()
     38
     39    def bowtie(self, ctx):
     40        ctx.move_to(0, 0)
     41        ctx.rel_line_to(2 * SIZE, 2 * SIZE)
     42        ctx.rel_line_to(-2 * SIZE, 0)
     43        ctx.rel_line_to(2 * SIZE, -2 * SIZE)
     44        ctx.close_path()
     45
     46    def inf(self, ctx):
     47        ctx.move_to(0, SIZE)
     48        ctx.rel_curve_to(0, SIZE, SIZE, SIZE, 2 * SIZE, 0)
     49        ctx.rel_curve_to(SIZE, -SIZE, 2 * SIZE, -SIZE, 2 * SIZE, 0)
     50        ctx.rel_curve_to(0, SIZE, -SIZE, SIZE, - 2 * SIZE, 0)
     51        ctx.rel_curve_to(-SIZE, -SIZE, - 2 * SIZE, -SIZE, - 2 * SIZE, 0)
     52        ctx.close_path()
     53
     54    def draw_shapes(self, ctx, x, y, fill):
     55        ctx.save()
     56
     57        ctx.new_path()
     58        ctx.translate(x + SIZE, y + SIZE)
     59        self.bowtie(ctx)
     60        if fill:
     61            ctx.fill()
     62        else:
     63            ctx.stroke()
     64
     65        ctx.new_path()
     66        ctx.translate(3 * SIZE, 0)
     67        self.square(ctx)
     68        if fill:
     69            ctx.fill()
     70        else:
     71            ctx.stroke()
     72
     73        ctx.new_path()
     74        ctx.translate(3 * SIZE, 0)
     75        self.triangle(ctx)
     76        if fill:
     77            ctx.fill()
     78        else:
     79            ctx.stroke()
     80
     81        ctx.new_path()
     82        ctx.translate(3 * SIZE, 0)
     83        self.inf(ctx)
     84        if fill:
     85            ctx.fill()
     86        else:
     87            ctx.stroke()
     88
     89        ctx.restore()
     90
     91    def fill_shapes(self, ctx, x, y):
     92        self.draw_shapes(ctx, x, y, True)
     93
     94    def stroke_shapes(self, ctx, x, y):
     95        self.draw_shapes(ctx, x, y, False)
     96
     97    def draw(self, da, ctx, width, height):
     98        ctx.set_source_rgb(0, 0, 0)
     99
    100        ctx.set_line_width(SIZE / 4)
    101        ctx.set_tolerance(0.1)
    102
    103        ctx.set_line_join(cairo.LINE_JOIN_ROUND)
    104        ctx.set_dash([SIZE / 4.0, SIZE / 4.0], 0)
    105        self.stroke_shapes(ctx, 0, 0)
    106
    107        ctx.set_dash([], 0)
    108        self.stroke_shapes(ctx, 0, 3 * SIZE)
    109
    110        ctx.set_line_join(cairo.LINE_JOIN_BEVEL)
    111        self.stroke_shapes(ctx, 0, 6 * SIZE)
    112
    113        ctx.set_line_join(cairo.LINE_JOIN_MITER)
    114        self.stroke_shapes(ctx, 0, 9 * SIZE)
    115
    116        self.fill_shapes(ctx, 0, 12 * SIZE)
    117
    118        ctx.set_line_join(cairo.LINE_JOIN_BEVEL)
    119        self.fill_shapes(ctx, 0, 15 * SIZE)
    120        ctx.set_source_rgb(1, 0, 0)
    121        self.stroke_shapes(ctx, 0, 15 * SIZE)
    122
    123
    124app = Application()
    125app.run()