summaryrefslogtreecommitdiff
path: root/boilerplate
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2010-01-22 21:26:26 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2010-01-22 23:01:52 +0000
commit1236c41072a7966eda7db48a381fd0508e5289be (patch)
treea381bd7fc6d8b0ea95fc0b57cc9af92ce2c32873 /boilerplate
parent77afe8491ed7038a8399c01f10d8f062a7239225 (diff)
xcb: Refresh.
Still an experimental backend, it's now a little too late to stabilise for 1.10, but this should represent a major step forward in its feature set and an attempt to catch up with all the bug fixes that have been performed on xlib. Notably not tested yet (and expected to be broken) are mixed-endian connections and low bitdepth servers (the dithering support has not been copied over for instance). However, it seems robust enough for daily use... Of particular note in this update is that the xcb surface is now capable of subverting the xlib surface through the ./configure --enable-xlib-xcb option. This replaces the xlib surface with a proxy that forwards all operations to an equivalent xcb surface whilst preserving the cairo-xlib API that is required for compatibility with the existing applications, for instance GTK+ and Mozilla. Also you can experiment with enabling a DRM bypass, though you need to be extremely foolhardy to do so.
Diffstat (limited to 'boilerplate')
-rw-r--r--boilerplate/Makefile.win32.features20
-rw-r--r--boilerplate/cairo-boilerplate-xcb.c522
2 files changed, 517 insertions, 25 deletions
diff --git a/boilerplate/Makefile.win32.features b/boilerplate/Makefile.win32.features
index 5c1e0119..8d564118 100644
--- a/boilerplate/Makefile.win32.features
+++ b/boilerplate/Makefile.win32.features
@@ -49,6 +49,16 @@ enabled_cairo_boilerplate_private += $(cairo_boilerplate_xcb_private)
enabled_cairo_boilerplate_sources += $(cairo_boilerplate_xcb_sources)
endif
+unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_xlib_xcb_headers)
+all_cairo_boilerplate_headers += $(cairo_boilerplate_xlib_xcb_headers)
+all_cairo_boilerplate_private += $(cairo_boilerplate_xlib_xcb_private)
+all_cairo_boilerplate_sources += $(cairo_boilerplate_xlib_xcb_sources)
+ifeq ($(CAIRO_HAS_XLIB_XCB_FUNCTIONS),1)
+enabled_cairo_boilerplate_headers += $(cairo_boilerplate_xlib_xcb_headers)
+enabled_cairo_boilerplate_private += $(cairo_boilerplate_xlib_xcb_private)
+enabled_cairo_boilerplate_sources += $(cairo_boilerplate_xlib_xcb_sources)
+endif
+
unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_qt_headers)
all_cairo_boilerplate_headers += $(cairo_boilerplate_qt_headers)
all_cairo_boilerplate_private += $(cairo_boilerplate_qt_private)
@@ -159,6 +169,16 @@ enabled_cairo_boilerplate_private += $(cairo_boilerplate_gallium_private)
enabled_cairo_boilerplate_sources += $(cairo_boilerplate_gallium_sources)
endif
+unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_xcb_drm_headers)
+all_cairo_boilerplate_headers += $(cairo_boilerplate_xcb_drm_headers)
+all_cairo_boilerplate_private += $(cairo_boilerplate_xcb_drm_private)
+all_cairo_boilerplate_sources += $(cairo_boilerplate_xcb_drm_sources)
+ifeq ($(CAIRO_HAS_XCB_DRM_FUNCTIONS),1)
+enabled_cairo_boilerplate_headers += $(cairo_boilerplate_xcb_drm_headers)
+enabled_cairo_boilerplate_private += $(cairo_boilerplate_xcb_drm_private)
+enabled_cairo_boilerplate_sources += $(cairo_boilerplate_xcb_drm_sources)
+endif
+
supported_cairo_boilerplate_headers += $(cairo_boilerplate_png_headers)
all_cairo_boilerplate_headers += $(cairo_boilerplate_png_headers)
all_cairo_boilerplate_private += $(cairo_boilerplate_png_private)
diff --git a/boilerplate/cairo-boilerplate-xcb.c b/boilerplate/cairo-boilerplate-xcb.c
index 0ab2026f..ed173e68 100644
--- a/boilerplate/cairo-boilerplate-xcb.c
+++ b/boilerplate/cairo-boilerplate-xcb.c
@@ -26,15 +26,16 @@
#include "cairo-boilerplate-private.h"
-#include <cairo-xcb-xrender.h>
-
-#include <xcb/xcb_renderutil.h>
+#include <cairo-xcb.h>
static const cairo_user_data_key_t xcb_closure_key;
typedef struct _xcb_target_closure {
xcb_connection_t *c;
- xcb_pixmap_t pixmap;
+ cairo_device_t *device;
+ uint32_t drawable;
+ cairo_bool_t is_pixmap;
+ cairo_surface_t *surface;
} xcb_target_closure_t;
static void
@@ -42,8 +43,17 @@ _cairo_boilerplate_xcb_cleanup (void *closure)
{
xcb_target_closure_t *xtc = closure;
- xcb_free_pixmap (xtc->c, xtc->pixmap);
+ if (xtc->is_pixmap)
+ xcb_free_pixmap (xtc->c, xtc->drawable);
+ else
+ xcb_destroy_window (xtc->c, xtc->drawable);
+ cairo_surface_destroy (xtc->surface);
+
+ cairo_device_finish (xtc->device);
+ cairo_device_destroy (xtc->device);
+
xcb_disconnect (xtc->c);
+
free (xtc);
}
@@ -53,10 +63,42 @@ _cairo_boilerplate_xcb_synchronize (void *closure)
xcb_target_closure_t *xtc = closure;
free (xcb_get_image_reply (xtc->c,
xcb_get_image (xtc->c, XCB_IMAGE_FORMAT_Z_PIXMAP,
- xtc->pixmap, 0, 0, 1, 1, /* AllPlanes */ ~0UL),
+ xtc->drawable, 0, 0, 1, 1, /* AllPlanes */ -1),
0));
}
+static xcb_render_pictforminfo_t *
+find_depth (xcb_connection_t *connection, int depth, void **formats_out)
+{
+ xcb_render_query_pict_formats_reply_t *formats;
+ xcb_render_query_pict_formats_cookie_t cookie;
+ xcb_render_pictforminfo_iterator_t i;
+
+ cookie = xcb_render_query_pict_formats (connection);
+ xcb_flush (connection);
+
+ formats = xcb_render_query_pict_formats_reply (connection, cookie, 0);
+ if (formats == NULL)
+ return NULL;
+
+ for (i = xcb_render_query_pict_formats_formats_iterator (formats);
+ i.rem;
+ xcb_render_pictforminfo_next (&i))
+ {
+ if (XCB_RENDER_PICT_TYPE_DIRECT != i.data->type)
+ continue;
+
+ if (depth != i.data->depth)
+ continue;
+
+ *formats_out = formats;
+ return i.data;
+ }
+
+ free (formats);
+ return NULL;
+}
+
static cairo_surface_t *
_cairo_boilerplate_xcb_create_surface (const char *name,
cairo_content_t content,
@@ -72,10 +114,11 @@ _cairo_boilerplate_xcb_create_surface (const char *name,
xcb_target_closure_t *xtc;
xcb_connection_t *c;
xcb_render_pictforminfo_t *render_format;
- xcb_pict_standard_t format;
+ int depth;
xcb_void_cookie_t cookie;
cairo_surface_t *surface;
cairo_status_t status;
+ void *formats;
*closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
@@ -85,32 +128,279 @@ _cairo_boilerplate_xcb_create_surface (const char *name,
height = 1;
xtc->c = c = xcb_connect(NULL,NULL);
- if (xcb_connection_has_error(c)) {
- fprintf (stderr, "Failed to connect to X server through XCB\n");
+ if (xcb_connection_has_error(c))
+ return NULL;
+
+ root = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
+
+ xtc->surface = NULL;
+ xtc->is_pixmap = TRUE;
+ xtc->drawable = xcb_generate_id (c);
+ switch (content) {
+ case CAIRO_CONTENT_COLOR:
+ depth = 24;
+ cookie = xcb_create_pixmap_checked (c, depth,
+ xtc->drawable, root->root,
+ width, height);
+ break;
+
+ case CAIRO_CONTENT_COLOR_ALPHA:
+ depth = 32;
+ cookie = xcb_create_pixmap_checked (c, depth,
+ xtc->drawable, root->root,
+ width, height);
+ break;
+
+ case CAIRO_CONTENT_ALPHA: /* would be XCB_PICT_STANDARD_A_8 */
+ default:
+ xcb_disconnect (c);
+ free (xtc);
+ return NULL;
+ }
+
+ /* slow, but sure */
+ if (xcb_request_check (c, cookie) != NULL) {
+ xcb_disconnect (c);
+ free (xtc);
+ return NULL;
+ }
+
+ render_format = find_depth (c, depth, &formats);
+ if (render_format == NULL) {
+ xcb_disconnect (c);
+ free (xtc);
+ return NULL;
+ }
+
+ surface = cairo_xcb_surface_create_with_xrender_format (c, root,
+ xtc->drawable,
+ render_format,
+ width, height);
+ free (formats);
+
+ xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
+ status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
+ if (status == CAIRO_STATUS_SUCCESS)
+ return surface;
+
+ cairo_surface_destroy (surface);
+
+ _cairo_boilerplate_xcb_cleanup (xtc);
+ return cairo_boilerplate_surface_create_in_error (status);
+}
+
+static xcb_visualtype_t *
+lookup_visual (xcb_screen_t *s, xcb_visualid_t visual)
+{
+ xcb_depth_iterator_t d;
+
+ d = xcb_screen_allowed_depths_iterator (s);
+ for (; d.rem; xcb_depth_next (&d)) {
+ xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator (d.data);
+ for (; v.rem; xcb_visualtype_next (&v)) {
+ if (v.data->visual_id == visual)
+ return v.data;
+ }
+ }
+
+ return 0;
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_xcb_create_window (const char *name,
+ cairo_content_t content,
+ double width,
+ double height,
+ double max_width,
+ double max_height,
+ cairo_boilerplate_mode_t mode,
+ int id,
+ void **closure)
+{
+ xcb_target_closure_t *xtc;
+ xcb_connection_t *c;
+ xcb_screen_t *s;
+ xcb_void_cookie_t cookie;
+ cairo_surface_t *surface;
+ cairo_status_t status;
+ uint32_t values[] = { 1 };
+
+ *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
+
+ if (width == 0)
+ width = 1;
+ if (height == 0)
+ height = 1;
+
+ xtc->c = c = xcb_connect(NULL,NULL);
+ if (xcb_connection_has_error(c))
+ return NULL;
+
+ xtc->surface = NULL;
+
+ s = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
+ xtc->is_pixmap = FALSE;
+ xtc->drawable = xcb_generate_id (c);
+ cookie = xcb_create_window_checked (c,
+ s->root_depth,
+ xtc->drawable,
+ s->root,
+ 0, 0, width, height, 0,
+ XCB_WINDOW_CLASS_INPUT_OUTPUT,
+ s->root_visual,
+ XCB_CW_OVERRIDE_REDIRECT,
+ values);
+ xcb_map_window (c, xtc->drawable);
+
+ /* slow, but sure */
+ if (xcb_request_check (c, cookie) != NULL) {
+ xcb_disconnect (c);
+ free (xtc);
+ return NULL;
+ }
+
+ surface = cairo_xcb_surface_create (c,
+ xtc->drawable,
+ lookup_visual (s, s->root_visual),
+ width, height);
+
+ xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
+ status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
+ if (status == CAIRO_STATUS_SUCCESS)
+ return surface;
+
+ cairo_surface_destroy (surface);
+
+ _cairo_boilerplate_xcb_cleanup (xtc);
+ return cairo_boilerplate_surface_create_in_error (status);
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_xcb_create_window_db (const char *name,
+ cairo_content_t content,
+ double width,
+ double height,
+ double max_width,
+ double max_height,
+ cairo_boilerplate_mode_t mode,
+ int id,
+ void **closure)
+{
+ xcb_target_closure_t *xtc;
+ xcb_connection_t *c;
+ xcb_screen_t *s;
+ xcb_void_cookie_t cookie;
+ cairo_surface_t *surface;
+ cairo_status_t status;
+ uint32_t values[] = { 1 };
+
+ *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
+
+ if (width == 0)
+ width = 1;
+ if (height == 0)
+ height = 1;
+
+ xtc->c = c = xcb_connect(NULL,NULL);
+ if (xcb_connection_has_error(c))
+ return NULL;
+
+ xtc->surface = NULL;
+
+ s = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
+ xtc->is_pixmap = FALSE;
+ xtc->drawable = xcb_generate_id (c);
+ cookie = xcb_create_window_checked (c,
+ s->root_depth,
+ xtc->drawable,
+ s->root,
+ 0, 0, width, height, 0,
+ XCB_WINDOW_CLASS_INPUT_OUTPUT,
+ s->root_visual,
+ XCB_CW_OVERRIDE_REDIRECT,
+ values);
+ xcb_map_window (c, xtc->drawable);
+
+ /* slow, but sure */
+ if (xcb_request_check (c, cookie) != NULL) {
+ xcb_disconnect (c);
+ free (xtc);
return NULL;
}
+ xtc->surface = cairo_xcb_surface_create (c,
+ xtc->drawable,
+ lookup_visual (s, s->root_visual),
+ width, height);
+ surface = cairo_surface_create_similar (xtc->surface, content, width, height);
+
+ xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
+ status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
+ if (status == CAIRO_STATUS_SUCCESS)
+ return surface;
+
+ cairo_surface_destroy (surface);
+
+ _cairo_boilerplate_xcb_cleanup (xtc);
+ return cairo_boilerplate_surface_create_in_error (status);
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_xcb_create_render_0_0 (const char *name,
+ cairo_content_t content,
+ double width,
+ double height,
+ double max_width,
+ double max_height,
+ cairo_boilerplate_mode_t mode,
+ int id,
+ void **closure)
+{
+ xcb_screen_t *root;
+ xcb_target_closure_t *xtc;
+ xcb_connection_t *c;
+ xcb_render_pictforminfo_t *render_format;
+ int depth;
+ xcb_void_cookie_t cookie;
+ cairo_surface_t *surface, *tmp;
+ cairo_status_t status;
+ void *formats;
+
+ *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
+
+ if (width == 0)
+ width = 1;
+ if (height == 0)
+ height = 1;
+
+ xtc->c = c = xcb_connect(NULL,NULL);
+ if (xcb_connection_has_error(c))
+ return NULL;
+
root = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
- xtc->pixmap = xcb_generate_id (c);
+ xtc->surface = NULL;
+ xtc->is_pixmap = TRUE;
+ xtc->drawable = xcb_generate_id (c);
switch (content) {
case CAIRO_CONTENT_COLOR:
- cookie = xcb_create_pixmap_checked (c, 24,
- xtc->pixmap, root->root,
+ depth = 24;
+ cookie = xcb_create_pixmap_checked (c, depth,
+ xtc->drawable, root->root,
width, height);
- format = XCB_PICT_STANDARD_RGB_24;
break;
case CAIRO_CONTENT_COLOR_ALPHA:
- cookie = xcb_create_pixmap_checked (c, 32,
- xtc->pixmap, root->root,
+ depth = 32;
+ cookie = xcb_create_pixmap_checked (c, depth,
+ xtc->drawable, root->root,
width, height);
- format = XCB_PICT_STANDARD_ARGB_32;
break;
case CAIRO_CONTENT_ALPHA: /* would be XCB_PICT_STANDARD_A_8 */
default:
- fprintf (stderr, "Invalid content for XCB test: %d\n", content);
+ xcb_disconnect (c);
+ free (xtc);
return NULL;
}
@@ -121,24 +411,127 @@ _cairo_boilerplate_xcb_create_surface (const char *name,
return NULL;
}
- render_format = xcb_render_util_find_standard_format (xcb_render_util_query_formats (c), format);
- if (render_format->id == 0)
+ render_format = find_depth (c, depth, &formats);
+ if (render_format == NULL) {
+ xcb_disconnect (c);
+ free (xtc);
return NULL;
+ }
- surface = cairo_xcb_surface_create_with_xrender_format (c, xtc->pixmap, root,
+ tmp = cairo_xcb_surface_create_with_xrender_format (c, root,
+ xtc->drawable,
+ render_format,
+ width, height);
+
+ cairo_xcb_device_debug_cap_xrender_version (cairo_surface_get_device (tmp),
+ 0, 0);
+ /* recreate with impaired connection */
+ surface = cairo_xcb_surface_create_with_xrender_format (c, root,
+ xtc->drawable,
render_format,
width, height);
+ free (formats);
+ cairo_surface_destroy (tmp);
+ xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
if (status == CAIRO_STATUS_SUCCESS)
return surface;
cairo_surface_destroy (surface);
- surface = cairo_boilerplate_surface_create_in_error (status);
_cairo_boilerplate_xcb_cleanup (xtc);
+ return cairo_boilerplate_surface_create_in_error (status);
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_xcb_create_fallback (const char *name,
+ cairo_content_t content,
+ double width,
+ double height,
+ double max_width,
+ double max_height,
+ cairo_boilerplate_mode_t mode,
+ int id,
+ void **closure)
+{
+ xcb_target_closure_t *xtc;
+ xcb_connection_t *c;
+ xcb_screen_t *s;
+ xcb_void_cookie_t cookie;
+ cairo_surface_t *tmp, *surface;
+ cairo_status_t status;
+ uint32_t values[] = { 1 };
+
+ *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
+
+ if (width == 0)
+ width = 1;
+ if (height == 0)
+ height = 1;
+
+ xtc->c = c = xcb_connect (NULL,NULL);
+ if (xcb_connection_has_error(c)) {
+ free (xtc);
+ return NULL;
+ }
+
+ s = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
+ if (width > s->width_in_pixels || height > s->height_in_pixels) {
+ xcb_disconnect (c);
+ free (xtc);
+ return NULL;
+ }
+
+ xtc->surface = NULL;
+ xtc->is_pixmap = FALSE;
+ xtc->drawable = xcb_generate_id (c);
+ cookie = xcb_create_window_checked (c,
+ s->root_depth,
+ xtc->drawable,
+ s->root,
+ 0, 0, width, height, 0,
+ XCB_WINDOW_CLASS_INPUT_OUTPUT,
+ s->root_visual,
+ XCB_CW_OVERRIDE_REDIRECT,
+ values);
+ xcb_map_window (c, xtc->drawable);
+
+ /* slow, but sure */
+ if (xcb_request_check (c, cookie) != NULL) {
+ xcb_disconnect (c);
+ free (xtc);
+ return NULL;
+ }
+
+ tmp = cairo_xcb_surface_create (c,
+ xtc->drawable,
+ lookup_visual (s, s->root_visual),
+ width, height);
+ if (cairo_surface_status (tmp)) {
+ xcb_disconnect (c);
+ free (xtc);
+ return tmp;
+ }
+
+ cairo_xcb_device_debug_cap_xrender_version (cairo_surface_get_device (tmp),
+ -1, -1);
+ /* recreate with impaired connection */
+ surface = cairo_xcb_surface_create (c,
+ xtc->drawable,
+ lookup_visual (s, s->root_visual),
+ width, height);
+ cairo_surface_destroy (tmp);
- return surface;
+ xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
+ status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
+ if (status == CAIRO_STATUS_SUCCESS)
+ return surface;
+
+ cairo_surface_destroy (surface);
+
+ _cairo_boilerplate_xcb_cleanup (xtc);
+ return cairo_boilerplate_surface_create_in_error (status);
}
static cairo_status_t
@@ -148,20 +541,39 @@ _cairo_boilerplate_xcb_finish_surface (cairo_surface_t *surface)
&xcb_closure_key);
xcb_generic_event_t *ev;
- cairo_surface_flush (surface);
+ if (xtc->surface != NULL) {
+ cairo_t *cr;
+
+ cr = cairo_create (xtc->surface);
+ cairo_surface_set_device_offset (surface, 0, 0);
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+
+ surface = xtc->surface;
+ }
+ cairo_surface_flush (surface);
if (cairo_surface_status (surface))
return cairo_surface_status (surface);
while ((ev = xcb_poll_for_event (xtc->c)) != NULL) {
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
if (ev->response_type == 0 /* trust me! */) {
xcb_generic_error_t *error = (xcb_generic_error_t *) ev;
- fprintf (stderr, "Detected error during xcb run: %d major=%d, minor=%d\n",
+ fprintf (stderr,
+ "Detected error during xcb run: %d major=%d, minor=%d\n",
error->error_code, error->major_code, error->minor_code);
+ free (error);
- return CAIRO_STATUS_WRITE_ERROR;
+ status = CAIRO_STATUS_WRITE_ERROR;
}
+
+ if (status)
+ return status;
}
if (xcb_connection_has_error (xtc->c))
@@ -197,5 +609,65 @@ static const cairo_boilerplate_target_t targets[] = {
_cairo_boilerplate_xcb_cleanup,
_cairo_boilerplate_xcb_synchronize
},
+ {
+ "xcb-window", "xlib", NULL, NULL,
+ CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
+ "cairo_xcb_surface_create_with_xrender_format",
+ _cairo_boilerplate_xcb_create_window,
+ NULL,
+ _cairo_boilerplate_xcb_finish_surface,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ _cairo_boilerplate_xcb_cleanup,
+ _cairo_boilerplate_xcb_synchronize
+ },
+ {
+ "xcb-window&", "xlib", NULL, NULL,
+ CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
+ "cairo_xcb_surface_create_with_xrender_format",
+ _cairo_boilerplate_xcb_create_window_db,
+ NULL,
+ _cairo_boilerplate_xcb_finish_surface,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ _cairo_boilerplate_xcb_cleanup,
+ _cairo_boilerplate_xcb_synchronize
+ },
+ {
+ "xcb-render-0.0", "xlib-fallback", NULL, NULL,
+ CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR_ALPHA, 1,
+ "cairo_xcb_surface_create_with_xrender_format",
+ _cairo_boilerplate_xcb_create_render_0_0,
+ NULL,
+ _cairo_boilerplate_xcb_finish_surface,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ _cairo_boilerplate_xcb_cleanup,
+ _cairo_boilerplate_xcb_synchronize
+ },
+ {
+ "xcb-render-0.0", "xlib-fallback", NULL, NULL,
+ CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
+ "cairo_xcb_surface_create_with_xrender_format",
+ _cairo_boilerplate_xcb_create_render_0_0,
+ NULL,
+ _cairo_boilerplate_xcb_finish_surface,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ _cairo_boilerplate_xcb_cleanup,
+ _cairo_boilerplate_xcb_synchronize
+ },
+ {
+ "xcb-fallback", "xlib-fallback", NULL, NULL,
+ CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
+ "cairo_xcb_surface_create_with_xrender_format",
+ _cairo_boilerplate_xcb_create_fallback,
+ NULL,
+ _cairo_boilerplate_xcb_finish_surface,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ _cairo_boilerplate_xcb_cleanup,
+ _cairo_boilerplate_xcb_synchronize
+ },
};
CAIRO_BOILERPLATE (xcb, targets)