Using Cairo and LGI
These days, Awesome’s interface is mostly based on a library called LGI. It provides access to C libraries such as GTK, GLib, Cairo, Pango, PangoCairo and RSVG using Lua code without having to write actual “glue” C code.
This is done using the GObject-introspection framework. The main advantage is the time saved and large number of features exposed for free. The downside is the lack of proper Lua centric documentation and examples. Some examples can be found in LGI’s own documentation, but this does not directly explain how to use a concrete API. Using other APIs requires some trial and error, and can be even impossible if the introspection data is missing or inaccurate. Using low-level APIs directly can easily cause crashes. It is the programmer’s responsibility to properly check return and error values.
Using LGI in Awesome
GObject and Gnome centric libraries tend to use the common C practice of emulating namespaces using underscores in function names. LGI exposes a proper namespace based API. For example, if the C function is:
Then the LGI equivalent is:
The same goes for enums:
LGI is also object oriented while the C API is function based. When those functions take the “class” “object”, then this:
cairo_line_to(cr, x, y)
can be expressed as:
It is however important to note some inconsistencies. For example, Cairo is
lgi.cairo while GLib is called
lgi.GLib. Figuring this out will
require some experimenting. The best way to do this without actually
reloading Awesome is to open the
lua command in a terminal and use print:
print("This will print a table address:", require("lgi").cairo) print("This will print an error:", require("lgi").Cairo)
local cairo = require("lgi").cairo
The Cairo API
Cairo is a 2D graphic library used by Awesome, Gnome and XFCE. It allows to
e.g. paint paths on a
Awesome uses it internally and being able to call it directly is a powerful
The following concepts are necessary to be able to use Cairo:
A surface is the area where the painting will be done. There are multiple types of surfaces including:
- Color images with transparency (
ARGB32) or without (
- Monochrome image surfaces with transparency (
A8) or without (
- SVG vectorial surfaces
- Native (XCB) surfaces
- Framebuffers and other less interesting ones (from an Awesome’s point of view)
For more details see Surfaces.
Sources are elements like colors, patterns or gradients. See gears.color for common sources.
For more details see Pattern.
Context and paths:
A context is the proxy between the program and the surface, and holds a path. Paths are something like a line, circle or rectangle, which may or may not be closed (a shape).
All drawing operations on a surface are done via a context. The current path is extended until it is used and reset (see next section). Until then nothing will be drawn to the surface. For example:
cr:rectangle(0 , 0 , 10, 10) cr:rectangle(10, 10, 10, 10)
will not do anything until the operation is applied to the context.
For more details, read:
A context also holds a transformation matrix (see gears.matrix), which is used when applying an operation.
Multiple operations can be done with the paths. The most common are:
- fill: Fill the path with the current source.
- stroke: Paint the path outline with the current source.
- mask: Use the current source as an alpha mask while painting with the current operator.
- clip: Crop the surface’s workarea so nothing outside of the clip will be affected by all following operations.
Operators are modifiers used when applying operations.
Cairo in Awesome
All of Awesome’s wiboxes, awful.wibars, gears.wallpapers and
awful.titlebars contain Cairo surfaces, which can be accessed through the
drawin API. This allows widgets to use the Cairo context directly.
declarative layout system
and new widgets articles for more
information and examples on how widgets work.
It is also possible to create surfaces manually. See gears.surface for some examples. Here is the most simple example you can get:
-- Create a surface local img = cairo.ImageSurface.create(cairo.Format.ARGB32, 50, 50) -- Create a context local cr = cairo.Context(img) -- Set a red source cr:set_source(1, 0, 0) -- Alternative: cr:set_source(gears.color("#ff0000")) -- Add a 10px square path to the context at x=10, y=10 cr:rectangle(10, 10, 10, 10) -- Actually draw the rectangle on img cr:fill()
screen.primary.mywibox.bgimage = img