1
/* Cairo - a vector graphics library with display and print output
2
 *
3
 * Copyright © 2007 Chris Wilson
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
 * The Original Code is the cairo graphics library.
29
 *
30
 * The Initial Developer of the Original Code is Chris Wilson.
31
 *
32
 * Contributor(s):
33
 *	Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
34
 */
35

            
36
#include "cairoint.h"
37

            
38
#if !CAIRO_HAS_XLIB_XCB_FUNCTIONS
39

            
40
#include "cairo-xlib-private.h"
41
#include "cairo-xlib-xrender-private.h"
42
#include "cairo-freelist-private.h"
43
#include "cairo-error-private.h"
44
#include "cairo-list-inline.h"
45

            
46
#include <X11/Xlibint.h>	/* For XESetCloseDisplay */
47

            
48
typedef int (*cairo_xlib_error_func_t) (Display     *display,
49
					XErrorEvent *event);
50

            
51
static cairo_xlib_display_t *_cairo_xlib_display_list;
52

            
53
static int
54
_noop_error_handler (Display     *display,
55
		     XErrorEvent *event)
56
{
57
    return False;		/* return value is ignored */
58
}
59

            
60
static void
61
4
_cairo_xlib_display_finish (void *abstract_display)
62
{
63
4
    cairo_xlib_display_t *display = abstract_display;
64
4
    Display *dpy = display->display;
65

            
66
4
    _cairo_xlib_display_fini_shm (display);
67

            
68
4
    if (! cairo_device_acquire (&display->base)) {
69
	cairo_xlib_error_func_t old_handler;
70

            
71
	/* protect the notifies from triggering XErrors */
72
4
	XSync (dpy, False);
73
4
	old_handler = XSetErrorHandler (_noop_error_handler);
74

            
75
4
	while (! cairo_list_is_empty (&display->fonts)) {
76
	    _cairo_xlib_font_close (cairo_list_first_entry (&display->fonts,
77
							    cairo_xlib_font_t,
78
							    link));
79
	}
80

            
81
8
	while (! cairo_list_is_empty (&display->screens)) {
82
4
	    _cairo_xlib_screen_destroy (display,
83
4
					cairo_list_first_entry (&display->screens,
84
								cairo_xlib_screen_t,
85
								link));
86
	}
87

            
88
4
	XSync (dpy, False);
89
4
	XSetErrorHandler (old_handler);
90

            
91
4
	cairo_device_release (&display->base);
92
    }
93
4
}
94

            
95
static void
96
4
_cairo_xlib_display_destroy (void *abstract_display)
97
{
98
4
    cairo_xlib_display_t *display = abstract_display;
99

            
100
4
    free (display);
101
4
}
102

            
103
static int
104
4
_cairo_xlib_close_display (Display *dpy, XExtCodes *codes)
105
{
106
    cairo_xlib_display_t *display, **prev, *next;
107

            
108
4
    CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
109
4
    for (display = _cairo_xlib_display_list; display; display = display->next)
110
4
	if (display->display == dpy)
111
4
	    break;
112
4
    CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
113
4
    if (display == NULL)
114
	return 0;
115

            
116
4
    cairo_device_finish (&display->base);
117

            
118
    /*
119
     * Unhook from the global list
120
     */
121
4
    CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
122
4
    prev = &_cairo_xlib_display_list;
123
4
    for (display = _cairo_xlib_display_list; display; display = next) {
124
4
	next = display->next;
125
4
	if (display->display == dpy) {
126
4
	    *prev = next;
127
4
	    break;
128
	} else
129
	    prev = &display->next;
130
    }
131
4
    CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
132

            
133
4
    display->display = NULL; /* catch any later invalid access */
134
4
    cairo_device_destroy (&display->base);
135

            
136
    /* Return value in accordance with requirements of
137
     * XESetCloseDisplay */
138
4
    return 0;
139
}
140

            
141
static const cairo_device_backend_t _cairo_xlib_device_backend = {
142
    CAIRO_DEVICE_TYPE_XLIB,
143

            
144
    NULL,
145
    NULL,
146

            
147
    NULL, /* flush */
148
    _cairo_xlib_display_finish,
149
    _cairo_xlib_display_destroy,
150
};
151

            
152
4
static void _cairo_xlib_display_select_compositor (cairo_xlib_display_t *display)
153
{
154
#if 1
155
4
    if (display->render_major > 0 || display->render_minor >= 4)
156
4
	display->compositor = _cairo_xlib_traps_compositor_get ();
157
    else if (display->render_major > 0 || display->render_minor >= 0)
158
	display->compositor = _cairo_xlib_mask_compositor_get ();
159
    else
160
	display->compositor = _cairo_xlib_core_compositor_get ();
161
#else
162
    display->compositor = _cairo_xlib_fallback_compositor_get ();
163
#endif
164
4
}
165

            
166
/**
167
 * _cairo_xlib_device_create:
168
 * @dpy: the display to create the device for
169
 *
170
 * Gets the device belonging to @dpy, or creates it if it doesn't exist yet.
171
 *
172
 * Returns: the device belonging to @dpy
173
 **/
