Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 1
/* Cairo - a vector graphics library with display and print output
2
 *
3
 * Copyright © 2009 Intel Corporation
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it either under the terms of the GNU Lesser General Public
7
 * License version 2.1 as published by the Free Software Foundation
8
 * (the "LGPL") or, at your option, under the terms of the Mozilla
9
 * Public License Version 1.1 (the "MPL"). If you do not alter this
10
 * notice, a recipient may use your version of this file under either
11
 * the MPL or the LGPL.
12
 *
13
 * You should have received a copy of the LGPL along with this library
14
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16
 * You should have received a copy of the MPL along with this library
17
 * in the file COPYING-MPL-1.1
18
 *
19
 * The contents of this file are subject to the Mozilla Public License
20
 * Version 1.1 (the "License"); you may not use this file except in
21
 * compliance with the License. You may obtain a copy of the License at
22
 * http://www.mozilla.org/MPL/
23
 *
24
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26
 * the specific language governing rights and limitations.
27
 *
28
 * Authors:
29
 *    Chris Wilson 
30
 */
31
 
32
 
33
#include "cairoint.h"
34
 
35
#include "cairo-xcb-private.h"
36
#include "cairo-hash-private.h"
37
#include "cairo-freelist-private.h"
38
#include "cairo-list-inline.h"
39
 
40
#include 
41
#include 
42
#include 
43
 
44
#if CAIRO_HAS_XCB_SHM_FUNCTIONS
45
#include 
46
#include 
47
#include 
48
#endif
49
 
50
typedef struct _cairo_xcb_xrender_format {
51
    cairo_hash_entry_t key;
52
    xcb_render_pictformat_t xrender_format;
53
} cairo_xcb_xrender_format_t;
54
 
55
typedef struct _cairo_xcb_xid {
56
    cairo_list_t link;
57
    uint32_t xid;
58
} cairo_xcb_xid_t;
59
 
60
#define XCB_RENDER_AT_LEAST(V, major, minor)	\
61
	(((V)->major_version > major) ||			\
62
	 (((V)->major_version == major) && ((V)->minor_version >= minor)))
63
 
64
#define XCB_RENDER_HAS_CREATE_PICTURE(surface)		XCB_RENDER_AT_LEAST((surface), 0, 0)
65
#define XCB_RENDER_HAS_COMPOSITE(surface)		XCB_RENDER_AT_LEAST((surface), 0, 0)
66
#define XCB_RENDER_HAS_COMPOSITE_TEXT(surface)		XCB_RENDER_AT_LEAST((surface), 0, 0)
67
 
68
#define XCB_RENDER_HAS_FILL_RECTANGLES(surface)		XCB_RENDER_AT_LEAST((surface), 0, 1)
69
 
70
#define XCB_RENDER_HAS_DISJOINT(surface)		XCB_RENDER_AT_LEAST((surface), 0, 2)
71
#define XCB_RENDER_HAS_CONJOINT(surface)		XCB_RENDER_AT_LEAST((surface), 0, 2)
72
 
73
#define XCB_RENDER_HAS_TRAPEZOIDS(surface)		XCB_RENDER_AT_LEAST((surface), 0, 4)
74
#define XCB_RENDER_HAS_TRIANGLES(surface)		XCB_RENDER_AT_LEAST((surface), 0, 4)
75
#define XCB_RENDER_HAS_TRISTRIP(surface)		XCB_RENDER_AT_LEAST((surface), 0, 4)
76
#define XCB_RENDER_HAS_TRIFAN(surface)			XCB_RENDER_AT_LEAST((surface), 0, 4)
77
 
78
#define XCB_RENDER_HAS_PICTURE_TRANSFORM(surface)	XCB_RENDER_AT_LEAST((surface), 0, 6)
79
#define XCB_RENDER_HAS_FILTERS(surface)			XCB_RENDER_AT_LEAST((surface), 0, 6)
80
 
81
#define XCB_RENDER_HAS_EXTENDED_REPEAT(surface)	XCB_RENDER_AT_LEAST((surface), 0, 10)
82
#define XCB_RENDER_HAS_GRADIENTS(surface)	XCB_RENDER_AT_LEAST((surface), 0, 10)
83
 
84
#define XCB_RENDER_HAS_PDF_OPERATORS(surface)	XCB_RENDER_AT_LEAST((surface), 0, 11)
85
 
86
static cairo_list_t connections;
87
 
88
static cairo_status_t
89
_cairo_xcb_connection_find_visual_formats (cairo_xcb_connection_t *connection,
90
					  const xcb_render_query_pict_formats_reply_t *formats)
