Fix bug in _cairo_gl_has_extension
[platform/core/graphics/cairo.git] / src / cairo-xlib-surface-shm.c
1 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2 /* cairo - a vector graphics library with display and print output
3  *
4  * Copyright © 2012 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  *      Chris Wilson <chris@chris-wilson.co.uk>
36  */
37
38 #include "cairoint.h"
39
40 #if !CAIRO_HAS_XLIB_XCB_FUNCTIONS
41
42 #include "cairo-xlib-private.h"
43 #include "cairo-xlib-surface-private.h"
44
45 #if !HAVE_X11_EXTENSIONS_XSHM_H || !(HAVE_X11_EXTENSIONS_SHMPROTO_H || HAVE_X11_EXTENSIONS_SHMSTR_H)
46 void _cairo_xlib_display_init_shm (cairo_xlib_display_t *display) {}
47
48 cairo_surface_t *
49 _cairo_xlib_surface_get_shm (cairo_xlib_surface_t *surface,
50                              cairo_bool_t overwrite)
51 {
52     return NULL;
53 }
54
55 cairo_int_status_t
56 _cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface)
57 {
58     assert (!surface->fallback);
59     return CAIRO_INT_STATUS_SUCCESS;
60 }
61
62 cairo_surface_t *
63 _cairo_xlib_surface_create_shm (cairo_xlib_surface_t *other,
64                                 pixman_format_code_t format,
65                                 int width, int height)
66 {
67     return NULL;
68 }
69
70 cairo_surface_t *
71 _cairo_xlib_surface_create_shm__image (cairo_xlib_surface_t *surface,
72                                        pixman_format_code_t format,
73                                        int width, int height)
74 {
75     return NULL;
76 }
77
78 cairo_surface_t *
79 _cairo_xlib_surface_create_similar_shm (void *other,
80                                         cairo_format_t format,
81                                         int width, int height)
82 {
83     return cairo_image_surface_create (format, width, height);
84 }
85
86 void
87 _cairo_xlib_shm_surface_mark_active (cairo_surface_t *_shm)
88 {
89     ASSERT_NOT_REACHED;
90 }
91
92 void
93 _cairo_xlib_shm_surface_get_ximage (cairo_surface_t *surface,
94                                     XImage *ximage)
95 {
96     ASSERT_NOT_REACHED;
97 }
98
99 void *
100 _cairo_xlib_shm_surface_get_obdata (cairo_surface_t *surface)
101 {
102     ASSERT_NOT_REACHED;
103     return NULL;
104 }
105
106 Pixmap
107 _cairo_xlib_shm_surface_get_pixmap (cairo_surface_t *surface)
108 {
109     ASSERT_NOT_REACHED;
110     return 0;
111 }
112
113 XRenderPictFormat *
114 _cairo_xlib_shm_surface_get_xrender_format (cairo_surface_t *surface)
115 {
116     ASSERT_NOT_REACHED;
117     return NULL;
118 }
119
120 cairo_bool_t
121 _cairo_xlib_shm_surface_is_active (cairo_surface_t *surface)
122 {
123     ASSERT_NOT_REACHED;
124     return FALSE;
125 }
126
127 cairo_bool_t
128 _cairo_xlib_shm_surface_is_idle (cairo_surface_t *surface)
129 {
130     ASSERT_NOT_REACHED;
131     return TRUE;
132 }
133
134 void _cairo_xlib_display_fini_shm (cairo_xlib_display_t *display) {}
135
136 #else
137
138 #include "cairo-damage-private.h"
139 #include "cairo-default-context-private.h"
140 #include "cairo-image-surface-private.h"
141 #include "cairo-list-inline.h"
142 #include "cairo-mempool-private.h"
143
144 #include <X11/Xlibint.h>
145 #include <X11/Xproto.h>
146 #include <X11/extensions/XShm.h>
147 #if HAVE_X11_EXTENSIONS_SHMPROTO_H
148 #include <X11/extensions/shmproto.h>
149 #elif HAVE_X11_EXTENSIONS_SHMSTR_H
150 #include <X11/extensions/shmstr.h>
151 #endif
152 #include <sys/ipc.h>
153 #include <sys/shm.h>
154
155 #define MIN_PIXMAP_SIZE 4096
156
157 #define MIN_BITS 8
158 #define MIN_SIZE (1<<(MIN_BITS-1))
159
160 typedef struct _cairo_xlib_shm cairo_xlib_shm_t;
161 typedef struct _cairo_xlib_shm_info cairo_xlib_shm_info_t;
162 typedef struct _cairo_xlib_shm_surface cairo_xlib_shm_surface_t;
163
164 struct _cairo_xlib_shm {
165     cairo_mempool_t mem;
166
167     XShmSegmentInfo shm;
168     unsigned long attached;
169     cairo_list_t link;
170 };
171
172 struct _cairo_xlib_shm_info {
173     unsigned long last_request;
174     void *mem;
175     size_t size;
176     cairo_xlib_shm_t *pool;
177 };
178
179 struct _cairo_xlib_shm_surface {
180     cairo_image_surface_t image;
181
182     cairo_list_t link;
183     cairo_xlib_shm_info_t *info;
184     Pixmap pixmap;
185     unsigned long active;
186     int idle;
187 };
188
189 /* the parent is always given by index/2 */
190 #define PQ_PARENT_INDEX(i) ((i) >> 1)
191 #define PQ_FIRST_ENTRY 1
192
193 /* left and right children are index * 2 and (index * 2) +1 respectively */
194 #define PQ_LEFT_CHILD_INDEX(i) ((i) << 1)
195
196 #define PQ_TOP(pq) ((pq)->elements[PQ_FIRST_ENTRY])
197
198 struct pqueue {
199     int size, max_size;
200     cairo_xlib_shm_info_t **elements;
201 };
202
203 struct _cairo_xlib_shm_display {
204     int has_pixmaps;
205     int opcode;
206     int event;
207
208     Window window;
209     unsigned long last_request;
210     unsigned long last_event;
211
212     cairo_list_t surfaces;
213
214     cairo_list_t pool;
215     struct pqueue info;
216 };
217
218 static inline cairo_bool_t
219 seqno_passed (unsigned long a, unsigned long b)
220 {
221     return (long)(b - a) >= 0;
222 }
223
224 static inline cairo_bool_t
225 seqno_before (unsigned long a, unsigned long b)
226 {
227     return (long)(b - a) > 0;
228 }
229
230 static inline cairo_bool_t
231 seqno_after (unsigned long a, unsigned long b)
232 {
233     return (long)(a - b) > 0;
234 }
235
236 static inline cairo_status_t
237 _pqueue_init (struct pqueue *pq)
238 {
239     pq->max_size = 32;
240     pq->size = 0;
241
242     pq->elements = _cairo_malloc_ab (pq->max_size,
243                                      sizeof (cairo_xlib_shm_info_t *));
244     if (unlikely (pq->elements == NULL))
245         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
246
247     PQ_TOP(pq) = NULL;
248     return CAIRO_STATUS_SUCCESS;
249 }
250
251 static inline void
252 _pqueue_fini (struct pqueue *pq)
253 {
254     free (pq->elements);
255 }
256
257 static cairo_status_t
258 _pqueue_grow (struct pqueue *pq)
259 {
260     cairo_xlib_shm_info_t **new_elements;
261
262     new_elements = _cairo_realloc_ab (pq->elements,
263                                       2 * pq->max_size,
264                                       sizeof (cairo_xlib_shm_info_t *));
265     if (unlikely (new_elements == NULL))
266         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
267
268     pq->elements = new_elements;
269     pq->max_size *= 2;
270     return CAIRO_STATUS_SUCCESS;
271 }
272
273 static void
274 _pqueue_shrink (struct pqueue *pq, int min_size)
275 {
276     cairo_xlib_shm_info_t **new_elements;
277
278     if (min_size > pq->max_size)
279         return;
280
281     new_elements = _cairo_realloc_ab (pq->elements,
282                                       min_size,
283                                       sizeof (cairo_xlib_shm_info_t *));
284     if (unlikely (new_elements == NULL))
285         return;
286
287     pq->elements = new_elements;
288     pq->max_size = min_size;
289 }
290
291 static inline cairo_status_t
292 _pqueue_push (struct pqueue *pq, cairo_xlib_shm_info_t *info)
293 {
294     cairo_xlib_shm_info_t **elements;
295     int i, parent;
296
297     if (unlikely (pq->size + 1 == pq->max_size)) {
298         cairo_status_t status;
299
300         status = _pqueue_grow (pq);
301         if (unlikely (status))
302             return status;
303     }
304
305     elements = pq->elements;
306
307     for (i = ++pq->size;
308          i != PQ_FIRST_ENTRY &&
309          info->last_request < elements[parent = PQ_PARENT_INDEX (i)]->last_request;
310          i = parent)
311     {
312         elements[i] = elements[parent];
313     }
314
315     elements[i] = info;
316
317     return CAIRO_STATUS_SUCCESS;
318 }
319
320 static inline void
321 _pqueue_pop (struct pqueue *pq)
322 {
323     cairo_xlib_shm_info_t **elements = pq->elements;
324     cairo_xlib_shm_info_t *tail;
325     int child, i;
326
327     tail = elements[pq->size--];
328     if (pq->size == 0) {
329         elements[PQ_FIRST_ENTRY] = NULL;
330         _pqueue_shrink (pq, 32);
331         return;
332     }
333
334     for (i = PQ_FIRST_ENTRY;
335          (child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size;
336          i = child)
337     {
338         if (child != pq->size &&
339             elements[child+1]->last_request < elements[child]->last_request)
340         {
341             child++;
342         }
343
344         if (elements[child]->last_request >= tail->last_request)
345             break;
346
347         elements[i] = elements[child];
348     }
349     elements[i] = tail;
350 }
351
352 static cairo_bool_t _x_error_occurred;
353
354 static int
355 _check_error_handler (Display     *display,
356                      XErrorEvent *event)
357 {
358     _x_error_occurred = TRUE;
359     return False; /* ignored */
360 }
361
362 static cairo_bool_t
363 can_use_shm (Display *dpy, int *has_pixmap)
364 {
365     XShmSegmentInfo shm;
366     int (*old_handler) (Display *display, XErrorEvent *event);
367     Status success;
368     int major, minor;
369
370     if (! XShmQueryExtension (dpy))
371         return FALSE;
372
373     XShmQueryVersion (dpy, &major, &minor, has_pixmap);
374
375     shm.shmid = shmget (IPC_PRIVATE, 0x1000, IPC_CREAT | 0600);
376     if (shm.shmid == -1)
377         return FALSE;
378
379     shm.readOnly = FALSE;
380     shm.shmaddr = shmat (shm.shmid, NULL, 0);
381     if (shm.shmaddr == (char *) -1) {
382         shmctl (shm.shmid, IPC_RMID, NULL);
383         return FALSE;
384     }
385
386     assert (CAIRO_MUTEX_IS_LOCKED (_cairo_xlib_display_mutex));
387     _x_error_occurred = FALSE;
388
389     XLockDisplay (dpy);
390     XSync (dpy, False);
391     old_handler = XSetErrorHandler (_check_error_handler);
392
393     success = XShmAttach (dpy, &shm);
394     if (success)
395         XShmDetach (dpy, &shm);
396
397     XSync (dpy, False);
398     XSetErrorHandler (old_handler);
399     XUnlockDisplay (dpy);
400
401     shmctl (shm.shmid, IPC_RMID, NULL);
402     shmdt (shm.shmaddr);
403
404     return success && ! _x_error_occurred;
405 }
406
407 static inline Display *
408 peek_display (cairo_device_t *device)
409 {
410     return ((cairo_xlib_display_t *)device)->display;
411 }
412
413 static inline unsigned long
414 peek_processed (cairo_device_t *device)
415 {
416     return LastKnownRequestProcessed (peek_display(device));
417 }
418
419 static void
420 _cairo_xlib_display_shm_pool_destroy (cairo_xlib_display_t *display,
421                                       cairo_xlib_shm_t *pool)
422 {
423     shmdt (pool->shm.shmaddr);
424     if (display->display) /* may be called after CloseDisplay */
425         XShmDetach (display->display, &pool->shm);
426
427     _cairo_mempool_fini (&pool->mem);
428
429     cairo_list_del (&pool->link);
430     free (pool);
431 }
432
433 static void send_event(cairo_xlib_display_t *display,
434                        cairo_xlib_shm_info_t *info,
435                        unsigned long seqno)
436 {
437     XShmCompletionEvent ev;
438
439     if (! seqno_after (seqno, display->shm->last_event))
440         return;
441
442     ev.type = display->shm->event;
443     ev.send_event = 1; /* XXX or lie? */
444     ev.serial = NextRequest (display->display);
445     ev.drawable = display->shm->window;
446     ev.major_code = display->shm->opcode;
447     ev.minor_code = X_ShmPutImage;
448     ev.shmseg = info->pool->shm.shmid;
449     ev.offset = (char *)info->mem - (char *)info->pool->shm.shmaddr;
450
451     XSendEvent (display->display, ev.drawable, False, 0, (XEvent *)&ev);
452
453     display->shm->last_event = ev.serial;
454 }
455
456 static void _cairo_xlib_display_sync (cairo_xlib_display_t *display)
457 {
458     cairo_xlib_shm_info_t *info;
459     struct pqueue *pq = &display->shm->info;
460
461     XSync (display->display, False);
462
463     while ((info = PQ_TOP(pq))) {
464         _cairo_mempool_free (&info->pool->mem, info->mem);
465         _pqueue_pop (&display->shm->info);
466         free (info);
467     }
468 }
469
470 static void
471 _cairo_xlib_shm_info_cleanup (cairo_xlib_display_t *display)
472 {
473     cairo_xlib_shm_info_t *info;
474     Display *dpy = display->display;
475     struct pqueue *pq = &display->shm->info;
476     unsigned long processed;
477
478     if (PQ_TOP(pq) == NULL)
479         return;
480
481     XEventsQueued (dpy, QueuedAfterReading);
482     processed = LastKnownRequestProcessed (dpy);
483
484     info = PQ_TOP(pq);
485     do {
486         if (! seqno_passed (info->last_request, processed)) {
487             send_event (display, info, display->shm->last_request);
488             return;
489         }
490
491         _cairo_mempool_free (&info->pool->mem, info->mem);
492         _pqueue_pop (&display->shm->info);
493         free (info);
494     } while ((info = PQ_TOP(pq)));
495 }
496
497 static cairo_xlib_shm_t *
498 _cairo_xlib_shm_info_find (cairo_xlib_display_t *display, size_t size,
499                            void **ptr, unsigned long *last_request)
500 {
501     cairo_xlib_shm_info_t *info;
502     struct pqueue *pq = &display->shm->info;
503
504     if (PQ_TOP(pq) == NULL)
505         return NULL;
506
507     info = PQ_TOP(pq);
508     do {
509         cairo_xlib_shm_t *pool = info->pool;
510
511         *last_request = info->last_request;
512
513         _pqueue_pop (&display->shm->info);
514         _cairo_mempool_free (&pool->mem, info->mem);
515         free (info);
516
517         if (pool->mem.free_bytes >= size) {
518             void *mem = _cairo_mempool_alloc (&pool->mem, size);
519             if (mem != NULL) {
520                 *ptr = mem;
521                 return pool;
522             }
523         }
524     } while ((info = PQ_TOP(pq)));
525
526     return NULL;
527 }
528
529 static cairo_xlib_shm_t *
530 _cairo_xlib_shm_pool_find (cairo_xlib_display_t *display,
531                            size_t size,
532                            void **ptr)
533 {
534     cairo_xlib_shm_t *pool;
535
536     cairo_list_foreach_entry (pool, cairo_xlib_shm_t, &display->shm->pool, link) {
537         if (pool->mem.free_bytes >= size) {
538             void *mem = _cairo_mempool_alloc (&pool->mem, size);
539             if (mem != NULL) {
540                 *ptr = mem;
541                 return pool;
542             }
543         }
544     }
545
546     return NULL;
547 }
548
549 static void
550 _cairo_xlib_shm_pool_cleanup (cairo_xlib_display_t *display)
551 {
552     cairo_xlib_shm_t *pool, *next;
553     unsigned long processed;
554
555     processed = LastKnownRequestProcessed (display->display);
556
557     cairo_list_foreach_entry_safe (pool, next, cairo_xlib_shm_t,
558                                    &display->shm->pool, link) {
559         if (! seqno_passed (pool->attached, processed))
560             break;
561
562         if (pool->mem.free_bytes == pool->mem.max_bytes)
563             _cairo_xlib_display_shm_pool_destroy (display, pool);
564     }
565 }
566
567 static cairo_xlib_shm_t *
568 _cairo_xlib_shm_pool_create(cairo_xlib_display_t *display,
569                             size_t size, void **ptr)
570 {
571     Display *dpy = display->display;
572     cairo_xlib_shm_t *pool;
573     size_t bytes, maxbits = 16, minbits = MIN_BITS;
574     Status success;
575
576     pool = malloc (sizeof (cairo_xlib_shm_t));
577     if (pool == NULL)
578         return NULL;
579
580     bytes = 1 << maxbits;
581     while (bytes <= size)
582         bytes <<= 1, maxbits++;
583     bytes <<= 3;
584
585     minbits += (maxbits - 16) / 2;
586
587     pool->shm.shmid = shmget (IPC_PRIVATE, bytes, IPC_CREAT | 0600);
588     while (pool->shm.shmid == -1 && bytes >= 2*size) {
589         bytes >>= 1;
590         pool->shm.shmid = shmget (IPC_PRIVATE, bytes, IPC_CREAT | 0600);
591     }
592     if (pool->shm.shmid == -1)
593         goto cleanup;
594
595     pool->shm.readOnly = FALSE;
596     pool->shm.shmaddr = shmat (pool->shm.shmid, NULL, 0);
597     if (pool->shm.shmaddr == (char *) -1) {
598         shmctl (pool->shm.shmid, IPC_RMID, NULL);
599         goto cleanup;
600     }
601
602     pool->attached = NextRequest (dpy);
603     success = XShmAttach (dpy, &pool->shm);
604 #if !IPC_RMID_DEFERRED_RELEASE
605     XSync (dpy, FALSE);
606 #endif
607     shmctl (pool->shm.shmid, IPC_RMID, NULL);
608
609     if (! success)
610         goto cleanup_shm;
611
612     if (_cairo_mempool_init (&pool->mem, pool->shm.shmaddr, bytes,
613                              minbits, maxbits - minbits + 1))
614         goto cleanup_detach;
615
616     cairo_list_add (&pool->link, &display->shm->pool);
617
618     *ptr = _cairo_mempool_alloc (&pool->mem, size);
619     assert (*ptr != NULL);
620     return pool;
621
622 cleanup_detach:
623     XShmDetach (dpy, &pool->shm);
624 cleanup_shm:
625     shmdt (pool->shm.shmaddr);
626 cleanup:
627     free (pool);
628     return NULL;
629 }
630
631 static cairo_xlib_shm_info_t *
632 _cairo_xlib_shm_info_create (cairo_xlib_display_t *display,
633                              size_t size, cairo_bool_t will_sync)
634 {
635     cairo_xlib_shm_info_t *info;
636     cairo_xlib_shm_t *pool;
637     unsigned long last_request = 0;
638     void *mem = NULL;
639
640     _cairo_xlib_shm_info_cleanup (display);
641     pool = _cairo_xlib_shm_pool_find (display, size, &mem);
642     _cairo_xlib_shm_pool_cleanup (display);
643
644     if (pool == NULL && will_sync)
645         pool = _cairo_xlib_shm_info_find (display, size, &mem, &last_request);
646     if (pool == NULL)
647         pool = _cairo_xlib_shm_pool_create (display, size, &mem);
648     if (pool == NULL)
649         return NULL;
650
651     assert (mem != NULL);
652
653     info = malloc (sizeof (*info));
654     if (info == NULL) {
655         _cairo_mempool_free (&pool->mem, mem);
656         return NULL;
657     }
658
659     info->pool = pool;
660     info->mem = mem;
661     info->size = size;
662     info->last_request = last_request;
663
664     return info;
665 }
666
667 static cairo_status_t
668 _cairo_xlib_shm_surface_flush (void *abstract_surface, unsigned flags)
669 {
670     cairo_xlib_shm_surface_t *shm = abstract_surface;
671     cairo_xlib_display_t *display;
672     Display *dpy;
673     _XQEvent *qev;
674     cairo_status_t status;
675
676     if (shm->active == 0)
677         return CAIRO_STATUS_SUCCESS;
678
679     if (shm->image.base._finishing)
680         return CAIRO_STATUS_SUCCESS;
681
682     if (seqno_passed (shm->active, peek_processed (shm->image.base.device))) {
683         shm->active = 0;
684         return CAIRO_STATUS_SUCCESS;
685     }
686
687     status = _cairo_xlib_display_acquire (shm->image.base.device, &display);
688     if (unlikely (status))
689         return status;
690
691     send_event (display, shm->info, shm->active);
692
693     dpy = display->display;
694     XEventsQueued (dpy, QueuedAfterReading);
695     while (! seqno_passed (shm->active, LastKnownRequestProcessed (dpy))) {
696         LockDisplay(dpy);
697         _XReadEvents(dpy);
698         while (dpy->head) {
699             qev = dpy->head;
700             _XDeq (dpy, NULL, qev);
701         }
702         UnlockDisplay(dpy);
703     }
704
705     cairo_device_release (&display->base);
706     shm->active = 0;
707
708     return CAIRO_STATUS_SUCCESS;
709 }
710
711 static inline cairo_bool_t
712 active (cairo_xlib_shm_surface_t *shm, Display *dpy)
713 {
714     return (shm->active &&
715             ! seqno_passed (shm->active, LastKnownRequestProcessed (dpy)));
716 }
717
718 static cairo_status_t
719 _cairo_xlib_shm_surface_finish (void *abstract_surface)
720 {
721     cairo_xlib_shm_surface_t *shm = abstract_surface;
722     cairo_xlib_display_t *display;
723     cairo_status_t status;
724
725     if (shm->image.base.damage) {
726         _cairo_damage_destroy (shm->image.base.damage);
727         shm->image.base.damage = _cairo_damage_create_in_error (CAIRO_STATUS_SURFACE_FINISHED);
728     }
729
730     status = _cairo_xlib_display_acquire (shm->image.base.device, &display);
731     if (unlikely (status))
732         return status;
733
734     if (shm->pixmap)
735         XFreePixmap (display->display, shm->pixmap);
736
737     if (active (shm, display->display)) {
738         shm->info->last_request = shm->active;
739         _pqueue_push (&display->shm->info, shm->info);
740         if (seqno_before (display->shm->last_request, shm->active))
741             display->shm->last_request = shm->active;
742     } else {
743         _cairo_mempool_free (&shm->info->pool->mem, shm->info->mem);
744         free (shm->info);
745
746         _cairo_xlib_shm_pool_cleanup (display);
747     }
748
749     cairo_list_del (&shm->link);
750
751     cairo_device_release (&display->base);
752     return _cairo_image_surface_finish (abstract_surface);
753 }
754
755 static const cairo_surface_backend_t cairo_xlib_shm_surface_backend = {
756     CAIRO_SURFACE_TYPE_IMAGE,
757     _cairo_xlib_shm_surface_finish,
758
759     _cairo_default_context_create,
760
761     _cairo_image_surface_create_similar,
762     NULL, /* create similar image */
763     _cairo_image_surface_map_to_image,
764     _cairo_image_surface_unmap_image,
765
766     _cairo_image_surface_source,
767     _cairo_image_surface_acquire_source_image,
768     _cairo_image_surface_release_source_image,
769     _cairo_image_surface_snapshot,
770
771     NULL, /* copy_page */
772     NULL, /* show_page */
773
774     _cairo_image_surface_get_extents,
775     _cairo_image_surface_get_font_options,
776
777     _cairo_xlib_shm_surface_flush,
778     NULL,
779
780     _cairo_image_surface_paint,
781     _cairo_image_surface_mask,
782     _cairo_image_surface_stroke,
783     _cairo_image_surface_fill,
784     NULL, /* fill-stroke */
785     _cairo_image_surface_glyphs,
786 };
787
788 static cairo_bool_t
789 has_shm (cairo_xlib_surface_t *surface)
790 {
791     cairo_xlib_display_t *display = (cairo_xlib_display_t *)surface->base.device;
792     return display->shm != NULL;
793 }
794
795 static int
796 has_shm_pixmaps (cairo_xlib_surface_t *surface)
797 {
798     cairo_xlib_display_t *display = (cairo_xlib_display_t *)surface->base.device;
799     if (!display->shm)
800         return 0;
801
802     return display->shm->has_pixmaps;
803 }
804
805 static cairo_xlib_shm_surface_t *
806 _cairo_xlib_shm_surface_create (cairo_xlib_surface_t *other,
807                                 pixman_format_code_t format,
808                                 int width, int height,
809                                 cairo_bool_t will_sync,
810                                 int create_pixmap)
811 {
812     cairo_xlib_shm_surface_t *shm;
813     cairo_xlib_display_t *display;
814     pixman_image_t *image;
815     int stride, size;
816
817     stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP(format));
818     size = stride * height;
819     if (size < MIN_SIZE)
820         return NULL;
821
822     shm = malloc (sizeof (*shm));
823     if (unlikely (shm == NULL))
824         return (cairo_xlib_shm_surface_t *)_cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
825
826     _cairo_surface_init (&shm->image.base,
827                          &cairo_xlib_shm_surface_backend,
828                          other->base.device,
829                          _cairo_content_from_pixman_format (format));
830
831     if (_cairo_xlib_display_acquire (other->base.device, &display))
832         goto cleanup_shm;
833
834     shm->info = _cairo_xlib_shm_info_create (display, size, will_sync);
835     if (shm->info == NULL)
836         goto cleanup_display;
837
838     image = pixman_image_create_bits (format, width, height,
839                                       (uint32_t *) shm->info->mem, stride);
840     if (image == NULL)
841         goto cleanup_info;
842
843     _cairo_image_surface_init (&shm->image, image, format);
844
845     shm->pixmap = 0;
846     if (create_pixmap && size >= create_pixmap) {
847         shm->pixmap = XShmCreatePixmap (display->display,
848                                         other->drawable,
849                                         shm->info->mem,
850                                         &shm->info->pool->shm,
851                                         shm->image.width,
852                                         shm->image.height,
853                                         shm->image.depth);
854     }
855     shm->active = shm->info->last_request;
856     shm->idle = -5;
857
858     assert (shm->active == 0 || will_sync);
859
860     cairo_list_add (&shm->link, &display->shm->surfaces);
861
862     cairo_device_release (&display->base);
863
864     return shm;
865
866 cleanup_info:
867     _cairo_mempool_free (&shm->info->pool->mem, shm->info->mem);
868     free(shm->info);
869 cleanup_display:
870     cairo_device_release (&display->base);
871 cleanup_shm:
872     free (shm);
873     return NULL;
874 }
875
876 static void
877 _cairo_xlib_surface_update_shm (cairo_xlib_surface_t *surface)
878 {
879     cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface->shm;
880     cairo_xlib_display_t *display;
881     cairo_damage_t *damage;
882     GC gc;
883
884     damage = _cairo_damage_reduce (surface->base.damage);
885     surface->base.damage = _cairo_damage_create();
886
887     if (_cairo_xlib_display_acquire (surface->base.device, &display))
888         goto cleanup_damage;
889
890     if (_cairo_xlib_surface_get_gc (display, surface, &gc))
891         goto cleanup_display;
892
893     if (! surface->owns_pixmap) {
894         XGCValues gcv;
895
896         gcv.subwindow_mode = IncludeInferiors;
897         XChangeGC (display->display, gc, GCSubwindowMode, &gcv);
898     }
899
900     if (damage->region) {
901         XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
902         XRectangle *rects = stack_rects;
903         cairo_rectangle_int_t r;
904         int n_rects, i;
905
906         n_rects = cairo_region_num_rectangles (damage->region);
907         if (n_rects == 0) {
908         } else if (n_rects == 1) {
909             cairo_region_get_rectangle (damage->region, 0, &r);
910             XCopyArea (display->display,
911                        surface->drawable, shm->pixmap, gc,
912                        r.x, r.y,
913                        r.width, r.height,
914                        r.x, r.y);
915         } else {
916             if (n_rects > ARRAY_LENGTH (stack_rects)) {
917                 rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
918                 if (unlikely (rects == NULL)) {
919                     rects = stack_rects;
920                     n_rects = ARRAY_LENGTH (stack_rects);
921                 }
922             }
923             for (i = 0; i < n_rects; i++) {
924                 cairo_region_get_rectangle (damage->region, i, &r);
925
926                 rects[i].x = r.x;
927                 rects[i].y = r.y;
928                 rects[i].width  = r.width;
929                 rects[i].height = r.height;
930             }
931             XSetClipRectangles (display->display, gc, 0, 0, rects, i, YXBanded);
932
933             XCopyArea (display->display,
934                        surface->drawable, shm->pixmap, gc,
935                        0, 0,
936                        shm->image.width, shm->image.height,
937                        0, 0);
938
939             if (damage->status == CAIRO_STATUS_SUCCESS && damage->region)
940                 XSetClipMask (display->display, gc, None);
941         }
942     } else {
943         XCopyArea (display->display,
944                    surface->drawable, shm->pixmap, gc,
945                    0, 0,
946                    shm->image.width, shm->image.height,
947                    0, 0);
948     }
949
950     if (! surface->owns_pixmap) {
951         XGCValues gcv;
952
953         gcv.subwindow_mode = ClipByChildren;
954         XChangeGC (display->display, gc, GCSubwindowMode, &gcv);
955     }
956
957     _cairo_xlib_display_sync (display);
958     shm->active = 0;
959     shm->idle--;
960
961     _cairo_xlib_surface_put_gc (display, surface, gc);
962 cleanup_display:
963     cairo_device_release (&display->base);
964 cleanup_damage:
965     _cairo_damage_destroy (damage);
966 }
967
968 static void
969 _cairo_xlib_surface_clear_shm (cairo_xlib_surface_t *surface)
970 {
971     cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface->shm;
972
973     assert (shm->active == 0);
974
975     _cairo_damage_destroy (surface->base.damage);
976     surface->base.damage = _cairo_damage_create();
977
978     memset (shm->image.data, 0, shm->image.stride * shm->image.height);
979     shm->image.base.is_clear = TRUE;
980 }
981
982 static void inc_idle (cairo_surface_t *surface)
983 {
984     cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface;
985     shm->idle++;
986 }
987
988 static void dec_idle (cairo_surface_t *surface)
989 {
990     cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface;
991     shm->idle--;
992 }
993
994 cairo_surface_t *
995 _cairo_xlib_surface_get_shm (cairo_xlib_surface_t *surface,
996                              cairo_bool_t overwrite)
997 {
998     if (surface->fallback) {
999         assert (surface->base.damage);
1000         assert (surface->shm);
1001         assert (surface->shm->damage);
1002         goto done;
1003     }
1004
1005     if (surface->shm == NULL) {
1006         pixman_format_code_t pixman_format;
1007         cairo_bool_t will_sync;
1008
1009         if (! has_shm_pixmaps (surface))
1010             return NULL;
1011
1012         if ((surface->width | surface->height) < 32)
1013             return NULL;
1014
1015         pixman_format = _pixman_format_for_xlib_surface (surface);
1016         if (pixman_format == 0)
1017             return NULL;
1018
1019         will_sync = !surface->base.is_clear && !overwrite;
1020
1021         surface->shm =
1022             &_cairo_xlib_shm_surface_create (surface, pixman_format,
1023                                              surface->width, surface->height,
1024                                              will_sync, 1)->image.base;
1025         if (surface->shm == NULL)
1026             return NULL;
1027
1028         assert (surface->base.damage == NULL);
1029         if (surface->base.serial || !surface->owns_pixmap) {
1030             cairo_rectangle_int_t rect;
1031
1032             rect.x = rect.y = 0;
1033             rect.width = surface->width;
1034             rect.height = surface->height;
1035
1036             surface->base.damage =
1037                 _cairo_damage_add_rectangle (NULL, &rect);
1038         } else
1039             surface->base.damage = _cairo_damage_create ();
1040
1041         surface->shm->damage = _cairo_damage_create ();
1042     }
1043
1044     if (overwrite) {
1045         _cairo_damage_destroy (surface->base.damage);
1046         surface->base.damage = _cairo_damage_create ();
1047     }
1048
1049     if (!surface->base.is_clear && surface->base.damage->dirty)
1050         _cairo_xlib_surface_update_shm (surface);
1051
1052     _cairo_xlib_shm_surface_flush (surface->shm, 1);
1053
1054     if (surface->base.is_clear && surface->base.damage->dirty)
1055         _cairo_xlib_surface_clear_shm (surface);
1056
1057 done:
1058     dec_idle(surface->shm);
1059     return surface->shm;
1060 }
1061
1062 cairo_int_status_t
1063 _cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface)
1064 {
1065     cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
1066
1067     if (!surface->fallback) {
1068         if (surface->shm)
1069             inc_idle (surface->shm);
1070         return CAIRO_INT_STATUS_SUCCESS;
1071     }
1072
1073     if (surface->shm->damage->dirty) {
1074         cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface->shm;
1075         cairo_xlib_display_t *display;
1076         cairo_damage_t *damage;
1077         GC gc;
1078
1079         status = _cairo_xlib_display_acquire (surface->base.device, &display);
1080         if (unlikely (status))
1081             return status;
1082
1083         damage = _cairo_damage_reduce (shm->image.base.damage);
1084         shm->image.base.damage = _cairo_damage_create ();
1085
1086         TRACE ((stderr, "%s: flushing damage x %d\n", __FUNCTION__,
1087                 damage->region ? cairo_region_num_rectangles (damage->region) : 0));
1088         if (damage->status == CAIRO_STATUS_SUCCESS && damage->region) {
1089             XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
1090             XRectangle *rects = stack_rects;
1091             cairo_rectangle_int_t r;
1092             int n_rects, i;
1093
1094             n_rects = cairo_region_num_rectangles (damage->region);
1095             if (n_rects == 0)
1096                 goto out;
1097
1098             status = _cairo_xlib_surface_get_gc (display, surface, &gc);
1099             if (unlikely (status))
1100                 goto out;
1101
1102             if (n_rects == 1) {
1103                 cairo_region_get_rectangle (damage->region, 0, &r);
1104                 _cairo_xlib_shm_surface_mark_active (surface->shm);
1105                 XCopyArea (display->display,
1106                            shm->pixmap, surface->drawable, gc,
1107                            r.x, r.y,
1108                            r.width, r.height,
1109                            r.x, r.y);
1110             } else {
1111                 if (n_rects > ARRAY_LENGTH (stack_rects)) {
1112                     rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
1113                     if (unlikely (rects == NULL)) {
1114                         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1115                         _cairo_xlib_surface_put_gc (display, surface, gc);
1116                         goto out;
1117                     }
1118                 }
1119                 for (i = 0; i < n_rects; i++) {
1120                     cairo_region_get_rectangle (damage->region, i, &r);
1121
1122                     rects[i].x = r.x;
1123                     rects[i].y = r.y;
1124                     rects[i].width  = r.width;
1125                     rects[i].height = r.height;
1126                 }
1127                 XSetClipRectangles (display->display, gc, 0, 0, rects, i, YXBanded);
1128
1129                 _cairo_xlib_shm_surface_mark_active (surface->shm);
1130                 XCopyArea (display->display,
1131                            shm->pixmap, surface->drawable, gc,
1132                            0, 0,
1133                            shm->image.width, shm->image.height,
1134                            0, 0);
1135
1136                 if (damage->status == CAIRO_STATUS_SUCCESS && damage->region)
1137                     XSetClipMask (display->display, gc, None);
1138             }
1139
1140             _cairo_xlib_surface_put_gc (display, surface, gc);
1141         }
1142
1143 out:
1144         _cairo_damage_destroy (damage);
1145         cairo_device_release (&display->base);
1146     }
1147
1148     return status;
1149 }
1150
1151 cairo_surface_t *
1152 _cairo_xlib_surface_create_shm (cairo_xlib_surface_t *other,
1153                                 pixman_format_code_t format,
1154                                 int width, int height)
1155 {
1156     cairo_surface_t *surface;
1157
1158     surface = NULL;
1159     if (has_shm (other))
1160         surface = &_cairo_xlib_shm_surface_create (other, format, width, height,
1161                                                    FALSE, has_shm_pixmaps (other))->image.base;
1162
1163     return surface;
1164 }
1165
1166 cairo_surface_t *
1167 _cairo_xlib_surface_create_shm__image (cairo_xlib_surface_t *surface,
1168                                        pixman_format_code_t format,
1169                                        int width, int height)
1170 {
1171     if (! has_shm(surface))
1172         return NULL;
1173
1174     return &_cairo_xlib_shm_surface_create (surface, format, width, height,
1175                                             FALSE, 0)->image.base;
1176 }
1177
1178 cairo_surface_t *
1179 _cairo_xlib_surface_create_similar_shm (void *other,
1180                                         cairo_format_t format,
1181                                         int width, int height)
1182 {
1183     cairo_surface_t *surface;
1184
1185     surface = _cairo_xlib_surface_create_shm (other,
1186                                               _cairo_format_to_pixman_format_code (format),
1187                                               width, height);
1188     if (surface) {
1189         if (! surface->is_clear) {
1190             cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface;
1191             assert (shm->active == 0);
1192             memset (shm->image.data, 0, shm->image.stride * shm->image.height);
1193             shm->image.base.is_clear = TRUE;
1194         }
1195     } else
1196         surface = cairo_image_surface_create (format, width, height);
1197
1198     return surface;
1199 }
1200
1201 void
1202 _cairo_xlib_shm_surface_mark_active (cairo_surface_t *_shm)
1203 {
1204     cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) _shm;
1205     cairo_xlib_display_t *display = (cairo_xlib_display_t *) _shm->device;
1206
1207     shm->active = NextRequest (display->display);
1208 }
1209
1210 void
1211 _cairo_xlib_shm_surface_get_ximage (cairo_surface_t *surface,
1212                                     XImage *ximage)
1213 {
1214     cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface;
1215     int native_byte_order = _cairo_is_little_endian () ? LSBFirst : MSBFirst;
1216     cairo_format_masks_t image_masks;
1217     int ret;
1218
1219     ret = _pixman_format_to_masks (shm->image.pixman_format, &image_masks);
1220     assert (ret);
1221
1222     ximage->width = shm->image.width;
1223     ximage->height = shm->image.height;
1224     ximage->format = ZPixmap;
1225     ximage->data = (char *) shm->image.data;
1226     ximage->obdata = (char *)&shm->info->pool->shm;
1227     ximage->byte_order = native_byte_order;
1228     ximage->bitmap_unit = 32;   /* always for libpixman */
1229     ximage->bitmap_bit_order = native_byte_order;
1230     ximage->bitmap_pad = 32;    /* always for libpixman */
1231     ximage->depth = shm->image.depth;
1232     ximage->bytes_per_line = shm->image.stride;
1233     ximage->bits_per_pixel = image_masks.bpp;
1234     ximage->red_mask = image_masks.red_mask;
1235     ximage->green_mask = image_masks.green_mask;
1236     ximage->blue_mask = image_masks.blue_mask;
1237     ximage->xoffset = 0;
1238
1239     ret = XInitImage (ximage);
1240     assert (ret != 0);
1241 }
1242
1243 void *
1244 _cairo_xlib_shm_surface_get_obdata (cairo_surface_t *surface)
1245 {
1246     cairo_xlib_display_t *display = (cairo_xlib_display_t *) surface->device;
1247     cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface;
1248
1249     display->shm->last_event = shm->active = NextRequest (display->display);
1250     return &shm->info->pool->shm;
1251 }
1252
1253 Pixmap
1254 _cairo_xlib_shm_surface_get_pixmap (cairo_surface_t *surface)
1255 {
1256     cairo_xlib_shm_surface_t *shm;
1257
1258     shm = (cairo_xlib_shm_surface_t *) surface;
1259     return shm->pixmap;
1260 }
1261
1262 XRenderPictFormat *
1263 _cairo_xlib_shm_surface_get_xrender_format (cairo_surface_t *surface)
1264 {
1265     cairo_xlib_shm_surface_t *shm;
1266
1267     shm = (cairo_xlib_shm_surface_t *) surface;
1268     if (shm->image.format != CAIRO_FORMAT_INVALID)
1269         return _cairo_xlib_display_get_xrender_format ((cairo_xlib_display_t *)surface->device,
1270                                                        shm->image.format);
1271
1272     return _cairo_xlib_display_get_xrender_format_for_pixman((cairo_xlib_display_t *)surface->device,
1273                                                              shm->image.pixman_format);
1274 }
1275
1276 cairo_bool_t
1277 _cairo_xlib_shm_surface_is_active (cairo_surface_t *surface)
1278 {
1279     cairo_xlib_shm_surface_t *shm;
1280
1281     shm = (cairo_xlib_shm_surface_t *) surface;
1282     if (shm->active == 0)
1283         return FALSE;
1284
1285     if (seqno_passed (shm->active, peek_processed (shm->image.base.device))) {
1286         shm->active = 0;
1287         return FALSE;
1288     }
1289
1290     return TRUE;
1291 }
1292
1293 cairo_bool_t
1294 _cairo_xlib_shm_surface_is_idle (cairo_surface_t *surface)
1295 {
1296     cairo_xlib_shm_surface_t *shm;
1297
1298     shm = (cairo_xlib_shm_surface_t *) surface;
1299     return shm->idle > 0;
1300 }
1301
1302 #define XORG_VERSION_ENCODE(major,minor,patch,snap) \
1303     (((major) * 10000000) + ((minor) * 100000) + ((patch) * 1000) + snap)
1304
1305 static cairo_bool_t
1306 has_broken_send_shm_event (cairo_xlib_display_t *display,
1307                            cairo_xlib_shm_display_t *shm)
1308 {
1309     Display *dpy = display->display;
1310     int (*old_handler) (Display *display, XErrorEvent *event);
1311     XShmCompletionEvent ev;
1312     XShmSegmentInfo info;
1313
1314     info.shmid = shmget (IPC_PRIVATE, 0x1000, IPC_CREAT | 0600);
1315     if (info.shmid == -1)
1316         return TRUE;
1317
1318     info.readOnly = FALSE;
1319     info.shmaddr = shmat (info.shmid, NULL, 0);
1320     if (info.shmaddr == (char *) -1) {
1321         shmctl (info.shmid, IPC_RMID, NULL);
1322         return TRUE;
1323     }
1324
1325     ev.type = shm->event;
1326     ev.send_event = 1;
1327     ev.serial = 1;
1328     ev.drawable = shm->window;
1329     ev.major_code = shm->opcode;
1330     ev.minor_code = X_ShmPutImage;
1331
1332     ev.shmseg = info.shmid;
1333     ev.offset = 0;
1334
1335     assert (CAIRO_MUTEX_IS_LOCKED (_cairo_xlib_display_mutex));
1336     _x_error_occurred = FALSE;
1337
1338     XLockDisplay (dpy);
1339     XSync (dpy, False);
1340     old_handler = XSetErrorHandler (_check_error_handler);
1341
1342     XShmAttach (dpy, &info);
1343     XSendEvent (dpy, ev.drawable, False, 0, (XEvent *)&ev);
1344     XShmDetach (dpy, &info);
1345
1346     XSync (dpy, False);
1347     XSetErrorHandler (old_handler);
1348     XUnlockDisplay (dpy);
1349
1350     shmctl (info.shmid, IPC_RMID, NULL);
1351     shmdt (info.shmaddr);
1352
1353     return _x_error_occurred;
1354 }
1355
1356 static cairo_bool_t
1357 xorg_has_buggy_send_shm_completion_event(cairo_xlib_display_t *display,
1358                                          cairo_xlib_shm_display_t *shm)
1359 {
1360     Display *dpy = display->display;
1361
1362     /* As libXext sets the SEND_EVENT bit in the ShmCompletionEvent,
1363      * the Xserver may crash if it does not take care when processing
1364      * the event type. For instance versions of Xorg prior to 1.11.1
1365      * exhibited this bug, and was fixed by:
1366      *
1367      * commit 2d2dce558d24eeea0eb011ec9ebaa6c5c2273c39
1368      * Author: Sam Spilsbury <sam.spilsbury@canonical.com>
1369      * Date:   Wed Sep 14 09:58:34 2011 +0800
1370      *
1371      * Remove the SendEvent bit (0x80) before doing range checks on event type.
1372      */
1373     if (_cairo_xlib_vendor_is_xorg (dpy) &&
1374         VendorRelease (dpy) < XORG_VERSION_ENCODE(1,11,0,1))
1375         return TRUE;
1376
1377     /* For everyone else check that no error is generated */
1378     return has_broken_send_shm_event (display, shm);
1379 }
1380
1381 void
1382 _cairo_xlib_display_init_shm (cairo_xlib_display_t *display)
1383 {
1384     cairo_xlib_shm_display_t *shm;
1385     XSetWindowAttributes attr;
1386     XExtCodes *codes;
1387     int has_pixmap, scr;
1388
1389     display->shm = NULL;
1390
1391     if (!can_use_shm (display->display, &has_pixmap))
1392         return;
1393
1394     shm = malloc (sizeof (*shm));
1395     if (unlikely (shm == NULL))
1396         return;
1397
1398     codes = XInitExtension (display->display, SHMNAME);
1399     if (codes == NULL) {
1400         free (shm);
1401         return;
1402     }
1403
1404     shm->opcode = codes ->major_opcode;
1405     shm->event = codes->first_event;
1406
1407     if (unlikely (_pqueue_init (&shm->info))) {
1408         free (shm);
1409         return;
1410     }
1411
1412     scr = DefaultScreen (display->display);
1413     attr.override_redirect = 1;
1414     shm->window = XCreateWindow (display->display,
1415                                  DefaultRootWindow (display->display), -1, -1,
1416                                  1, 1, 0,
1417                                  DefaultDepth (display->display, scr),
1418                                  InputOutput,
1419                                  DefaultVisual (display->display, scr),
1420                                  CWOverrideRedirect, &attr);
1421     shm->last_event = 0;
1422     shm->last_request = 0;
1423
1424     if (xorg_has_buggy_send_shm_completion_event(display, shm))
1425         has_pixmap = 0;
1426
1427     shm->has_pixmaps = has_pixmap ? MIN_PIXMAP_SIZE : 0;
1428     cairo_list_init (&shm->pool);
1429
1430     cairo_list_init (&shm->surfaces);
1431
1432     display->shm = shm;
1433 }
1434
1435 void
1436 _cairo_xlib_display_fini_shm (cairo_xlib_display_t *display)
1437 {
1438     cairo_xlib_shm_display_t *shm = display->shm;
1439
1440     if (shm == NULL)
1441         return;
1442
1443     while (!cairo_list_is_empty (&shm->surfaces))
1444         cairo_surface_finish (&cairo_list_first_entry (&shm->surfaces,
1445                                                        cairo_xlib_shm_surface_t,
1446                                                        link)->image.base);
1447
1448     _pqueue_fini (&shm->info);
1449
1450     while (!cairo_list_is_empty (&shm->pool)) {
1451         cairo_xlib_shm_t *pool;
1452
1453         pool = cairo_list_first_entry (&shm->pool, cairo_xlib_shm_t, link);
1454         _cairo_xlib_display_shm_pool_destroy (display, pool);
1455     }
1456
1457     if (display->display)
1458         XDestroyWindow (display->display, shm->window);
1459
1460     free (shm);
1461     display->shm = NULL;
1462 }
1463 #endif
1464 #endif