forked from KolibriOS/kolibrios
845 lines
24 KiB
C
845 lines
24 KiB
C
|
/* 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 <cworth@cworth.org>
|
||
|
* Chris Wilson <chris@chris-wilson.co.uk>
|
||
|
*/
|
||
|
|
||
|
#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 <X11/Xlib-xcb.h>
|
||
|
#include <X11/Xlibint.h> /* 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);
|
||
|
|
||
|
/* _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));
|
||
|
}
|
||
|
|
||
|
cairo_surface_t *
|
||
|
cairo_xlib_surface_create_for_bitmap (Display *dpy,
|
||
|
Pixmap bitmap,
|
||
|
Screen *scr,
|
||
|
int width,
|
||
|
int height)
|
||
|
{
|
||
|
return _cairo_xlib_xcb_surface_create (dpy, scr, NULL, NULL,
|
||
|
cairo_xcb_surface_create_for_bitmap (XGetXCBConnection (dpy),
|
||
|
(xcb_screen_t *) scr,
|
||
|
bitmap,
|
||
|
width, height));
|
||
|
}
|
||
|
|
||
|
#if CAIRO_HAS_XLIB_XRENDER_SURFACE
|
||
|
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_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 */
|