Git init
[framework/graphics/cairo.git] / src / cairo-xlib-display.c
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
45 #include <X11/Xlibint.h>        /* For XESetCloseDisplay */
46
47 typedef int (*cairo_xlib_error_func_t) (Display     *display,
48                                         XErrorEvent *event);
49
50 static cairo_xlib_display_t *_cairo_xlib_display_list;
51
52 static int
53 _noop_error_handler (Display     *display,
54                      XErrorEvent *event)
55 {
56     return False;               /* return value is ignored */
57 }
58
59 static void
60 _cairo_xlib_display_finish (void *abstract_display)
61 {
62     cairo_xlib_display_t *display = abstract_display;
63     Display *dpy = display->display;
64
65     if (! cairo_device_acquire (&display->base)) {
66         cairo_xlib_error_func_t old_handler;
67
68         /* protect the notifies from triggering XErrors */
69         XSync (dpy, False);
70         old_handler = XSetErrorHandler (_noop_error_handler);
71
72         while (! cairo_list_is_empty (&display->fonts)) {
73             _cairo_xlib_font_close (cairo_list_first_entry (&display->fonts,
74                                                             cairo_xlib_font_t,
75                                                             link));
76         }
77
78         while (! cairo_list_is_empty (&display->screens)) {
79             _cairo_xlib_screen_destroy (display,
80                                         cairo_list_first_entry (&display->screens,
81                                                                 cairo_xlib_screen_t,
82                                                                 link));
83         }
84
85         XSync (dpy, False);
86         XSetErrorHandler (old_handler);
87
88         cairo_device_release (&display->base);
89     }
90 }
91
92 static void
93 _cairo_xlib_display_destroy (void *abstract_display)
94 {
95     cairo_xlib_display_t *display = abstract_display;
96
97     free (display);
98 }
99
100 static int
101 _cairo_xlib_close_display (Display *dpy, XExtCodes *codes)
102 {
103     cairo_xlib_display_t *display, **prev, *next;
104
105     CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
106     for (display = _cairo_xlib_display_list; display; display = display->next)
107         if (display->display == dpy)
108             break;
109     CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
110     if (display == NULL)
111         return 0;
112
113     cairo_device_finish (&display->base);
114
115     /*
116      * Unhook from the global list
117      */
118     CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
119     prev = &_cairo_xlib_display_list;
120     for (display = _cairo_xlib_display_list; display; display = next) {
121         next = display->next;
122         if (display->display == dpy) {
123             *prev = next;
124             break;
125         } else
126             prev = &display->next;
127     }
128     CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
129
130     display->display = NULL; /* catch any later invalid access */
131     cairo_device_destroy (&display->base);
132
133     /* Return value in accordance with requirements of
134      * XESetCloseDisplay */
135     return 0;
136 }
137
138 static const cairo_device_backend_t _cairo_xlib_device_backend = {
139     CAIRO_DEVICE_TYPE_XLIB,
140
141     NULL,
142     NULL,
143
144     NULL, /* flush */
145     _cairo_xlib_display_finish,
146     _cairo_xlib_display_destroy,
147 };
148
149 /**
150  * cairo_xlib_device_create:
151  * @dpy: the display to create the device for
152  *
153  * Gets the device belonging to @dpy, or creates it if it doesn't exist yet.
154  *
155  * Returns: the device belonging to @dpy
156  **/
157 cairo_device_t *
158 _cairo_xlib_device_create (Display *dpy)
159 {
160     cairo_xlib_display_t *display;
161     cairo_xlib_display_t **prev;
162     cairo_device_t *device;
163     XExtCodes *codes;
164     const char *env;
165
166     CAIRO_MUTEX_INITIALIZE ();
167
168     /* There is an apparent deadlock between this mutex and the
169      * mutex for the display, but it's actually safe. For the
170      * app to call XCloseDisplay() while any other thread is
171      * inside this function would be an error in the logic
172      * app, and the CloseDisplay hook is the only other place we
173      * acquire this mutex.
174      */
175     CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
176
177     for (prev = &_cairo_xlib_display_list; (display = *prev); prev = &(*prev)->next)
178     {
179         if (display->display == dpy) {
180             /*
181              * MRU the list
182              */
183             if (prev != &_cairo_xlib_display_list) {
184                 *prev = display->next;
185                 display->next = _cairo_xlib_display_list;
186                 _cairo_xlib_display_list = display;
187             }
188             device = cairo_device_reference (&display->base);
189             goto UNLOCK;
190         }
191     }
192
193     display = malloc (sizeof (cairo_xlib_display_t));
194     if (unlikely (display == NULL)) {
195         device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
196         goto UNLOCK;
197     }
198
199     /* Xlib calls out to the extension close_display hooks in LIFO
200      * order. So we have to ensure that all extensions that we depend
201      * on in our close_display hook are properly initialized before we
202      * add our hook. For now, that means Render, so we call into its
203      * QueryVersion function to ensure it gets initialized.
204      */
205     display->render_major = display->render_minor = -1;
206     XRenderQueryVersion (dpy, &display->render_major, &display->render_minor);
207     env = getenv ("CAIRO_DEBUG");
208     if (env != NULL && (env = strstr (env, "xrender-version=")) != NULL) {
209         int max_render_major, max_render_minor;
210
211         env += sizeof ("xrender-version=") - 1;
212         if (sscanf (env, "%d.%d", &max_render_major, &max_render_minor) != 2)
213             max_render_major = max_render_minor = -1;
214
215         if (max_render_major < display->render_major ||
216             (max_render_major == display->render_major &&
217              max_render_minor < display->render_minor))
218         {
219             display->render_major = max_render_major;
220             display->render_minor = max_render_minor;
221         }
222     }
223
224     codes = XAddExtension (dpy);
225     if (unlikely (codes == NULL)) {
226         device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
227         free (display);
228         goto UNLOCK;
229     }
230
231     _cairo_device_init (&display->base, &_cairo_xlib_device_backend);
232
233     XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display);
234
235     cairo_device_reference (&display->base); /* add one for the CloseDisplay */
236     display->display = dpy;
237     cairo_list_init (&display->screens);
238     cairo_list_init (&display->fonts);
239     display->closed = FALSE;
240
241     display->white = NULL;
242     memset (display->alpha, 0, sizeof (display->alpha));
243     memset (display->solid, 0, sizeof (display->solid));
244     memset (display->solid_cache, 0, sizeof (display->solid_cache));
245     memset (display->last_solid_cache, 0, sizeof (display->last_solid_cache));
246
247     memset (display->cached_xrender_formats, 0,
248             sizeof (display->cached_xrender_formats));
249
250     display->force_precision = -1;
251
252     /* Prior to Render 0.10, there is no protocol support for gradients and
253      * we call function stubs instead, which would silently consume the drawing.
254      */
255 #if RENDER_MAJOR == 0 && RENDER_MINOR < 10
256     display->buggy_gradients = TRUE;
257 #else
258     display->buggy_gradients = FALSE;
259 #endif
260     display->buggy_pad_reflect = FALSE;
261     display->buggy_repeat = FALSE;
262
263     /* This buggy_repeat condition is very complicated because there
264      * are multiple X server code bases (with multiple versioning
265      * schemes within a code base), and multiple bugs.
266      *
267      * The X servers:
268      *
269      *    1. The Vendor=="XFree86" code base with release numbers such
270      *    as 4.7.0 (VendorRelease==40700000).
271      *
272      *    2. The Vendor=="X.Org" code base (a descendant of the
273      *    XFree86 code base). It originally had things like
274      *    VendorRelease==60700000 for release 6.7.0 but then changed
275      *    its versioning scheme so that, for example,
276      *    VendorRelease==10400000 for the 1.4.0 X server within the
277      *    X.Org 7.3 release.
278      *
279      * The bugs:
280      *
281      *    1. The original bug that led to the buggy_repeat
282      *    workaround. This was a bug that Owen Taylor investigated,
283      *    understood well, and characterized against carious X
284      *    servers. Confirmed X servers with this bug include:
285      *
286      *          "XFree86" <= 40500000
287      *          "X.Org" <= 60802000 (only with old numbering >= 60700000)
288      *
289      *    2. A separate bug resulting in a crash of the X server when
290      *    using cairo's extend-reflect test case, (which, surprisingly
291      *    enough was not passing RepeatReflect to the X server, but
292      *    instead using RepeatNormal in a workaround). Nobody to date
293      *    has understood the bug well, but it appears to be gone as of
294      *    the X.Org 1.4.0 server. This bug is coincidentally avoided
295      *    by using the same buggy_repeat workaround. Confirmed X
296      *    servers with this bug include:
297      *
298      *          "X.org" == 60900000 (old versioning scheme)
299      *          "X.org"  < 10400000 (new numbering scheme)
300      *
301      *    For the old-versioning-scheme X servers we don't know
302      *    exactly when second the bug started, but since bug 1 is
303      *    present through 6.8.2 and bug 2 is present in 6.9.0 it seems
304      *    safest to just blacklist all old-versioning-scheme X servers,
305      *    (just using VendorRelease < 70000000), as buggy_repeat=TRUE.
306      */
307     if (strstr (ServerVendor (dpy), "X.Org") != NULL) {
308         if (VendorRelease (dpy) >= 60700000) {
309             if (VendorRelease (dpy) < 70000000)
310                 display->buggy_repeat = TRUE;
311
312             /* We know that gradients simply do not work in early Xorg servers */
313             if (VendorRelease (dpy) < 70200000)
314                 display->buggy_gradients = TRUE;
315
316             /* And the extended repeat modes were not fixed until much later */
317             display->buggy_pad_reflect = TRUE;
318         } else {
319             if (VendorRelease (dpy) < 10400000)
320                 display->buggy_repeat = TRUE;
321
322             /* Too many bugs in the early drivers */
323             if (VendorRelease (dpy) < 10699000)
324                 display->buggy_pad_reflect = TRUE;
325         }
326     } else if (strstr (ServerVendor (dpy), "XFree86") != NULL) {
327         if (VendorRelease (dpy) <= 40500000)
328             display->buggy_repeat = TRUE;
329
330         display->buggy_gradients = TRUE;
331         display->buggy_pad_reflect = TRUE;
332     }
333
334     if (display->render_major > 0 || display->render_minor >= 4)
335         display->compositor = _cairo_xlib_traps_compositor_get ();
336     else if (display->render_major > 0 || display->render_minor >= 0)
337         display->compositor = _cairo_xlib_mask_compositor_get ();
338     else
339         display->compositor = _cairo_xlib_core_compositor_get ();
340
341     display->next = _cairo_xlib_display_list;
342     _cairo_xlib_display_list = display;
343
344     device = &display->base;
345
346 UNLOCK:
347     CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
348     return device;
349 }
350
351 cairo_status_t
352 _cairo_xlib_display_acquire (cairo_device_t *device, cairo_xlib_display_t **display)
353 {
354     cairo_status_t status;
355
356     status = cairo_device_acquire (device);
357     if (status)
358         return status;
359
360     *display = (cairo_xlib_display_t *) device;
361     return status;
362 }
363
364 XRenderPictFormat *
365 _cairo_xlib_display_get_xrender_format_for_pixman(cairo_xlib_display_t *display,
366                                                   pixman_format_code_t format)
367 {
368     Display *dpy = display->display;
369     XRenderPictFormat tmpl;
370     int mask;
371
372 #define MASK(x) ((1<<(x))-1)
373
374     tmpl.depth = PIXMAN_FORMAT_DEPTH(format);
375     mask = PictFormatType | PictFormatDepth;
376
377     switch (PIXMAN_FORMAT_TYPE(format)) {
378     case PIXMAN_TYPE_ARGB:
379         tmpl.type = PictTypeDirect;
380
381         tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
382         if (PIXMAN_FORMAT_A(format))
383             tmpl.direct.alpha = (PIXMAN_FORMAT_R(format) +
384                                  PIXMAN_FORMAT_G(format) +
385                                  PIXMAN_FORMAT_B(format));
386
387         tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
388         tmpl.direct.red = (PIXMAN_FORMAT_G(format) +
389                            PIXMAN_FORMAT_B(format));
390
391         tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
392         tmpl.direct.green = PIXMAN_FORMAT_B(format);
393
394         tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
395         tmpl.direct.blue = 0;
396
397         mask |= PictFormatRed | PictFormatRedMask;
398         mask |= PictFormatGreen | PictFormatGreenMask;
399         mask |= PictFormatBlue | PictFormatBlueMask;
400         mask |= PictFormatAlpha | PictFormatAlphaMask;
401         break;
402
403     case PIXMAN_TYPE_ABGR:
404         tmpl.type = PictTypeDirect;
405
406         tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
407         if (tmpl.direct.alphaMask)
408             tmpl.direct.alpha = (PIXMAN_FORMAT_B(format) +
409                                  PIXMAN_FORMAT_G(format) +
410                                  PIXMAN_FORMAT_R(format));
411
412         tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
413         tmpl.direct.blue = (PIXMAN_FORMAT_G(format) +
414                             PIXMAN_FORMAT_R(format));
415
416         tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
417         tmpl.direct.green = PIXMAN_FORMAT_R(format);
418
419         tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
420         tmpl.direct.red = 0;
421
422         mask |= PictFormatRed | PictFormatRedMask;
423         mask |= PictFormatGreen | PictFormatGreenMask;
424         mask |= PictFormatBlue | PictFormatBlueMask;
425         mask |= PictFormatAlpha | PictFormatAlphaMask;
426         break;
427
428     case PIXMAN_TYPE_BGRA:
429         tmpl.type = PictTypeDirect;
430
431         tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format));
432         tmpl.direct.blue = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format));
433
434         tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format));
435         tmpl.direct.green = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) -
436                              PIXMAN_FORMAT_G(format));
437
438         tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format));
439         tmpl.direct.red = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) -
440                            PIXMAN_FORMAT_G(format) - PIXMAN_FORMAT_R(format));
441
442         tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
443         tmpl.direct.alpha = 0;
444
445         mask |= PictFormatRed | PictFormatRedMask;
446         mask |= PictFormatGreen | PictFormatGreenMask;
447         mask |= PictFormatBlue | PictFormatBlueMask;
448         mask |= PictFormatAlpha | PictFormatAlphaMask;
449         break;
450
451     case PIXMAN_TYPE_A:
452         tmpl.type = PictTypeDirect;
453
454         tmpl.direct.alpha = 0;
455         tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format));
456
457         mask |= PictFormatAlpha | PictFormatAlphaMask;
458         break;
459
460     case PIXMAN_TYPE_COLOR:
461     case PIXMAN_TYPE_GRAY:
462         /* XXX Find matching visual/colormap */
463         tmpl.type = PictTypeIndexed;
464         //tmpl.colormap = screen->visuals[PIXMAN_FORMAT_VIS(format)].vid;
465         //mask |= PictFormatColormap;
466         return NULL;
467     }
468 #undef MASK
469
470     /* XXX caching? */
471     return XRenderFindFormat(dpy, mask, &tmpl, 1);
472 }
473
474 XRenderPictFormat *
475 _cairo_xlib_display_get_xrender_format (cairo_xlib_display_t    *display,
476                                         cairo_format_t           format)
477 {
478     XRenderPictFormat *xrender_format;
479
480 #if ! ATOMIC_OP_NEEDS_MEMORY_BARRIER
481     xrender_format = display->cached_xrender_formats[format];
482     if (likely (xrender_format != NULL))
483         return xrender_format;
484 #endif
485
486     xrender_format = display->cached_xrender_formats[format];
487     if (xrender_format == NULL) {
488         int pict_format;
489
490         switch (format) {
491         case CAIRO_FORMAT_A1:
492             pict_format = PictStandardA1; break;
493         case CAIRO_FORMAT_A8:
494             pict_format = PictStandardA8; break;
495         case CAIRO_FORMAT_RGB24:
496             pict_format = PictStandardRGB24; break;
497         case CAIRO_FORMAT_RGB16_565:
498             xrender_format = _cairo_xlib_display_get_xrender_format_for_pixman(display,
499                                                                                PIXMAN_r5g6b5);
500             break;
501         case CAIRO_FORMAT_RGB30:
502             xrender_format = _cairo_xlib_display_get_xrender_format_for_pixman(display,
503                                                                                PIXMAN_x2r10g10b10);
504             break;
505         case CAIRO_FORMAT_INVALID:
506         default:
507             ASSERT_NOT_REACHED;
508         case CAIRO_FORMAT_ARGB32:
509             pict_format = PictStandardARGB32; break;
510         }
511         if (!xrender_format)
512             xrender_format = XRenderFindStandardFormat (display->display,
513                                                         pict_format);
514         display->cached_xrender_formats[format] = xrender_format;
515     }
516
517     return xrender_format;
518 }
519
520 cairo_xlib_screen_t *
521 _cairo_xlib_display_get_screen (cairo_xlib_display_t *display,
522                                 Screen *screen)
523 {
524     cairo_xlib_screen_t *info;
525
526     cairo_list_foreach_entry (info, cairo_xlib_screen_t, &display->screens, link) {
527         if (info->screen == screen) {
528             if (display->screens.next != &info->link)
529                 cairo_list_move (&info->link, &display->screens);
530             return info;
531         }
532     }
533
534     return NULL;
535 }
536
537 cairo_bool_t
538 _cairo_xlib_display_has_repeat (cairo_device_t *device)
539 {
540     return ! ((cairo_xlib_display_t *) device)->buggy_repeat;
541 }
542
543 cairo_bool_t
544 _cairo_xlib_display_has_reflect (cairo_device_t *device)
545 {
546     return ! ((cairo_xlib_display_t *) device)->buggy_pad_reflect;
547 }
548
549 cairo_bool_t
550 _cairo_xlib_display_has_gradients (cairo_device_t *device)
551 {
552     return ! ((cairo_xlib_display_t *) device)->buggy_gradients;
553 }
554
555 void
556 cairo_xlib_device_debug_set_precision (cairo_device_t *device,
557                                        int precision)
558 {
559     if (device == NULL || device->status)
560         return;
561     if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) {
562         cairo_status_t status;
563
564         status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
565         (void) status;
566         return;
567     }
568
569     ((cairo_xlib_display_t *) device)->force_precision = precision;
570 }
571
572 int
573 cairo_xlib_device_debug_get_precision (cairo_device_t *device)
574 {
575     if (device == NULL || device->status)
576         return -1;
577     if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) {
578         cairo_status_t status;
579
580         status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
581         (void) status;
582         return -1;
583     }
584
585     return ((cairo_xlib_display_t *) device)->force_precision;
586 }
587
588 #endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */