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
    display->shm = NULL;
49
}
50

            
51
cairo_surface_t *
52
_cairo_xlib_surface_get_shm (cairo_xlib_surface_t *surface,
53
			     cairo_bool_t overwrite)
54
{
55
    return NULL;
56
}
57

            
58
cairo_int_status_t
59
_cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface)
60
{
61
    assert (!surface->fallback);
62
    return CAIRO_INT_STATUS_SUCCESS;
63
}
64

            
65
cairo_surface_t *
66
_cairo_xlib_surface_create_shm (cairo_xlib_surface_t *other,
67
				pixman_format_code_t format,
68
				int width, int height)
69
{
70
    return NULL;
71
}
72

            
73
cairo_surface_t *
74
_cairo_xlib_surface_create_shm__image (cairo_xlib_surface_t *surface,
75
				       pixman_format_code_t format,
76
				       int width, int height)
77
{
78
    return NULL;
79
}
80

            
81
cairo_surface_t *
82
_cairo_xlib_surface_create_similar_shm (void *other,
83
					cairo_format_t format,
84
					int width, int height)
85
{
86
    return cairo_image_surface_create (format, width, height);
87
}
88

            
89
void
90
_cairo_xlib_shm_surface_mark_active (cairo_surface_t *_shm)
91
{
92
    ASSERT_NOT_REACHED;
93
}
94

            
95
void
96
_cairo_xlib_shm_surface_get_ximage (cairo_surface_t *surface,
97
				    XImage *ximage)