174
cairo_device_t *
175
4
_cairo_xlib_device_create (Display *dpy)
176
{
177
    cairo_xlib_display_t *display;
178
    cairo_xlib_display_t **prev;
179
    cairo_device_t *device;
180
    XExtCodes *codes;
181
    const char *env;
182

            
183
    CAIRO_MUTEX_INITIALIZE ();
184

            
185
    /* There is an apparent deadlock between this mutex and the
186
     * mutex for the display, but it's actually safe. For the
187
     * app to call XCloseDisplay() while any other thread is
188
     * inside this function would be an error in the logic
189
     * app, and the CloseDisplay hook is the only other place we
190
     * acquire this mutex.
191
     */
192
4
    CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
193

            
194
4
    for (prev = &_cairo_xlib_display_list; (display = *prev); prev = &(*prev)->next)
195
    {
196
	if (display->display == dpy) {
197
	    /*
198
	     * MRU the list
199
	     */
200
	    if (prev != &_cairo_xlib_display_list) {
201
		*prev = display->next;
202
		display->next = _cairo_xlib_display_list;
203
		_cairo_xlib_display_list = display;
204
	    }
205
            device = cairo_device_reference (&display->base);
206
	    goto UNLOCK;
207
	}
208
    }
209

            
210
4
    display = _cairo_calloc (sizeof (cairo_xlib_display_t));
211
4
    if (unlikely (display == NULL)) {
212
	device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
213
	goto UNLOCK;
214
    }
215

            
216
4
    _cairo_device_init (&display->base, &_cairo_xlib_device_backend);
217

            
218
4
    display->display = dpy;
219
4
    cairo_list_init (&display->screens);
220
4
    cairo_list_init (&display->fonts);
221
4
    display->closed = FALSE;
222

            
223
    /* Xlib calls out to the extension close_display hooks in LIFO
224
     * order. So we have to ensure that all extensions that we depend
225
     * on in our close_display hook are properly initialized before we
226
     * add our hook. For now, that means Render, so we call into its
227
     * QueryVersion function to ensure it gets initialized.
228
     */
229
4
    display->render_major = display->render_minor = -1;
230
4
    XRenderQueryVersion (dpy, &display->render_major, &display->render_minor);
231
4
    env = getenv ("CAIRO_DEBUG");
232
4
    if (env != NULL && (env = strstr (env, "xrender-version=")) != NULL) {
233
	int max_render_major, max_render_minor;
234

            
235
	env += sizeof ("xrender-version=") - 1;
236
	if (sscanf (env, "%d.%d", &max_render_major, &max_render_minor) != 2)
237
	    max_render_major = max_render_minor = -1;
238

            
239
	if (max_render_major < display->render_major ||
240
	    (max_render_major == display->render_major &&
241
	     max_render_minor < display->render_minor))
242
	{
243
	    display->render_major = max_render_major;
244
	    display->render_minor = max_render_minor;
245
	}
246
    }
247

            
248
4
    _cairo_xlib_display_select_compositor (display);
249

            
250
4
    display->white = NULL;
251
4
    memset (display->alpha, 0, sizeof (display->alpha));
252
4
    memset (display->solid, 0, sizeof (display->solid));
253
4
    memset (display->solid_cache, 0, sizeof (display->solid_cache));
254
4
    memset (display->last_solid_cache, 0, sizeof (display->last_solid_cache));
255

            
256
4
    memset (display->cached_xrender_formats, 0,
257
	    sizeof (display->cached_xrender_formats));
258

            
259
4
    display->force_precision = -1;
260

            
261
4
    _cairo_xlib_display_init_shm (display);
262

            
263
    /* Prior to Render 0.10, there is no protocol support for gradients and
264
     * we call function stubs instead, which would silently consume the drawing.
265
     */
266
#if RENDER_MAJOR == 0 && RENDER_MINOR < 10
267
    display->buggy_gradients = TRUE;
268
#else
269
4
    display->buggy_gradients = FALSE;
270
#endif
271
4
    display->buggy_pad_reflect = FALSE;
272
4
    display->buggy_repeat = FALSE;
273

            
274
    /* This buggy_repeat condition is very complicated because there
275
     * are multiple X server code bases (with multiple versioning
276
     * schemes within a code base), and multiple bugs.
277
     *
278
     * The X servers:
279
     *
280
     *    1. The Vendor=="XFree86" code base with release numbers such
281
     *    as 4.7.0 (VendorRelease==40700000).
282
     *
283
     *    2. The Vendor=="X.Org" code base (a descendant of the
284
     *    XFree86 code base). It originally had things like
285
     *    VendorRelease==60700000 for release 6.7.0 but then changed
286
     *    its versioning scheme so that, for example,
287
     *    VendorRelease==10400000 for the 1.4.0 X server within the
288
     *    X.Org 7.3 release.
289
     *
290
     * The bugs:
291
     *
292
     *    1. The original bug that led to the buggy_repeat
293
     *    workaround. This was a bug that Owen Taylor investigated,
294
     *    understood well, and characterized against various X
295
     *    servers. Confirmed X servers with this bug include:
296
     *
297
     *		"XFree86" <= 40500000
298
     *		"X.Org" <= 60802000 (only with old numbering >= 60700000)
299
     *
300
     *    2. A separate bug resulting in a crash of the X server when
301
     *    using cairo's extend-reflect test case, (which, surprisingly
302
     *    enough was not passing RepeatReflect to the X server, but
303
     *    instead using RepeatNormal in a workaround). Nobody to date
304
     *    has understood the bug well, but it appears to be gone as of
305
     *    the X.Org 1.4.0 server. This bug is coincidentally avoided
306
     *    by using the same buggy_repeat workaround. Confirmed X
307
     *    servers with this bug include:
308
     *
309
     *		"X.org" == 60900000 (old versioning scheme)
310
     *		"X.org"  < 10400000 (new numbering scheme)
311
     *
312
     *    For the old-versioning-scheme X servers we don't know
313
     *    exactly when second the bug started, but since bug 1 is
314
     *    present through 6.8.2 and bug 2 is present in 6.9.0 it seems
315
     *    safest to just blacklist all old-versioning-scheme X servers,
316
     *    (just using VendorRelease < 70000000), as buggy_repeat=TRUE.
317
     */
318
4
    if (_cairo_xlib_vendor_is_xorg (dpy)) {
319
4
	if (VendorRelease (dpy) >= 60700000) {
320
	    if (VendorRelease (dpy) < 70000000)
321
		display->buggy_repeat = TRUE;
322

            
323
	    /* We know that gradients simply do not work in early Xorg servers */
324
	    if (VendorRelease (dpy) < 70200000)
325
		display->buggy_gradients = TRUE;
326

            
327
	    /* And the extended repeat modes were not fixed until much later */
328
	    display->buggy_pad_reflect = TRUE;
329
	} else {
330
4
	    if (VendorRelease (dpy) < 10400000)
331
		display->buggy_repeat = TRUE;
332

            
333
	    /* Too many bugs in the early drivers */
334
4
	    if (VendorRelease (dpy) < 10699000)
335
		display->buggy_pad_reflect = TRUE;
336
	}
337
    } else if (strstr (ServerVendor (dpy), "XFree86") != NULL) {
338
	if (VendorRelease (dpy) <= 40500000)
339
	    display->buggy_repeat = TRUE;
340

            
341
	display->buggy_gradients = TRUE;
342
	display->buggy_pad_reflect = TRUE;
343
    }
344

            
345
4
    codes = XAddExtension (dpy);
346
4
    if (unlikely (codes == NULL)) {
347
	device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
348
	free (display);
349
	goto UNLOCK;
350
    }
351

            
352
4
    XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display);
