xcb_io.c revision b4ee4795
11ab64890Smrg/* Copyright (C) 2003-2006 Jamey Sharp, Josh Triplett
21ab64890Smrg * This file is licensed under the MIT license. See the file COPYING. */
31ab64890Smrg
4b4ee4795Smrg#ifdef HAVE_CONFIG_H
5b4ee4795Smrg#include <config.h>
6b4ee4795Smrg#endif
7b4ee4795Smrg
81ab64890Smrg#include "Xlibint.h"
91ab64890Smrg#include "locking.h"
1061b2299dSmrg#include "Xprivate.h"
111ab64890Smrg#include "Xxcbint.h"
121ab64890Smrg#include <xcb/xcbext.h>
131ab64890Smrg
141ab64890Smrg#include <assert.h>
1561b2299dSmrg#include <inttypes.h>
1661b2299dSmrg#include <stdint.h>
171ab64890Smrg#include <stdlib.h>
181ab64890Smrg#include <string.h>
19b4ee4795Smrg#ifdef HAVE_SYS_SELECT_H
20b4ee4795Smrg#include <sys/select.h>
21b4ee4795Smrg#endif
221ab64890Smrg
2361b2299dSmrgstatic void return_socket(void *closure)
2461b2299dSmrg{
2561b2299dSmrg	Display *dpy = closure;
2661b2299dSmrg	LockDisplay(dpy);
2761b2299dSmrg	_XSend(dpy, NULL, 0);
2861b2299dSmrg	dpy->bufmax = dpy->buffer;
2961b2299dSmrg	UnlockDisplay(dpy);
3061b2299dSmrg}
3161b2299dSmrg
3261b2299dSmrgstatic void require_socket(Display *dpy)
3361b2299dSmrg{
3461b2299dSmrg	if(dpy->bufmax == dpy->buffer)
3561b2299dSmrg	{
3661b2299dSmrg		uint64_t sent;
3761b2299dSmrg		int flags = 0;
3861b2299dSmrg		/* if we don't own the event queue, we have to ask XCB
3961b2299dSmrg		 * to set our errors aside for us. */
4061b2299dSmrg		if(dpy->xcb->event_owner != XlibOwnsEventQueue)
4161b2299dSmrg			flags = XCB_REQUEST_CHECKED;
4261b2299dSmrg		if(!xcb_take_socket(dpy->xcb->connection, return_socket, dpy,
4361b2299dSmrg		                    flags, &sent))
4461b2299dSmrg			_XIOError(dpy);
4561b2299dSmrg		/* Xlib uses unsigned long for sequence numbers.  XCB
4661b2299dSmrg		 * uses 64-bit internally, but currently exposes an
4761b2299dSmrg		 * unsigned int API.  If these differ, Xlib cannot track
4861b2299dSmrg		 * the full 64-bit sequence number if 32-bit wrap
4961b2299dSmrg		 * happens while Xlib does not own the socket.  A
5061b2299dSmrg		 * complete fix would be to make XCB's public API use
5161b2299dSmrg		 * 64-bit sequence numbers. */
5261b2299dSmrg		assert(!(sizeof(unsigned long) > sizeof(unsigned int)
5361b2299dSmrg		         && dpy->xcb->event_owner == XlibOwnsEventQueue
5461b2299dSmrg		         && (sent - dpy->last_request_read >= (UINT64_C(1) << 32))));
5561b2299dSmrg		dpy->xcb->last_flushed = dpy->request = sent;
5661b2299dSmrg		dpy->bufmax = dpy->xcb->real_bufmax;
5761b2299dSmrg	}
5861b2299dSmrg}
5961b2299dSmrg
601ab64890Smrg/* Call internal connection callbacks for any fds that are currently
611ab64890Smrg * ready to read. This function will not block unless one of the
621ab64890Smrg * callbacks blocks.
631ab64890Smrg *
641ab64890Smrg * This code borrowed from _XWaitForReadable. Inverse call tree:
651ab64890Smrg * _XRead
661ab64890Smrg *  _XWaitForWritable
671ab64890Smrg *   _XFlush
681ab64890Smrg *   _XSend
691ab64890Smrg *  _XEventsQueued
701ab64890Smrg *  _XReadEvents
711ab64890Smrg *  _XRead[0-9]+
721ab64890Smrg *   _XAllocIDs
731ab64890Smrg *  _XReply
741ab64890Smrg *  _XEatData
751ab64890Smrg * _XReadPad
761ab64890Smrg */
771ab64890Smrgstatic void check_internal_connections(Display *dpy)
781ab64890Smrg{
7961b2299dSmrg	struct _XConnectionInfo *ilist;
801ab64890Smrg	fd_set r_mask;
811ab64890Smrg	struct timeval tv;
821ab64890Smrg	int result;
831ab64890Smrg	int highest_fd = -1;
841ab64890Smrg
851ab64890Smrg	if(dpy->flags & XlibDisplayProcConni || !dpy->im_fd_info)
861ab64890Smrg		return;
871ab64890Smrg
881ab64890Smrg	FD_ZERO(&r_mask);
891ab64890Smrg	for(ilist = dpy->im_fd_info; ilist; ilist = ilist->next)
901ab64890Smrg	{
911ab64890Smrg		assert(ilist->fd >= 0);
921ab64890Smrg		FD_SET(ilist->fd, &r_mask);
931ab64890Smrg		if(ilist->fd > highest_fd)
941ab64890Smrg			highest_fd = ilist->fd;
951ab64890Smrg	}
961ab64890Smrg	assert(highest_fd >= 0);
971ab64890Smrg
981ab64890Smrg	tv.tv_sec = 0;
991ab64890Smrg	tv.tv_usec = 0;
1001ab64890Smrg	result = select(highest_fd + 1, &r_mask, NULL, NULL, &tv);
1011ab64890Smrg
1021ab64890Smrg	if(result == -1)
1031ab64890Smrg	{
1041ab64890Smrg		if(errno == EINTR)
1051ab64890Smrg			return;
1061ab64890Smrg		_XIOError(dpy);
1071ab64890Smrg	}
1081ab64890Smrg
1091ab64890Smrg	for(ilist = dpy->im_fd_info; result && ilist; ilist = ilist->next)
1101ab64890Smrg		if(FD_ISSET(ilist->fd, &r_mask))
1111ab64890Smrg		{
1121ab64890Smrg			_XProcessInternalConnection(dpy, ilist);
1131ab64890Smrg			--result;
1141ab64890Smrg		}
1151ab64890Smrg}
1161ab64890Smrg
1171ab64890Smrgstatic void call_handlers(Display *dpy, xcb_generic_reply_t *buf)
1181ab64890Smrg{
1191ab64890Smrg	_XAsyncHandler *async, *next;
1201ab64890Smrg	for(async = dpy->async_handlers; async; async = next)
1211ab64890Smrg	{
1221ab64890Smrg		next = async->next;
1231ab64890Smrg		if(async->handler(dpy, (xReply *) buf, (char *) buf, sizeof(xReply) + (buf->length << 2), async->data))
1241ab64890Smrg			return;
1251ab64890Smrg	}
1261ab64890Smrg	if(buf->response_type == 0) /* unhandled error */
1271ab64890Smrg	    _XError(dpy, (xError *) buf);
1281ab64890Smrg}
1291ab64890Smrg
1301ab64890Smrgstatic xcb_generic_event_t * wait_or_poll_for_event(Display *dpy, int wait)
1311ab64890Smrg{
1321ab64890Smrg	xcb_connection_t *c = dpy->xcb->connection;
1331ab64890Smrg	xcb_generic_event_t *event;
1341ab64890Smrg	if(wait)
1351ab64890Smrg	{
13661b2299dSmrg		if(dpy->xcb->event_waiter)
13761b2299dSmrg		{
13861b2299dSmrg			ConditionWait(dpy, dpy->xcb->event_notify);
13961b2299dSmrg			event = xcb_poll_for_event(c);
14061b2299dSmrg		}
14161b2299dSmrg		else
14261b2299dSmrg		{
14361b2299dSmrg			dpy->xcb->event_waiter = 1;
14461b2299dSmrg			UnlockDisplay(dpy);
14561b2299dSmrg			event = xcb_wait_for_event(c);
14661b2299dSmrg			LockDisplay(dpy);
14761b2299dSmrg			dpy->xcb->event_waiter = 0;
14861b2299dSmrg			ConditionBroadcast(dpy, dpy->xcb->event_notify);
14961b2299dSmrg		}
1501ab64890Smrg	}
1511ab64890Smrg	else
1521ab64890Smrg		event = xcb_poll_for_event(c);
1531ab64890Smrg	return event;
1541ab64890Smrg}
1551ab64890Smrg
15661b2299dSmrg/* Widen a 32-bit sequence number into a native-word-size (unsigned long)
15761b2299dSmrg * sequence number.  Treating the comparison as a 1 and shifting it avoids a
15861b2299dSmrg * conditional branch, and shifting by 16 twice avoids a compiler warning when
15961b2299dSmrg * sizeof(unsigned long) == 4. */
16061b2299dSmrgstatic void widen(unsigned long *wide, unsigned int narrow)
16161b2299dSmrg{
16261b2299dSmrg	unsigned long new = (*wide & ~0xFFFFFFFFUL) | narrow;
16361b2299dSmrg	*wide = new + ((unsigned long) (new < *wide) << 16 << 16);
16461b2299dSmrg}
16561b2299dSmrg
16661b2299dSmrgstatic void process_responses(Display *dpy, int wait_for_first_event, xcb_generic_error_t **current_error, unsigned long current_request)
1671ab64890Smrg{
1681ab64890Smrg	void *reply;
1691ab64890Smrg	xcb_generic_event_t *event = dpy->xcb->next_event;
1701ab64890Smrg	xcb_generic_error_t *error;
1711ab64890Smrg	xcb_connection_t *c = dpy->xcb->connection;
1721ab64890Smrg	if(!event && dpy->xcb->event_owner == XlibOwnsEventQueue)
1731ab64890Smrg		event = wait_or_poll_for_event(dpy, wait_for_first_event);
1741ab64890Smrg
17561b2299dSmrg	require_socket(dpy);
17661b2299dSmrg
1771ab64890Smrg	while(1)
1781ab64890Smrg	{
1791ab64890Smrg		PendingRequest *req = dpy->xcb->pending_requests;
18061b2299dSmrg		unsigned long event_sequence = dpy->last_request_read;
18161b2299dSmrg		if(event)
18261b2299dSmrg			widen(&event_sequence, event->full_sequence);
18361b2299dSmrg		assert(!(req && current_request && !XLIB_SEQUENCE_COMPARE(req->sequence, <=, current_request)));
18461b2299dSmrg		if(event && (!req || XLIB_SEQUENCE_COMPARE(event_sequence, <=, req->sequence)))
1851ab64890Smrg		{
18661b2299dSmrg			dpy->last_request_read = event_sequence;
1871ab64890Smrg			if(event->response_type != X_Error)
1881ab64890Smrg			{
18961b2299dSmrg				/* GenericEvents may be > 32 bytes. In this
19061b2299dSmrg				 * case, the event struct is trailed by the
19161b2299dSmrg				 * additional bytes. the xcb_generic_event_t
19261b2299dSmrg				 * struct uses 4 bytes for internal numbering,
19361b2299dSmrg				 * so we need to shift the trailing data to be
19461b2299dSmrg				 * after the first 32 bytes.  */
19561b2299dSmrg                                if (event->response_type == GenericEvent &&
19661b2299dSmrg                                        ((xcb_ge_event_t*)event)->length)
19761b2299dSmrg				{
19861b2299dSmrg					memmove(&event->full_sequence,
19961b2299dSmrg                                                &event[1],
20061b2299dSmrg						((xcb_ge_event_t*)event)->length * 4);
20161b2299dSmrg				}
2021ab64890Smrg				_XEnq(dpy, (xEvent *) event);
2031ab64890Smrg				wait_for_first_event = 0;
2041ab64890Smrg			}
20561b2299dSmrg			else if(current_error && event_sequence == current_request)
2061ab64890Smrg			{
2071ab64890Smrg				/* This can only occur when called from
2081ab64890Smrg				 * _XReply, which doesn't need a new event. */
2091ab64890Smrg				*current_error = (xcb_generic_error_t *) event;
21061b2299dSmrg				event = NULL;
2111ab64890Smrg				break;
2121ab64890Smrg			}
2131ab64890Smrg			else
2141ab64890Smrg				_XError(dpy, (xError *) event);
2151ab64890Smrg			free(event);
2161ab64890Smrg			event = wait_or_poll_for_event(dpy, wait_for_first_event);
2171ab64890Smrg		}
21861b2299dSmrg		else if(req && req->sequence == current_request)
2191ab64890Smrg		{
22061b2299dSmrg			break;
2211ab64890Smrg		}
2221ab64890Smrg		else if(req && xcb_poll_for_reply(dpy->xcb->connection, req->sequence, &reply, &error))
2231ab64890Smrg		{
2242e9c7c8cSmrg			uint64_t sequence = req->sequence;
2251ab64890Smrg			if(!reply)
2261ab64890Smrg			{
2271ab64890Smrg				dpy->xcb->pending_requests = req->next;
2281ab64890Smrg				if(!dpy->xcb->pending_requests)
2291ab64890Smrg					dpy->xcb->pending_requests_tail = &dpy->xcb->pending_requests;
2301ab64890Smrg				free(req);
2311ab64890Smrg				reply = error;
2321ab64890Smrg			}
2331ab64890Smrg			if(reply)
2341ab64890Smrg			{
2351ab64890Smrg				dpy->last_request_read = sequence;
2361ab64890Smrg				call_handlers(dpy, reply);
2371ab64890Smrg				free(reply);
2381ab64890Smrg			}
2391ab64890Smrg		}
2401ab64890Smrg		else
2411ab64890Smrg			break;
2421ab64890Smrg	}
2431ab64890Smrg
2441ab64890Smrg	dpy->xcb->next_event = event;
2451ab64890Smrg
2461ab64890Smrg	if(xcb_connection_has_error(c))
2471ab64890Smrg		_XIOError(dpy);
2481ab64890Smrg
24961b2299dSmrg	assert(XLIB_SEQUENCE_COMPARE(dpy->last_request_read, <=, dpy->request));
2501ab64890Smrg}
2511ab64890Smrg
2521ab64890Smrgint _XEventsQueued(Display *dpy, int mode)
2531ab64890Smrg{
2541ab64890Smrg	if(dpy->flags & XlibDisplayIOError)
2551ab64890Smrg		return 0;
2561ab64890Smrg	if(dpy->xcb->event_owner != XlibOwnsEventQueue)
2571ab64890Smrg		return 0;
2581ab64890Smrg
2591ab64890Smrg	if(mode == QueuedAfterFlush)
26061b2299dSmrg		_XSend(dpy, NULL, 0);
2611ab64890Smrg	else
2621ab64890Smrg		check_internal_connections(dpy);
26361b2299dSmrg	process_responses(dpy, 0, NULL, 0);
2641ab64890Smrg	return dpy->qlen;
2651ab64890Smrg}
2661ab64890Smrg
2671ab64890Smrg/* _XReadEvents - Flush the output queue,
2681ab64890Smrg * then read as many events as possible (but at least 1) and enqueue them
2691ab64890Smrg */
2701ab64890Smrgvoid _XReadEvents(Display *dpy)
2711ab64890Smrg{
2721ab64890Smrg	if(dpy->flags & XlibDisplayIOError)
2731ab64890Smrg		return;
27461b2299dSmrg	_XSend(dpy, NULL, 0);
2751ab64890Smrg	if(dpy->xcb->event_owner != XlibOwnsEventQueue)
2761ab64890Smrg		return;
2771ab64890Smrg	check_internal_connections(dpy);
27861b2299dSmrg	do {
27961b2299dSmrg		process_responses(dpy, 1, NULL, 0);
28061b2299dSmrg	} while (dpy->qlen == 0);
2811ab64890Smrg}
2821ab64890Smrg
2831ab64890Smrg/*
2841ab64890Smrg * _XSend - Flush the buffer and send the client data. 32 bit word aligned
2851ab64890Smrg * transmission is used, if size is not 0 mod 4, extra bytes are transmitted.
2861ab64890Smrg *
2871ab64890Smrg * Note that the connection must not be read from once the data currently
2881ab64890Smrg * in the buffer has been written.
2891ab64890Smrg */
2901ab64890Smrgvoid _XSend(Display *dpy, const char *data, long size)
2911ab64890Smrg{
29261b2299dSmrg	static const xReq dummy_request;
29361b2299dSmrg	static char const pad[3];
29461b2299dSmrg	struct iovec vec[3];
29561b2299dSmrg	uint64_t requests;
29661b2299dSmrg	_XExtension *ext;
2971ab64890Smrg	xcb_connection_t *c = dpy->xcb->connection;
2981ab64890Smrg	if(dpy->flags & XlibDisplayIOError)
2991ab64890Smrg		return;
3001ab64890Smrg
30161b2299dSmrg	if(dpy->bufptr == dpy->buffer && !size)
30261b2299dSmrg		return;
3031ab64890Smrg
30461b2299dSmrg	/* iff we asked XCB to set aside errors, we must pick those up
30561b2299dSmrg	 * eventually. iff there are async handlers, we may have just
30661b2299dSmrg	 * issued requests that will generate replies. in either case,
30761b2299dSmrg	 * we need to remember to check later. */
30861b2299dSmrg	if(dpy->xcb->event_owner != XlibOwnsEventQueue || dpy->async_handlers)
30961b2299dSmrg	{
3102e9c7c8cSmrg		uint64_t sequence;
31161b2299dSmrg		for(sequence = dpy->xcb->last_flushed; sequence < dpy->request; ++sequence)
31261b2299dSmrg		{
31361b2299dSmrg			PendingRequest *req = malloc(sizeof(PendingRequest));
31461b2299dSmrg			assert(req);
31561b2299dSmrg			req->next = NULL;
31661b2299dSmrg			req->sequence = sequence;
31761b2299dSmrg			*dpy->xcb->pending_requests_tail = req;
31861b2299dSmrg			dpy->xcb->pending_requests_tail = &req->next;
31961b2299dSmrg		}
32061b2299dSmrg	}
32161b2299dSmrg	requests = dpy->request - dpy->xcb->last_flushed;
32261b2299dSmrg	dpy->xcb->last_flushed = dpy->request;
3231ab64890Smrg
32461b2299dSmrg	vec[0].iov_base = dpy->buffer;
32561b2299dSmrg	vec[0].iov_len = dpy->bufptr - dpy->buffer;
32661b2299dSmrg	vec[1].iov_base = (caddr_t) data;
32761b2299dSmrg	vec[1].iov_len = size;
32861b2299dSmrg	vec[2].iov_base = (caddr_t) pad;
32961b2299dSmrg	vec[2].iov_len = -size & 3;
33061b2299dSmrg
33161b2299dSmrg	for(ext = dpy->flushes; ext; ext = ext->next_flush)
33261b2299dSmrg	{
33361b2299dSmrg		int i;
33461b2299dSmrg		for(i = 0; i < 3; ++i)
33561b2299dSmrg			if(vec[i].iov_len)
33661b2299dSmrg				ext->before_flush(dpy, &ext->codes, vec[i].iov_base, vec[i].iov_len);
33761b2299dSmrg	}
3381ab64890Smrg
33961b2299dSmrg	if(xcb_writev(c, vec, 3, requests) < 0)
34061b2299dSmrg		_XIOError(dpy);
34161b2299dSmrg	dpy->bufptr = dpy->buffer;
34261b2299dSmrg	dpy->last_req = (char *) &dummy_request;
3431ab64890Smrg
3441ab64890Smrg	check_internal_connections(dpy);
3451ab64890Smrg
34661b2299dSmrg	_XSetSeqSyncFunction(dpy);
3471ab64890Smrg}
3481ab64890Smrg
3491ab64890Smrg/*
3501ab64890Smrg * _XFlush - Flush the X request buffer.  If the buffer is empty, no
3511ab64890Smrg * action is taken.
3521ab64890Smrg */
3531ab64890Smrgvoid _XFlush(Display *dpy)
3541ab64890Smrg{
35561b2299dSmrg	require_socket(dpy);
35661b2299dSmrg	_XSend(dpy, NULL, 0);
3571ab64890Smrg
3581ab64890Smrg	_XEventsQueued(dpy, QueuedAfterReading);
3591ab64890Smrg}
3601ab64890Smrg
36161b2299dSmrgstatic const XID inval_id = ~0UL;
36261b2299dSmrg
36361b2299dSmrgint _XIDHandler(Display *dpy)
3641ab64890Smrg{
36561b2299dSmrg	XID next;
36661b2299dSmrg
36761b2299dSmrg	if (dpy->xcb->next_xid != inval_id)
36861b2299dSmrg	    return 0;
36961b2299dSmrg
37061b2299dSmrg	next = xcb_generate_id(dpy->xcb->connection);
3711ab64890Smrg	LockDisplay(dpy);
3721ab64890Smrg	dpy->xcb->next_xid = next;
37361b2299dSmrg#ifdef XTHREADS
37461b2299dSmrg	if (dpy->lock)
37561b2299dSmrg		(*dpy->lock->user_unlock_display)(dpy);
37661b2299dSmrg#endif
3771ab64890Smrg	UnlockDisplay(dpy);
3781ab64890Smrg	return 0;
3791ab64890Smrg}
3801ab64890Smrg
3811ab64890Smrg/* _XAllocID - resource ID allocation routine. */
3821ab64890SmrgXID _XAllocID(Display *dpy)
3831ab64890Smrg{
3841ab64890Smrg	XID ret = dpy->xcb->next_xid;
38561b2299dSmrg	assert (ret != inval_id);
38661b2299dSmrg#ifdef XTHREADS
38761b2299dSmrg	if (dpy->lock)
38861b2299dSmrg		(*dpy->lock->user_lock_display)(dpy);
38961b2299dSmrg#endif
39061b2299dSmrg	dpy->xcb->next_xid = inval_id;
39161b2299dSmrg	_XSetPrivSyncFunction(dpy);
3921ab64890Smrg	return ret;
3931ab64890Smrg}
3941ab64890Smrg
3951ab64890Smrg/* _XAllocIDs - multiple resource ID allocation routine. */
3961ab64890Smrgvoid _XAllocIDs(Display *dpy, XID *ids, int count)
3971ab64890Smrg{
3981ab64890Smrg	int i;
39961b2299dSmrg#ifdef XTHREADS
40061b2299dSmrg	if (dpy->lock)
40161b2299dSmrg		(*dpy->lock->user_lock_display)(dpy);
40261b2299dSmrg	UnlockDisplay(dpy);
40361b2299dSmrg#endif
4041ab64890Smrg	for (i = 0; i < count; i++)
4051ab64890Smrg		ids[i] = xcb_generate_id(dpy->xcb->connection);
40661b2299dSmrg#ifdef XTHREADS
40761b2299dSmrg	LockDisplay(dpy);
40861b2299dSmrg	if (dpy->lock)
40961b2299dSmrg		(*dpy->lock->user_unlock_display)(dpy);
41061b2299dSmrg#endif
4111ab64890Smrg}
4121ab64890Smrg
4131ab64890Smrgstatic void _XFreeReplyData(Display *dpy, Bool force)
4141ab64890Smrg{
4151ab64890Smrg	if(!force && dpy->xcb->reply_consumed < dpy->xcb->reply_length)
4161ab64890Smrg		return;
4171ab64890Smrg	free(dpy->xcb->reply_data);
41861b2299dSmrg	dpy->xcb->reply_data = NULL;
4191ab64890Smrg}
4201ab64890Smrg
4211ab64890Smrgstatic PendingRequest * insert_pending_request(Display *dpy)
4221ab64890Smrg{
4231ab64890Smrg	PendingRequest **cur = &dpy->xcb->pending_requests;
42461b2299dSmrg	while(*cur && XLIB_SEQUENCE_COMPARE((*cur)->sequence, <, dpy->request))
4251ab64890Smrg		cur = &((*cur)->next);
42661b2299dSmrg	if(!*cur || (*cur)->sequence != dpy->request)
4271ab64890Smrg	{
4281ab64890Smrg		PendingRequest *node = malloc(sizeof(PendingRequest));
4291ab64890Smrg		assert(node);
4301ab64890Smrg		node->next = *cur;
4311ab64890Smrg		node->sequence = dpy->request;
4321ab64890Smrg		if(cur == dpy->xcb->pending_requests_tail)
4331ab64890Smrg			dpy->xcb->pending_requests_tail = &(node->next);
4341ab64890Smrg		*cur = node;
4351ab64890Smrg	}
4361ab64890Smrg	return *cur;
4371ab64890Smrg}
4381ab64890Smrg
4391ab64890Smrg/*
4401ab64890Smrg * _XReply - Wait for a reply packet and copy its contents into the
4411ab64890Smrg * specified rep.
4421ab64890Smrg * extra: number of 32-bit words expected after the reply
4431ab64890Smrg * discard: should I discard data following "extra" words?
4441ab64890Smrg */
4451ab64890SmrgStatus _XReply(Display *dpy, xReply *rep, int extra, Bool discard)
4461ab64890Smrg{
4471ab64890Smrg	xcb_generic_error_t *error;
4481ab64890Smrg	xcb_connection_t *c = dpy->xcb->connection;
4491ab64890Smrg	char *reply;
4501ab64890Smrg	PendingRequest *current;
4511ab64890Smrg
4521ab64890Smrg	assert(!dpy->xcb->reply_data);
4531ab64890Smrg
4541ab64890Smrg	if(dpy->flags & XlibDisplayIOError)
4551ab64890Smrg		return 0;
4561ab64890Smrg
45761b2299dSmrg	_XSend(dpy, NULL, 0);
4581ab64890Smrg	current = insert_pending_request(dpy);
45961b2299dSmrg	/* FIXME: drop the Display lock while waiting?
46061b2299dSmrg	 * Complicates process_responses. */
4611ab64890Smrg	reply = xcb_wait_for_reply(c, current->sequence, &error);
4621ab64890Smrg
4631ab64890Smrg	check_internal_connections(dpy);
4641ab64890Smrg	process_responses(dpy, 0, &error, current->sequence);
4651ab64890Smrg
4661ab64890Smrg	if(error)
4671ab64890Smrg	{
4681ab64890Smrg		_XExtension *ext;
4691ab64890Smrg		xError *err = (xError *) error;
4701ab64890Smrg		int ret_code;
4711ab64890Smrg
4721ab64890Smrg		dpy->last_request_read = error->full_sequence;
4731ab64890Smrg
4741ab64890Smrg		/* Xlib is evil and assumes that even errors will be
4751ab64890Smrg		 * copied into rep. */
4761ab64890Smrg		memcpy(rep, error, 32);
4771ab64890Smrg
4781ab64890Smrg		/* do not die on "no such font", "can't allocate",
4791ab64890Smrg		   "can't grab" failures */
4801ab64890Smrg		switch(err->errorCode)
4811ab64890Smrg		{
4821ab64890Smrg			case BadName:
4831ab64890Smrg				switch(err->majorCode)
4841ab64890Smrg				{
4851ab64890Smrg					case X_LookupColor:
4861ab64890Smrg					case X_AllocNamedColor:
48761b2299dSmrg						free(error);
4881ab64890Smrg						return 0;
4891ab64890Smrg				}
4901ab64890Smrg				break;
4911ab64890Smrg			case BadFont:
49261b2299dSmrg				if(err->majorCode == X_QueryFont) {
49361b2299dSmrg					free(error);
4941ab64890Smrg					return 0;
49561b2299dSmrg				}
4961ab64890Smrg				break;
4971ab64890Smrg			case BadAlloc:
4981ab64890Smrg			case BadAccess:
49961b2299dSmrg				free(error);
5001ab64890Smrg				return 0;
5011ab64890Smrg		}
5021ab64890Smrg
50361b2299dSmrg		/*
5041ab64890Smrg		 * we better see if there is an extension who may
5051ab64890Smrg		 * want to suppress the error.
5061ab64890Smrg		 */
5071ab64890Smrg		for(ext = dpy->ext_procs; ext; ext = ext->next)
50861b2299dSmrg			if(ext->error && ext->error(dpy, err, &ext->codes, &ret_code)) {
50961b2299dSmrg				free(error);
5101ab64890Smrg				return ret_code;
51161b2299dSmrg			}
5121ab64890Smrg
51361b2299dSmrg		_XError(dpy, err);
51461b2299dSmrg		free(error);
5151ab64890Smrg		return 0;
5161ab64890Smrg	}
5171ab64890Smrg
5181ab64890Smrg	/* it's not an error, but we don't have a reply, so it's an I/O
5191ab64890Smrg	 * error. */
5201ab64890Smrg	if(!reply)
5211ab64890Smrg	{
5221ab64890Smrg		_XIOError(dpy);
5231ab64890Smrg		return 0;
5241ab64890Smrg	}
5251ab64890Smrg
5261ab64890Smrg	dpy->last_request_read = current->sequence;
5271ab64890Smrg
5281ab64890Smrg	/* there's no error and we have a reply. */
5291ab64890Smrg	dpy->xcb->reply_data = reply;
5301ab64890Smrg	dpy->xcb->reply_consumed = sizeof(xReply) + (extra * 4);
5311ab64890Smrg	dpy->xcb->reply_length = sizeof(xReply);
5321ab64890Smrg	if(dpy->xcb->reply_data[0] == 1)
5331ab64890Smrg		dpy->xcb->reply_length += (((xcb_generic_reply_t *) dpy->xcb->reply_data)->length * 4);
5341ab64890Smrg
5351ab64890Smrg	/* error: Xlib asks too much. give them what we can anyway. */
5361ab64890Smrg	if(dpy->xcb->reply_length < dpy->xcb->reply_consumed)
5371ab64890Smrg		dpy->xcb->reply_consumed = dpy->xcb->reply_length;
5381ab64890Smrg
5391ab64890Smrg	memcpy(rep, dpy->xcb->reply_data, dpy->xcb->reply_consumed);
5401ab64890Smrg	_XFreeReplyData(dpy, discard);
5411ab64890Smrg	return 1;
5421ab64890Smrg}
5431ab64890Smrg
5441ab64890Smrgint _XRead(Display *dpy, char *data, long size)
5451ab64890Smrg{
5461ab64890Smrg	assert(size >= 0);
5471ab64890Smrg	if(size == 0)
5481ab64890Smrg		return 0;
54961b2299dSmrg	assert(dpy->xcb->reply_data != NULL);
5501ab64890Smrg	assert(dpy->xcb->reply_consumed + size <= dpy->xcb->reply_length);
5511ab64890Smrg	memcpy(data, dpy->xcb->reply_data + dpy->xcb->reply_consumed, size);
5521ab64890Smrg	dpy->xcb->reply_consumed += size;
5531ab64890Smrg	_XFreeReplyData(dpy, False);
5541ab64890Smrg	return 0;
5551ab64890Smrg}
5561ab64890Smrg
5571ab64890Smrg/*
5581ab64890Smrg * _XReadPad - Read bytes from the socket taking into account incomplete
5591ab64890Smrg * reads.  If the number of bytes is not 0 mod 4, read additional pad
5601ab64890Smrg * bytes.
5611ab64890Smrg */
5621ab64890Smrgvoid _XReadPad(Display *dpy, char *data, long size)
5631ab64890Smrg{
5641ab64890Smrg	_XRead(dpy, data, size);
5651ab64890Smrg	dpy->xcb->reply_consumed += -size & 3;
5661ab64890Smrg	_XFreeReplyData(dpy, False);
5671ab64890Smrg}
5681ab64890Smrg
5691ab64890Smrg/* Read and discard "n" 8-bit bytes of data */
5701ab64890Smrgvoid _XEatData(Display *dpy, unsigned long n)
5711ab64890Smrg{
5721ab64890Smrg	dpy->xcb->reply_consumed += n;
5731ab64890Smrg	_XFreeReplyData(dpy, False);
5741ab64890Smrg}
575