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