91
{
92
    xcb_render_pictscreen_iterator_t screens;
93
    xcb_render_pictdepth_iterator_t depths;
94
    xcb_render_pictvisual_iterator_t visuals;
95
 
96
    for (screens = xcb_render_query_pict_formats_screens_iterator (formats);
97
	 screens.rem;
98
	 xcb_render_pictscreen_next (&screens))
99
    {
100
	for (depths = xcb_render_pictscreen_depths_iterator (screens.data);
101
	     depths.rem;
102
	     xcb_render_pictdepth_next (&depths))
103
	{
104
	    for (visuals = xcb_render_pictdepth_visuals_iterator (depths.data);
105
		 visuals.rem;
106
		 xcb_render_pictvisual_next (&visuals))
107
	    {
108
		cairo_xcb_xrender_format_t *f;
109
		cairo_status_t status;
110
 
111
		f = malloc (sizeof (cairo_xcb_xrender_format_t));
112
		if (unlikely (f == NULL))
113
		    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
114
 
115
		f->key.hash = visuals.data->visual;
116
		f->xrender_format = visuals.data->format;
117
		status = _cairo_hash_table_insert (connection->visual_to_xrender_format,
118
						   &f->key);
119
		if (unlikely (status))
120
		    return status;
121
	    }
122
	}
123
    }
124
 
125
    return CAIRO_STATUS_SUCCESS;
126
}
127
 
128
#if 0
129
static xcb_format_t *
130
find_format_for_depth (const xcb_setup_t *setup, uint8_t depth)
131
{
132
    xcb_format_t *fmt = xcb_setup_pixmap_formats (setup);
133
    xcb_format_t *fmtend = fmt + xcb_setup_pixmap_formats_length (setup);
134
 
135
    for (; fmt != fmtend; ++fmt)
136
	if (fmt->depth == depth)
137
	    return fmt;
138
 
139
    return 0;
140
}
141
#endif
142
 
143
static cairo_status_t
144
_cairo_xcb_connection_parse_xrender_formats (cairo_xcb_connection_t *connection,
145
					     const xcb_render_query_pict_formats_reply_t *formats)
146
{
147
    xcb_render_pictforminfo_iterator_t i;
148
    cairo_status_t status;
149
 
150
    for (i = xcb_render_query_pict_formats_formats_iterator (formats);
151
	 i.rem;
152
	 xcb_render_pictforminfo_next (&i))
153
    {
154
	cairo_format_masks_t masks;
155
	pixman_format_code_t pixman_format;
156
 
157
	if (i.data->type != XCB_RENDER_PICT_TYPE_DIRECT)
158
	    continue;
159
 
160
	masks.alpha_mask =
161
	    (unsigned long) i.data->direct.alpha_mask << i.data->direct.alpha_shift;
162
	masks.red_mask =
163
	    (unsigned long) i.data->direct.red_mask << i.data->direct.red_shift;
164
	masks.green_mask =
165
	    (unsigned long) i.data->direct.green_mask << i.data->direct.green_shift;
166
	masks.blue_mask =
167
	    (unsigned long) i.data->direct.blue_mask << i.data->direct.blue_shift;
168
	masks.bpp = i.data->depth;
169
 
170
	if (_pixman_format_from_masks (&masks, &pixman_format)) {
171
	    cairo_hash_entry_t key;
172
 
173
	    key.hash = pixman_format;
174
	    if (! _cairo_hash_table_lookup (connection->xrender_formats, &key)) {
175
		cairo_xcb_xrender_format_t *f;
176
 
177
		f = malloc (sizeof (cairo_xcb_xrender_format_t));
178
		if (unlikely (f == NULL))
179
		    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
180
 
181
		f->key.hash = pixman_format;
182
		f->xrender_format = i.data->id;
183
		status = _cairo_hash_table_insert (connection->xrender_formats,
184
						   &f->key);
185
		if (unlikely (status))
186
		    return status;
187
 
188
#if 0
189
		printf ("xrender %x -> (%lx, %lx, %lx, %lx, %d) %x [%d, %d]\n",
190
			i.data->id,
191
			masks.alpha_mask,
192
			masks.red_mask,
193
			masks.green_mask,
194
			masks.blue_mask,
195
			masks.bpp,
196
			pixman_format,
197
			PIXMAN_FORMAT_DEPTH(pixman_format),
198
			PIXMAN_FORMAT_BPP(pixman_format));
199
#endif
200
	    }
201
	}
202
    }
203
 
204
    status = _cairo_xcb_connection_find_visual_formats (connection, formats);
205
    if (unlikely (status))
206
	return status;
207
 
208
    connection->standard_formats[CAIRO_FORMAT_A1] =
209
	_cairo_xcb_connection_get_xrender_format (connection, PIXMAN_a1);
210
 
211
    connection->standard_formats[CAIRO_FORMAT_A8] =
212
	_cairo_xcb_connection_get_xrender_format (connection, PIXMAN_a8);
213
 
214
    connection->standard_formats[CAIRO_FORMAT_RGB24] =
215
	_cairo_xcb_connection_get_xrender_format (connection,
216
						  PIXMAN_FORMAT (24,
217
								 PIXMAN_TYPE_ARGB,
218
								 0, 8, 8, 8));
219
    if (connection->standard_formats[CAIRO_FORMAT_RGB24] == XCB_NONE) {
220
	connection->standard_formats[CAIRO_FORMAT_RGB24] =
221
	    _cairo_xcb_connection_get_xrender_format (connection,
222
						      PIXMAN_FORMAT (24, PIXMAN_TYPE_ABGR,
223
								     0, 8, 8, 8));
224
    }
225
 
226
    connection->standard_formats[CAIRO_FORMAT_ARGB32] =
227
	_cairo_xcb_connection_get_xrender_format (connection, PIXMAN_a8r8g8b8);
228
    if (connection->standard_formats[CAIRO_FORMAT_ARGB32] == XCB_NONE) {
229
	connection->standard_formats[CAIRO_FORMAT_ARGB32] =
230
	    _cairo_xcb_connection_get_xrender_format (connection, PIXMAN_a8b8g8r8);
231
    }
232
 
233
    return CAIRO_STATUS_SUCCESS;
234
}
235
 
