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 *
_cairo_xlib_xcb_surface_create_similar(void * abstract_other,cairo_content_t content,int width,int height)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
_cairo_xlib_xcb_surface_finish(void * abstract_surface)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 *
_cairo_xlib_xcb_surface_create_similar_image(void * abstract_other,cairo_format_t format,int width,int height)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_image_surface_t *
_cairo_xlib_xcb_surface_map_to_image(void * abstract_surface,const cairo_rectangle_int_t * extents)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
_cairo_xlib_xcb_surface_unmap(void * abstract_surface,cairo_image_surface_t * image)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     return _cairo_surface_unmap_image (&surface->xcb->base, image);
133 }
134 
135 static cairo_surface_t *
_cairo_xlib_xcb_surface_source(void * abstract_surface,cairo_rectangle_int_t * extents)136 _cairo_xlib_xcb_surface_source (void *abstract_surface,
137 				cairo_rectangle_int_t *extents)
138 {
139     cairo_xlib_xcb_surface_t *surface = abstract_surface;
140     return _cairo_surface_get_source (&surface->xcb->base, extents);
141 }
142 
143 static cairo_status_t
_cairo_xlib_xcb_surface_acquire_source_image(void * abstract_surface,cairo_image_surface_t ** image_out,void ** image_extra)144 _cairo_xlib_xcb_surface_acquire_source_image (void *abstract_surface,
145 					      cairo_image_surface_t **image_out,
146 					      void **image_extra)
147 {
148     cairo_xlib_xcb_surface_t *surface = abstract_surface;
149     return _cairo_surface_acquire_source_image (&surface->xcb->base,
150 						image_out, image_extra);
151 }
152 
153 static void
_cairo_xlib_xcb_surface_release_source_image(void * abstract_surface,cairo_image_surface_t * image_out,void * image_extra)154 _cairo_xlib_xcb_surface_release_source_image (void *abstract_surface,
155 					      cairo_image_surface_t *image_out,
156 					      void *image_extra)
157 {
158     cairo_xlib_xcb_surface_t *surface = abstract_surface;
159     _cairo_surface_release_source_image (&surface->xcb->base, image_out, image_extra);
160 }
161 
162 static cairo_bool_t
_cairo_xlib_xcb_surface_get_extents(void * abstract_surface,cairo_rectangle_int_t * extents)163 _cairo_xlib_xcb_surface_get_extents (void *abstract_surface,
164 				     cairo_rectangle_int_t *extents)
165 {
166     cairo_xlib_xcb_surface_t *surface = abstract_surface;
167     return _cairo_surface_get_extents (&surface->xcb->base, extents);
168 }
169 
170 static void
_cairo_xlib_xcb_surface_get_font_options(void * abstract_surface,cairo_font_options_t * options)171 _cairo_xlib_xcb_surface_get_font_options (void *abstract_surface,
172 					  cairo_font_options_t *options)
173 {
174     cairo_xlib_xcb_surface_t *surface = abstract_surface;
175     cairo_surface_get_font_options (&surface->xcb->base, options);
176 }
177 
178 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)179 _cairo_xlib_xcb_surface_paint (void			*abstract_surface,
180 			       cairo_operator_t		 op,
181 			       const cairo_pattern_t	*source,
182 			       const cairo_clip_t	*clip)
183 {
184     cairo_xlib_xcb_surface_t *surface = abstract_surface;
185     return _cairo_surface_paint (&surface->xcb->base, op, source, clip);
186 }
187 
188 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)189 _cairo_xlib_xcb_surface_mask (void			*abstract_surface,
190 			      cairo_operator_t		 op,
191 			      const cairo_pattern_t	*source,
192 			      const cairo_pattern_t	*mask,
193 			      const cairo_clip_t	*clip)
194 {
195     cairo_xlib_xcb_surface_t *surface = abstract_surface;
196     return _cairo_surface_mask (&surface->xcb->base, op, source, mask, clip);
197 }
198 
199 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)200 _cairo_xlib_xcb_surface_stroke (void				*abstract_surface,
201 				cairo_operator_t		 op,
202 				const cairo_pattern_t		*source,
203 				const cairo_path_fixed_t	*path,
204 				const cairo_stroke_style_t	*style,
205 				const cairo_matrix_t		*ctm,
206 				const cairo_matrix_t		*ctm_inverse,
207 				double				 tolerance,
208 				cairo_antialias_t		 antialias,
209 				const cairo_clip_t		*clip)
210 {
211     cairo_xlib_xcb_surface_t *surface = abstract_surface;
212     return _cairo_surface_stroke (&surface->xcb->base,
213 				  op, source, path, style, ctm, ctm_inverse,
214 				  tolerance, antialias, clip);
215 }
216 
217 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)218 _cairo_xlib_xcb_surface_fill (void			*abstract_surface,
219 			      cairo_operator_t		 op,
220 			      const cairo_pattern_t	*source,
221 			      const cairo_path_fixed_t	*path,
222 			      cairo_fill_rule_t		 fill_rule,
223 			      double			 tolerance,
224 			      cairo_antialias_t		 antialias,
225 			      const cairo_clip_t	*clip)
226 {
227     cairo_xlib_xcb_surface_t *surface = abstract_surface;
228     return _cairo_surface_fill (&surface->xcb->base,
229 				op, source, path,
230 				fill_rule, tolerance,
231 				antialias, clip);
232 }
233 
234 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)235 _cairo_xlib_xcb_surface_glyphs (void			*abstract_surface,
236 				cairo_operator_t	 op,
237 				const cairo_pattern_t	*source,
238 				cairo_glyph_t		*glyphs,
239 				int			 num_glyphs,
240 				cairo_scaled_font_t	*scaled_font,
241 				const cairo_clip_t	*clip)
242 {
243     cairo_xlib_xcb_surface_t *surface = abstract_surface;
244     return _cairo_surface_show_text_glyphs (&surface->xcb->base, op, source,
245 					    NULL, 0,
246 					    glyphs, num_glyphs,
247 					    NULL, 0, 0,
248 					    scaled_font, clip);
249 }
250 
251 static cairo_status_t
_cairo_xlib_xcb_surface_flush(void * abstract_surface,unsigned flags)252 _cairo_xlib_xcb_surface_flush (void *abstract_surface, unsigned flags)
253 {
254     cairo_xlib_xcb_surface_t *surface = abstract_surface;
255     /* We have to call cairo_surface_flush() to make sure snapshots are detached */
256     return _cairo_surface_flush (&surface->xcb->base, flags);
257 }
258 
259 static cairo_status_t
_cairo_xlib_xcb_surface_mark_dirty(void * abstract_surface,int x,int y,int width,int height)260 _cairo_xlib_xcb_surface_mark_dirty (void *abstract_surface,
261 				    int x, int y,
262 				    int width, int height)
263 {
264     cairo_xlib_xcb_surface_t *surface = abstract_surface;
265     cairo_surface_mark_dirty_rectangle (&surface->xcb->base, x, y, width, height);
266     return cairo_surface_status (&surface->xcb->base);
267 }
268 
269 static const cairo_surface_backend_t _cairo_xlib_xcb_surface_backend = {
270     CAIRO_SURFACE_TYPE_XLIB,
271     _cairo_xlib_xcb_surface_finish,
272 
273     _cairo_default_context_create, /* XXX */
274 
275     _cairo_xlib_xcb_surface_create_similar,
276     _cairo_xlib_xcb_surface_create_similar_image,
277     _cairo_xlib_xcb_surface_map_to_image,
278     _cairo_xlib_xcb_surface_unmap,
279 
280     _cairo_xlib_xcb_surface_source,
281     _cairo_xlib_xcb_surface_acquire_source_image,
282     _cairo_xlib_xcb_surface_release_source_image,
283     NULL, /* snapshot */
284 
285     NULL, /* copy_page */
286     NULL, /* show_page */
287 
288     _cairo_xlib_xcb_surface_get_extents,
289     _cairo_xlib_xcb_surface_get_font_options,
290 
291     _cairo_xlib_xcb_surface_flush,
292     _cairo_xlib_xcb_surface_mark_dirty,
293 
294     _cairo_xlib_xcb_surface_paint,
295     _cairo_xlib_xcb_surface_mask,
296     _cairo_xlib_xcb_surface_stroke,
297     _cairo_xlib_xcb_surface_fill,
298     NULL, /* fill_stroke */
299     _cairo_xlib_xcb_surface_glyphs,
300 };
301 
302 static void
_cairo_xlib_xcb_display_finish(void * abstract_display)303 _cairo_xlib_xcb_display_finish (void *abstract_display)
304 {
305     cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) abstract_display;
306 
307     CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
308     cairo_list_del (&display->link);
309     CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
310 
311     cairo_device_destroy (display->xcb_device);
312     display->xcb_device = NULL;
313 
314     XESetCloseDisplay (display->dpy, display->codes->extension, NULL);
315     /* Drop the reference from _cairo_xlib_xcb_device_create */
316     cairo_device_destroy (&display->base);
317 }
318 
319 static int
_cairo_xlib_xcb_close_display(Display * dpy,XExtCodes * codes)320 _cairo_xlib_xcb_close_display(Display *dpy, XExtCodes *codes)
321 {
322     cairo_xlib_xcb_display_t *display;
323 
324     CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
325     cairo_list_foreach_entry (display,
326 			      cairo_xlib_xcb_display_t,
327 			      &displays,
328 			      link)
329     {
330 	if (display->dpy == dpy)
331 	{
332 	    /* _cairo_xlib_xcb_display_finish will lock the mutex again
333 	     * -> deadlock (This mutex isn't recursive) */
334 	    cairo_device_reference (&display->base);
335 	    CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
336 
337 	    /* Make sure the xcb and xlib-xcb devices are finished */
338 	    cairo_device_finish (display->xcb_device);
339 	    cairo_device_finish (&display->base);
340 
341 	    cairo_device_destroy (&display->base);
342 	    return 0;
343 	}
344     }
345     CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
346 
347     return 0;
348 }
349 
350 static const cairo_device_backend_t _cairo_xlib_xcb_device_backend = {
351     CAIRO_DEVICE_TYPE_XLIB,
352 
353     NULL,
354     NULL,
355 
356     NULL, /* flush */
357     _cairo_xlib_xcb_display_finish,
358     free, /* destroy */
359 };
360 
361 static cairo_device_t *
_cairo_xlib_xcb_device_create(Display * dpy,cairo_device_t * xcb_device)362 _cairo_xlib_xcb_device_create (Display *dpy, cairo_device_t *xcb_device)
363 {
364     cairo_xlib_xcb_display_t *display = NULL;
365     cairo_device_t *device;
366 
367     if (xcb_device == NULL)
368 	return NULL;
369 
370     CAIRO_MUTEX_INITIALIZE ();
371 
372     CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
373     if (displays.next == NULL) {
374 	cairo_list_init (&displays);
375     }
376 
377     cairo_list_foreach_entry (display,
378 			      cairo_xlib_xcb_display_t,
379 			      &displays,
380 			      link)
381     {
382 	if (display->dpy == dpy) {
383 	    /* Maintain MRU order. */
384 	    if (displays.next != &display->link)
385 		cairo_list_move (&display->link, &displays);
386 
387 	    /* Grab a reference for our caller */
388 	    device = cairo_device_reference (&display->base);
389 	    assert (display->xcb_device == xcb_device);
390 	    goto unlock;
391 	}
392     }
393 
394     display = _cairo_malloc (sizeof (cairo_xlib_xcb_display_t));
395     if (unlikely (display == NULL)) {
396 	device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
397 	goto unlock;
398     }
399 
400     display->codes = XAddExtension (dpy);
401     if (unlikely (display->codes == NULL)) {
402 	device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
403 	free (display);
404 	goto unlock;
405     }
406 
407     _cairo_device_init (&display->base, &_cairo_xlib_xcb_device_backend);
408 
409     XESetCloseDisplay (dpy, display->codes->extension, _cairo_xlib_xcb_close_display);
410     /* Add a reference for _cairo_xlib_xcb_display_finish. This basically means
411      * that the device's reference count never drops to zero
412      * as long as our Display* is alive. We need this because there is no
413      * "XDelExtension" to undo XAddExtension and having lots of registered
414      * extensions slows down libX11. */
415     cairo_device_reference (&display->base);
416 
417     display->dpy = dpy;
418     display->xcb_device = cairo_device_reference(xcb_device);
419 
420     cairo_list_add (&display->link, &displays);
421     device = &display->base;
422 
423 unlock:
424     CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
425 
426     return device;
427 }
428 
429 static cairo_surface_t *
_cairo_xlib_xcb_surface_create(void * dpy,void * scr,void * visual,void * format,cairo_surface_t * xcb)430 _cairo_xlib_xcb_surface_create (void *dpy,
431 				void *scr,
432 				void *visual,
433 				void *format,
434 				cairo_surface_t *xcb)
435 {
436     cairo_xlib_xcb_surface_t *surface;
437 
438     if (unlikely (xcb->status))
439 	return xcb;
440 
441     surface = _cairo_malloc (sizeof (*surface));
442     if (unlikely (surface == NULL)) {
443 	cairo_surface_destroy (xcb);
444 	return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
445     }
446 
447     _cairo_surface_init (&surface->base,
448 			 &_cairo_xlib_xcb_surface_backend,
449 			 _cairo_xlib_xcb_device_create (dpy, xcb->device),
450 			 xcb->content,
451 			 FALSE); /* is_vector */
452 
453     /* _cairo_surface_init() got another reference to the device, drop ours */
454     cairo_device_destroy (surface->base.device);
455 
456     surface->display = dpy;
457     surface->screen = scr;
458     surface->visual = visual;
459     surface->format = format;
460     surface->xcb = (cairo_xcb_surface_t *) xcb;
461 
462     return &surface->base;
463 }
464 
465 static Screen *
_cairo_xlib_screen_from_visual(Display * dpy,Visual * visual)466 _cairo_xlib_screen_from_visual (Display *dpy, Visual *visual)
467 {
468     int s, d, v;
469 
470     for (s = 0; s < ScreenCount (dpy); s++) {
471 	Screen *screen;
472 
473 	screen = ScreenOfDisplay (dpy, s);
474 	if (visual == DefaultVisualOfScreen (screen))
475 	    return screen;
476 
477 	for (d = 0; d < screen->ndepths; d++) {
478 	    Depth  *depth;
479 
480 	    depth = &screen->depths[d];
481 	    for (v = 0; v < depth->nvisuals; v++)
482 		if (visual == &depth->visuals[v])
483 		    return screen;
484 	}
485     }
486 
487     return NULL;
488 }
489 
490 cairo_surface_t *
cairo_xlib_surface_create(Display * dpy,Drawable drawable,Visual * visual,int width,int height)491 cairo_xlib_surface_create (Display     *dpy,
492 			   Drawable	drawable,
493 			   Visual      *visual,
494 			   int		width,
495 			   int		height)
496 {
497     Screen *scr;
498     xcb_visualtype_t xcb_visual;
499 
500     scr = _cairo_xlib_screen_from_visual (dpy, visual);
501     if (scr == NULL)
502 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
503 
504     xcb_visual.visual_id = visual->visualid;
505 #if defined(__cplusplus) || defined(c_plusplus)
506     xcb_visual._class = visual->c_class;
507 #else
508     xcb_visual._class = visual->class;
509 #endif
510     xcb_visual.bits_per_rgb_value = visual->bits_per_rgb;
511     xcb_visual.colormap_entries = visual->map_entries;
512     xcb_visual.red_mask = visual->red_mask;
513     xcb_visual.green_mask = visual->green_mask;
514     xcb_visual.blue_mask = visual->blue_mask;
515 
516     return _cairo_xlib_xcb_surface_create (dpy, scr, visual, NULL,
517 					   cairo_xcb_surface_create (XGetXCBConnection (dpy),
518 								     drawable,
519 								     &xcb_visual,
520 								     width, height));
521 }
522 
523 static xcb_screen_t *
_cairo_xcb_screen_from_root(xcb_connection_t * connection,xcb_window_t id)524 _cairo_xcb_screen_from_root (xcb_connection_t *connection,
525 			     xcb_window_t id)
526 {
527     xcb_screen_iterator_t s;
528 
529     s = xcb_setup_roots_iterator (xcb_get_setup (connection));
530     for (; s.rem; xcb_screen_next (&s)) {
531 	if (s.data->root == id)
532 	    return s.data;
533     }
534 
535     return NULL;
536 }
537 
538 cairo_surface_t *
cairo_xlib_surface_create_for_bitmap(Display * dpy,Pixmap bitmap,Screen * scr,int width,int height)539 cairo_xlib_surface_create_for_bitmap (Display  *dpy,
540 				      Pixmap	bitmap,
541 				      Screen   *scr,
542 				      int	width,
543 				      int	height)
544 {
545     xcb_connection_t *connection = XGetXCBConnection (dpy);
546     xcb_screen_t *screen = _cairo_xcb_screen_from_root (connection, (xcb_window_t) scr->root);
547     return _cairo_xlib_xcb_surface_create (dpy, scr, NULL, NULL,
548 					   cairo_xcb_surface_create_for_bitmap (connection,
549 										screen,
550 										bitmap,
551 										width, height));
552 }
553 
554 #if CAIRO_HAS_XLIB_XRENDER_SURFACE
555 cairo_surface_t *
cairo_xlib_surface_create_with_xrender_format(Display * dpy,Drawable drawable,Screen * scr,XRenderPictFormat * format,int width,int height)556 cairo_xlib_surface_create_with_xrender_format (Display		    *dpy,
557 					       Drawable		    drawable,
558 					       Screen		    *scr,
559 					       XRenderPictFormat    *format,
560 					       int		    width,
561 					       int		    height)
562 {
563     xcb_render_pictforminfo_t xcb_format;
564     xcb_connection_t *connection;
565     xcb_screen_t *screen;
566 
567     xcb_format.id = format->id;
568     xcb_format.type = format->type;
569     xcb_format.depth = format->depth;
570     xcb_format.direct.red_shift = format->direct.red;
571     xcb_format.direct.red_mask = format->direct.redMask;
572     xcb_format.direct.green_shift = format->direct.green;
573     xcb_format.direct.green_mask = format->direct.greenMask;
574     xcb_format.direct.blue_shift = format->direct.blue;
575     xcb_format.direct.blue_mask = format->direct.blueMask;
576     xcb_format.direct.alpha_shift = format->direct.alpha;
577     xcb_format.direct.alpha_mask = format->direct.alphaMask;
578     xcb_format.colormap = format->colormap;
579 
580     connection = XGetXCBConnection (dpy);
581     screen = _cairo_xcb_screen_from_root (connection, (xcb_window_t) scr->root);
582 
583     return _cairo_xlib_xcb_surface_create (dpy, scr, NULL, format,
584 					   cairo_xcb_surface_create_with_xrender_format (connection, screen,
585 											 drawable,
586 											 &xcb_format,
587 											 width, height));
588 }
589 
590 XRenderPictFormat *
cairo_xlib_surface_get_xrender_format(cairo_surface_t * surface)591 cairo_xlib_surface_get_xrender_format (cairo_surface_t *surface)
592 {
593     cairo_xlib_xcb_surface_t *xlib_surface = (cairo_xlib_xcb_surface_t *) surface;
594 
595     /* Throw an error for a non-xlib surface */
596     if (surface->type != CAIRO_SURFACE_TYPE_XLIB) {
597 	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
598 	return NULL;
599     }
600 
601     return xlib_surface->format;
602 }
603 #endif
604 
605 void
cairo_xlib_surface_set_size(cairo_surface_t * abstract_surface,int width,int height)606 cairo_xlib_surface_set_size (cairo_surface_t *abstract_surface,
607 			     int              width,
608 			     int              height)
609 {
610     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
611     cairo_status_t status;
612 
613     if (unlikely (abstract_surface->status))
614 	return;
615     if (unlikely (abstract_surface->finished)) {
616 	status = _cairo_surface_set_error (abstract_surface,
617 		                           _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
618 	return;
619     }
620 
621     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
622 	status = _cairo_surface_set_error (abstract_surface,
623 		                           CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
624 	return;
625     }
626 
627     cairo_xcb_surface_set_size (&surface->xcb->base, width, height);
628     if (unlikely (surface->xcb->base.status)) {
629 	status = _cairo_surface_set_error (abstract_surface,
630 		                           _cairo_error (surface->xcb->base.status));
631     }
632 }
633 
634 void
cairo_xlib_surface_set_drawable(cairo_surface_t * abstract_surface,Drawable drawable,int width,int height)635 cairo_xlib_surface_set_drawable (cairo_surface_t   *abstract_surface,
636 				 Drawable	    drawable,
637 				 int		    width,
638 				 int		    height)
639 {
640     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *)abstract_surface;
641     cairo_status_t status;
642 
643     if (unlikely (abstract_surface->status))
644 	return;
645     if (unlikely (abstract_surface->finished)) {
646 	status = _cairo_surface_set_error (abstract_surface,
647 		                           _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
648 	return;
649     }
650 
651     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
652 	status = _cairo_surface_set_error (abstract_surface,
653 		                           CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
654 	return;
655     }
656 
657     cairo_xcb_surface_set_drawable (&surface->xcb->base, drawable, width, height);
658     if (unlikely (surface->xcb->base.status)) {
659 	status = _cairo_surface_set_error (abstract_surface,
660 		                           _cairo_error (surface->xcb->base.status));
661     }
662 }
663 
664 Display *
cairo_xlib_surface_get_display(cairo_surface_t * abstract_surface)665 cairo_xlib_surface_get_display (cairo_surface_t *abstract_surface)
666 {
667     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
668 
669     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
670 	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
671 	return NULL;
672     }
673 
674     return surface->display;
675 }
676 
677 Drawable
cairo_xlib_surface_get_drawable(cairo_surface_t * abstract_surface)678 cairo_xlib_surface_get_drawable (cairo_surface_t *abstract_surface)
679 {
680     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
681 
682     if (unlikely (abstract_surface->finished)) {
683 	_cairo_error_throw (CAIRO_STATUS_SURFACE_FINISHED);
684 	return 0;
685     }
686     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
687 	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
688 	return 0;
689     }
690     /* This can happen when e.g. create_similar falls back to an image surface
691      * because we don't have the RENDER extension. */
692     if (surface->xcb->base.type != CAIRO_SURFACE_TYPE_XCB) {
693 	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
694 	return 0;
695     }
696 
697     return surface->xcb->drawable;
698 }
699 
700 Screen *
cairo_xlib_surface_get_screen(cairo_surface_t * abstract_surface)701 cairo_xlib_surface_get_screen (cairo_surface_t *abstract_surface)
702 {
703     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
704 
705     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
706 	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
707 	return NULL;
708     }
709 
710     return surface->screen;
711 }
712 
713 Visual *
cairo_xlib_surface_get_visual(cairo_surface_t * abstract_surface)714 cairo_xlib_surface_get_visual (cairo_surface_t *abstract_surface)
715 {
716     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
717 
718     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
719 	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
720 	return NULL;
721     }
722 
723     return surface->visual;
724 }
725 
726 int
cairo_xlib_surface_get_depth(cairo_surface_t * abstract_surface)727 cairo_xlib_surface_get_depth (cairo_surface_t *abstract_surface)
728 {
729     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
730 
731     if (unlikely (abstract_surface->finished)) {
732 	_cairo_error_throw (CAIRO_STATUS_SURFACE_FINISHED);
733 	return 0;
734     }
735     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
736 	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
737 	return 0;
738     }
739     /* This can happen when e.g. create_similar falls back to an image surface
740      * because we don't have the RENDER extension. */
741     if (surface->xcb->base.type != CAIRO_SURFACE_TYPE_XCB) {
742 	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
743 	return 0;
744     }
745 
746     return surface->xcb->depth;
747 }
748 
749 int
cairo_xlib_surface_get_width(cairo_surface_t * abstract_surface)750 cairo_xlib_surface_get_width (cairo_surface_t *abstract_surface)
751 {
752     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
753 
754     if (unlikely (abstract_surface->finished)) {
755 	_cairo_error_throw (CAIRO_STATUS_SURFACE_FINISHED);
756 	return 0;
757     }
758     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
759 	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
760 	return 0;
761     }
762     /* This can happen when e.g. create_similar falls back to an image surface
763      * because we don't have the RENDER extension. */
764     if (surface->xcb->base.type != CAIRO_SURFACE_TYPE_XCB) {
765 	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
766 	return 0;
767     }
768 
769     return surface->xcb->width;
770 }
771 
772 int
cairo_xlib_surface_get_height(cairo_surface_t * abstract_surface)773 cairo_xlib_surface_get_height (cairo_surface_t *abstract_surface)
774 {
775     cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
776 
777     if (unlikely (abstract_surface->finished)) {
778 	_cairo_error_throw (CAIRO_STATUS_SURFACE_FINISHED);
779 	return 0;
780     }
781     if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
782 	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
783 	return 0;
784     }
785     /* This can happen when e.g. create_similar falls back to an image surface
786      * because we don't have the RENDER extension. */
787     if (surface->xcb->base.type != CAIRO_SURFACE_TYPE_XCB) {
788 	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
789 	return 0;
790     }
791 
792     return surface->xcb->height;
793 }
794 
795 void
cairo_xlib_device_debug_cap_xrender_version(cairo_device_t * device,int major,int minor)796 cairo_xlib_device_debug_cap_xrender_version (cairo_device_t *device,
797 					     int major, int minor)
798 {
799     cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) device;
800 
801     if (device == NULL || device->status)
802 	return;
803 
804     if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB)
805 	return;
806 
807     cairo_xcb_device_debug_cap_xrender_version (display->xcb_device,
808 						major, minor);
809 }
810 
811 void
cairo_xlib_device_debug_set_precision(cairo_device_t * device,int precision)812 cairo_xlib_device_debug_set_precision (cairo_device_t *device,
813 				       int precision)
814 {
815     cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) device;
816 
817     if (device == NULL || device->status)
818 	return;
819     if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) {
820 	cairo_status_t status;
821 
822 	status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
823 	(void) status;
824 	return;
825     }
826 
827     cairo_xcb_device_debug_set_precision (display->xcb_device, precision);
828 }
829 
830 int
cairo_xlib_device_debug_get_precision(cairo_device_t * device)831 cairo_xlib_device_debug_get_precision (cairo_device_t *device)
832 {
833     cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) device;
834 
835     if (device == NULL || device->status)
836 	return -1;
837     if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) {
838 	cairo_status_t status;
839 
840 	status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
841 	(void) status;
842 	return -1;
843     }
844 
845     return cairo_xcb_device_debug_get_precision (display->xcb_device);
846 }
847 
848 #endif /* CAIRO_HAS_XLIB_XCB_FUNCTIONS */
849