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
#include "cairo-malloc-private.h"
29

            
30
#include <cairo-xcb.h>
31

            
32
#include <assert.h>
33

            
34
/* Errors have response_type == 0 */
35
#define CAIRO_XCB_ERROR 0
36

            
37
static const cairo_user_data_key_t xcb_closure_key;
38

            
39
typedef struct _xcb_target_closure {
40
    xcb_connection_t *c;
41
    cairo_device_t *device;
42
    uint32_t drawable;
43
    cairo_bool_t is_pixmap;
44
    cairo_surface_t *surface;
45
} xcb_target_closure_t;
46

            
47
static cairo_status_t
48
_cairo_boilerplate_xcb_handle_errors (xcb_target_closure_t *xtc)
49
{
50
    xcb_generic_event_t *ev = NULL;
51

            
52
    /* Ignore all MappingNotify events; those might happen without us causing them */
53
    do {
54
	free(ev);
55
	ev = xcb_poll_for_event(xtc->c);
56
    } while (ev != NULL && ev->response_type == XCB_MAPPING_NOTIFY);
57

            
58
    if (ev != NULL) {
59
	if (ev->response_type == CAIRO_XCB_ERROR) {
60
	    xcb_generic_error_t *error = (xcb_generic_error_t *) ev;
61

            
62
	    fprintf (stderr,
63
		     "Detected error during xcb run: error=%d, "
64
		     "seqno=0x%02x, major=%d, minor=%d\n",
65
		     error->error_code, error->sequence,
66
		     error->major_code, error->minor_code);
67
	} else {
68
	    fprintf (stderr,
69
		     "Detected unexpected event during xcb run: type=%d, seqno=0x%02x\n",
70
		     ev->response_type, ev->sequence);
71
	}
72
	free (ev);
73

            
74
	/* Silently discard all following errors */
75
	while ((ev = xcb_poll_for_event (xtc->c)) != NULL)
76
	    free (ev);
77

            
78
	return CAIRO_STATUS_WRITE_ERROR;
79
    }
80

            
81
    return CAIRO_STATUS_SUCCESS;
82
}
83

            
84
static void
85
_cairo_boilerplate_xcb_sync_server (xcb_target_closure_t *xtc)
86
{
87
    free (xcb_get_input_focus_reply (xtc->c,
88
				     xcb_get_input_focus (xtc->c), NULL));
89
}
90

            
91
static void
92
_cairo_boilerplate_xcb_setup_test_surface (cairo_surface_t *surface)
93
{
94

            
95
    /* For testing purposes, tell the X server to strictly adhere to the
96
     * Render specification.
97
     */
98
    cairo_xcb_device_debug_set_precision(cairo_surface_get_device(surface),
99
					 XCB_RENDER_POLY_MODE_PRECISE);
100
}
101

            
102
static void
103
_cairo_boilerplate_xcb_cleanup (void *closure)
104
{
105
    xcb_target_closure_t *xtc = closure;
106
    cairo_status_t status;
107

            
108
    cairo_surface_finish (xtc->surface);
109
    if (xtc->is_pixmap)
110
	xcb_free_pixmap (xtc->c, xtc->drawable);
111
    else
112
	xcb_destroy_window (xtc->c, xtc->drawable);
113
    cairo_surface_destroy (xtc->surface);
114

            
115
    cairo_device_finish (xtc->device);
116
    cairo_device_destroy (xtc->device);
117

            
118
    /* First synchronize with the X server to make sure there are no more errors
119
     * in-flight which we would miss otherwise */
120
    _cairo_boilerplate_xcb_sync_server (xtc);
121
    status = _cairo_boilerplate_xcb_handle_errors (xtc);
122
    assert (status == CAIRO_STATUS_SUCCESS);
123

            
124
    xcb_disconnect (xtc->c);
125

            
126
    free (xtc);
127
}
128

            
129
static void
130
_cairo_boilerplate_xcb_synchronize (void *closure)
131
{
132
    xcb_target_closure_t *xtc = closure;
133
    cairo_status_t status;
134
    free (xcb_get_image_reply (xtc->c,
135
		xcb_get_image (xtc->c, XCB_IMAGE_FORMAT_Z_PIXMAP,
136
		    xtc->drawable, 0, 0, 1, 1, /* AllPlanes */ -1),
137
		0));
138

            
139
    status = _cairo_boilerplate_xcb_handle_errors (xtc);
140
    assert (status == CAIRO_STATUS_SUCCESS);
141
}
142

            
143
static xcb_render_pictforminfo_t *
144
find_depth (xcb_connection_t  *connection,
145
	    int 	       depth,
146
	    void	     **formats_out)