236
/*
237
 * We require support for depth 1, 8, 24 and 32 pixmaps
238
 */
239
#define DEPTH_MASK(d)	(1 << ((d) - 1))
240
#define REQUIRED_DEPTHS	(DEPTH_MASK(1) | \
241
			 DEPTH_MASK(8) | \
242
			 DEPTH_MASK(24) | \
243
			 DEPTH_MASK(32))
244
static cairo_bool_t
245
pixmap_depths_usable (cairo_xcb_connection_t *connection,
246
		      uint32_t missing,
247
		      xcb_drawable_t root)
248
{
249
    xcb_connection_t *c = connection->xcb_connection;
250
    xcb_void_cookie_t create_cookie[32];
251
    xcb_pixmap_t pixmap;
252
    cairo_bool_t success = TRUE;
253
    int depth, i, j;
254
 
255
    pixmap = _cairo_xcb_connection_get_xid (connection);
256
 
257
    for (depth = 1, i = 0; depth <= 32; depth++) {
258
	if (missing & DEPTH_MASK(depth)) {
259
	    create_cookie[i] = xcb_create_pixmap_checked (c, depth, pixmap, root, 1, 1);
260
	    xcb_free_pixmap (c, pixmap);
261
	    if (!create_cookie[i].sequence) {
262
		success = FALSE;
263
		break;
264
	    }
265
	    i++;
266
	}
267
    }
268
 
269
    for (j = 0; j < i; j++) {
270
	xcb_generic_error_t *create_error = xcb_request_check (c, create_cookie[j]);
271
	success &= create_error == NULL;
272
	free (create_error);
273
    }
274
 
275
    _cairo_xcb_connection_put_xid (connection, pixmap);
276
 
277
    return success;
278
}
279
 
280
static cairo_bool_t
281
has_required_depths (cairo_xcb_connection_t *connection)
282
{
283
    xcb_screen_iterator_t screens;
284
 
285
    for (screens = xcb_setup_roots_iterator (connection->root);
286
	 screens.rem;
287
	 xcb_screen_next (&screens))
288
    {
289
	xcb_depth_iterator_t depths;
290
	uint32_t missing = REQUIRED_DEPTHS;
291
 
292
	for (depths = xcb_screen_allowed_depths_iterator (screens.data);
293
	     depths.rem;
294
	     xcb_depth_next (&depths))
295
	{
296
	    missing &= ~DEPTH_MASK (depths.data->depth);
297
	}
298
	if (missing == 0)
299
	    continue;
300
 
301
	/*
302
	 * Ok, this is ugly.  It should be sufficient at this
303
	 * point to just return false, but Xinerama is broken at
304
	 * this point and only advertises depths which have an
305
	 * associated visual.  Of course, the other depths still
306
	 * work, but the only way to find out is to try them.
307
	 */
308
	if (! pixmap_depths_usable (connection, missing, screens.data->root))
309
	    return FALSE;
310
    }
311
 
312
    return TRUE;
313
}
314
 
315
static xcb_render_query_version_reply_t *
316
_render_restrict_env(xcb_render_query_version_reply_t *version)
317
{
318
    const char *env;
319
 
320
    if (version == NULL)
321
	return NULL;
322
 
323
    env = getenv ("CAIRO_DEBUG");
324
    if (env != NULL)
325
	env = strstr (env, "xrender-version=");
326
    if (env != NULL) {
327
	int max_render_major, max_render_minor;
328
 
329
	env += sizeof ("xrender-version=") - 1;
330
	if (sscanf (env, "%d.%d", &max_render_major, &max_render_minor) != 2)
331
	    max_render_major = max_render_minor = -1;
332
 
333
	if (max_render_major < 0 || max_render_minor < 0) {
334
	    free (version);
335
	    return NULL;
336
	}
337
 
338
	if (max_render_major < (int) version->major_version ||
339
	    (max_render_major == (int) version->major_version &&
340
	     max_render_minor < (int) version->minor_version))
341
	{
342
	    version->major_version = max_render_major;
343
	    version->minor_version = max_render_minor;
344
	}
345
    }
346
 
347
    return version;
348
}
349
 
