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