1 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2 /*
3 * Copyright © 2004,2006 Red Hat, Inc.
4 *
5 * Permission to use, copy, modify, distribute, and sell this software
6 * and its documentation for any purpose is hereby granted without
7 * fee, provided that the above copyright notice appear in all copies
8 * and that both that copyright notice and this permission notice
9 * appear in supporting documentation, and that the name of
10 * Red Hat, Inc. not be used in advertising or publicity pertaining to
11 * distribution of the software without specific, written prior
12 * permission. Red Hat, Inc. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as
14 * is" without express or implied warranty.
15 *
16 * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
18 * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
19 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
20 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
22 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 *
24 * Author: Carl D. Worth <cworth@cworth.org>
25 */
26
27 #include "cairo-boilerplate-private.h"
28
29 #include <cairo-xcb.h>
30
31 #include <assert.h>
32
33 static const cairo_user_data_key_t xcb_closure_key;
34
35 typedef struct _xcb_target_closure {
36 xcb_connection_t *c;
37 cairo_device_t *device;
38 uint32_t drawable;
39 cairo_bool_t is_pixmap;
40 cairo_surface_t *surface;
41 } xcb_target_closure_t;
42
43 static void
_cairo_boilerplate_xcb_cleanup(void * closure)44 _cairo_boilerplate_xcb_cleanup (void *closure)
45 {
46 xcb_target_closure_t *xtc = closure;
47
48 if (xtc->is_pixmap)
49 xcb_free_pixmap (xtc->c, xtc->drawable);
50 else
51 xcb_destroy_window (xtc->c, xtc->drawable);
52 cairo_surface_destroy (xtc->surface);
53
54 cairo_device_finish (xtc->device);
55 cairo_device_destroy (xtc->device);
56
57 xcb_disconnect (xtc->c);
58
59 free (xtc);
60 }
61
62 static void
_cairo_boilerplate_xcb_synchronize(void * closure)63 _cairo_boilerplate_xcb_synchronize (void *closure)
64 {
65 xcb_target_closure_t *xtc = closure;
66 free (xcb_get_image_reply (xtc->c,
67 xcb_get_image (xtc->c, XCB_IMAGE_FORMAT_Z_PIXMAP,
68 xtc->drawable, 0, 0, 1, 1, /* AllPlanes */ -1),
69 0));
70 }
71
72 static xcb_render_pictforminfo_t *
find_depth(xcb_connection_t * connection,int depth,void ** formats_out)73 find_depth (xcb_connection_t *connection,
74 int depth,
75 void **formats_out)
76 {
77 xcb_render_query_pict_formats_reply_t *formats;
78 xcb_render_query_pict_formats_cookie_t cookie;
79 xcb_render_pictforminfo_iterator_t i;
80
81 cookie = xcb_render_query_pict_formats (connection);
82 xcb_flush (connection);
83
84 formats = xcb_render_query_pict_formats_reply (connection, cookie, 0);
85 if (formats == NULL)
86 return NULL;
87
88 for (i = xcb_render_query_pict_formats_formats_iterator (formats);
89 i.rem;
90 xcb_render_pictforminfo_next (&i))
91 {
92 if (XCB_RENDER_PICT_TYPE_DIRECT != i.data->type)
93 continue;
94
95 if (depth != i.data->depth)
96 continue;
97
98 *formats_out = formats;
99 return i.data;
100 }
101
102 free (formats);
103 return NULL;
104 }
105
106 static cairo_surface_t *
_cairo_boilerplate_xcb_create_surface(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)107 _cairo_boilerplate_xcb_create_surface (const char *name,
108 cairo_content_t content,
109 double width,
110 double height,
111 double max_width,
112 double max_height,
113 cairo_boilerplate_mode_t mode,
114 int id,
115 void **closure)
116 {
117 xcb_screen_t *root;
118 xcb_target_closure_t *xtc;
119 xcb_connection_t *c;
120 xcb_render_pictforminfo_t *render_format;
121 int depth;
122 xcb_void_cookie_t cookie;
123 cairo_surface_t *surface;
124 cairo_status_t status;
125 void *formats;
126
127 *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
128
129 if (width == 0)
130 width = 1;
131 if (height == 0)
132 height = 1;
133
134 xtc->c = c = xcb_connect(NULL,NULL);
135 if (c == NULL || xcb_connection_has_error(c)) {
136 free (xtc);
137 return NULL;
138 }
139
140 root = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
141
142 xtc->surface = NULL;
143 xtc->is_pixmap = TRUE;
144 xtc->drawable = xcb_generate_id (c);
145 switch (content) {
146 case CAIRO_CONTENT_COLOR:
147 depth = 24;
148 cookie = xcb_create_pixmap_checked (c, depth,
149 xtc->drawable, root->root,
150 width, height);
151 break;
152
153 case CAIRO_CONTENT_COLOR_ALPHA:
154 depth = 32;
155 cookie = xcb_create_pixmap_checked (c, depth,
156 xtc->drawable, root->root,
157 width, height);
158 break;
159
160 case CAIRO_CONTENT_ALPHA: /* would be XCB_PICT_STANDARD_A_8 */
161 default:
162 xcb_disconnect (c);
163 free (xtc);
164 return NULL;
165 }
166
167 /* slow, but sure */
168 if (xcb_request_check (c, cookie) != NULL) {
169 xcb_disconnect (c);
170 free (xtc);
171 return NULL;
172 }
173
174 render_format = find_depth (c, depth, &formats);
175 if (render_format == NULL) {
176 xcb_disconnect (c);
177 free (xtc);
178 return NULL;
179 }
180
181 surface = cairo_xcb_surface_create_with_xrender_format (c, root,
182 xtc->drawable,
183 render_format,
184 width, height);
185 free (formats);
186
187 xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
188 status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
189 if (status == CAIRO_STATUS_SUCCESS)
190 return surface;
191
192 cairo_surface_destroy (surface);
193
194 _cairo_boilerplate_xcb_cleanup (xtc);
195 return cairo_boilerplate_surface_create_in_error (status);
196 }
197
198 static xcb_visualtype_t *
lookup_visual(xcb_screen_t * s,xcb_visualid_t visual)199 lookup_visual (xcb_screen_t *s,
200 xcb_visualid_t visual)
201 {
202 xcb_depth_iterator_t d;
203
204 d = xcb_screen_allowed_depths_iterator (s);
205 for (; d.rem; xcb_depth_next (&d)) {
206 xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator (d.data);
207 for (; v.rem; xcb_visualtype_next (&v)) {
208 if (v.data->visual_id == visual)
209 return v.data;
210 }
211 }
212
213 return 0;
214 }
215
216 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)217 _cairo_boilerplate_xcb_create_window (const char *name,
218 cairo_content_t content,
219 double width,
220 double height,
221 double max_width,
222 double max_height,
223 cairo_boilerplate_mode_t mode,
224 int id,
225 void **closure)
226 {
227 xcb_target_closure_t *xtc;
228 xcb_connection_t *c;
229 xcb_screen_t *s;
230 xcb_void_cookie_t cookie;
231 cairo_surface_t *surface;
232 cairo_status_t status;
233 uint32_t values[] = { 1 };
234
235 *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
236
237 if (width == 0)
238 width = 1;
239 if (height == 0)
240 height = 1;
241
242 xtc->c = c = xcb_connect(NULL,NULL);
243 if (xcb_connection_has_error(c)) {
244 free (xtc);
245 return NULL;
246 }
247
248 xtc->surface = NULL;
249
250 s = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
251 xtc->is_pixmap = FALSE;
252 xtc->drawable = xcb_generate_id (c);
253 cookie = xcb_create_window_checked (c,
254 s->root_depth,
255 xtc->drawable,
256 s->root,
257 0, 0, width, height, 0,
258 XCB_WINDOW_CLASS_INPUT_OUTPUT,
259 s->root_visual,
260 XCB_CW_OVERRIDE_REDIRECT,
261 values);
262 xcb_map_window (c, xtc->drawable);
263
264 /* slow, but sure */
265 if (xcb_request_check (c, cookie) != NULL) {
266 xcb_disconnect (c);
267 free (xtc);
268 return NULL;
269 }
270
271 surface = cairo_xcb_surface_create (c,
272 xtc->drawable,
273 lookup_visual (s, s->root_visual),
274 width, height);
275
276 xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
277 status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
278 if (status == CAIRO_STATUS_SUCCESS)
279 return surface;
280
281 cairo_surface_destroy (surface);
282
283 _cairo_boilerplate_xcb_cleanup (xtc);
284 return cairo_boilerplate_surface_create_in_error (status);
285 }
286
287 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)288 _cairo_boilerplate_xcb_create_window_db (const char *name,
289 cairo_content_t content,
290 double width,
291 double height,
292 double max_width,
293 double max_height,
294 cairo_boilerplate_mode_t mode,
295 int id,
296 void **closure)
297 {
298 xcb_target_closure_t *xtc;
299 xcb_connection_t *c;
300 xcb_screen_t *s;
301 xcb_void_cookie_t cookie;
302 cairo_surface_t *surface;
303 cairo_status_t status;
304 uint32_t values[] = { 1 };
305
306 *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
307
308 if (width == 0)
309 width = 1;
310 if (height == 0)
311 height = 1;
312
313 xtc->c = c = xcb_connect(NULL,NULL);
314 if (xcb_connection_has_error(c)) {
315 free (xtc);
316 return NULL;
317 }
318
319 xtc->surface = NULL;
320
321 s = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
322 xtc->is_pixmap = FALSE;
323 xtc->drawable = xcb_generate_id (c);
324 cookie = xcb_create_window_checked (c,
325 s->root_depth,
326 xtc->drawable,
327 s->root,
328 0, 0, width, height, 0,
329 XCB_WINDOW_CLASS_INPUT_OUTPUT,
330 s->root_visual,
331 XCB_CW_OVERRIDE_REDIRECT,
332 values);
333 xcb_map_window (c, xtc->drawable);
334
335 /* slow, but sure */
336 if (xcb_request_check (c, cookie) != NULL) {
337 xcb_disconnect (c);
338 free (xtc);
339 return NULL;
340 }
341
342 xtc->surface = cairo_xcb_surface_create (c,
343 xtc->drawable,
344 lookup_visual (s, s->root_visual),
345 width, height);
346 surface = cairo_surface_create_similar (xtc->surface, content, width, height);
347
348 xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
349 status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
350 if (status == CAIRO_STATUS_SUCCESS)
351 return surface;
352
353 cairo_surface_destroy (surface);
354
355 _cairo_boilerplate_xcb_cleanup (xtc);
356 return cairo_boilerplate_surface_create_in_error (status);
357 }
358
359 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)360 _cairo_boilerplate_xcb_create_render_0_0 (const char *name,
361 cairo_content_t content,
362 double width,
363 double height,
364 double max_width,
365 double max_height,
366 cairo_boilerplate_mode_t mode,
367 int id,
368 void **closure)
369 {
370 xcb_screen_t *root;
371 xcb_target_closure_t *xtc;
372 xcb_connection_t *c;
373 xcb_render_pictforminfo_t *render_format;
374 int depth;
375 xcb_void_cookie_t cookie;
376 cairo_surface_t *surface, *tmp;
377 cairo_status_t status;
378 void *formats;
379
380 *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
381
382 if (width == 0)
383 width = 1;
384 if (height == 0)
385 height = 1;
386
387 xtc->c = c = xcb_connect(NULL,NULL);
388 if (xcb_connection_has_error(c)) {
389 free (xtc);
390 return NULL;
391 }
392
393 root = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
394
395 xtc->surface = NULL;
396 xtc->is_pixmap = TRUE;
397 xtc->drawable = xcb_generate_id (c);
398 switch (content) {
399 case CAIRO_CONTENT_COLOR:
400 depth = 24;
401 cookie = xcb_create_pixmap_checked (c, depth,
402 xtc->drawable, root->root,
403 width, height);
404 break;
405
406 case CAIRO_CONTENT_COLOR_ALPHA:
407 depth = 32;
408 cookie = xcb_create_pixmap_checked (c, depth,
409 xtc->drawable, root->root,
410 width, height);
411 break;
412
413 case CAIRO_CONTENT_ALPHA: /* would be XCB_PICT_STANDARD_A_8 */
414 default:
415 xcb_disconnect (c);
416 free (xtc);
417 return NULL;
418 }
419
420 /* slow, but sure */
421 if (xcb_request_check (c, cookie) != NULL) {
422 xcb_disconnect (c);
423 free (xtc);
424 return NULL;
425 }
426
427 render_format = find_depth (c, depth, &formats);
428 if (render_format == NULL) {
429 xcb_disconnect (c);
430 free (xtc);
431 return NULL;
432 }
433
434 tmp = cairo_xcb_surface_create_with_xrender_format (c, root,
435 xtc->drawable,
436 render_format,
437 width, height);
438 if (cairo_surface_status (tmp)) {
439 free (formats);
440 xcb_disconnect (c);
441 free (xtc);
442 return tmp;
443 }
444
445 xtc->device = cairo_device_reference (cairo_surface_get_device (tmp));
446 cairo_xcb_device_debug_cap_xrender_version (xtc->device, 0, 0);
447
448 /* recreate with impaired connection */
449 surface = cairo_xcb_surface_create_with_xrender_format (c, root,
450 xtc->drawable,
451 render_format,
452 width, height);
453 free (formats);
454 cairo_surface_destroy (tmp);
455
456 assert (cairo_surface_get_device (surface) == xtc->device);
457
458 status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
459 if (status == CAIRO_STATUS_SUCCESS)
460 return surface;
461
462 cairo_surface_destroy (surface);
463
464 _cairo_boilerplate_xcb_cleanup (xtc);
465 return cairo_boilerplate_surface_create_in_error (status);
466 }
467
468 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)469 _cairo_boilerplate_xcb_create_fallback (const char *name,
470 cairo_content_t content,
471 double width,
472 double height,
473 double max_width,
474 double max_height,
475 cairo_boilerplate_mode_t mode,
476 int id,
477 void **closure)
478 {
479 xcb_target_closure_t *xtc;
480 xcb_connection_t *c;
481 xcb_screen_t *s;
482 xcb_void_cookie_t cookie;
483 cairo_surface_t *tmp, *surface;
484 cairo_status_t status;
485 uint32_t values[] = { 1 };
486
487 *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
488
489 if (width == 0)
490 width = 1;
491 if (height == 0)
492 height = 1;
493
494 xtc->c = c = xcb_connect (NULL,NULL);
495 if (xcb_connection_has_error(c)) {
496 free (xtc);
497 return NULL;
498 }
499
500 s = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
501 if (width > s->width_in_pixels || height > s->height_in_pixels) {
502 xcb_disconnect (c);
503 free (xtc);
504 return NULL;
505 }
506
507 xtc->surface = NULL;
508 xtc->is_pixmap = FALSE;
509 xtc->drawable = xcb_generate_id (c);
510 cookie = xcb_create_window_checked (c,
511 s->root_depth,
512 xtc->drawable,
513 s->root,
514 0, 0, width, height, 0,
515 XCB_WINDOW_CLASS_INPUT_OUTPUT,
516 s->root_visual,
517 XCB_CW_OVERRIDE_REDIRECT,
518 values);
519 xcb_map_window (c, xtc->drawable);
520
521 /* slow, but sure */
522 if (xcb_request_check (c, cookie) != NULL) {
523 xcb_disconnect (c);
524 free (xtc);
525 return NULL;
526 }
527
528 tmp = cairo_xcb_surface_create (c,
529 xtc->drawable,
530 lookup_visual (s, s->root_visual),
531 width, height);
532 if (cairo_surface_status (tmp)) {
533 xcb_disconnect (c);
534 free (xtc);
535 return tmp;
536 }
537
538 cairo_xcb_device_debug_cap_xrender_version (cairo_surface_get_device (tmp),
539 -1, -1);
540 /* recreate with impaired connection */
541 surface = cairo_xcb_surface_create (c,
542 xtc->drawable,
543 lookup_visual (s, s->root_visual),
544 width, height);
545 cairo_surface_destroy (tmp);
546
547 xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
548 status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
549 if (status == CAIRO_STATUS_SUCCESS)
550 return surface;
551
552 cairo_surface_destroy (surface);
553
554 _cairo_boilerplate_xcb_cleanup (xtc);
555 return cairo_boilerplate_surface_create_in_error (status);
556 }
557
558 static cairo_status_t
_cairo_boilerplate_xcb_finish_surface(cairo_surface_t * surface)559 _cairo_boilerplate_xcb_finish_surface (cairo_surface_t *surface)
560 {
561 xcb_target_closure_t *xtc = cairo_surface_get_user_data (surface,
562 &xcb_closure_key);
563 xcb_generic_event_t *ev;
564
565 if (xtc->surface != NULL) {
566 cairo_t *cr;
567
568 cr = cairo_create (xtc->surface);
569 cairo_surface_set_device_offset (surface, 0, 0);
570 cairo_set_source_surface (cr, surface, 0, 0);
571 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
572 cairo_paint (cr);
573 cairo_destroy (cr);
574
575 surface = xtc->surface;
576 }
577
578 cairo_surface_flush (surface);
579 if (cairo_surface_status (surface))
580 return cairo_surface_status (surface);
581
582 while ((ev = xcb_poll_for_event (xtc->c)) != NULL) {
583 cairo_status_t status = CAIRO_STATUS_SUCCESS;
584
585 if (ev->response_type == 0 /* trust me! */) {
586 xcb_generic_error_t *error = (xcb_generic_error_t *) ev;
587
588 #if XCB_GENERIC_ERROR_HAS_MAJOR_MINOR_CODES
589 fprintf (stderr,
590 "Detected error during xcb run: %d major=%d, minor=%d\n",
591 error->error_code, error->major_code, error->minor_code);
592 #else
593 fprintf (stderr,
594 "Detected error during xcb run: %d\n",
595 error->error_code);
596 #endif
597 free (error);
598
599 status = CAIRO_STATUS_WRITE_ERROR;
600 }
601
602 if (status)
603 return status;
604 }
605
606 if (xcb_connection_has_error (xtc->c))
607 return CAIRO_STATUS_WRITE_ERROR;
608
609 return CAIRO_STATUS_SUCCESS;
610 }
611
612 static const cairo_boilerplate_target_t targets[] = {
613 /* Acceleration architectures may make the results differ by a
614 * bit, so we set the error tolerance to 1. */
615 {
616 "xcb", "xlib", NULL, NULL,
617 CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR_ALPHA, 1,
618 "cairo_xcb_surface_create_with_xrender_format",
619 _cairo_boilerplate_xcb_create_surface,
620 NULL,
621 _cairo_boilerplate_xcb_finish_surface,
622 _cairo_boilerplate_get_image_surface,
623 cairo_surface_write_to_png,
624 _cairo_boilerplate_xcb_cleanup,
625 _cairo_boilerplate_xcb_synchronize,
626 NULL,
627 TRUE, FALSE, FALSE
628 },
629 {
630 "xcb", "xlib", NULL, NULL,
631 CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
632 "cairo_xcb_surface_create_with_xrender_format",
633 _cairo_boilerplate_xcb_create_surface,
634 NULL,
635 _cairo_boilerplate_xcb_finish_surface,
636 _cairo_boilerplate_get_image_surface,
637 cairo_surface_write_to_png,
638 _cairo_boilerplate_xcb_cleanup,
639 _cairo_boilerplate_xcb_synchronize,
640 NULL,
641 FALSE, FALSE, FALSE
642 },
643 {
644 "xcb-window", "xlib", NULL, NULL,
645 CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
646 "cairo_xcb_surface_create_with_xrender_format",
647 _cairo_boilerplate_xcb_create_window,
648 NULL,
649 _cairo_boilerplate_xcb_finish_surface,
650 _cairo_boilerplate_get_image_surface,
651 cairo_surface_write_to_png,
652 _cairo_boilerplate_xcb_cleanup,
653 _cairo_boilerplate_xcb_synchronize,
654 NULL,
655 FALSE, FALSE, FALSE
656 },
657 {
658 "xcb-window&", "xlib", NULL, NULL,
659 CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
660 "cairo_xcb_surface_create_with_xrender_format",
661 _cairo_boilerplate_xcb_create_window_db,
662 NULL,
663 _cairo_boilerplate_xcb_finish_surface,
664 _cairo_boilerplate_get_image_surface,
665 cairo_surface_write_to_png,
666 _cairo_boilerplate_xcb_cleanup,
667 _cairo_boilerplate_xcb_synchronize,
668 NULL,
669 FALSE, FALSE, FALSE
670 },
671 {
672 "xcb-render-0.0", "xlib-fallback", NULL, NULL,
673 CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR_ALPHA, 1,
674 "cairo_xcb_surface_create_with_xrender_format",
675 _cairo_boilerplate_xcb_create_render_0_0,
676 NULL,
677 _cairo_boilerplate_xcb_finish_surface,
678 _cairo_boilerplate_get_image_surface,
679 cairo_surface_write_to_png,
680 _cairo_boilerplate_xcb_cleanup,
681 _cairo_boilerplate_xcb_synchronize,
682 NULL,
683 FALSE, FALSE, FALSE
684 },
685 {
686 "xcb-render-0.0", "xlib-fallback", NULL, NULL,
687 CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
688 "cairo_xcb_surface_create_with_xrender_format",
689 _cairo_boilerplate_xcb_create_render_0_0,
690 NULL,
691 _cairo_boilerplate_xcb_finish_surface,
692 _cairo_boilerplate_get_image_surface,
693 cairo_surface_write_to_png,
694 _cairo_boilerplate_xcb_cleanup,
695 _cairo_boilerplate_xcb_synchronize,
696 NULL,
697 FALSE, FALSE, FALSE
698 },
699 {
700 "xcb-fallback", "xlib-fallback", NULL, NULL,
701 CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
702 "cairo_xcb_surface_create_with_xrender_format",
703 _cairo_boilerplate_xcb_create_fallback,
704 NULL,
705 _cairo_boilerplate_xcb_finish_surface,
706 _cairo_boilerplate_get_image_surface,
707 cairo_surface_write_to_png,
708 _cairo_boilerplate_xcb_cleanup,
709 _cairo_boilerplate_xcb_synchronize,
710 NULL,
711 FALSE, FALSE, FALSE
712 },
713 };
714 CAIRO_BOILERPLATE (xcb, targets)
715