350
static cairo_status_t
351
_cairo_xcb_connection_query_render (cairo_xcb_connection_t *connection)
352
{
353
    xcb_connection_t *c = connection->xcb_connection;
354
    xcb_render_query_version_cookie_t version_cookie;
355
    xcb_render_query_pict_formats_cookie_t formats_cookie;
356
    xcb_render_query_version_reply_t *version;
357
    xcb_render_query_pict_formats_reply_t *formats;
358
    cairo_status_t status;
359
    cairo_bool_t present;
360
 
361
    version_cookie = xcb_render_query_version (c, XCB_RENDER_MAJOR_VERSION, XCB_RENDER_MINOR_VERSION);
362
    formats_cookie = xcb_render_query_pict_formats (c);
363
 
364
    present = has_required_depths (connection);
365
    version = xcb_render_query_version_reply (c, version_cookie, 0);
366
    formats = xcb_render_query_pict_formats_reply (c, formats_cookie, 0);
367
 
368
    version = _render_restrict_env (version);
369
 
370
    if (! present || version == NULL || formats == NULL) {
371
	free (version);
372
	free (formats);
373
	return CAIRO_STATUS_SUCCESS;
374
    }
375
 
376
    /* always true if the extension is present (i.e. >= 0.0) */
377
    connection->flags |= CAIRO_XCB_HAS_RENDER;
378
    connection->flags |= CAIRO_XCB_RENDER_HAS_COMPOSITE;
379
    connection->flags |= CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS;
380
 
381
    if (XCB_RENDER_HAS_FILL_RECTANGLES (version))
382
	connection->flags |= CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES;
383
 
384
    if (XCB_RENDER_HAS_TRAPEZOIDS (version))
385
	connection->flags |= CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS;
386
 
387
    if (XCB_RENDER_HAS_PICTURE_TRANSFORM (version))
388
	connection->flags |= CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM;
389
 
390
    if (XCB_RENDER_HAS_FILTERS (version))
391
	connection->flags |= CAIRO_XCB_RENDER_HAS_FILTERS;
392
 
393
    if (XCB_RENDER_HAS_PDF_OPERATORS (version))
394
	connection->flags |= CAIRO_XCB_RENDER_HAS_PDF_OPERATORS;
395
 
396
    if (XCB_RENDER_HAS_EXTENDED_REPEAT (version))
397
	connection->flags |= CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT;
398
 
399
    if (XCB_RENDER_HAS_GRADIENTS (version))
400
	connection->flags |= CAIRO_XCB_RENDER_HAS_GRADIENTS;
401
 
402
    free (version);
403
 
404
    status = _cairo_xcb_connection_parse_xrender_formats (connection, formats);
405
    free (formats);
406
 
407
    return status;
408
}
409
 
410
#if 0
411
static void
412
_cairo_xcb_connection_query_cairo (cairo_xcb_connection_t *connection)
413
{
414
    xcb_connection_t *c = connection->xcb_connection;
415
    xcb_cairo_query_version_reply_t *version;
416
 
417
    version = xcb_cairo_query_version_reply (c,
418
					     xcb_cairo_query_version (c, 0, 0),
419
					     0);
420
 
421
    free (version);
422
}
423
#endif
424
 
425
#if CAIRO_HAS_XCB_SHM_FUNCTIONS
426
static cairo_bool_t
427
can_use_shm (cairo_xcb_connection_t *connection)
428
{
429
    cairo_bool_t success = TRUE;
430
    xcb_connection_t *c = connection->xcb_connection;
431
    xcb_void_cookie_t cookie[2];
432
    xcb_generic_error_t *error;
433
    int shmid;
434
    uint32_t shmseg;
435
    void *ptr;
436
 
437
    shmid = shmget (IPC_PRIVATE, 0x1000, IPC_CREAT | 0600);
438
    if (shmid == -1)
439
	return FALSE;
440
 
441
    ptr = shmat (shmid, NULL, 0);
442
    if (ptr == (char *) -1) {
443
	shmctl (shmid, IPC_RMID, NULL);
444
	return FALSE;
445
    }
446
 
447
    shmseg = _cairo_xcb_connection_get_xid (connection);
448
    cookie[0] = xcb_shm_attach_checked (c, shmseg, shmid, FALSE);
449
    cookie[1] = xcb_shm_detach_checked (c, shmseg);
450
    _cairo_xcb_connection_put_xid (connection, shmseg);
451
 
452
    error = xcb_request_check (c, cookie[0]);
453
    if (error != NULL)
454
	success = FALSE;
455
 
456
    error = xcb_request_check (c, cookie[1]);
457
    if (error != NULL)
458
	success = FALSE;
459
 
460
    shmctl (shmid, IPC_RMID, NULL);
461
    shmdt (ptr);
462
 
463
    return success;
464
}
465
 
