Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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 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.     cairo_status_t status;
  674.  
  675.     if (shm->active == 0)
  676.         return CAIRO_STATUS_SUCCESS;
  677.  
  678.     if (shm->image.base._finishing)
  679.         return CAIRO_STATUS_SUCCESS;
  680.  
  681.     if (seqno_passed (shm->active, peek_processed (shm->image.base.device))) {
  682.         shm->active = 0;
  683.         return CAIRO_STATUS_SUCCESS;
  684.     }
  685.  
  686.     status = _cairo_xlib_display_acquire (shm->image.base.device, &display);
  687.     if (unlikely (status))
  688.         return status;
  689.  
  690.     send_event (display, shm->info, shm->active);
  691.  
  692.     dpy = display->display;
  693.     XEventsQueued (dpy, QueuedAfterReading);
  694.     while (! seqno_passed (shm->active, LastKnownRequestProcessed (dpy))) {
  695.         LockDisplay(dpy);
  696.         _XReadEvents(dpy);
  697.         UnlockDisplay(dpy);
  698.     }
  699.  
  700.     cairo_device_release (&display->base);
  701.     shm->active = 0;
  702.  
  703.     return CAIRO_STATUS_SUCCESS;
  704. }
  705.  
  706. static inline cairo_bool_t
  707. active (cairo_xlib_shm_surface_t *shm, Display *dpy)
  708. {
  709.     return (shm->active &&
  710.             ! seqno_passed (shm->active, LastKnownRequestProcessed (dpy)));
  711. }
  712.  
  713. static cairo_status_t
  714. _cairo_xlib_shm_surface_finish (void *abstract_surface)
  715. {
  716.     cairo_xlib_shm_surface_t *shm = abstract_surface;
  717.     cairo_xlib_display_t *display;
  718.     cairo_status_t status;
  719.  
  720.     if (shm->image.base.damage) {
  721.         _cairo_damage_destroy (shm->image.base.damage);
  722.         shm->image.base.damage = _cairo_damage_create_in_error (CAIRO_STATUS_SURFACE_FINISHED);
  723.     }
  724.  
  725.     status = _cairo_xlib_display_acquire (shm->image.base.device, &display);
  726.     if (unlikely (status))
  727.         return status;
  728.  
  729.     if (shm->pixmap)
  730.         XFreePixmap (display->display, shm->pixmap);
  731.  
  732.     if (active (shm, display->display)) {
  733.         shm->info->last_request = shm->active;
  734.         _pqueue_push (&display->shm->info, shm->info);
  735.         if (seqno_before (display->shm->last_request, shm->active))
  736.             display->shm->last_request = shm->active;
  737.     } else {
  738.         _cairo_mempool_free (&shm->info->pool->mem, shm->info->mem);
  739.         free (shm->info);
  740.  
  741.         _cairo_xlib_shm_pool_cleanup (display);
  742.     }
  743.  
  744.     cairo_list_del (&shm->link);
  745.  
  746.     cairo_device_release (&display->base);
  747.     return _cairo_image_surface_finish (abstract_surface);
  748. }
  749.  
  750. static const cairo_surface_backend_t cairo_xlib_shm_surface_backend = {
  751.     CAIRO_SURFACE_TYPE_IMAGE,
  752.     _cairo_xlib_shm_surface_finish,
  753.  
  754.     _cairo_default_context_create,
  755.  
  756.     _cairo_image_surface_create_similar,
  757.     NULL, /* create similar image */
  758.     _cairo_image_surface_map_to_image,
  759.     _cairo_image_surface_unmap_image,
  760.  
  761.     _cairo_image_surface_source,
  762.     _cairo_image_surface_acquire_source_image,
  763.     _cairo_image_surface_release_source_image,
  764.     _cairo_image_surface_snapshot,
  765.  
  766.     NULL, /* copy_page */
  767.     NULL, /* show_page */
  768.  
  769.     _cairo_image_surface_get_extents,
  770.     _cairo_image_surface_get_font_options,
  771.  
  772.     _cairo_xlib_shm_surface_flush,
  773.     NULL,
  774.  
  775.     _cairo_image_surface_paint,
  776.     _cairo_image_surface_mask,
  777.     _cairo_image_surface_stroke,
  778.     _cairo_image_surface_fill,
  779.     NULL, /* fill-stroke */
  780.     _cairo_image_surface_glyphs,
  781. };
  782.  
  783. static cairo_bool_t
  784. has_shm (cairo_xlib_surface_t *surface)
  785. {
  786.     cairo_xlib_display_t *display = (cairo_xlib_display_t *)surface->base.device;
  787.     return display->shm != NULL;
  788. }
  789.  
  790. static int
  791. has_shm_pixmaps (cairo_xlib_surface_t *surface)
  792. {
  793.     cairo_xlib_display_t *display = (cairo_xlib_display_t *)surface->base.device;
  794.     if (!display->shm)
  795.         return 0;
  796.  
  797.     return display->shm->has_pixmaps;
  798. }
  799.  
  800. static cairo_xlib_shm_surface_t *
  801. _cairo_xlib_shm_surface_create (cairo_xlib_surface_t *other,
  802.                                 pixman_format_code_t format,
  803.                                 int width, int height,
  804.                                 cairo_bool_t will_sync,
  805.                                 int create_pixmap)
  806. {
  807.     cairo_xlib_shm_surface_t *shm;
  808.     cairo_xlib_display_t *display;
  809.     pixman_image_t *image;
  810.     int stride, size;
  811.  
  812.     stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP(format));
  813.     size = stride * height;
  814.     if (size < MIN_SIZE)
  815.         return NULL;
  816.  
  817.     shm = malloc (sizeof (*shm));
  818.     if (unlikely (shm == NULL))
  819.         return (cairo_xlib_shm_surface_t *)_cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
  820.  
  821.     _cairo_surface_init (&shm->image.base,
  822.                          &cairo_xlib_shm_surface_backend,
  823.                          other->base.device,
  824.                          _cairo_content_from_pixman_format (format));
  825.  
  826.     if (_cairo_xlib_display_acquire (other->base.device, &display))
  827.         goto cleanup_shm;
  828.  
  829.     shm->info = _cairo_xlib_shm_info_create (display, size, will_sync);
  830.     if (shm->info == NULL)
  831.         goto cleanup_display;
  832.  
  833.     image = pixman_image_create_bits (format, width, height,
  834.                                       (uint32_t *) shm->info->mem, stride);
  835.     if (image == NULL)
  836.         goto cleanup_info;
  837.  
  838.     _cairo_image_surface_init (&shm->image, image, format);
  839.  
  840.     shm->pixmap = 0;
  841.     if (create_pixmap && size >= create_pixmap) {
  842.         shm->pixmap = XShmCreatePixmap (display->display,
  843.                                         other->drawable,
  844.                                         shm->info->mem,
  845.                                         &shm->info->pool->shm,
  846.                                         shm->image.width,
  847.                                         shm->image.height,
  848.                                         shm->image.depth);
  849.     }
  850.     shm->active = shm->info->last_request;
  851.     shm->idle = -5;
  852.  
  853.     assert (shm->active == 0 || will_sync);
  854.  
  855.     cairo_list_add (&shm->link, &display->shm->surfaces);
  856.  
  857.     cairo_device_release (&display->base);
  858.  
  859.     return shm;
  860.  
  861. cleanup_info:
  862.     _cairo_mempool_free (&shm->info->pool->mem, shm->info->mem);
  863.     free(shm->info);
  864. cleanup_display:
  865.     cairo_device_release (&display->base);
  866. cleanup_shm:
  867.     free (shm);
  868.     return NULL;
  869. }
  870.  
  871. static void
  872. _cairo_xlib_surface_update_shm (cairo_xlib_surface_t *surface)
  873. {
  874.     cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface->shm;
  875.     cairo_xlib_display_t *display;
  876.     cairo_damage_t *damage;
  877.     GC gc;
  878.  
  879.     damage = _cairo_damage_reduce (surface->base.damage);
  880.     surface->base.damage = _cairo_damage_create();
  881.  
  882.     if (_cairo_xlib_display_acquire (surface->base.device, &display))
  883.         goto cleanup_damage;
  884.  
  885.     if (_cairo_xlib_surface_get_gc (display, surface, &gc))
  886.         goto cleanup_display;
  887.  
  888.     if (! surface->owns_pixmap) {
  889.         XGCValues gcv;
  890.  
  891.         gcv.subwindow_mode = IncludeInferiors;
  892.         XChangeGC (display->display, gc, GCSubwindowMode, &gcv);
  893.     }
  894.  
  895.     if (damage->region) {
  896.         XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (sizeof (XRectangle))];
  897.         XRectangle *rects = stack_rects;
  898.         cairo_rectangle_int_t r;
  899.         int n_rects, i;
  900.  
  901.         n_rects = cairo_region_num_rectangles (damage->region);
  902.         if (n_rects == 0) {
  903.         } else if (n_rects == 1) {
  904.             cairo_region_get_rectangle (damage->region, 0, &r);
  905.             XCopyArea (display->display,
  906.                        surface->drawable, shm->pixmap, gc,
  907.                        r.x, r.y,
  908.                        r.width, r.height,
  909.                        r.x, r.y);
  910.         } else {
  911.             if (n_rects > ARRAY_LENGTH (stack_rects)) {
  912.                 rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
  913.                 if (unlikely (rects == NULL)) {
  914.                     rects = stack_rects;
  915.                     n_rects = ARRAY_LENGTH (stack_rects);
  916.                 }
  917.             }
  918.             for (i = 0; i < n_rects; i++) {
  919.                 cairo_region_get_rectangle (damage->region, i, &r);
  920.  
  921.                 rects[i].x = r.x;
  922.                 rects[i].y = r.y;
  923.                 rects[i].width  = r.width;
  924.                 rects[i].height = r.height;
  925.             }
  926.             XSetClipRectangles (display->display, gc, 0, 0, rects, i, YXBanded);
  927.  
  928.             XCopyArea (display->display,
  929.                        surface->drawable, shm->pixmap, gc,
  930.                        0, 0,
  931.                        shm->image.width, shm->image.height,
  932.                        0, 0);
  933.  
  934.             if (damage->status == CAIRO_STATUS_SUCCESS && damage->region)
  935.                 XSetClipMask (display->display, gc, None);
  936.         }
  937.     } else {
  938.         XCopyArea (display->display,
  939.                    surface->drawable, shm->pixmap, gc,
  940.                    0, 0,
  941.                    shm->image.width, shm->image.height,
  942.                    0, 0);
  943.     }
  944.  
  945.     if (! surface->owns_pixmap) {
  946.         XGCValues gcv;
  947.  
  948.         gcv.subwindow_mode = ClipByChildren;
  949.         XChangeGC (display->display, gc, GCSubwindowMode, &gcv);
  950.     }
  951.  
  952.     sync (display);
  953.     shm->active = 0;
  954.     shm->idle--;
  955.  
  956.     _cairo_xlib_surface_put_gc (display, surface, gc);
  957. cleanup_display:
  958.     cairo_device_release (&display->base);
  959. cleanup_damage:
  960.     _cairo_damage_destroy (damage);
  961. }
  962.  
  963. static void
  964. _cairo_xlib_surface_clear_shm (cairo_xlib_surface_t *surface)
  965. {
  966.     cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface->shm;
  967.  
  968.     assert (shm->active == 0);
  969.  
  970.     _cairo_damage_destroy (surface->base.damage);
  971.     surface->base.damage = _cairo_damage_create();
  972.  
  973.     memset (shm->image.data, 0, shm->image.stride * shm->image.height);
  974.     shm->image.base.is_clear = TRUE;
  975. }
  976.  
  977. static void inc_idle (cairo_surface_t *surface)
  978. {
  979.     cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface;
  980.     shm->idle++;
  981. }
  982.  
  983. static void dec_idle (cairo_surface_t *surface)
  984. {
  985.     cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface;
  986.     shm->idle--;
  987. }
  988.  
  989. cairo_surface_t *
  990. _cairo_xlib_surface_get_shm (cairo_xlib_surface_t *surface,
  991.                              cairo_bool_t overwrite)
  992. {
  993.     if (surface->fallback) {
  994.         assert (surface->base.damage);
  995.         assert (surface->shm);
  996.         assert (surface->shm->damage);
  997.         goto done;
  998.     }
  999.  
  1000.     if (surface->shm == NULL) {
  1001.         pixman_format_code_t pixman_format;
  1002.         cairo_bool_t will_sync;
  1003.  
  1004.         if (! has_shm_pixmaps (surface))
  1005.             return NULL;
  1006.  
  1007.         if ((surface->width | surface->height) < 32)
  1008.             return NULL;
  1009.  
  1010.         pixman_format = _pixman_format_for_xlib_surface (surface);
  1011.         if (pixman_format == 0)
  1012.             return NULL;
  1013.  
  1014.         will_sync = !surface->base.is_clear && !overwrite;
  1015.  
  1016.         surface->shm =
  1017.             &_cairo_xlib_shm_surface_create (surface, pixman_format,
  1018.                                              surface->width, surface->height,
  1019.                                              will_sync, 1)->image.base;
  1020.         if (surface->shm == NULL)
  1021.             return NULL;
  1022.  
  1023.         assert (surface->base.damage == NULL);
  1024.         if (surface->base.serial || !surface->owns_pixmap) {
  1025.             cairo_rectangle_int_t rect;
  1026.  
  1027.             rect.x = rect.y = 0;
  1028.             rect.width = surface->width;
  1029.             rect.height = surface->height;
  1030.  
  1031.             surface->base.damage =
  1032.                 _cairo_damage_add_rectangle (NULL, &rect);
  1033.         } else
  1034.             surface->base.damage = _cairo_damage_create ();
  1035.  
  1036.         surface->shm->damage = _cairo_damage_create ();
  1037.     }
  1038.  
  1039.     if (overwrite) {
  1040.         _cairo_damage_destroy (surface->base.damage);
  1041.         surface->base.damage = _cairo_damage_create ();
  1042.     }
  1043.  
  1044.     if (!surface->base.is_clear && surface->base.damage->dirty)
  1045.         _cairo_xlib_surface_update_shm (surface);
  1046.  
  1047.     _cairo_xlib_shm_surface_flush (surface->shm, 1);
  1048.  
  1049.     if (surface->base.is_clear && surface->base.damage->dirty)
  1050.         _cairo_xlib_surface_clear_shm (surface);
  1051.  
  1052. done:
  1053.     dec_idle(surface->shm);
  1054.     return surface->shm;
  1055. }
  1056.  
  1057. cairo_int_status_t
  1058. _cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface)
  1059. {
  1060.     cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
  1061.  
  1062.     if (!surface->fallback) {
  1063.         if (surface->shm)
  1064.             inc_idle (surface->shm);
  1065.         return CAIRO_INT_STATUS_SUCCESS;
  1066.     }
  1067.  
  1068.     if (surface->shm->damage->dirty) {
  1069.         cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface->shm;
  1070.         cairo_xlib_display_t *display;
  1071.         cairo_damage_t *damage;
  1072.         GC gc;
  1073.  
  1074.         status = _cairo_xlib_display_acquire (surface->base.device, &display);
  1075.         if (unlikely (status))
  1076.             return status;
  1077.  
  1078.         damage = _cairo_damage_reduce (shm->image.base.damage);
  1079.         shm->image.base.damage = _cairo_damage_create ();
  1080.  
  1081.         TRACE ((stderr, "%s: flushing damage x %d\n", __FUNCTION__,
  1082.                 damage->region ? cairo_region_num_rectangles (damage->region) : 0));
  1083.         if (damage->status == CAIRO_STATUS_SUCCESS && damage->region) {
  1084.             XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (sizeof (XRectangle))];
  1085.             XRectangle *rects = stack_rects;
  1086.             cairo_rectangle_int_t r;
  1087.             int n_rects, i;
  1088.  
  1089.             n_rects = cairo_region_num_rectangles (damage->region);
  1090.             if (n_rects == 0)
  1091.                 goto out;
  1092.  
  1093.             status = _cairo_xlib_surface_get_gc (display, surface, &gc);
  1094.             if (unlikely (status))
  1095.                 goto out;
  1096.  
  1097.             if (n_rects == 1) {
  1098.                 cairo_region_get_rectangle (damage->region, 0, &r);
  1099.                 _cairo_xlib_shm_surface_mark_active (surface->shm);
  1100.                 XCopyArea (display->display,
  1101.                            shm->pixmap, surface->drawable, gc,
  1102.                            r.x, r.y,
  1103.                            r.width, r.height,
  1104.                            r.x, r.y);
  1105.             } else {
  1106.                 if (n_rects > ARRAY_LENGTH (stack_rects)) {
  1107.                     rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
  1108.                     if (unlikely (rects == NULL)) {
  1109.                         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  1110.                         _cairo_xlib_surface_put_gc (display, surface, gc);
  1111.                         goto out;
  1112.                     }
  1113.                 }
  1114.                 for (i = 0; i < n_rects; i++) {
  1115.                     cairo_region_get_rectangle (damage->region, i, &r);
  1116.  
  1117.                     rects[i].x = r.x;
  1118.                     rects[i].y = r.y;
  1119.                     rects[i].width  = r.width;
  1120.                     rects[i].height = r.height;
  1121.                 }
  1122.                 XSetClipRectangles (display->display, gc, 0, 0, rects, i, YXBanded);
  1123.  
  1124.                 _cairo_xlib_shm_surface_mark_active (surface->shm);
  1125.                 XCopyArea (display->display,
  1126.                            shm->pixmap, surface->drawable, gc,
  1127.                            0, 0,
  1128.                            shm->image.width, shm->image.height,
  1129.                            0, 0);
  1130.  
  1131.                 if (damage->status == CAIRO_STATUS_SUCCESS && damage->region)
  1132.                     XSetClipMask (display->display, gc, None);
  1133.             }
  1134.  
  1135.             _cairo_xlib_surface_put_gc (display, surface, gc);
  1136.         }
  1137.  
  1138. out:
  1139.         _cairo_damage_destroy (damage);
  1140.         cairo_device_release (&display->base);
  1141.     }
  1142.  
  1143.     return status;
  1144. }
  1145.  
  1146. cairo_surface_t *
  1147. _cairo_xlib_surface_create_shm (cairo_xlib_surface_t *other,
  1148.                                 pixman_format_code_t format,
  1149.                                 int width, int height)
  1150. {
  1151.     cairo_surface_t *surface;
  1152.  
  1153.     surface = NULL;
  1154.     if (has_shm (other))
  1155.         surface = &_cairo_xlib_shm_surface_create (other, format, width, height,
  1156.                                                    FALSE, has_shm_pixmaps (other))->image.base;
  1157.  
  1158.     return surface;
  1159. }
  1160.  
  1161. cairo_surface_t *
  1162. _cairo_xlib_surface_create_shm__image (cairo_xlib_surface_t *surface,
  1163.                                        pixman_format_code_t format,
  1164.                                        int width, int height)
  1165. {
  1166.     if (! has_shm(surface))
  1167.         return NULL;
  1168.  
  1169.     return &_cairo_xlib_shm_surface_create (surface, format, width, height,
  1170.                                             FALSE, 0)->image.base;
  1171. }
  1172.  
  1173. cairo_surface_t *
  1174. _cairo_xlib_surface_create_similar_shm (void *other,
  1175.                                         cairo_format_t format,
  1176.                                         int width, int height)
  1177. {
  1178.     cairo_surface_t *surface;
  1179.  
  1180.     surface = _cairo_xlib_surface_create_shm (other,
  1181.                                               _cairo_format_to_pixman_format_code (format),
  1182.                                               width, height);
  1183.     if (surface) {
  1184.         if (! surface->is_clear) {
  1185.             cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface;
  1186.             assert (shm->active == 0);
  1187.             memset (shm->image.data, 0, shm->image.stride * shm->image.height);
  1188.             shm->image.base.is_clear = TRUE;
  1189.         }
  1190.     } else
  1191.         surface = cairo_image_surface_create (format, width, height);
  1192.  
  1193.     return surface;
  1194. }
  1195.  
  1196. void
  1197. _cairo_xlib_shm_surface_mark_active (cairo_surface_t *_shm)
  1198. {
  1199.     cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) _shm;
  1200.     cairo_xlib_display_t *display = (cairo_xlib_display_t *) _shm->device;
  1201.  
  1202.     shm->active = NextRequest (display->display);
  1203. }
  1204.  
  1205. void
  1206. _cairo_xlib_shm_surface_get_ximage (cairo_surface_t *surface,
  1207.                                     XImage *ximage)
  1208. {
  1209.     cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface;
  1210.     int native_byte_order = _cairo_is_little_endian () ? LSBFirst : MSBFirst;
  1211.     cairo_format_masks_t image_masks;
  1212.     int ret;
  1213.  
  1214.     ret = _pixman_format_to_masks (shm->image.pixman_format, &image_masks);
  1215.     assert (ret);
  1216.  
  1217.     ximage->width = shm->image.width;
  1218.     ximage->height = shm->image.height;
  1219.     ximage->format = ZPixmap;
  1220.     ximage->data = (char *) shm->image.data;
  1221.     ximage->obdata = (char *)&shm->info->pool->shm;
  1222.     ximage->byte_order = native_byte_order;
  1223.     ximage->bitmap_unit = 32;   /* always for libpixman */
  1224.     ximage->bitmap_bit_order = native_byte_order;
  1225.     ximage->bitmap_pad = 32;    /* always for libpixman */
  1226.     ximage->depth = shm->image.depth;
  1227.     ximage->bytes_per_line = shm->image.stride;
  1228.     ximage->bits_per_pixel = image_masks.bpp;
  1229.     ximage->red_mask = image_masks.red_mask;
  1230.     ximage->green_mask = image_masks.green_mask;
  1231.     ximage->blue_mask = image_masks.blue_mask;
  1232.     ximage->xoffset = 0;
  1233.  
  1234.     ret = XInitImage (ximage);
  1235.     assert (ret != 0);
  1236. }
  1237.  
  1238. void *
  1239. _cairo_xlib_shm_surface_get_obdata (cairo_surface_t *surface)
  1240. {
  1241.     cairo_xlib_display_t *display = (cairo_xlib_display_t *) surface->device;
  1242.     cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface;
  1243.  
  1244.     display->shm->last_event = shm->active = NextRequest (display->display);
  1245.     return &shm->info->pool->shm;
  1246. }
  1247.  
  1248. Pixmap
  1249. _cairo_xlib_shm_surface_get_pixmap (cairo_surface_t *surface)
  1250. {
  1251.     cairo_xlib_shm_surface_t *shm;
  1252.  
  1253.     shm = (cairo_xlib_shm_surface_t *) surface;
  1254.     return shm->pixmap;
  1255. }
  1256.  
  1257. XRenderPictFormat *
  1258. _cairo_xlib_shm_surface_get_xrender_format (cairo_surface_t *surface)
  1259. {
  1260.     cairo_xlib_shm_surface_t *shm;
  1261.  
  1262.     shm = (cairo_xlib_shm_surface_t *) surface;
  1263.     if (shm->image.format != CAIRO_FORMAT_INVALID)
  1264.         return _cairo_xlib_display_get_xrender_format ((cairo_xlib_display_t *)surface->device,
  1265.                                                        shm->image.format);
  1266.  
  1267.     return _cairo_xlib_display_get_xrender_format_for_pixman((cairo_xlib_display_t *)surface->device,
  1268.                                                              shm->image.pixman_format);
  1269. }
  1270.  
  1271. cairo_bool_t
  1272. _cairo_xlib_shm_surface_is_active (cairo_surface_t *surface)
  1273. {
  1274.     cairo_xlib_shm_surface_t *shm;
  1275.  
  1276.     shm = (cairo_xlib_shm_surface_t *) surface;
  1277.     if (shm->active == 0)
  1278.         return FALSE;
  1279.  
  1280.     if (seqno_passed (shm->active, peek_processed (shm->image.base.device))) {
  1281.         shm->active = 0;
  1282.         return FALSE;
  1283.     }
  1284.  
  1285.     return TRUE;
  1286. }
  1287.  
  1288. cairo_bool_t
  1289. _cairo_xlib_shm_surface_is_idle (cairo_surface_t *surface)
  1290. {
  1291.     cairo_xlib_shm_surface_t *shm;
  1292.  
  1293.     shm = (cairo_xlib_shm_surface_t *) surface;
  1294.     return shm->idle > 0;
  1295. }
  1296.  
  1297. #define XORG_VERSION_ENCODE(major,minor,patch,snap) \
  1298.     (((major) * 10000000) + ((minor) * 100000) + ((patch) * 1000) + snap)
  1299.  
  1300. static cairo_bool_t
  1301. has_broken_send_shm_event (cairo_xlib_display_t *display,
  1302.                            cairo_xlib_shm_display_t *shm)
  1303. {
  1304.     Display *dpy = display->display;
  1305.     int (*old_handler) (Display *display, XErrorEvent *event);
  1306.     XShmCompletionEvent ev;
  1307.     XShmSegmentInfo info;
  1308.  
  1309.     info.shmid = shmget (IPC_PRIVATE, 0x1000, IPC_CREAT | 0600);
  1310.     if (info.shmid == -1)
  1311.         return TRUE;
  1312.  
  1313.     info.readOnly = FALSE;
  1314.     info.shmaddr = shmat (info.shmid, NULL, 0);
  1315.     if (info.shmaddr == (char *) -1) {
  1316.         shmctl (info.shmid, IPC_RMID, NULL);
  1317.         return TRUE;
  1318.     }
  1319.  
  1320.     ev.type = shm->event;
  1321.     ev.send_event = 1;
  1322.     ev.serial = 1;
  1323.     ev.drawable = shm->window;
  1324.     ev.major_code = shm->opcode;
  1325.     ev.minor_code = X_ShmPutImage;
  1326.  
  1327.     ev.shmseg = info.shmid;
  1328.     ev.offset = 0;
  1329.  
  1330.     assert (CAIRO_MUTEX_IS_LOCKED (_cairo_xlib_display_mutex));
  1331.     _x_error_occurred = FALSE;
  1332.  
  1333.     XLockDisplay (dpy);
  1334.     XSync (dpy, False);
  1335.     old_handler = XSetErrorHandler (_check_error_handler);
  1336.  
  1337.     XShmAttach (dpy, &info);
  1338.     XSendEvent (dpy, ev.drawable, False, 0, (XEvent *)&ev);
  1339.     XShmDetach (dpy, &info);
  1340.  
  1341.     XSync (dpy, False);
  1342.     XSetErrorHandler (old_handler);
  1343.     XUnlockDisplay (dpy);
  1344.  
  1345.     shmctl (info.shmid, IPC_RMID, NULL);
  1346.     shmdt (info.shmaddr);
  1347.  
  1348.     return _x_error_occurred;
  1349. }
  1350.  
  1351. static cairo_bool_t
  1352. xorg_has_buggy_send_shm_completion_event(cairo_xlib_display_t *display,
  1353.                                          cairo_xlib_shm_display_t *shm)
  1354. {
  1355.     Display *dpy = display->display;
  1356.  
  1357.     /* As libXext sets the SEND_EVENT bit in the ShmCompletionEvent,
  1358.      * the Xserver may crash if it does not take care when processing
  1359.      * the event type. For instance versions of Xorg prior to 1.11.1
  1360.      * exhibited this bug, and was fixed by:
  1361.      *
  1362.      * commit 2d2dce558d24eeea0eb011ec9ebaa6c5c2273c39
  1363.      * Author: Sam Spilsbury <sam.spilsbury@canonical.com>
  1364.      * Date:   Wed Sep 14 09:58:34 2011 +0800
  1365.      *
  1366.      * Remove the SendEvent bit (0x80) before doing range checks on event type.
  1367.      */
  1368.     if (_cairo_xlib_vendor_is_xorg (dpy) &&
  1369.         VendorRelease (dpy) < XORG_VERSION_ENCODE(1,11,0,1))
  1370.         return TRUE;
  1371.  
  1372.     /* For everyone else check that no error is generated */
  1373.     return has_broken_send_shm_event (display, shm);
  1374. }
  1375.  
  1376. void
  1377. _cairo_xlib_display_init_shm (cairo_xlib_display_t *display)
  1378. {
  1379.     cairo_xlib_shm_display_t *shm;
  1380.     XSetWindowAttributes attr;
  1381.     XExtCodes *codes;
  1382.     int has_pixmap, scr;
  1383.  
  1384.     display->shm = NULL;
  1385.  
  1386.     if (!can_use_shm (display->display, &has_pixmap))
  1387.         return;
  1388.  
  1389.     shm = malloc (sizeof (*shm));
  1390.     if (unlikely (shm == NULL))
  1391.         return;
  1392.  
  1393.     codes = XInitExtension (display->display, SHMNAME);
  1394.     if (codes == NULL) {
  1395.         free (shm);
  1396.         return;
  1397.     }
  1398.  
  1399.     shm->opcode = codes ->major_opcode;
  1400.     shm->event = codes->first_event;
  1401.  
  1402.     if (unlikely (_pqueue_init (&shm->info))) {
  1403.         free (shm);
  1404.         return;
  1405.     }
  1406.  
  1407.     scr = DefaultScreen (display->display);
  1408.     attr.override_redirect = 1;
  1409.     shm->window = XCreateWindow (display->display,
  1410.                                  DefaultRootWindow (display->display), -1, -1,
  1411.                                  1, 1, 0,
  1412.                                  DefaultDepth (display->display, scr),
  1413.                                  InputOutput,
  1414.                                  DefaultVisual (display->display, scr),
  1415.                                  CWOverrideRedirect, &attr);
  1416.     shm->last_event = 0;
  1417.     shm->last_request = 0;
  1418.  
  1419.     if (xorg_has_buggy_send_shm_completion_event(display, shm))
  1420.         has_pixmap = 0;
  1421.  
  1422.     shm->has_pixmaps = has_pixmap ? MIN_PIXMAP_SIZE : 0;
  1423.     cairo_list_init (&shm->pool);
  1424.  
  1425.     cairo_list_init (&shm->surfaces);
  1426.  
  1427.     display->shm = shm;
  1428. }
  1429.  
  1430. void
  1431. _cairo_xlib_display_fini_shm (cairo_xlib_display_t *display)
  1432. {
  1433.     cairo_xlib_shm_display_t *shm = display->shm;
  1434.  
  1435.     if (shm == NULL)
  1436.         return;
  1437.  
  1438.     while (!cairo_list_is_empty (&shm->surfaces))
  1439.         cairo_surface_finish (&cairo_list_first_entry (&shm->surfaces,
  1440.                                                        cairo_xlib_shm_surface_t,
  1441.                                                        link)->image.base);
  1442.  
  1443.     _pqueue_fini (&shm->info);
  1444.  
  1445.     while (!cairo_list_is_empty (&shm->pool)) {
  1446.         cairo_xlib_shm_t *pool;
  1447.  
  1448.         pool = cairo_list_first_entry (&shm->pool, cairo_xlib_shm_t, link);
  1449.         _cairo_xlib_display_shm_pool_destroy (display, pool);
  1450.     }
  1451.  
  1452.     if (display->display)
  1453.         XDestroyWindow (display->display, shm->window);
  1454.  
  1455.     free (shm);
  1456.     display->shm = NULL;
  1457. }
  1458. #endif
  1459. #endif
  1460.