98
{
99
    ASSERT_NOT_REACHED;
100
}
101

            
102
void *
103
_cairo_xlib_shm_surface_get_obdata (cairo_surface_t *surface)
104
{
105
    ASSERT_NOT_REACHED;
106
    return NULL;
107
}
108

            
109
Pixmap
110
_cairo_xlib_shm_surface_get_pixmap (cairo_surface_t *surface)
111
{
112
    ASSERT_NOT_REACHED;
113
    return 0;
114
}
115

            
116
XRenderPictFormat *
117
_cairo_xlib_shm_surface_get_xrender_format (cairo_surface_t *surface)
118
{
119
    ASSERT_NOT_REACHED;
120
    return NULL;
121
}
122

            
123
cairo_bool_t
124
_cairo_xlib_shm_surface_is_active (cairo_surface_t *surface)
125
{
126
    ASSERT_NOT_REACHED;
127
    return FALSE;
128
}
129

            
130
cairo_bool_t
131
_cairo_xlib_shm_surface_is_idle (cairo_surface_t *surface)
132
{
133
    ASSERT_NOT_REACHED;
134
    return TRUE;
135
}
136

            
137
void _cairo_xlib_display_fini_shm (cairo_xlib_display_t *display) {}
138

            
139
#else
140

            
141
#include "cairo-damage-private.h"
142
#include "cairo-default-context-private.h"
143
#include "cairo-image-surface-private.h"
144
#include "cairo-list-inline.h"
145
#include "cairo-mempool-private.h"
146

            
147
#include <X11/Xlibint.h>
148
#include <X11/Xproto.h>
149
#include <X11/extensions/XShm.h>
150
#if HAVE_X11_EXTENSIONS_SHMPROTO_H
151
#include <X11/extensions/shmproto.h>
152
#elif HAVE_X11_EXTENSIONS_SHMSTR_H
153
#include <X11/extensions/shmstr.h>
154
#endif
155
#include <sys/ipc.h>
156
#include <sys/shm.h>
157

            
158
#define MIN_PIXMAP_SIZE 4096
159

            
160
#define MIN_BITS 8
161
#define MIN_SIZE (1<<(MIN_BITS-1))
162

            
163
typedef struct _cairo_xlib_shm cairo_xlib_shm_t;
164
typedef struct _cairo_xlib_shm_info cairo_xlib_shm_info_t;
165
typedef struct _cairo_xlib_shm_surface cairo_xlib_shm_surface_t;
166

            
167
struct _cairo_xlib_shm {
168
    cairo_mempool_t mem;
169

            
170
    XShmSegmentInfo shm;
171
    unsigned long attached;
172
    cairo_list_t link;
173
};
174

            
175
struct _cairo_xlib_shm_info {
176
    unsigned long last_request;
177
    void *mem;
178
    size_t size;
179
    cairo_xlib_shm_t *pool;
180
};
181

            
182
struct _cairo_xlib_shm_surface {
183
    cairo_image_surface_t image;
184

            
185
    cairo_list_t link;
186
    cairo_xlib_shm_info_t *info;
187
    Pixmap pixmap;
188
    unsigned long active;
189
    int idle;
190
};
191

            
192
/* the parent is always given by index/2 */
193
#define PQ_PARENT_INDEX(i) ((i) >> 1)
194
#define PQ_FIRST_ENTRY 1
195

            
196
/* left and right children are index * 2 and (index * 2) +1 respectively */
197
#define PQ_LEFT_CHILD_INDEX(i) ((i) << 1)
198

            
199
#define PQ_TOP(pq) ((pq)->elements[PQ_FIRST_ENTRY])
200

            
201
struct pqueue {
202
    int size, max_size;
203
    cairo_xlib_shm_info_t **elements;
204
};
205

            
206
struct _cairo_xlib_shm_display {
207
    int has_pixmaps;
208
    int opcode;
209
    int event;
210

            
211
    Window window;
212
    unsigned long last_request;
213
    unsigned long last_event;
214

            
215
    cairo_list_t surfaces;
216

            
217
    cairo_list_t pool;
218
    struct pqueue info;
219
};
220

            
221
static inline cairo_bool_t
222
3
seqno_passed (unsigned long a, unsigned long b)
223
{
224
3
    return (long)(b - a) >= 0;
225
}
226

            
227
static inline cairo_bool_t
228
seqno_before (unsigned long a, unsigned long b)
229
{
230
    return (long)(b - a) > 0;
231
}
232

            
233
static inline cairo_bool_t
234
seqno_after (unsigned long a, unsigned long b)
235
{
236
    return (long)(a - b) > 0;
237
}
238

            
239
static inline cairo_status_t
240
4
_pqueue_init (struct pqueue *pq)
241
{
242
4
    pq->max_size = 32;
243
4
    pq->size = 0;
244

            
245
4
    pq->elements = _cairo_malloc_ab (pq->max_size,
246
				     sizeof (cairo_xlib_shm_info_t *));
247
4
    if (unlikely (pq->elements == NULL))
248
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
249

            
250
4
    PQ_TOP(pq) = NULL;
251
4
    return CAIRO_STATUS_SUCCESS;
252
}
253

            
254
static inline void
255
4
_pqueue_fini (struct pqueue *pq)
256
{
257
4
    free (pq->elements);
258
4
}
259

            
260
static cairo_status_t
261
_pqueue_grow (struct pqueue *pq)
262
{
263
    cairo_xlib_shm_info_t **new_elements;
264

            
265
    new_elements = _cairo_realloc_ab (pq->elements,
266
				      2 * pq->max_size,
267
				      sizeof (cairo_xlib_shm_info_t *));
268
    if (unlikely (new_elements == NULL))
269
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
270

            
271
    pq->elements = new_elements;
272
    pq->max_size *= 2;
273
    return CAIRO_STATUS_SUCCESS;
274
}
275

            
276
static void
277
_pqueue_shrink (struct pqueue *pq, int min_size)
278
{
279
    cairo_xlib_shm_info_t **new_elements;
280

            
281
    if (min_size > pq->max_size)
282
	return;
283

            
284
    new_elements = _cairo_realloc_ab (pq->elements,
285
				      min_size,
286
				      sizeof (cairo_xlib_shm_info_t *));
287
    if (unlikely (new_elements == NULL))
288
	return;
289

            
290
    pq->elements = new_elements;
291
    pq->max_size = min_size;
292
}
293

            
294
static inline cairo_status_t
295
_pqueue_push (struct pqueue *pq, cairo_xlib_shm_info_t *info)
296
{
297
    cairo_xlib_shm_info_t **elements;
298
    int i, parent;
299

            
300
    if (unlikely (pq->size + 1 == pq->max_size)) {
301
	cairo_status_t status;
302

            
303
	status = _pqueue_grow (pq);
304
	if (unlikely (status))
305
	    return status;
306
    }
307

            
308
    elements = pq->elements;
309

            
310
    for (i = ++pq->size;
311
	 i != PQ_FIRST_ENTRY &&
312
	 info->last_request < elements[parent = PQ_PARENT_INDEX (i)]->last_request;
313
	 i = parent)
314
    {
315
	elements[i] = elements[parent];
316
    }
317

            
318
    elements[i] = info;
319

            
320
    return CAIRO_STATUS_SUCCESS;
321
}
322

            
323
static inline void
324
_pqueue_pop (struct pqueue *pq)
325
{
326
    cairo_xlib_shm_info_t **elements = pq->elements;
327
    cairo_xlib_shm_info_t *tail;
328
    int child, i;
329

            
330
    tail = elements[pq->size--];
331
    if (pq->size == 0) {
332
	elements[PQ_FIRST_ENTRY] = NULL;
333
	_pqueue_shrink (pq, 32);
334
	return;
335
    }
336

            
337
    for (i = PQ_FIRST_ENTRY;
338
	 (child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size;
339
	 i = child)
340
    {
341
	if (child != pq->size &&
342
	    elements[child+1]->last_request < elements[child]->last_request)
343
	{
344
	    child++;
345
	}
346

            
347
	if (elements[child]->last_request >= tail->last_request)
348
	    break;
349

            
350
	elements[i] = elements[child];
351
    }
352
    elements[i] = tail;
353
}
354

            
355
static cairo_bool_t _x_error_occurred;
356

            
357
static int
358
_check_error_handler (Display     *display,
359
		     XErrorEvent *event)
360
{
361
    _x_error_occurred = TRUE;
362
    return False; /* ignored */
363
}
364

            
365
static cairo_bool_t
366
4
can_use_shm (Display *dpy, int *has_pixmap)
367
{
368
    XShmSegmentInfo shm;
369
    int (*old_handler) (Display *display, XErrorEvent *event);
370
    Status success;
371
    int major, minor;
372

            
373
4
    if (! XShmQueryExtension (dpy))
374
	return FALSE;
375

            
376
4
    XShmQueryVersion (dpy, &major, &minor, has_pixmap);
377

            
378
4
    shm.shmid = shmget (IPC_PRIVATE, 0x1000, IPC_CREAT | 0600);
379
4
    if (shm.shmid == -1)
380
	return FALSE;
381

            
382
4
    shm.readOnly = FALSE;
383
4
    shm.shmaddr = shmat (shm.shmid, NULL, 0);
384
4
    if (shm.shmaddr == (char *) -1) {
385
	shmctl (shm.shmid, IPC_RMID, NULL);
386
	return FALSE;
387
    }
388

            
389
    assert (CAIRO_MUTEX_IS_LOCKED (_cairo_xlib_display_mutex));
390
4
    _x_error_occurred = FALSE;
391

            
392
4
    XLockDisplay (dpy);
393
4
    XSync (dpy, False);
394
4
    old_handler = XSetErrorHandler (_check_error_handler);
395

            
396
4
    success = XShmAttach (dpy, &shm);
397
4
    if (success)
398
4
	XShmDetach (dpy, &shm);
399

            
400
4
    XSync (dpy, False);
401
4
    XSetErrorHandler (old_handler);
402
4
    XUnlockDisplay (dpy);
403

            
404
4
    shmctl (shm.shmid, IPC_RMID, NULL);
405
4
    shmdt (shm.shmaddr);
406

            
407
4
    return success && ! _x_error_occurred;
408
}
409

            
410
static inline Display *
411
peek_display (cairo_device_t *device)
412
{
413
    return ((cairo_xlib_display_t *)device)->display;
414
}
415

            
416
static inline unsigned long
417
peek_processed (cairo_device_t *device)
418
{
419
    return LastKnownRequestProcessed (peek_display(device));
420
}
421

            
422
static void
423
3
_cairo_xlib_display_shm_pool_destroy (cairo_xlib_display_t *display,
424
				      cairo_xlib_shm_t *pool)
425
{
426
3
    shmdt (pool->shm.shmaddr);
427
3
    if (display->display) /* may be called after CloseDisplay */
428
3
	XShmDetach (display->display, &pool->shm);
429

            
430
3
    _cairo_mempool_fini (&pool->mem);
431

            
432
3
    cairo_list_del (&pool->link);
433
3
    free (pool);
434
3
}
435

            
436
static void send_event(cairo_xlib_display_t *display,
437
		       cairo_xlib_shm_info_t *info,
438
		       unsigned long seqno)
439
{
440
    XShmCompletionEvent ev;
441

            
442
    if (! seqno_after (seqno, display->shm->last_event))
443
	return;
444

            
445
    ev.type = display->shm->event;
446
    ev.send_event = 1; /* XXX or lie? */
447
    ev.serial = XNextRequest (display->display);
448
    ev.drawable = display->shm->window;
449
    ev.major_code = display->shm->opcode;
450
    ev.minor_code = X_ShmPutImage;
451
    ev.shmseg = info->pool->shm.shmid;
452
    ev.offset = (char *)info->mem - (char *)info->pool->shm.shmaddr;
453

            
454
    XSendEvent (display->display, ev.drawable, False, 0, (XEvent *)&ev);
455

            
456
    display->shm->last_event = ev.serial;
457
}
458

            
459
3
static void _cairo_xlib_display_sync (cairo_xlib_display_t *display)
460
{
461
    cairo_xlib_shm_info_t *info;
462
3
    struct pqueue *pq = &display->shm->info;
463

            
464
3
    XSync (display->display, False);
465

            
466
3
    while ((info = PQ_TOP(pq))) {
467
	_cairo_mempool_free (&info->pool->mem, info->mem);
468
	_pqueue_pop (&display->shm->info);
469
	free (info);
470
    }
471
3
}
472

            
473
static void
474
3
_cairo_xlib_shm_info_cleanup (cairo_xlib_display_t *display)
475
{
476
    cairo_xlib_shm_info_t *info;
477
3
    Display *dpy = display->display;
478
3
    struct pqueue *pq = &display->shm->info;
479
    unsigned long processed;
480

            
481
3
    if (PQ_TOP(pq) == NULL)
482
3
	return;
483

            
484
    XEventsQueued (dpy, QueuedAfterReading);
485
    processed = LastKnownRequestProcessed (dpy);
486

            
487
    info = PQ_TOP(pq);
488
    do {
489
	if (! seqno_passed (info->last_request, processed)) {
490
	    send_event (display, info, display->shm->last_request);
491
	    return;
492
	}
493

            
494
	_cairo_mempool_free (&info->pool->mem, info->mem);
495
	_pqueue_pop (&display->shm->info);
496
	free (info);
497
    } while ((info = PQ_TOP(pq)));
498
}
499

            
500
static cairo_xlib_shm_t *
501
3
_cairo_xlib_shm_info_find (cairo_xlib_display_t *display, size_t size,
502
			   void **ptr, unsigned long *last_request)
503
{
504
    cairo_xlib_shm_info_t *info;
505
3
    struct pqueue *pq = &display->shm->info;
506

            
507
3
    if (PQ_TOP(pq) == NULL)
508
3
	return NULL;
509

            
510
    info = PQ_TOP(pq);
511
    do {
512
	cairo_xlib_shm_t *pool = info->pool;
513

            
514
	*last_request = info->last_request;
515

            
516
	_pqueue_pop (&display->shm->info);
517
	_cairo_mempool_free (&pool->mem, info->mem);
518
	free (info);
519

            
520
	if (pool->mem.free_bytes >= size) {
521
	    void *mem = _cairo_mempool_alloc (&pool->mem, size);
522
	    if (mem != NULL) {
523
		*ptr = mem;
524
		return pool;
525
	    }
526
	}
527
    } while ((info = PQ_TOP(pq)));
528

            
529
    return NULL;
530
}
531

            
532
static cairo_xlib_shm_t *
533
3
_cairo_xlib_shm_pool_find (cairo_xlib_display_t *display,
534
			   size_t size,
535
			   void **ptr)
536
{
537
    cairo_xlib_shm_t *pool;
538

            
539
3
    cairo_list_foreach_entry (pool, cairo_xlib_shm_t, &display->shm->pool, link) {
540
	if (pool->mem.free_bytes >= size) {
541
	    void *mem = _cairo_mempool_alloc (&pool->mem, size);
542
	    if (mem != NULL) {
543
		*ptr = mem;
544
		return pool;
545
	    }
546
	}
547
    }
548

            
549
3
    return NULL;
550
}
551

            
552
static void
553
6
_cairo_xlib_shm_pool_cleanup (cairo_xlib_display_t *display)
554
{
555
    cairo_xlib_shm_t *pool, *next;
556
    unsigned long processed;
557

            
558
6
    processed = LastKnownRequestProcessed (display->display);
559

            
560
9
    cairo_list_foreach_entry_safe (pool, next, cairo_xlib_shm_t,
561
				   &display->shm->pool, link) {
562
3
	if (! seqno_passed (pool->attached, processed))
563
	    break;
564

            
565
3
	if (pool->mem.free_bytes == pool->mem.max_bytes)
566
3
	    _cairo_xlib_display_shm_pool_destroy (display, pool);
567
    }
568
6
}
569

            
570
static cairo_xlib_shm_t *
571
3
_cairo_xlib_shm_pool_create(cairo_xlib_display_t *display,
572
			    size_t size, void **ptr)
573
{
574
3
    Display *dpy = display->display;
575
    cairo_xlib_shm_t *pool;
576
3
    size_t bytes, maxbits = 16, minbits = MIN_BITS;
577
    Status success;
578

            
579
3
    pool = _cairo_calloc (sizeof (cairo_xlib_shm_t));
580
3
    if (pool == NULL)
581
	return NULL;
582

            
583
3
    bytes = 1 << maxbits;
584
18
    while (bytes <= size)
585
15
	bytes <<= 1, maxbits++;
586
3
    bytes <<= 3;
587

            
588
3
    minbits += (maxbits - 16) / 2;
589

            
590
3
    pool->shm.shmid = shmget (IPC_PRIVATE, bytes, IPC_CREAT | 0600);
591
3
    while (pool->shm.shmid == -1 && bytes >= 2*size) {
592
	bytes >>= 1;
593
	pool->shm.shmid = shmget (IPC_PRIVATE, bytes, IPC_CREAT | 0600);
594
    }
595
3
    if (pool->shm.shmid == -1)
596
	goto cleanup;
597

            
598
3
    pool->shm.readOnly = FALSE;
599
3
    pool->shm.shmaddr = shmat (pool->shm.shmid, NULL, 0);
600
3
    if (pool->shm.shmaddr == (char *) -1) {
601
	shmctl (pool->shm.shmid, IPC_RMID, NULL);
602
	goto cleanup;
603
    }
604

            
605
3
    pool->attached = XNextRequest (dpy);
606
3
    success = XShmAttach (dpy, &pool->shm);
607
#if !IPC_RMID_DEFERRED_RELEASE
608
    XSync (dpy, FALSE);
609
#endif
610
3
    shmctl (pool->shm.shmid, IPC_RMID, NULL);
611

            
612
3
    if (! success)
613
	goto cleanup_shm;
614

            
615
3
    if (_cairo_mempool_init (&pool->mem, pool->shm.shmaddr, bytes,
616
3
			     minbits, maxbits - minbits + 1))
617
	goto cleanup_detach;
618

            
619
3
    cairo_list_add (&pool->link, &display->shm->pool);
620

            
621
3
    *ptr = _cairo_mempool_alloc (&pool->mem, size);
622
3
    assert (*ptr != NULL);
623
3
    return pool;
624

            
625
cleanup_detach:
626
    XShmDetach (dpy, &pool->shm);
627
cleanup_shm:
628
    shmdt (pool->shm.shmaddr);
629
cleanup:
630
    free (pool);
631
    return NULL;
632
}
633

            
634
static cairo_xlib_shm_info_t *
635
3
_cairo_xlib_shm_info_create (cairo_xlib_display_t *display,
636
			     size_t size, cairo_bool_t will_sync)
637
{
638
    cairo_xlib_shm_info_t *info;
639
    cairo_xlib_shm_t *pool;
640
3
    unsigned long last_request = 0;
641
3
    void *mem = NULL;
642

            
643
3
    _cairo_xlib_shm_info_cleanup (display);
644
3
    pool = _cairo_xlib_shm_pool_find (display, size, &mem);
645
3
    _cairo_xlib_shm_pool_cleanup (display);
646

            
647
3
    if (pool == NULL && will_sync)
648
3
	pool = _cairo_xlib_shm_info_find (display, size, &mem, &last_request);
649
3
    if (pool == NULL)
650
3
	pool = _cairo_xlib_shm_pool_create (display, size, &mem);
651
3
    if (pool == NULL)
652
	return NULL;
653

            
654
3
    assert (mem != NULL);
655

            
656
3
    info = _cairo_calloc (sizeof (*info));
657
3
    if (info == NULL) {
658
	_cairo_mempool_free (&pool->mem, mem);
659
	return NULL;
660
    }
661

            
662
3
    info->pool = pool;
663
3
    info->mem = mem;
664
3
    info->size = size;
665
3
    info->last_request = last_request;
666

            
667
3
    return info;
668
}
669

            
670
static cairo_status_t
671
6
_cairo_xlib_shm_surface_flush (void *abstract_surface, unsigned flags)
672
{
673
6
    cairo_xlib_shm_surface_t *shm = abstract_surface;
674
    cairo_xlib_display_t *display;
675
    Display *dpy;
676
    cairo_status_t status;
677

            
678
6
    if (shm->active == 0)
679
6
	return CAIRO_STATUS_SUCCESS;
680

            
681
    if (shm->image.base._finishing)
682
	return CAIRO_STATUS_SUCCESS;
683

            
684
    if (seqno_passed (shm->active, peek_processed (shm->image.base.device))) {
685
	shm->active = 0;
686
	return CAIRO_STATUS_SUCCESS;
687
    }
688

            
689
    status = _cairo_xlib_display_acquire (shm->image.base.device, &display);
690
    if (unlikely (status))
691
	return status;
692

            
693
    send_event (display, shm->info, shm->active);
694

            
695
    dpy = display->display;
696
    XEventsQueued (dpy, QueuedAfterReading);
697
    while (! seqno_passed (shm->active, LastKnownRequestProcessed (dpy))) {
698
	LockDisplay(dpy);
699
	_XReadEvents(dpy);
700
	UnlockDisplay(dpy);
701
    }
702

            
703
    cairo_device_release (&display->base);
704
    shm->active = 0;
705

            
706
    return CAIRO_STATUS_SUCCESS;
707
}
708

            
709
static inline cairo_bool_t
710
3
active (cairo_xlib_shm_surface_t *shm, Display *dpy)
711
{
712
3
    return (shm->active &&
713
	    ! seqno_passed (shm->active, LastKnownRequestProcessed (dpy)));
714
}
715

            
716
static cairo_status_t
717
3
_cairo_xlib_shm_surface_finish (void *abstract_surface)
718
{
719
3
    cairo_xlib_shm_surface_t *shm = abstract_surface;
720
    cairo_xlib_display_t *display;
721
    cairo_status_t status;
722

            
723
3
    if (shm->image.base.damage) {
724
3
	_cairo_damage_destroy (shm->image.base.damage);
725
3
	shm->image.base.damage = _cairo_damage_create_in_error (CAIRO_STATUS_SURFACE_FINISHED);
726
    }
727

            
728
3
    status = _cairo_xlib_display_acquire (shm->image.base.device, &display);
729
3
    if (unlikely (status))
730
	return status;
731

            
732
3
    if (shm->pixmap)
733
3
	XFreePixmap (display->display, shm->pixmap);
734

            
735
3
    if (active (shm, display->display)) {
736
	shm->info->last_request = shm->active;
737
	_pqueue_push (&display->shm->info, shm->info);
738
	if (seqno_before (display->shm->last_request, shm->active))
739
	    display->shm->last_request = shm->active;
740
    } else {
741
3
	_cairo_mempool_free (&shm->info->pool->mem, shm->info->mem);
742
3
	free (shm->info);
743

            
744
3
	_cairo_xlib_shm_pool_cleanup (display);
745
    }
746

            
747
3
    cairo_list_del (&shm->link);
748

            
749
3
    cairo_device_release (&display->base);
750
3
    return _cairo_image_surface_finish (abstract_surface);
751
}
752

            
753
static const cairo_surface_backend_t cairo_xlib_shm_surface_backend = {
754
    CAIRO_SURFACE_TYPE_IMAGE,
755
    _cairo_xlib_shm_surface_finish,
756

            
757
    _cairo_default_context_create,
758

            
759
    _cairo_image_surface_create_similar,
760
    NULL, /* create similar image */
761
    _cairo_image_surface_map_to_image,
762
    _cairo_image_surface_unmap_image,
763

            
764
    _cairo_image_surface_source,
765
    _cairo_image_surface_acquire_source_image,
766
    _cairo_image_surface_release_source_image,
767
    _cairo_image_surface_snapshot,
768

            
769
    NULL, /* copy_page */
770
    NULL, /* show_page */
771

            
772
    _cairo_image_surface_get_extents,
773
    _cairo_image_surface_get_font_options,
774

            
775
    _cairo_xlib_shm_surface_flush,
776
    NULL,
777

            
778
    _cairo_image_surface_paint,
779
    _cairo_image_surface_mask,
780
    _cairo_image_surface_stroke,
781
    _cairo_image_surface_fill,
782
    NULL, /* fill-stroke */
783
    _cairo_image_surface_glyphs,
784
};
785

            
786
static cairo_bool_t
787
has_shm (cairo_xlib_surface_t *surface)
788
{
789
    cairo_xlib_display_t *display = (cairo_xlib_display_t *)surface->base.device;
790
    return display->shm != NULL;
791
}
792

            
793
static int
794
3
has_shm_pixmaps (cairo_xlib_surface_t *surface)
795
{
796
3
    cairo_xlib_display_t *display = (cairo_xlib_display_t *)surface->base.device;
797
3
    if (!display->shm)
798
	return 0;
799

            
800
3
    return display->shm->has_pixmaps;
801
}
802

            
803
static cairo_xlib_shm_surface_t *
804
3
_cairo_xlib_shm_surface_create (cairo_xlib_surface_t *other,
805
				pixman_format_code_t format,
806
				int width, int height,
807
				cairo_bool_t will_sync,
808
				int create_pixmap)
809
{
810
    cairo_xlib_shm_surface_t *shm;
811
    cairo_xlib_display_t *display;
812
    pixman_image_t *image;
813
    int stride, size;
814

            
815
3
    if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
816
	return NULL;
817

            
818
3
    stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP(format));
819
3
    size = stride * height;
820
3
    if (size < MIN_SIZE)
821
	return NULL;
822

            
823
3
    shm = _cairo_calloc (sizeof (*shm));
824
3
    if (unlikely (shm == NULL))
825
	return (cairo_xlib_shm_surface_t *)_cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
826

            
827
3
    _cairo_surface_init (&shm->image.base,
828
			 &cairo_xlib_shm_surface_backend,
829
			 other->base.device,
830
			 _cairo_content_from_pixman_format (format),
831
			 FALSE); /* is_vector */
832

            
833
3
    if (_cairo_xlib_display_acquire (other->base.device, &display))
834
	goto cleanup_shm;
835

            
836
3
    shm->info = _cairo_xlib_shm_info_create (display, size, will_sync);
837
3
    if (shm->info == NULL)
838
	goto cleanup_display;
839

            
840
3
    image = pixman_image_create_bits (format, width, height,
841
3
				      (uint32_t *) shm->info->mem, stride);
842
3
    if (image == NULL)
843
	goto cleanup_info;
844

            
845
3
    _cairo_image_surface_init (&shm->image, image, format);
846

            
847
3
    shm->pixmap = 0;
848
3
    if (create_pixmap && size >= create_pixmap) {
849
3
	shm->pixmap = XShmCreatePixmap (display->display,
850
					other->drawable,
851
3
					shm->info->mem,
852
3
					&shm->info->pool->shm,
853
3
					shm->image.width,
854
3
					shm->image.height,
855
3
					shm->image.depth);
856
    }
857
3
    shm->active = shm->info->last_request;
858
3
    shm->idle = -5;
859

            
860
3
    assert (shm->active == 0 || will_sync);
861

            
862
3
    cairo_list_add (&shm->link, &display->shm->surfaces);
863

            
864
3
    cairo_device_release (&display->base);
865

            
866
3
    return shm;
867

            
868
cleanup_info:
869
    _cairo_mempool_free (&shm->info->pool->mem, shm->info->mem);
870
    free(shm->info);
871
cleanup_display:
872
    cairo_device_release (&display->base);
873
cleanup_shm:
874
    free (shm);
875
    return NULL;
876
}
877

            
878
static void
879
3
_cairo_xlib_surface_update_shm (cairo_xlib_surface_t *surface)
880
{
881
3
    cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface->shm;
882
    cairo_xlib_display_t *display;
883
    cairo_damage_t *damage;
884
    GC gc;
885

            
886
3
    damage = _cairo_damage_reduce (surface->base.damage);
887
3
    surface->base.damage = _cairo_damage_create();
888

            
889
3
    if (_cairo_xlib_display_acquire (surface->base.device, &display))
890
	goto cleanup_damage;
891

            
892
3
    if (_cairo_xlib_surface_get_gc (display, surface, &gc))
893
	goto cleanup_display;
894

            
895
3
    if (! surface->owns_pixmap) {
896
	XGCValues gcv;
897

            
898
	gcv.subwindow_mode = IncludeInferiors;
899
	XChangeGC (display->display, gc, GCSubwindowMode, &gcv);
900
    }
901

            
902
3
    if (damage->region) {
903
	XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
904
3
	XRectangle *rects = stack_rects;
905
	cairo_rectangle_int_t r;
906
	int n_rects, i;
907

            
908
3
	n_rects = cairo_region_num_rectangles (damage->region);
909
3
	if (n_rects == 0) {
910
3
	} else if (n_rects == 1) {
911
3
	    cairo_region_get_rectangle (damage->region, 0, &r);
912
3
	    XCopyArea (display->display,
913
		       surface->drawable, shm->pixmap, gc,
914
		       r.x, r.y,
915
3
		       r.width, r.height,
916
		       r.x, r.y);
917
	} else {
918
	    if (n_rects > ARRAY_LENGTH (stack_rects)) {
919
		rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
920
		if (unlikely (rects == NULL)) {
921
		    rects = stack_rects;
922
		    n_rects = ARRAY_LENGTH (stack_rects);
923
		}
924
	    }
925
	    for (i = 0; i < n_rects; i++) {
926
		cairo_region_get_rectangle (damage->region, i, &r);
927

            
928
		rects[i].x = r.x;
929
		rects[i].y = r.y;
930
		rects[i].width  = r.width;
931
		rects[i].height = r.height;
932
	    }
933
	    XSetClipRectangles (display->display, gc, 0, 0, rects, i, YXBanded);
934

            
935
	    XCopyArea (display->display,
936
		       surface->drawable, shm->pixmap, gc,
937
		       0, 0,
938
		       shm->image.width, shm->image.height,
939
		       0, 0);
940

            
941
	    if (damage->status == CAIRO_STATUS_SUCCESS && damage->region)
942
		XSetClipMask (display->display, gc, None);
943
	}
944
    } else {
945
	XCopyArea (display->display,
946
		   surface->drawable, shm->pixmap, gc,
947
		   0, 0,
948
		   shm->image.width, shm->image.height,
949
		   0, 0);
950
    }
951

            
952
3
    if (! surface->owns_pixmap) {
953
	XGCValues gcv;
954

            
955
	gcv.subwindow_mode = ClipByChildren;
956
	XChangeGC (display->display, gc, GCSubwindowMode, &gcv);
957
    }
958

            
959
3
    _cairo_xlib_display_sync (display);
960
3
    shm->active = 0;
961
3
    shm->idle--;
962

            
963
3
    _cairo_xlib_surface_put_gc (display, surface, gc);
964
3
cleanup_display:
965
3
    cairo_device_release (&display->base);
966
3
cleanup_damage:
967
3
    _cairo_damage_destroy (damage);
968
3
}
969

            
970
static void
971
_cairo_xlib_surface_clear_shm (cairo_xlib_surface_t *surface)
972
{
973
    cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface->shm;
974

            
975
    assert (shm->active == 0);
976

            
977
    _cairo_damage_destroy (surface->base.damage);
978
    surface->base.damage = _cairo_damage_create();
979

            
980
    memset (shm->image.data, 0, shm->image.stride * shm->image.height);
981
    shm->image.base.is_clear = TRUE;
982
}
983

            
984
3
static void inc_idle (cairo_surface_t *surface)
985
{
986
3
    cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface;
987
3
    shm->idle++;
988
3
}
989

            
990
3
static void dec_idle (cairo_surface_t *surface)
991
{
992
3
    cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface;
993
3
    shm->idle--;
994
3
}
995

            
996
cairo_surface_t *
997
3
_cairo_xlib_surface_get_shm (cairo_xlib_surface_t *surface,
998
			     cairo_bool_t overwrite)