466
static void
467
_cairo_xcb_connection_query_shm (cairo_xcb_connection_t *connection)
468
{
469
    xcb_connection_t *c = connection->xcb_connection;
470
    xcb_shm_query_version_reply_t *version;
471
 
472
    version = xcb_shm_query_version_reply (c, xcb_shm_query_version (c), 0);
473
    if (version == NULL)
474
	return;
475
 
476
    free (version);
477
 
478
    if (can_use_shm (connection))
479
	connection->flags |= CAIRO_XCB_HAS_SHM;
480
}
481
#endif
482
 
483
static cairo_status_t
484
_device_flush (void *device)
485
{
486
    cairo_xcb_connection_t *connection = device;
487
    cairo_status_t status;
488
 
489
    status = cairo_device_acquire (&connection->device);
490
    if (unlikely (status))
491
	return status;
492
 
493
#if CAIRO_HAS_XCB_SHM_FUNCTIONS
494
    _cairo_xcb_connection_shm_mem_pools_flush (connection);
495
#endif
496
 
497
    xcb_flush (connection->xcb_connection);
498
 
499
    cairo_device_release (&connection->device);
500
    return CAIRO_STATUS_SUCCESS;
501
}
502
 
503
static void
504
_pluck_xrender_format (void *entry,
505
		       void *closure)
506
{
507
    _cairo_hash_table_remove (closure, entry);
508
    free (entry);
509
}
510
 
511
static void
512
_device_finish (void *device)
513
{
514
    cairo_xcb_connection_t *connection = device;
515
    cairo_bool_t was_cached = FALSE;
516
 
517
    if (! cairo_list_is_empty (&connection->link)) {
518
	CAIRO_MUTEX_LOCK (_cairo_xcb_connections_mutex);
519
	cairo_list_del (&connection->link);
520
	CAIRO_MUTEX_UNLOCK (_cairo_xcb_connections_mutex);
521
	was_cached = TRUE;
522
    }
523
 
524
    while (! cairo_list_is_empty (&connection->fonts)) {
525
	cairo_xcb_font_t *font;
526
 
527
	font = cairo_list_first_entry (&connection->fonts,
528
				       cairo_xcb_font_t,
529
				       link);
530
	_cairo_xcb_font_close (font);
531
    }
532
 
533
    while (! cairo_list_is_empty (&connection->screens)) {
534
	cairo_xcb_screen_t *screen;
535
 
536
	screen = cairo_list_first_entry (&connection->screens,
537
					 cairo_xcb_screen_t,
538
					 link);
539
	_cairo_xcb_screen_finish (screen);
540
    }
541
 
542
#if CAIRO_HAS_XCB_SHM_FUNCTIONS
543
    /* _cairo_xcb_screen_finish finishes surfaces. If any of those surfaces had
544
     * a fallback image, we might have done a SHM PutImage. */
545
    _cairo_xcb_connection_shm_mem_pools_flush (connection);
546
#endif
547
 
548
    if (was_cached)
549
	cairo_device_destroy (device);
550
}
551
 
552
static void
553
_device_destroy (void *device)
554
{
555
    cairo_xcb_connection_t *connection = device;
556
 
557
    _cairo_hash_table_foreach (connection->xrender_formats,
558
			       _pluck_xrender_format, connection->xrender_formats);
559
    _cairo_hash_table_destroy (connection->xrender_formats);
560
 
561
    _cairo_hash_table_foreach (connection->visual_to_xrender_format,
562
			       _pluck_xrender_format,
563
			       connection->visual_to_xrender_format);
564
    _cairo_hash_table_destroy (connection->visual_to_xrender_format);
565
 
566
#if CAIRO_HAS_XCB_SHM_FUNCTIONS
567
    _cairo_xcb_connection_shm_mem_pools_fini (connection);
568
#endif
569
    _cairo_freepool_fini (&connection->shm_info_freelist);
570
 
571
    _cairo_freepool_fini (&connection->xid_pool);
572
 
573
    CAIRO_MUTEX_FINI (connection->shm_mutex);
574
    CAIRO_MUTEX_FINI (connection->screens_mutex);
575
 
576
    free (connection);
577
}
578
 
579
static const cairo_device_backend_t _cairo_xcb_device_backend = {
580
    CAIRO_DEVICE_TYPE_XCB,
581
 
582
    NULL, NULL, /* lock, unlock */
583
 
584
    _device_flush,
585
    _device_finish,
586
    _device_destroy,
587
};
588
 