353
4
    cairo_device_reference (&display->base); /* add one for the CloseDisplay */
354

            
355
4
    display->next = _cairo_xlib_display_list;
356
4
    _cairo_xlib_display_list = display;
357

            
358
4
    device = &display->base;
359

            
360
4
UNLOCK:
361
4
    CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
362
4
    return device;
363
}
364

            
365
cairo_status_t
366
63
_cairo_xlib_display_acquire (cairo_device_t *device, cairo_xlib_display_t **display)
367
{
368
    cairo_status_t status;
369

            
370
63
    status = cairo_device_acquire (device);
371
63
    if (status)
372
        return status;
373

            
374
63
    *display = (cairo_xlib_display_t *) device;
375
63
    return CAIRO_STATUS_SUCCESS;
376
}
377

            
378
XRenderPictFormat *
379
_cairo_xlib_display_get_xrender_format_for_pixman(cairo_xlib_display_t *display,
380
						  pixman_format_code_t format)
381
{
382
    Display *dpy = display->display;
383
    XRenderPictFormat tmpl;
384
    int mask;
385

            
386
    /* No equivalent in X11 yet. */
387
    if (format == PIXMAN_rgba_float || format == PIXMAN_rgb_float)
388
	return NULL;
389

            
390
#define MASK(x) ((1<<(x))-1)
391

            
392
    tmpl.depth = PIXMAN_FORMAT_DEPTH(format);
393
    mask = PictFormatType | PictFormatDepth;
394

            
395
    switch (PIXMAN_FORMAT_TYPE(format)) {
396
    case PIXMAN_TYPE_ARGB:
397
	tmpl.type = PictTypeDirect;
398

            
399
	tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
400
	if (PIXMAN_FORMAT_A(format))
401
	    tmpl.direct.alpha = (PIXMAN_FORMAT_R(format) +
402
				 PIXMAN_FORMAT_G(format) +
403
				 PIXMAN_FORMAT_B(format));
404

            
405
	tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
406
	tmpl.direct.red = (PIXMAN_FORMAT_G(format) +
407
			   PIXMAN_FORMAT_B(format));
408

            
409
	tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
410
	tmpl.direct.green = PIXMAN_FORMAT_B(format);
411

            
412
	tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
413
	tmpl.direct.blue = 0;
414

            
415
	mask |= PictFormatRed | PictFormatRedMask;
416
	mask |= PictFormatGreen | PictFormatGreenMask;
417
	mask |= PictFormatBlue | PictFormatBlueMask;
418
	mask |= PictFormatAlpha | PictFormatAlphaMask;
419
	break;
420

            
421
    case PIXMAN_TYPE_ABGR:
422
	tmpl.type = PictTypeDirect;
423

            
424
	tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
425
	if (tmpl.direct.alphaMask)
426
	    tmpl.direct.alpha = (PIXMAN_FORMAT_B(format) +
427
				 PIXMAN_FORMAT_G(format) +
428
				 PIXMAN_FORMAT_R(format));
429

            
430
	tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
431
	tmpl.direct.blue = (PIXMAN_FORMAT_G(format) +
432
			    PIXMAN_FORMAT_R(format));
433

            
434
	tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
435
	tmpl.direct.green = PIXMAN_FORMAT_R(format);
436

            
437
	tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
438
	tmpl.direct.red = 0;
439

            
440
	mask |= PictFormatRed | PictFormatRedMask;
441
	mask |= PictFormatGreen | PictFormatGreenMask;
442
	mask |= PictFormatBlue | PictFormatBlueMask;
443
	mask |= PictFormatAlpha | PictFormatAlphaMask;
444
	break;
445

            
446
    case PIXMAN_TYPE_BGRA:
447
	tmpl.type = PictTypeDirect;
448

            
449
	tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
450
	tmpl.direct.blue = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format));
