summaryrefslogtreecommitdiff
path: root/src/cairo-xlib-surface-shm.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2012-10-26 10:51:31 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2012-10-26 10:59:05 +0100
commit00feb8ce530a472abbde445b52d9ae8c99ec97f0 (patch)
treeeee6d1abee726be8139a85fa83f2aa19981455b2 /src/cairo-xlib-surface-shm.c
parente43f53bf7f3d371116f31f22ab9754b08b5abe7f (diff)
downloadcairo-00feb8ce530a472abbde445b52d9ae8c99ec97f0.tar.gz
xlib/shm: Sanity check that the server handles XSendEvent with ShmCompletion
Uli Schlachter suggested it would be wiser to complement our blacklist of known broken X/libXext with an explicit roundtrip to check for a BadValue error return when we try to use XSendEvent. Suggested-by: Uli Schlachter <psychon@znc.in> Reported-by: Martin Husemann <martin@duskware.de> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'src/cairo-xlib-surface-shm.c')
-rw-r--r--src/cairo-xlib-surface-shm.c77
1 files changed, 69 insertions, 8 deletions
diff --git a/src/cairo-xlib-surface-shm.c b/src/cairo-xlib-surface-shm.c
index ec0d334ef..17594b166 100644
--- a/src/cairo-xlib-surface-shm.c
+++ b/src/cairo-xlib-surface-shm.c
@@ -1128,8 +1128,60 @@ _cairo_xlib_shm_surface_is_idle (cairo_surface_t *surface)
(((major) * 10000000) + ((minor) * 100000) + ((patch) * 1000) + snap)
static cairo_bool_t
-xorg_has_buggy_send_shm_completion_event(Display *dpy)
+has_broken_send_shm_event (cairo_xlib_display_t *display,
+ cairo_xlib_shm_display_t *shm)
{
+ Display *dpy = display->display;
+ int (*old_handler) (Display *display, XErrorEvent *event);
+ XShmCompletionEvent ev;
+ XShmSegmentInfo info;
+
+ info.shmid = shmget (IPC_PRIVATE, 0x1000, IPC_CREAT | 0600);
+ if (info.shmid == -1)
+ return TRUE;
+
+ info.readOnly = FALSE;
+ info.shmaddr = shmat (info.shmid, NULL, 0);
+ if (info.shmaddr == (char *) -1) {
+ shmctl (info.shmid, IPC_RMID, NULL);
+ return TRUE;
+ }
+
+ ev.type = shm->event;
+ ev.drawable = shm->window;
+ ev.major_code = shm->opcode;
+ ev.minor_code = X_ShmPutImage;
+
+ ev.shmseg = info.shmid;
+ ev.offset = 0;
+
+ assert (CAIRO_MUTEX_IS_LOCKED (_cairo_xlib_display_mutex));
+ _x_error_occurred = FALSE;
+
+ XLockDisplay (dpy);
+ XSync (dpy, False);
+ old_handler = XSetErrorHandler (_check_error_handler);
+
+ XShmAttach (dpy, &info);
+ XSendEvent (dpy, ev.drawable, False, 0, (XEvent *)&ev);
+ XShmDetach (dpy, &info);
+
+ XSync (dpy, False);
+ XSetErrorHandler (old_handler);
+ XUnlockDisplay (dpy);
+
+ shmctl (info.shmid, IPC_RMID, NULL);
+ shmdt (info.shmaddr);
+
+ return _x_error_occurred;
+}
+
+static cairo_bool_t
+xorg_has_buggy_send_shm_completion_event(cairo_xlib_display_t *display,
+ cairo_xlib_shm_display_t *shm)
+{
+ 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
@@ -1141,8 +1193,12 @@ xorg_has_buggy_send_shm_completion_event(Display *dpy)
*
* Remove the SendEvent bit (0x80) before doing range checks on event type.
*/
- return (strstr (ServerVendor (dpy), "X.Org") != NULL &&
- VendorRelease (dpy) < XORG_VERSION_ENCODE(1,11,0,1));
+ if (strstr (ServerVendor (dpy), "X.Org") != NULL &&
+ VendorRelease (dpy) < XORG_VERSION_ENCODE(1,11,0,1))
+ return TRUE;
+
+ /* For everyone else check that no error is generated */
+ return has_broken_send_shm_event (display, shm);
}
void
@@ -1162,6 +1218,15 @@ _cairo_xlib_display_init_shm (cairo_xlib_display_t *display)
if (unlikely (shm == NULL))
return;
+ codes = XInitExtension (display->display, SHMNAME);
+ if (codes == NULL) {
+ free (shm);
+ return;
+ }
+
+ shm->opcode = codes ->major_opcode;
+ shm->event = codes->first_event;
+
if (unlikely (_pqueue_init (&shm->info))) {
free (shm);
return;
@@ -1177,16 +1242,12 @@ _cairo_xlib_display_init_shm (cairo_xlib_display_t *display)
DefaultVisual (display->display, scr),
CWOverrideRedirect, &attr);
- if (xorg_has_buggy_send_shm_completion_event(display->display))
+ if (xorg_has_buggy_send_shm_completion_event(display, shm))
has_pixmap = 0;
shm->has_pixmaps = has_pixmap ? MIN_PIXMAP_SIZE : 0;
cairo_list_init (&shm->pool);
- codes = XInitExtension (display->display, SHMNAME);
- shm->opcode = codes ->major_opcode;
- shm->event = codes->first_event;
-
cairo_list_init (&shm->surfaces);
display->shm = shm;