147
{
148
    xcb_render_query_pict_formats_reply_t *formats;
149
    xcb_render_query_pict_formats_cookie_t cookie;
150
    xcb_render_pictforminfo_iterator_t i;
151

            
152
    cookie = xcb_render_query_pict_formats (connection);
153
    xcb_flush (connection);
154

            
155
    formats = xcb_render_query_pict_formats_reply (connection, cookie, 0);
156
    if (formats == NULL)
157
	return NULL;
158

            
159
    for (i = xcb_render_query_pict_formats_formats_iterator (formats);
160
	 i.rem;
161
	 xcb_render_pictforminfo_next (&i))
162
    {
163
	if (XCB_RENDER_PICT_TYPE_DIRECT != i.data->type)
164
	    continue;
165

            
166
	if (depth != i.data->depth)
167
	    continue;
168

            
169
	*formats_out = formats;
170
	return i.data;
171
    }
172

            
173
    free (formats);
174
    return NULL;
175
}
176

            
177
static const cairo_user_data_key_t key;
178
static const cairo_user_data_key_t key2;
179

            
180
struct similar {
181
    xcb_connection_t *connection;
182
    xcb_drawable_t pixmap;
183
};
184

            
185
static void _destroy_similar (void *closure)
186
{
187
    struct similar *similar = closure;
188

            
189
    xcb_free_pixmap (similar->connection, similar->pixmap);
190
    free (similar);
191
}
192

            
193
struct xcb_info {
194
	xcb_render_query_pict_formats_reply_t *formats;
195
	xcb_render_pictforminfo_t *render_format[3];
196
};
197

            
198
static cairo_surface_t *
199
_cairo_boilerplate_xcb_create_similar (cairo_surface_t *other,
200
				       cairo_content_t content,
201
				       int width, int height)
202
{
203
    cairo_device_t *device = cairo_surface_get_device (other);
204
    struct xcb_info *info = cairo_device_get_user_data (device, &key);
205
    xcb_screen_t *root;
206
    cairo_surface_t *surface;
207
    struct similar *similar;
208
    xcb_render_pictforminfo_t *render_format;
209
    int depth;
210

            
211
    similar = _cairo_malloc (sizeof (*similar));
212

            
213
    switch (content) {
214
    default:
215
    case CAIRO_CONTENT_COLOR_ALPHA:
216
	    depth = 32;
217
	    render_format = info->render_format[0];
218
	    break;
219
    case CAIRO_CONTENT_COLOR:
220
	    depth = 24;
221
	    render_format = info->render_format[1];
222
	    break;
223
    case CAIRO_CONTENT_ALPHA:
224
	    depth = 8;
225
	    render_format = info->render_format[2];
226
	    break;
227
    }
228

            
229
    similar->connection =
230
	cairo_xcb_device_get_connection (cairo_surface_get_device(other));
231
    similar->pixmap = xcb_generate_id (similar->connection);
232

            
233
    root = xcb_setup_roots_iterator(xcb_get_setup(similar->connection)).data;
234
    xcb_create_pixmap (similar->connection, depth,
235
		       similar->pixmap, root->root,
236
		       width, height);
237

            
238
    surface = cairo_xcb_surface_create_with_xrender_format (similar->connection,
239
							    root,
240
							    similar->pixmap,
241
							    render_format,
242
							    width, height);
243
    cairo_surface_set_user_data (surface, &key, similar, _destroy_similar);
244

            
245
    return surface;
246
}
247

            
248
static cairo_surface_t *
249
_cairo_boilerplate_xcb_create_surface (const char		 *name,
250
				       cairo_content_t		  content,
251
				       double			  width,
252
				       double			  height,
253
				       double			  max_width,
254
				       double			  max_height,
255
				       cairo_boilerplate_mode_t   mode,
256
				       void			**closure)