451

            
452
	tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
453
	tmpl.direct.green = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) -
454
			     PIXMAN_FORMAT_G(format));
455

            
456
	tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
457
	tmpl.direct.red = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) -
458
			   PIXMAN_FORMAT_G(format) - PIXMAN_FORMAT_R(format));
459

            
460
	tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
461
	tmpl.direct.alpha = 0;
462

            
463
	mask |= PictFormatRed | PictFormatRedMask;
464
	mask |= PictFormatGreen | PictFormatGreenMask;
465
	mask |= PictFormatBlue | PictFormatBlueMask;
466
	mask |= PictFormatAlpha | PictFormatAlphaMask;
467
	break;
468

            
469
    case PIXMAN_TYPE_A:
470
	tmpl.type = PictTypeDirect;
471

            
472
	tmpl.direct.alpha = 0;
473
	tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
474

            
475
	mask |= PictFormatAlpha | PictFormatAlphaMask;
476
	break;
477

            
478
    case PIXMAN_TYPE_COLOR:
479
    case PIXMAN_TYPE_GRAY:
480
	/* XXX Find matching visual/colormap */
481
	tmpl.type = PictTypeIndexed;
482
	//tmpl.colormap = screen->visuals[PIXMAN_FORMAT_VIS(format)].vid;