589
cairo_xcb_connection_t *
590
_cairo_xcb_connection_get (xcb_connection_t *xcb_connection)
591
{
592
    cairo_xcb_connection_t *connection;
593
    const xcb_query_extension_reply_t *ext;
594
    cairo_status_t status;
595
 
596
    CAIRO_MUTEX_INITIALIZE ();
597
 
598
    CAIRO_MUTEX_LOCK (_cairo_xcb_connections_mutex);
599
    if (connections.next == NULL) {
600
	/* XXX _cairo_init () */
601
	cairo_list_init (&connections);
602
    }
603
 
604
    cairo_list_foreach_entry (connection,
605
			      cairo_xcb_connection_t,
606
			      &connections,
607
			      link)
608
    {
609
	if (connection->xcb_connection == xcb_connection) {
610
	    /* Maintain MRU order. */
611
	    if (connections.next != &connection->link)
612
		cairo_list_move (&connection->link, &connections);
613
 
614
	    goto unlock;
615
	}
616
    }
617
 
618
    connection = malloc (sizeof (cairo_xcb_connection_t));
619
    if (unlikely (connection == NULL))
620
	goto unlock;
621
 
622
    _cairo_device_init (&connection->device, &_cairo_xcb_device_backend);
623
 
624
    connection->xcb_connection = xcb_connection;
625
 
626
    cairo_list_init (&connection->fonts);
627
    cairo_list_init (&connection->screens);
628
    cairo_list_init (&connection->link);
629
    connection->xrender_formats = _cairo_hash_table_create (NULL);
630
    if (connection->xrender_formats == NULL) {
631
	CAIRO_MUTEX_FINI (connection->device.mutex);
632
	free (connection);
633
	connection = NULL;
634
	goto unlock;
635
    }
636
 
637
    connection->visual_to_xrender_format = _cairo_hash_table_create (NULL);
638
    if (connection->visual_to_xrender_format == NULL) {
639
	_cairo_hash_table_destroy (connection->xrender_formats);
640
	CAIRO_MUTEX_FINI (connection->device.mutex);
641
	free (connection);
642
	connection = NULL;
643
	goto unlock;
644
    }
645
 
646
    cairo_list_init (&connection->free_xids);
647
    _cairo_freepool_init (&connection->xid_pool,
648
			  sizeof (cairo_xcb_xid_t));
649
 
650
    cairo_list_init (&connection->shm_pools);
651
    cairo_list_init (&connection->shm_pending);
652
    _cairo_freepool_init (&connection->shm_info_freelist,
653
			  sizeof (cairo_xcb_shm_info_t));
654
 
655
    connection->maximum_request_length =
656
	xcb_get_maximum_request_length (xcb_connection);
657
 
658
    CAIRO_MUTEX_INIT (connection->shm_mutex);
659
    CAIRO_MUTEX_INIT (connection->screens_mutex);
660
 
661
    CAIRO_MUTEX_LOCK (connection->device.mutex);
662
 
663
    connection->flags = 0;
664
    connection->force_precision = -1;
665
 
666
    xcb_prefetch_extension_data (xcb_connection, &xcb_big_requests_id);
667
    xcb_prefetch_extension_data (xcb_connection, &xcb_render_id);
668
#if CAIRO_HAS_XCB_SHM_FUNCTIONS
669
    xcb_prefetch_extension_data (xcb_connection, &xcb_shm_id);
670
#endif
671
#if 0
672
    xcb_prefetch_extension_data (xcb_connection, &xcb_cairo_id);
673
#endif
674
 
675
    xcb_prefetch_maximum_request_length (xcb_connection);
676
 
677
    connection->root = xcb_get_setup (xcb_connection);
678
    connection->render = NULL;
679
    ext = xcb_get_extension_data (xcb_connection, &xcb_render_id);
680
    if (ext != NULL && ext->present) {
681
	status = _cairo_xcb_connection_query_render (connection);
682
	if (unlikely (status)) {
683
	    CAIRO_MUTEX_UNLOCK (connection->device.mutex);
684
	    _cairo_xcb_connection_destroy (connection);
685
	    connection = NULL;
686
	    goto unlock;
687
	}
688
 
689
	connection->render = ext;
690
    }
691
 
692
#if 0
693
    ext = xcb_get_extension_data (connection, &xcb_cairo_id);
694
    if (ext != NULL && ext->present)
695
	_cairo_xcb_connection_query_cairo (connection);
696
#endif
697
 
698
    connection->shm = NULL;
699
#if CAIRO_HAS_XCB_SHM_FUNCTIONS
700
    ext = xcb_get_extension_data (xcb_connection, &xcb_shm_id);
701
    if (ext != NULL && ext->present) {
702
	_cairo_xcb_connection_query_shm (connection);
703
	connection->shm = ext;
704
    }
705
#endif
706
 
707
    connection->original_flags = connection->flags;
708
 
709
    CAIRO_MUTEX_UNLOCK (connection->device.mutex);
710
 
711
    cairo_list_add (&connection->link, &connections);
712
unlock:
713
    CAIRO_MUTEX_UNLOCK (_cairo_xcb_connections_mutex);
714
 
715
    return connection;
716
}
717
 