257
{
258
    xcb_screen_t *root;
259
    xcb_target_closure_t *xtc;
260
    xcb_connection_t *c;
261
    xcb_render_query_pict_formats_cookie_t formats_cookie;
262
    xcb_render_pictforminfo_t *render_format;
263
    xcb_render_pictforminfo_iterator_t i;
264
    struct xcb_info *info;
265
    int depth;
266
    xcb_void_cookie_t cookie;
267
    cairo_surface_t *surface;
268
    cairo_status_t status;
269

            
270
    *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
271
    info = xcalloc (1, sizeof (struct xcb_info));
272

            
273
    if (width == 0)
274
	width = 1;
275
    if (height == 0)
276
	height = 1;
277

            
278
    xtc->c = c = xcb_connect(NULL,NULL);
279
    if (c == NULL || xcb_connection_has_error(c)) {
280
	free (xtc);
281
	free (info);
282
	return NULL;
283
    }
284

            
285
    root = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
286
    formats_cookie = xcb_render_query_pict_formats (c);
287

            
288
    xtc->surface = NULL;
289
    xtc->is_pixmap = TRUE;
290
    xtc->drawable = xcb_generate_id (c);
291
    switch (content) {
292
    case CAIRO_CONTENT_COLOR:
293
	depth = 24;
294
	break;
295

            
296
    case CAIRO_CONTENT_COLOR_ALPHA:
297
	depth = 32;
298
	break;
299

            
300
    case CAIRO_CONTENT_ALPHA:  /* would be XCB_PICT_STANDARD_A_8 */
301
    default:
302
	xcb_disconnect (c);
303
	free (xtc);
304
	return NULL;
305
    }
306

            
307
    cookie = xcb_create_pixmap_checked (c, depth,
308
					xtc->drawable, root->root,
309
					width, height);
310

            
311
    /* slow, but sure */
312
    if (xcb_request_check (c, cookie) != NULL) {
313
	xcb_disconnect (c);
314
	free (xtc);
315
	free (info);
316
	return NULL;
317
    }
318

            
319
    info->formats = xcb_render_query_pict_formats_reply (c, formats_cookie, 0);
320
    if (info->formats == NULL) {
321
	xcb_disconnect (c);
322
	free (xtc);
323
	free (info);
324
	return NULL;
325
    }
326

            
327
    for (i = xcb_render_query_pict_formats_formats_iterator (info->formats);
328
	 i.rem;
329
	 xcb_render_pictforminfo_next (&i))
330
    {
331
	if (XCB_RENDER_PICT_TYPE_DIRECT != i.data->type)
332
	    continue;
333

            
334
	if (i.data->depth == 32) {
335
		if (info->render_format[0] == 0)
336
			info->render_format[0] = i.data;
337
	} else if (i.data->depth == 24) {
338
		if (info->render_format[1] == 0)
339
			info->render_format[1] = i.data;
340
	} else if (i.data->depth == 8) {
341
		if (info->render_format[2] == 0)
342
			info->render_format[2] = i.data;
343
	}
344
    }
345

            
346
    assert (info->render_format[0]);
347
    assert (info->render_format[1]);
348
    assert (info->render_format[2]);
349

            
350
    switch (content) {
351
    default:
352
    case CAIRO_CONTENT_COLOR_ALPHA:
353
	    render_format = info->render_format[0];
354
	    break;
355

            
356
    case CAIRO_CONTENT_COLOR:
357
	    render_format = info->render_format[1];
358
	    break;
359

            
360
    case CAIRO_CONTENT_ALPHA:  /* would be XCB_PICT_STANDARD_A_8 */
361
	    render_format = info->render_format[2];
362
	    break;
363
    }
364

            
365
    surface = cairo_xcb_surface_create_with_xrender_format (c, root,
366
							    xtc->drawable,
367
							    render_format,
368
							    width, height);
369
    cairo_device_set_user_data (cairo_surface_get_device (surface), &key, info, free);
370
    cairo_device_set_user_data (cairo_surface_get_device (surface), &key2, info->formats, free);
371
    if (mode != CAIRO_BOILERPLATE_MODE_PERF)
372
	_cairo_boilerplate_xcb_setup_test_surface(surface);
373

            
374
    xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
375
    status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
376
    if (status == CAIRO_STATUS_SUCCESS)
377
	return surface;
378

            
379
    cairo_surface_destroy (surface);
380

            
381
    _cairo_boilerplate_xcb_cleanup (xtc);
382
    return cairo_boilerplate_surface_create_in_error (status);
383
}
384

            
385
static xcb_visualtype_t *
386
lookup_visual (xcb_screen_t   *s,
387
	       xcb_visualid_t  visual)
