Upload Tizen2.0 source
[framework/graphics/cairo.git] / src / cairo-xlib-xcb-surface.c
1 /* cairo - a vector graphics library with display and print output
2  *
3  * Copyright © 2002 University of Southern California
4  * Copyright © 2009 Intel Corporation
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it either under the terms of the GNU Lesser General Public
8  * License version 2.1 as published by the Free Software Foundation
9  * (the "LGPL") or, at your option, under the terms of the Mozilla
10  * Public License Version 1.1 (the "MPL"). If you do not alter this
11  * notice, a recipient may use your version of this file under either
12  * the MPL or the LGPL.
13  *
14  * You should have received a copy of the LGPL along with this library
15  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17  * You should have received a copy of the MPL along with this library
18  * in the file COPYING-MPL-1.1
19  *
20  * The contents of this file are subject to the Mozilla Public License
21  * Version 1.1 (the "License"); you may not use this file except in
22  * compliance with the License. You may obtain a copy of the License at
23  * http://www.mozilla.org/MPL/
24  *
25  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27  * the specific language governing rights and limitations.
28  *
29  * The Original Code is the cairo graphics library.
30  *
31  * The Initial Developer of the Original Code is University of Southern
32  * California.
33  *
34  * Contributor(s):
35  *      Carl D. Worth <cworth@cworth.org>
36  *      Chris Wilson <chris@chris-wilson.co.uk>
37  */
38
39 #include "cairoint.h"
40
41 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
42
43 #include "cairo-xlib.h"
44 #include "cairo-xcb.h"
45
46 #include "cairo-xcb-private.h"
47 #include "cairo-xlib-xrender-private.h"
48
49 #include "cairo-default-context-private.h"
50 #include "cairo-list-inline.h"
51 #include "cairo-image-surface-private.h"
52 #include "cairo-surface-backend-private.h"
53
54 #include <X11/Xlib-xcb.h>
55 #include <X11/Xlibint.h>        /* For XESetCloseDisplay */
56
57 struct cairo_xlib_xcb_display_t {
58     cairo_device_t  base;
59
60     Display        *dpy;
61     cairo_device_t *xcb_device;
62     XExtCodes      *codes;
63
64     cairo_list_t    link;
65 };
66 typedef struct cairo_xlib_xcb_display_t cairo_xlib_xcb_display_t;
67
68 /* List of all #cairo_xlib_xcb_display_t alive,
69  * protected by _cairo_xlib_display_mutex */
70 static cairo_list_t displays;
71
72 static cairo_surface_t *
73 _cairo_xlib_xcb_surface_create (void *dpy,
74                                 void *scr,
75                                 void *visual,
76                                 void *format,
77                                 cairo_surface_t *xcb);
78
79 static cairo_surface_t *
80 _cairo_xlib_xcb_surface_create_similar (void                    *abstract_other,
81                                         cairo_content_t          content,
82                                         int                      width,
83                                         int                      height)
84 {
85     cairo_xlib_xcb_surface_t *other = abstract_other;
86     cairo_surface_t *xcb;
87
88     xcb = other->xcb->base.backend->create_similar (other->xcb, content, width, height);
89     if (unlikely (xcb == NULL || xcb->status))
90         return xcb;
91
92     return _cairo_xlib_xcb_surface_create (other->display, other->screen, NULL, NULL, xcb);
93 }
94
95 static cairo_status_t
96 _cairo_xlib_xcb_surface_finish (void *abstract_surface)
97 {
98     cairo_xlib_xcb_surface_t *surface = abstract_surface;
99     cairo_status_t status;
100
101     cairo_surface_finish (&surface->xcb->base);
102     status = surface->xcb->base.status;
103     cairo_surface_destroy (&surface->xcb->base);
104     surface->xcb = NULL;
105
106     return status;
107 }
108
109 static cairo_surface_t *
110 _cairo_xlib_xcb_surface_create_similar_image (void                      *abstract_other,
111                                               cairo_format_t             format,
112                                               int                        width,
113                                               int                        height)
114 {
115     cairo_xlib_xcb_surface_t *surface = abstract_other;
116     return cairo_surface_create_similar_image (&surface->xcb->base, format, width, height);
117 }
118
119 static cairo_surface_t *
120 _cairo_xlib_xcb_surface_map_to_image (void *abstract_surface,
121                                       const cairo_rectangle_int_t *extents)
122 {
123     cairo_xlib_xcb_surface_t *surface = abstract_surface;
124     return cairo_surface_map_to_image (&surface->xcb->base, extents);
125 }
126
127 static cairo_int_status_t
128 _cairo_xlib_xcb_surface_unmap (void *abstract_surface,
129                                cairo_image_surface_t *image)
130 {
131     cairo_xlib_xcb_surface_t *surface = abstract_surface;
132
133     /* cairo_surface_unmap_image destroys the surface, so get a new reference
134      * for it to destroy.
135      */
136     cairo_surface_reference (&image->base);
137     cairo_surface_unmap_image (&surface->xcb->base, &image->base);
138     return cairo_surface_status (&surface->xcb->base);
139 }
140
141 static cairo_surface_t *
142 _cairo_xlib_xcb_surface_source (void *abstract_surface,
143                                 cairo_rectangle_int_t *extents)
144 {
145     cairo_xlib_xcb_surface_t *surface = abstract_surface;
146     return _cairo_surface_get_source (&surface->xcb->base, extents);
147 }
148
149 static cairo_status_t
150 _cairo_xlib_xcb_surface_acquire_source_image (void *abstract_surface,
151                                               cairo_image_surface_t **image_out,
152                                               void **image_extra)
153 {
154     cairo_xlib_xcb_surface_t *surface = abstract_surface;
155     return _cairo_surface_acquire_source_image (&surface->xcb->base,
156                                                 image_out, image_extra);
157 }
158
159 static void
160 _cairo_xlib_xcb_surface_release_source_image (void *abstract_surface,
161                                               cairo_image_surface_t *image_out,
162                                               void *image_extra)
163 {
164     cairo_xlib_xcb_surface_t *surface = abstract_surface;
165     _cairo_surface_release_source_image (&surface->xcb->base, image_out, image_extra);
166 }
167
168 static cairo_bool_t
169 _cairo_xlib_xcb_surface_get_extents (void *abstract_surface,
170                                      cairo_rectangle_int_t *extents)
171 {
172     cairo_xlib_xcb_surface_t *surface = abstract_surface;
173     return _cairo_surface_get_extents (&surface->xcb->base, extents);
174 }
175
176 static void
177 _cairo_xlib_xcb_surface_get_font_options (void *abstract_surface,
178                                           cairo_font_options_t *options)
179 {
180     cairo_xlib_xcb_surface_t *surface = abstract_surface;
181     cairo_surface_get_font_options (&surface->xcb->base, options);
182 }
183
184 static cairo_int_status_t
185 _cairo_xlib_xcb_surface_paint (void                     *abstract_surface,
186                                cairo_operator_t          op,
187                                const cairo_pattern_t    *source,
188                                const cairo_clip_t       *clip)
189 {
190     cairo_xlib_xcb_surface_t *surface = abstract_surface;
191     return _cairo_surface_paint (&surface->xcb->base, op, source, clip);
192 }
193
194 static cairo_int_status_t
195 _cairo_xlib_xcb_surface_mask (void                      *abstract_surface,
196                               cairo_operator_t           op,
197                               const cairo_pattern_t     *source,
198                               const cairo_pattern_t     *mask,
199                               const cairo_clip_t        *clip)
200 {
201     cairo_xlib_xcb_surface_t *surface = abstract_surface;
202     return _cairo_surface_mask (&surface->xcb->base, op, source, mask, clip);
203 }
204
205 static cairo_int_status_t
206 _cairo_xlib_xcb_surface_stroke (void                            *abstract_surface,
207                                 cairo_operator_t                 op,
208                                 const cairo_pattern_t           *source,
209                                 const cairo_path_fixed_t        *path,
210                                 const cairo_stroke_style_t      *style,
211                                 const cairo_matrix_t            *ctm,
212                                 const cairo_matrix_t            *ctm_inverse,
213                                 double                           tolerance,
214                                 cairo_antialias_t                antialias,
215                                 const cairo_clip_t              *clip)
216 {
217     cairo_xlib_xcb_surface_t *surface = abstract_surface;
218     return _cairo_surface_stroke (&surface->xcb->base,
219                                   op, source, path, style, ctm, ctm_inverse,
220                                   tolerance, antialias, clip);
221 }
222
223 static cairo_int_status_t
224 _cairo_xlib_xcb_surface_fill (void                      *abstract_surface,
225                               cairo_operator_t           op,
226                               const cairo_pattern_t     *source,
227                               const cairo_path_fixed_t  *path,
228                               cairo_fill_rule_t          fill_rule,
229                               double                     tolerance,
230                               cairo_antialias_t          antialias,
231                               const cairo_clip_t        *clip)
232 {
233     cairo_xlib_xcb_surface_t *surface = abstract_surface;
234     return _cairo_surface_fill (&surface->xcb->base,
235                                 op, source, path,
236                                 fill_rule, tolerance,
237                                 antialias, clip);
238 }
239
240 static cairo_int_status_t
241 _cairo_xlib_xcb_surface_glyphs (void                    *abstract_surface,
242                                 cairo_operator_t         op,
243                                 const cairo_pattern_t   *source,
244                                 cairo_glyph_t           *glyphs,
245                                 int                      num_glyphs,
246                                 cairo_scaled_font_t     *scaled_font,
247                                 const cairo_clip_t      *clip)
248 {
249     cairo_xlib_xcb_surface_t *surface = abstract_surface;
250     return _cairo_surface_show_text_glyphs (&surface->xcb->base, op, source,
251                                             NULL, 0,
252                                             glyphs, num_glyphs,
253                                             NULL, 0, 0,
254                                             scaled_font, clip);
255 }
256
257 static cairo_status_t
258 _cairo_xlib_xcb_surface_flush (void *abstract_surface)
259 {
260     cairo_xlib_xcb_surface_t *surface = abstract_surface;
261     /* We have to call cairo_surface_flush() to make sure snapshots are detached */
262     cairo_surface_flush (&surface->xcb->base);
263     return CAIRO_STATUS_SUCCESS;
264 }
265
266 static cairo_status_t
267 _cairo_xlib_xcb_surface_mark_dirty (void *abstract_surface,
268                                     int x, int y,
269                                     int width, int height)
270 {
271     cairo_xlib_xcb_surface_t *surface = abstract_surface;
272     cairo_surface_mark_dirty_rectangle (&surface->xcb->base, x, y, width, height);
273     return cairo_surface_status (&surface->xcb->base);
274 }
275
276 static const cairo_surface_backend_t _cairo_xlib_xcb_surface_backend = {
277     CAIRO_SURFACE_TYPE_XLIB,
278     _cairo_xlib_xcb_surface_finish,
279
280     _cairo_default_context_create, /* XXX */
281
282     _cairo_xlib_xcb_surface_create_similar,
283     _cairo_xlib_xcb_surface_create_similar_image,
284     _cairo_xlib_xcb_surface_map_to_image,
285     _cairo_xlib_xcb_surface_unmap,
286
287     _cairo_xlib_xcb_surface_source,
288     _cairo_xlib_xcb_surface_acquire_source_image,
289     _cairo_xlib_xcb_surface_release_source_image,
290     NULL, /* snapshot */
291
292     NULL, /* copy_page */
293     NULL, /* show_page */
294
295     _cairo_xlib_xcb_surface_get_extents,
296     _cairo_xlib_xcb_surface_get_font_options,
297
298     _cairo_xlib_xcb_surface_flush,
299     _cairo_xlib_xcb_surface_mark_dirty,
300
301     _cairo_xlib_xcb_surface_paint,
302     _cairo_xlib_xcb_surface_mask,
303     _cairo_xlib_xcb_surface_stroke,
304     _cairo_xlib_xcb_surface_fill,
305     NULL, /* fill_stroke */
306     _cairo_xlib_xcb_surface_glyphs,
307 };
308
309 static void
310 _cairo_xlib_xcb_display_finish (void *abstract_display)
311 {
312     cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) abstract_display;
313
314     CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
315     cairo_list_del (&display->link);
316     CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
317
318     cairo_device_destroy (display->xcb_device);
319     display->xcb_device = NULL;
320
321     XESetCloseDisplay (display->dpy, display->codes->extension, NULL);
322     /* Drop the reference from _cairo_xlib_xcb_device_create */
323     cairo_device_destroy (&display->base);
324 }
325
326 static int
327 _cairo_xlib_xcb_close_display(Display *dpy, XExtCodes *codes)
328 {
329     cairo_xlib_xcb_display_t *display;
330
331     CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
332     cairo_list_foreach_entry (display,
333                               cairo_xlib_xcb_display_t,
334                               &displays,
335                               link)
336     {
337         if (display->dpy == dpy)
338         {
339             /* _cairo_xlib_xcb_display_finish will lock the mutex again
340              * -> deadlock (This mutex isn't recursive) */
341             cairo_device_reference (&display->base);
342             CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
343
344             /* Make sure the xcb and xlib-xcb devices are finished */
345             cairo_device_finish (display->xcb_device);
346             cairo_device_finish (&display->base);
347
348             cairo_device_destroy (&display->base);
349             return 0;
350         }
351     }
352     CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
353
354     return 0;
355 }
356
357 static const cairo_device_backend_t _cairo_xlib_xcb_device_backend = {
358     CAIRO_DEVICE_TYPE_XLIB,
359
360     NULL,
361     NULL,
362
363     NULL, /* flush */
364     _cairo_xlib_xcb_display_finish,
365     free, /* destroy */
366 };
367
368 static cairo_device_t *
369 _cairo_xlib_xcb_device_create (Display *dpy, cairo_device_t *xcb_device)
370 {
371     cairo_xlib_xcb_display_t *display = NULL;
372     cairo_device_t *device;
373
374     if (xcb_device == NULL)
375         return NULL;
376
377     CAIRO_MUTEX_INITIALIZE ();
378
379     CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
380     if (displays.next == NULL) {
381         cairo_list_init (&displays);
382     }
383
384     cairo_list_foreach_entry (display,
385                               cairo_xlib_xcb_display_t,
386                               &displays,
387                               link)
388     {
389         if (display->dpy == dpy) {
390             /* Maintain MRU order. */
391             if (displays.next != &display->link)
392                 cairo_list_move (&display->link, &displays);
393
394             /* Grab a reference for our caller */
395             device = cairo_device_reference (&display->base);
396             assert (display->xcb_device == xcb_device);
397             goto unlock;
398         }
399     }
400
401     display = malloc (sizeof (cairo_xlib_xcb_display_t));
402     if (unlikely (display == NULL)) {
403         device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
404         goto unlock;
405     }
406
407     display->codes = XAddExtension (dpy);
408     if (unlikely (display->codes == NULL)) {
409         device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
410         free (display);
411         goto unlock;
412     }
413
414     _cairo_device_init (&display->base, &_cairo_xlib_xcb_device_backend);
415
416     XESetCloseDisplay (dpy, display->codes->extension, _cairo_xlib_xcb_close_display);
417     /* Add a reference for _cairo_xlib_xcb_display_finish. This basically means
418      * that the device's reference count never drops to zero
419      * as long as our Display* is alive. We need this because there is no
420      * "XDelExtension" to undo XAddExtension and having lots of registered
421      * extensions slows down libX11. */
422     cairo_device_reference (&display->base);
423
424     display->dpy = dpy;
425     display->xcb_device = cairo_device_reference(xcb_device);
426
427     cairo_list_add (&display->link, &displays);
428     device = &display->base;
429
430 unlock:
431     CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
432
433     return device;
434 }
435
436 static cairo_surface_t *
437 _cairo_xlib_xcb_surface_create (void *dpy,
438                                 void *scr,
439                                 void *visual,
440                                 void *format,
441                                 cairo_surface_t *xcb)
442 {
443     cairo_xlib_xcb_surface_t *surface;
444
445     if (unlikely (xcb->status))
446         return xcb;
447
448     surface = malloc (sizeof (*surface));
449     if (unlikely (surface == NULL)) {
450         cairo_surface_destroy (xcb);
451         return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
452     }
453
454     _cairo_surface_init (&surface->base,
455                          &_cairo_xlib_xcb_surface_backend,
456                          _cairo_xlib_xcb_device_create (dpy, xcb->device),
457                          xcb->content);
458
459     /* _cairo_surface_init() got another reference to the device, drop ours */
460     cairo_device_destroy (surface->base.device);
461
462     surface->display = dpy;
463     surface->screen = scr;
464     surface->visual = visual;
465     surface->format = format;
466     surface->xcb = (cairo_xcb_surface_t *) xcb;
467
468     return &surface->base;
469 }
470
471 static Screen *
472 _cairo_xlib_screen_from_visual (Display *dpy, Visual *visual)
473 {
474     int s, d, v;
475
476     for (s = 0; s < ScreenCount (dpy); s++) {
477         Screen *screen;
478
479         screen = ScreenOfDisplay (dpy, s);
480         if (visual == DefaultVisualOfScreen (screen))
481             return screen;
482
483         for (d = 0; d < screen->ndepths; d++) {
484             Depth  *depth;
485
486             depth = &screen->depths[d];
487             for (v = 0; v < depth->nvisuals; v++)
488                 if (visual == &depth->visuals[v])
489                     return screen;
490         }
491     }
492
493     return NULL;
494 }
495
496 cairo_surface_t *
497 cairo_xlib_surface_create (Display     *dpy,
498                            Drawable     drawable,
499                            Visual      *visual,
500                            int          width,
501                            int          height)
502 {
503     Screen *scr;
504     xcb_visualtype_t xcb_visual;
505
506     scr = _cairo_xlib_screen_from_visual (dpy, visual);
507     if (scr == NULL)
508         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
509
510     xcb_visual.visual_id = visual->visualid;
511 #if defined(__cplusplus) || defined(c_plusplus)
512     xcb_visual._class = visual->c_class;
513 #else
514     xcb_visual._class = visual->class;
515 #endif
516     xcb_visual.bits_per_rgb_value = visual->bits_per_rgb;
517     xcb_visual.colormap_entries = visual->map_entries;
518     xcb_visual.red_mask = visual->red_mask;
519     xcb_visual.green_mask = visual->green_mask;
520     xcb_visual.blue_mask = visual->blue_mask;
521
522     return _cairo_xlib_xcb_surface_create (dpy, scr, visual, NULL,
523                                            cairo_xcb_surface_create (XGetXCBConnection (dpy),
524                                                                      drawable,
525                                                                      &xcb_visual,
526                                                                      width, height));
527 }
528
529 cairo_surface_t *
530 cairo_xlib_surface_create_for_bitmap (Display  *dpy,
531                                       Pixmap    bitmap,
532                                       Screen   *scr,
533                                       int       width,
534                                       int       height)
535 {
536     return _cairo_xlib_xcb_surface_create (dpy, scr, NULL, NULL,
537                                            cairo_xcb_surface_create_for_bitmap (XGetXCBConnection (dpy),
538                                                                                 (xcb_screen_t *) scr,
539                                                                                 bitmap,
540                                                                                 width, height));
541 }
542
543 #if CAIRO_HAS_XLIB_XRENDER_SURFACE
544 static xcb_screen_t *
545 _cairo_xcb_screen_from_root (xcb_connection_t *connection,
546                              xcb_window_t id)
547 {
548     xcb_screen_iterator_t s;
549
550     s = xcb_setup_roots_iterator (xcb_get_setup (connection));
551     for (; s.rem; xcb_screen_next (&s)) {
552         if (s.data->root == id)
553             return s.data;
554     }
555
556     return NULL;
557 }
558 cairo_surface_t *
559 cairo_xlib_surface_create_with_xrender_format (Display              *dpy,
560                                                Drawable             drawable,
561                                                Screen               *scr,
562                                                XRenderPictFormat    *format,
563                                                int                  width,
564                                                int                  height)
565 {
566     xcb_render_pictforminfo_t xcb_format;
567     xcb_connection_t *connection;
568     xcb_screen_t *screen;
569
570     xcb_format.id = format->id;
571     xcb_format.type = format->type;
572     xcb_format.depth = format->depth;
573     xcb_format.direct.red_shift = format->direct.red;
574     xcb_format.direct.red_mask = format->direct.redMask;
575     xcb_format.direct.green_shift = format->direct.green;
576     xcb_format.direct.green_mask = format->direct.greenMask;
577     xcb_format.direct.blue_shift = format->direct.blue;
578     xcb_format.direct.blue_mask = format->direct.blueMask;
579     xcb_format.direct.alpha_shift = format->direct.alpha;
580     xcb_format.direct.alpha_mask = format->direct.alphaMask;
581     xcb_format.colormap = format->colormap;
582
583     connection = XGetXCBConnection (dpy);
584     screen = _cairo_xcb_screen_from_root (connection, (xcb_window_t) scr->root);
585
586     return _cairo_xlib_xcb_surface_create (dpy, scr, NULL, format,
587                                            cairo_xcb_surface_create_with_xrender_format (connection, screen,
588                                                                                          drawable,
589                                                                                          &xcb_format,
590                                                                                          width, height));
591 }
592
593 XRenderPictFormat *
594 cairo_xlib_surface_get_xrender_format (cairo_surface_t *surface)
595 {
596     cairo_xlib_xcb_surface_t *xlib_surface = (cairo_xlib_xcb_surface_t *) surface;
597
598     /* Throw an error for a non-xlib surface */
599     if (surface->type != CAIRO_SURFACE_TYPE_XLIB) {
600         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
601         return NULL;
602     }
603
604     return xlib_surface->format;
605 }
606 #endif
607
608 void
609 cairo_xlib_surface_set_size (cairo_surface_t *abstract_surface,
610                              int              width,
611                              int              height)
612 {
613     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
614     cairo_status_t status;
615
616     if (unlikely (abstract_surface->status))
617         return;
618     if (unlikely (abstract_surface->finished)) {
619         status = _cairo_surface_set_error (abstract_surface,
620                                            _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
621         return;
622     }
623
624     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
625         status = _cairo_surface_set_error (abstract_surface,
626                                            CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
627         return;
628     }
629
630     cairo_xcb_surface_set_size (&surface->xcb->base, width, height);
631     if (unlikely (surface->xcb->base.status)) {
632         status = _cairo_surface_set_error (abstract_surface,
633                                            _cairo_error (surface->xcb->base.status));
634     }
635 }
636
637 void
638 cairo_xlib_surface_set_drawable (cairo_surface_t   *abstract_surface,
639                                  Drawable           drawable,
640                                  int                width,
641                                  int                height)
642 {
643     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *)abstract_surface;
644     cairo_status_t status;
645
646     if (unlikely (abstract_surface->status))
647         return;
648     if (unlikely (abstract_surface->finished)) {
649         status = _cairo_surface_set_error (abstract_surface,
650                                            _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
651         return;
652     }
653
654     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
655         status = _cairo_surface_set_error (abstract_surface,
656                                            CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
657         return;
658     }
659
660     cairo_xcb_surface_set_drawable (&surface->xcb->base, drawable, width, height);
661     if (unlikely (surface->xcb->base.status)) {
662         status = _cairo_surface_set_error (abstract_surface,
663                                            _cairo_error (surface->xcb->base.status));
664     }
665 }
666
667 Display *
668 cairo_xlib_surface_get_display (cairo_surface_t *abstract_surface)
669 {
670     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
671
672     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
673         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
674         return NULL;
675     }
676
677     return surface->display;
678 }
679
680 Drawable
681 cairo_xlib_surface_get_drawable (cairo_surface_t *abstract_surface)
682 {
683     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
684
685     if (unlikely (abstract_surface->finished)) {
686         _cairo_error_throw (CAIRO_STATUS_SURFACE_FINISHED);
687         return 0;
688     }
689     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
690         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
691         return 0;
692     }
693     /* This can happen when e.g. create_similar falls back to an image surface
694      * because we don't have the RENDER extension. */
695     if (surface->xcb->base.type != CAIRO_SURFACE_TYPE_XCB) {
696         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
697         return 0;
698     }
699
700     return surface->xcb->drawable;
701 }
702
703 Screen *
704 cairo_xlib_surface_get_screen (cairo_surface_t *abstract_surface)
705 {
706     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
707
708     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
709         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
710         return NULL;
711     }
712
713     return surface->screen;
714 }
715
716 Visual *
717 cairo_xlib_surface_get_visual (cairo_surface_t *abstract_surface)
718 {
719     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
720
721     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
722         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
723         return NULL;
724     }
725
726     return surface->visual;
727 }
728
729 int
730 cairo_xlib_surface_get_depth (cairo_surface_t *abstract_surface)
731 {
732     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
733
734     if (unlikely (abstract_surface->finished)) {
735         _cairo_error_throw (CAIRO_STATUS_SURFACE_FINISHED);
736         return 0;
737     }
738     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
739         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
740         return 0;
741     }
742     /* This can happen when e.g. create_similar falls back to an image surface
743      * because we don't have the RENDER extension. */
744     if (surface->xcb->base.type != CAIRO_SURFACE_TYPE_XCB) {
745         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
746         return 0;
747     }
748
749     return surface->xcb->depth;
750 }
751
752 int
753 cairo_xlib_surface_get_width (cairo_surface_t *abstract_surface)
754 {
755     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
756
757     if (unlikely (abstract_surface->finished)) {
758         _cairo_error_throw (CAIRO_STATUS_SURFACE_FINISHED);
759         return 0;
760     }
761     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
762         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
763         return 0;
764     }
765     /* This can happen when e.g. create_similar falls back to an image surface
766      * because we don't have the RENDER extension. */
767     if (surface->xcb->base.type != CAIRO_SURFACE_TYPE_XCB) {
768         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
769         return 0;
770     }
771
772     return surface->xcb->width;
773 }
774
775 int
776 cairo_xlib_surface_get_height (cairo_surface_t *abstract_surface)
777 {
778     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
779
780     if (unlikely (abstract_surface->finished)) {
781         _cairo_error_throw (CAIRO_STATUS_SURFACE_FINISHED);
782         return 0;
783     }
784     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
785         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
786         return 0;
787     }
788     /* This can happen when e.g. create_similar falls back to an image surface
789      * because we don't have the RENDER extension. */
790     if (surface->xcb->base.type != CAIRO_SURFACE_TYPE_XCB) {
791         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
792         return 0;
793     }
794
795     return surface->xcb->height;
796 }
797
798 void
799 cairo_xlib_device_debug_cap_xrender_version (cairo_device_t *device,
800                                              int major, int minor)
801 {
802     cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) device;
803
804     if (device == NULL || device->status)
805         return;
806
807     if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB)
808         return;
809
810     cairo_xcb_device_debug_cap_xrender_version (display->xcb_device,
811                                                 major, minor);
812 }
813
814 void
815 cairo_xlib_device_debug_set_precision (cairo_device_t *device,
816                                        int precision)
817 {
818     cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) device;
819
820     if (device == NULL || device->status)
821         return;
822     if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) {
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     cairo_xcb_device_debug_set_precision (display->xcb_device, precision);
831 }
832
833 int
834 cairo_xlib_device_debug_get_precision (cairo_device_t *device)
835 {
836     cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) device;
837
838     if (device == NULL || device->status)
839         return -1;
840     if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) {
841         cairo_status_t status;
842
843         status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
844         (void) status;
845         return -1;
846     }
847
848     return cairo_xcb_device_debug_get_precision (display->xcb_device);
849 }
850
851 #endif /* CAIRO_HAS_XLIB_XCB_FUNCTIONS */