718
xcb_render_pictformat_t
719
_cairo_xcb_connection_get_xrender_format (cairo_xcb_connection_t *connection,
720
					  pixman_format_code_t pixman_format)
721
{
722
    cairo_hash_entry_t key;
723
    cairo_xcb_xrender_format_t *format;
724
 
725
    key.hash = pixman_format;
726
    format = _cairo_hash_table_lookup (connection->xrender_formats, &key);
727
    return format ? format->xrender_format : XCB_NONE;
728
}
729
 
730
xcb_render_pictformat_t
731
_cairo_xcb_connection_get_xrender_format_for_visual (cairo_xcb_connection_t *connection,
732
						     const xcb_visualid_t visual)
733
{
734
    cairo_hash_entry_t key;
735
    cairo_xcb_xrender_format_t *format;
736
 
737
    key.hash = visual;
738
    format = _cairo_hash_table_lookup (connection->visual_to_xrender_format, &key);
739
    return format ? format->xrender_format : XCB_NONE;
740
}
741
 
742
void
743
_cairo_xcb_connection_put_xid (cairo_xcb_connection_t *connection,
744
			       uint32_t xid)
745
{
746
    cairo_xcb_xid_t *cache;
747
 
748
    assert (CAIRO_MUTEX_IS_LOCKED (connection->device.mutex));
749
    cache = _cairo_freepool_alloc (&connection->xid_pool);
750
    if (likely (cache != NULL)) {
751
	cache->xid = xid;
752
	cairo_list_add (&cache->link, &connection->free_xids);
753
    }
754
}
755
 
756
uint32_t
757
_cairo_xcb_connection_get_xid (cairo_xcb_connection_t *connection)
758
{
759
    uint32_t xid;
760
 
761
    assert (CAIRO_MUTEX_IS_LOCKED (connection->device.mutex));
762
    if (! cairo_list_is_empty (&connection->free_xids)) {
763
	cairo_xcb_xid_t *cache;
764
 
765
	cache = cairo_list_first_entry (&connection->free_xids,
766
					cairo_xcb_xid_t,
767
					link);
768
	xid = cache->xid;
769
 
770
	cairo_list_del (&cache->link);
771
	_cairo_freepool_free (&connection->xid_pool, cache);
772
    } else {
773
	xid = xcb_generate_id (connection->xcb_connection);
774
    }
775
 
776
    return xid;
777
}
778
 
779
/**
780
 * cairo_xcb_device_get_connection:
781
 * @device: a #cairo_device_t for the XCB backend
782
 *
783
 * Get the connection for the XCB device.
784
 *
785
 * Returns: the #xcb_connection_t for the connection
786
 *
787
 * Since: 1.12
788
 **/
789
xcb_connection_t *
790
cairo_xcb_device_get_connection (cairo_device_t *device)
791
{
792
    if (device->backend->type != CAIRO_DEVICE_TYPE_XCB)
793
	    return NULL;
794
 
795
    return ((cairo_xcb_connection_t *)device)->xcb_connection;
796
}
797
 
798
/* public (debug) interface */
799
 
800
/**
801
 * cairo_xcb_device_debug_cap_xshm_version:
802
 * @device: a #cairo_device_t for the XCB backend
803
 * @major_version: major version to restrict to
804
 * @minor_version: minor version to restrict to
805
 *
806
 * Restricts all future XCB surfaces for this devices to the specified version
807
 * of the SHM extension. This function exists solely for debugging purpose.
808
 * It let's you find out how cairo would behave with an older version of
809
 * the SHM extension.
810
 *
811
 * Use the special values -1 and -1 for disabling the SHM extension.
812
 *
813
 * Since: 1.12
814
 **/
815
void
816
cairo_xcb_device_debug_cap_xshm_version (cairo_device_t *device,
817
                                         int major_version,
818
                                         int minor_version)
819
{
820
    cairo_xcb_connection_t *connection = (cairo_xcb_connection_t *) device;
821
 
822
    if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) {
823
	cairo_status_t status;
824
 
825
	status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
826
	(void) status;
827
	return;
828
    }
829
 
830
    /* First reset all the SHM flags to their original value. This works
831
     * because we only ever clear bits after the connection was created.
832
     */
833
    connection->flags |= (connection->original_flags & CAIRO_XCB_SHM_MASK);
834
 
835
    /* clear any flags that are inappropriate for the desired version */
836
    if (major_version < 0 && minor_version < 0) {
837
	connection->flags &= ~(CAIRO_XCB_HAS_SHM);
838
    }
839
}
840
 
