Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 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 
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 
145
#include 
146
#include 
147
#if HAVE_X11_EXTENSIONS_SHMPROTO_H
148
#include 
149
#elif HAVE_X11_EXTENSIONS_SHMSTR_H
150
#include 
151
#endif
152
#include 
153
#include 
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 
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