388
{
389
    xcb_depth_iterator_t d;
390

            
391
    d = xcb_screen_allowed_depths_iterator (s);
392
    for (; d.rem; xcb_depth_next (&d)) {
393
	xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator (d.data);
394
	for (; v.rem; xcb_visualtype_next (&v)) {
395
	    if (v.data->visual_id == visual)
396
		return v.data;
397
	}
398
    }
399

            
400
    return 0;
401
}
402

            
403
static cairo_surface_t *
404
_cairo_boilerplate_xcb_create_window (const char		*name,
405
				      cairo_content_t		 content,
406
				      double			 width,
407
				      double			 height,
408
				      double			 max_width,
409
				      double			 max_height,
410
				      cairo_boilerplate_mode_t	 mode,
411
				      void		       **closure)
412
{
413
    xcb_target_closure_t *xtc;
414
    xcb_connection_t *c;
415
    xcb_screen_t *s;
416
    xcb_void_cookie_t cookie;
417
    cairo_surface_t *surface;
418
    cairo_status_t status;
419
    uint32_t values[] = { 1 };
420

            
421
    *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
422

            
423
    if (width == 0)
424
	width = 1;
425
    if (height == 0)
426
	height = 1;
427

            
428
    xtc->c = c = xcb_connect(NULL,NULL);
429
    if (xcb_connection_has_error(c)) {
430
	free (xtc);
431
	return NULL;
432
    }
433

            
434
    xtc->surface = NULL;
435

            
436
    s = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
437
    if (width > s->width_in_pixels || height > s->height_in_pixels) {
438
	xcb_disconnect (c);
439
	free (xtc);
440
	return NULL;
441
    }
442

            
443
    xtc->is_pixmap = FALSE;
444
    xtc->drawable = xcb_generate_id (c);
445
    cookie = xcb_create_window_checked (c,
446
					s->root_depth,
447
					xtc->drawable,
448
					s->root,
449
					0, 0, width, height, 0,
450
					XCB_WINDOW_CLASS_INPUT_OUTPUT,
451
					s->root_visual,
452
					XCB_CW_OVERRIDE_REDIRECT,
453
					values);
454
    xcb_map_window (c, xtc->drawable);
455

            
456
    /* slow, but sure */
457
    if (xcb_request_check (c, cookie) != NULL) {
458
	xcb_disconnect (c);
459
	free (xtc);
460
	return NULL;
461
    }
462

            
463
    surface = cairo_xcb_surface_create (c,
464
					xtc->drawable,
465
					lookup_visual (s, s->root_visual),
466
					width, height);
467

            
468
    xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
469
    status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
470
    if (status == CAIRO_STATUS_SUCCESS)
471
	return surface;
472

            
473
    cairo_surface_destroy (surface);
474

            
475
    _cairo_boilerplate_xcb_cleanup (xtc);
476
    return cairo_boilerplate_surface_create_in_error (status);
477
}
478

            
479
static cairo_surface_t *
480
_cairo_boilerplate_xcb_create_window_db (const char		   *name,
481
					 cairo_content_t	    content,
482
					 double 		    width,
483
					 double 		    height,
484
					 double 		    max_width,
485
					 double 		    max_height,
486
					 cairo_boilerplate_mode_t   mode,
487
					 void			  **closure)