841
/**
842
 * cairo_xcb_device_debug_cap_xrender_version:
843
 * @device: a #cairo_device_t for the XCB backend
844
 * @major_version: major version to restrict to
845
 * @minor_version: minor version to restrict to
846
 *
847
 * Restricts all future XCB surfaces for this devices to the specified version
848
 * of the RENDER extension. This function exists solely for debugging purpose.
849
 * It let's you find out how cairo would behave with an older version of
850
 * the RENDER extension.
851
 *
852
 * Use the special values -1 and -1 for disabling the RENDER extension.
853
 *
854
 * Since: 1.12
855
 **/
856
void
857
cairo_xcb_device_debug_cap_xrender_version (cairo_device_t *device,
858
                                            int major_version,
859
                                            int minor_version)
860
{
861
    cairo_xcb_connection_t *connection = (cairo_xcb_connection_t *) device;
862
 
863
    if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) {
864
	cairo_status_t status;
865
 
866
	status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
867
	(void) status;
868
	return;
869
    }
870
 
871
    /* First reset all the RENDER flags to their original value. This works
872
     * because we only ever clear bits after the connection was created.
873
     */
874
    connection->flags |= (connection->original_flags & CAIRO_XCB_RENDER_MASK);
875
 
876
    /* clear any flags that are inappropriate for the desired version */
877
    if (major_version < 0 && minor_version < 0) {
878
	connection->flags &= ~(CAIRO_XCB_HAS_RENDER |
879
			       CAIRO_XCB_RENDER_HAS_COMPOSITE |
880
			       CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS |
881
			       CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES |
882
			       CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS |
883
			       CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM |
884
			       CAIRO_XCB_RENDER_HAS_FILTERS |
885
			       CAIRO_XCB_RENDER_HAS_PDF_OPERATORS |
886
			       CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT |
887
			       CAIRO_XCB_RENDER_HAS_GRADIENTS);
888
    } else {
889
	xcb_render_query_version_reply_t version;
890
 
891
	version.major_version = major_version;
892
	version.minor_version = minor_version;
893
 
894
	if (! XCB_RENDER_HAS_FILL_RECTANGLES (&version))
895
	    connection->flags &= ~CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES;
896
 
897
	if (! XCB_RENDER_HAS_TRAPEZOIDS (&version))
898
	    connection->flags &= ~CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS;
899
 
900
	if (! XCB_RENDER_HAS_PICTURE_TRANSFORM (&version))
901
	    connection->flags &= ~CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM;
902
 
903
	if (! XCB_RENDER_HAS_FILTERS (&version))
904
	    connection->flags &= ~CAIRO_XCB_RENDER_HAS_FILTERS;
905
 
906
	if (! XCB_RENDER_HAS_PDF_OPERATORS (&version))
907
	    connection->flags &= ~CAIRO_XCB_RENDER_HAS_PDF_OPERATORS;
908
 
909
	if (! XCB_RENDER_HAS_EXTENDED_REPEAT (&version))
910
	    connection->flags &= ~CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT;
911
 
912
	if (! XCB_RENDER_HAS_GRADIENTS (&version))
913
	    connection->flags &= ~CAIRO_XCB_RENDER_HAS_GRADIENTS;
914
    }
915
}
916
#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
917
slim_hidden_def (cairo_xcb_device_debug_cap_xrender_version);
918
#endif
919
 
920
/**
921
 * cairo_xcb_device_debug_set_precision:
922
 * @device: a #cairo_device_t for the XCB backend
923
 * @precision: the precision to use
924
 *
925
 * Render supports two modes of precision when rendering trapezoids. Set
926
 * the precision to the desired mode.
927
 *
928
 * Since: 1.12
929
 **/
930
void
931
cairo_xcb_device_debug_set_precision (cairo_device_t *device,
932
				      int precision)
933
{
934
    if (device == NULL || device->status)
935
	return;
936
    if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) {
937
	cairo_status_t status;
938
 
939
	status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
940
	(void) status;
941
	return;
942
    }
943
 
944
    ((cairo_xcb_connection_t *) device)->force_precision = precision;
945
}
946
#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
947
slim_hidden_def (cairo_xcb_device_debug_set_precision);
948
#endif
949
 
950
/**
951
 * cairo_xcb_device_debug_get_precision:
952
 * @device: a #cairo_device_t for the XCB backend
953
 *
954
 * Get the Xrender precision mode.
955
 *
956
 * Returns: the render precision mode
957
 *
958
 * Since: 1.12
959
 **/
960
int
961
cairo_xcb_device_debug_get_precision (cairo_device_t *device)
962
{
963
    if (device == NULL || device->status)
964
	return -1;
965
    if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) {
966
	cairo_status_t status;
967
 
968
	status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
969
	(void) status;
970
	return -1;
971
    }
972
 
973
    return ((cairo_xcb_connection_t *) device)->force_precision;
974
}
975
#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
976
slim_hidden_def (cairo_xcb_device_debug_get_precision);
977
#endif