999
{
3
    if (surface->fallback) {
	assert (surface->base.damage);
	assert (surface->shm);
	assert (surface->shm->damage);
	goto done;
    }
3
    if (surface->shm == NULL) {
	pixman_format_code_t pixman_format;
	cairo_bool_t will_sync;
3
	if (! has_shm_pixmaps (surface))
	    return NULL;
3
	if ((surface->width | surface->height) < 32)
	    return NULL;
3
	pixman_format = _pixman_format_for_xlib_surface (surface);
3
	if (pixman_format == 0)
	    return NULL;
3
	will_sync = !surface->base.is_clear && !overwrite;
3
	surface->shm =
3
	    &_cairo_xlib_shm_surface_create (surface, pixman_format,
					     surface->width, surface->height,
					     will_sync, 1)->image.base;
3
	if (surface->shm == NULL)
	    return NULL;
3
	assert (surface->base.damage == NULL);
3
	if (surface->base.serial || !surface->owns_pixmap) {
	    cairo_rectangle_int_t rect;
3
	    rect.x = rect.y = 0;
3
	    rect.width = surface->width;
3
	    rect.height = surface->height;
3
	    surface->base.damage =
3
		_cairo_damage_add_rectangle (NULL, &rect);
	} else
	    surface->base.damage = _cairo_damage_create ();
3
	surface->shm->damage = _cairo_damage_create ();
    }
3
    if (overwrite) {
	_cairo_damage_destroy (surface->base.damage);
	surface->base.damage = _cairo_damage_create ();
    }
3
    if (!surface->base.is_clear && surface->base.damage->dirty)
3
	_cairo_xlib_surface_update_shm (surface);
3
    _cairo_xlib_shm_surface_flush (surface->shm, 1);
3
    if (surface->base.is_clear && surface->base.damage->dirty)
	_cairo_xlib_surface_clear_shm (surface);
3
done:
3
    dec_idle(surface->shm);
3
    return surface->shm;
}
cairo_int_status_t
7
_cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface)
{
7
    cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
7
    if (!surface->fallback) {
7
	if (surface->shm)
3
	    inc_idle (surface->shm);
7
	return CAIRO_INT_STATUS_SUCCESS;
    }
    if (surface->shm->damage->dirty) {
	cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface->shm;
	cairo_xlib_display_t *display;
	cairo_damage_t *damage;
	GC gc;
	status = _cairo_xlib_display_acquire (surface->base.device, &display);
	if (unlikely (status))
	    return status;
	damage = _cairo_damage_reduce (shm->image.base.damage);
	shm->image.base.damage = _cairo_damage_create ();
	TRACE ((stderr, "%s: flushing damage x %d\n", __FUNCTION__,
		damage->region ? cairo_region_num_rectangles (damage->region) : 0));
	if (damage->status == CAIRO_STATUS_SUCCESS && damage->region) {
	    XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
	    XRectangle *rects = stack_rects;
	    cairo_rectangle_int_t r;
	    int n_rects, i;
	    n_rects = cairo_region_num_rectangles (damage->region);
	    if (n_rects == 0)
		goto out;
	    status = _cairo_xlib_surface_get_gc (display, surface, &gc);
	    if (unlikely (status))
		goto out;
	    if (n_rects == 1) {
		cairo_region_get_rectangle (damage->region, 0, &r);
		_cairo_xlib_shm_surface_mark_active (surface->shm);
		XCopyArea (display->display,
			   shm->pixmap, surface->drawable, gc,
			   r.x, r.y,
			   r.width, r.height,
			   r.x, r.y);
	    } else {
		if (n_rects > ARRAY_LENGTH (stack_rects)) {
		    rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
		    if (unlikely (rects == NULL)) {
			status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
			_cairo_xlib_surface_put_gc (display, surface, gc);
			goto out;
		    }
		}
		for (i = 0; i < n_rects; i++) {
		    cairo_region_get_rectangle (damage->region, i, &r);
		    rects[i].x = r.x;
		    rects[i].y = r.y;
		    rects[i].width  = r.width;
		    rects[i].height = r.height;
		}
		XSetClipRectangles (display->display, gc, 0, 0, rects, i, YXBanded);
		_cairo_xlib_shm_surface_mark_active (surface->shm);
		XCopyArea (display->display,
			   shm->pixmap, surface->drawable, gc,
			   0, 0,
			   shm->image.width, shm->image.height,
			   0, 0);
		if (damage->status == CAIRO_STATUS_SUCCESS && damage->region)
		    XSetClipMask (display->display, gc, None);
	    }
	    _cairo_xlib_surface_put_gc (display, surface, gc);
	}
out:
	_cairo_damage_destroy (damage);
	cairo_device_release (&display->base);
    }
    return status;
}
cairo_surface_t *
_cairo_xlib_surface_create_shm (cairo_xlib_surface_t *other,
				pixman_format_code_t format,
				int width, int height)
{
    cairo_surface_t *surface;
    surface = NULL;
    if (has_shm (other))
	surface = &_cairo_xlib_shm_surface_create (other, format, width, height,
						   FALSE, has_shm_pixmaps (other))->image.base;
    return surface;
}
cairo_surface_t *
_cairo_xlib_surface_create_shm__image (cairo_xlib_surface_t *surface,
				       pixman_format_code_t format,
				       int width, int height)
{
    if (! has_shm(surface))
	return NULL;
    return &_cairo_xlib_shm_surface_create (surface, format, width, height,
					    FALSE, 0)->image.base;
}
cairo_surface_t *
_cairo_xlib_surface_create_similar_shm (void *other,
					cairo_format_t format,
					int width, int height)
{
    cairo_surface_t *surface;
    surface = _cairo_xlib_surface_create_shm (other,
					      _cairo_format_to_pixman_format_code (format),
					      width, height);
    if (surface) {
	if (! surface->is_clear) {
	    cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface;
	    assert (shm->active == 0);
	    memset (shm->image.data, 0, shm->image.stride * shm->image.height);
	    shm->image.base.is_clear = TRUE;
	}
    } else
	surface = cairo_image_surface_create (format, width, height);
    return surface;
}
void
_cairo_xlib_shm_surface_mark_active (cairo_surface_t *_shm)
{
    cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) _shm;
    cairo_xlib_display_t *display = (cairo_xlib_display_t *) _shm->device;
    shm->active = XNextRequest (display->display);
}
void
_cairo_xlib_shm_surface_get_ximage (cairo_surface_t *surface,
				    XImage *ximage)
{
    cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface;
    int native_byte_order = _cairo_is_little_endian () ? LSBFirst : MSBFirst;
    cairo_format_masks_t image_masks;
    int ret;
    ret = _pixman_format_to_masks (shm->image.pixman_format, &image_masks);
    assert (ret);
    ximage->width = shm->image.width;
    ximage->height = shm->image.height;
    ximage->format = ZPixmap;
    ximage->data = (char *) shm->image.data;
    ximage->obdata = (char *)&shm->info->pool->shm;
    ximage->byte_order = native_byte_order;
    ximage->bitmap_unit = 32;	/* always for libpixman */
    ximage->bitmap_bit_order = native_byte_order;
    ximage->bitmap_pad = 32;	/* always for libpixman */
    ximage->depth = shm->image.depth;
    ximage->bytes_per_line = shm->image.stride;
    ximage->bits_per_pixel = image_masks.bpp;
    ximage->red_mask = image_masks.red_mask;
    ximage->green_mask = image_masks.green_mask;
    ximage->blue_mask = image_masks.blue_mask;
    ximage->xoffset = 0;
    ret = XInitImage (ximage);
    assert (ret != 0);
}
void *
_cairo_xlib_shm_surface_get_obdata (cairo_surface_t *surface)
{
    cairo_xlib_display_t *display = (cairo_xlib_display_t *) surface->device;
    cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface;
    display->shm->last_event = shm->active = XNextRequest (display->display);
    return &shm->info->pool->shm;
}
Pixmap
_cairo_xlib_shm_surface_get_pixmap (cairo_surface_t *surface)
{
    cairo_xlib_shm_surface_t *shm;
    shm = (cairo_xlib_shm_surface_t *) surface;
    return shm->pixmap;
}
XRenderPictFormat *
_cairo_xlib_shm_surface_get_xrender_format (cairo_surface_t *surface)
{
    cairo_xlib_shm_surface_t *shm;
    shm = (cairo_xlib_shm_surface_t *) surface;
    if (shm->image.format != CAIRO_FORMAT_INVALID)
	return _cairo_xlib_display_get_xrender_format ((cairo_xlib_display_t *)surface->device,
						       shm->image.format);
    return _cairo_xlib_display_get_xrender_format_for_pixman((cairo_xlib_display_t *)surface->device,
							     shm->image.pixman_format);
}
cairo_bool_t
_cairo_xlib_shm_surface_is_active (cairo_surface_t *surface)
{
    cairo_xlib_shm_surface_t *shm;
    shm = (cairo_xlib_shm_surface_t *) surface;
    if (shm->active == 0)
	return FALSE;
    if (seqno_passed (shm->active, peek_processed (shm->image.base.device))) {
	shm->active = 0;
	return FALSE;
    }
    return TRUE;
}
cairo_bool_t
3
_cairo_xlib_shm_surface_is_idle (cairo_surface_t *surface)
{
    cairo_xlib_shm_surface_t *shm;
3
    shm = (cairo_xlib_shm_surface_t *) surface;
3
    return shm->idle > 0;
}
#define XORG_VERSION_ENCODE(major,minor,patch,snap) \
    (((major) * 10000000) + ((minor) * 100000) + ((patch) * 1000) + snap)
