Drawing to an external Cairo context
Giza can plot into a caller-owned cairo_t context.
This is intended for embedding giza plots in GUI toolkits (for example
GtkDrawingArea)
or other applications that already use Cairo for rendering.
This device is not opened with
giza_open_device("/cairo", ...). Use the dedicated API described
below instead.
Overview
Opening a giza device and binding a cairo context are separate steps:
- Open a cairo device (logical size only; no drawing yet).
- Configure the plot (world coordinates, colours, etc.) at any time.
- Bind a
cairo_twithgiza_set_cairo_contextwhen you are ready to draw. - Plot using the usual giza drawing routines.
- Release the context with
giza_release_cairo_contextwhen the frame is finished.
Giza performs cairo_save when binding and
cairo_restore when releasing, so toolkit state on the context
is preserved. Giza never destroys the caller's context or surface.
API summary
int giza_open_device_cairo (void);
int giza_open_device_size_cairo (double width, double height, int units);
int giza_open_device_size_cairo_float (float width, float height, int units);
int giza_set_cairo_context (cairo_t *cr);
int giza_release_cairo_context (void);
int giza_resize_device_cairo (double width, double height, int units);
cairo_surface_t *giza_get_cairo_surface (void);
giza_open_device_cairo() is like
giza_open_device(): it opens a device with a default logical
size (800×600 pixels). giza_open_device_size_cairo() is
like giza_open_device_size() and lets you specify width, height
and units (GIZA_UNITS_PIXELS, GIZA_UNITS_MM, etc.).
Plotting routines require a bound context. Call
giza_set_cairo_context before drawing and
giza_release_cairo_context when done (typically once per
expose/redraw event in a GUI).
Off-screen example (image surface)
Click here for a complete C example, or follow the steps below.
1. Open the device
#include <giza.h>
#include <cairo/cairo.h>
int dev = giza_open_device_size_cairo (400., 300., GIZA_UNITS_PIXELS);
if (dev <= 0)
return 1;
2. Create a cairo surface and bind it
cairo_surface_t *surface =
cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 400, 300);
cairo_t *cr = cairo_create (surface);
if (giza_set_cairo_context (cr) != 0)
return 1;
3. Plot as usual
giza_set_environment (0., 1., 0., 1., 0, 0);
giza_box ("BCNT", 0., 0, "BCNT", 0., 0);
giza_move (0.1, 0.5);
giza_draw (0.9, 0.5);
4. Release, close, and save
giza_release_cairo_context ();
giza_close_device ();
cairo_surface_write_to_png (surface, "plot.png");
cairo_destroy (cr);
cairo_surface_destroy (surface);
GTK / toolkit integration
In a typical GtkDrawingArea (GTK 4) draw handler, the toolkit supplies a
fresh cairo_t for each frame. Open the giza device once when the
widget is created; bind and release on every draw:
/* once, e.g. in widget init */
int giza_dev = giza_open_device_size_cairo (w, h, GIZA_UNITS_PIXELS);
giza_select_device (giza_dev);
giza_set_environment (...); /* optional one-time setup */
/* on each draw callback */
static void on_draw (GtkDrawingArea *area, cairo_t *cr, int w, int h, gpointer data)
{
(void) area;
(void) data;
giza_select_device (giza_dev);
giza_resize_device_cairo ((double) w, (double) h, GIZA_UNITS_PIXELS);
giza_set_cairo_context (cr);
/* ... giza plotting calls ... */
giza_release_cairo_context ();
}
Keep giza_resize_device_cairo in sync with the widget size
whenever the allocation changes. The cairo surface passed to
giza_set_cairo_context should match that logical size.
Important notes
- Ownership: You own the
cairo_tand its target surface. Do not destroy them while giza still has them bound; callgiza_release_cairo_contextorgiza_close_devicefirst. - Before plotting: Always call
giza_set_cairo_contextbefore any drawing routine. Opening the device alone is not enough. - Between frames: After
giza_release_cairo_context, the device remains open and configured; re-bind on the next frame. - Not interactive: This device has no cursor or band input; it is for rendering only.
Compiling
Link against giza and cairo, for example:
gcc -o cairo-device cairo-device.c -lgiza -lcairo
See also the API reference for full function documentation.