483
	//mask |= PictFormatColormap;
484
	return NULL;
485
    }
486
#undef MASK
487

            
488
    /* XXX caching? */
489
    return XRenderFindFormat(dpy, mask, &tmpl, 0);
490
}
491

            
492
XRenderPictFormat *
493
_cairo_xlib_display_get_xrender_format (cairo_xlib_display_t	*display,
494
	                                cairo_format_t		 format)
495
{
496
    XRenderPictFormat *xrender_format;
497

            
498
    xrender_format = display->cached_xrender_formats[format];
499
    if (xrender_format == NULL) {
500
	int pict_format = PictStandardNUM;
501

            
502
	switch (format) {
503
	case CAIRO_FORMAT_A1:
504
	    pict_format = PictStandardA1; break;
505
	case CAIRO_FORMAT_A8:
506
	    pict_format = PictStandardA8; break;
507
	case CAIRO_FORMAT_RGB24:
508
	    pict_format = PictStandardRGB24; break;
509
	case CAIRO_FORMAT_RGB16_565:
510
	    xrender_format = _cairo_xlib_display_get_xrender_format_for_pixman(display,
511
									       PIXMAN_r5g6b5);
512
	    break;
513
	case CAIRO_FORMAT_RGB30:
514
	    xrender_format = _cairo_xlib_display_get_xrender_format_for_pixman(display,
515
									       PIXMAN_x2r10g10b10);
516
	    break;
517
	case CAIRO_FORMAT_RGBA128F:
518
	    xrender_format = _cairo_xlib_display_get_xrender_format_for_pixman(display,
519
									       PIXMAN_rgba_float);
520
	    break;
521
	case CAIRO_FORMAT_RGB96F:
522
	    xrender_format = _cairo_xlib_display_get_xrender_format_for_pixman(display,
523
									       PIXMAN_rgb_float);
524
	    break;
525
	case CAIRO_FORMAT_INVALID:
526
	default:
527
	    ASSERT_NOT_REACHED;
528
	case CAIRO_FORMAT_ARGB32:
529
	    pict_format = PictStandardARGB32; break;
530
	}
531
	if (pict_format != PictStandardNUM)
532
	    xrender_format =
533
		XRenderFindStandardFormat (display->display, pict_format);
534
	display->cached_xrender_formats[format] = xrender_format;
535
    }
536

            
537
    return xrender_format;
538
}
539

            
540
cairo_xlib_screen_t *
541
4
_cairo_xlib_display_get_screen (cairo_xlib_display_t *display,
542
				Screen *screen)