static cairo_bool_t
4
has_broken_send_shm_event (cairo_xlib_display_t *display,
			   cairo_xlib_shm_display_t *shm)
{
4
    Display *dpy = display->display;
    int (*old_handler) (Display *display, XErrorEvent *event);
    XShmCompletionEvent ev;
    XShmSegmentInfo info;
4
    info.shmid = shmget (IPC_PRIVATE, 0x1000, IPC_CREAT | 0600);
4
    if (info.shmid == -1)
	return TRUE;
4
    info.readOnly = FALSE;
4
    info.shmaddr = shmat (info.shmid, NULL, 0);
4
    if (info.shmaddr == (char *) -1) {
	shmctl (info.shmid, IPC_RMID, NULL);
	return TRUE;
    }
4
    ev.type = shm->event;
4
    ev.send_event = 1;
4
    ev.serial = 1;
4
    ev.drawable = shm->window;
4
    ev.major_code = shm->opcode;
4
    ev.minor_code = X_ShmPutImage;
4
    ev.shmseg = info.shmid;
4
    ev.offset = 0;
    assert (CAIRO_MUTEX_IS_LOCKED (_cairo_xlib_display_mutex));
4
    _x_error_occurred = FALSE;
4
    XLockDisplay (dpy);
4
    XSync (dpy, False);
4
    old_handler = XSetErrorHandler (_check_error_handler);
4
    XShmAttach (dpy, &info);
4
    XSendEvent (dpy, ev.drawable, False, 0, (XEvent *)&ev);
4
    XShmDetach (dpy, &info);
4
    XSync (dpy, False);
4
    XSetErrorHandler (old_handler);
4
    XUnlockDisplay (dpy);
4
    shmctl (info.shmid, IPC_RMID, NULL);
4
    shmdt (info.shmaddr);
4
    return _x_error_occurred;
}
static cairo_bool_t
4
xorg_has_buggy_send_shm_completion_event(cairo_xlib_display_t *display,
					 cairo_xlib_shm_display_t *shm)
{
4
    Display *dpy = display->display;
    /* As libXext sets the SEND_EVENT bit in the ShmCompletionEvent,
     * the Xserver may crash if it does not take care when processing
     * the event type. For instance versions of Xorg prior to 1.11.1
     * exhibited this bug, and was fixed by:
     *
     * commit 2d2dce558d24eeea0eb011ec9ebaa6c5c2273c39
     * Author: Sam Spilsbury <sam.spilsbury@canonical.com>
     * Date:   Wed Sep 14 09:58:34 2011 +0800
     *
     * Remove the SendEvent bit (0x80) before doing range checks on event type.
     */
4
    if (_cairo_xlib_vendor_is_xorg (dpy) &&
4
	VendorRelease (dpy) < XORG_VERSION_ENCODE(1,11,0,1))
	return TRUE;
    /* For everyone else check that no error is generated */
4
    return has_broken_send_shm_event (display, shm);
}
void
4
_cairo_xlib_display_init_shm (cairo_xlib_display_t *display)
{
    cairo_xlib_shm_display_t *shm;
    XSetWindowAttributes attr;
    XExtCodes *codes;
    int has_pixmap, scr;
4
    display->shm = NULL;
4
    if (!can_use_shm (display->display, &has_pixmap))
	return;
4
    shm = _cairo_calloc (sizeof (*shm));
4
    if (unlikely (shm == NULL))
	return;
4
    codes = XInitExtension (display->display, SHMNAME);
4
    if (codes == NULL) {
	free (shm);
	return;
    }
4
    shm->opcode = codes ->major_opcode;
4
    shm->event = codes->first_event;
4
    if (unlikely (_pqueue_init (&shm->info))) {
	free (shm);
	return;
    }
4
    scr = DefaultScreen (display->display);
4
    attr.override_redirect = 1;
8
    shm->window = XCreateWindow (display->display,
4
				 DefaultRootWindow (display->display), -1, -1,
				 1, 1, 0,
4
				 DefaultDepth (display->display, scr),
				 InputOutput,
4
				 DefaultVisual (display->display, scr),
				 CWOverrideRedirect, &attr);
4
    shm->last_event = 0;
4
    shm->last_request = 0;
4
    if (xorg_has_buggy_send_shm_completion_event(display, shm))
	has_pixmap = 0;
4
    shm->has_pixmaps = has_pixmap ? MIN_PIXMAP_SIZE : 0;
4
    cairo_list_init (&shm->pool);
4
    cairo_list_init (&shm->surfaces);
4
    display->shm = shm;
}
void
4
_cairo_xlib_display_fini_shm (cairo_xlib_display_t *display)
{
4
    cairo_xlib_shm_display_t *shm = display->shm;
4
    if (shm == NULL)
	return;
7
    while (!cairo_list_is_empty (&shm->surfaces))
3
	cairo_surface_finish (&cairo_list_first_entry (&shm->surfaces,
						       cairo_xlib_shm_surface_t,
						       link)->image.base);
4
    _pqueue_fini (&shm->info);
4
    while (!cairo_list_is_empty (&shm->pool)) {
	cairo_xlib_shm_t *pool;
	pool = cairo_list_first_entry (&shm->pool, cairo_xlib_shm_t, link);
	_cairo_xlib_display_shm_pool_destroy (display, pool);
    }
4
    if (display->display)
4
	XDestroyWindow (display->display, shm->window);
4
    free (shm);
4
    display->shm = NULL;
}
#endif
#endif