488
{
489
    xcb_target_closure_t *xtc;
490
    xcb_connection_t *c;
491
    xcb_screen_t *s;
492
    xcb_void_cookie_t cookie;
493
    cairo_surface_t *surface;
494
    cairo_status_t status;
495
    uint32_t values[] = { 1 };
496

            
497
    *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
498

            
499
    if (width == 0)
500
	width = 1;
501
    if (height == 0)
502
	height = 1;
503

            
504
    xtc->c = c = xcb_connect(NULL,NULL);
505
    if (xcb_connection_has_error(c)) {
506
	free (xtc);
507
	return NULL;
508
    }
509

            
510
    xtc->surface = NULL;
511

            
512
    s = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
513
    if (width > s->width_in_pixels || height > s->height_in_pixels) {
514
	xcb_disconnect (c);
515
	free (xtc);
516
	return NULL;
517
    }
518

            
519
    xtc->is_pixmap = FALSE;
520
    xtc->drawable = xcb_generate_id (c);
521
    cookie = xcb_create_window_checked (c,
522
					s->root_depth,
523
					xtc->drawable,
524
					s->root,
525
					0, 0, width, height, 0,
526
					XCB_WINDOW_CLASS_INPUT_OUTPUT,
527
					s->root_visual,
528
					XCB_CW_OVERRIDE_REDIRECT,
529
					values);
530
    xcb_map_window (c, xtc->drawable);
531

            
532
    /* slow, but sure */
533
    if (xcb_request_check (c, cookie) != NULL) {
534
	xcb_disconnect (c);
535
	free (xtc);
536
	return NULL;
537
    }
538

            
539
    xtc->surface = cairo_xcb_surface_create (c,
540
					     xtc->drawable,
541
					     lookup_visual (s, s->root_visual),
542
					     width, height);
543
    surface = cairo_surface_create_similar (xtc->surface, content, width, height);
544

            
545
    xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
546
    status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
547
    if (status == CAIRO_STATUS_SUCCESS)
548
	return surface;
549

            
550
    cairo_surface_destroy (surface);
551

            
552
    _cairo_boilerplate_xcb_cleanup (xtc);
553
    return cairo_boilerplate_surface_create_in_error (status);
554
}
555

            
556
static cairo_surface_t *
557
_cairo_boilerplate_xcb_create_render_0_0 (const char		    *name,
558
					  cairo_content_t	     content,
559
					  double		     width,
560
					  double		     height,
561
					  double		     max_width,
562
					  double		     max_height,
563
					  cairo_boilerplate_mode_t   mode,
564
					  void			   **closure)
565
{
566
    xcb_screen_t *root;
567
    xcb_target_closure_t *xtc;
568
    xcb_connection_t *c;
569
    xcb_render_pictforminfo_t *render_format;
570
    int depth;
571
    xcb_void_cookie_t cookie;
572
    cairo_surface_t *surface;
573
    cairo_status_t status;
574
    void *formats;
575

            
576
    *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
577

            
578
    if (width == 0)
579
	width = 1;
580
    if (height == 0)
581
	height = 1;
582

            
583
    xtc->c = c = xcb_connect(NULL,NULL);
584
    if (xcb_connection_has_error(c)) {
585
	free (xtc);
586
	return NULL;
587
    }
588

            
589
    root = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
590

            
591
    xtc->surface = NULL;
592
    xtc->is_pixmap = TRUE;
593
    xtc->drawable = xcb_generate_id (c);
594
    switch (content) {
595
    case CAIRO_CONTENT_COLOR:
596
	depth = 24;
597
	cookie = xcb_create_pixmap_checked (c, depth,
598
					    xtc->drawable, root->root,
599
					    width, height);
600
	break;
601

            
602
    case CAIRO_CONTENT_COLOR_ALPHA:
603
	depth = 32;
604
	cookie = xcb_create_pixmap_checked (c, depth,
605
					    xtc->drawable, root->root,
606
					    width, height);
607
	break;
608

            
609
    case CAIRO_CONTENT_ALPHA:  /* would be XCB_PICT_STANDARD_A_8 */
610
    default:
611
	xcb_disconnect (c);
612
	free (xtc);
613
	return NULL;
614
    }
615

            
616
    /* slow, but sure */
617
    if (xcb_request_check (c, cookie) != NULL) {
618
	xcb_disconnect (c);
619
	free (xtc);
620
	return NULL;
621
    }
622
    xcb_flush (c);
623

            
624
    render_format = find_depth (c, depth, &formats);
625
    if (render_format == NULL) {
626
	xcb_disconnect (c);
627
	free (xtc);
628
	return NULL;
629
    }
630

            
631
    surface = cairo_xcb_surface_create_with_xrender_format (c, root,
632
							    xtc->drawable,
633
							    render_format,
634
							    width, height);
635
    free (formats);
636
    if (cairo_surface_status (surface)) {
637
	xcb_disconnect (c);
638
	free (xtc);
639
	return surface;
640
    }
641

            
642
    xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
643
    cairo_xcb_device_debug_cap_xrender_version (xtc->device, 0, 0);
644

            
645
    assert (cairo_surface_get_device (surface) == xtc->device);
646

            
647
    status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
648
    if (status == CAIRO_STATUS_SUCCESS)
649
	return surface;
650

            
651
    cairo_surface_destroy (surface);
652

            
653
    _cairo_boilerplate_xcb_cleanup (xtc);
654
    return cairo_boilerplate_surface_create_in_error (status);
655
}
656

            
657
static cairo_surface_t *
658
_cairo_boilerplate_xcb_create_fallback (const char		  *name,
659
					cairo_content_t 	   content,
660
					double			   width,
661
					double			   height,
662
					double			   max_width,
663
					double			   max_height,
664
					cairo_boilerplate_mode_t   mode,
665
					void			 **closure)