543
{
544
    cairo_xlib_screen_t *info;
545

            
546
4
    cairo_list_foreach_entry (info, cairo_xlib_screen_t, &display->screens, link) {
547
	if (info->screen == screen) {
548
            if (display->screens.next != &info->link)
549
                cairo_list_move (&info->link, &display->screens);
550
            return info;
551
        }
552
    }
553

            
554
4
    return NULL;
555
}
556

            
557
cairo_bool_t
558
_cairo_xlib_display_has_repeat (cairo_device_t *device)
559
{
560
    return ! ((cairo_xlib_display_t *) device)->buggy_repeat;
561
}
562

            
563
cairo_bool_t
564
_cairo_xlib_display_has_reflect (cairo_device_t *device)
565
{
566
    return ! ((cairo_xlib_display_t *) device)->buggy_pad_reflect;
567
}
568

            
569
cairo_bool_t
570
_cairo_xlib_display_has_gradients (cairo_device_t *device)
571
{
572
    return ! ((cairo_xlib_display_t *) device)->buggy_gradients;
573
}
574

            
575
/**
576
 * cairo_xlib_device_debug_cap_xrender_version:
577
 * @device: a #cairo_device_t for the Xlib backend
578
 * @major_version: major version to restrict to
579
 * @minor_version: minor version to restrict to
580
 *
581
 * Restricts all future Xlib surfaces for this devices to the specified version
582
 * of the RENDER extension. This function exists solely for debugging purpose.
583
 * It lets you find out how cairo would behave with an older version of
584
 * the RENDER extension.
585
 *
586
 * Use the special values -1 and -1 for disabling the RENDER extension.
587
 *
588
 * Since: 1.12
589
 **/
590
void
591
cairo_xlib_device_debug_cap_xrender_version (cairo_device_t *device,
592
					     int major_version,
593
					     int minor_version)
594
{
595
    cairo_xlib_display_t *display = (cairo_xlib_display_t *) device;
596

            
597
    if (device == NULL || device->status)
598
	return;
599

            
600
    if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB)
601
	return;
602

            
603
    if (major_version < display->render_major ||
604
	(major_version == display->render_major &&
605
	 minor_version < display->render_minor))
606
    {
607
	display->render_major = major_version;
608
	display->render_minor = minor_version;
609
    }
610

            
611
    _cairo_xlib_display_select_compositor (display);
612
}
613

            
614
/**
615
 * cairo_xlib_device_debug_set_precision:
616
 * @device: a #cairo_device_t for the Xlib backend
617
 * @precision: the precision to use
618
 *
619
 * Render supports two modes of precision when rendering trapezoids. Set
620
 * the precision to the desired mode.
621
 *
622
 * Since: 1.12
623
 **/
624
void
625
cairo_xlib_device_debug_set_precision (cairo_device_t *device,
626
				       int precision)
627
{
628
    if (device == NULL || device->status)
629
	return;
630
    if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) {
631
	cairo_status_t status;
632

            
633
	status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
634
	(void) status;
635
	return;
636
    }
637

            
638
    ((cairo_xlib_display_t *) device)->force_precision = precision;
639
}
640

            
641
/**
642
 * cairo_xlib_device_debug_get_precision:
643
 * @device: a #cairo_device_t for the Xlib backend
644
 *
645
 * Get the Xrender precision mode.
646
 *
647
 * Returns: the render precision mode
648
 *
649
 * Since: 1.12
650
 **/
651
int
652
cairo_xlib_device_debug_get_precision (cairo_device_t *device)
653
{
654
    if (device == NULL || device->status)
655
	return -1;
656
    if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) {
657
	cairo_status_t status;
658

            
659
	status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
660
	(void) status;
661
	return -1;
662
    }
663

            
664
    return ((cairo_xlib_display_t *) device)->force_precision;
665
}
666

            
667
#endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */