mirror of
https://github.com/Stichting-MINIX-Research-Foundation/xsrc.git
synced 2025-09-10 21:28:49 -04:00
3400 lines
89 KiB
C
3400 lines
89 KiB
C
/* $Xorg: XlibInt.c,v 1.8 2001/02/09 02:03:38 xorgcvs Exp $ */
|
|
/*
|
|
|
|
Copyright 1985, 1986, 1987, 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.
|
|
|
|
*/
|
|
/* $XFree86: xc/lib/X11/XlibInt.c,v 3.39 2003/11/17 22:20:10 dawes Exp $ */
|
|
|
|
/*
|
|
* XlibInt.c - Internal support routines for the C subroutine
|
|
* interface library (Xlib) to the X Window System Protocol V11.0.
|
|
*/
|
|
#define NEED_EVENTS
|
|
#define NEED_REPLIES
|
|
|
|
#include "Xlibint.h"
|
|
#include <X11/Xpoll.h>
|
|
#include <X11/Xtrans.h>
|
|
#include <X11/extensions/xcmiscstr.h>
|
|
#include <stdio.h>
|
|
|
|
#ifdef XTHREADS
|
|
#include "locking.h"
|
|
|
|
/* these pointers get initialized by XInitThreads */
|
|
LockInfoPtr _Xglobal_lock = NULL;
|
|
void (*_XCreateMutex_fn)(LockInfoPtr) = NULL;
|
|
/* struct _XCVList *(*_XCreateCVL_fn)() = NULL; */
|
|
void (*_XFreeMutex_fn)(LockInfoPtr) = NULL;
|
|
void (*_XLockMutex_fn)(
|
|
LockInfoPtr /* lock */
|
|
#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE)
|
|
, char * /* file */
|
|
, int /* line */
|
|
#endif
|
|
) = NULL;
|
|
void (*_XUnlockMutex_fn)(
|
|
LockInfoPtr /* lock */
|
|
#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE)
|
|
, char * /* file */
|
|
, int /* line */
|
|
#endif
|
|
) = NULL;
|
|
xthread_t (*_Xthread_self_fn)(void) = NULL;
|
|
|
|
#define XThread_Self() ((*_Xthread_self_fn)())
|
|
|
|
#define UnlockNextReplyReader(d) if ((d)->lock) \
|
|
(*(d)->lock->pop_reader)((d),&(d)->lock->reply_awaiters,&(d)->lock->reply_awaiters_tail)
|
|
|
|
#define QueueReplyReaderLock(d) ((d)->lock ? \
|
|
(*(d)->lock->push_reader)(d,&(d)->lock->reply_awaiters_tail) : NULL)
|
|
#define QueueEventReaderLock(d) ((d)->lock ? \
|
|
(*(d)->lock->push_reader)(d,&(d)->lock->event_awaiters_tail) : NULL)
|
|
|
|
#if defined(XTHREADS_WARN) || defined(XTHREADS_FILE_LINE)
|
|
#define InternalLockDisplay(d,wskip) if ((d)->lock) \
|
|
(*(d)->lock->internal_lock_display)(d,wskip,__FILE__,__LINE__)
|
|
#else
|
|
#define InternalLockDisplay(d,wskip) if ((d)->lock) \
|
|
(*(d)->lock->internal_lock_display)(d,wskip)
|
|
#endif
|
|
|
|
#else /* XTHREADS else */
|
|
|
|
#define UnlockNextReplyReader(d)
|
|
#define UnlockNextEventReader(d)
|
|
#define InternalLockDisplay(d,wskip)
|
|
|
|
#endif /* XTHREADS else */
|
|
|
|
/* check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
|
|
* systems are broken and return EWOULDBLOCK when they should return EAGAIN
|
|
*/
|
|
#ifdef WIN32
|
|
#define ETEST() (WSAGetLastError() == WSAEWOULDBLOCK)
|
|
#else
|
|
#ifdef __CYGWIN__ /* Cygwin uses ENOBUFS to signal socket is full */
|
|
#define ETEST() (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
|
|
#else
|
|
#if defined(EAGAIN) && defined(EWOULDBLOCK)
|
|
#define ETEST() (errno == EAGAIN || errno == EWOULDBLOCK)
|
|
#else
|
|
#ifdef EAGAIN
|
|
#define ETEST() (errno == EAGAIN)
|
|
#else
|
|
#define ETEST() (errno == EWOULDBLOCK)
|
|
#endif /* EAGAIN */
|
|
#endif /* EAGAIN && EWOULDBLOCK */
|
|
#endif /* __CYGWIN__ */
|
|
#endif /* WIN32 */
|
|
|
|
#ifdef WIN32
|
|
#define ECHECK(err) (WSAGetLastError() == err)
|
|
#define ESET(val) WSASetLastError(val)
|
|
#else
|
|
#ifdef __UNIXOS2__
|
|
#define ECHECK(err) (errno == err)
|
|
#define ESET(val)
|
|
#else
|
|
#ifdef ISC
|
|
#define ECHECK(err) ((errno == err) || ETEST())
|
|
#else
|
|
#define ECHECK(err) (errno == err)
|
|
#endif
|
|
#define ESET(val) errno = val
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(LOCALCONN) || defined(LACHMAN)
|
|
#ifdef EMSGSIZE
|
|
#define ESZTEST() (ECHECK(EMSGSIZE) || ECHECK(ERANGE))
|
|
#else
|
|
#define ESZTEST() ECHECK(ERANGE)
|
|
#endif
|
|
#else
|
|
#ifdef EMSGSIZE
|
|
#define ESZTEST() ECHECK(EMSGSIZE)
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef __UNIXOS2__
|
|
#define select(n,r,w,x,t) os2ClientSelect(n,r,w,x,t)
|
|
#include <limits.h>
|
|
#define MAX_PATH _POSIX_PATH_MAX
|
|
#endif
|
|
|
|
#ifdef MUSTCOPY
|
|
|
|
#define STARTITERATE(tpvar,type,start,endcond) \
|
|
{ register char *cpvar; \
|
|
for (cpvar = (char *) (start); endcond; ) { \
|
|
type dummy; memcpy ((char *) &dummy, cpvar, SIZEOF(type)); \
|
|
tpvar = &dummy;
|
|
#define ITERPTR(tpvar) cpvar
|
|
#define RESETITERPTR(tpvar,type,start) cpvar = start
|
|
#define INCITERPTR(tpvar,type) cpvar += SIZEOF(type)
|
|
#define ENDITERATE }}
|
|
|
|
#else
|
|
|
|
#define STARTITERATE(tpvar,type,start,endcond) \
|
|
for (tpvar = (type *) (start); endcond; )
|
|
#define ITERPTR(tpvar) (char *)tpvar
|
|
#define RESETITERPTR(tpvar,type,start) tpvar = (type *) (start)
|
|
#define INCITERPTR(tpvar,type) tpvar++
|
|
#define ENDITERATE
|
|
|
|
#endif /* MUSTCOPY */
|
|
|
|
typedef union {
|
|
xReply rep;
|
|
char buf[BUFSIZE];
|
|
} _XAlignedBuffer;
|
|
|
|
static char *_XAsyncReply(
|
|
Display *dpy,
|
|
register xReply *rep,
|
|
char *buf,
|
|
register int *lenp,
|
|
Bool discard);
|
|
|
|
static void _XProcessInternalConnection(
|
|
Display *dpy,
|
|
struct _XConnectionInfo *conn_info);
|
|
|
|
#define SEQLIMIT (65535 - (BUFSIZE / SIZEOF(xReq)) - 10)
|
|
|
|
/*
|
|
* The following routines are internal routines used by Xlib for protocol
|
|
* packet transmission and reception.
|
|
*
|
|
* _XIOError(Display *) will be called if any sort of system call error occurs.
|
|
* This is assumed to be a fatal condition, i.e., XIOError should not return.
|
|
*
|
|
* _XError(Display *, xError *) will be called whenever an X_Error event is
|
|
* received. This is not assumed to be a fatal condition, i.e., it is
|
|
* acceptable for this procedure to return. However, XError should NOT
|
|
* perform any operations (directly or indirectly) on the DISPLAY.
|
|
*
|
|
* Routines declared with a return type of 'Status' return 0 on failure,
|
|
* and non 0 on success. Routines with no declared return type don't
|
|
* return anything. Whenever possible routines that create objects return
|
|
* the object they have created.
|
|
*/
|
|
|
|
static xReq _dummy_request = {
|
|
0, 0, 0
|
|
};
|
|
|
|
/*
|
|
* This is an OS dependent routine which:
|
|
* 1) returns as soon as the connection can be written on....
|
|
* 2) if the connection can be read, must enqueue events and handle errors,
|
|
* until the connection is writable.
|
|
*/
|
|
static void
|
|
_XWaitForWritable(
|
|
Display *dpy
|
|
#ifdef XTHREADS
|
|
,
|
|
xcondition_t cv /* our reading condition variable */
|
|
#endif
|
|
)
|
|
{
|
|
#ifdef USE_POLL
|
|
struct pollfd filedes;
|
|
#else
|
|
fd_set r_mask;
|
|
fd_set w_mask;
|
|
#endif
|
|
int nfound;
|
|
|
|
#ifdef USE_POLL
|
|
filedes.fd = dpy->fd;
|
|
filedes.events = 0;
|
|
#else
|
|
FD_ZERO(&r_mask);
|
|
FD_ZERO(&w_mask);
|
|
#endif
|
|
|
|
for (;;) {
|
|
#ifdef XTHREADS
|
|
/* We allow only one thread at a time to read, to minimize
|
|
passing of read data between threads.
|
|
Now, who is it? If there is a non-NULL reply_awaiters and
|
|
we (i.e., our cv) are not at the head of it, then whoever
|
|
is at the head is the reader, and we don't read.
|
|
Otherwise there is no reply_awaiters or we are at the
|
|
head, having just appended ourselves.
|
|
In this case, if there is a event_awaiters, then whoever
|
|
is at the head of it got there before we did, and they are the
|
|
reader.
|
|
|
|
Last cases: no event_awaiters and we are at the head of
|
|
reply_awaiters or reply_awaiters is NULL: we are the reader,
|
|
since there is obviously no one else involved.
|
|
|
|
XXX - what if cv is NULL and someone else comes along after
|
|
us while we are waiting?
|
|
*/
|
|
|
|
if (!dpy->lock ||
|
|
(!dpy->lock->event_awaiters &&
|
|
(!dpy->lock->reply_awaiters ||
|
|
dpy->lock->reply_awaiters->cv == cv)))
|
|
#endif
|
|
#ifdef USE_POLL
|
|
filedes.events = POLLIN;
|
|
filedes.events |= POLLOUT;
|
|
#else
|
|
FD_SET(dpy->fd, &r_mask);
|
|
FD_SET(dpy->fd, &w_mask);
|
|
#endif
|
|
|
|
do {
|
|
UnlockDisplay(dpy);
|
|
#ifdef USE_POLL
|
|
nfound = poll (&filedes, 1, -1);
|
|
#else
|
|
nfound = Select (dpy->fd + 1, &r_mask, &w_mask, NULL, NULL);
|
|
#endif
|
|
InternalLockDisplay(dpy, cv != NULL);
|
|
if (nfound < 0 && !ECHECK(EINTR))
|
|
_XIOError(dpy);
|
|
} while (nfound <= 0);
|
|
|
|
if (
|
|
#ifdef USE_POLL
|
|
filedes.revents & POLLIN
|
|
#else
|
|
FD_ISSET(dpy->fd, &r_mask)
|
|
#endif
|
|
)
|
|
{
|
|
_XAlignedBuffer buf;
|
|
BytesReadable_t pend;
|
|
register int len;
|
|
register xReply *rep;
|
|
|
|
/* find out how much data can be read */
|
|
if (_X11TransBytesReadable(dpy->trans_conn, &pend) < 0)
|
|
_XIOError(dpy);
|
|
len = pend;
|
|
|
|
/* must read at least one xEvent; if none is pending, then
|
|
we'll just block waiting for it */
|
|
if (len < SIZEOF(xReply)
|
|
#ifdef XTHREADS
|
|
|| dpy->async_handlers
|
|
#endif
|
|
)
|
|
len = SIZEOF(xReply);
|
|
|
|
/* but we won't read more than the max buffer size */
|
|
if (len > BUFSIZE) len = BUFSIZE;
|
|
|
|
/* round down to an integral number of XReps */
|
|
len = (len / SIZEOF(xReply)) * SIZEOF(xReply);
|
|
|
|
(void) _XRead (dpy, buf.buf, (long) len);
|
|
|
|
STARTITERATE(rep,xReply,buf.buf,len > 0) {
|
|
if (rep->generic.type == X_Reply) {
|
|
int tmp = len;
|
|
RESETITERPTR(rep,xReply,
|
|
_XAsyncReply (dpy, rep,
|
|
ITERPTR(rep), &tmp, True));
|
|
len = tmp;
|
|
pend = len;
|
|
} else {
|
|
if (rep->generic.type == X_Error)
|
|
_XError (dpy, (xError *)rep);
|
|
else /* must be an event packet */
|
|
_XEnq (dpy, (xEvent *)rep);
|
|
INCITERPTR(rep,xReply);
|
|
len -= SIZEOF(xReply);
|
|
}
|
|
} ENDITERATE
|
|
#ifdef XTHREADS
|
|
if (dpy->lock && dpy->lock->event_awaiters)
|
|
ConditionSignal(dpy, dpy->lock->event_awaiters->cv);
|
|
#endif
|
|
}
|
|
#ifdef USE_POLL
|
|
if (filedes.revents & (POLLOUT|POLLHUP|POLLERR))
|
|
#else
|
|
if (FD_ISSET(dpy->fd, &w_mask))
|
|
#endif
|
|
{
|
|
#ifdef XTHREADS
|
|
if (dpy->lock) {
|
|
ConditionBroadcast(dpy, dpy->lock->writers);
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#define POLLFD_CACHE_SIZE 5
|
|
|
|
/* initialize the struct array passed to poll() below */
|
|
Bool _XPollfdCacheInit(
|
|
Display *dpy)
|
|
{
|
|
#ifdef USE_POLL
|
|
struct pollfd *pfp;
|
|
|
|
pfp = (struct pollfd *)Xmalloc(POLLFD_CACHE_SIZE * sizeof(struct pollfd));
|
|
if (!pfp)
|
|
return False;
|
|
pfp[0].fd = dpy->fd;
|
|
pfp[0].events = POLLIN;
|
|
|
|
dpy->filedes = (XPointer)pfp;
|
|
#endif
|
|
return True;
|
|
}
|
|
|
|
void _XPollfdCacheAdd(
|
|
Display *dpy,
|
|
int fd)
|
|
{
|
|
#ifdef USE_POLL
|
|
struct pollfd *pfp = (struct pollfd *)dpy->filedes;
|
|
|
|
if (dpy->im_fd_length <= POLLFD_CACHE_SIZE) {
|
|
pfp[dpy->im_fd_length].fd = fd;
|
|
pfp[dpy->im_fd_length].events = POLLIN;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
void _XPollfdCacheDel(
|
|
Display *dpy,
|
|
int fd) /* not used */
|
|
{
|
|
#ifdef USE_POLL
|
|
struct pollfd *pfp = (struct pollfd *)dpy->filedes;
|
|
struct _XConnectionInfo *conni;
|
|
|
|
/* just recalculate whole list */
|
|
if (dpy->im_fd_length <= POLLFD_CACHE_SIZE) {
|
|
int loc = 1;
|
|
for (conni = dpy->im_fd_info; conni; conni=conni->next) {
|
|
pfp[loc].fd = conni->fd;
|
|
pfp[loc].events = POLLIN;
|
|
loc++;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* returns True iff there is an event in the queue newer than serial_num */
|
|
|
|
static Bool
|
|
_XNewerQueuedEvent(
|
|
Display *dpy,
|
|
int serial_num)
|
|
{
|
|
_XQEvent *qev;
|
|
|
|
if (dpy->next_event_serial_num == serial_num)
|
|
return False;
|
|
|
|
qev = dpy->head;
|
|
while (qev) {
|
|
if (qev->qserial_num >= serial_num) {
|
|
return True;
|
|
}
|
|
qev = qev->next;
|
|
}
|
|
return False;
|
|
}
|
|
|
|
static int
|
|
_XWaitForReadable(
|
|
Display *dpy)
|
|
{
|
|
int result;
|
|
int fd = dpy->fd;
|
|
struct _XConnectionInfo *ilist;
|
|
register int saved_event_serial = 0;
|
|
int in_read_events = 0;
|
|
register Bool did_proc_conni = False;
|
|
#ifdef USE_POLL
|
|
struct pollfd *filedes;
|
|
#else
|
|
fd_set r_mask;
|
|
int highest_fd = fd;
|
|
#endif
|
|
|
|
#ifdef USE_POLL
|
|
if (dpy->im_fd_length + 1 > POLLFD_CACHE_SIZE
|
|
&& !(dpy->flags & XlibDisplayProcConni)) {
|
|
/* XXX - this fallback is gross */
|
|
int i;
|
|
|
|
filedes = (struct pollfd *)Xmalloc(dpy->im_fd_length * sizeof(struct pollfd));
|
|
filedes[0].fd = fd;
|
|
filedes[0].events = POLLIN;
|
|
for (ilist=dpy->im_fd_info, i=1; ilist; ilist=ilist->next, i++) {
|
|
filedes[i].fd = ilist->fd;
|
|
filedes[i].events = POLLIN;
|
|
}
|
|
} else {
|
|
filedes = (struct pollfd *)dpy->filedes;
|
|
}
|
|
#else
|
|
FD_ZERO(&r_mask);
|
|
#endif
|
|
for (;;) {
|
|
#ifndef USE_POLL
|
|
FD_SET(fd, &r_mask);
|
|
if (!(dpy->flags & XlibDisplayProcConni))
|
|
for (ilist=dpy->im_fd_info; ilist; ilist=ilist->next) {
|
|
FD_SET(ilist->fd, &r_mask);
|
|
if (ilist->fd > highest_fd)
|
|
highest_fd = ilist->fd;
|
|
}
|
|
#endif
|
|
UnlockDisplay(dpy);
|
|
#ifdef USE_POLL
|
|
result = poll(filedes,
|
|
(dpy->flags & XlibDisplayProcConni) ? 1 : 1+dpy->im_fd_length,
|
|
-1);
|
|
#else
|
|
result = Select(highest_fd + 1, &r_mask, NULL, NULL, NULL);
|
|
#endif
|
|
InternalLockDisplay(dpy, dpy->flags & XlibDisplayReply);
|
|
if (result == -1 && !ECHECK(EINTR)) _XIOError(dpy);
|
|
if (result <= 0)
|
|
continue;
|
|
#ifdef USE_POLL
|
|
if (filedes[0].revents & (POLLIN|POLLHUP|POLLERR))
|
|
#else
|
|
if (FD_ISSET(fd, &r_mask))
|
|
#endif
|
|
break;
|
|
if (!(dpy->flags & XlibDisplayProcConni)) {
|
|
int i;
|
|
|
|
saved_event_serial = dpy->next_event_serial_num;
|
|
/* dpy flags can be clobbered by internal connection callback */
|
|
in_read_events = dpy->flags & XlibDisplayReadEvents;
|
|
for (ilist=dpy->im_fd_info, i=1; ilist; ilist=ilist->next, i++) {
|
|
#ifdef USE_POLL
|
|
if (filedes[i].revents & POLLIN)
|
|
#else
|
|
if (FD_ISSET(ilist->fd, &r_mask))
|
|
#endif
|
|
{
|
|
_XProcessInternalConnection(dpy, ilist);
|
|
did_proc_conni = True;
|
|
}
|
|
}
|
|
#ifdef USE_POLL
|
|
if (dpy->im_fd_length + 1 > POLLFD_CACHE_SIZE)
|
|
Xfree(filedes);
|
|
#endif
|
|
}
|
|
if (did_proc_conni) {
|
|
/* some internal connection callback might have done an
|
|
XPutBackEvent. We notice it here and if we needed an event,
|
|
we can return all the way. */
|
|
if (_XNewerQueuedEvent(dpy, saved_event_serial)
|
|
&& (in_read_events
|
|
#ifdef XTHREADS
|
|
|| (dpy->lock && dpy->lock->event_awaiters)
|
|
#endif
|
|
))
|
|
return -2;
|
|
did_proc_conni = False;
|
|
}
|
|
}
|
|
#ifdef XTHREADS
|
|
#ifdef XTHREADS_DEBUG
|
|
printf("thread %x _XWaitForReadable returning\n", XThread_Self());
|
|
#endif
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
int _XSeqSyncFunction(
|
|
register Display *dpy)
|
|
{
|
|
xGetInputFocusReply rep;
|
|
register xReq *req;
|
|
|
|
LockDisplay(dpy);
|
|
if ((dpy->request - dpy->last_request_read) >= (BUFSIZE / SIZEOF(xReq))) {
|
|
GetEmptyReq(GetInputFocus, req);
|
|
(void) _XReply (dpy, (xReply *)&rep, 0, xTrue);
|
|
}
|
|
/* could get XID handler while waiting for reply in MT env */
|
|
if (dpy->synchandler == _XSeqSyncFunction) {
|
|
dpy->synchandler = dpy->savedsynchandler;
|
|
dpy->flags &= ~XlibDisplayPrivSync;
|
|
}
|
|
UnlockDisplay(dpy);
|
|
SyncHandle();
|
|
return 0;
|
|
}
|
|
|
|
#ifdef XTHREADS
|
|
static void _XFlushInt(
|
|
register Display *dpy,
|
|
register xcondition_t cv);
|
|
#endif
|
|
|
|
/*
|
|
* _XFlush - Flush the X request buffer. If the buffer is empty, no
|
|
* action is taken. This routine correctly handles incremental writes.
|
|
* This routine may have to be reworked if int < long.
|
|
*/
|
|
void _XFlush(
|
|
register Display *dpy)
|
|
{
|
|
#ifdef XTHREADS
|
|
/* With multi-threading we introduce an internal routine to which
|
|
we can pass a condition variable to do locking correctly. */
|
|
|
|
_XFlushInt(dpy, NULL);
|
|
}
|
|
|
|
/* _XFlushInt - Internal version of _XFlush used to do multi-threaded
|
|
* locking correctly.
|
|
*/
|
|
|
|
static void _XFlushInt(
|
|
register Display *dpy,
|
|
register xcondition_t cv)
|
|
{
|
|
#endif /* XTHREADS*/
|
|
register long size, todo;
|
|
register int write_stat;
|
|
register char *bufindex;
|
|
_XExtension *ext;
|
|
|
|
/* This fix resets the bufptr to the front of the buffer so
|
|
* additional appends to the bufptr will not corrupt memory. Since
|
|
* the server is down, these appends are no-op's anyway but
|
|
* callers of _XFlush() are not verifying this before they call it.
|
|
*/
|
|
if (dpy->flags & XlibDisplayIOError)
|
|
{
|
|
dpy->bufptr = dpy->buffer;
|
|
dpy->last_req = (char *)&_dummy_request;
|
|
return;
|
|
}
|
|
|
|
#ifdef XTHREADS
|
|
while (dpy->flags & XlibDisplayWriting) {
|
|
if (dpy->lock) {
|
|
ConditionWait(dpy, dpy->lock->writers);
|
|
} else {
|
|
_XWaitForWritable (dpy, cv);
|
|
}
|
|
}
|
|
#endif
|
|
size = todo = dpy->bufptr - dpy->buffer;
|
|
if (!size) return;
|
|
#ifdef XTHREADS
|
|
dpy->flags |= XlibDisplayWriting;
|
|
/* make sure no one else can put in data */
|
|
dpy->bufptr = dpy->bufmax;
|
|
#endif
|
|
for (ext = dpy->flushes; ext; ext = ext->next_flush)
|
|
(*ext->before_flush)(dpy, &ext->codes, dpy->buffer, size);
|
|
bufindex = dpy->buffer;
|
|
/*
|
|
* While write has not written the entire buffer, keep looping
|
|
* until the entire buffer is written. bufindex will be
|
|
* incremented and size decremented as buffer is written out.
|
|
*/
|
|
while (size) {
|
|
ESET(0);
|
|
write_stat = _X11TransWrite(dpy->trans_conn,
|
|
bufindex, (int) todo);
|
|
if (write_stat >= 0) {
|
|
size -= write_stat;
|
|
todo = size;
|
|
bufindex += write_stat;
|
|
} else if (ETEST()) {
|
|
_XWaitForWritable(dpy
|
|
#ifdef XTHREADS
|
|
, cv
|
|
#endif
|
|
);
|
|
#ifdef SUNSYSV
|
|
} else if (ECHECK(0)) {
|
|
_XWaitForWritable(dpy
|
|
#ifdef XTHREADS
|
|
, cv
|
|
#endif
|
|
);
|
|
#endif
|
|
#ifdef ESZTEST
|
|
} else if (ESZTEST()) {
|
|
if (todo > 1)
|
|
todo >>= 1;
|
|
else {
|
|
_XWaitForWritable(dpy
|
|
#ifdef XTHREADS
|
|
, cv
|
|
#endif
|
|
);
|
|
}
|
|
#endif
|
|
} else if (!ECHECK(EINTR)) {
|
|
/* Write failed! */
|
|
/* errno set by write system call. */
|
|
_XIOError(dpy);
|
|
}
|
|
}
|
|
dpy->last_req = (char *)&_dummy_request;
|
|
if ((dpy->request - dpy->last_request_read) >= SEQLIMIT &&
|
|
!(dpy->flags & XlibDisplayPrivSync)) {
|
|
dpy->savedsynchandler = dpy->synchandler;
|
|
dpy->synchandler = _XSeqSyncFunction;
|
|
dpy->flags |= XlibDisplayPrivSync;
|
|
}
|
|
dpy->bufptr = dpy->buffer;
|
|
#ifdef XTHREADS
|
|
dpy->flags &= ~XlibDisplayWriting;
|
|
#endif
|
|
}
|
|
|
|
int
|
|
_XEventsQueued(
|
|
register Display *dpy,
|
|
int mode)
|
|
{
|
|
register int len;
|
|
BytesReadable_t pend;
|
|
_XAlignedBuffer buf;
|
|
register xReply *rep;
|
|
char *read_buf;
|
|
#ifdef XTHREADS
|
|
int entry_event_serial_num;
|
|
struct _XCVList *cvl = NULL;
|
|
xthread_t self;
|
|
|
|
#ifdef XTHREADS_DEBUG
|
|
printf("_XEventsQueued called in thread %x\n", XThread_Self());
|
|
#endif
|
|
#endif /* XTHREADS*/
|
|
|
|
if (mode == QueuedAfterFlush)
|
|
{
|
|
_XFlush(dpy);
|
|
if (dpy->qlen)
|
|
return(dpy->qlen);
|
|
}
|
|
if (dpy->flags & XlibDisplayIOError) return(dpy->qlen);
|
|
|
|
#ifdef XTHREADS
|
|
/* create our condition variable and append to list,
|
|
* unless we were called from within XProcessInternalConnection
|
|
* or XLockDisplay
|
|
*/
|
|
xthread_clear_id(self);
|
|
if (dpy->lock && (xthread_have_id (dpy->lock->conni_thread)
|
|
|| xthread_have_id (dpy->lock->locking_thread)))
|
|
/* some thread is in XProcessInternalConnection or XLockDisplay
|
|
so we have to see if we are it */
|
|
self = XThread_Self();
|
|
if (!xthread_have_id(self)
|
|
|| (!xthread_equal(self, dpy->lock->conni_thread)
|
|
&& !xthread_equal(self, dpy->lock->locking_thread))) {
|
|
/* In the multi-threaded case, if there is someone else
|
|
reading events, then there aren't any available, so
|
|
we just return. If we waited we would block.
|
|
*/
|
|
if (dpy->lock && dpy->lock->event_awaiters)
|
|
return dpy->qlen;
|
|
/* nobody here but us, so lock out any newcomers */
|
|
cvl = QueueEventReaderLock(dpy);
|
|
}
|
|
|
|
while (dpy->lock && cvl && dpy->lock->reply_first) {
|
|
/* note which events we have already seen so we'll know
|
|
if _XReply (in another thread) reads one */
|
|
entry_event_serial_num = dpy->next_event_serial_num;
|
|
ConditionWait(dpy, cvl->cv);
|
|
/* did _XReply read an event we can return? */
|
|
if (_XNewerQueuedEvent(dpy, entry_event_serial_num))
|
|
{
|
|
UnlockNextEventReader(dpy);
|
|
return 0;
|
|
}
|
|
}
|
|
#endif /* XTHREADS*/
|
|
|
|
if (_X11TransBytesReadable(dpy->trans_conn, &pend) < 0)
|
|
_XIOError(dpy);
|
|
#ifdef XCONN_CHECK_FREQ
|
|
/* This is a crock, required because FIONREAD or equivalent is
|
|
* not guaranteed to detect a broken connection.
|
|
*/
|
|
if (!pend && !dpy->qlen && ++dpy->conn_checker >= XCONN_CHECK_FREQ)
|
|
{
|
|
int result;
|
|
#ifdef USE_POLL
|
|
struct pollfd filedes;
|
|
#else
|
|
fd_set r_mask;
|
|
static struct timeval zero_time;
|
|
#endif
|
|
|
|
dpy->conn_checker = 0;
|
|
#ifdef USE_POLL
|
|
filedes.fd = dpy->fd;
|
|
filedes.events = POLLIN;
|
|
if ((result = poll(&filedes, 1, 0)))
|
|
#else
|
|
FD_ZERO(&r_mask);
|
|
FD_SET(dpy->fd, &r_mask);
|
|
if ((result = Select(dpy->fd + 1, &r_mask, NULL, NULL, &zero_time)))
|
|
#endif
|
|
{
|
|
if (result > 0)
|
|
{
|
|
if (_X11TransBytesReadable(dpy->trans_conn, &pend) < 0)
|
|
_XIOError(dpy);
|
|
/* we should not get zero, if we do, force a read */
|
|
if (!pend)
|
|
pend = SIZEOF(xReply);
|
|
}
|
|
else if (result < 0 && !ECHECK(EINTR))
|
|
_XIOError(dpy);
|
|
}
|
|
}
|
|
#endif /* XCONN_CHECK_FREQ */
|
|
if (!(len = pend)) {
|
|
/* _XFlush can enqueue events */
|
|
#ifdef XTHREADS
|
|
if (cvl)
|
|
#endif
|
|
{
|
|
UnlockNextEventReader(dpy);
|
|
}
|
|
return(dpy->qlen);
|
|
}
|
|
/* Force a read if there is not enough data. Otherwise,
|
|
* a select() loop at a higher-level will spin undesirably,
|
|
* and we've seen at least one OS that appears to not update
|
|
* the result from FIONREAD once it has returned nonzero.
|
|
*/
|
|
#ifdef XTHREADS
|
|
if (dpy->lock && dpy->lock->reply_awaiters) {
|
|
read_buf = (char *)dpy->lock->reply_awaiters->buf;
|
|
len = SIZEOF(xReply);
|
|
} else
|
|
#endif /* XTHREADS*/
|
|
{
|
|
read_buf = buf.buf;
|
|
|
|
if (len < SIZEOF(xReply)
|
|
#ifdef XTHREADS
|
|
|| dpy->async_handlers
|
|
#endif
|
|
)
|
|
len = SIZEOF(xReply);
|
|
else if (len > BUFSIZE)
|
|
len = BUFSIZE;
|
|
len = (len / SIZEOF(xReply)) * SIZEOF(xReply);
|
|
}
|
|
#ifdef XCONN_CHECK_FREQ
|
|
dpy->conn_checker = 0;
|
|
#endif
|
|
|
|
(void) _XRead (dpy, read_buf, (long) len);
|
|
|
|
#ifdef XTHREADS
|
|
/* what did we actually read: reply or event? */
|
|
if (dpy->lock && dpy->lock->reply_awaiters) {
|
|
if (((xReply *)read_buf)->generic.type == X_Reply ||
|
|
((xReply *)read_buf)->generic.type == X_Error)
|
|
{
|
|
dpy->lock->reply_was_read = True;
|
|
dpy->lock->reply_first = True;
|
|
if (read_buf != (char *)dpy->lock->reply_awaiters->buf)
|
|
memcpy(dpy->lock->reply_awaiters->buf, read_buf,
|
|
len);
|
|
if (cvl) {
|
|
UnlockNextEventReader(dpy);
|
|
}
|
|
return(dpy->qlen); /* we read, so we can return */
|
|
} else if (read_buf != buf.buf)
|
|
memcpy(buf.buf, read_buf, len);
|
|
}
|
|
#endif /* XTHREADS*/
|
|
|
|
STARTITERATE(rep,xReply,buf.buf,len > 0) {
|
|
if (rep->generic.type == X_Reply) {
|
|
int tmp = len;
|
|
RESETITERPTR(rep,xReply,
|
|
_XAsyncReply (dpy, rep,
|
|
ITERPTR(rep), &tmp, True));
|
|
len = tmp;
|
|
pend = len;
|
|
} else {
|
|
if (rep->generic.type == X_Error)
|
|
_XError (dpy, (xError *)rep);
|
|
else /* must be an event packet */
|
|
_XEnq (dpy, (xEvent *)rep);
|
|
INCITERPTR(rep,xReply);
|
|
len -= SIZEOF(xReply);
|
|
}
|
|
} ENDITERATE
|
|
|
|
#ifdef XTHREADS
|
|
if (cvl)
|
|
#endif
|
|
{
|
|
UnlockNextEventReader(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(
|
|
register Display *dpy)
|
|
{
|
|
_XAlignedBuffer buf;
|
|
BytesReadable_t pend;
|
|
int len;
|
|
register xReply *rep;
|
|
Bool not_yet_flushed = True;
|
|
char *read_buf;
|
|
int i;
|
|
int entry_event_serial_num = dpy->next_event_serial_num;
|
|
#ifdef XTHREADS
|
|
struct _XCVList *cvl = NULL;
|
|
xthread_t self;
|
|
|
|
#ifdef XTHREADS_DEBUG
|
|
printf("_XReadEvents called in thread %x\n",
|
|
XThread_Self());
|
|
#endif
|
|
/* create our condition variable and append to list,
|
|
* unless we were called from within XProcessInternalConnection
|
|
* or XLockDisplay
|
|
*/
|
|
xthread_clear_id(self);
|
|
if (dpy->lock && (xthread_have_id (dpy->lock->conni_thread)
|
|
|| xthread_have_id (dpy->lock->locking_thread)))
|
|
/* some thread is in XProcessInternalConnection or XLockDisplay
|
|
so we have to see if we are it */
|
|
self = XThread_Self();
|
|
if (!xthread_have_id(self)
|
|
|| (!xthread_equal(self, dpy->lock->conni_thread)
|
|
&& !xthread_equal(self, dpy->lock->locking_thread)))
|
|
cvl = QueueEventReaderLock(dpy);
|
|
#endif /* XTHREADS */
|
|
|
|
do {
|
|
#ifdef XTHREADS
|
|
/* if it is not our turn to read an event off the wire,
|
|
wait til we're at head of list */
|
|
if (dpy->lock && cvl &&
|
|
(dpy->lock->event_awaiters != cvl ||
|
|
dpy->lock->reply_first)) {
|
|
ConditionWait(dpy, cvl->cv);
|
|
continue;
|
|
}
|
|
#endif /* XTHREADS */
|
|
/* find out how much data can be read */
|
|
if (_X11TransBytesReadable(dpy->trans_conn, &pend) < 0)
|
|
_XIOError(dpy);
|
|
len = pend;
|
|
|
|
/* must read at least one xEvent; if none is pending, then
|
|
we'll just flush and block waiting for it */
|
|
if (len < SIZEOF(xEvent)
|
|
#ifdef XTHREADS
|
|
|| dpy->async_handlers
|
|
#endif
|
|
) {
|
|
len = SIZEOF(xEvent);
|
|
/* don't flush until the first time we would block */
|
|
if (not_yet_flushed) {
|
|
_XFlush (dpy);
|
|
if (_XNewerQueuedEvent(dpy, entry_event_serial_num)) {
|
|
/* _XReply has read an event for us */
|
|
goto got_event;
|
|
}
|
|
not_yet_flushed = False;
|
|
}
|
|
}
|
|
|
|
#ifdef XTHREADS
|
|
/* If someone is waiting for a reply, gamble that
|
|
the reply will be the next thing on the wire
|
|
and read it into their buffer. */
|
|
if (dpy->lock && dpy->lock->reply_awaiters) {
|
|
read_buf = (char *)dpy->lock->reply_awaiters->buf;
|
|
len = SIZEOF(xReply);
|
|
} else
|
|
#endif /* XTHREADS*/
|
|
{
|
|
read_buf = buf.buf;
|
|
|
|
/* but we won't read more than the max buffer size */
|
|
if (len > BUFSIZE)
|
|
len = BUFSIZE;
|
|
|
|
/* round down to an integral number of XReps */
|
|
len = (len / SIZEOF(xEvent)) * SIZEOF(xEvent);
|
|
}
|
|
|
|
#ifdef XTHREADS
|
|
if (xthread_have_id(self))
|
|
/* save value we may have to stick in conni_thread */
|
|
dpy->lock->reading_thread = self;
|
|
#endif /* XTHREADS */
|
|
dpy->flags |= XlibDisplayReadEvents;
|
|
i = _XRead (dpy, read_buf, (long) len);
|
|
dpy->flags &= ~XlibDisplayReadEvents;
|
|
if (i == -2) {
|
|
/* special flag from _XRead to say that internal connection has
|
|
done XPutBackEvent. Which we can use so we're done. */
|
|
got_event:
|
|
#ifdef XTHREADS
|
|
if (dpy->lock && dpy->lock->lock_wait) {
|
|
if (dpy->lock->event_awaiters != cvl)
|
|
/* since it is not us, must be user lock thread */
|
|
ConditionSignal(dpy,
|
|
dpy->lock->event_awaiters->cv);
|
|
(*dpy->lock->lock_wait)(dpy);
|
|
continue;
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
#ifdef XTHREADS
|
|
if (xthread_have_id(self))
|
|
xthread_clear_id(dpy->lock->reading_thread);
|
|
|
|
/* what did we actually read: reply or event? */
|
|
if (dpy->lock && dpy->lock->reply_awaiters) {
|
|
if (((xReply *)read_buf)->generic.type == X_Reply ||
|
|
((xReply *)read_buf)->generic.type == X_Error)
|
|
{
|
|
dpy->lock->reply_was_read = True;
|
|
dpy->lock->reply_first = True;
|
|
if (read_buf != (char *)dpy->lock->reply_awaiters->buf)
|
|
memcpy(dpy->lock->reply_awaiters->buf,
|
|
read_buf, len);
|
|
ConditionSignal(dpy, dpy->lock->reply_awaiters->cv);
|
|
continue;
|
|
} else if (read_buf != buf.buf)
|
|
memcpy(buf.buf, read_buf, len);
|
|
}
|
|
#endif /* XTHREADS */
|
|
|
|
STARTITERATE(rep,xReply,buf.buf,len > 0) {
|
|
if (rep->generic.type == X_Reply) {
|
|
RESETITERPTR(rep,xReply,
|
|
_XAsyncReply (dpy, rep,
|
|
ITERPTR(rep), &len, True));
|
|
pend = len;
|
|
} else {
|
|
if (rep->generic.type == X_Error)
|
|
_XError (dpy, (xError *) rep);
|
|
else /* must be an event packet */
|
|
_XEnq (dpy, (xEvent *)rep);
|
|
INCITERPTR(rep,xReply);
|
|
len -= SIZEOF(xReply);
|
|
}
|
|
} ENDITERATE;
|
|
} while (!_XNewerQueuedEvent(dpy, entry_event_serial_num));
|
|
|
|
UnlockNextEventReader(dpy);
|
|
}
|
|
|
|
/*
|
|
* _XRead - Read bytes from the socket taking into account incomplete
|
|
* reads. This routine may have to be reworked if int < long.
|
|
*/
|
|
int _XRead(
|
|
register Display *dpy,
|
|
register char *data,
|
|
register long size)
|
|
{
|
|
register long bytes_read;
|
|
#ifdef XTHREADS
|
|
int original_size = size;
|
|
#endif
|
|
|
|
if ((dpy->flags & XlibDisplayIOError) || size == 0)
|
|
return 0;
|
|
ESET(0);
|
|
while ((bytes_read = _X11TransRead(dpy->trans_conn, data, (int)size))
|
|
!= size) {
|
|
|
|
if (bytes_read > 0) {
|
|
size -= bytes_read;
|
|
data += bytes_read;
|
|
}
|
|
else if (ETEST()) {
|
|
if (_XWaitForReadable(dpy) == -2)
|
|
return -2; /* internal connection did XPutBackEvent */
|
|
ESET(0);
|
|
}
|
|
#ifdef SUNSYSV
|
|
else if (ECHECK(0)) {
|
|
if (_XWaitForReadable(dpy) == -2)
|
|
return -2; /* internal connection did XPutBackEvent */
|
|
}
|
|
#endif
|
|
else if (bytes_read == 0) {
|
|
/* Read failed because of end of file! */
|
|
ESET(EPIPE);
|
|
_XIOError(dpy);
|
|
}
|
|
|
|
else /* bytes_read is less than 0; presumably -1 */ {
|
|
/* If it's a system call interrupt, it's not an error. */
|
|
if (!ECHECK(EINTR))
|
|
_XIOError(dpy);
|
|
}
|
|
}
|
|
#ifdef XTHREADS
|
|
if (dpy->lock && dpy->lock->reply_bytes_left > 0)
|
|
{
|
|
dpy->lock->reply_bytes_left -= original_size;
|
|
if (dpy->lock->reply_bytes_left == 0) {
|
|
dpy->flags &= ~XlibDisplayReply;
|
|
UnlockNextReplyReader(dpy);
|
|
}
|
|
}
|
|
#endif /* XTHREADS*/
|
|
return 0;
|
|
}
|
|
|
|
#ifdef LONG64
|
|
void _XRead32(
|
|
Display *dpy,
|
|
register long *data,
|
|
long len)
|
|
{
|
|
register int *buf;
|
|
register long i;
|
|
|
|
if (len) {
|
|
(void) _XRead(dpy, (char *)data, len);
|
|
i = len >> 2;
|
|
buf = (int *)data + i;
|
|
data += i;
|
|
while (--i >= 0)
|
|
*--data = *--buf;
|
|
}
|
|
}
|
|
#endif /* LONG64 */
|
|
|
|
#ifdef WORD64
|
|
|
|
/*
|
|
* XXX This is a *really* stupid way of doing this....
|
|
* PACKBUFFERSIZE must be a multiple of 4.
|
|
*/
|
|
|
|
#define PACKBUFFERSIZE 4096
|
|
|
|
|
|
/*
|
|
* _XRead32 - Read bytes from the socket unpacking each 32 bits
|
|
* into a long (64 bits on a CRAY computer).
|
|
*
|
|
*/
|
|
static void _doXRead32(
|
|
register Display *dpy,
|
|
register long *data
|
|
register long size,
|
|
register char *packbuffer)
|
|
{
|
|
long *lpack,*lp;
|
|
long mask32 = 0x00000000ffffffff;
|
|
long maskw, nwords, i, bits;
|
|
|
|
_XReadPad (dpy, packbuffer, size);
|
|
|
|
lp = data;
|
|
lpack = (long *) packbuffer;
|
|
nwords = size >> 2;
|
|
bits = 32;
|
|
|
|
for(i=0;i<nwords;i++){
|
|
maskw = mask32 << bits;
|
|
*lp++ = ( *lpack & maskw ) >> bits;
|
|
bits = bits ^32;
|
|
if(bits){
|
|
lpack++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void _XRead32(
|
|
Display *dpy,
|
|
long *data,
|
|
long len)
|
|
{
|
|
char packbuffer[PACKBUFFERSIZE];
|
|
unsigned nunits = PACKBUFFERSIZE >> 2;
|
|
|
|
for (; len > PACKBUFFERSIZE; len -= PACKBUFFERSIZE, data += nunits) {
|
|
_doXRead32 (dpy, data, PACKBUFFERSIZE, packbuffer);
|
|
}
|
|
if (len) _doXRead32 (dpy, data, len, packbuffer);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* _XRead16 - Read bytes from the socket unpacking each 16 bits
|
|
* into a long (64 bits on a CRAY computer).
|
|
*
|
|
*/
|
|
static _doXRead16(
|
|
register Display *dpy,
|
|
register short *data,
|
|
register long size,
|
|
char *packbuffer)
|
|
{
|
|
long *lpack,*lp;
|
|
long mask16 = 0x000000000000ffff;
|
|
long maskw, nwords, i, bits;
|
|
|
|
(void) _XRead(dpy,packbuffer,size); /* don't do a padded read... */
|
|
|
|
lp = (long *) data;
|
|
lpack = (long *) packbuffer;
|
|
nwords = size >> 1; /* number of 16 bit words to be unpacked */
|
|
bits = 48;
|
|
for(i=0;i<nwords;i++){
|
|
maskw = mask16 << bits;
|
|
*lp++ = ( *lpack & maskw ) >> bits;
|
|
bits -= 16;
|
|
if(bits < 0){
|
|
lpack++;
|
|
bits = 48;
|
|
}
|
|
}
|
|
}
|
|
|
|
void _XRead16(
|
|
Display *dpy,
|
|
short *data,
|
|
long len)
|
|
{
|
|
char packbuffer[PACKBUFFERSIZE];
|
|
unsigned nunits = PACKBUFFERSIZE >> 1;
|
|
|
|
for (; len > PACKBUFFERSIZE; len -= PACKBUFFERSIZE, data += nunits) {
|
|
_doXRead16 (dpy, data, PACKBUFFERSIZE, packbuffer);
|
|
}
|
|
if (len) _doXRead16 (dpy, data, len, packbuffer);
|
|
}
|
|
|
|
void _XRead16Pad(
|
|
Display *dpy,
|
|
short *data,
|
|
long size)
|
|
{
|
|
int slop = (size & 3);
|
|
short slopbuf[3];
|
|
|
|
_XRead16 (dpy, data, size);
|
|
if (slop > 0) {
|
|
_XRead16 (dpy, slopbuf, 4 - slop);
|
|
}
|
|
}
|
|
#endif /* WORD64 */
|
|
|
|
|
|
/*
|
|
* _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. This routine may have to be reworked if int < long.
|
|
*/
|
|
void _XReadPad(
|
|
register Display *dpy,
|
|
register char *data,
|
|
register long size)
|
|
{
|
|
register long bytes_read;
|
|
struct iovec iov[2];
|
|
char pad[3];
|
|
#ifdef XTHREADS
|
|
int original_size;
|
|
#endif
|
|
|
|
if ((dpy->flags & XlibDisplayIOError) || size == 0) return;
|
|
iov[0].iov_len = (int)size;
|
|
iov[0].iov_base = data;
|
|
/*
|
|
* The following hack is used to provide 32 bit long-word
|
|
* aligned padding. The [1] vector is of length 0, 1, 2, or 3,
|
|
* whatever is needed.
|
|
*/
|
|
|
|
iov[1].iov_len = -size & 3;
|
|
iov[1].iov_base = pad;
|
|
size += iov[1].iov_len;
|
|
#ifdef XTHREADS
|
|
original_size = size;
|
|
#endif
|
|
ESET(0);
|
|
while ((bytes_read = _X11TransReadv (dpy->trans_conn, iov, 2)) != size) {
|
|
|
|
if (bytes_read > 0) {
|
|
size -= bytes_read;
|
|
if (iov[0].iov_len < bytes_read) {
|
|
iov[1].iov_len += iov[0].iov_len - bytes_read;
|
|
iov[1].iov_base =
|
|
(char *)iov[1].iov_base + bytes_read - iov[0].iov_len;
|
|
iov[0].iov_len = 0;
|
|
}
|
|
else {
|
|
iov[0].iov_len -= bytes_read;
|
|
iov[0].iov_base = (char *)iov[0].iov_base + bytes_read;
|
|
}
|
|
}
|
|
else if (ETEST()) {
|
|
_XWaitForReadable(dpy);
|
|
ESET(0);
|
|
}
|
|
#ifdef SUNSYSV
|
|
else if (ECHECK(0)) {
|
|
_XWaitForReadable(dpy);
|
|
}
|
|
#endif
|
|
else if (bytes_read == 0) {
|
|
/* Read failed because of end of file! */
|
|
ESET(EPIPE);
|
|
_XIOError(dpy);
|
|
}
|
|
|
|
else /* bytes_read is less than 0; presumably -1 */ {
|
|
/* If it's a system call interrupt, it's not an error. */
|
|
if (!ECHECK(EINTR))
|
|
_XIOError(dpy);
|
|
}
|
|
}
|
|
#ifdef XTHREADS
|
|
if (dpy->lock && dpy->lock->reply_bytes_left > 0)
|
|
{
|
|
dpy->lock->reply_bytes_left -= original_size;
|
|
if (dpy->lock->reply_bytes_left == 0) {
|
|
dpy->flags &= ~XlibDisplayReply;
|
|
UnlockNextReplyReader(dpy);
|
|
}
|
|
}
|
|
#endif /* XTHREADS*/
|
|
}
|
|
|
|
/*
|
|
* _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.
|
|
* This routine may have to be reworked if int < long;
|
|
*/
|
|
void
|
|
_XSend (
|
|
register Display *dpy,
|
|
_Xconst char *data,
|
|
register long size)
|
|
{
|
|
struct iovec iov[3];
|
|
static char const pad[3] = {0, 0, 0};
|
|
/* XText8 and XText16 require that the padding bytes be zero! */
|
|
|
|
long skip, dbufsize, padsize, total, todo;
|
|
_XExtension *ext;
|
|
|
|
if (!size || (dpy->flags & XlibDisplayIOError)) return;
|
|
dbufsize = dpy->bufptr - dpy->buffer;
|
|
#ifdef XTHREADS
|
|
dpy->flags |= XlibDisplayWriting;
|
|
/* make sure no one else can put in data */
|
|
dpy->bufptr = dpy->bufmax;
|
|
#endif
|
|
padsize = -size & 3;
|
|
for (ext = dpy->flushes; ext; ext = ext->next_flush) {
|
|
(*ext->before_flush)(dpy, &ext->codes, dpy->buffer, dbufsize);
|
|
(*ext->before_flush)(dpy, &ext->codes, (char *)data, size);
|
|
if (padsize)
|
|
(*ext->before_flush)(dpy, &ext->codes, pad, padsize);
|
|
}
|
|
skip = 0;
|
|
todo = total = dbufsize + size + padsize;
|
|
|
|
/*
|
|
* There are 3 pieces that may need to be written out:
|
|
*
|
|
* o whatever is in the display buffer
|
|
* o the data passed in by the user
|
|
* o any padding needed to 32bit align the whole mess
|
|
*
|
|
* This loop looks at all 3 pieces each time through. It uses skip
|
|
* to figure out whether or not a given piece is needed.
|
|
*/
|
|
while (total) {
|
|
long before = skip; /* amount of whole thing written */
|
|
long remain = todo; /* amount to try this time, <= total */
|
|
int i = 0;
|
|
long len;
|
|
|
|
/* You could be very general here and have "in" and "out" iovecs
|
|
* and write a loop without using a macro, but what the heck. This
|
|
* translates to:
|
|
*
|
|
* how much of this piece is new?
|
|
* if more new then we are trying this time, clamp
|
|
* if nothing new
|
|
* then bump down amount already written, for next piece
|
|
* else put new stuff in iovec, will need all of next piece
|
|
*
|
|
* Note that todo had better be at least 1 or else we'll end up
|
|
* writing 0 iovecs.
|
|
*/
|
|
#define InsertIOV(pointer, length) \
|
|
len = (length) - before; \
|
|
if (len > remain) \
|
|
len = remain; \
|
|
if (len <= 0) { \
|
|
before = (-len); \
|
|
} else { \
|
|
iov[i].iov_len = len; \
|
|
iov[i].iov_base = (pointer) + before; \
|
|
i++; \
|
|
remain -= len; \
|
|
before = 0; \
|
|
}
|
|
|
|
InsertIOV (dpy->buffer, dbufsize)
|
|
InsertIOV ((char *)data, size)
|
|
InsertIOV ((char *)pad, padsize)
|
|
|
|
ESET(0);
|
|
if ((len = _X11TransWritev(dpy->trans_conn, iov, i)) >= 0) {
|
|
skip += len;
|
|
total -= len;
|
|
todo = total;
|
|
} else if (ETEST()) {
|
|
_XWaitForWritable(dpy
|
|
#ifdef XTHREADS
|
|
, NULL
|
|
#endif
|
|
);
|
|
#ifdef SUNSYSV
|
|
} else if (ECHECK(0)) {
|
|
_XWaitForWritable(dpy
|
|
#ifdef XTHREADS
|
|
, NULL
|
|
#endif
|
|
);
|
|
#endif
|
|
#ifdef ESZTEST
|
|
} else if (ESZTEST()) {
|
|
if (todo > 1)
|
|
todo >>= 1;
|
|
else {
|
|
_XWaitForWritable(dpy
|
|
#ifdef XTHREADS
|
|
, NULL
|
|
#endif
|
|
);
|
|
}
|
|
#endif
|
|
} else if (!ECHECK(EINTR)) {
|
|
_XIOError(dpy);
|
|
}
|
|
}
|
|
dpy->last_req = (char *) & _dummy_request;
|
|
if ((dpy->request - dpy->last_request_read) >= SEQLIMIT &&
|
|
!(dpy->flags & XlibDisplayPrivSync)) {
|
|
dpy->savedsynchandler = dpy->synchandler;
|
|
dpy->synchandler = _XSeqSyncFunction;
|
|
dpy->flags |= XlibDisplayPrivSync;
|
|
}
|
|
dpy->bufptr = dpy->buffer;
|
|
#ifdef XTHREADS
|
|
dpy->flags &= ~XlibDisplayWriting;
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
static void
|
|
_XGetMiscCode(
|
|
register Display *dpy)
|
|
{
|
|
xQueryExtensionReply qrep;
|
|
register xQueryExtensionReq *qreq;
|
|
xXCMiscGetVersionReply vrep;
|
|
register xXCMiscGetVersionReq *vreq;
|
|
|
|
if (dpy->xcmisc_opcode)
|
|
return;
|
|
GetReq(QueryExtension, qreq);
|
|
qreq->nbytes = sizeof(XCMiscExtensionName) - 1;
|
|
qreq->length += (qreq->nbytes+(unsigned)3)>>2;
|
|
_XSend(dpy, XCMiscExtensionName, (long)qreq->nbytes);
|
|
if (!_XReply (dpy, (xReply *)&qrep, 0, xTrue))
|
|
dpy->xcmisc_opcode = -1;
|
|
else {
|
|
GetReq(XCMiscGetVersion, vreq);
|
|
vreq->reqType = qrep.major_opcode;
|
|
vreq->miscReqType = X_XCMiscGetVersion;
|
|
vreq->majorVersion = XCMiscMajorVersion;
|
|
vreq->minorVersion = XCMiscMinorVersion;
|
|
if (!_XReply (dpy, (xReply *)&vrep, 0, xTrue))
|
|
dpy->xcmisc_opcode = -1;
|
|
else
|
|
dpy->xcmisc_opcode = qrep.major_opcode;
|
|
}
|
|
}
|
|
|
|
static int
|
|
_XIDHandler(
|
|
register Display *dpy)
|
|
{
|
|
xXCMiscGetXIDRangeReply grep;
|
|
register xXCMiscGetXIDRangeReq *greq;
|
|
|
|
LockDisplay(dpy);
|
|
_XGetMiscCode(dpy);
|
|
if (dpy->xcmisc_opcode > 0) {
|
|
GetReq(XCMiscGetXIDRange, greq);
|
|
greq->reqType = dpy->xcmisc_opcode;
|
|
greq->miscReqType = X_XCMiscGetXIDRange;
|
|
if (_XReply (dpy, (xReply *)&grep, 0, xTrue) && grep.count) {
|
|
dpy->resource_id = ((grep.start_id - dpy->resource_base) >>
|
|
dpy->resource_shift);
|
|
dpy->resource_max = dpy->resource_id;
|
|
if (grep.count > 5)
|
|
dpy->resource_max += grep.count - 6;
|
|
dpy->resource_max <<= dpy->resource_shift;
|
|
}
|
|
}
|
|
if (dpy->flags & XlibDisplayPrivSync) {
|
|
dpy->synchandler = dpy->savedsynchandler;
|
|
dpy->flags &= ~XlibDisplayPrivSync;
|
|
}
|
|
UnlockDisplay(dpy);
|
|
SyncHandle();
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* _XAllocID - resource ID allocation routine.
|
|
*/
|
|
XID _XAllocID(
|
|
register Display *dpy)
|
|
{
|
|
XID id;
|
|
|
|
id = dpy->resource_id << dpy->resource_shift;
|
|
if (id >= dpy->resource_max) {
|
|
if (!(dpy->flags & XlibDisplayPrivSync)) {
|
|
dpy->savedsynchandler = dpy->synchandler;
|
|
dpy->flags |= XlibDisplayPrivSync;
|
|
}
|
|
dpy->synchandler = _XIDHandler;
|
|
dpy->resource_max = dpy->resource_mask + 1;
|
|
}
|
|
if (id <= dpy->resource_mask) {
|
|
dpy->resource_id++;
|
|
return (dpy->resource_base + id);
|
|
}
|
|
if (id != 0x10000000) {
|
|
(void) fprintf(stderr,
|
|
"Xlib: resource ID allocation space exhausted!\n");
|
|
id = 0x10000000;
|
|
dpy->resource_id = id >> dpy->resource_shift;
|
|
}
|
|
return id;
|
|
}
|
|
|
|
/*
|
|
* _XAllocIDs - multiple resource ID allocation routine.
|
|
*/
|
|
void _XAllocIDs(
|
|
register Display *dpy,
|
|
XID *ids,
|
|
int count)
|
|
{
|
|
XID id;
|
|
int i;
|
|
xXCMiscGetXIDListReply grep;
|
|
register xXCMiscGetXIDListReq *greq;
|
|
|
|
id = dpy->resource_id << dpy->resource_shift;
|
|
if (dpy->resource_max <= dpy->resource_mask &&
|
|
id <= dpy->resource_mask &&
|
|
(dpy->resource_max - id) > ((count - 1) << dpy->resource_shift)) {
|
|
id += dpy->resource_base;
|
|
for (i = 0; i < count; i++) {
|
|
ids[i] = id;
|
|
id += (1 << dpy->resource_shift);
|
|
dpy->resource_id++;
|
|
}
|
|
return;
|
|
}
|
|
grep.count = 0;
|
|
_XGetMiscCode(dpy);
|
|
if (dpy->xcmisc_opcode > 0) {
|
|
GetReq(XCMiscGetXIDList, greq);
|
|
greq->reqType = dpy->xcmisc_opcode;
|
|
greq->miscReqType = X_XCMiscGetXIDList;
|
|
greq->count = count;
|
|
if (_XReply(dpy, (xReply *)&grep, 0, xFalse) && grep.count) {
|
|
_XRead32(dpy, (long *) ids, 4L * (long) (grep.count));
|
|
for (i = 0; i < grep.count; i++) {
|
|
id = (ids[i] - dpy->resource_base) >> dpy->resource_shift;
|
|
if (id >= dpy->resource_id)
|
|
dpy->resource_id = id;
|
|
}
|
|
if (id >= dpy->resource_max) {
|
|
if (!(dpy->flags & XlibDisplayPrivSync)) {
|
|
dpy->savedsynchandler = dpy->synchandler;
|
|
dpy->flags |= XlibDisplayPrivSync;
|
|
}
|
|
dpy->synchandler = _XIDHandler;
|
|
dpy->resource_max = dpy->resource_mask + 1;
|
|
}
|
|
}
|
|
}
|
|
for (i = grep.count; i < count; i++)
|
|
ids[i] = XAllocID(dpy);
|
|
}
|
|
|
|
/*
|
|
* The hard part about this is that we only get 16 bits from a reply.
|
|
* We have three values that will march along, with the following invariant:
|
|
* dpy->last_request_read <= rep->sequenceNumber <= dpy->request
|
|
* We have to keep
|
|
* dpy->request - dpy->last_request_read < 2^16
|
|
* or else we won't know for sure what value to use in events. We do this
|
|
* by forcing syncs when we get close.
|
|
*/
|
|
|
|
unsigned long
|
|
_XSetLastRequestRead(
|
|
register Display *dpy,
|
|
register xGenericReply *rep)
|
|
{
|
|
register unsigned long newseq, lastseq;
|
|
|
|
lastseq = dpy->last_request_read;
|
|
/*
|
|
* KeymapNotify has no sequence number, but is always guaranteed
|
|
* to immediately follow another event, except when generated via
|
|
* SendEvent (hmmm).
|
|
*/
|
|
if ((rep->type & 0x7f) == KeymapNotify)
|
|
return(lastseq);
|
|
|
|
newseq = (lastseq & ~((unsigned long)0xffff)) | rep->sequenceNumber;
|
|
|
|
if (newseq < lastseq) {
|
|
newseq += 0x10000;
|
|
if (newseq > dpy->request) {
|
|
(void) fprintf (stderr,
|
|
"Xlib: sequence lost (0x%lx > 0x%lx) in reply type 0x%x!\n",
|
|
newseq, dpy->request,
|
|
(unsigned int) rep->type);
|
|
newseq -= 0x10000;
|
|
}
|
|
}
|
|
|
|
dpy->last_request_read = newseq;
|
|
return(newseq);
|
|
}
|
|
|
|
/*
|
|
* _XReply - Wait for a reply packet and copy its contents into the
|
|
* specified rep. Meanwhile we must handle error and event packets that
|
|
* we may encounter.
|
|
*/
|
|
Status
|
|
_XReply (
|
|
register Display *dpy,
|
|
register xReply *rep,
|
|
int extra, /* number of 32-bit words expected after the reply */
|
|
Bool discard) /* should I discard data following "extra" words? */
|
|
{
|
|
/* Pull out the serial number now, so that (currently illegal) requests
|
|
* generated by an error handler don't confuse us.
|
|
*/
|
|
unsigned long cur_request = dpy->request;
|
|
#ifdef XTHREADS
|
|
struct _XCVList *cvl;
|
|
#endif
|
|
|
|
if (dpy->flags & XlibDisplayIOError)
|
|
return 0;
|
|
|
|
#ifdef XTHREADS
|
|
/* create our condition variable and append to list */
|
|
cvl = QueueReplyReaderLock(dpy);
|
|
if (cvl) {
|
|
cvl->buf = rep;
|
|
if (dpy->lock->reply_awaiters == cvl && !dpy->lock->event_awaiters)
|
|
dpy->lock->reply_first = True;
|
|
}
|
|
|
|
#ifdef XTHREADS_DEBUG
|
|
printf("_XReply called in thread %x, adding %x to cvl\n",
|
|
XThread_Self(), cvl);
|
|
#endif
|
|
|
|
_XFlushInt(dpy, cvl ? cvl->cv : NULL);
|
|
/* if it is not our turn to read a reply off the wire,
|
|
* wait til we're at head of list. if there is an event waiter,
|
|
* and our reply hasn't been read, they'll be in select and will
|
|
* hand control back to us next.
|
|
*/
|
|
if(dpy->lock &&
|
|
(dpy->lock->reply_awaiters != cvl || !dpy->lock->reply_first)) {
|
|
ConditionWait(dpy, cvl->cv);
|
|
}
|
|
dpy->flags |= XlibDisplayReply;
|
|
#else /* XTHREADS else */
|
|
_XFlush(dpy);
|
|
#endif
|
|
|
|
for (;;) {
|
|
#ifdef XTHREADS
|
|
/* Did another thread's _XReadEvents get our reply by accident? */
|
|
if (!dpy->lock || !dpy->lock->reply_was_read)
|
|
#endif
|
|
(void) _XRead(dpy, (char *)rep, (long)SIZEOF(xReply));
|
|
#ifdef XTHREADS
|
|
if (dpy->lock)
|
|
dpy->lock->reply_was_read = False;
|
|
#endif
|
|
|
|
switch ((int)rep->generic.type) {
|
|
|
|
case X_Reply:
|
|
/* Reply received. Fast update for synchronous replies,
|
|
* but deal with multiple outstanding replies.
|
|
*/
|
|
if (rep->generic.sequenceNumber == (cur_request & 0xffff))
|
|
dpy->last_request_read = cur_request;
|
|
else {
|
|
int pend = SIZEOF(xReply);
|
|
if (_XAsyncReply(dpy, rep, (char *)rep, &pend, False)
|
|
!= (char *)rep)
|
|
continue;
|
|
}
|
|
if (extra <= rep->generic.length) {
|
|
if (extra > 0)
|
|
/*
|
|
* Read the extra data into storage immediately
|
|
* following the GenericReply structure.
|
|
*/
|
|
(void) _XRead (dpy, (char *) (NEXTPTR(rep,xReply)),
|
|
((long)extra) << 2);
|
|
if (discard) {
|
|
if (extra < rep->generic.length)
|
|
_XEatData(dpy, (rep->generic.length - extra) << 2);
|
|
}
|
|
#ifdef XTHREADS
|
|
if (dpy->lock) {
|
|
if (discard) {
|
|
dpy->lock->reply_bytes_left = 0;
|
|
} else {
|
|
dpy->lock->reply_bytes_left =
|
|
(rep->generic.length - extra) << 2;
|
|
}
|
|
if (dpy->lock->reply_bytes_left == 0) {
|
|
dpy->flags &= ~XlibDisplayReply;
|
|
UnlockNextReplyReader(dpy);
|
|
}
|
|
} else
|
|
dpy->flags &= ~XlibDisplayReply;
|
|
#endif
|
|
return 1;
|
|
}
|
|
/*
|
|
*if we get here, then extra > rep->generic.length--meaning we
|
|
* read a reply that's shorter than we expected. This is an
|
|
* error, but we still need to figure out how to handle it...
|
|
*/
|
|
(void) _XRead (dpy, (char *) (NEXTPTR(rep,xReply)),
|
|
((long) rep->generic.length) << 2);
|
|
dpy->flags &= ~XlibDisplayReply;
|
|
UnlockNextReplyReader(dpy);
|
|
_XIOError (dpy);
|
|
return (0);
|
|
|
|
case X_Error:
|
|
{
|
|
register _XExtension *ext;
|
|
register Bool ret = False;
|
|
int ret_code;
|
|
xError *err = (xError *) rep;
|
|
unsigned long serial;
|
|
|
|
dpy->flags &= ~XlibDisplayReply;
|
|
serial = _XSetLastRequestRead(dpy, (xGenericReply *)rep);
|
|
if (serial == cur_request)
|
|
/* do not die on "no such font", "can't allocate",
|
|
"can't grab" failures */
|
|
switch ((int)err->errorCode) {
|
|
case BadName:
|
|
switch (err->majorCode) {
|
|
case X_LookupColor:
|
|
case X_AllocNamedColor:
|
|
UnlockNextReplyReader(dpy);
|
|
return(0);
|
|
}
|
|
break;
|
|
case BadFont:
|
|
if (err->majorCode == X_QueryFont) {
|
|
UnlockNextReplyReader(dpy);
|
|
return (0);
|
|
}
|
|
break;
|
|
case BadAlloc:
|
|
case BadAccess:
|
|
UnlockNextReplyReader(dpy);
|
|
return (0);
|
|
}
|
|
/*
|
|
* we better see if there is an extension who may
|
|
* want to suppress the error.
|
|
*/
|
|
for (ext = dpy->ext_procs; !ret && ext; ext = ext->next) {
|
|
if (ext->error)
|
|
ret = (*ext->error)(dpy, err, &ext->codes, &ret_code);
|
|
}
|
|
if (!ret) {
|
|
_XError(dpy, err);
|
|
ret_code = 0;
|
|
}
|
|
if (serial == cur_request) {
|
|
UnlockNextReplyReader(dpy);
|
|
return(ret_code);
|
|
}
|
|
|
|
} /* case X_Error */
|
|
break;
|
|
default:
|
|
_XEnq(dpy, (xEvent *) rep);
|
|
#ifdef XTHREADS
|
|
if (dpy->lock && dpy->lock->event_awaiters)
|
|
ConditionSignal(dpy, dpy->lock->event_awaiters->cv);
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static char *
|
|
_XAsyncReply(
|
|
Display *dpy,
|
|
register xReply *rep,
|
|
char *buf,
|
|
register int *lenp,
|
|
Bool discard)
|
|
{
|
|
register _XAsyncHandler *async, *next;
|
|
register int len;
|
|
register Bool consumed = False;
|
|
char *nbuf;
|
|
|
|
(void) _XSetLastRequestRead(dpy, &rep->generic);
|
|
len = SIZEOF(xReply) + (rep->generic.length << 2);
|
|
if (len < SIZEOF(xReply)) {
|
|
_XIOError (dpy);
|
|
buf += *lenp;
|
|
*lenp = 0;
|
|
return buf;
|
|
}
|
|
|
|
for (async = dpy->async_handlers; async; async = next) {
|
|
next = async->next;
|
|
if ((consumed = (*async->handler)(dpy, rep, buf, *lenp, async->data)))
|
|
break;
|
|
}
|
|
if (!consumed) {
|
|
if (!discard)
|
|
return buf;
|
|
(void) fprintf(stderr,
|
|
"Xlib: unexpected async reply (sequence 0x%lx)!\n",
|
|
dpy->last_request_read);
|
|
#ifdef XTHREADS
|
|
#ifdef XTHREADS_DEBUG
|
|
printf("thread %x, unexpected async reply\n", XThread_Self());
|
|
#endif
|
|
#endif
|
|
if (len > *lenp)
|
|
_XEatData(dpy, len - *lenp);
|
|
}
|
|
if (len < SIZEOF(xReply))
|
|
{
|
|
_XIOError (dpy);
|
|
buf += *lenp;
|
|
*lenp = 0;
|
|
return buf;
|
|
}
|
|
if (len >= *lenp) {
|
|
buf += *lenp;
|
|
*lenp = 0;
|
|
return buf;
|
|
}
|
|
*lenp -= len;
|
|
buf += len;
|
|
len = *lenp;
|
|
nbuf = buf;
|
|
while (len > SIZEOF(xReply)) {
|
|
if (*buf == X_Reply)
|
|
return nbuf;
|
|
buf += SIZEOF(xReply);
|
|
len -= SIZEOF(xReply);
|
|
}
|
|
if (len > 0 && len < SIZEOF(xReply)) {
|
|
buf = nbuf;
|
|
len = SIZEOF(xReply) - len;
|
|
nbuf -= len;
|
|
memmove(nbuf, buf, *lenp);
|
|
(void) _XRead(dpy, nbuf + *lenp, (long)len);
|
|
*lenp += len;
|
|
}
|
|
return nbuf;
|
|
}
|
|
|
|
/*
|
|
* Support for internal connections, such as an IM might use.
|
|
* By Stephen Gildea, X Consortium, September 1993
|
|
*/
|
|
|
|
/* _XRegisterInternalConnection
|
|
* Each IM (or Xlib extension) that opens a file descriptor that Xlib should
|
|
* include in its select/poll mask must call this function to register the
|
|
* fd with Xlib. Any XConnectionWatchProc registered by XAddConnectionWatch
|
|
* will also be called.
|
|
*
|
|
* Whenever Xlib detects input available on fd, it will call callback
|
|
* with call_data to process it. If non-Xlib code calls select/poll
|
|
* and detects input available, it must call XProcessInternalConnection,
|
|
* which will call the associated callback.
|
|
*
|
|
* Non-Xlib code can learn about these additional fds by calling
|
|
* XInternalConnectionNumbers or, more typically, by registering
|
|
* a XConnectionWatchProc with XAddConnectionWatch
|
|
* to be called when fds are registered or unregistered.
|
|
*
|
|
* Returns True if registration succeeded, False if not, typically
|
|
* because could not allocate memory.
|
|
* Assumes Display locked when called.
|
|
*/
|
|
Status
|
|
_XRegisterInternalConnection(
|
|
Display* dpy,
|
|
int fd,
|
|
_XInternalConnectionProc callback,
|
|
XPointer call_data
|
|
)
|
|
{
|
|
struct _XConnectionInfo *new_conni, **iptr;
|
|
struct _XConnWatchInfo *watchers;
|
|
XPointer *wd;
|
|
|
|
new_conni = (struct _XConnectionInfo*)Xmalloc(sizeof(struct _XConnectionInfo));
|
|
if (!new_conni)
|
|
return 0;
|
|
new_conni->watch_data = (XPointer *)Xmalloc(dpy->watcher_count * sizeof(XPointer));
|
|
if (!new_conni->watch_data) {
|
|
Xfree(new_conni);
|
|
return 0;
|
|
}
|
|
new_conni->fd = fd;
|
|
new_conni->read_callback = callback;
|
|
new_conni->call_data = call_data;
|
|
new_conni->next = NULL;
|
|
/* link new structure onto end of list */
|
|
for (iptr = &dpy->im_fd_info; *iptr; iptr = &(*iptr)->next)
|
|
;
|
|
*iptr = new_conni;
|
|
dpy->im_fd_length++;
|
|
_XPollfdCacheAdd(dpy, fd);
|
|
|
|
for (watchers=dpy->conn_watchers, wd=new_conni->watch_data;
|
|
watchers;
|
|
watchers=watchers->next, wd++) {
|
|
*wd = NULL; /* for cleanliness */
|
|
(*watchers->fn) (dpy, watchers->client_data, fd, True, wd);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* _XUnregisterInternalConnection
|
|
* Each IM (or Xlib extension) that closes a file descriptor previously
|
|
* registered with _XRegisterInternalConnection must call this function.
|
|
* Any XConnectionWatchProc registered by XAddConnectionWatch
|
|
* will also be called.
|
|
*
|
|
* Assumes Display locked when called.
|
|
*/
|
|
void
|
|
_XUnregisterInternalConnection(
|
|
Display* dpy,
|
|
int fd
|
|
)
|
|
{
|
|
struct _XConnectionInfo *info_list, **prev;
|
|
struct _XConnWatchInfo *watch;
|
|
XPointer *wd;
|
|
|
|
for (prev = &dpy->im_fd_info; (info_list = *prev);
|
|
prev = &info_list->next) {
|
|
if (info_list->fd == fd) {
|
|
*prev = info_list->next;
|
|
dpy->im_fd_length--;
|
|
for (watch=dpy->conn_watchers, wd=info_list->watch_data;
|
|
watch;
|
|
watch=watch->next, wd++) {
|
|
(*watch->fn) (dpy, watch->client_data, fd, False, wd);
|
|
}
|
|
if (info_list->watch_data)
|
|
Xfree (info_list->watch_data);
|
|
Xfree (info_list);
|
|
break;
|
|
}
|
|
}
|
|
_XPollfdCacheDel(dpy, fd);
|
|
}
|
|
|
|
/* XInternalConnectionNumbers
|
|
* Returns an array of fds and an array of corresponding call data.
|
|
* Typically a XConnectionWatchProc registered with XAddConnectionWatch
|
|
* will be used instead of this function to discover
|
|
* additional fds to include in the select/poll mask.
|
|
*
|
|
* The list is allocated with Xmalloc and should be freed by the caller
|
|
* with Xfree;
|
|
*/
|
|
Status
|
|
XInternalConnectionNumbers(
|
|
Display *dpy,
|
|
int **fd_return,
|
|
int *count_return
|
|
)
|
|
{
|
|
int count;
|
|
struct _XConnectionInfo *info_list;
|
|
int *fd_list;
|
|
|
|
LockDisplay(dpy);
|
|
count = 0;
|
|
for (info_list=dpy->im_fd_info; info_list; info_list=info_list->next)
|
|
count++;
|
|
fd_list = (int*) Xmalloc (count * sizeof(int));
|
|
if (!fd_list) {
|
|
UnlockDisplay(dpy);
|
|
return 0;
|
|
}
|
|
count = 0;
|
|
for (info_list=dpy->im_fd_info; info_list; info_list=info_list->next) {
|
|
fd_list[count] = info_list->fd;
|
|
count++;
|
|
}
|
|
UnlockDisplay(dpy);
|
|
|
|
*fd_return = fd_list;
|
|
*count_return = count;
|
|
return 1;
|
|
}
|
|
|
|
static void _XProcessInternalConnection(
|
|
Display *dpy,
|
|
struct _XConnectionInfo *conn_info)
|
|
{
|
|
dpy->flags |= XlibDisplayProcConni;
|
|
#ifdef XTHREADS
|
|
if (dpy->lock) {
|
|
/* check cache to avoid call to thread_self */
|
|
if (xthread_have_id(dpy->lock->reading_thread))
|
|
dpy->lock->conni_thread = dpy->lock->reading_thread;
|
|
else
|
|
dpy->lock->conni_thread = XThread_Self();
|
|
}
|
|
#endif /* XTHREADS */
|
|
UnlockDisplay(dpy);
|
|
(*conn_info->read_callback) (dpy, conn_info->fd, conn_info->call_data);
|
|
LockDisplay(dpy);
|
|
#ifdef XTHREADS
|
|
if (dpy->lock)
|
|
xthread_clear_id(dpy->lock->conni_thread);
|
|
#endif /* XTHREADS */
|
|
dpy->flags &= ~XlibDisplayProcConni;
|
|
}
|
|
|
|
/* XProcessInternalConnection
|
|
* Call the _XInternalConnectionProc registered by _XRegisterInternalConnection
|
|
* for this fd.
|
|
* The Display is NOT locked during the call.
|
|
*/
|
|
void
|
|
XProcessInternalConnection(
|
|
Display* dpy,
|
|
int fd
|
|
)
|
|
{
|
|
struct _XConnectionInfo *info_list;
|
|
|
|
LockDisplay(dpy);
|
|
for (info_list=dpy->im_fd_info; info_list; info_list=info_list->next) {
|
|
if (info_list->fd == fd) {
|
|
_XProcessInternalConnection(dpy, info_list);
|
|
break;
|
|
}
|
|
}
|
|
UnlockDisplay(dpy);
|
|
}
|
|
|
|
/* XAddConnectionWatch
|
|
* Register a callback to be called whenever _XRegisterInternalConnection
|
|
* or _XUnregisterInternalConnection is called.
|
|
* Callbacks are called with the Display locked.
|
|
* If any connections are already registered, the callback is immediately
|
|
* called for each of them.
|
|
*/
|
|
Status
|
|
XAddConnectionWatch(
|
|
Display* dpy,
|
|
XConnectionWatchProc callback,
|
|
XPointer client_data
|
|
)
|
|
{
|
|
struct _XConnWatchInfo *new_watcher, **wptr;
|
|
struct _XConnectionInfo *info_list;
|
|
XPointer *wd_array;
|
|
|
|
LockDisplay(dpy);
|
|
|
|
/* allocate new watch data */
|
|
for (info_list=dpy->im_fd_info; info_list; info_list=info_list->next) {
|
|
wd_array = (XPointer *)Xrealloc((char *)info_list->watch_data,
|
|
(dpy->watcher_count + 1) *
|
|
sizeof(XPointer));
|
|
if (!wd_array) {
|
|
UnlockDisplay(dpy);
|
|
return 0;
|
|
}
|
|
wd_array[dpy->watcher_count] = NULL; /* for cleanliness */
|
|
}
|
|
|
|
new_watcher = (struct _XConnWatchInfo*)Xmalloc(sizeof(struct _XConnWatchInfo));
|
|
if (!new_watcher) {
|
|
UnlockDisplay(dpy);
|
|
return 0;
|
|
}
|
|
new_watcher->fn = callback;
|
|
new_watcher->client_data = client_data;
|
|
new_watcher->next = NULL;
|
|
|
|
/* link new structure onto end of list */
|
|
for (wptr = &dpy->conn_watchers; *wptr; wptr = &(*wptr)->next)
|
|
;
|
|
*wptr = new_watcher;
|
|
dpy->watcher_count++;
|
|
|
|
/* call new watcher on all currently registered fds */
|
|
for (info_list=dpy->im_fd_info; info_list; info_list=info_list->next) {
|
|
(*callback) (dpy, client_data, info_list->fd, True,
|
|
info_list->watch_data + dpy->watcher_count - 1);
|
|
}
|
|
|
|
UnlockDisplay(dpy);
|
|
return 1;
|
|
}
|
|
|
|
/* XRemoveConnectionWatch
|
|
* Unregister a callback registered by XAddConnectionWatch.
|
|
* Both callback and client_data must match what was passed to
|
|
* XAddConnectionWatch.
|
|
*/
|
|
void
|
|
XRemoveConnectionWatch(
|
|
Display* dpy,
|
|
XConnectionWatchProc callback,
|
|
XPointer client_data
|
|
)
|
|
{
|
|
struct _XConnWatchInfo *watch;
|
|
struct _XConnWatchInfo *previous = NULL;
|
|
struct _XConnectionInfo *conni;
|
|
int counter = 0;
|
|
|
|
LockDisplay(dpy);
|
|
for (watch=dpy->conn_watchers; watch; watch=watch->next) {
|
|
if (watch->fn == callback && watch->client_data == client_data) {
|
|
if (previous)
|
|
previous->next = watch->next;
|
|
else
|
|
dpy->conn_watchers = watch->next;
|
|
Xfree (watch);
|
|
dpy->watcher_count--;
|
|
/* remove our watch_data for each connection */
|
|
for (conni=dpy->im_fd_info; conni; conni=conni->next) {
|
|
/* don't bother realloc'ing; these arrays are small anyway */
|
|
/* overlapping */
|
|
memmove(conni->watch_data+counter,
|
|
conni->watch_data+counter+1,
|
|
dpy->watcher_count - counter);
|
|
}
|
|
break;
|
|
}
|
|
previous = watch;
|
|
counter++;
|
|
}
|
|
UnlockDisplay(dpy);
|
|
}
|
|
|
|
/* end of internal connections support */
|
|
|
|
|
|
/* Read and discard "n" 8-bit bytes of data */
|
|
|
|
void _XEatData(
|
|
Display *dpy,
|
|
register unsigned long n)
|
|
{
|
|
#define SCRATCHSIZE 2048
|
|
char buf[SCRATCHSIZE];
|
|
|
|
while (n > 0) {
|
|
register long bytes_read = (n > SCRATCHSIZE) ? SCRATCHSIZE : n;
|
|
(void) _XRead (dpy, buf, bytes_read);
|
|
n -= bytes_read;
|
|
}
|
|
#undef SCRATCHSIZE
|
|
}
|
|
|
|
|
|
/*
|
|
* _XEnq - Place event packets on the display's queue.
|
|
* note that no squishing of move events in V11, since there
|
|
* is pointer motion hints....
|
|
*/
|
|
void _XEnq(
|
|
register Display *dpy,
|
|
register xEvent *event)
|
|
{
|
|
register _XQEvent *qelt;
|
|
|
|
if ((qelt = dpy->qfree)) {
|
|
/* If dpy->qfree is non-NULL do this, else malloc a new one. */
|
|
dpy->qfree = qelt->next;
|
|
}
|
|
else if ((qelt =
|
|
(_XQEvent *) Xmalloc((unsigned)sizeof(_XQEvent))) == NULL) {
|
|
/* Malloc call failed! */
|
|
ESET(ENOMEM);
|
|
_XIOError(dpy);
|
|
}
|
|
qelt->next = NULL;
|
|
/* go call through display to find proper event reformatter */
|
|
if ((*dpy->event_vec[event->u.u.type & 0177])(dpy, &qelt->event, event)) {
|
|
qelt->qserial_num = dpy->next_event_serial_num++;
|
|
if (dpy->tail) dpy->tail->next = qelt;
|
|
else dpy->head = qelt;
|
|
|
|
dpy->tail = qelt;
|
|
dpy->qlen++;
|
|
} else {
|
|
/* ignored, or stashed away for many-to-one compression */
|
|
qelt->next = dpy->qfree;
|
|
dpy->qfree = qelt;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* _XDeq - Remove event packet from the display's queue.
|
|
*/
|
|
void _XDeq(
|
|
register Display *dpy,
|
|
register _XQEvent *prev, /* element before qelt */
|
|
register _XQEvent *qelt) /* element to be unlinked */
|
|
{
|
|
if (prev) {
|
|
if ((prev->next = qelt->next) == NULL)
|
|
dpy->tail = prev;
|
|
} else {
|
|
/* no prev, so removing first elt */
|
|
if ((dpy->head = qelt->next) == NULL)
|
|
dpy->tail = NULL;
|
|
}
|
|
qelt->qserial_num = 0;
|
|
qelt->next = dpy->qfree;
|
|
dpy->qfree = qelt;
|
|
dpy->qlen--;
|
|
}
|
|
|
|
/*
|
|
* EventToWire in separate file in that often not needed.
|
|
*/
|
|
|
|
/*ARGSUSED*/
|
|
Bool
|
|
_XUnknownWireEvent(
|
|
register Display *dpy, /* pointer to display structure */
|
|
register XEvent *re, /* pointer to where event should be reformatted */
|
|
register xEvent *event) /* wire protocol event */
|
|
{
|
|
#ifdef notdef
|
|
(void) fprintf(stderr,
|
|
"Xlib: unhandled wire event! event number = %d, display = %x\n.",
|
|
event->u.u.type, dpy);
|
|
#endif
|
|
return(False);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
Status
|
|
_XUnknownNativeEvent(
|
|
register Display *dpy, /* pointer to display structure */
|
|
register XEvent *re, /* pointer to where event should be reformatted */
|
|
register xEvent *event) /* wire protocol event */
|
|
{
|
|
#ifdef notdef
|
|
(void) fprintf(stderr,
|
|
"Xlib: unhandled native event! event number = %d, display = %x\n.",
|
|
re->type, dpy);
|
|
#endif
|
|
return(0);
|
|
}
|
|
/*
|
|
* reformat a wire event into an XEvent structure of the right type.
|
|
*/
|
|
Bool
|
|
_XWireToEvent(
|
|
register Display *dpy, /* pointer to display structure */
|
|
register XEvent *re, /* pointer to where event should be reformatted */
|
|
register xEvent *event) /* wire protocol event */
|
|
{
|
|
|
|
re->type = event->u.u.type & 0x7f;
|
|
((XAnyEvent *)re)->serial = _XSetLastRequestRead(dpy,
|
|
(xGenericReply *)event);
|
|
((XAnyEvent *)re)->send_event = ((event->u.u.type & 0x80) != 0);
|
|
((XAnyEvent *)re)->display = dpy;
|
|
|
|
/* Ignore the leading bit of the event type since it is set when a
|
|
client sends an event rather than the server. */
|
|
|
|
switch (event-> u.u.type & 0177) {
|
|
case KeyPress:
|
|
case KeyRelease:
|
|
{
|
|
register XKeyEvent *ev = (XKeyEvent*) re;
|
|
ev->root = event->u.keyButtonPointer.root;
|
|
ev->window = event->u.keyButtonPointer.event;
|
|
ev->subwindow = event->u.keyButtonPointer.child;
|
|
ev->time = event->u.keyButtonPointer.time;
|
|
ev->x = cvtINT16toInt(event->u.keyButtonPointer.eventX);
|
|
ev->y = cvtINT16toInt(event->u.keyButtonPointer.eventY);
|
|
ev->x_root = cvtINT16toInt(event->u.keyButtonPointer.rootX);
|
|
ev->y_root = cvtINT16toInt(event->u.keyButtonPointer.rootY);
|
|
ev->state = event->u.keyButtonPointer.state;
|
|
ev->same_screen = event->u.keyButtonPointer.sameScreen;
|
|
ev->keycode = event->u.u.detail;
|
|
}
|
|
break;
|
|
case ButtonPress:
|
|
case ButtonRelease:
|
|
{
|
|
register XButtonEvent *ev = (XButtonEvent *) re;
|
|
ev->root = event->u.keyButtonPointer.root;
|
|
ev->window = event->u.keyButtonPointer.event;
|
|
ev->subwindow = event->u.keyButtonPointer.child;
|
|
ev->time = event->u.keyButtonPointer.time;
|
|
ev->x = cvtINT16toInt(event->u.keyButtonPointer.eventX);
|
|
ev->y = cvtINT16toInt(event->u.keyButtonPointer.eventY);
|
|
ev->x_root = cvtINT16toInt(event->u.keyButtonPointer.rootX);
|
|
ev->y_root = cvtINT16toInt(event->u.keyButtonPointer.rootY);
|
|
ev->state = event->u.keyButtonPointer.state;
|
|
ev->same_screen = event->u.keyButtonPointer.sameScreen;
|
|
ev->button = event->u.u.detail;
|
|
}
|
|
break;
|
|
case MotionNotify:
|
|
{
|
|
register XMotionEvent *ev = (XMotionEvent *)re;
|
|
ev->root = event->u.keyButtonPointer.root;
|
|
ev->window = event->u.keyButtonPointer.event;
|
|
ev->subwindow = event->u.keyButtonPointer.child;
|
|
ev->time = event->u.keyButtonPointer.time;
|
|
ev->x = cvtINT16toInt(event->u.keyButtonPointer.eventX);
|
|
ev->y = cvtINT16toInt(event->u.keyButtonPointer.eventY);
|
|
ev->x_root = cvtINT16toInt(event->u.keyButtonPointer.rootX);
|
|
ev->y_root = cvtINT16toInt(event->u.keyButtonPointer.rootY);
|
|
ev->state = event->u.keyButtonPointer.state;
|
|
ev->same_screen = event->u.keyButtonPointer.sameScreen;
|
|
ev->is_hint = event->u.u.detail;
|
|
}
|
|
break;
|
|
case EnterNotify:
|
|
case LeaveNotify:
|
|
{
|
|
register XCrossingEvent *ev = (XCrossingEvent *) re;
|
|
ev->root = event->u.enterLeave.root;
|
|
ev->window = event->u.enterLeave.event;
|
|
ev->subwindow = event->u.enterLeave.child;
|
|
ev->time = event->u.enterLeave.time;
|
|
ev->x = cvtINT16toInt(event->u.enterLeave.eventX);
|
|
ev->y = cvtINT16toInt(event->u.enterLeave.eventY);
|
|
ev->x_root = cvtINT16toInt(event->u.enterLeave.rootX);
|
|
ev->y_root = cvtINT16toInt(event->u.enterLeave.rootY);
|
|
ev->state = event->u.enterLeave.state;
|
|
ev->mode = event->u.enterLeave.mode;
|
|
ev->same_screen = (event->u.enterLeave.flags &
|
|
ELFlagSameScreen) && True;
|
|
ev->focus = (event->u.enterLeave.flags &
|
|
ELFlagFocus) && True;
|
|
ev->detail = event->u.u.detail;
|
|
}
|
|
break;
|
|
case FocusIn:
|
|
case FocusOut:
|
|
{
|
|
register XFocusChangeEvent *ev = (XFocusChangeEvent *) re;
|
|
ev->window = event->u.focus.window;
|
|
ev->mode = event->u.focus.mode;
|
|
ev->detail = event->u.u.detail;
|
|
}
|
|
break;
|
|
case KeymapNotify:
|
|
{
|
|
register XKeymapEvent *ev = (XKeymapEvent *) re;
|
|
ev->window = None;
|
|
memcpy(&ev->key_vector[1],
|
|
(char *)((xKeymapEvent *) event)->map,
|
|
sizeof (((xKeymapEvent *) event)->map));
|
|
}
|
|
break;
|
|
case Expose:
|
|
{
|
|
register XExposeEvent *ev = (XExposeEvent *) re;
|
|
ev->window = event->u.expose.window;
|
|
ev->x = event->u.expose.x;
|
|
ev->y = event->u.expose.y;
|
|
ev->width = event->u.expose.width;
|
|
ev->height = event->u.expose.height;
|
|
ev->count = event->u.expose.count;
|
|
}
|
|
break;
|
|
case GraphicsExpose:
|
|
{
|
|
register XGraphicsExposeEvent *ev =
|
|
(XGraphicsExposeEvent *) re;
|
|
ev->drawable = event->u.graphicsExposure.drawable;
|
|
ev->x = event->u.graphicsExposure.x;
|
|
ev->y = event->u.graphicsExposure.y;
|
|
ev->width = event->u.graphicsExposure.width;
|
|
ev->height = event->u.graphicsExposure.height;
|
|
ev->count = event->u.graphicsExposure.count;
|
|
ev->major_code = event->u.graphicsExposure.majorEvent;
|
|
ev->minor_code = event->u.graphicsExposure.minorEvent;
|
|
}
|
|
break;
|
|
case NoExpose:
|
|
{
|
|
register XNoExposeEvent *ev = (XNoExposeEvent *) re;
|
|
ev->drawable = event->u.noExposure.drawable;
|
|
ev->major_code = event->u.noExposure.majorEvent;
|
|
ev->minor_code = event->u.noExposure.minorEvent;
|
|
}
|
|
break;
|
|
case VisibilityNotify:
|
|
{
|
|
register XVisibilityEvent *ev = (XVisibilityEvent *) re;
|
|
ev->window = event->u.visibility.window;
|
|
ev->state = event->u.visibility.state;
|
|
}
|
|
break;
|
|
case CreateNotify:
|
|
{
|
|
register XCreateWindowEvent *ev =
|
|
(XCreateWindowEvent *) re;
|
|
ev->window = event->u.createNotify.window;
|
|
ev->parent = event->u.createNotify.parent;
|
|
ev->x = cvtINT16toInt(event->u.createNotify.x);
|
|
ev->y = cvtINT16toInt(event->u.createNotify.y);
|
|
ev->width = event->u.createNotify.width;
|
|
ev->height = event->u.createNotify.height;
|
|
ev->border_width = event->u.createNotify.borderWidth;
|
|
ev->override_redirect = event->u.createNotify.override;
|
|
}
|
|
break;
|
|
case DestroyNotify:
|
|
{
|
|
register XDestroyWindowEvent *ev =
|
|
(XDestroyWindowEvent *) re;
|
|
ev->window = event->u.destroyNotify.window;
|
|
ev->event = event->u.destroyNotify.event;
|
|
}
|
|
break;
|
|
case UnmapNotify:
|
|
{
|
|
register XUnmapEvent *ev = (XUnmapEvent *) re;
|
|
ev->window = event->u.unmapNotify.window;
|
|
ev->event = event->u.unmapNotify.event;
|
|
ev->from_configure = event->u.unmapNotify.fromConfigure;
|
|
}
|
|
break;
|
|
case MapNotify:
|
|
{
|
|
register XMapEvent *ev = (XMapEvent *) re;
|
|
ev->window = event->u.mapNotify.window;
|
|
ev->event = event->u.mapNotify.event;
|
|
ev->override_redirect = event->u.mapNotify.override;
|
|
}
|
|
break;
|
|
case MapRequest:
|
|
{
|
|
register XMapRequestEvent *ev = (XMapRequestEvent *) re;
|
|
ev->window = event->u.mapRequest.window;
|
|
ev->parent = event->u.mapRequest.parent;
|
|
}
|
|
break;
|
|
case ReparentNotify:
|
|
{
|
|
register XReparentEvent *ev = (XReparentEvent *) re;
|
|
ev->event = event->u.reparent.event;
|
|
ev->window = event->u.reparent.window;
|
|
ev->parent = event->u.reparent.parent;
|
|
ev->x = cvtINT16toInt(event->u.reparent.x);
|
|
ev->y = cvtINT16toInt(event->u.reparent.y);
|
|
ev->override_redirect = event->u.reparent.override;
|
|
}
|
|
break;
|
|
case ConfigureNotify:
|
|
{
|
|
register XConfigureEvent *ev = (XConfigureEvent *) re;
|
|
ev->event = event->u.configureNotify.event;
|
|
ev->window = event->u.configureNotify.window;
|
|
ev->above = event->u.configureNotify.aboveSibling;
|
|
ev->x = cvtINT16toInt(event->u.configureNotify.x);
|
|
ev->y = cvtINT16toInt(event->u.configureNotify.y);
|
|
ev->width = event->u.configureNotify.width;
|
|
ev->height = event->u.configureNotify.height;
|
|
ev->border_width = event->u.configureNotify.borderWidth;
|
|
ev->override_redirect = event->u.configureNotify.override;
|
|
}
|
|
break;
|
|
case ConfigureRequest:
|
|
{
|
|
register XConfigureRequestEvent *ev =
|
|
(XConfigureRequestEvent *) re;
|
|
ev->window = event->u.configureRequest.window;
|
|
ev->parent = event->u.configureRequest.parent;
|
|
ev->above = event->u.configureRequest.sibling;
|
|
ev->x = cvtINT16toInt(event->u.configureRequest.x);
|
|
ev->y = cvtINT16toInt(event->u.configureRequest.y);
|
|
ev->width = event->u.configureRequest.width;
|
|
ev->height = event->u.configureRequest.height;
|
|
ev->border_width = event->u.configureRequest.borderWidth;
|
|
ev->value_mask = event->u.configureRequest.valueMask;
|
|
ev->detail = event->u.u.detail;
|
|
}
|
|
break;
|
|
case GravityNotify:
|
|
{
|
|
register XGravityEvent *ev = (XGravityEvent *) re;
|
|
ev->window = event->u.gravity.window;
|
|
ev->event = event->u.gravity.event;
|
|
ev->x = cvtINT16toInt(event->u.gravity.x);
|
|
ev->y = cvtINT16toInt(event->u.gravity.y);
|
|
}
|
|
break;
|
|
case ResizeRequest:
|
|
{
|
|
register XResizeRequestEvent *ev =
|
|
(XResizeRequestEvent *) re;
|
|
ev->window = event->u.resizeRequest.window;
|
|
ev->width = event->u.resizeRequest.width;
|
|
ev->height = event->u.resizeRequest.height;
|
|
}
|
|
break;
|
|
case CirculateNotify:
|
|
{
|
|
register XCirculateEvent *ev = (XCirculateEvent *) re;
|
|
ev->window = event->u.circulate.window;
|
|
ev->event = event->u.circulate.event;
|
|
ev->place = event->u.circulate.place;
|
|
}
|
|
break;
|
|
case CirculateRequest:
|
|
{
|
|
register XCirculateRequestEvent *ev =
|
|
(XCirculateRequestEvent *) re;
|
|
ev->window = event->u.circulate.window;
|
|
ev->parent = event->u.circulate.event;
|
|
ev->place = event->u.circulate.place;
|
|
}
|
|
break;
|
|
case PropertyNotify:
|
|
{
|
|
register XPropertyEvent *ev = (XPropertyEvent *) re;
|
|
ev->window = event->u.property.window;
|
|
ev->atom = event->u.property.atom;
|
|
ev->time = event->u.property.time;
|
|
ev->state = event->u.property.state;
|
|
}
|
|
break;
|
|
case SelectionClear:
|
|
{
|
|
register XSelectionClearEvent *ev =
|
|
(XSelectionClearEvent *) re;
|
|
ev->window = event->u.selectionClear.window;
|
|
ev->selection = event->u.selectionClear.atom;
|
|
ev->time = event->u.selectionClear.time;
|
|
}
|
|
break;
|
|
case SelectionRequest:
|
|
{
|
|
register XSelectionRequestEvent *ev =
|
|
(XSelectionRequestEvent *) re;
|
|
ev->owner = event->u.selectionRequest.owner;
|
|
ev->requestor = event->u.selectionRequest.requestor;
|
|
ev->selection = event->u.selectionRequest.selection;
|
|
ev->target = event->u.selectionRequest.target;
|
|
ev->property = event->u.selectionRequest.property;
|
|
ev->time = event->u.selectionRequest.time;
|
|
}
|
|
break;
|
|
case SelectionNotify:
|
|
{
|
|
register XSelectionEvent *ev = (XSelectionEvent *) re;
|
|
ev->requestor = event->u.selectionNotify.requestor;
|
|
ev->selection = event->u.selectionNotify.selection;
|
|
ev->target = event->u.selectionNotify.target;
|
|
ev->property = event->u.selectionNotify.property;
|
|
ev->time = event->u.selectionNotify.time;
|
|
}
|
|
break;
|
|
case ColormapNotify:
|
|
{
|
|
register XColormapEvent *ev = (XColormapEvent *) re;
|
|
ev->window = event->u.colormap.window;
|
|
ev->colormap = event->u.colormap.colormap;
|
|
ev->new = event->u.colormap.new;
|
|
ev->state = event->u.colormap.state;
|
|
}
|
|
break;
|
|
case ClientMessage:
|
|
{
|
|
register int i;
|
|
register XClientMessageEvent *ev
|
|
= (XClientMessageEvent *) re;
|
|
ev->window = event->u.clientMessage.window;
|
|
ev->format = event->u.u.detail;
|
|
switch (ev->format) {
|
|
case 8:
|
|
ev->message_type = event->u.clientMessage.u.b.type;
|
|
for (i = 0; i < 20; i++)
|
|
ev->data.b[i] = event->u.clientMessage.u.b.bytes[i];
|
|
break;
|
|
case 16:
|
|
ev->message_type = event->u.clientMessage.u.s.type;
|
|
ev->data.s[0] = cvtINT16toShort(event->u.clientMessage.u.s.shorts0);
|
|
ev->data.s[1] = cvtINT16toShort(event->u.clientMessage.u.s.shorts1);
|
|
ev->data.s[2] = cvtINT16toShort(event->u.clientMessage.u.s.shorts2);
|
|
ev->data.s[3] = cvtINT16toShort(event->u.clientMessage.u.s.shorts3);
|
|
ev->data.s[4] = cvtINT16toShort(event->u.clientMessage.u.s.shorts4);
|
|
ev->data.s[5] = cvtINT16toShort(event->u.clientMessage.u.s.shorts5);
|
|
ev->data.s[6] = cvtINT16toShort(event->u.clientMessage.u.s.shorts6);
|
|
ev->data.s[7] = cvtINT16toShort(event->u.clientMessage.u.s.shorts7);
|
|
ev->data.s[8] = cvtINT16toShort(event->u.clientMessage.u.s.shorts8);
|
|
ev->data.s[9] = cvtINT16toShort(event->u.clientMessage.u.s.shorts9);
|
|
break;
|
|
case 32:
|
|
ev->message_type = event->u.clientMessage.u.l.type;
|
|
ev->data.l[0] = cvtINT32toLong(event->u.clientMessage.u.l.longs0);
|
|
ev->data.l[1] = cvtINT32toLong(event->u.clientMessage.u.l.longs1);
|
|
ev->data.l[2] = cvtINT32toLong(event->u.clientMessage.u.l.longs2);
|
|
ev->data.l[3] = cvtINT32toLong(event->u.clientMessage.u.l.longs3);
|
|
ev->data.l[4] = cvtINT32toLong(event->u.clientMessage.u.l.longs4);
|
|
break;
|
|
default: /* XXX should never occur */
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case MappingNotify:
|
|
{
|
|
register XMappingEvent *ev = (XMappingEvent *)re;
|
|
ev->window = 0;
|
|
ev->first_keycode = event->u.mappingNotify.firstKeyCode;
|
|
ev->request = event->u.mappingNotify.request;
|
|
ev->count = event->u.mappingNotify.count;
|
|
}
|
|
break;
|
|
default:
|
|
return(_XUnknownWireEvent(dpy, re, event));
|
|
}
|
|
return(True);
|
|
}
|
|
|
|
|
|
/*
|
|
* _XDefaultIOError - Default fatal system error reporting routine. Called
|
|
* when an X internal system error is encountered.
|
|
*/
|
|
int _XDefaultIOError(
|
|
Display *dpy)
|
|
{
|
|
if (ECHECK(EPIPE)) {
|
|
(void) fprintf (stderr,
|
|
"X connection to %s broken (explicit kill or server shutdown).\r\n",
|
|
DisplayString (dpy));
|
|
} else {
|
|
(void) fprintf (stderr,
|
|
"XIO: fatal IO error %d (%s) on X server \"%s\"\r\n",
|
|
#ifdef WIN32
|
|
WSAGetLastError(), strerror(WSAGetLastError()),
|
|
#else
|
|
errno, strerror (errno),
|
|
#endif
|
|
DisplayString (dpy));
|
|
(void) fprintf (stderr,
|
|
" after %lu requests (%lu known processed) with %d events remaining.\r\n",
|
|
NextRequest(dpy) - 1, LastKnownRequestProcessed(dpy),
|
|
QLength(dpy));
|
|
|
|
}
|
|
exit(1);
|
|
return(0); /* dummy - function should never return */
|
|
}
|
|
|
|
|
|
static int _XPrintDefaultError(
|
|
Display *dpy,
|
|
XErrorEvent *event,
|
|
FILE *fp)
|
|
{
|
|
char buffer[BUFSIZ];
|
|
char mesg[BUFSIZ];
|
|
char number[32];
|
|
char *mtype = "XlibMessage";
|
|
register _XExtension *ext = (_XExtension *)NULL;
|
|
_XExtension *bext = (_XExtension *)NULL;
|
|
XGetErrorText(dpy, event->error_code, buffer, BUFSIZ);
|
|
XGetErrorDatabaseText(dpy, mtype, "XError", "X Error", mesg, BUFSIZ);
|
|
(void) fprintf(fp, "%s: %s\n ", mesg, buffer);
|
|
XGetErrorDatabaseText(dpy, mtype, "MajorCode", "Request Major code %d",
|
|
mesg, BUFSIZ);
|
|
(void) fprintf(fp, mesg, event->request_code);
|
|
if (event->request_code < 128) {
|
|
sprintf(number, "%d", event->request_code);
|
|
XGetErrorDatabaseText(dpy, "XRequest", number, "", buffer, BUFSIZ);
|
|
} else {
|
|
for (ext = dpy->ext_procs;
|
|
ext && (ext->codes.major_opcode != event->request_code);
|
|
ext = ext->next)
|
|
;
|
|
if (ext)
|
|
strcpy(buffer, ext->name);
|
|
else
|
|
buffer[0] = '\0';
|
|
}
|
|
(void) fprintf(fp, " (%s)\n", buffer);
|
|
if (event->request_code >= 128) {
|
|
XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code %d",
|
|
mesg, BUFSIZ);
|
|
fputs(" ", fp);
|
|
(void) fprintf(fp, mesg, event->minor_code);
|
|
if (ext) {
|
|
sprintf(mesg, "%s.%d", ext->name, event->minor_code);
|
|
XGetErrorDatabaseText(dpy, "XRequest", mesg, "", buffer, BUFSIZ);
|
|
(void) fprintf(fp, " (%s)", buffer);
|
|
}
|
|
fputs("\n", fp);
|
|
}
|
|
if (event->error_code >= 128) {
|
|
/* kludge, try to find the extension that caused it */
|
|
buffer[0] = '\0';
|
|
for (ext = dpy->ext_procs; ext; ext = ext->next) {
|
|
if (ext->error_string)
|
|
(*ext->error_string)(dpy, event->error_code, &ext->codes,
|
|
buffer, BUFSIZ);
|
|
if (buffer[0]) {
|
|
bext = ext;
|
|
break;
|
|
}
|
|
if (ext->codes.first_error &&
|
|
ext->codes.first_error < (int)event->error_code &&
|
|
(!bext || ext->codes.first_error > bext->codes.first_error))
|
|
bext = ext;
|
|
}
|
|
if (bext)
|
|
sprintf(buffer, "%s.%d", bext->name,
|
|
event->error_code - bext->codes.first_error);
|
|
else
|
|
strcpy(buffer, "Value");
|
|
XGetErrorDatabaseText(dpy, mtype, buffer, "", mesg, BUFSIZ);
|
|
if (mesg[0]) {
|
|
fputs(" ", fp);
|
|
(void) fprintf(fp, mesg, event->resourceid);
|
|
fputs("\n", fp);
|
|
}
|
|
/* let extensions try to print the values */
|
|
for (ext = dpy->ext_procs; ext; ext = ext->next) {
|
|
if (ext->error_values)
|
|
(*ext->error_values)(dpy, event, fp);
|
|
}
|
|
} else if ((event->error_code == BadWindow) ||
|
|
(event->error_code == BadPixmap) ||
|
|
(event->error_code == BadCursor) ||
|
|
(event->error_code == BadFont) ||
|
|
(event->error_code == BadDrawable) ||
|
|
(event->error_code == BadColor) ||
|
|
(event->error_code == BadGC) ||
|
|
(event->error_code == BadIDChoice) ||
|
|
(event->error_code == BadValue) ||
|
|
(event->error_code == BadAtom)) {
|
|
if (event->error_code == BadValue)
|
|
XGetErrorDatabaseText(dpy, mtype, "Value", "Value 0x%x",
|
|
mesg, BUFSIZ);
|
|
else if (event->error_code == BadAtom)
|
|
XGetErrorDatabaseText(dpy, mtype, "AtomID", "AtomID 0x%x",
|
|
mesg, BUFSIZ);
|
|
else
|
|
XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x",
|
|
mesg, BUFSIZ);
|
|
fputs(" ", fp);
|
|
(void) fprintf(fp, mesg, event->resourceid);
|
|
fputs("\n", fp);
|
|
}
|
|
XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d",
|
|
mesg, BUFSIZ);
|
|
fputs(" ", fp);
|
|
(void) fprintf(fp, mesg, event->serial);
|
|
XGetErrorDatabaseText(dpy, mtype, "CurrentSerial", "Current Serial #%d",
|
|
mesg, BUFSIZ);
|
|
fputs("\n ", fp);
|
|
(void) fprintf(fp, mesg, dpy->request);
|
|
fputs("\n", fp);
|
|
if (event->error_code == BadImplementation) return 0;
|
|
return 1;
|
|
}
|
|
|
|
int _XDefaultError(
|
|
Display *dpy,
|
|
XErrorEvent *event)
|
|
{
|
|
if (_XPrintDefaultError (dpy, event, stderr) == 0) return 0;
|
|
exit(1);
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
Bool _XDefaultWireError(display, he, we)
|
|
Display *display;
|
|
XErrorEvent *he;
|
|
xError *we;
|
|
{
|
|
return True;
|
|
}
|
|
|
|
/*
|
|
* _XError - upcall internal or user protocol error handler
|
|
*/
|
|
int _XError (
|
|
Display *dpy,
|
|
register xError *rep)
|
|
{
|
|
/*
|
|
* X_Error packet encountered! We need to unpack the error before
|
|
* giving it to the user.
|
|
*/
|
|
XEvent event; /* make it a large event */
|
|
register _XAsyncHandler *async, *next;
|
|
|
|
event.xerror.serial = _XSetLastRequestRead(dpy, (xGenericReply *)rep);
|
|
|
|
for (async = dpy->async_handlers; async; async = next) {
|
|
next = async->next;
|
|
if ((*async->handler)(dpy, (xReply *)rep,
|
|
(char *)rep, SIZEOF(xError), async->data))
|
|
return 0;
|
|
}
|
|
|
|
event.xerror.display = dpy;
|
|
event.xerror.type = X_Error;
|
|
event.xerror.resourceid = rep->resourceID;
|
|
event.xerror.error_code = rep->errorCode;
|
|
event.xerror.request_code = rep->majorCode;
|
|
event.xerror.minor_code = rep->minorCode;
|
|
if (dpy->error_vec &&
|
|
!(*dpy->error_vec[rep->errorCode])(dpy, &event.xerror, rep))
|
|
return 0;
|
|
if (_XErrorFunction != NULL) {
|
|
int rtn_val;
|
|
#ifdef XTHREADS
|
|
if (dpy->lock)
|
|
(*dpy->lock->user_lock_display)(dpy);
|
|
UnlockDisplay(dpy);
|
|
#endif /* XTHREADS */
|
|
rtn_val = (*_XErrorFunction)(dpy, (XErrorEvent *)&event); /* upcall */
|
|
#ifdef XTHREADS
|
|
LockDisplay(dpy);
|
|
if (dpy->lock)
|
|
(*dpy->lock->user_unlock_display)(dpy);
|
|
#endif /* XTHREADS */
|
|
return rtn_val;
|
|
} else {
|
|
return _XDefaultError(dpy, (XErrorEvent *)&event);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* _XIOError - call user connection error handler and exit
|
|
*/
|
|
int
|
|
_XIOError (
|
|
Display *dpy)
|
|
{
|
|
dpy->flags |= XlibDisplayIOError;
|
|
#ifdef WIN32
|
|
errno = WSAGetLastError();
|
|
#endif
|
|
|
|
if (_XIOErrorFunction != NULL)
|
|
(*_XIOErrorFunction)(dpy);
|
|
else
|
|
_XDefaultIOError(dpy);
|
|
exit (1);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* This routine can be used to (cheaply) get some memory within a single
|
|
* Xlib routine for scratch space. A single buffer is reused each time
|
|
* if possible. To be MT safe, you can only call this between a call to
|
|
* GetReq* and a call to Data* or _XSend*, or in a context when the thread
|
|
* is guaranteed to not unlock the display.
|
|
*/
|
|
char *_XAllocScratch(
|
|
register Display *dpy,
|
|
unsigned long nbytes)
|
|
{
|
|
if (nbytes > dpy->scratch_length) {
|
|
if (dpy->scratch_buffer) Xfree (dpy->scratch_buffer);
|
|
if ((dpy->scratch_buffer = Xmalloc((unsigned) nbytes)))
|
|
dpy->scratch_length = nbytes;
|
|
else dpy->scratch_length = 0;
|
|
}
|
|
return (dpy->scratch_buffer);
|
|
}
|
|
|
|
/*
|
|
* Scratch space allocator you can call any time, multiple times, and be
|
|
* MT safe, but you must hand the buffer back with _XFreeTemp.
|
|
*/
|
|
char *_XAllocTemp(
|
|
register Display *dpy,
|
|
unsigned long nbytes)
|
|
{
|
|
char *buf;
|
|
|
|
buf = _XAllocScratch(dpy, nbytes);
|
|
dpy->scratch_buffer = NULL;
|
|
dpy->scratch_length = 0;
|
|
return buf;
|
|
}
|
|
|
|
void _XFreeTemp(
|
|
register Display *dpy,
|
|
char *buf,
|
|
unsigned long nbytes)
|
|
{
|
|
if (dpy->scratch_buffer)
|
|
Xfree(dpy->scratch_buffer);
|
|
dpy->scratch_buffer = buf;
|
|
dpy->scratch_length = nbytes;
|
|
}
|
|
|
|
/*
|
|
* Given a visual id, find the visual structure for this id on this display.
|
|
*/
|
|
Visual *_XVIDtoVisual(
|
|
Display *dpy,
|
|
VisualID id)
|
|
{
|
|
register int i, j, k;
|
|
register Screen *sp;
|
|
register Depth *dp;
|
|
register Visual *vp;
|
|
for (i = 0; i < dpy->nscreens; i++) {
|
|
sp = &dpy->screens[i];
|
|
for (j = 0; j < sp->ndepths; j++) {
|
|
dp = &sp->depths[j];
|
|
/* if nvisuals == 0 then visuals will be NULL */
|
|
for (k = 0; k < dp->nvisuals; k++) {
|
|
vp = &dp->visuals[k];
|
|
if (vp->visualid == id) return (vp);
|
|
}
|
|
}
|
|
}
|
|
return (NULL);
|
|
}
|
|
|
|
int
|
|
XFree (void *data)
|
|
{
|
|
Xfree (data);
|
|
return 1;
|
|
}
|
|
|
|
#ifdef _XNEEDBCOPYFUNC
|
|
void _Xbcopy(b1, b2, length)
|
|
register char *b1, *b2;
|
|
register length;
|
|
{
|
|
if (b1 < b2) {
|
|
b2 += length;
|
|
b1 += length;
|
|
while (length--)
|
|
*--b2 = *--b1;
|
|
} else {
|
|
while (length--)
|
|
*b2++ = *b1++;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef DataRoutineIsProcedure
|
|
void Data(
|
|
Display *dpy,
|
|
char *data,
|
|
long len)
|
|
{
|
|
if (dpy->bufptr + (len) <= dpy->bufmax) {
|
|
memcpy(dpy->bufptr, data, (int)len);
|
|
dpy->bufptr += ((len) + 3) & ~3;
|
|
} else {
|
|
_XSend(dpy, data, len);
|
|
}
|
|
}
|
|
#endif /* DataRoutineIsProcedure */
|
|
|
|
|
|
#ifdef LONG64
|
|
int
|
|
_XData32(
|
|
Display *dpy,
|
|
register long *data,
|
|
unsigned len)
|
|
{
|
|
register int *buf;
|
|
register long i;
|
|
|
|
while (len) {
|
|
buf = (int *)dpy->bufptr;
|
|
i = dpy->bufmax - (char *)buf;
|
|
if (!i) {
|
|
_XFlush(dpy);
|
|
continue;
|
|
}
|
|
if (len < i)
|
|
i = len;
|
|
dpy->bufptr = (char *)buf + i;
|
|
len -= i;
|
|
i >>= 2;
|
|
while (--i >= 0)
|
|
*buf++ = *data++;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif /* LONG64 */
|
|
|
|
#ifdef WORD64
|
|
|
|
/*
|
|
* XXX This is a *really* stupid way of doing this. It should just use
|
|
* dpy->bufptr directly, taking into account where in the word it is.
|
|
*/
|
|
|
|
/*
|
|
* Data16 - Place 16 bit data in the buffer.
|
|
*
|
|
* "dpy" is a pointer to a Display.
|
|
* "data" is a pointer to the data.
|
|
* "len" is the length in bytes of the data.
|
|
*/
|
|
|
|
static doData16(
|
|
register Display *dpy,
|
|
short *data,
|
|
unsigned len,
|
|
char *packbuffer)
|
|
{
|
|
long *lp,*lpack;
|
|
long i, nwords,bits;
|
|
long mask16 = 0x000000000000ffff;
|
|
|
|
lp = (long *)data;
|
|
lpack = (long *)packbuffer;
|
|
|
|
/* nwords is the number of 16 bit values to be packed,
|
|
* the low order 16 bits of each word will be packed
|
|
* into 64 bit words
|
|
*/
|
|
nwords = len >> 1;
|
|
bits = 48;
|
|
|
|
for(i=0;i<nwords;i++){
|
|
if (bits == 48) *lpack = 0;
|
|
*lpack ^= (*lp & mask16) << bits;
|
|
bits -= 16 ;
|
|
lp++;
|
|
if(bits < 0){
|
|
lpack++;
|
|
bits = 48;
|
|
}
|
|
}
|
|
Data(dpy, packbuffer, len);
|
|
}
|
|
|
|
_XData16 (
|
|
Display *dpy,
|
|
short *data,
|
|
unsigned len)
|
|
{
|
|
char packbuffer[PACKBUFFERSIZE];
|
|
unsigned nunits = PACKBUFFERSIZE >> 1;
|
|
|
|
for (; len > PACKBUFFERSIZE; len -= PACKBUFFERSIZE, data += nunits) {
|
|
doData16 (dpy, data, PACKBUFFERSIZE, packbuffer);
|
|
}
|
|
if (len) doData16 (dpy, data, len, packbuffer);
|
|
}
|
|
|
|
/*
|
|
* Data32 - Place 32 bit data in the buffer.
|
|
*
|
|
* "dpy" is a pointer to a Display.
|
|
* "data" is a pointer to the data.
|
|
* "len" is the length in bytes of the data.
|
|
*/
|
|
|
|
static doData32(
|
|
register Display *dpy
|
|
long *data,
|
|
unsigned len,
|
|
char *packbuffer)
|
|
{
|
|
long *lp,*lpack;
|
|
long i,bits,nwords;
|
|
long mask32 = 0x00000000ffffffff;
|
|
|
|
lpack = (long *) packbuffer;
|
|
lp = data;
|
|
|
|
/* nwords is the number of 32 bit values to be packed
|
|
* the low order 32 bits of each word will be packed
|
|
* into 64 bit words
|
|
*/
|
|
nwords = len >> 2;
|
|
bits = 32;
|
|
|
|
for(i=0;i<nwords;i++){
|
|
if (bits == 32) *lpack = 0;
|
|
*lpack ^= (*lp & mask32) << bits;
|
|
bits = bits ^32;
|
|
lp++;
|
|
if(bits)
|
|
lpack++;
|
|
}
|
|
Data(dpy, packbuffer, len);
|
|
}
|
|
|
|
void _XData32(
|
|
Display *dpy,
|
|
long *data,
|
|
unsigned len,
|
|
{
|
|
char packbuffer[PACKBUFFERSIZE];
|
|
unsigned nunits = PACKBUFFERSIZE >> 2;
|
|
|
|
for (; len > PACKBUFFERSIZE; len -= PACKBUFFERSIZE, data += nunits) {
|
|
doData32 (dpy, data, PACKBUFFERSIZE, packbuffer);
|
|
}
|
|
if (len) doData32 (dpy, data, len, packbuffer);
|
|
}
|
|
|
|
#endif /* WORD64 */
|
|
|
|
|
|
/* Make sure this produces the same string as DefineLocal/DefineSelf in xdm.
|
|
* Otherwise, Xau will not be able to find your cookies in the Xauthority file.
|
|
*
|
|
* Note: POSIX says that the ``nodename'' member of utsname does _not_ have
|
|
* to have sufficient information for interfacing to the network,
|
|
* and so, you may be better off using gethostname (if it exists).
|
|
*/
|
|
|
|
#if (defined(_POSIX_SOURCE) && !defined(AIXV3) && !defined(__QNX__)) || defined(hpux) || defined(USG) || defined(SVR4)
|
|
#define NEED_UTSNAME
|
|
#include <sys/utsname.h>
|
|
#endif
|
|
|
|
/*
|
|
* _XGetHostname - similar to gethostname but allows special processing.
|
|
*/
|
|
int _XGetHostname (
|
|
char *buf,
|
|
int maxlen)
|
|
{
|
|
int len;
|
|
|
|
#ifdef NEED_UTSNAME
|
|
struct utsname name;
|
|
|
|
if (maxlen <= 0 || buf == NULL)
|
|
return 0;
|
|
|
|
uname (&name);
|
|
len = strlen (name.nodename);
|
|
if (len >= maxlen) len = maxlen - 1;
|
|
strncpy (buf, name.nodename, len);
|
|
buf[len] = '\0';
|
|
#else
|
|
if (maxlen <= 0 || buf == NULL)
|
|
return 0;
|
|
|
|
buf[0] = '\0';
|
|
(void) gethostname (buf, maxlen);
|
|
buf [maxlen - 1] = '\0';
|
|
len = strlen(buf);
|
|
#endif /* NEED_UTSNAME */
|
|
return len;
|
|
}
|
|
|
|
|
|
/*
|
|
* _XScreenOfWindow - get the Screen of a given window
|
|
*/
|
|
|
|
Screen *_XScreenOfWindow (dpy, w)
|
|
Display *dpy;
|
|
Window w;
|
|
{
|
|
register int i;
|
|
Window root;
|
|
int x, y; /* dummy variables */
|
|
unsigned int width, height, bw, depth; /* dummy variables */
|
|
|
|
if (XGetGeometry (dpy, w, &root, &x, &y, &width, &height,
|
|
&bw, &depth) == False) {
|
|
return None;
|
|
}
|
|
for (i = 0; i < ScreenCount (dpy); i++) { /* find root from list */
|
|
if (root == RootWindow (dpy, i)) {
|
|
return ScreenOfDisplay (dpy, i);
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
#if defined(WIN32)
|
|
|
|
/*
|
|
* These functions are intended to be used internally to Xlib only.
|
|
* These functions will always prefix the path with a DOS drive in the
|
|
* form "<drive-letter>:". As such, these functions are only suitable
|
|
* for use by Xlib function that supply a root-based path to some
|
|
* particular file, e.g. <ProjectRoot>/lib/X11/locale/locale.dir will
|
|
* be converted to "C:/usr/X11R6.3/lib/X11/locale/locale.dir".
|
|
*/
|
|
|
|
static int access_file (path, pathbuf, len_pathbuf, pathret)
|
|
char* path;
|
|
char* pathbuf;
|
|
int len_pathbuf;
|
|
char** pathret;
|
|
{
|
|
if (access (path, F_OK) == 0) {
|
|
if (strlen (path) < len_pathbuf)
|
|
*pathret = pathbuf;
|
|
else
|
|
*pathret = Xmalloc (strlen (path) + 1);
|
|
if (*pathret) {
|
|
strcpy (*pathret, path);
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int AccessFile (path, pathbuf, len_pathbuf, pathret)
|
|
char* path;
|
|
char* pathbuf;
|
|
int len_pathbuf;
|
|
char** pathret;
|
|
{
|
|
unsigned long drives;
|
|
int i, len;
|
|
char* drive;
|
|
char buf[MAX_PATH];
|
|
char* bufp;
|
|
|
|
/* just try the "raw" name first and see if it works */
|
|
if (access_file (path, pathbuf, len_pathbuf, pathret))
|
|
return 1;
|
|
|
|
/* try the places set in the environment */
|
|
drive = getenv ("_XBASEDRIVE");
|
|
#ifdef __UNIXOS2__
|
|
if (!drive)
|
|
drive = getenv ("X11ROOT");
|
|
#endif
|
|
if (!drive)
|
|
drive = "C:";
|
|
len = strlen (drive) + strlen (path);
|
|
if (len < MAX_PATH) bufp = buf;
|
|
else bufp = Xmalloc (len + 1);
|
|
strcpy (bufp, drive);
|
|
strcat (bufp, path);
|
|
if (access_file (bufp, pathbuf, len_pathbuf, pathret)) {
|
|
if (bufp != buf) Xfree (bufp);
|
|
return 1;
|
|
}
|
|
|
|
#ifndef __UNIXOS2__
|
|
/* one last place to look */
|
|
drive = getenv ("HOMEDRIVE");
|
|
if (drive) {
|
|
len = strlen (drive) + strlen (path);
|
|
if (len < MAX_PATH) bufp = buf;
|
|
else bufp = Xmalloc (len + 1);
|
|
strcpy (bufp, drive);
|
|
strcat (bufp, path);
|
|
if (access_file (bufp, pathbuf, len_pathbuf, pathret)) {
|
|
if (bufp != buf) Xfree (bufp);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/* tried everywhere else, go fishing */
|
|
#define C_DRIVE ('C' - 'A')
|
|
#define Z_DRIVE ('Z' - 'A')
|
|
/* does OS/2 (with or with gcc-emx) have getdrives? */
|
|
drives = _getdrives ();
|
|
for (i = C_DRIVE; i <= Z_DRIVE; i++) { /* don't check on A: or B: */
|
|
if ((1 << i) & drives) {
|
|
len = 2 + strlen (path);
|
|
if (len < MAX_PATH) bufp = buf;
|
|
else bufp = Xmalloc (len + 1);
|
|
*bufp = 'A' + i;
|
|
*(bufp + 1) = ':';
|
|
*(bufp + 2) = '\0';
|
|
strcat (bufp, path);
|
|
if (access_file (bufp, pathbuf, len_pathbuf, pathret)) {
|
|
if (bufp != buf) Xfree (bufp);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
int _XOpenFile(path, flags)
|
|
_Xconst char* path;
|
|
int flags;
|
|
{
|
|
char buf[MAX_PATH];
|
|
char* bufp;
|
|
int ret = -1;
|
|
UINT olderror = SetErrorMode (SEM_FAILCRITICALERRORS);
|
|
|
|
if (AccessFile (path, buf, MAX_PATH, &bufp))
|
|
ret = open (bufp, flags);
|
|
|
|
(void) SetErrorMode (olderror);
|
|
|
|
if (bufp != buf) Xfree (bufp);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void* _XFopenFile(path, mode)
|
|
_Xconst char* path;
|
|
_Xconst char* mode;
|
|
{
|
|
char buf[MAX_PATH];
|
|
char* bufp;
|
|
void* ret = NULL;
|
|
UINT olderror = SetErrorMode (SEM_FAILCRITICALERRORS);
|
|
|
|
if (AccessFile (path, buf, MAX_PATH, &bufp))
|
|
ret = fopen (bufp, mode);
|
|
|
|
(void) SetErrorMode (olderror);
|
|
|
|
if (bufp != buf) Xfree (bufp);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int _XAccessFile(path)
|
|
_Xconst char* path;
|
|
{
|
|
char buf[MAX_PATH];
|
|
char* bufp;
|
|
int ret = -1;
|
|
UINT olderror = SetErrorMode (SEM_FAILCRITICALERRORS);
|
|
|
|
ret = AccessFile (path, buf, MAX_PATH, &bufp);
|
|
|
|
(void) SetErrorMode (olderror);
|
|
|
|
if (bufp != buf) Xfree (bufp);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif
|
|
|