666
{
667
    xcb_target_closure_t *xtc;
668
    xcb_connection_t *c;
669
    xcb_screen_t *s;
670
    xcb_void_cookie_t cookie;
671
    cairo_surface_t *surface;
672
    cairo_status_t status;
673
    uint32_t values[] = { 1 };
674

            
675
    *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
676

            
677
    if (width == 0)
678
	width = 1;
679
    if (height == 0)
680
	height = 1;
681

            
682
    xtc->c = c = xcb_connect (NULL,NULL);
683
    if (xcb_connection_has_error(c)) {
684
	free (xtc);
685
	return NULL;
686
    }
687

            
688
    s = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
689
    if (width > s->width_in_pixels || height > s->height_in_pixels) {
690
	xcb_disconnect (c);
691
	free (xtc);
692
	return NULL;
693
    }
694

            
695
    xtc->surface = NULL;
696
    xtc->is_pixmap = FALSE;
697
    xtc->drawable = xcb_generate_id (c);
698
    cookie = xcb_create_window_checked (c,
699
					s->root_depth,
700
					xtc->drawable,
701
					s->root,
702
					0, 0, width, height, 0,
703
					XCB_WINDOW_CLASS_INPUT_OUTPUT,
704
					s->root_visual,
705
					XCB_CW_OVERRIDE_REDIRECT,
706
					values);
707
    xcb_map_window (c, xtc->drawable);
708

            
709
    /* slow, but sure */
710
    if (xcb_request_check (c, cookie) != NULL) {
711
	xcb_disconnect (c);
712
	free (xtc);
713
	return NULL;
714
    }
715

            
716
    surface = cairo_xcb_surface_create (c,
717
					xtc->drawable,
718
					lookup_visual (s, s->root_visual),
719
					width, height);
720
    if (cairo_surface_status (surface)) {
721
	xcb_disconnect (c);
722
	free (xtc);
723
	return surface;
724
    }
725

            
726
    cairo_xcb_device_debug_cap_xrender_version (cairo_surface_get_device (surface),
727
						-1, -1);
728

            
729
    xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
730
    status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
731
    if (status == CAIRO_STATUS_SUCCESS)
732
	return surface;
733

            
734
    cairo_surface_destroy (surface);
735

            
736
    _cairo_boilerplate_xcb_cleanup (xtc);
737
    return cairo_boilerplate_surface_create_in_error (status);
738
}
739

            
740
static cairo_status_t
741
_cairo_boilerplate_xcb_finish_surface (cairo_surface_t *surface)
742
{
743
    xcb_target_closure_t *xtc = cairo_surface_get_user_data (surface,
744
							     &xcb_closure_key);
745
    cairo_status_t status;
746

            
747
    if (xtc->surface != NULL) {
748
	cairo_t *cr;
749

            
750
	cr = cairo_create (xtc->surface);
751
	cairo_set_source_surface (cr, surface, 0, 0);
752
	cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
753
	cairo_paint (cr);
754
	cairo_destroy (cr);
755

            
756
	surface = xtc->surface;
757
    }
758

            
759
    cairo_surface_flush (surface);
760
    if (cairo_surface_status (surface))
761
	return cairo_surface_status (surface);
762

            
763
    /* First synchronize with the X server to make sure there are no more errors
764
     * in-flight which we would miss otherwise */
765
    _cairo_boilerplate_xcb_sync_server (xtc);
766
    status = _cairo_boilerplate_xcb_handle_errors (xtc);
767
    if (status)
768
	return status;
769

            
770
    if (xcb_connection_has_error (xtc->c))
771
	return CAIRO_STATUS_WRITE_ERROR;
772

            
773
    return CAIRO_STATUS_SUCCESS;
774
}
775

            
776
static const cairo_boilerplate_target_t targets[] = {
777
    /* Acceleration architectures may make the results differ by a
778
     * bit, so we set the error tolerance to 1. */
779
    {
780
	"xcb", "traps", NULL, NULL,
781
	CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR_ALPHA, 1,
782
	"cairo_xcb_surface_create_with_xrender_format",
783
	_cairo_boilerplate_xcb_create_surface,
784
	_cairo_boilerplate_xcb_create_similar,
785
	NULL,
786
	_cairo_boilerplate_xcb_finish_surface,
787
	_cairo_boilerplate_get_image_surface,
788
	cairo_surface_write_to_png,
789
	_cairo_boilerplate_xcb_cleanup,
790
	_cairo_boilerplate_xcb_synchronize,
791
        NULL,
792
	TRUE, FALSE, FALSE
793
    },
794
    {
795
	"xcb", "traps", NULL, NULL,
796
	CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
797
	"cairo_xcb_surface_create_with_xrender_format",
798
	_cairo_boilerplate_xcb_create_surface,
799
	_cairo_boilerplate_xcb_create_similar,
800
	NULL,
801
	_cairo_boilerplate_xcb_finish_surface,
802
	_cairo_boilerplate_get_image_surface,
803
	cairo_surface_write_to_png,
804
	_cairo_boilerplate_xcb_cleanup,
805
	_cairo_boilerplate_xcb_synchronize,
806
        NULL,
807
	FALSE, FALSE, FALSE
808
    },
809
    {
810
	"xcb-window", "traps", NULL, NULL,
811
	CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
812
	"cairo_xcb_surface_create_with_xrender_format",
813
	_cairo_boilerplate_xcb_create_window,
814
	_cairo_boilerplate_xcb_create_similar,
815
	NULL,
816
	_cairo_boilerplate_xcb_finish_surface,
817
	_cairo_boilerplate_get_image_surface,
818
	cairo_surface_write_to_png,
819
	_cairo_boilerplate_xcb_cleanup,
820
	_cairo_boilerplate_xcb_synchronize,
821
        NULL,
822
	FALSE, FALSE, FALSE
823
    },
824
    {
825
	"xcb-window&", "traps", NULL, NULL,
826
	CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
827
	"cairo_xcb_surface_create_with_xrender_format",
828
	_cairo_boilerplate_xcb_create_window_db,
829
	_cairo_boilerplate_xcb_create_similar,
830
	NULL,
831
	_cairo_boilerplate_xcb_finish_surface,
832
	_cairo_boilerplate_get_image_surface,
833
	cairo_surface_write_to_png,
834
	_cairo_boilerplate_xcb_cleanup,
835
	_cairo_boilerplate_xcb_synchronize,
836
        NULL,
837
	FALSE, FALSE, FALSE
838
    },
839
    {
840
	"xcb-render-0_0", "xlib-fallback", NULL, NULL,
841
	CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR_ALPHA, 1,
842
	"cairo_xcb_surface_create_with_xrender_format",
843
	_cairo_boilerplate_xcb_create_render_0_0,
844
	cairo_surface_create_similar,
845
	NULL,
846
	_cairo_boilerplate_xcb_finish_surface,
847
	_cairo_boilerplate_get_image_surface,
848
	cairo_surface_write_to_png,
849
	_cairo_boilerplate_xcb_cleanup,
850
	_cairo_boilerplate_xcb_synchronize,
851
        NULL,
852
	FALSE, FALSE, FALSE
853
    },
854
    {
855
	"xcb-render-0_0", "xlib-fallback", NULL, NULL,
856
	CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
857
	"cairo_xcb_surface_create_with_xrender_format",
858
	_cairo_boilerplate_xcb_create_render_0_0,
859
	cairo_surface_create_similar,
860
	NULL,
861
	_cairo_boilerplate_xcb_finish_surface,
862
	_cairo_boilerplate_get_image_surface,
863
	cairo_surface_write_to_png,
864
	_cairo_boilerplate_xcb_cleanup,
865
	_cairo_boilerplate_xcb_synchronize,
866
        NULL,
867
	FALSE, FALSE, FALSE
868
    },
869
    {
870
	"xcb-fallback", "xlib-fallback", NULL, NULL,
871
	CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
872
	"cairo_xcb_surface_create_with_xrender_format",
873
	_cairo_boilerplate_xcb_create_fallback,
874
	cairo_surface_create_similar,
875
	NULL,
876
	_cairo_boilerplate_xcb_finish_surface,
877
	_cairo_boilerplate_get_image_surface,
878
	cairo_surface_write_to_png,
879
	_cairo_boilerplate_xcb_cleanup,
880
	_cairo_boilerplate_xcb_synchronize,
881
        NULL,
882
	FALSE, FALSE, FALSE
883
    },
884
};
885
1
CAIRO_BOILERPLATE (xcb, targets)