/* cairo - a vector graphics library with display and print output * * Copyright © 2002 University of Southern California * Copyright © 2009 Intel Corporation * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * (the "LGPL") or, at your option, under the terms of the Mozilla * Public License Version 1.1 (the "MPL"). If you do not alter this * notice, a recipient may use your version of this file under either * the MPL or the LGPL. * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY * OF ANY KIND, either express or implied. See the LGPL or the MPL for * the specific language governing rights and limitations. * * The Original Code is the cairo graphics library. * * The Initial Developer of the Original Code is University of Southern * California. * * Contributor(s): * Carl D. Worth * Chris Wilson */ #include "cairoint.h" #if CAIRO_HAS_XLIB_XCB_FUNCTIONS #include "cairo-xlib.h" #include "cairo-xcb.h" #include "cairo-xcb-private.h" #include "cairo-xlib-xrender-private.h" #include "cairo-default-context-private.h" #include "cairo-list-inline.h" #include "cairo-image-surface-private.h" #include "cairo-surface-backend-private.h" #include #include /* For XESetCloseDisplay */ struct cairo_xlib_xcb_display_t { cairo_device_t base; Display *dpy; cairo_device_t *xcb_device; XExtCodes *codes; cairo_list_t link; }; typedef struct cairo_xlib_xcb_display_t cairo_xlib_xcb_display_t; /* List of all #cairo_xlib_xcb_display_t alive, * protected by _cairo_xlib_display_mutex */ static cairo_list_t displays; static cairo_surface_t * _cairo_xlib_xcb_surface_create (void *dpy, void *scr, void *visual, void *format, cairo_surface_t *xcb); static cairo_surface_t * _cairo_xlib_xcb_surface_create_similar (void *abstract_other, cairo_content_t content, int width, int height) { cairo_xlib_xcb_surface_t *other = abstract_other; cairo_surface_t *xcb; xcb = other->xcb->base.backend->create_similar (other->xcb, content, width, height); if (unlikely (xcb == NULL || xcb->status)) return xcb; return _cairo_xlib_xcb_surface_create (other->display, other->screen, NULL, NULL, xcb); } static cairo_status_t _cairo_xlib_xcb_surface_finish (void *abstract_surface) { cairo_xlib_xcb_surface_t *surface = abstract_surface; cairo_status_t status; cairo_surface_finish (&surface->xcb->base); status = surface->xcb->base.status; cairo_surface_destroy (&surface->xcb->base); surface->xcb = NULL; return status; } static cairo_surface_t * _cairo_xlib_xcb_surface_create_similar_image (void *abstract_other, cairo_format_t format, int width, int height) { cairo_xlib_xcb_surface_t *surface = abstract_other; return cairo_surface_create_similar_image (&surface->xcb->base, format, width, height); } static cairo_image_surface_t * _cairo_xlib_xcb_surface_map_to_image (void *abstract_surface, const cairo_rectangle_int_t *extents) { cairo_xlib_xcb_surface_t *surface = abstract_surface; return _cairo_surface_map_to_image (&surface->xcb->base, extents); } static cairo_int_status_t _cairo_xlib_xcb_surface_unmap (void *abstract_surface, cairo_image_surface_t *image) { cairo_xlib_xcb_surface_t *surface = abstract_surface; return _cairo_surface_unmap_image (&surface->xcb->base, image); } static cairo_surface_t * _cairo_xlib_xcb_surface_source (void *abstract_surface, cairo_rectangle_int_t *extents) { cairo_xlib_xcb_surface_t *surface = abstract_surface; return _cairo_surface_get_source (&surface->xcb->base, extents); } static cairo_status_t _cairo_xlib_xcb_surface_acquire_source_image (void *abstract_surface, cairo_image_surface_t **image_out, void **image_extra) { cairo_xlib_xcb_surface_t *surface = abstract_surface; return _cairo_surface_acquire_source_image (&surface->xcb->base, image_out, image_extra); } static void _cairo_xlib_xcb_surface_release_source_image (void *abstract_surface, cairo_image_surface_t *image_out, void *image_extra) { cairo_xlib_xcb_surface_t *surface = abstract_surface; _cairo_surface_release_source_image (&surface->xcb->base, image_out, image_extra); } static cairo_bool_t _cairo_xlib_xcb_surface_get_extents (void *abstract_surface, cairo_rectangle_int_t *extents) { cairo_xlib_xcb_surface_t *surface = abstract_surface; return _cairo_surface_get_extents (&surface->xcb->base, extents); } static void _cairo_xlib_xcb_surface_get_font_options (void *abstract_surface, cairo_font_options_t *options) { cairo_xlib_xcb_surface_t *surface = abstract_surface; cairo_surface_get_font_options (&surface->xcb->base, options); } static cairo_int_status_t _cairo_xlib_xcb_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_clip_t *clip) { cairo_xlib_xcb_surface_t *surface = abstract_surface; return _cairo_surface_paint (&surface->xcb->base, op, source, clip); } static cairo_int_status_t _cairo_xlib_xcb_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, const cairo_clip_t *clip) { cairo_xlib_xcb_surface_t *surface = abstract_surface; return _cairo_surface_mask (&surface->xcb->base, op, source, mask, clip); } static cairo_int_status_t _cairo_xlib_xcb_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, const cairo_clip_t *clip) { cairo_xlib_xcb_surface_t *surface = abstract_surface; return _cairo_surface_stroke (&surface->xcb->base, op, source, path, style, ctm, ctm_inverse, tolerance, antialias, clip); } static cairo_int_status_t _cairo_xlib_xcb_surface_fill (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, const cairo_clip_t *clip) { cairo_xlib_xcb_surface_t *surface = abstract_surface; return _cairo_surface_fill (&surface->xcb->base, op, source, path, fill_rule, tolerance, antialias, clip); } static cairo_int_status_t _cairo_xlib_xcb_surface_glyphs (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, const cairo_clip_t *clip) { cairo_xlib_xcb_surface_t *surface = abstract_surface; return _cairo_surface_show_text_glyphs (&surface->xcb->base, op, source, NULL, 0, glyphs, num_glyphs, NULL, 0, 0, scaled_font, clip); } static cairo_status_t _cairo_xlib_xcb_surface_flush (void *abstract_surface, unsigned flags) { cairo_xlib_xcb_surface_t *surface = abstract_surface; /* We have to call cairo_surface_flush() to make sure snapshots are detached */ return _cairo_surface_flush (&surface->xcb->base, flags); } static cairo_status_t _cairo_xlib_xcb_surface_mark_dirty (void *abstract_surface, int x, int y, int width, int height) { cairo_xlib_xcb_surface_t *surface = abstract_surface; cairo_surface_mark_dirty_rectangle (&surface->xcb->base, x, y, width, height); return cairo_surface_status (&surface->xcb->base); } static const cairo_surface_backend_t _cairo_xlib_xcb_surface_backend = { CAIRO_SURFACE_TYPE_XLIB, _cairo_xlib_xcb_surface_finish, _cairo_default_context_create, /* XXX */ _cairo_xlib_xcb_surface_create_similar, _cairo_xlib_xcb_surface_create_similar_image, _cairo_xlib_xcb_surface_map_to_image, _cairo_xlib_xcb_surface_unmap, _cairo_xlib_xcb_surface_source, _cairo_xlib_xcb_surface_acquire_source_image, _cairo_xlib_xcb_surface_release_source_image, NULL, /* snapshot */ NULL, /* copy_page */ NULL, /* show_page */ _cairo_xlib_xcb_surface_get_extents, _cairo_xlib_xcb_surface_get_font_options, _cairo_xlib_xcb_surface_flush, _cairo_xlib_xcb_surface_mark_dirty, _cairo_xlib_xcb_surface_paint, _cairo_xlib_xcb_surface_mask, _cairo_xlib_xcb_surface_stroke, _cairo_xlib_xcb_surface_fill, NULL, /* fill_stroke */ _cairo_xlib_xcb_surface_glyphs, }; static void _cairo_xlib_xcb_display_finish (void *abstract_display) { cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) abstract_display; CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex); cairo_list_del (&display->link); CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex); cairo_device_destroy (display->xcb_device); display->xcb_device = NULL; XESetCloseDisplay (display->dpy, display->codes->extension, NULL); /* Drop the reference from _cairo_xlib_xcb_device_create */ cairo_device_destroy (&display->base); } static int _cairo_xlib_xcb_close_display(Display *dpy, XExtCodes *codes) { cairo_xlib_xcb_display_t *display; CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex); cairo_list_foreach_entry (display, cairo_xlib_xcb_display_t, &displays, link) { if (display->dpy == dpy) { /* _cairo_xlib_xcb_display_finish will lock the mutex again * -> deadlock (This mutex isn't recursive) */ cairo_device_reference (&display->base); CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex); /* Make sure the xcb and xlib-xcb devices are finished */ cairo_device_finish (display->xcb_device); cairo_device_finish (&display->base); cairo_device_destroy (&display->base); return 0; } } CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex); return 0; } static const cairo_device_backend_t _cairo_xlib_xcb_device_backend = { CAIRO_DEVICE_TYPE_XLIB, NULL, NULL, NULL, /* flush */ _cairo_xlib_xcb_display_finish, free, /* destroy */ }; static cairo_device_t * _cairo_xlib_xcb_device_create (Display *dpy, cairo_device_t *xcb_device) { cairo_xlib_xcb_display_t *display = NULL; cairo_device_t *device; if (xcb_device == NULL) return NULL; CAIRO_MUTEX_INITIALIZE (); CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex); if (displays.next == NULL) { cairo_list_init (&displays); } cairo_list_foreach_entry (display, cairo_xlib_xcb_display_t, &displays, link) { if (display->dpy == dpy) { /* Maintain MRU order. */ if (displays.next != &display->link) cairo_list_move (&display->link, &displays); /* Grab a reference for our caller */ device = cairo_device_reference (&display->base); assert (display->xcb_device == xcb_device); goto unlock; } } display = malloc (sizeof (cairo_xlib_xcb_display_t)); if (unlikely (display == NULL)) { device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY); goto unlock; } display->codes = XAddExtension (dpy); if (unlikely (display->codes == NULL)) { device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY); free (display); goto unlock; } _cairo_device_init (&display->base, &_cairo_xlib_xcb_device_backend); XESetCloseDisplay (dpy, display->codes->extension, _cairo_xlib_xcb_close_display); /* Add a reference for _cairo_xlib_xcb_display_finish. This basically means * that the device's reference count never drops to zero * as long as our Display* is alive. We need this because there is no * "XDelExtension" to undo XAddExtension and having lots of registered * extensions slows down libX11. */ cairo_device_reference (&display->base); display->dpy = dpy; display->xcb_device = cairo_device_reference(xcb_device); cairo_list_add (&display->link, &displays); device = &display->base; unlock: CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex); return device; } static cairo_surface_t * _cairo_xlib_xcb_surface_create (void *dpy, void *scr, void *visual, void *format, cairo_surface_t *xcb) { cairo_xlib_xcb_surface_t *surface; if (unlikely (xcb->status)) return xcb; surface = malloc (sizeof (*surface)); if (unlikely (surface == NULL)) { cairo_surface_destroy (xcb); return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); } _cairo_surface_init (&surface->base, &_cairo_xlib_xcb_surface_backend, _cairo_xlib_xcb_device_create (dpy, xcb->device), xcb->content, FALSE); /* is_vector */ /* _cairo_surface_init() got another reference to the device, drop ours */ cairo_device_destroy (surface->base.device); surface->display = dpy; surface->screen = scr; surface->visual = visual; surface->format = format; surface->xcb = (cairo_xcb_surface_t *) xcb; return &surface->base; } static Screen * _cairo_xlib_screen_from_visual (Display *dpy, Visual *visual) { int s, d, v; for (s = 0; s < ScreenCount (dpy); s++) { Screen *screen; screen = ScreenOfDisplay (dpy, s); if (visual == DefaultVisualOfScreen (screen)) return screen; for (d = 0; d < screen->ndepths; d++) { Depth *depth; depth = &screen->depths[d]; for (v = 0; v < depth->nvisuals; v++) if (visual == &depth->visuals[v]) return screen; } } return NULL; } cairo_surface_t * cairo_xlib_surface_create (Display *dpy, Drawable drawable, Visual *visual, int width, int height) { Screen *scr; xcb_visualtype_t xcb_visual; scr = _cairo_xlib_screen_from_visual (dpy, visual); if (scr == NULL) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL)); xcb_visual.visual_id = visual->visualid; #if defined(__cplusplus) || defined(c_plusplus) xcb_visual._class = visual->c_class; #else xcb_visual._class = visual->class; #endif xcb_visual.bits_per_rgb_value = visual->bits_per_rgb; xcb_visual.colormap_entries = visual->map_entries; xcb_visual.red_mask = visual->red_mask; xcb_visual.green_mask = visual->green_mask; xcb_visual.blue_mask = visual->blue_mask; return _cairo_xlib_xcb_surface_create (dpy, scr, visual, NULL, cairo_xcb_surface_create (XGetXCBConnection (dpy), drawable, &xcb_visual, width, height)); } static xcb_screen_t * _cairo_xcb_screen_from_root (xcb_connection_t *connection, xcb_window_t id) { xcb_screen_iterator_t s; s = xcb_setup_roots_iterator (xcb_get_setup (connection)); for (; s.rem; xcb_screen_next (&s)) { if (s.data->root == id) return s.data; } return NULL; } cairo_surface_t * cairo_xlib_surface_create_for_bitmap (Display *dpy, Pixmap bitmap, Screen *scr, int width, int height) { xcb_connection_t *connection = XGetXCBConnection (dpy); xcb_screen_t *screen = _cairo_xcb_screen_from_root (connection, (xcb_window_t) scr->root); return _cairo_xlib_xcb_surface_create (dpy, scr, NULL, NULL, cairo_xcb_surface_create_for_bitmap (connection, screen, bitmap, width, height)); } #if CAIRO_HAS_XLIB_XRENDER_SURFACE cairo_surface_t * cairo_xlib_surface_create_with_xrender_format (Display *dpy, Drawable drawable, Screen *scr, XRenderPictFormat *format, int width, int height) { xcb_render_pictforminfo_t xcb_format; xcb_connection_t *connection; xcb_screen_t *screen; xcb_format.id = format->id; xcb_format.type = format->type; xcb_format.depth = format->depth; xcb_format.direct.red_shift = format->direct.red; xcb_format.direct.red_mask = format->direct.redMask; xcb_format.direct.green_shift = format->direct.green; xcb_format.direct.green_mask = format->direct.greenMask; xcb_format.direct.blue_shift = format->direct.blue; xcb_format.direct.blue_mask = format->direct.blueMask; xcb_format.direct.alpha_shift = format->direct.alpha; xcb_format.direct.alpha_mask = format->direct.alphaMask; xcb_format.colormap = format->colormap; connection = XGetXCBConnection (dpy); screen = _cairo_xcb_screen_from_root (connection, (xcb_window_t) scr->root); return _cairo_xlib_xcb_surface_create (dpy, scr, NULL, format, cairo_xcb_surface_create_with_xrender_format (connection, screen, drawable, &xcb_format, width, height)); } XRenderPictFormat * cairo_xlib_surface_get_xrender_format (cairo_surface_t *surface) { cairo_xlib_xcb_surface_t *xlib_surface = (cairo_xlib_xcb_surface_t *) surface; /* Throw an error for a non-xlib surface */ if (surface->type != CAIRO_SURFACE_TYPE_XLIB) { _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return NULL; } return xlib_surface->format; } #endif void cairo_xlib_surface_set_size (cairo_surface_t *abstract_surface, int width, int height) { cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface; cairo_status_t status; if (unlikely (abstract_surface->status)) return; if (unlikely (abstract_surface->finished)) { status = _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); return; } if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) { status = _cairo_surface_set_error (abstract_surface, CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return; } cairo_xcb_surface_set_size (&surface->xcb->base, width, height); if (unlikely (surface->xcb->base.status)) { status = _cairo_surface_set_error (abstract_surface, _cairo_error (surface->xcb->base.status)); } } void cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface, Drawable drawable, int width, int height) { cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *)abstract_surface; cairo_status_t status; if (unlikely (abstract_surface->status)) return; if (unlikely (abstract_surface->finished)) { status = _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); return; } if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) { status = _cairo_surface_set_error (abstract_surface, CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return; } cairo_xcb_surface_set_drawable (&surface->xcb->base, drawable, width, height); if (unlikely (surface->xcb->base.status)) { status = _cairo_surface_set_error (abstract_surface, _cairo_error (surface->xcb->base.status)); } } Display * cairo_xlib_surface_get_display (cairo_surface_t *abstract_surface) { cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface; if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) { _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return NULL; } return surface->display; } Drawable cairo_xlib_surface_get_drawable (cairo_surface_t *abstract_surface) { cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface; if (unlikely (abstract_surface->finished)) { _cairo_error_throw (CAIRO_STATUS_SURFACE_FINISHED); return 0; } if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) { _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return 0; } /* This can happen when e.g. create_similar falls back to an image surface * because we don't have the RENDER extension. */ if (surface->xcb->base.type != CAIRO_SURFACE_TYPE_XCB) { _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return 0; } return surface->xcb->drawable; } Screen * cairo_xlib_surface_get_screen (cairo_surface_t *abstract_surface) { cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface; if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) { _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return NULL; } return surface->screen; } Visual * cairo_xlib_surface_get_visual (cairo_surface_t *abstract_surface) { cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface; if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) { _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return NULL; } return surface->visual; } int cairo_xlib_surface_get_depth (cairo_surface_t *abstract_surface) { cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface; if (unlikely (abstract_surface->finished)) { _cairo_error_throw (CAIRO_STATUS_SURFACE_FINISHED); return 0; } if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) { _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return 0; } /* This can happen when e.g. create_similar falls back to an image surface * because we don't have the RENDER extension. */ if (surface->xcb->base.type != CAIRO_SURFACE_TYPE_XCB) { _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return 0; } return surface->xcb->depth; } int cairo_xlib_surface_get_width (cairo_surface_t *abstract_surface) { cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface; if (unlikely (abstract_surface->finished)) { _cairo_error_throw (CAIRO_STATUS_SURFACE_FINISHED); return 0; } if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) { _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return 0; } /* This can happen when e.g. create_similar falls back to an image surface * because we don't have the RENDER extension. */ if (surface->xcb->base.type != CAIRO_SURFACE_TYPE_XCB) { _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return 0; } return surface->xcb->width; } int cairo_xlib_surface_get_height (cairo_surface_t *abstract_surface) { cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface; if (unlikely (abstract_surface->finished)) { _cairo_error_throw (CAIRO_STATUS_SURFACE_FINISHED); return 0; } if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) { _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return 0; } /* This can happen when e.g. create_similar falls back to an image surface * because we don't have the RENDER extension. */ if (surface->xcb->base.type != CAIRO_SURFACE_TYPE_XCB) { _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return 0; } return surface->xcb->height; } void cairo_xlib_device_debug_cap_xrender_version (cairo_device_t *device, int major, int minor) { cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) device; if (device == NULL || device->status) return; if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) return; cairo_xcb_device_debug_cap_xrender_version (display->xcb_device, major, minor); } void cairo_xlib_device_debug_set_precision (cairo_device_t *device, int precision) { cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) device; if (device == NULL || device->status) return; if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) { cairo_status_t status; status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH); (void) status; return; } cairo_xcb_device_debug_set_precision (display->xcb_device, precision); } int cairo_xlib_device_debug_get_precision (cairo_device_t *device) { cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) device; if (device == NULL || device->status) return -1; if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) { cairo_status_t status; status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH); (void) status; return -1; } return cairo_xcb_device_debug_get_precision (display->xcb_device); } #endif /* CAIRO_HAS_XLIB_XCB_FUNCTIONS */