aboutsummaryrefslogtreecommitdiff
path: root/libX11/src
diff options
context:
space:
mode:
Diffstat (limited to 'libX11/src')
-rw-r--r--libX11/src/OpenDis.c1459
-rw-r--r--libX11/src/xcb_io.c1518
2 files changed, 1479 insertions, 1498 deletions
diff --git a/libX11/src/OpenDis.c b/libX11/src/OpenDis.c
index 0b779b0ad..9379fec83 100644
--- a/libX11/src/OpenDis.c
+++ b/libX11/src/OpenDis.c
@@ -1,739 +1,720 @@
-/*
-
-Copyright 1985, 1986, 1998 The Open Group
-
-Permission to use, copy, modify, distribute, and sell this software and its
-documentation for any purpose is hereby granted without fee, provided that
-the above copyright notice appear in all copies and that both that
-copyright notice and this permission notice appear in supporting
-documentation.
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
-AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of The Open Group shall not be
-used in advertising or otherwise to promote the sale, use or other dealings
-in this Software without prior written authorization from The Open Group.
-
-*/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include "Xlibint.h"
-#include "Xxcbint.h"
-#include <X11/Xatom.h>
-#include <X11/Xresource.h>
-#include <stdio.h>
-#include "Xintconn.h"
-
-#ifdef XKB
-#include "XKBlib.h"
-#endif /* XKB */
-
-#ifdef XTHREADS
-#include "locking.h"
-int (*_XInitDisplayLock_fn)(Display *dpy) = NULL;
-void (*_XFreeDisplayLock_fn)(Display *dpy) = NULL;
-
-#define InitDisplayLock(d) (_XInitDisplayLock_fn ? (*_XInitDisplayLock_fn)(d) : Success)
-#define FreeDisplayLock(d) if (_XFreeDisplayLock_fn) (*_XFreeDisplayLock_fn)(d)
-#else
-#define InitDisplayLock(dis) Success
-#define FreeDisplayLock(dis)
-#endif /* XTHREADS */
-
-static xReq _dummy_request = {
- 0, 0, 0
-};
-
-static void OutOfMemory(Display *dpy);
-
-/*
- * Connects to a server, creates a Display object and returns a pointer to
- * the newly created Display back to the caller.
- */
-Display *
-XOpenDisplay (
- register _Xconst char *display)
-{
- register Display *dpy; /* New Display object being created. */
- register int i;
- int j, k; /* random iterator indexes */
- char *display_name; /* pointer to display name */
- char *setup = NULL; /* memory allocated at startup */
- int iscreen; /* screen number */
- xConnSetupPrefix prefix; /* prefix information */
- int vendorlen; /* length of vendor string */
- union {
- xConnSetup *setup;
- char *failure;
- char *vendor;
- xPixmapFormat *sf;
- xWindowRoot *rp;
- xDepth *dp;
- xVisualType *vp;
- } u; /* proto data returned from server */
- long setuplength; /* number of bytes in setup message */
- long usedbytes = 0; /* number of bytes we have processed */
- unsigned long mask;
- long int conn_buf_size;
- char *xlib_buffer_size;
-
- /*
- * If the display specifier string supplied as an argument to this
- * routine is NULL or a pointer to NULL, read the DISPLAY variable.
- */
- if (display == NULL || *display == '\0') {
- if ((display_name = getenv("DISPLAY")) == NULL) {
- /* Oops! No DISPLAY environment variable - error. */
- return(NULL);
- }
- }
- else {
- /* Display is non-NULL, copy the pointer */
- display_name = (char *)display;
- }
-
-/*
- * Set the default error handlers. This allows the global variables to
- * default to NULL for use with shared libraries.
- */
- if (_XErrorFunction == NULL) (void) XSetErrorHandler (NULL);
- if (_XIOErrorFunction == NULL) (void) XSetIOErrorHandler (NULL);
-
-/*
- * Attempt to allocate a display structure. Return NULL if allocation fails.
- */
- if ((dpy = (Display *)Xcalloc(1, sizeof(Display))) == NULL) {
- return(NULL);
- }
-
- if ((dpy->display_name = strdup(display_name)) == NULL) {
- OutOfMemory(dpy);
- return(NULL);
- }
-
-/*
- * Call the Connect routine to get the transport connection object.
- * If NULL is returned, the connection failed.
- */
-
- if(!_XConnectXCB(dpy, display, &iscreen)) {
- /* Try falling back on other transports if no transport specified */
- const char *slash = strrchr(display_name, '/');
- if(slash == NULL) {
- const char *protocols[] = {"local", "unix", "tcp", "inet6", "inet", NULL};
- const char **s;
- size_t buf_size = strlen(display_name) + 7; // max strlen + 2 (null + /)
- char *buf = Xmalloc(buf_size * sizeof(char));
-
- if(buf) {
- for(s = protocols; buf && *s; s++) {
- snprintf(buf, buf_size, "%s/%s", *s, display_name);
- if(_XConnectXCB(dpy, buf, &iscreen))
- goto fallback_success;
- }
- Xfree(buf);
- }
- }
-
- OutOfMemory(dpy);
- return NULL;
- }
-fallback_success:
-
- /* Initialize as much of the display structure as we can.
- * Initialize pointers to NULL so that XFreeDisplayStructure will
- * work if we run out of memory before we finish initializing.
- */
- dpy->keysyms = (KeySym *) NULL;
- dpy->modifiermap = NULL;
- dpy->lock_meaning = NoSymbol;
- dpy->keysyms_per_keycode = 0;
- dpy->xdefaults = (char *)NULL;
- dpy->scratch_length = 0L;
- dpy->scratch_buffer = NULL;
- dpy->key_bindings = NULL;
- dpy->ext_procs = (_XExtension *)NULL;
- dpy->ext_data = (XExtData *)NULL;
- dpy->ext_number = 0;
- dpy->event_vec[X_Error] = _XUnknownWireEvent;
- dpy->event_vec[X_Reply] = _XUnknownWireEvent;
- dpy->wire_vec[X_Error] = _XUnknownNativeEvent;
- dpy->wire_vec[X_Reply] = _XUnknownNativeEvent;
- for (i = KeyPress; i < LASTEvent; i++) {
- dpy->event_vec[i] = _XWireToEvent;
- dpy->wire_vec[i] = NULL;
- }
- for (i = LASTEvent; i < 128; i++) {
- dpy->event_vec[i] = _XUnknownWireEvent;
- dpy->wire_vec[i] = _XUnknownNativeEvent;
- }
- dpy->resource_id = 0;
- dpy->db = (struct _XrmHashBucketRec *)NULL;
- dpy->cursor_font = None;
- dpy->flags = 0;
- dpy->async_handlers = NULL;
- dpy->screens = NULL;
- dpy->vendor = NULL;
- dpy->buffer = NULL;
- dpy->atoms = NULL;
- dpy->error_vec = NULL;
- dpy->context_db = NULL;
- dpy->free_funcs = NULL;
- dpy->pixmap_format = NULL;
- dpy->cms.clientCmaps = NULL;
- dpy->cms.defaultCCCs = NULL;
- dpy->cms.perVisualIntensityMaps = NULL;
- dpy->im_filters = NULL;
- dpy->bigreq_size = 0;
- dpy->lock = NULL;
- dpy->lock_fns = NULL;
- dpy->qfree = NULL;
- dpy->next_event_serial_num = 1;
- dpy->im_fd_info = NULL;
- dpy->im_fd_length = 0;
- dpy->conn_watchers = NULL;
- dpy->watcher_count = 0;
- dpy->filedes = NULL;
- dpy->flushes = NULL;
- dpy->xcmisc_opcode = 0;
- dpy->xkb_info = NULL;
-
-/*
- * Setup other information in this display structure.
- */
- dpy->vnumber = X_PROTOCOL;
- dpy->resource_alloc = _XAllocID;
- dpy->idlist_alloc = _XAllocIDs;
- dpy->synchandler = NULL;
- dpy->savedsynchandler = NULL;
- dpy->request = 0;
- dpy->last_request_read = 0;
- dpy->default_screen = iscreen; /* Value returned by ConnectDisplay */
- dpy->last_req = (char *)&_dummy_request;
-
- /* Initialize the display lock */
- if (InitDisplayLock(dpy) != 0) {
- OutOfMemory (dpy);
- return(NULL);
- }
-
- if (!_XPollfdCacheInit(dpy)) {
- OutOfMemory (dpy);
- return(NULL);
- }
-
- /* Set up the output buffers. */
-#ifndef XLIBDEFAULTBUFSIZE
-#define XLIBDEFAULTBUFSIZE 16384 /* 16k */
-#endif
-#ifndef XLIBMINBUFSIZE
-#define XLIBMINBUFSIZE BUFSIZE /* old default buffer size */
-#endif
- xlib_buffer_size = getenv("XLIBBUFFERSIZE");
-
-#ifdef __sun /* Backwards compatibility for old Solaris libX11 name */
- if (xlib_buffer_size == NULL)
- xlib_buffer_size = getenv("XSUNBUFFERSIZE");
-#endif
-
- if (xlib_buffer_size == NULL)
- conn_buf_size = XLIBDEFAULTBUFSIZE;
- else
- conn_buf_size = 1024 * strtol(xlib_buffer_size, NULL, 10);
- if (conn_buf_size < XLIBMINBUFSIZE)
- conn_buf_size = XLIBMINBUFSIZE;
-
- if ((dpy->bufptr = dpy->buffer = Xcalloc(1, conn_buf_size)) == NULL) {
- OutOfMemory (dpy);
- return(NULL);
- }
- dpy->xcb->real_bufmax = dpy->buffer + conn_buf_size;
- dpy->bufmax = dpy->buffer;
-
- /* Set up the input event queue and input event queue parameters. */
- dpy->head = dpy->tail = NULL;
- dpy->qlen = 0;
-
- /* Set up free-function record */
- if ((dpy->free_funcs = (_XFreeFuncRec *)Xcalloc(1,
- sizeof(_XFreeFuncRec)))
- == NULL) {
- OutOfMemory (dpy);
- return(NULL);
- }
-
- {
- const struct xcb_setup_t *xcbsetup = xcb_get_setup(dpy->xcb->connection);
- memcpy(&prefix, xcbsetup, sizeof(prefix));
- setuplength = prefix.length << 2;
- setup = (char *) xcbsetup;
- setup += SIZEOF(xConnSetupPrefix);
- u.setup = (xConnSetup *) setup;
- }
-
-/*
- * Check if the reply was long enough to get any information out of it.
- */
- usedbytes = sz_xConnSetup;
- if (setuplength < usedbytes ) {
- fprintf (stderr, "Xlib: Broken initial reply: Too short (%ld)\n", setuplength);
- OutOfMemory(dpy);
- return (NULL);
- }
-
-/*
- * We succeeded at authorization, so let us move the data into
- * the display structure.
- */
- dpy->proto_major_version= prefix.majorVersion;
- dpy->proto_minor_version= prefix.minorVersion;
- dpy->release = u.setup->release;
- dpy->resource_base = u.setup->ridBase;
- dpy->resource_mask = u.setup->ridMask;
- dpy->min_keycode = u.setup->minKeyCode;
- dpy->max_keycode = u.setup->maxKeyCode;
- dpy->motion_buffer = u.setup->motionBufferSize;
- dpy->nformats = u.setup->numFormats;
- dpy->nscreens = u.setup->numRoots;
- dpy->byte_order = u.setup->imageByteOrder;
- dpy->bitmap_unit = u.setup->bitmapScanlineUnit;
- dpy->bitmap_pad = u.setup->bitmapScanlinePad;
- dpy->bitmap_bit_order = u.setup->bitmapBitOrder;
- dpy->max_request_size = u.setup->maxRequestSize;
- mask = dpy->resource_mask;
- dpy->resource_shift = 0;
- if (!mask)
- {
- fprintf (stderr, "Xlib: connection to \"%s\" invalid setup\n",
- dpy->display_name);
- OutOfMemory(dpy);
- return (NULL);
- }
-
- while (!(mask & 1)) {
- dpy->resource_shift++;
- mask = mask >> 1;
- }
- dpy->resource_max = (dpy->resource_mask >> dpy->resource_shift) - 5;
-/*
- * now extract the vendor string... String must be null terminated,
- * padded to multiple of 4 bytes.
- */
- /* Check for a sane vendor string length */
- if (u.setup->nbytesVendor > 256) {
- OutOfMemory(dpy);
- return (NULL);
- }
-
- dpy->vendor = (char *) Xmalloc((unsigned) (u.setup->nbytesVendor + 1));
- if (dpy->vendor == NULL) {
- OutOfMemory(dpy);
- return (NULL);
- }
- vendorlen = u.setup->nbytesVendor;
-
-/*
- * validate setup length
- */
- usedbytes += (vendorlen + 3) & ~3;
- if (setuplength < usedbytes) {
- fprintf (stderr, "Xlib: Broken initial reply: Too short (%ld)\n", setuplength);
- OutOfMemory(dpy);
- return (NULL);
- }
-
- u.setup = (xConnSetup *) (((char *) u.setup) + sz_xConnSetup);
- (void) strncpy(dpy->vendor, u.vendor, vendorlen);
- dpy->vendor[vendorlen] = '\0';
- vendorlen = (vendorlen + 3) & ~3; /* round up */
- u.vendor += vendorlen;
-
-/*
- * Now iterate down setup information.....
- */
- dpy->pixmap_format =
- (ScreenFormat *)Xmalloc(
- (unsigned) (dpy->nformats *sizeof(ScreenFormat)));
- if (dpy->pixmap_format == NULL) {
- OutOfMemory (dpy);
- return(NULL);
- }
-/*
- * First decode the Z axis Screen format information.
- */
- usedbytes += dpy->nformats * sz_xPixmapFormat;
-
- if (setuplength < usedbytes) {
- fprintf (stderr, "Xlib: Broken initial reply: Too short (%ld)\n", setuplength);
- OutOfMemory (dpy);
- return(NULL);
- }
-
- for (i = 0; i < dpy->nformats; i++) {
- register ScreenFormat *fmt = &dpy->pixmap_format[i];
- fmt->depth = u.sf->depth;
- fmt->bits_per_pixel = u.sf->bitsPerPixel;
- fmt->scanline_pad = u.sf->scanLinePad;
- fmt->ext_data = NULL;
- u.sf = (xPixmapFormat *) (((char *) u.sf) + sz_xPixmapFormat);
- }
-
-/*
- * next the Screen structures.
- */
- dpy->screens =
- (Screen *)Xmalloc((unsigned) dpy->nscreens*sizeof(Screen));
- if (dpy->screens == NULL) {
- OutOfMemory (dpy);
- return(NULL);
- }
-
-/*
- * Now go deal with each screen structure.
- */
- for (i = 0; i < dpy->nscreens; i++) {
- register Screen *sp = &dpy->screens[i];
- VisualID root_visualID;
-
- usedbytes += sz_xWindowRoot;
- if (setuplength < usedbytes) {
- fprintf (stderr, "Xlib: Broken initial reply: Too short (%ld)\n", setuplength);
- OutOfMemory (dpy);
- return(NULL);
- }
-
- root_visualID = u.rp->rootVisualID;
- sp->display = dpy;
- sp->root = u.rp->windowId;
- sp->cmap = u.rp->defaultColormap;
- sp->white_pixel = u.rp->whitePixel;
- sp->black_pixel = u.rp->blackPixel;
- sp->root_input_mask = u.rp->currentInputMask;
- sp->width = u.rp->pixWidth;
- sp->height = u.rp->pixHeight;
- sp->mwidth = u.rp->mmWidth;
- sp->mheight = u.rp->mmHeight;
- sp->min_maps = u.rp->minInstalledMaps;
- sp->max_maps = u.rp->maxInstalledMaps;
- sp->backing_store= u.rp->backingStore;
- sp->save_unders = u.rp->saveUnders;
- sp->root_depth = u.rp->rootDepth;
- sp->ndepths = u.rp->nDepths;
- sp->ext_data = NULL;
- u.rp = (xWindowRoot *) (((char *) u.rp) + sz_xWindowRoot);
-/*
- * lets set up the depth structures.
- */
- sp->depths = (Depth *)Xmalloc(
- (unsigned)sp->ndepths*sizeof(Depth));
- if (sp->depths == NULL) {
- OutOfMemory (dpy);
- return(NULL);
- }
- /*
- * for all depths on this screen.
- */
- for (j = 0; j < sp->ndepths; j++) {
- Depth *dp = &sp->depths[j];
-
- usedbytes += sz_xDepth;
- if (setuplength < usedbytes) {
- fprintf (stderr, "Xlib: Broken initial reply: Too short (%ld)\n", setuplength);
- OutOfMemory (dpy);
- return(NULL);
- }
-
- dp->depth = u.dp->depth;
- dp->nvisuals = u.dp->nVisuals;
- u.dp = (xDepth *) (((char *) u.dp) + sz_xDepth);
- if (dp->nvisuals > 0) {
- dp->visuals =
- (Visual *)Xmalloc((unsigned)dp->nvisuals*sizeof(Visual));
- if (dp->visuals == NULL) {
- OutOfMemory (dpy);
- return(NULL);
- }
- for (k = 0; k < dp->nvisuals; k++) {
- register Visual *vp = &dp->visuals[k];
-
- usedbytes += sz_xVisualType;
- if (setuplength < usedbytes) {
- fprintf (stderr, "Xlib: Broken initial reply: Too short (%ld)\n", setuplength);
- OutOfMemory (dpy);
- return(NULL);
- }
-
- vp->visualid = u.vp->visualID;
- vp->class = u.vp->class;
- vp->bits_per_rgb= u.vp->bitsPerRGB;
- vp->map_entries = u.vp->colormapEntries;
- vp->red_mask = u.vp->redMask;
- vp->green_mask = u.vp->greenMask;
- vp->blue_mask = u.vp->blueMask;
- vp->ext_data = NULL;
- u.vp = (xVisualType *) (((char *) u.vp) +
- sz_xVisualType);
- }
- if (dp->depth == 32 && getenv ("XLIB_SKIP_ARGB_VISUALS"))
- {
- Xfree (dp->visuals);
- dp->visuals = NULL;
- dp->nvisuals = 0;
- }
- } else {
- dp->visuals = (Visual *) NULL;
- }
- }
- sp->root_visual = _XVIDtoVisual(dpy, root_visualID);
- }
-
- if(usedbytes != setuplength){
- /* Sanity check, shouldn't happen. */
- fprintf(stderr, "Xlib: Did not parse entire setup message: "
- "parsed: %ld, message: %ld\n",
- usedbytes, setuplength);
- OutOfMemory(dpy);
- return(NULL);
- }
-
-/*
- * Now start talking to the server to setup all other information...
- */
-
-/*
- * Make sure default screen is legal.
- */
- if (iscreen >= dpy->nscreens) {
- OutOfMemory(dpy);
- return(NULL);
- }
-
- dpy->bigreq_size = xcb_get_maximum_request_length(dpy->xcb->connection);
- if(dpy->bigreq_size <= dpy->max_request_size)
- dpy->bigreq_size = 0;
-
-/*
- * Set up other stuff clients are always going to use.
- */
- for (i = 0; i < dpy->nscreens; i++) {
- register Screen *sp = &dpy->screens[i];
- XGCValues values;
- values.foreground = sp->black_pixel;
- values.background = sp->white_pixel;
- if ((sp->default_gc = XCreateGC (dpy, sp->root,
- GCForeground|GCBackground,
- &values)) == NULL) {
- OutOfMemory(dpy);
- return (NULL);
- }
- }
-/*
- * call into synchronization routine so that all programs can be
- * forced synchronous
- */
- (void) XSynchronize(dpy, _Xdebug);
-
-/*
- * get availability of large requests, and
- * get the resource manager database off the root window.
- */
- LockDisplay(dpy);
- {
- xGetPropertyReply reply;
- xGetPropertyReq *req;
-
- GetReq (GetProperty, req);
- req->window = RootWindow(dpy, 0);
- req->property = XA_RESOURCE_MANAGER;
- req->type = XA_STRING;
- req->delete = False;
- req->longOffset = 0;
- req->longLength = 100000000L;
-
- if (_XReply (dpy, (xReply *) &reply, 0, xFalse)) {
- if (reply.format == 8 && reply.propertyType == XA_STRING &&
- (reply.nItems + 1 > 0) &&
- (reply.nItems <= req->longLength * 4) &&
- (dpy->xdefaults = Xmalloc (reply.nItems + 1))) {
- _XReadPad (dpy, dpy->xdefaults, reply.nItems);
- dpy->xdefaults[reply.nItems] = '\0';
- }
- else if (reply.propertyType != None)
- _XEatData(dpy, reply.nItems * (reply.format >> 3));
- }
- }
- UnlockDisplay(dpy);
-
-#ifdef MOTIFBC
- {
- extern Display *_XHeadOfDisplayList;
- _XHeadOfDisplayList = dpy;
- }
-#endif
-#ifdef XKB
- XkbUseExtension(dpy,NULL,NULL);
-#endif
-/*
- * and return successfully
- */
- return(dpy);
-}
-
-/* XFreeDisplayStructure frees all the storage associated with a
- * Display. It is used by XOpenDisplay if it runs out of memory,
- * and also by XCloseDisplay. It needs to check whether all pointers
- * are non-NULL before dereferencing them, since it may be called
- * by XOpenDisplay before the Display structure is fully formed.
- * XOpenDisplay must be sure to initialize all the pointers to NULL
- * before the first possible call on this.
- */
-
-void _XFreeDisplayStructure(Display *dpy)
-{
- /* move all cookies in the EQ to the jar, then free them. */
- if (dpy->qfree) {
- _XQEvent *qelt = dpy->qfree;
- while (qelt) {
- if (_XIsEventCookie(dpy, &qelt->event))
- _XStoreEventCookie(dpy, &qelt->event);
- qelt = qelt->next;
- }
- }
- if (dpy->cookiejar)
- _XFreeEventCookies(dpy);
- while (dpy->ext_procs) {
- _XExtension *ext = dpy->ext_procs;
- dpy->ext_procs = ext->next;
- if (ext->name)
- Xfree (ext->name);
- Xfree ((char *)ext);
- }
- if (dpy->im_filters)
- (*dpy->free_funcs->im_filters)(dpy);
- if (dpy->cms.clientCmaps)
- (*dpy->free_funcs->clientCmaps)(dpy);
- if (dpy->cms.defaultCCCs)
- (*dpy->free_funcs->defaultCCCs)(dpy);
- if (dpy->cms.perVisualIntensityMaps)
- (*dpy->free_funcs->intensityMaps)(dpy);
- if (dpy->atoms)
- (*dpy->free_funcs->atoms)(dpy);
- if (dpy->modifiermap)
- (*dpy->free_funcs->modifiermap)(dpy->modifiermap);
- if (dpy->key_bindings)
- (*dpy->free_funcs->key_bindings)(dpy);
- if (dpy->context_db)
- (*dpy->free_funcs->context_db)(dpy);
- if (dpy->xkb_info)
- (*dpy->free_funcs->xkb)(dpy);
-
- /* if RM database was allocated by XGetDefault() free it */
- if (dpy->db && (dpy->flags & XlibDisplayDfltRMDB))
- XrmDestroyDatabase(dpy->db);
-
- if (dpy->screens) {
- register int i;
-
- for (i = 0; i < dpy->nscreens; i++) {
- Screen *sp = &dpy->screens[i];
-
- if (sp->depths) {
- register int j;
-
- for (j = 0; j < sp->ndepths; j++) {
- Depth *dp = &sp->depths[j];
-
- if (dp->visuals) {
- register int k;
-
- for (k = 0; k < dp->nvisuals; k++)
- _XFreeExtData (dp->visuals[k].ext_data);
- Xfree ((char *) dp->visuals);
- }
- }
-
- Xfree ((char *) sp->depths);
- }
-
- _XFreeExtData (sp->ext_data);
- }
-
- Xfree ((char *)dpy->screens);
- }
-
- if (dpy->pixmap_format) {
- register int i;
-
- for (i = 0; i < dpy->nformats; i++)
- _XFreeExtData (dpy->pixmap_format[i].ext_data);
- Xfree ((char *)dpy->pixmap_format);
- }
-
- free(dpy->display_name);
- if (dpy->vendor)
- Xfree (dpy->vendor);
-
- if (dpy->buffer)
- Xfree (dpy->buffer);
- if (dpy->keysyms)
- Xfree ((char *) dpy->keysyms);
- if (dpy->xdefaults)
- Xfree (dpy->xdefaults);
- if (dpy->error_vec)
- Xfree ((char *)dpy->error_vec);
-
- _XFreeExtData (dpy->ext_data);
- if (dpy->free_funcs)
- Xfree ((char *)dpy->free_funcs);
- if (dpy->scratch_buffer)
- Xfree (dpy->scratch_buffer);
- FreeDisplayLock(dpy);
-
- if (dpy->qfree) {
- register _XQEvent *qelt = dpy->qfree;
-
- while (qelt) {
- register _XQEvent *qnxt = qelt->next;
- Xfree ((char *) qelt);
- qelt = qnxt;
- }
- }
- while (dpy->im_fd_info) {
- struct _XConnectionInfo *conni = dpy->im_fd_info;
- dpy->im_fd_info = conni->next;
- if (conni->watch_data)
- Xfree (conni->watch_data);
- Xfree (conni);
- }
- if (dpy->conn_watchers) {
- struct _XConnWatchInfo *watcher = dpy->conn_watchers;
- dpy->conn_watchers = watcher->next;
- Xfree (watcher);
- }
- if (dpy->filedes)
- Xfree (dpy->filedes);
-
- _XFreeX11XCBStructure(dpy);
-
- Xfree ((char *)dpy);
-}
-
-/* OutOfMemory is called if malloc fails. XOpenDisplay returns NULL
- after this returns. */
-
-static void OutOfMemory(Display *dpy)
-{
- if(dpy->xcb->connection)
- xcb_disconnect(dpy->xcb->connection);
- _XFreeDisplayStructure (dpy);
-}
+/*
+
+Copyright 1985, 1986, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "Xlibint.h"
+#include "Xxcbint.h"
+#include <X11/Xatom.h>
+#include <X11/Xresource.h>
+#include <stdio.h>
+#include "Xintconn.h"
+
+#ifdef XKB
+#include "XKBlib.h"
+#endif /* XKB */
+
+#ifdef XTHREADS
+#include "locking.h"
+int (*_XInitDisplayLock_fn)(Display *dpy) = NULL;
+void (*_XFreeDisplayLock_fn)(Display *dpy) = NULL;
+
+#define InitDisplayLock(d) (_XInitDisplayLock_fn ? (*_XInitDisplayLock_fn)(d) : Success)
+#define FreeDisplayLock(d) if (_XFreeDisplayLock_fn) (*_XFreeDisplayLock_fn)(d)
+#else
+#define InitDisplayLock(dis) Success
+#define FreeDisplayLock(dis)
+#endif /* XTHREADS */
+
+static xReq _dummy_request = {
+ 0, 0, 0
+};
+
+static void OutOfMemory(Display *dpy);
+
+/*
+ * Connects to a server, creates a Display object and returns a pointer to
+ * the newly created Display back to the caller.
+ */
+Display *
+XOpenDisplay (
+ register _Xconst char *display)
+{
+ register Display *dpy; /* New Display object being created. */
+ register int i;
+ int j, k; /* random iterator indexes */
+ char *display_name; /* pointer to display name */
+ char *setup = NULL; /* memory allocated at startup */
+ int iscreen; /* screen number */
+ xConnSetupPrefix prefix; /* prefix information */
+ int vendorlen; /* length of vendor string */
+ union {
+ xConnSetup *setup;
+ char *failure;
+ char *vendor;
+ xPixmapFormat *sf;
+ xWindowRoot *rp;
+ xDepth *dp;
+ xVisualType *vp;
+ } u; /* proto data returned from server */
+ long setuplength; /* number of bytes in setup message */
+ long usedbytes = 0; /* number of bytes we have processed */
+ unsigned long mask;
+ long int conn_buf_size;
+ char *xlib_buffer_size;
+
+ /*
+ * If the display specifier string supplied as an argument to this
+ * routine is NULL or a pointer to NULL, read the DISPLAY variable.
+ */
+ if (display == NULL || *display == '\0') {
+ if ((display_name = getenv("DISPLAY")) == NULL) {
+ /* Oops! No DISPLAY environment variable - error. */
+ return(NULL);
+ }
+ }
+ else {
+ /* Display is non-NULL, copy the pointer */
+ display_name = (char *)display;
+ }
+
+/*
+ * Set the default error handlers. This allows the global variables to
+ * default to NULL for use with shared libraries.
+ */
+ if (_XErrorFunction == NULL) (void) XSetErrorHandler (NULL);
+ if (_XIOErrorFunction == NULL) (void) XSetIOErrorHandler (NULL);
+
+/*
+ * Attempt to allocate a display structure. Return NULL if allocation fails.
+ */
+ if ((dpy = (Display *)Xcalloc(1, sizeof(Display))) == NULL) {
+ return(NULL);
+ }
+
+ if ((dpy->display_name = strdup(display_name)) == NULL) {
+ OutOfMemory(dpy);
+ return(NULL);
+ }
+
+/*
+ * Call the Connect routine to get the transport connection object.
+ * If NULL is returned, the connection failed.
+ */
+
+ if(!_XConnectXCB(dpy, display, &iscreen)) {
+ OutOfMemory(dpy);
+ return NULL;
+ }
+
+ /* Initialize as much of the display structure as we can.
+ * Initialize pointers to NULL so that XFreeDisplayStructure will
+ * work if we run out of memory before we finish initializing.
+ */
+ dpy->keysyms = (KeySym *) NULL;
+ dpy->modifiermap = NULL;
+ dpy->lock_meaning = NoSymbol;
+ dpy->keysyms_per_keycode = 0;
+ dpy->xdefaults = (char *)NULL;
+ dpy->scratch_length = 0L;
+ dpy->scratch_buffer = NULL;
+ dpy->key_bindings = NULL;
+ dpy->ext_procs = (_XExtension *)NULL;
+ dpy->ext_data = (XExtData *)NULL;
+ dpy->ext_number = 0;
+ dpy->event_vec[X_Error] = _XUnknownWireEvent;
+ dpy->event_vec[X_Reply] = _XUnknownWireEvent;
+ dpy->wire_vec[X_Error] = _XUnknownNativeEvent;
+ dpy->wire_vec[X_Reply] = _XUnknownNativeEvent;
+ for (i = KeyPress; i < LASTEvent; i++) {
+ dpy->event_vec[i] = _XWireToEvent;
+ dpy->wire_vec[i] = NULL;
+ }
+ for (i = LASTEvent; i < 128; i++) {
+ dpy->event_vec[i] = _XUnknownWireEvent;
+ dpy->wire_vec[i] = _XUnknownNativeEvent;
+ }
+ dpy->resource_id = 0;
+ dpy->db = (struct _XrmHashBucketRec *)NULL;
+ dpy->cursor_font = None;
+ dpy->flags = 0;
+ dpy->async_handlers = NULL;
+ dpy->screens = NULL;
+ dpy->vendor = NULL;
+ dpy->buffer = NULL;
+ dpy->atoms = NULL;
+ dpy->error_vec = NULL;
+ dpy->context_db = NULL;
+ dpy->free_funcs = NULL;
+ dpy->pixmap_format = NULL;
+ dpy->cms.clientCmaps = NULL;
+ dpy->cms.defaultCCCs = NULL;
+ dpy->cms.perVisualIntensityMaps = NULL;
+ dpy->im_filters = NULL;
+ dpy->bigreq_size = 0;
+ dpy->lock = NULL;
+ dpy->lock_fns = NULL;
+ dpy->qfree = NULL;
+ dpy->next_event_serial_num = 1;
+ dpy->im_fd_info = NULL;
+ dpy->im_fd_length = 0;
+ dpy->conn_watchers = NULL;
+ dpy->watcher_count = 0;
+ dpy->filedes = NULL;
+ dpy->flushes = NULL;
+ dpy->xcmisc_opcode = 0;
+ dpy->xkb_info = NULL;
+
+/*
+ * Setup other information in this display structure.
+ */
+ dpy->vnumber = X_PROTOCOL;
+ dpy->resource_alloc = _XAllocID;
+ dpy->idlist_alloc = _XAllocIDs;
+ dpy->synchandler = NULL;
+ dpy->savedsynchandler = NULL;
+ dpy->request = 0;
+ dpy->last_request_read = 0;
+ dpy->default_screen = iscreen; /* Value returned by ConnectDisplay */
+ dpy->last_req = (char *)&_dummy_request;
+
+ /* Initialize the display lock */
+ if (InitDisplayLock(dpy) != 0) {
+ OutOfMemory (dpy);
+ return(NULL);
+ }
+
+ if (!_XPollfdCacheInit(dpy)) {
+ OutOfMemory (dpy);
+ return(NULL);
+ }
+
+ /* Set up the output buffers. */
+#ifndef XLIBDEFAULTBUFSIZE
+#define XLIBDEFAULTBUFSIZE 16384 /* 16k */
+#endif
+#ifndef XLIBMINBUFSIZE
+#define XLIBMINBUFSIZE BUFSIZE /* old default buffer size */
+#endif
+ xlib_buffer_size = getenv("XLIBBUFFERSIZE");
+
+#ifdef __sun /* Backwards compatibility for old Solaris libX11 name */
+ if (xlib_buffer_size == NULL)
+ xlib_buffer_size = getenv("XSUNBUFFERSIZE");
+#endif
+
+ if (xlib_buffer_size == NULL)
+ conn_buf_size = XLIBDEFAULTBUFSIZE;
+ else
+ conn_buf_size = 1024 * strtol(xlib_buffer_size, NULL, 10);
+ if (conn_buf_size < XLIBMINBUFSIZE)
+ conn_buf_size = XLIBMINBUFSIZE;
+
+ if ((dpy->bufptr = dpy->buffer = Xcalloc(1, conn_buf_size)) == NULL) {
+ OutOfMemory (dpy);
+ return(NULL);
+ }
+ dpy->xcb->real_bufmax = dpy->buffer + conn_buf_size;
+ dpy->bufmax = dpy->buffer;
+
+ /* Set up the input event queue and input event queue parameters. */
+ dpy->head = dpy->tail = NULL;
+ dpy->qlen = 0;
+
+ /* Set up free-function record */
+ if ((dpy->free_funcs = (_XFreeFuncRec *)Xcalloc(1,
+ sizeof(_XFreeFuncRec)))
+ == NULL) {
+ OutOfMemory (dpy);
+ return(NULL);
+ }
+
+ {
+ const struct xcb_setup_t *xcbsetup = xcb_get_setup(dpy->xcb->connection);
+ memcpy(&prefix, xcbsetup, sizeof(prefix));
+ setuplength = prefix.length << 2;
+ setup = (char *) xcbsetup;
+ setup += SIZEOF(xConnSetupPrefix);
+ u.setup = (xConnSetup *) setup;
+ }
+
+/*
+ * Check if the reply was long enough to get any information out of it.
+ */
+ usedbytes = sz_xConnSetup;
+ if (setuplength < usedbytes ) {
+ fprintf (stderr, "Xlib: Broken initial reply: Too short (%ld)\n", setuplength);
+ OutOfMemory(dpy);
+ return (NULL);
+ }
+
+/*
+ * We succeeded at authorization, so let us move the data into
+ * the display structure.
+ */
+ dpy->proto_major_version= prefix.majorVersion;
+ dpy->proto_minor_version= prefix.minorVersion;
+ dpy->release = u.setup->release;
+ dpy->resource_base = u.setup->ridBase;
+ dpy->resource_mask = u.setup->ridMask;
+ dpy->min_keycode = u.setup->minKeyCode;
+ dpy->max_keycode = u.setup->maxKeyCode;
+ dpy->motion_buffer = u.setup->motionBufferSize;
+ dpy->nformats = u.setup->numFormats;
+ dpy->nscreens = u.setup->numRoots;
+ dpy->byte_order = u.setup->imageByteOrder;
+ dpy->bitmap_unit = u.setup->bitmapScanlineUnit;
+ dpy->bitmap_pad = u.setup->bitmapScanlinePad;
+ dpy->bitmap_bit_order = u.setup->bitmapBitOrder;
+ dpy->max_request_size = u.setup->maxRequestSize;
+ mask = dpy->resource_mask;
+ dpy->resource_shift = 0;
+ if (!mask)
+ {
+ fprintf (stderr, "Xlib: connection to \"%s\" invalid setup\n",
+ dpy->display_name);
+ OutOfMemory(dpy);
+ return (NULL);
+ }
+
+ while (!(mask & 1)) {
+ dpy->resource_shift++;
+ mask = mask >> 1;
+ }
+ dpy->resource_max = (dpy->resource_mask >> dpy->resource_shift) - 5;
+/*
+ * now extract the vendor string... String must be null terminated,
+ * padded to multiple of 4 bytes.
+ */
+ /* Check for a sane vendor string length */
+ if (u.setup->nbytesVendor > 256) {
+ OutOfMemory(dpy);
+ return (NULL);
+ }
+
+ dpy->vendor = (char *) Xmalloc((unsigned) (u.setup->nbytesVendor + 1));
+ if (dpy->vendor == NULL) {
+ OutOfMemory(dpy);
+ return (NULL);
+ }
+ vendorlen = u.setup->nbytesVendor;
+
+/*
+ * validate setup length
+ */
+ usedbytes += (vendorlen + 3) & ~3;
+ if (setuplength < usedbytes) {
+ fprintf (stderr, "Xlib: Broken initial reply: Too short (%ld)\n", setuplength);
+ OutOfMemory(dpy);
+ return (NULL);
+ }
+
+ u.setup = (xConnSetup *) (((char *) u.setup) + sz_xConnSetup);
+ (void) strncpy(dpy->vendor, u.vendor, vendorlen);
+ dpy->vendor[vendorlen] = '\0';
+ vendorlen = (vendorlen + 3) & ~3; /* round up */
+ u.vendor += vendorlen;
+
+/*
+ * Now iterate down setup information.....
+ */
+ dpy->pixmap_format =
+ (ScreenFormat *)Xmalloc(
+ (unsigned) (dpy->nformats *sizeof(ScreenFormat)));
+ if (dpy->pixmap_format == NULL) {
+ OutOfMemory (dpy);
+ return(NULL);
+ }
+/*
+ * First decode the Z axis Screen format information.
+ */
+ usedbytes += dpy->nformats * sz_xPixmapFormat;
+
+ if (setuplength < usedbytes) {
+ fprintf (stderr, "Xlib: Broken initial reply: Too short (%ld)\n", setuplength);
+ OutOfMemory (dpy);
+ return(NULL);
+ }
+
+ for (i = 0; i < dpy->nformats; i++) {
+ register ScreenFormat *fmt = &dpy->pixmap_format[i];
+ fmt->depth = u.sf->depth;
+ fmt->bits_per_pixel = u.sf->bitsPerPixel;
+ fmt->scanline_pad = u.sf->scanLinePad;
+ fmt->ext_data = NULL;
+ u.sf = (xPixmapFormat *) (((char *) u.sf) + sz_xPixmapFormat);
+ }
+
+/*
+ * next the Screen structures.
+ */
+ dpy->screens =
+ (Screen *)Xmalloc((unsigned) dpy->nscreens*sizeof(Screen));
+ if (dpy->screens == NULL) {
+ OutOfMemory (dpy);
+ return(NULL);
+ }
+
+/*
+ * Now go deal with each screen structure.
+ */
+ for (i = 0; i < dpy->nscreens; i++) {
+ register Screen *sp = &dpy->screens[i];
+ VisualID root_visualID;
+
+ usedbytes += sz_xWindowRoot;
+ if (setuplength < usedbytes) {
+ fprintf (stderr, "Xlib: Broken initial reply: Too short (%ld)\n", setuplength);
+ OutOfMemory (dpy);
+ return(NULL);
+ }
+
+ root_visualID = u.rp->rootVisualID;
+ sp->display = dpy;
+ sp->root = u.rp->windowId;
+ sp->cmap = u.rp->defaultColormap;
+ sp->white_pixel = u.rp->whitePixel;
+ sp->black_pixel = u.rp->blackPixel;
+ sp->root_input_mask = u.rp->currentInputMask;
+ sp->width = u.rp->pixWidth;
+ sp->height = u.rp->pixHeight;
+ sp->mwidth = u.rp->mmWidth;
+ sp->mheight = u.rp->mmHeight;
+ sp->min_maps = u.rp->minInstalledMaps;
+ sp->max_maps = u.rp->maxInstalledMaps;
+ sp->backing_store= u.rp->backingStore;
+ sp->save_unders = u.rp->saveUnders;
+ sp->root_depth = u.rp->rootDepth;
+ sp->ndepths = u.rp->nDepths;
+ sp->ext_data = NULL;
+ u.rp = (xWindowRoot *) (((char *) u.rp) + sz_xWindowRoot);
+/*
+ * lets set up the depth structures.
+ */
+ sp->depths = (Depth *)Xmalloc(
+ (unsigned)sp->ndepths*sizeof(Depth));
+ if (sp->depths == NULL) {
+ OutOfMemory (dpy);
+ return(NULL);
+ }
+ /*
+ * for all depths on this screen.
+ */
+ for (j = 0; j < sp->ndepths; j++) {
+ Depth *dp = &sp->depths[j];
+
+ usedbytes += sz_xDepth;
+ if (setuplength < usedbytes) {
+ fprintf (stderr, "Xlib: Broken initial reply: Too short (%ld)\n", setuplength);
+ OutOfMemory (dpy);
+ return(NULL);
+ }
+
+ dp->depth = u.dp->depth;
+ dp->nvisuals = u.dp->nVisuals;
+ u.dp = (xDepth *) (((char *) u.dp) + sz_xDepth);
+ if (dp->nvisuals > 0) {
+ dp->visuals =
+ (Visual *)Xmalloc((unsigned)dp->nvisuals*sizeof(Visual));
+ if (dp->visuals == NULL) {
+ OutOfMemory (dpy);
+ return(NULL);
+ }
+ for (k = 0; k < dp->nvisuals; k++) {
+ register Visual *vp = &dp->visuals[k];
+
+ usedbytes += sz_xVisualType;
+ if (setuplength < usedbytes) {
+ fprintf (stderr, "Xlib: Broken initial reply: Too short (%ld)\n", setuplength);
+ OutOfMemory (dpy);
+ return(NULL);
+ }
+
+ vp->visualid = u.vp->visualID;
+ vp->class = u.vp->class;
+ vp->bits_per_rgb= u.vp->bitsPerRGB;
+ vp->map_entries = u.vp->colormapEntries;
+ vp->red_mask = u.vp->redMask;
+ vp->green_mask = u.vp->greenMask;
+ vp->blue_mask = u.vp->blueMask;
+ vp->ext_data = NULL;
+ u.vp = (xVisualType *) (((char *) u.vp) +
+ sz_xVisualType);
+ }
+ if (dp->depth == 32 && getenv ("XLIB_SKIP_ARGB_VISUALS"))
+ {
+ Xfree (dp->visuals);
+ dp->visuals = NULL;
+ dp->nvisuals = 0;
+ }
+ } else {
+ dp->visuals = (Visual *) NULL;
+ }
+ }
+ sp->root_visual = _XVIDtoVisual(dpy, root_visualID);
+ }
+
+ if(usedbytes != setuplength){
+ /* Sanity check, shouldn't happen. */
+ fprintf(stderr, "Xlib: Did not parse entire setup message: "
+ "parsed: %ld, message: %ld\n",
+ usedbytes, setuplength);
+ OutOfMemory(dpy);
+ return(NULL);
+ }
+
+/*
+ * Now start talking to the server to setup all other information...
+ */
+
+/*
+ * Make sure default screen is legal.
+ */
+ if (iscreen >= dpy->nscreens) {
+ OutOfMemory(dpy);
+ return(NULL);
+ }
+
+ dpy->bigreq_size = xcb_get_maximum_request_length(dpy->xcb->connection);
+ if(dpy->bigreq_size <= dpy->max_request_size)
+ dpy->bigreq_size = 0;
+
+/*
+ * Set up other stuff clients are always going to use.
+ */
+ for (i = 0; i < dpy->nscreens; i++) {
+ register Screen *sp = &dpy->screens[i];
+ XGCValues values;
+ values.foreground = sp->black_pixel;
+ values.background = sp->white_pixel;
+ if ((sp->default_gc = XCreateGC (dpy, sp->root,
+ GCForeground|GCBackground,
+ &values)) == NULL) {
+ OutOfMemory(dpy);
+ return (NULL);
+ }
+ }
+/*
+ * call into synchronization routine so that all programs can be
+ * forced synchronous
+ */
+ (void) XSynchronize(dpy, _Xdebug);
+
+/*
+ * get availability of large requests, and
+ * get the resource manager database off the root window.
+ */
+ LockDisplay(dpy);
+ {
+ xGetPropertyReply reply;
+ xGetPropertyReq *req;
+
+ GetReq (GetProperty, req);
+ req->window = RootWindow(dpy, 0);
+ req->property = XA_RESOURCE_MANAGER;
+ req->type = XA_STRING;
+ req->delete = False;
+ req->longOffset = 0;
+ req->longLength = 100000000L;
+
+ if (_XReply (dpy, (xReply *) &reply, 0, xFalse)) {
+ if (reply.format == 8 && reply.propertyType == XA_STRING &&
+ (reply.nItems + 1 > 0) &&
+ (reply.nItems <= req->longLength * 4) &&
+ (dpy->xdefaults = Xmalloc (reply.nItems + 1))) {
+ _XReadPad (dpy, dpy->xdefaults, reply.nItems);
+ dpy->xdefaults[reply.nItems] = '\0';
+ }
+ else if (reply.propertyType != None)
+ _XEatData(dpy, reply.nItems * (reply.format >> 3));
+ }
+ }
+ UnlockDisplay(dpy);
+
+#ifdef MOTIFBC
+ {
+ extern Display *_XHeadOfDisplayList;
+ _XHeadOfDisplayList = dpy;
+ }
+#endif
+#ifdef XKB
+ XkbUseExtension(dpy,NULL,NULL);
+#endif
+/*
+ * and return successfully
+ */
+ return(dpy);
+}
+
+/* XFreeDisplayStructure frees all the storage associated with a
+ * Display. It is used by XOpenDisplay if it runs out of memory,
+ * and also by XCloseDisplay. It needs to check whether all pointers
+ * are non-NULL before dereferencing them, since it may be called
+ * by XOpenDisplay before the Display structure is fully formed.
+ * XOpenDisplay must be sure to initialize all the pointers to NULL
+ * before the first possible call on this.
+ */
+
+void _XFreeDisplayStructure(Display *dpy)
+{
+ /* move all cookies in the EQ to the jar, then free them. */
+ if (dpy->qfree) {
+ _XQEvent *qelt = dpy->qfree;
+ while (qelt) {
+ if (_XIsEventCookie(dpy, &qelt->event))
+ _XStoreEventCookie(dpy, &qelt->event);
+ qelt = qelt->next;
+ }
+ }
+ if (dpy->cookiejar)
+ _XFreeEventCookies(dpy);
+ while (dpy->ext_procs) {
+ _XExtension *ext = dpy->ext_procs;
+ dpy->ext_procs = ext->next;
+ if (ext->name)
+ Xfree (ext->name);
+ Xfree ((char *)ext);
+ }
+ if (dpy->im_filters)
+ (*dpy->free_funcs->im_filters)(dpy);
+ if (dpy->cms.clientCmaps)
+ (*dpy->free_funcs->clientCmaps)(dpy);
+ if (dpy->cms.defaultCCCs)
+ (*dpy->free_funcs->defaultCCCs)(dpy);
+ if (dpy->cms.perVisualIntensityMaps)
+ (*dpy->free_funcs->intensityMaps)(dpy);
+ if (dpy->atoms)
+ (*dpy->free_funcs->atoms)(dpy);
+ if (dpy->modifiermap)
+ (*dpy->free_funcs->modifiermap)(dpy->modifiermap);
+ if (dpy->key_bindings)
+ (*dpy->free_funcs->key_bindings)(dpy);
+ if (dpy->context_db)
+ (*dpy->free_funcs->context_db)(dpy);
+ if (dpy->xkb_info)
+ (*dpy->free_funcs->xkb)(dpy);
+
+ /* if RM database was allocated by XGetDefault() free it */
+ if (dpy->db && (dpy->flags & XlibDisplayDfltRMDB))
+ XrmDestroyDatabase(dpy->db);
+
+ if (dpy->screens) {
+ register int i;
+
+ for (i = 0; i < dpy->nscreens; i++) {
+ Screen *sp = &dpy->screens[i];
+
+ if (sp->depths) {
+ register int j;
+
+ for (j = 0; j < sp->ndepths; j++) {
+ Depth *dp = &sp->depths[j];
+
+ if (dp->visuals) {
+ register int k;
+
+ for (k = 0; k < dp->nvisuals; k++)
+ _XFreeExtData (dp->visuals[k].ext_data);
+ Xfree ((char *) dp->visuals);
+ }
+ }
+
+ Xfree ((char *) sp->depths);
+ }
+
+ _XFreeExtData (sp->ext_data);
+ }
+
+ Xfree ((char *)dpy->screens);
+ }
+
+ if (dpy->pixmap_format) {
+ register int i;
+
+ for (i = 0; i < dpy->nformats; i++)
+ _XFreeExtData (dpy->pixmap_format[i].ext_data);
+ Xfree ((char *)dpy->pixmap_format);
+ }
+
+ free(dpy->display_name);
+ if (dpy->vendor)
+ Xfree (dpy->vendor);
+
+ if (dpy->buffer)
+ Xfree (dpy->buffer);
+ if (dpy->keysyms)
+ Xfree ((char *) dpy->keysyms);
+ if (dpy->xdefaults)
+ Xfree (dpy->xdefaults);
+ if (dpy->error_vec)
+ Xfree ((char *)dpy->error_vec);
+
+ _XFreeExtData (dpy->ext_data);
+ if (dpy->free_funcs)
+ Xfree ((char *)dpy->free_funcs);
+ if (dpy->scratch_buffer)
+ Xfree (dpy->scratch_buffer);
+ FreeDisplayLock(dpy);
+
+ if (dpy->qfree) {
+ register _XQEvent *qelt = dpy->qfree;
+
+ while (qelt) {
+ register _XQEvent *qnxt = qelt->next;
+ Xfree ((char *) qelt);
+ qelt = qnxt;
+ }
+ }
+ while (dpy->im_fd_info) {
+ struct _XConnectionInfo *conni = dpy->im_fd_info;
+ dpy->im_fd_info = conni->next;
+ if (conni->watch_data)
+ Xfree (conni->watch_data);
+ Xfree (conni);
+ }
+ if (dpy->conn_watchers) {
+ struct _XConnWatchInfo *watcher = dpy->conn_watchers;
+ dpy->conn_watchers = watcher->next;
+ Xfree (watcher);
+ }
+ if (dpy->filedes)
+ Xfree (dpy->filedes);
+
+ _XFreeX11XCBStructure(dpy);
+
+ Xfree ((char *)dpy);
+}
+
+/* OutOfMemory is called if malloc fails. XOpenDisplay returns NULL
+ after this returns. */
+
+static void OutOfMemory(Display *dpy)
+{
+ if(dpy->xcb->connection)
+ xcb_disconnect(dpy->xcb->connection);
+ _XFreeDisplayStructure (dpy);
+}
diff --git a/libX11/src/xcb_io.c b/libX11/src/xcb_io.c
index bac9bdf0b..300ef571f 100644
--- a/libX11/src/xcb_io.c
+++ b/libX11/src/xcb_io.c
@@ -1,759 +1,759 @@
-/* Copyright (C) 2003-2006 Jamey Sharp, Josh Triplett
- * This file is licensed under the MIT license. See the file COPYING. */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "Xlibint.h"
-#include "locking.h"
-#include "Xprivate.h"
-#include "Xxcbint.h"
-#include <xcb/xcbext.h>
-
-#include <assert.h>
-#ifdef HAVE_INTTYPES_H
-#include <inttypes.h>
-#endif
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-
-#define xcb_fail_assert(_message, _var) { \
- unsigned int _var = 1; \
- fprintf(stderr, "[xcb] Aborting, sorry about that.\n"); \
- assert(!_var); \
-}
-
-#define throw_thread_fail_assert(_message, _var) { \
- fprintf(stderr, "[xcb] " _message "\n"); \
- fprintf(stderr, "[xcb] Most likely this is a multi-threaded client " \
- "and XInitThreads has not been called\n"); \
- xcb_fail_assert(_message, _var); \
-}
-
-/* XXX: It would probably be most useful if we stored the last-processed
- * request, so we could find the offender from the message. */
-#define throw_extlib_fail_assert(_message, _var) { \
- fprintf(stderr, "[xcb] " _message "\n"); \
- fprintf(stderr, "[xcb] This is most likely caused by a broken X " \
- "extension library\n"); \
- xcb_fail_assert(_message, _var); \
-}
-
-static void return_socket(void *closure)
-{
- Display *dpy = closure;
- InternalLockDisplay(dpy, /* don't skip user locks */ 0);
- _XSend(dpy, NULL, 0);
- dpy->bufmax = dpy->buffer;
- UnlockDisplay(dpy);
-}
-
-static void require_socket(Display *dpy)
-{
- if(dpy->bufmax == dpy->buffer)
- {
- uint64_t sent;
- int flags = 0;
- /* if we don't own the event queue, we have to ask XCB
- * to set our errors aside for us. */
- if(dpy->xcb->event_owner != XlibOwnsEventQueue)
- flags = XCB_REQUEST_CHECKED;
- if(!xcb_take_socket(dpy->xcb->connection, return_socket, dpy,
- flags, &sent))
- _XIOError(dpy);
- /* Xlib uses unsigned long for sequence numbers. XCB
- * uses 64-bit internally, but currently exposes an
- * unsigned int API. If these differ, Xlib cannot track
- * the full 64-bit sequence number if 32-bit wrap
- * happens while Xlib does not own the socket. A
- * complete fix would be to make XCB's public API use
- * 64-bit sequence numbers. */
- if (sizeof(unsigned long) > sizeof(unsigned int) &&
- dpy->xcb->event_owner == XlibOwnsEventQueue &&
- (sent - dpy->last_request_read >= (UINT64_C(1) << 32))) {
- throw_thread_fail_assert("Sequence number wrapped "
- "beyond 32 bits while Xlib "
- "did not own the socket",
- xcb_xlib_seq_number_wrapped);
- }
- dpy->xcb->last_flushed = dpy->request = sent;
- dpy->bufmax = dpy->xcb->real_bufmax;
- }
-}
-
-/* Call internal connection callbacks for any fds that are currently
- * ready to read. This function will not block unless one of the
- * callbacks blocks.
- *
- * This code borrowed from _XWaitForReadable. Inverse call tree:
- * _XRead
- * _XWaitForWritable
- * _XFlush
- * _XSend
- * _XEventsQueued
- * _XReadEvents
- * _XRead[0-9]+
- * _XAllocIDs
- * _XReply
- * _XEatData
- * _XReadPad
- */
-static void check_internal_connections(Display *dpy)
-{
- struct _XConnectionInfo *ilist;
- fd_set r_mask;
- struct timeval tv;
- int result;
- int highest_fd = -1;
-
- if(dpy->flags & XlibDisplayProcConni || !dpy->im_fd_info)
- return;
-
- FD_ZERO(&r_mask);
- for(ilist = dpy->im_fd_info; ilist; ilist = ilist->next)
- {
- assert(ilist->fd >= 0);
- FD_SET(ilist->fd, &r_mask);
- if(ilist->fd > highest_fd)
- highest_fd = ilist->fd;
- }
- assert(highest_fd >= 0);
-
- tv.tv_sec = 0;
- tv.tv_usec = 0;
- result = select(highest_fd + 1, &r_mask, NULL, NULL, &tv);
-
- if(result == -1)
- {
- if(errno == EINTR)
- return;
- _XIOError(dpy);
- }
-
- for(ilist = dpy->im_fd_info; result && ilist; ilist = ilist->next)
- if(FD_ISSET(ilist->fd, &r_mask))
- {
- _XProcessInternalConnection(dpy, ilist);
- --result;
- }
-}
-
-static PendingRequest *append_pending_request(Display *dpy, unsigned long sequence)
-{
- PendingRequest *node = malloc(sizeof(PendingRequest));
- assert(node);
- node->next = NULL;
- node->sequence = sequence;
- node->reply_waiter = 0;
- if(dpy->xcb->pending_requests_tail)
- {
- if (XLIB_SEQUENCE_COMPARE(dpy->xcb->pending_requests_tail->sequence,
- >=, node->sequence))
- throw_thread_fail_assert("Unknown sequence number "
- "while appending request",
- xcb_xlib_unknown_seq_number);
- if (dpy->xcb->pending_requests_tail->next != NULL)
- throw_thread_fail_assert("Unknown request in queue "
- "while appending request",
- xcb_xlib_unknown_req_pending);
- dpy->xcb->pending_requests_tail->next = node;
- }
- else
- dpy->xcb->pending_requests = node;
- dpy->xcb->pending_requests_tail = node;
- return node;
-}
-
-static void dequeue_pending_request(Display *dpy, PendingRequest *req)
-{
- if (req != dpy->xcb->pending_requests)
- throw_thread_fail_assert("Unknown request in queue while "
- "dequeuing",
- xcb_xlib_unknown_req_in_deq);
-
- dpy->xcb->pending_requests = req->next;
- if(!dpy->xcb->pending_requests)
- {
- if (req != dpy->xcb->pending_requests_tail)
- throw_thread_fail_assert("Unknown request in queue "
- "while dequeuing",
- xcb_xlib_unknown_req_in_deq);
- dpy->xcb->pending_requests_tail = NULL;
- }
- else if (XLIB_SEQUENCE_COMPARE(req->sequence, >=,
- dpy->xcb->pending_requests->sequence))
- throw_thread_fail_assert("Unknown sequence number while "
- "dequeuing request",
- xcb_xlib_threads_sequence_lost);
-
- free(req);
-}
-
-static int handle_error(Display *dpy, xError *err, Bool in_XReply)
-{
- _XExtension *ext;
- int ret_code;
- /* Oddly, Xlib only allows extensions to suppress errors when
- * those errors were seen by _XReply. */
- if(in_XReply)
- /*
- * we better see if there is an extension who may
- * want to suppress the error.
- */
- for(ext = dpy->ext_procs; ext; ext = ext->next)
- if(ext->error && (*ext->error)(dpy, err, &ext->codes, &ret_code))
- return ret_code;
- _XError(dpy, err);
- return 0;
-}
-
-/* Widen a 32-bit sequence number into a native-word-size (unsigned long)
- * sequence number. Treating the comparison as a 1 and shifting it avoids a
- * conditional branch, and shifting by 16 twice avoids a compiler warning when
- * sizeof(unsigned long) == 4. */
-static void widen(unsigned long *wide, unsigned int narrow)
-{
- unsigned long new = (*wide & ~0xFFFFFFFFUL) | narrow;
- *wide = new + ((unsigned long) (new < *wide) << 16 << 16);
-}
-
-/* Thread-safety rules:
- *
- * At most one thread can be reading from XCB's event queue at a time.
- * If you are not the current event-reading thread and you need to find
- * out if an event is available, you must wait.
- *
- * The same rule applies for reading replies.
- *
- * A single thread cannot be both the the event-reading and the
- * reply-reading thread at the same time.
- *
- * We always look at both the current event and the first pending reply
- * to decide which to process next.
- *
- * We always process all responses in sequence-number order, which may
- * mean waiting for another thread (either the event_waiter or the
- * reply_waiter) to handle an earlier response before we can process or
- * return a later one. If so, we wait on the corresponding condition
- * variable for that thread to process the response and wake us up.
- */
-
-static xcb_generic_reply_t *poll_for_event(Display *dpy)
-{
- /* Make sure the Display's sequence numbers are valid */
- require_socket(dpy);
-
- /* Precondition: This thread can safely get events from XCB. */
- assert(dpy->xcb->event_owner == XlibOwnsEventQueue && !dpy->xcb->event_waiter);
-
- if(!dpy->xcb->next_event)
- dpy->xcb->next_event = xcb_poll_for_event(dpy->xcb->connection);
-
- if(dpy->xcb->next_event)
- {
- PendingRequest *req = dpy->xcb->pending_requests;
- xcb_generic_event_t *event = dpy->xcb->next_event;
- unsigned long event_sequence = dpy->last_request_read;
- widen(&event_sequence, event->full_sequence);
- if(!req || XLIB_SEQUENCE_COMPARE(event_sequence, <, req->sequence)
- || (event->response_type != X_Error && event_sequence == req->sequence))
- {
- if (XLIB_SEQUENCE_COMPARE(event_sequence, >,
- dpy->request))
- {
- throw_thread_fail_assert("Unknown sequence "
- "number while "
- "processing queue",
- xcb_xlib_threads_sequence_lost);
- }
- dpy->last_request_read = event_sequence;
- dpy->xcb->next_event = NULL;
- return (xcb_generic_reply_t *) event;
- }
- }
- return NULL;
-}
-
-static xcb_generic_reply_t *poll_for_response(Display *dpy)
-{
- void *response;
- xcb_generic_error_t *error;
- PendingRequest *req;
- while(!(response = poll_for_event(dpy)) &&
- (req = dpy->xcb->pending_requests) &&
- !req->reply_waiter &&
- xcb_poll_for_reply(dpy->xcb->connection, req->sequence, &response, &error))
- {
- if(XLIB_SEQUENCE_COMPARE(req->sequence, >, dpy->request))
- {
- throw_thread_fail_assert("Unknown sequence number "
- "while awaiting reply",
- xcb_xlib_threads_sequence_lost);
- }
- dpy->last_request_read = req->sequence;
- if(response)
- break;
- dequeue_pending_request(dpy, req);
- if(error)
- return (xcb_generic_reply_t *) error;
- }
- return response;
-}
-
-static void handle_response(Display *dpy, xcb_generic_reply_t *response, Bool in_XReply)
-{
- _XAsyncHandler *async, *next;
- switch(response->response_type)
- {
- case X_Reply:
- for(async = dpy->async_handlers; async; async = next)
- {
- next = async->next;
- if(async->handler(dpy, (xReply *) response, (char *) response, sizeof(xReply) + (response->length << 2), async->data))
- break;
- }
- break;
-
- case X_Error:
- handle_error(dpy, (xError *) response, in_XReply);
- break;
-
- default: /* event */
- /* GenericEvents may be > 32 bytes. In this case, the
- * event struct is trailed by the additional bytes. the
- * xcb_generic_event_t struct uses 4 bytes for internal
- * numbering, so we need to shift the trailing data to
- * be after the first 32 bytes. */
- if(response->response_type == GenericEvent && ((xcb_ge_event_t *) response)->length)
- {
- xcb_ge_event_t *event = (xcb_ge_event_t *) response;
- memmove(&event->full_sequence, &event[1], event->length * 4);
- }
- _XEnq(dpy, (xEvent *) response);
- break;
- }
- free(response);
-}
-
-int _XEventsQueued(Display *dpy, int mode)
-{
- xcb_generic_reply_t *response;
- if(dpy->flags & XlibDisplayIOError)
- return 0;
- if(dpy->xcb->event_owner != XlibOwnsEventQueue)
- return 0;
-
- if(mode == QueuedAfterFlush)
- _XSend(dpy, NULL, 0);
- else
- check_internal_connections(dpy);
-
- /* If another thread is blocked waiting for events, then we must
- * let that thread pick up the next event. Since it blocked, we
- * can reasonably claim there are no new events right now. */
- if(!dpy->xcb->event_waiter)
- {
- while((response = poll_for_response(dpy)))
- handle_response(dpy, response, False);
- if(xcb_connection_has_error(dpy->xcb->connection))
- _XIOError(dpy);
- }
- return dpy->qlen;
-}
-
-/* _XReadEvents - Flush the output queue,
- * then read as many events as possible (but at least 1) and enqueue them
- */
-void _XReadEvents(Display *dpy)
-{
- xcb_generic_reply_t *response;
- unsigned long serial;
-
- if(dpy->flags & XlibDisplayIOError)
- return;
- _XSend(dpy, NULL, 0);
- if(dpy->xcb->event_owner != XlibOwnsEventQueue)
- return;
- check_internal_connections(dpy);
-
- serial = dpy->next_event_serial_num;
- while(serial == dpy->next_event_serial_num || dpy->qlen == 0)
- {
- if(dpy->xcb->event_waiter)
- {
- ConditionWait(dpy, dpy->xcb->event_notify);
- /* Maybe the other thread got us an event. */
- continue;
- }
-
- if(!dpy->xcb->next_event)
- {
- xcb_generic_event_t *event;
- dpy->xcb->event_waiter = 1;
- UnlockDisplay(dpy);
- event = xcb_wait_for_event(dpy->xcb->connection);
- /* It appears that classic Xlib respected user
- * locks when waking up after waiting for
- * events. However, if this thread did not have
- * any user locks, and another thread takes a
- * user lock and tries to read events, then we'd
- * deadlock. So we'll choose to let the thread
- * that got in first consume events, despite the
- * later thread's user locks. */
- InternalLockDisplay(dpy, /* ignore user locks */ 1);
- dpy->xcb->event_waiter = 0;
- ConditionBroadcast(dpy, dpy->xcb->event_notify);
- if(!event)
- _XIOError(dpy);
- dpy->xcb->next_event = event;
- }
-
- /* We've established most of the conditions for
- * poll_for_response to return non-NULL. The exceptions
- * are connection shutdown, and finding that another
- * thread is waiting for the next reply we'd like to
- * process. */
-
- response = poll_for_response(dpy);
- if(response)
- handle_response(dpy, response, False);
- else if(dpy->xcb->pending_requests->reply_waiter)
- { /* need braces around ConditionWait */
- ConditionWait(dpy, dpy->xcb->reply_notify);
- }
- else
- _XIOError(dpy);
- }
-
- /* The preceding loop established that there is no
- * event_waiter--unless we just called ConditionWait because of
- * a reply_waiter, in which case another thread may have become
- * the event_waiter while we slept unlocked. */
- if(!dpy->xcb->event_waiter)
- while((response = poll_for_response(dpy)))
- handle_response(dpy, response, False);
- if(xcb_connection_has_error(dpy->xcb->connection))
- _XIOError(dpy);
-}
-
-/*
- * _XSend - Flush the buffer and send the client data. 32 bit word aligned
- * transmission is used, if size is not 0 mod 4, extra bytes are transmitted.
- *
- * Note that the connection must not be read from once the data currently
- * in the buffer has been written.
- */
-void _XSend(Display *dpy, const char *data, long size)
-{
- static const xReq dummy_request;
- static char const pad[3];
- struct iovec vec[3];
- uint64_t requests;
- _XExtension *ext;
- xcb_connection_t *c = dpy->xcb->connection;
- if(dpy->flags & XlibDisplayIOError)
- return;
-
- if(dpy->bufptr == dpy->buffer && !size)
- return;
-
- /* iff we asked XCB to set aside errors, we must pick those up
- * eventually. iff there are async handlers, we may have just
- * issued requests that will generate replies. in either case,
- * we need to remember to check later. */
- if(dpy->xcb->event_owner != XlibOwnsEventQueue || dpy->async_handlers)
- {
- uint64_t sequence;
- for(sequence = dpy->xcb->last_flushed + 1; sequence <= dpy->request; ++sequence)
- append_pending_request(dpy, sequence);
- }
- requests = dpy->request - dpy->xcb->last_flushed;
- dpy->xcb->last_flushed = dpy->request;
-
- vec[0].iov_base = dpy->buffer;
- vec[0].iov_len = dpy->bufptr - dpy->buffer;
- vec[1].iov_base = (caddr_t) data;
- vec[1].iov_len = size;
- vec[2].iov_base = (caddr_t) pad;
- vec[2].iov_len = -size & 3;
-
- for(ext = dpy->flushes; ext; ext = ext->next_flush)
- {
- int i;
- for(i = 0; i < 3; ++i)
- if(vec[i].iov_len)
- ext->before_flush(dpy, &ext->codes, vec[i].iov_base, vec[i].iov_len);
- }
-
- if(xcb_writev(c, vec, 3, requests) < 0)
- _XIOError(dpy);
- dpy->bufptr = dpy->buffer;
- dpy->last_req = (char *) &dummy_request;
-
- check_internal_connections(dpy);
-
- _XSetSeqSyncFunction(dpy);
-}
-
-/*
- * _XFlush - Flush the X request buffer. If the buffer is empty, no
- * action is taken.
- */
-void _XFlush(Display *dpy)
-{
- require_socket(dpy);
- _XSend(dpy, NULL, 0);
-
- _XEventsQueued(dpy, QueuedAfterReading);
-}
-
-static const XID inval_id = ~0UL;
-
-void _XIDHandler(Display *dpy)
-{
- if (dpy->xcb->next_xid == inval_id)
- _XAllocIDs(dpy, &dpy->xcb->next_xid, 1);
-}
-
-/* _XAllocID - resource ID allocation routine. */
-XID _XAllocID(Display *dpy)
-{
- XID ret = dpy->xcb->next_xid;
- assert (ret != inval_id);
- dpy->xcb->next_xid = inval_id;
- _XSetPrivSyncFunction(dpy);
- return ret;
-}
-
-/* _XAllocIDs - multiple resource ID allocation routine. */
-void _XAllocIDs(Display *dpy, XID *ids, int count)
-{
- int i;
-#ifdef XTHREADS
- if (dpy->lock)
- (*dpy->lock->user_lock_display)(dpy);
- UnlockDisplay(dpy);
-#endif
- for (i = 0; i < count; i++)
- ids[i] = xcb_generate_id(dpy->xcb->connection);
-#ifdef XTHREADS
- InternalLockDisplay(dpy, /* don't skip user locks */ 0);
- if (dpy->lock)
- (*dpy->lock->user_unlock_display)(dpy);
-#endif
-}
-
-static void _XFreeReplyData(Display *dpy, Bool force)
-{
- if(!force && dpy->xcb->reply_consumed < dpy->xcb->reply_length)
- return;
- free(dpy->xcb->reply_data);
- dpy->xcb->reply_data = NULL;
-}
-
-/*
- * _XReply - Wait for a reply packet and copy its contents into the
- * specified rep.
- * extra: number of 32-bit words expected after the reply
- * discard: should I discard data following "extra" words?
- */
-Status _XReply(Display *dpy, xReply *rep, int extra, Bool discard)
-{
- xcb_generic_error_t *error;
- xcb_connection_t *c = dpy->xcb->connection;
- char *reply;
- PendingRequest *current;
-
- if (dpy->xcb->reply_data)
- throw_extlib_fail_assert("Extra reply data still left in queue",
- xcb_xlib_extra_reply_data_left);
-
- if(dpy->flags & XlibDisplayIOError)
- return 0;
-
- _XSend(dpy, NULL, 0);
- if(dpy->xcb->pending_requests_tail && dpy->xcb->pending_requests_tail->sequence == dpy->request)
- current = dpy->xcb->pending_requests_tail;
- else
- current = append_pending_request(dpy, dpy->request);
- /* Don't let any other thread get this reply. */
- current->reply_waiter = 1;
-
- while(1)
- {
- PendingRequest *req = dpy->xcb->pending_requests;
- xcb_generic_reply_t *response;
-
- if(req != current && req->reply_waiter)
- {
- ConditionWait(dpy, dpy->xcb->reply_notify);
- /* Another thread got this reply. */
- continue;
- }
- req->reply_waiter = 1;
- UnlockDisplay(dpy);
- response = xcb_wait_for_reply(c, req->sequence, &error);
- /* Any user locks on another thread must have been taken
- * while we slept in xcb_wait_for_reply. Classic Xlib
- * ignored those user locks in this case, so we do too. */
- InternalLockDisplay(dpy, /* ignore user locks */ 1);
-
- /* We have the response we're looking for. Now, before
- * letting anyone else process this sequence number, we
- * need to process any events that should have come
- * earlier. */
-
- if(dpy->xcb->event_owner == XlibOwnsEventQueue)
- {
- xcb_generic_reply_t *event;
- /* If some thread is already waiting for events,
- * it will get the first one. That thread must
- * process that event before we can continue. */
- /* FIXME: That event might be after this reply,
- * and might never even come--or there might be
- * multiple threads trying to get events. */
- while(dpy->xcb->event_waiter)
- { /* need braces around ConditionWait */
- ConditionWait(dpy, dpy->xcb->event_notify);
- }
- while((event = poll_for_event(dpy)))
- handle_response(dpy, event, True);
- }
-
- req->reply_waiter = 0;
- ConditionBroadcast(dpy, dpy->xcb->reply_notify);
- if(XLIB_SEQUENCE_COMPARE(req->sequence, >, dpy->request)) {
- throw_thread_fail_assert("Unknown sequence number "
- "while processing reply",
- xcb_xlib_threads_sequence_lost);
- }
- dpy->last_request_read = req->sequence;
- if(!response)
- dequeue_pending_request(dpy, req);
-
- if(req == current)
- {
- reply = (char *) response;
- break;
- }
-
- if(error)
- handle_response(dpy, (xcb_generic_reply_t *) error, True);
- else if(response)
- handle_response(dpy, response, True);
- }
- check_internal_connections(dpy);
-
- if(dpy->xcb->next_event && dpy->xcb->next_event->response_type == X_Error)
- {
- xcb_generic_event_t *event = dpy->xcb->next_event;
- unsigned long event_sequence = dpy->last_request_read;
- widen(&event_sequence, event->full_sequence);
- if(event_sequence == dpy->last_request_read)
- {
- error = (xcb_generic_error_t *) event;
- dpy->xcb->next_event = NULL;
- }
- }
-
- if(error)
- {
- int ret_code;
-
- /* Xlib is evil and assumes that even errors will be
- * copied into rep. */
- memcpy(rep, error, 32);
-
- /* do not die on "no such font", "can't allocate",
- "can't grab" failures */
- switch(error->error_code)
- {
- case BadName:
- switch(error->major_code)
- {
- case X_LookupColor:
- case X_AllocNamedColor:
- free(error);
- return 0;
- }
- break;
- case BadFont:
- if(error->major_code == X_QueryFont) {
- free(error);
- return 0;
- }
- break;
- case BadAlloc:
- case BadAccess:
- free(error);
- return 0;
- }
-
- ret_code = handle_error(dpy, (xError *) error, True);
- free(error);
- return ret_code;
- }
-
- /* it's not an error, but we don't have a reply, so it's an I/O
- * error. */
- if(!reply)
- {
- _XIOError(dpy);
- return 0;
- }
-
- /* there's no error and we have a reply. */
- dpy->xcb->reply_data = reply;
- dpy->xcb->reply_consumed = sizeof(xReply) + (extra * 4);
- dpy->xcb->reply_length = sizeof(xReply);
- if(dpy->xcb->reply_data[0] == 1)
- dpy->xcb->reply_length += (((xcb_generic_reply_t *) dpy->xcb->reply_data)->length * 4);
-
- /* error: Xlib asks too much. give them what we can anyway. */
- if(dpy->xcb->reply_length < dpy->xcb->reply_consumed)
- dpy->xcb->reply_consumed = dpy->xcb->reply_length;
-
- memcpy(rep, dpy->xcb->reply_data, dpy->xcb->reply_consumed);
- _XFreeReplyData(dpy, discard);
- return 1;
-}
-
-int _XRead(Display *dpy, char *data, long size)
-{
- assert(size >= 0);
- if(size == 0)
- return 0;
- if(dpy->xcb->reply_data == NULL ||
- dpy->xcb->reply_consumed + size > dpy->xcb->reply_length)
- throw_extlib_fail_assert("Too much data requested from _XRead",
- xcb_xlib_too_much_data_requested);
- memcpy(data, dpy->xcb->reply_data + dpy->xcb->reply_consumed, size);
- dpy->xcb->reply_consumed += size;
- _XFreeReplyData(dpy, False);
- return 0;
-}
-
-/*
- * _XReadPad - Read bytes from the socket taking into account incomplete
- * reads. If the number of bytes is not 0 mod 4, read additional pad
- * bytes.
- */
-void _XReadPad(Display *dpy, char *data, long size)
-{
- _XRead(dpy, data, size);
- dpy->xcb->reply_consumed += -size & 3;
- _XFreeReplyData(dpy, False);
-}
-
-/* Read and discard "n" 8-bit bytes of data */
-void _XEatData(Display *dpy, unsigned long n)
-{
- dpy->xcb->reply_consumed += n;
- _XFreeReplyData(dpy, False);
-}
+/* Copyright (C) 2003-2006 Jamey Sharp, Josh Triplett
+ * This file is licensed under the MIT license. See the file COPYING. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "Xlibint.h"
+#include "locking.h"
+#include "Xprivate.h"
+#include "Xxcbint.h"
+#include <xcb/xcbext.h>
+
+#include <assert.h>
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#define xcb_fail_assert(_message, _var) { \
+ unsigned int _var = 1; \
+ fprintf(stderr, "[xcb] Aborting, sorry about that.\n"); \
+ assert(!_var); \
+}
+
+#define throw_thread_fail_assert(_message, _var) { \
+ fprintf(stderr, "[xcb] " _message "\n"); \
+ fprintf(stderr, "[xcb] Most likely this is a multi-threaded client " \
+ "and XInitThreads has not been called\n"); \
+ xcb_fail_assert(_message, _var); \
+}
+
+/* XXX: It would probably be most useful if we stored the last-processed
+ * request, so we could find the offender from the message. */
+#define throw_extlib_fail_assert(_message, _var) { \
+ fprintf(stderr, "[xcb] " _message "\n"); \
+ fprintf(stderr, "[xcb] This is most likely caused by a broken X " \
+ "extension library\n"); \
+ xcb_fail_assert(_message, _var); \
+}
+
+static void return_socket(void *closure)
+{
+ Display *dpy = closure;
+ InternalLockDisplay(dpy, /* don't skip user locks */ 0);
+ _XSend(dpy, NULL, 0);
+ dpy->bufmax = dpy->buffer;
+ UnlockDisplay(dpy);
+}
+
+static void require_socket(Display *dpy)
+{
+ if(dpy->bufmax == dpy->buffer)
+ {
+ uint64_t sent;
+ int flags = 0;
+ /* if we don't own the event queue, we have to ask XCB
+ * to set our errors aside for us. */
+ if(dpy->xcb->event_owner != XlibOwnsEventQueue)
+ flags = XCB_REQUEST_CHECKED;
+ if(!xcb_take_socket(dpy->xcb->connection, return_socket, dpy,
+ flags, &sent))
+ _XIOError(dpy);
+ /* Xlib uses unsigned long for sequence numbers. XCB
+ * uses 64-bit internally, but currently exposes an
+ * unsigned int API. If these differ, Xlib cannot track
+ * the full 64-bit sequence number if 32-bit wrap
+ * happens while Xlib does not own the socket. A
+ * complete fix would be to make XCB's public API use
+ * 64-bit sequence numbers. */
+ if (sizeof(unsigned long) > sizeof(unsigned int) &&
+ dpy->xcb->event_owner == XlibOwnsEventQueue &&
+ (sent - dpy->last_request_read >= (UINT64_C(1) << 32))) {
+ throw_thread_fail_assert("Sequence number wrapped "
+ "beyond 32 bits while Xlib "
+ "did not own the socket",
+ xcb_xlib_seq_number_wrapped);
+ }
+ dpy->xcb->last_flushed = dpy->request = sent;
+ dpy->bufmax = dpy->xcb->real_bufmax;
+ }
+}
+
+/* Call internal connection callbacks for any fds that are currently
+ * ready to read. This function will not block unless one of the
+ * callbacks blocks.
+ *
+ * This code borrowed from _XWaitForReadable. Inverse call tree:
+ * _XRead
+ * _XWaitForWritable
+ * _XFlush
+ * _XSend
+ * _XEventsQueued
+ * _XReadEvents
+ * _XRead[0-9]+
+ * _XAllocIDs
+ * _XReply
+ * _XEatData
+ * _XReadPad
+ */
+static void check_internal_connections(Display *dpy)
+{
+ struct _XConnectionInfo *ilist;
+ fd_set r_mask;
+ struct timeval tv;
+ int result;
+ int highest_fd = -1;
+
+ if(dpy->flags & XlibDisplayProcConni || !dpy->im_fd_info)
+ return;
+
+ FD_ZERO(&r_mask);
+ for(ilist = dpy->im_fd_info; ilist; ilist = ilist->next)
+ {
+ assert(ilist->fd >= 0);
+ FD_SET(ilist->fd, &r_mask);
+ if(ilist->fd > highest_fd)
+ highest_fd = ilist->fd;
+ }
+ assert(highest_fd >= 0);
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ result = select(highest_fd + 1, &r_mask, NULL, NULL, &tv);
+
+ if(result == -1)
+ {
+ if(errno == EINTR)
+ return;
+ _XIOError(dpy);
+ }
+
+ for(ilist = dpy->im_fd_info; result && ilist; ilist = ilist->next)
+ if(FD_ISSET(ilist->fd, &r_mask))
+ {
+ _XProcessInternalConnection(dpy, ilist);
+ --result;
+ }
+}
+
+static PendingRequest *append_pending_request(Display *dpy, unsigned long sequence)
+{
+ PendingRequest *node = malloc(sizeof(PendingRequest));
+ assert(node);
+ node->next = NULL;
+ node->sequence = sequence;
+ node->reply_waiter = 0;
+ if(dpy->xcb->pending_requests_tail)
+ {
+ if (XLIB_SEQUENCE_COMPARE(dpy->xcb->pending_requests_tail->sequence,
+ >=, node->sequence))
+ throw_thread_fail_assert("Unknown sequence number "
+ "while appending request",
+ xcb_xlib_unknown_seq_number);
+ if (dpy->xcb->pending_requests_tail->next != NULL)
+ throw_thread_fail_assert("Unknown request in queue "
+ "while appending request",
+ xcb_xlib_unknown_req_pending);
+ dpy->xcb->pending_requests_tail->next = node;
+ }
+ else
+ dpy->xcb->pending_requests = node;
+ dpy->xcb->pending_requests_tail = node;
+ return node;
+}
+
+static void dequeue_pending_request(Display *dpy, PendingRequest *req)
+{
+ if (req != dpy->xcb->pending_requests)
+ throw_thread_fail_assert("Unknown request in queue while "
+ "dequeuing",
+ xcb_xlib_unknown_req_in_deq);
+
+ dpy->xcb->pending_requests = req->next;
+ if(!dpy->xcb->pending_requests)
+ {
+ if (req != dpy->xcb->pending_requests_tail)
+ throw_thread_fail_assert("Unknown request in queue "
+ "while dequeuing",
+ xcb_xlib_unknown_req_in_deq);
+ dpy->xcb->pending_requests_tail = NULL;
+ }
+ else if (XLIB_SEQUENCE_COMPARE(req->sequence, >=,
+ dpy->xcb->pending_requests->sequence))
+ throw_thread_fail_assert("Unknown sequence number while "
+ "dequeuing request",
+ xcb_xlib_threads_sequence_lost);
+
+ free(req);
+}
+
+static int handle_error(Display *dpy, xError *err, Bool in_XReply)
+{
+ _XExtension *ext;
+ int ret_code;
+ /* Oddly, Xlib only allows extensions to suppress errors when
+ * those errors were seen by _XReply. */
+ if(in_XReply)
+ /*
+ * we better see if there is an extension who may
+ * want to suppress the error.
+ */
+ for(ext = dpy->ext_procs; ext; ext = ext->next)
+ if(ext->error && (*ext->error)(dpy, err, &ext->codes, &ret_code))
+ return ret_code;
+ _XError(dpy, err);
+ return 0;
+}
+
+/* Widen a 32-bit sequence number into a native-word-size (unsigned long)
+ * sequence number. Treating the comparison as a 1 and shifting it avoids a
+ * conditional branch, and shifting by 16 twice avoids a compiler warning when
+ * sizeof(unsigned long) == 4. */
+static void widen(unsigned long *wide, unsigned int narrow)
+{
+ unsigned long new = (*wide & ~0xFFFFFFFFUL) | narrow;
+ *wide = new + ((unsigned long) (new < *wide) << 16 << 16);
+}
+
+/* Thread-safety rules:
+ *
+ * At most one thread can be reading from XCB's event queue at a time.
+ * If you are not the current event-reading thread and you need to find
+ * out if an event is available, you must wait.
+ *
+ * The same rule applies for reading replies.
+ *
+ * A single thread cannot be both the the event-reading and the
+ * reply-reading thread at the same time.
+ *
+ * We always look at both the current event and the first pending reply
+ * to decide which to process next.
+ *
+ * We always process all responses in sequence-number order, which may
+ * mean waiting for another thread (either the event_waiter or the
+ * reply_waiter) to handle an earlier response before we can process or
+ * return a later one. If so, we wait on the corresponding condition
+ * variable for that thread to process the response and wake us up.
+ */
+
+static xcb_generic_reply_t *poll_for_event(Display *dpy)
+{
+ /* Make sure the Display's sequence numbers are valid */
+ require_socket(dpy);
+
+ /* Precondition: This thread can safely get events from XCB. */
+ assert(dpy->xcb->event_owner == XlibOwnsEventQueue && !dpy->xcb->event_waiter);
+
+ if(!dpy->xcb->next_event)
+ dpy->xcb->next_event = xcb_poll_for_event(dpy->xcb->connection);
+
+ if(dpy->xcb->next_event)
+ {
+ PendingRequest *req = dpy->xcb->pending_requests;
+ xcb_generic_event_t *event = dpy->xcb->next_event;
+ unsigned long event_sequence = dpy->last_request_read;
+ widen(&event_sequence, event->full_sequence);
+ if(!req || XLIB_SEQUENCE_COMPARE(event_sequence, <, req->sequence)
+ || (event->response_type != X_Error && event_sequence == req->sequence))
+ {
+ if (XLIB_SEQUENCE_COMPARE(event_sequence, >,
+ dpy->request))
+ {
+ throw_thread_fail_assert("Unknown sequence "
+ "number while "
+ "processing queue",
+ xcb_xlib_threads_sequence_lost);
+ }
+ dpy->last_request_read = event_sequence;
+ dpy->xcb->next_event = NULL;
+ return (xcb_generic_reply_t *) event;
+ }
+ }
+ return NULL;
+}
+
+static xcb_generic_reply_t *poll_for_response(Display *dpy)
+{
+ void *response;
+ xcb_generic_error_t *error;
+ PendingRequest *req;
+ while(!(response = poll_for_event(dpy)) &&
+ (req = dpy->xcb->pending_requests) &&
+ !req->reply_waiter &&
+ xcb_poll_for_reply(dpy->xcb->connection, req->sequence, &response, &error))
+ {
+ if(XLIB_SEQUENCE_COMPARE(req->sequence, >, dpy->request))
+ {
+ throw_thread_fail_assert("Unknown sequence number "
+ "while awaiting reply",
+ xcb_xlib_threads_sequence_lost);
+ }
+ dpy->last_request_read = req->sequence;
+ if(response)
+ break;
+ dequeue_pending_request(dpy, req);
+ if(error)
+ return (xcb_generic_reply_t *) error;
+ }
+ return response;
+}
+
+static void handle_response(Display *dpy, xcb_generic_reply_t *response, Bool in_XReply)
+{
+ _XAsyncHandler *async, *next;
+ switch(response->response_type)
+ {
+ case X_Reply:
+ for(async = dpy->async_handlers; async; async = next)
+ {
+ next = async->next;
+ if(async->handler(dpy, (xReply *) response, (char *) response, sizeof(xReply) + (response->length << 2), async->data))
+ break;
+ }
+ break;
+
+ case X_Error:
+ handle_error(dpy, (xError *) response, in_XReply);
+ break;
+
+ default: /* event */
+ /* GenericEvents may be > 32 bytes. In this case, the
+ * event struct is trailed by the additional bytes. the
+ * xcb_generic_event_t struct uses 4 bytes for internal
+ * numbering, so we need to shift the trailing data to
+ * be after the first 32 bytes. */
+ if(response->response_type == GenericEvent && ((xcb_ge_event_t *) response)->length)
+ {
+ xcb_ge_event_t *event = (xcb_ge_event_t *) response;
+ memmove(&event->full_sequence, &event[1], event->length * 4);
+ }
+ _XEnq(dpy, (xEvent *) response);
+ break;
+ }
+ free(response);
+}
+
+int _XEventsQueued(Display *dpy, int mode)
+{
+ xcb_generic_reply_t *response;
+ if(dpy->flags & XlibDisplayIOError)
+ return 0;
+ if(dpy->xcb->event_owner != XlibOwnsEventQueue)
+ return 0;
+
+ if(mode == QueuedAfterFlush)
+ _XSend(dpy, NULL, 0);
+ else
+ check_internal_connections(dpy);
+
+ /* If another thread is blocked waiting for events, then we must
+ * let that thread pick up the next event. Since it blocked, we
+ * can reasonably claim there are no new events right now. */
+ if(!dpy->xcb->event_waiter)
+ {
+ while((response = poll_for_response(dpy)))
+ handle_response(dpy, response, False);
+ if(xcb_connection_has_error(dpy->xcb->connection))
+ _XIOError(dpy);
+ }
+ return dpy->qlen;
+}
+
+/* _XReadEvents - Flush the output queue,
+ * then read as many events as possible (but at least 1) and enqueue them
+ */
+void _XReadEvents(Display *dpy)
+{
+ xcb_generic_reply_t *response;
+ unsigned long serial;
+
+ if(dpy->flags & XlibDisplayIOError)
+ return;
+ _XSend(dpy, NULL, 0);
+ if(dpy->xcb->event_owner != XlibOwnsEventQueue)
+ return;
+ check_internal_connections(dpy);
+
+ serial = dpy->next_event_serial_num;
+ while(serial == dpy->next_event_serial_num || dpy->qlen == 0)
+ {
+ if(dpy->xcb->event_waiter)
+ {
+ ConditionWait(dpy, dpy->xcb->event_notify);
+ /* Maybe the other thread got us an event. */
+ continue;
+ }
+
+ if(!dpy->xcb->next_event)
+ {
+ xcb_generic_event_t *event;
+ dpy->xcb->event_waiter = 1;
+ UnlockDisplay(dpy);
+ event = xcb_wait_for_event(dpy->xcb->connection);
+ /* It appears that classic Xlib respected user
+ * locks when waking up after waiting for
+ * events. However, if this thread did not have
+ * any user locks, and another thread takes a
+ * user lock and tries to read events, then we'd
+ * deadlock. So we'll choose to let the thread
+ * that got in first consume events, despite the
+ * later thread's user locks. */
+ InternalLockDisplay(dpy, /* ignore user locks */ 1);
+ dpy->xcb->event_waiter = 0;
+ ConditionBroadcast(dpy, dpy->xcb->event_notify);
+ if(!event)
+ _XIOError(dpy);
+ dpy->xcb->next_event = event;
+ }
+
+ /* We've established most of the conditions for
+ * poll_for_response to return non-NULL. The exceptions
+ * are connection shutdown, and finding that another
+ * thread is waiting for the next reply we'd like to
+ * process. */
+
+ response = poll_for_response(dpy);
+ if(response)
+ handle_response(dpy, response, False);
+ else if(dpy->xcb->pending_requests->reply_waiter)
+ { /* need braces around ConditionWait */
+ ConditionWait(dpy, dpy->xcb->reply_notify);
+ }
+ else
+ _XIOError(dpy);
+ }
+
+ /* The preceding loop established that there is no
+ * event_waiter--unless we just called ConditionWait because of
+ * a reply_waiter, in which case another thread may have become
+ * the event_waiter while we slept unlocked. */
+ if(!dpy->xcb->event_waiter)
+ while((response = poll_for_response(dpy)))
+ handle_response(dpy, response, False);
+ if(xcb_connection_has_error(dpy->xcb->connection))
+ _XIOError(dpy);
+}
+
+/*
+ * _XSend - Flush the buffer and send the client data. 32 bit word aligned
+ * transmission is used, if size is not 0 mod 4, extra bytes are transmitted.
+ *
+ * Note that the connection must not be read from once the data currently
+ * in the buffer has been written.
+ */
+void _XSend(Display *dpy, const char *data, long size)
+{
+ static const xReq dummy_request;
+ static char const pad[3];
+ struct iovec vec[3];
+ uint64_t requests;
+ _XExtension *ext;
+ xcb_connection_t *c = dpy->xcb->connection;
+ if(dpy->flags & XlibDisplayIOError)
+ return;
+
+ if(dpy->bufptr == dpy->buffer && !size)
+ return;
+
+ /* iff we asked XCB to set aside errors, we must pick those up
+ * eventually. iff there are async handlers, we may have just
+ * issued requests that will generate replies. in either case,
+ * we need to remember to check later. */
+ if(dpy->xcb->event_owner != XlibOwnsEventQueue || dpy->async_handlers)
+ {
+ uint64_t sequence;
+ for(sequence = dpy->xcb->last_flushed + 1; sequence <= dpy->request; ++sequence)
+ append_pending_request(dpy, sequence);
+ }
+ requests = dpy->request - dpy->xcb->last_flushed;
+ dpy->xcb->last_flushed = dpy->request;
+
+ vec[0].iov_base = dpy->buffer;
+ vec[0].iov_len = dpy->bufptr - dpy->buffer;
+ vec[1].iov_base = (char *)data;
+ vec[1].iov_len = size;
+ vec[2].iov_base = (char *)pad;
+ vec[2].iov_len = -size & 3;
+
+ for(ext = dpy->flushes; ext; ext = ext->next_flush)
+ {
+ int i;
+ for(i = 0; i < 3; ++i)
+ if(vec[i].iov_len)
+ ext->before_flush(dpy, &ext->codes, vec[i].iov_base, vec[i].iov_len);
+ }
+
+ if(xcb_writev(c, vec, 3, requests) < 0)
+ _XIOError(dpy);
+ dpy->bufptr = dpy->buffer;
+ dpy->last_req = (char *) &dummy_request;
+
+ check_internal_connections(dpy);
+
+ _XSetSeqSyncFunction(dpy);
+}
+
+/*
+ * _XFlush - Flush the X request buffer. If the buffer is empty, no
+ * action is taken.
+ */
+void _XFlush(Display *dpy)
+{
+ require_socket(dpy);
+ _XSend(dpy, NULL, 0);
+
+ _XEventsQueued(dpy, QueuedAfterReading);
+}
+
+static const XID inval_id = ~0UL;
+
+void _XIDHandler(Display *dpy)
+{
+ if (dpy->xcb->next_xid == inval_id)
+ _XAllocIDs(dpy, &dpy->xcb->next_xid, 1);
+}
+
+/* _XAllocID - resource ID allocation routine. */
+XID _XAllocID(Display *dpy)
+{
+ XID ret = dpy->xcb->next_xid;
+ assert (ret != inval_id);
+ dpy->xcb->next_xid = inval_id;
+ _XSetPrivSyncFunction(dpy);
+ return ret;
+}
+
+/* _XAllocIDs - multiple resource ID allocation routine. */
+void _XAllocIDs(Display *dpy, XID *ids, int count)
+{
+ int i;
+#ifdef XTHREADS
+ if (dpy->lock)
+ (*dpy->lock->user_lock_display)(dpy);
+ UnlockDisplay(dpy);
+#endif
+ for (i = 0; i < count; i++)
+ ids[i] = xcb_generate_id(dpy->xcb->connection);
+#ifdef XTHREADS
+ InternalLockDisplay(dpy, /* don't skip user locks */ 0);
+ if (dpy->lock)
+ (*dpy->lock->user_unlock_display)(dpy);
+#endif
+}
+
+static void _XFreeReplyData(Display *dpy, Bool force)
+{
+ if(!force && dpy->xcb->reply_consumed < dpy->xcb->reply_length)
+ return;
+ free(dpy->xcb->reply_data);
+ dpy->xcb->reply_data = NULL;
+}
+
+/*
+ * _XReply - Wait for a reply packet and copy its contents into the
+ * specified rep.
+ * extra: number of 32-bit words expected after the reply
+ * discard: should I discard data following "extra" words?
+ */
+Status _XReply(Display *dpy, xReply *rep, int extra, Bool discard)
+{
+ xcb_generic_error_t *error;
+ xcb_connection_t *c = dpy->xcb->connection;
+ char *reply;
+ PendingRequest *current;
+
+ if (dpy->xcb->reply_data)
+ throw_extlib_fail_assert("Extra reply data still left in queue",
+ xcb_xlib_extra_reply_data_left);
+
+ if(dpy->flags & XlibDisplayIOError)
+ return 0;
+
+ _XSend(dpy, NULL, 0);
+ if(dpy->xcb->pending_requests_tail && dpy->xcb->pending_requests_tail->sequence == dpy->request)
+ current = dpy->xcb->pending_requests_tail;
+ else
+ current = append_pending_request(dpy, dpy->request);
+ /* Don't let any other thread get this reply. */
+ current->reply_waiter = 1;
+
+ while(1)
+ {
+ PendingRequest *req = dpy->xcb->pending_requests;
+ xcb_generic_reply_t *response;
+
+ if(req != current && req->reply_waiter)
+ {
+ ConditionWait(dpy, dpy->xcb->reply_notify);
+ /* Another thread got this reply. */
+ continue;
+ }
+ req->reply_waiter = 1;
+ UnlockDisplay(dpy);
+ response = xcb_wait_for_reply(c, req->sequence, &error);
+ /* Any user locks on another thread must have been taken
+ * while we slept in xcb_wait_for_reply. Classic Xlib
+ * ignored those user locks in this case, so we do too. */
+ InternalLockDisplay(dpy, /* ignore user locks */ 1);
+
+ /* We have the response we're looking for. Now, before
+ * letting anyone else process this sequence number, we
+ * need to process any events that should have come
+ * earlier. */
+
+ if(dpy->xcb->event_owner == XlibOwnsEventQueue)
+ {
+ xcb_generic_reply_t *event;
+ /* If some thread is already waiting for events,
+ * it will get the first one. That thread must
+ * process that event before we can continue. */
+ /* FIXME: That event might be after this reply,
+ * and might never even come--or there might be
+ * multiple threads trying to get events. */
+ while(dpy->xcb->event_waiter)
+ { /* need braces around ConditionWait */
+ ConditionWait(dpy, dpy->xcb->event_notify);
+ }
+ while((event = poll_for_event(dpy)))
+ handle_response(dpy, event, True);
+ }
+
+ req->reply_waiter = 0;
+ ConditionBroadcast(dpy, dpy->xcb->reply_notify);
+ if(XLIB_SEQUENCE_COMPARE(req->sequence, >, dpy->request)) {
+ throw_thread_fail_assert("Unknown sequence number "
+ "while processing reply",
+ xcb_xlib_threads_sequence_lost);
+ }
+ dpy->last_request_read = req->sequence;
+ if(!response)
+ dequeue_pending_request(dpy, req);
+
+ if(req == current)
+ {
+ reply = (char *) response;
+ break;
+ }
+
+ if(error)
+ handle_response(dpy, (xcb_generic_reply_t *) error, True);
+ else if(response)
+ handle_response(dpy, response, True);
+ }
+ check_internal_connections(dpy);
+
+ if(dpy->xcb->next_event && dpy->xcb->next_event->response_type == X_Error)
+ {
+ xcb_generic_event_t *event = dpy->xcb->next_event;
+ unsigned long event_sequence = dpy->last_request_read;
+ widen(&event_sequence, event->full_sequence);
+ if(event_sequence == dpy->last_request_read)
+ {
+ error = (xcb_generic_error_t *) event;
+ dpy->xcb->next_event = NULL;
+ }
+ }
+
+ if(error)
+ {
+ int ret_code;
+
+ /* Xlib is evil and assumes that even errors will be
+ * copied into rep. */
+ memcpy(rep, error, 32);
+
+ /* do not die on "no such font", "can't allocate",
+ "can't grab" failures */
+ switch(error->error_code)
+ {
+ case BadName:
+ switch(error->major_code)
+ {
+ case X_LookupColor:
+ case X_AllocNamedColor:
+ free(error);
+ return 0;
+ }
+ break;
+ case BadFont:
+ if(error->major_code == X_QueryFont) {
+ free(error);
+ return 0;
+ }
+ break;
+ case BadAlloc:
+ case BadAccess:
+ free(error);
+ return 0;
+ }
+
+ ret_code = handle_error(dpy, (xError *) error, True);
+ free(error);
+ return ret_code;
+ }
+
+ /* it's not an error, but we don't have a reply, so it's an I/O
+ * error. */
+ if(!reply)
+ {
+ _XIOError(dpy);
+ return 0;
+ }
+
+ /* there's no error and we have a reply. */
+ dpy->xcb->reply_data = reply;
+ dpy->xcb->reply_consumed = sizeof(xReply) + (extra * 4);
+ dpy->xcb->reply_length = sizeof(xReply);
+ if(dpy->xcb->reply_data[0] == 1)
+ dpy->xcb->reply_length += (((xcb_generic_reply_t *) dpy->xcb->reply_data)->length * 4);
+
+ /* error: Xlib asks too much. give them what we can anyway. */
+ if(dpy->xcb->reply_length < dpy->xcb->reply_consumed)
+ dpy->xcb->reply_consumed = dpy->xcb->reply_length;
+
+ memcpy(rep, dpy->xcb->reply_data, dpy->xcb->reply_consumed);
+ _XFreeReplyData(dpy, discard);
+ return 1;
+}
+
+int _XRead(Display *dpy, char *data, long size)
+{
+ assert(size >= 0);
+ if(size == 0)
+ return 0;
+ if(dpy->xcb->reply_data == NULL ||
+ dpy->xcb->reply_consumed + size > dpy->xcb->reply_length)
+ throw_extlib_fail_assert("Too much data requested from _XRead",
+ xcb_xlib_too_much_data_requested);
+ memcpy(data, dpy->xcb->reply_data + dpy->xcb->reply_consumed, size);
+ dpy->xcb->reply_consumed += size;
+ _XFreeReplyData(dpy, False);
+ return 0;
+}
+
+/*
+ * _XReadPad - Read bytes from the socket taking into account incomplete
+ * reads. If the number of bytes is not 0 mod 4, read additional pad
+ * bytes.
+ */
+void _XReadPad(Display *dpy, char *data, long size)
+{
+ _XRead(dpy, data, size);
+ dpy->xcb->reply_consumed += -size & 3;
+ _XFreeReplyData(dpy, False);
+}
+
+/* Read and discard "n" 8-bit bytes of data */
+void _XEatData(Display *dpy, unsigned long n)
+{
+ dpy->xcb->reply_consumed += n;
+ _XFreeReplyData(dpy, False);
+}