From b91444584a64f4f7b3eaeee05ef36ac53691fb24 Mon Sep 17 00:00:00 2001 From: marha Date: Mon, 12 Mar 2012 07:18:46 +0100 Subject: xkeyboard-config fontconfig libX11 libXft libxcb mesa git update 12 Mar 2012 --- libX11/src/OpenDis.c | 1459 ++++++++++++++++++++++++------------------------ libX11/src/xcb_io.c | 1518 +++++++++++++++++++++++++------------------------- 2 files changed, 1479 insertions(+), 1498 deletions(-) (limited to 'libX11/src') 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 -#endif -#include "Xlibint.h" -#include "Xxcbint.h" -#include -#include -#include -#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 +#endif +#include "Xlibint.h" +#include "Xxcbint.h" +#include +#include +#include +#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 -#endif - -#include "Xlibint.h" -#include "locking.h" -#include "Xprivate.h" -#include "Xxcbint.h" -#include - -#include -#ifdef HAVE_INTTYPES_H -#include -#endif -#include -#include -#include -#include -#ifdef HAVE_SYS_SELECT_H -#include -#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 +#endif + +#include "Xlibint.h" +#include "locking.h" +#include "Xprivate.h" +#include "Xxcbint.h" +#include + +#include +#ifdef HAVE_INTTYPES_H +#include +#endif +#include +#include +#include +#include +#ifdef HAVE_SYS_SELECT_H +#include +#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); +} -- cgit v1.2.3