xcb_io.c revision 57f47464
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>
1588de56ccSmrg#ifdef HAVE_INTTYPES_H
1661b2299dSmrg#include <inttypes.h>
1788de56ccSmrg#endif
1861b2299dSmrg#include <stdint.h>
191ab64890Smrg#include <stdlib.h>
201ab64890Smrg#include <string.h>
21b4ee4795Smrg#ifdef HAVE_SYS_SELECT_H
22b4ee4795Smrg#include <sys/select.h>
23b4ee4795Smrg#endif
241ab64890Smrg
2561b2299dSmrgstatic void return_socket(void *closure)
2661b2299dSmrg{
2761b2299dSmrg	Display *dpy = closure;
2888de56ccSmrg	InternalLockDisplay(dpy, /* don't skip user locks */ 0);
2961b2299dSmrg	_XSend(dpy, NULL, 0);
3061b2299dSmrg	dpy->bufmax = dpy->buffer;
3161b2299dSmrg	UnlockDisplay(dpy);
3261b2299dSmrg}
3361b2299dSmrg
3461b2299dSmrgstatic void require_socket(Display *dpy)
3561b2299dSmrg{
3661b2299dSmrg	if(dpy->bufmax == dpy->buffer)
3761b2299dSmrg	{
3861b2299dSmrg		uint64_t sent;
3961b2299dSmrg		int flags = 0;
4061b2299dSmrg		/* if we don't own the event queue, we have to ask XCB
4161b2299dSmrg		 * to set our errors aside for us. */
4261b2299dSmrg		if(dpy->xcb->event_owner != XlibOwnsEventQueue)
4361b2299dSmrg			flags = XCB_REQUEST_CHECKED;
4461b2299dSmrg		if(!xcb_take_socket(dpy->xcb->connection, return_socket, dpy,
4561b2299dSmrg		                    flags, &sent))
4661b2299dSmrg			_XIOError(dpy);
4761b2299dSmrg		/* Xlib uses unsigned long for sequence numbers.  XCB
4861b2299dSmrg		 * uses 64-bit internally, but currently exposes an
4961b2299dSmrg		 * unsigned int API.  If these differ, Xlib cannot track
5061b2299dSmrg		 * the full 64-bit sequence number if 32-bit wrap
5161b2299dSmrg		 * happens while Xlib does not own the socket.  A
5261b2299dSmrg		 * complete fix would be to make XCB's public API use
5361b2299dSmrg		 * 64-bit sequence numbers. */
5461b2299dSmrg		assert(!(sizeof(unsigned long) > sizeof(unsigned int)
5561b2299dSmrg		         && dpy->xcb->event_owner == XlibOwnsEventQueue
5661b2299dSmrg		         && (sent - dpy->last_request_read >= (UINT64_C(1) << 32))));
5761b2299dSmrg		dpy->xcb->last_flushed = dpy->request = sent;
5861b2299dSmrg		dpy->bufmax = dpy->xcb->real_bufmax;
5961b2299dSmrg	}
6061b2299dSmrg}
6161b2299dSmrg
621ab64890Smrg/* Call internal connection callbacks for any fds that are currently
631ab64890Smrg * ready to read. This function will not block unless one of the
641ab64890Smrg * callbacks blocks.
651ab64890Smrg *
661ab64890Smrg * This code borrowed from _XWaitForReadable. Inverse call tree:
671ab64890Smrg * _XRead
681ab64890Smrg *  _XWaitForWritable
691ab64890Smrg *   _XFlush
701ab64890Smrg *   _XSend
711ab64890Smrg *  _XEventsQueued
721ab64890Smrg *  _XReadEvents
731ab64890Smrg *  _XRead[0-9]+
741ab64890Smrg *   _XAllocIDs
751ab64890Smrg *  _XReply
761ab64890Smrg *  _XEatData
771ab64890Smrg * _XReadPad
781ab64890Smrg */
791ab64890Smrgstatic void check_internal_connections(Display *dpy)
801ab64890Smrg{
8161b2299dSmrg	struct _XConnectionInfo *ilist;
821ab64890Smrg	fd_set r_mask;
831ab64890Smrg	struct timeval tv;
841ab64890Smrg	int result;
851ab64890Smrg	int highest_fd = -1;
861ab64890Smrg
871ab64890Smrg	if(dpy->flags & XlibDisplayProcConni || !dpy->im_fd_info)
881ab64890Smrg		return;
891ab64890Smrg
901ab64890Smrg	FD_ZERO(&r_mask);
911ab64890Smrg	for(ilist = dpy->im_fd_info; ilist; ilist = ilist->next)
921ab64890Smrg	{
931ab64890Smrg		assert(ilist->fd >= 0);
941ab64890Smrg		FD_SET(ilist->fd, &r_mask);
951ab64890Smrg		if(ilist->fd > highest_fd)
961ab64890Smrg			highest_fd = ilist->fd;
971ab64890Smrg	}
981ab64890Smrg	assert(highest_fd >= 0);
991ab64890Smrg
1001ab64890Smrg	tv.tv_sec = 0;
1011ab64890Smrg	tv.tv_usec = 0;
1021ab64890Smrg	result = select(highest_fd + 1, &r_mask, NULL, NULL, &tv);
1031ab64890Smrg
1041ab64890Smrg	if(result == -1)
1051ab64890Smrg	{
1061ab64890Smrg		if(errno == EINTR)
1071ab64890Smrg			return;
1081ab64890Smrg		_XIOError(dpy);
1091ab64890Smrg	}
1101ab64890Smrg
1111ab64890Smrg	for(ilist = dpy->im_fd_info; result && ilist; ilist = ilist->next)
1121ab64890Smrg		if(FD_ISSET(ilist->fd, &r_mask))
1131ab64890Smrg		{
1141ab64890Smrg			_XProcessInternalConnection(dpy, ilist);
1151ab64890Smrg			--result;
1161ab64890Smrg		}
1171ab64890Smrg}
1181ab64890Smrg
11988de56ccSmrgstatic PendingRequest *append_pending_request(Display *dpy, unsigned long sequence)
1201ab64890Smrg{
12188de56ccSmrg	PendingRequest *node = malloc(sizeof(PendingRequest));
12288de56ccSmrg	assert(node);
12388de56ccSmrg	node->next = NULL;
12488de56ccSmrg	node->sequence = sequence;
12588de56ccSmrg	node->reply_waiter = 0;
12688de56ccSmrg	if(dpy->xcb->pending_requests_tail)
1271ab64890Smrg	{
12888de56ccSmrg		assert(XLIB_SEQUENCE_COMPARE(dpy->xcb->pending_requests_tail->sequence, <, node->sequence));
12988de56ccSmrg		assert(dpy->xcb->pending_requests_tail->next == NULL);
13088de56ccSmrg		dpy->xcb->pending_requests_tail->next = node;
1311ab64890Smrg	}
13288de56ccSmrg	else
13388de56ccSmrg		dpy->xcb->pending_requests = node;
13488de56ccSmrg	dpy->xcb->pending_requests_tail = node;
13588de56ccSmrg	return node;
1361ab64890Smrg}
1371ab64890Smrg
13888de56ccSmrgstatic void dequeue_pending_request(Display *dpy, PendingRequest *req)
1391ab64890Smrg{
14088de56ccSmrg	assert(req == dpy->xcb->pending_requests);
14188de56ccSmrg	dpy->xcb->pending_requests = req->next;
14288de56ccSmrg	if(!dpy->xcb->pending_requests)
1431ab64890Smrg	{
14488de56ccSmrg		assert(req == dpy->xcb->pending_requests_tail);
14588de56ccSmrg		dpy->xcb->pending_requests_tail = NULL;
1461ab64890Smrg	}
1471ab64890Smrg	else
14888de56ccSmrg		assert(XLIB_SEQUENCE_COMPARE(req->sequence, <, dpy->xcb->pending_requests->sequence));
14988de56ccSmrg	free(req);
15088de56ccSmrg}
15188de56ccSmrg
15288de56ccSmrgstatic int handle_error(Display *dpy, xError *err, Bool in_XReply)
15388de56ccSmrg{
15488de56ccSmrg	_XExtension *ext;
15588de56ccSmrg	int ret_code;
15688de56ccSmrg	/* Oddly, Xlib only allows extensions to suppress errors when
15788de56ccSmrg	 * those errors were seen by _XReply. */
15888de56ccSmrg	if(in_XReply)
15988de56ccSmrg		/*
16088de56ccSmrg		 * we better see if there is an extension who may
16188de56ccSmrg		 * want to suppress the error.
16288de56ccSmrg		 */
16388de56ccSmrg		for(ext = dpy->ext_procs; ext; ext = ext->next)
16488de56ccSmrg			if(ext->error && (*ext->error)(dpy, err, &ext->codes, &ret_code))
16588de56ccSmrg				return ret_code;
16688de56ccSmrg	_XError(dpy, err);
16788de56ccSmrg	return 0;
1681ab64890Smrg}
1691ab64890Smrg
17061b2299dSmrg/* Widen a 32-bit sequence number into a native-word-size (unsigned long)
17161b2299dSmrg * sequence number.  Treating the comparison as a 1 and shifting it avoids a
17261b2299dSmrg * conditional branch, and shifting by 16 twice avoids a compiler warning when
17361b2299dSmrg * sizeof(unsigned long) == 4. */
17461b2299dSmrgstatic void widen(unsigned long *wide, unsigned int narrow)
17561b2299dSmrg{
17661b2299dSmrg	unsigned long new = (*wide & ~0xFFFFFFFFUL) | narrow;
17761b2299dSmrg	*wide = new + ((unsigned long) (new < *wide) << 16 << 16);
17861b2299dSmrg}
17961b2299dSmrg
18088de56ccSmrg/* Thread-safety rules:
18188de56ccSmrg *
18288de56ccSmrg * At most one thread can be reading from XCB's event queue at a time.
18388de56ccSmrg * If you are not the current event-reading thread and you need to find
18488de56ccSmrg * out if an event is available, you must wait.
18588de56ccSmrg *
18688de56ccSmrg * The same rule applies for reading replies.
18788de56ccSmrg *
18888de56ccSmrg * A single thread cannot be both the the event-reading and the
18988de56ccSmrg * reply-reading thread at the same time.
19088de56ccSmrg *
19188de56ccSmrg * We always look at both the current event and the first pending reply
19288de56ccSmrg * to decide which to process next.
19388de56ccSmrg *
19488de56ccSmrg * We always process all responses in sequence-number order, which may
19588de56ccSmrg * mean waiting for another thread (either the event_waiter or the
19688de56ccSmrg * reply_waiter) to handle an earlier response before we can process or
19788de56ccSmrg * return a later one. If so, we wait on the corresponding condition
19888de56ccSmrg * variable for that thread to process the response and wake us up.
19988de56ccSmrg */
2001ab64890Smrg
20188de56ccSmrgstatic xcb_generic_reply_t *poll_for_event(Display *dpy)
20288de56ccSmrg{
20388de56ccSmrg	/* Make sure the Display's sequence numbers are valid */
20461b2299dSmrg	require_socket(dpy);
20561b2299dSmrg
20688de56ccSmrg	/* Precondition: This thread can safely get events from XCB. */
20788de56ccSmrg	assert(dpy->xcb->event_owner == XlibOwnsEventQueue && !dpy->xcb->event_waiter);
20888de56ccSmrg
20988de56ccSmrg	if(!dpy->xcb->next_event)
21088de56ccSmrg		dpy->xcb->next_event = xcb_poll_for_event(dpy->xcb->connection);
21188de56ccSmrg
21288de56ccSmrg	if(dpy->xcb->next_event)
2131ab64890Smrg	{
2141ab64890Smrg		PendingRequest *req = dpy->xcb->pending_requests;
21588de56ccSmrg		xcb_generic_event_t *event = dpy->xcb->next_event;
21661b2299dSmrg		unsigned long event_sequence = dpy->last_request_read;
21788de56ccSmrg		widen(&event_sequence, event->full_sequence);
21888de56ccSmrg		if(!req || XLIB_SEQUENCE_COMPARE(event_sequence, <, req->sequence)
21988de56ccSmrg		        || (event->response_type != X_Error && event_sequence == req->sequence))
2201ab64890Smrg		{
22188de56ccSmrg			assert(XLIB_SEQUENCE_COMPARE(event_sequence, <=, dpy->request));
22261b2299dSmrg			dpy->last_request_read = event_sequence;
22388de56ccSmrg			dpy->xcb->next_event = NULL;
22488de56ccSmrg			return (xcb_generic_reply_t *) event;
2251ab64890Smrg		}
22688de56ccSmrg	}
22788de56ccSmrg	return NULL;
22888de56ccSmrg}
22988de56ccSmrg
23088de56ccSmrgstatic xcb_generic_reply_t *poll_for_response(Display *dpy)
23188de56ccSmrg{
23288de56ccSmrg	void *response;
23388de56ccSmrg	xcb_generic_error_t *error;
23488de56ccSmrg	PendingRequest *req;
23588de56ccSmrg	while(!(response = poll_for_event(dpy)) &&
23688de56ccSmrg	      (req = dpy->xcb->pending_requests) &&
23788de56ccSmrg	      !req->reply_waiter &&
23888de56ccSmrg	      xcb_poll_for_reply(dpy->xcb->connection, req->sequence, &response, &error))
23988de56ccSmrg	{
24088de56ccSmrg		assert(XLIB_SEQUENCE_COMPARE(req->sequence, <=, dpy->request));
24188de56ccSmrg		dpy->last_request_read = req->sequence;
242e9fcaa8aSmrg		if(response)
243e9fcaa8aSmrg			break;
244e9fcaa8aSmrg		dequeue_pending_request(dpy, req);
24588de56ccSmrg		if(error)
24688de56ccSmrg			return (xcb_generic_reply_t *) error;
24788de56ccSmrg	}
24888de56ccSmrg	return response;
24988de56ccSmrg}
25088de56ccSmrg
25188de56ccSmrgstatic void handle_response(Display *dpy, xcb_generic_reply_t *response, Bool in_XReply)
25288de56ccSmrg{
25388de56ccSmrg	_XAsyncHandler *async, *next;
25488de56ccSmrg	switch(response->response_type)
25588de56ccSmrg	{
25688de56ccSmrg	case X_Reply:
25788de56ccSmrg		for(async = dpy->async_handlers; async; async = next)
2581ab64890Smrg		{
25988de56ccSmrg			next = async->next;
26088de56ccSmrg			if(async->handler(dpy, (xReply *) response, (char *) response, sizeof(xReply) + (response->length << 2), async->data))
26188de56ccSmrg				break;
2621ab64890Smrg		}
26388de56ccSmrg		break;
26488de56ccSmrg
26588de56ccSmrg	case X_Error:
26688de56ccSmrg		handle_error(dpy, (xError *) response, in_XReply);
26788de56ccSmrg		break;
26888de56ccSmrg
26988de56ccSmrg	default: /* event */
27088de56ccSmrg		/* GenericEvents may be > 32 bytes. In this case, the
27188de56ccSmrg		 * event struct is trailed by the additional bytes. the
27288de56ccSmrg		 * xcb_generic_event_t struct uses 4 bytes for internal
27388de56ccSmrg		 * numbering, so we need to shift the trailing data to
27488de56ccSmrg		 * be after the first 32 bytes. */
27588de56ccSmrg		if(response->response_type == GenericEvent && ((xcb_ge_event_t *) response)->length)
2761ab64890Smrg		{
27788de56ccSmrg			xcb_ge_event_t *event = (xcb_ge_event_t *) response;
27888de56ccSmrg			memmove(&event->full_sequence, &event[1], event->length * 4);
2791ab64890Smrg		}
28088de56ccSmrg		_XEnq(dpy, (xEvent *) response);
28188de56ccSmrg		break;
2821ab64890Smrg	}
28388de56ccSmrg	free(response);
2841ab64890Smrg}
2851ab64890Smrg
2861ab64890Smrgint _XEventsQueued(Display *dpy, int mode)
2871ab64890Smrg{
28888de56ccSmrg	xcb_generic_reply_t *response;
2891ab64890Smrg	if(dpy->flags & XlibDisplayIOError)
2901ab64890Smrg		return 0;
2911ab64890Smrg	if(dpy->xcb->event_owner != XlibOwnsEventQueue)
2921ab64890Smrg		return 0;
2931ab64890Smrg
2941ab64890Smrg	if(mode == QueuedAfterFlush)
29561b2299dSmrg		_XSend(dpy, NULL, 0);
2961ab64890Smrg	else
2971ab64890Smrg		check_internal_connections(dpy);
29888de56ccSmrg
29988de56ccSmrg	/* If another thread is blocked waiting for events, then we must
30088de56ccSmrg	 * let that thread pick up the next event. Since it blocked, we
30188de56ccSmrg	 * can reasonably claim there are no new events right now. */
30288de56ccSmrg	if(!dpy->xcb->event_waiter)
30388de56ccSmrg	{
30488de56ccSmrg		while((response = poll_for_response(dpy)))
30588de56ccSmrg			handle_response(dpy, response, False);
30688de56ccSmrg		if(xcb_connection_has_error(dpy->xcb->connection))
30788de56ccSmrg			_XIOError(dpy);
30888de56ccSmrg	}
3091ab64890Smrg	return dpy->qlen;
3101ab64890Smrg}
3111ab64890Smrg
3121ab64890Smrg/* _XReadEvents - Flush the output queue,
3131ab64890Smrg * then read as many events as possible (but at least 1) and enqueue them
3141ab64890Smrg */
3151ab64890Smrgvoid _XReadEvents(Display *dpy)
3161ab64890Smrg{
31788de56ccSmrg	xcb_generic_reply_t *response;
31888de56ccSmrg	unsigned long serial;
31988de56ccSmrg
3201ab64890Smrg	if(dpy->flags & XlibDisplayIOError)
3211ab64890Smrg		return;
32261b2299dSmrg	_XSend(dpy, NULL, 0);
3231ab64890Smrg	if(dpy->xcb->event_owner != XlibOwnsEventQueue)
3241ab64890Smrg		return;
3251ab64890Smrg	check_internal_connections(dpy);
32688de56ccSmrg
32788de56ccSmrg	serial = dpy->next_event_serial_num;
32888de56ccSmrg	while(serial == dpy->next_event_serial_num || dpy->qlen == 0)
32988de56ccSmrg	{
33088de56ccSmrg		if(dpy->xcb->event_waiter)
33188de56ccSmrg		{
33288de56ccSmrg			ConditionWait(dpy, dpy->xcb->event_notify);
33388de56ccSmrg			/* Maybe the other thread got us an event. */
33488de56ccSmrg			continue;
33588de56ccSmrg		}
33688de56ccSmrg
33788de56ccSmrg		if(!dpy->xcb->next_event)
33888de56ccSmrg		{
33988de56ccSmrg			xcb_generic_event_t *event;
34088de56ccSmrg			dpy->xcb->event_waiter = 1;
34188de56ccSmrg			UnlockDisplay(dpy);
34288de56ccSmrg			event = xcb_wait_for_event(dpy->xcb->connection);
34357f47464Smrg			/* It appears that classic Xlib respected user
34457f47464Smrg			 * locks when waking up after waiting for
34557f47464Smrg			 * events. However, if this thread did not have
34657f47464Smrg			 * any user locks, and another thread takes a
34757f47464Smrg			 * user lock and tries to read events, then we'd
34857f47464Smrg			 * deadlock. So we'll choose to let the thread
34957f47464Smrg			 * that got in first consume events, despite the
35057f47464Smrg			 * later thread's user locks. */
35157f47464Smrg			InternalLockDisplay(dpy, /* ignore user locks */ 1);
35288de56ccSmrg			dpy->xcb->event_waiter = 0;
35388de56ccSmrg			ConditionBroadcast(dpy, dpy->xcb->event_notify);
35488de56ccSmrg			if(!event)
35588de56ccSmrg				_XIOError(dpy);
35688de56ccSmrg			dpy->xcb->next_event = event;
35788de56ccSmrg		}
35888de56ccSmrg
35988de56ccSmrg		/* We've established most of the conditions for
36088de56ccSmrg		 * poll_for_response to return non-NULL. The exceptions
36188de56ccSmrg		 * are connection shutdown, and finding that another
36288de56ccSmrg		 * thread is waiting for the next reply we'd like to
36388de56ccSmrg		 * process. */
36488de56ccSmrg
36588de56ccSmrg		response = poll_for_response(dpy);
36688de56ccSmrg		if(response)
36788de56ccSmrg			handle_response(dpy, response, False);
36888de56ccSmrg		else if(dpy->xcb->pending_requests->reply_waiter)
36988de56ccSmrg		{ /* need braces around ConditionWait */
37088de56ccSmrg			ConditionWait(dpy, dpy->xcb->reply_notify);
37188de56ccSmrg		}
37288de56ccSmrg		else
37388de56ccSmrg			_XIOError(dpy);
37488de56ccSmrg	}
37588de56ccSmrg
37688de56ccSmrg	/* The preceding loop established that there is no
37788de56ccSmrg	 * event_waiter--unless we just called ConditionWait because of
37888de56ccSmrg	 * a reply_waiter, in which case another thread may have become
37988de56ccSmrg	 * the event_waiter while we slept unlocked. */
38088de56ccSmrg	if(!dpy->xcb->event_waiter)
38188de56ccSmrg		while((response = poll_for_response(dpy)))
38288de56ccSmrg			handle_response(dpy, response, False);
38388de56ccSmrg	if(xcb_connection_has_error(dpy->xcb->connection))
38488de56ccSmrg		_XIOError(dpy);
3851ab64890Smrg}
3861ab64890Smrg
3871ab64890Smrg/*
3881ab64890Smrg * _XSend - Flush the buffer and send the client data. 32 bit word aligned
3891ab64890Smrg * transmission is used, if size is not 0 mod 4, extra bytes are transmitted.
3901ab64890Smrg *
3911ab64890Smrg * Note that the connection must not be read from once the data currently
3921ab64890Smrg * in the buffer has been written.
3931ab64890Smrg */
3941ab64890Smrgvoid _XSend(Display *dpy, const char *data, long size)
3951ab64890Smrg{
39661b2299dSmrg	static const xReq dummy_request;
39761b2299dSmrg	static char const pad[3];
39861b2299dSmrg	struct iovec vec[3];
39961b2299dSmrg	uint64_t requests;
40061b2299dSmrg	_XExtension *ext;
4011ab64890Smrg	xcb_connection_t *c = dpy->xcb->connection;
4021ab64890Smrg	if(dpy->flags & XlibDisplayIOError)
4031ab64890Smrg		return;
4041ab64890Smrg
40561b2299dSmrg	if(dpy->bufptr == dpy->buffer && !size)
40661b2299dSmrg		return;
4071ab64890Smrg
40861b2299dSmrg	/* iff we asked XCB to set aside errors, we must pick those up
40961b2299dSmrg	 * eventually. iff there are async handlers, we may have just
41061b2299dSmrg	 * issued requests that will generate replies. in either case,
41161b2299dSmrg	 * we need to remember to check later. */
41261b2299dSmrg	if(dpy->xcb->event_owner != XlibOwnsEventQueue || dpy->async_handlers)
41361b2299dSmrg	{
4142e9c7c8cSmrg		uint64_t sequence;
41588de56ccSmrg		for(sequence = dpy->xcb->last_flushed + 1; sequence <= dpy->request; ++sequence)
41688de56ccSmrg			append_pending_request(dpy, sequence);
41761b2299dSmrg	}
41861b2299dSmrg	requests = dpy->request - dpy->xcb->last_flushed;
41961b2299dSmrg	dpy->xcb->last_flushed = dpy->request;
4201ab64890Smrg
42161b2299dSmrg	vec[0].iov_base = dpy->buffer;
42261b2299dSmrg	vec[0].iov_len = dpy->bufptr - dpy->buffer;
42361b2299dSmrg	vec[1].iov_base = (caddr_t) data;
42461b2299dSmrg	vec[1].iov_len = size;
42561b2299dSmrg	vec[2].iov_base = (caddr_t) pad;
42661b2299dSmrg	vec[2].iov_len = -size & 3;
42761b2299dSmrg
42861b2299dSmrg	for(ext = dpy->flushes; ext; ext = ext->next_flush)
42961b2299dSmrg	{
43061b2299dSmrg		int i;
43161b2299dSmrg		for(i = 0; i < 3; ++i)
43261b2299dSmrg			if(vec[i].iov_len)
43361b2299dSmrg				ext->before_flush(dpy, &ext->codes, vec[i].iov_base, vec[i].iov_len);
43461b2299dSmrg	}
4351ab64890Smrg
43661b2299dSmrg	if(xcb_writev(c, vec, 3, requests) < 0)
43761b2299dSmrg		_XIOError(dpy);
43861b2299dSmrg	dpy->bufptr = dpy->buffer;
43961b2299dSmrg	dpy->last_req = (char *) &dummy_request;
4401ab64890Smrg
4411ab64890Smrg	check_internal_connections(dpy);
4421ab64890Smrg
44361b2299dSmrg	_XSetSeqSyncFunction(dpy);
4441ab64890Smrg}
4451ab64890Smrg
4461ab64890Smrg/*
4471ab64890Smrg * _XFlush - Flush the X request buffer.  If the buffer is empty, no
4481ab64890Smrg * action is taken.
4491ab64890Smrg */
4501ab64890Smrgvoid _XFlush(Display *dpy)
4511ab64890Smrg{
45261b2299dSmrg	require_socket(dpy);
45361b2299dSmrg	_XSend(dpy, NULL, 0);
4541ab64890Smrg
4551ab64890Smrg	_XEventsQueued(dpy, QueuedAfterReading);
4561ab64890Smrg}
4571ab64890Smrg
45861b2299dSmrgstatic const XID inval_id = ~0UL;
45961b2299dSmrg
46088de56ccSmrgvoid _XIDHandler(Display *dpy)
4611ab64890Smrg{
46288de56ccSmrg	if (dpy->xcb->next_xid == inval_id)
46388de56ccSmrg		_XAllocIDs(dpy, &dpy->xcb->next_xid, 1);
4641ab64890Smrg}
4651ab64890Smrg
4661ab64890Smrg/* _XAllocID - resource ID allocation routine. */
4671ab64890SmrgXID _XAllocID(Display *dpy)
4681ab64890Smrg{
4691ab64890Smrg	XID ret = dpy->xcb->next_xid;
47061b2299dSmrg	assert (ret != inval_id);
47161b2299dSmrg	dpy->xcb->next_xid = inval_id;
47261b2299dSmrg	_XSetPrivSyncFunction(dpy);
4731ab64890Smrg	return ret;
4741ab64890Smrg}
4751ab64890Smrg
4761ab64890Smrg/* _XAllocIDs - multiple resource ID allocation routine. */
4771ab64890Smrgvoid _XAllocIDs(Display *dpy, XID *ids, int count)
4781ab64890Smrg{
4791ab64890Smrg	int i;
48061b2299dSmrg#ifdef XTHREADS
48161b2299dSmrg	if (dpy->lock)
48261b2299dSmrg		(*dpy->lock->user_lock_display)(dpy);
48361b2299dSmrg	UnlockDisplay(dpy);
48461b2299dSmrg#endif
4851ab64890Smrg	for (i = 0; i < count; i++)
4861ab64890Smrg		ids[i] = xcb_generate_id(dpy->xcb->connection);
48761b2299dSmrg#ifdef XTHREADS
48888de56ccSmrg	InternalLockDisplay(dpy, /* don't skip user locks */ 0);
48961b2299dSmrg	if (dpy->lock)
49061b2299dSmrg		(*dpy->lock->user_unlock_display)(dpy);
49161b2299dSmrg#endif
4921ab64890Smrg}
4931ab64890Smrg
4941ab64890Smrgstatic void _XFreeReplyData(Display *dpy, Bool force)
4951ab64890Smrg{
4961ab64890Smrg	if(!force && dpy->xcb->reply_consumed < dpy->xcb->reply_length)
4971ab64890Smrg		return;
4981ab64890Smrg	free(dpy->xcb->reply_data);
49961b2299dSmrg	dpy->xcb->reply_data = NULL;
5001ab64890Smrg}
5011ab64890Smrg
5021ab64890Smrg/*
5031ab64890Smrg * _XReply - Wait for a reply packet and copy its contents into the
5041ab64890Smrg * specified rep.
5051ab64890Smrg * extra: number of 32-bit words expected after the reply
5061ab64890Smrg * discard: should I discard data following "extra" words?
5071ab64890Smrg */
5081ab64890SmrgStatus _XReply(Display *dpy, xReply *rep, int extra, Bool discard)
5091ab64890Smrg{
5101ab64890Smrg	xcb_generic_error_t *error;
5111ab64890Smrg	xcb_connection_t *c = dpy->xcb->connection;
5121ab64890Smrg	char *reply;
5131ab64890Smrg	PendingRequest *current;
5141ab64890Smrg
5151ab64890Smrg	assert(!dpy->xcb->reply_data);
5161ab64890Smrg
5171ab64890Smrg	if(dpy->flags & XlibDisplayIOError)
5181ab64890Smrg		return 0;
5191ab64890Smrg
52061b2299dSmrg	_XSend(dpy, NULL, 0);
52188de56ccSmrg	if(dpy->xcb->pending_requests_tail && dpy->xcb->pending_requests_tail->sequence == dpy->request)
52288de56ccSmrg		current = dpy->xcb->pending_requests_tail;
52388de56ccSmrg	else
52488de56ccSmrg		current = append_pending_request(dpy, dpy->request);
52588de56ccSmrg	/* Don't let any other thread get this reply. */
52688de56ccSmrg	current->reply_waiter = 1;
52788de56ccSmrg
52888de56ccSmrg	while(1)
52988de56ccSmrg	{
53088de56ccSmrg		PendingRequest *req = dpy->xcb->pending_requests;
53188de56ccSmrg		xcb_generic_reply_t *response;
5321ab64890Smrg
53388de56ccSmrg		if(req != current && req->reply_waiter)
53488de56ccSmrg		{
53588de56ccSmrg			ConditionWait(dpy, dpy->xcb->reply_notify);
53688de56ccSmrg			/* Another thread got this reply. */
53788de56ccSmrg			continue;
53888de56ccSmrg		}
53988de56ccSmrg		req->reply_waiter = 1;
54088de56ccSmrg		UnlockDisplay(dpy);
54188de56ccSmrg		response = xcb_wait_for_reply(c, req->sequence, &error);
54257f47464Smrg		/* Any user locks on another thread must have been taken
54357f47464Smrg		 * while we slept in xcb_wait_for_reply. Classic Xlib
54457f47464Smrg		 * ignored those user locks in this case, so we do too. */
54557f47464Smrg		InternalLockDisplay(dpy, /* ignore user locks */ 1);
54688de56ccSmrg
54788de56ccSmrg		/* We have the response we're looking for. Now, before
54888de56ccSmrg		 * letting anyone else process this sequence number, we
54988de56ccSmrg		 * need to process any events that should have come
55088de56ccSmrg		 * earlier. */
55188de56ccSmrg
55288de56ccSmrg		if(dpy->xcb->event_owner == XlibOwnsEventQueue)
55388de56ccSmrg		{
55488de56ccSmrg			xcb_generic_reply_t *event;
55588de56ccSmrg			/* If some thread is already waiting for events,
55688de56ccSmrg			 * it will get the first one. That thread must
55788de56ccSmrg			 * process that event before we can continue. */
55888de56ccSmrg			/* FIXME: That event might be after this reply,
55988de56ccSmrg			 * and might never even come--or there might be
56088de56ccSmrg			 * multiple threads trying to get events. */
56188de56ccSmrg			while(dpy->xcb->event_waiter)
56288de56ccSmrg			{ /* need braces around ConditionWait */
56388de56ccSmrg				ConditionWait(dpy, dpy->xcb->event_notify);
56488de56ccSmrg			}
56588de56ccSmrg			while((event = poll_for_event(dpy)))
56688de56ccSmrg				handle_response(dpy, event, True);
56788de56ccSmrg		}
56888de56ccSmrg
56988de56ccSmrg		req->reply_waiter = 0;
57088de56ccSmrg		ConditionBroadcast(dpy, dpy->xcb->reply_notify);
57188de56ccSmrg		assert(XLIB_SEQUENCE_COMPARE(req->sequence, <=, dpy->request));
57288de56ccSmrg		dpy->last_request_read = req->sequence;
57388de56ccSmrg		if(!response)
57488de56ccSmrg			dequeue_pending_request(dpy, req);
57588de56ccSmrg
57688de56ccSmrg		if(req == current)
57788de56ccSmrg		{
57888de56ccSmrg			reply = (char *) response;
57988de56ccSmrg			break;
58088de56ccSmrg		}
58188de56ccSmrg
58288de56ccSmrg		if(error)
58388de56ccSmrg			handle_response(dpy, (xcb_generic_reply_t *) error, True);
58488de56ccSmrg		else if(response)
58588de56ccSmrg			handle_response(dpy, response, True);
58688de56ccSmrg	}
5871ab64890Smrg	check_internal_connections(dpy);
58888de56ccSmrg
58988de56ccSmrg	if(dpy->xcb->next_event && dpy->xcb->next_event->response_type == X_Error)
59088de56ccSmrg	{
59188de56ccSmrg		xcb_generic_event_t *event = dpy->xcb->next_event;
59288de56ccSmrg		unsigned long event_sequence = dpy->last_request_read;
59388de56ccSmrg		widen(&event_sequence, event->full_sequence);
59461234c2cSmrg		if(event_sequence == dpy->last_request_read)
59588de56ccSmrg		{
59688de56ccSmrg			error = (xcb_generic_error_t *) event;
59788de56ccSmrg			dpy->xcb->next_event = NULL;
59888de56ccSmrg		}
59988de56ccSmrg	}
6001ab64890Smrg
6011ab64890Smrg	if(error)
6021ab64890Smrg	{
6031ab64890Smrg		int ret_code;
6041ab64890Smrg
6051ab64890Smrg		/* Xlib is evil and assumes that even errors will be
6061ab64890Smrg		 * copied into rep. */
6071ab64890Smrg		memcpy(rep, error, 32);
6081ab64890Smrg
6091ab64890Smrg		/* do not die on "no such font", "can't allocate",
6101ab64890Smrg		   "can't grab" failures */
61188de56ccSmrg		switch(error->error_code)
6121ab64890Smrg		{
6131ab64890Smrg			case BadName:
61488de56ccSmrg				switch(error->major_code)
6151ab64890Smrg				{
6161ab64890Smrg					case X_LookupColor:
6171ab64890Smrg					case X_AllocNamedColor:
61861b2299dSmrg						free(error);
6191ab64890Smrg						return 0;
6201ab64890Smrg				}
6211ab64890Smrg				break;
6221ab64890Smrg			case BadFont:
62388de56ccSmrg				if(error->major_code == X_QueryFont) {
62461b2299dSmrg					free(error);
6251ab64890Smrg					return 0;
62661b2299dSmrg				}
6271ab64890Smrg				break;
6281ab64890Smrg			case BadAlloc:
6291ab64890Smrg			case BadAccess:
63061b2299dSmrg				free(error);
6311ab64890Smrg				return 0;
6321ab64890Smrg		}
6331ab64890Smrg
63488de56ccSmrg		ret_code = handle_error(dpy, (xError *) error, True);
63561b2299dSmrg		free(error);
63688de56ccSmrg		return ret_code;
6371ab64890Smrg	}
6381ab64890Smrg
6391ab64890Smrg	/* it's not an error, but we don't have a reply, so it's an I/O
6401ab64890Smrg	 * error. */
6411ab64890Smrg	if(!reply)
6421ab64890Smrg	{
6431ab64890Smrg		_XIOError(dpy);
6441ab64890Smrg		return 0;
6451ab64890Smrg	}
6461ab64890Smrg
6471ab64890Smrg	/* there's no error and we have a reply. */
6481ab64890Smrg	dpy->xcb->reply_data = reply;
6491ab64890Smrg	dpy->xcb->reply_consumed = sizeof(xReply) + (extra * 4);
6501ab64890Smrg	dpy->xcb->reply_length = sizeof(xReply);
6511ab64890Smrg	if(dpy->xcb->reply_data[0] == 1)
6521ab64890Smrg		dpy->xcb->reply_length += (((xcb_generic_reply_t *) dpy->xcb->reply_data)->length * 4);
6531ab64890Smrg
6541ab64890Smrg	/* error: Xlib asks too much. give them what we can anyway. */
6551ab64890Smrg	if(dpy->xcb->reply_length < dpy->xcb->reply_consumed)
6561ab64890Smrg		dpy->xcb->reply_consumed = dpy->xcb->reply_length;
6571ab64890Smrg
6581ab64890Smrg	memcpy(rep, dpy->xcb->reply_data, dpy->xcb->reply_consumed);
6591ab64890Smrg	_XFreeReplyData(dpy, discard);
6601ab64890Smrg	return 1;
6611ab64890Smrg}
6621ab64890Smrg
6631ab64890Smrgint _XRead(Display *dpy, char *data, long size)
6641ab64890Smrg{
6651ab64890Smrg	assert(size >= 0);
6661ab64890Smrg	if(size == 0)
6671ab64890Smrg		return 0;
66861b2299dSmrg	assert(dpy->xcb->reply_data != NULL);
6691ab64890Smrg	assert(dpy->xcb->reply_consumed + size <= dpy->xcb->reply_length);
6701ab64890Smrg	memcpy(data, dpy->xcb->reply_data + dpy->xcb->reply_consumed, size);
6711ab64890Smrg	dpy->xcb->reply_consumed += size;
6721ab64890Smrg	_XFreeReplyData(dpy, False);
6731ab64890Smrg	return 0;
6741ab64890Smrg}
6751ab64890Smrg
6761ab64890Smrg/*
6771ab64890Smrg * _XReadPad - Read bytes from the socket taking into account incomplete
6781ab64890Smrg * reads.  If the number of bytes is not 0 mod 4, read additional pad
6791ab64890Smrg * bytes.
6801ab64890Smrg */
6811ab64890Smrgvoid _XReadPad(Display *dpy, char *data, long size)
6821ab64890Smrg{
6831ab64890Smrg	_XRead(dpy, data, size);
6841ab64890Smrg	dpy->xcb->reply_consumed += -size & 3;
6851ab64890Smrg	_XFreeReplyData(dpy, False);
6861ab64890Smrg}
6871ab64890Smrg
6881ab64890Smrg/* Read and discard "n" 8-bit bytes of data */
6891ab64890Smrgvoid _XEatData(Display *dpy, unsigned long n)
6901ab64890Smrg{
6911ab64890Smrg	dpy->xcb->reply_consumed += n;
6921ab64890Smrg	_XFreeReplyData(dpy, False);
6931ab64890Smrg}
694