mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-27 14:12:25 +00:00
da80415f55
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@525 fc73d0e0-1445-4013-8a0c-d673dee63da5
1845 lines
41 KiB
C
1845 lines
41 KiB
C
//network interface
|
|
|
|
#include "bothdefs.h"
|
|
|
|
#ifndef NOMEDIA
|
|
|
|
#include "qux.h"
|
|
|
|
#ifdef _WIN32
|
|
#define EWOULDBLOCK WSAEWOULDBLOCK
|
|
#define EMSGSIZE WSAEMSGSIZE
|
|
#define ECONNRESET WSAECONNRESET
|
|
#define ECONNABORTED WSAECONNABORTED
|
|
#define ECONNREFUSED WSAECONNREFUSED
|
|
#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
|
|
|
|
#define qerrno WSAGetLastError()
|
|
#else
|
|
|
|
|
|
#define qerrno errno
|
|
|
|
#define MSG_PARTIAL 0
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <netdb.h>
|
|
#include <sys/param.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/uio.h>
|
|
#include <arpa/inet.h>
|
|
#include <errno.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#define closesocket close
|
|
#define ioctlsocket ioctl
|
|
#endif
|
|
|
|
#undef malloc
|
|
#undef free
|
|
|
|
#define free BZ_Free
|
|
#define malloc BZ_Malloc
|
|
#define realloc BZ_Realloc
|
|
|
|
static xclient_t *xclients;
|
|
static int xlistensocket=-1;
|
|
|
|
xwindow_t *xfocusedwindow;
|
|
|
|
qboolean xrefreshed;
|
|
|
|
xclient_t *xgrabbedclient; //clients can ask the server to ignore other clients
|
|
|
|
#define MAXREQUESTSIZE 65535
|
|
|
|
|
|
void X_SendData(xclient_t *cl, void *data, int datalen)
|
|
{
|
|
#ifdef MULTITHREADWIN32
|
|
if (cl->threadhandle)
|
|
EnterCriticalSection(&cl->delecatesection);
|
|
#endif
|
|
|
|
if (cl->outbufferlen + datalen > cl->outbuffermaxlen)
|
|
{ //extend buffer size
|
|
cl->outbuffermaxlen = cl->outbufferlen + datalen + 1024;
|
|
cl->outbuffer = realloc(cl->outbuffer, cl->outbuffermaxlen);
|
|
}
|
|
|
|
memcpy(cl->outbuffer+cl->outbufferlen, data, datalen);
|
|
cl->outbufferlen += datalen;
|
|
|
|
#ifdef MULTITHREADWIN32
|
|
if (cl->threadhandle)
|
|
LeaveCriticalSection(&cl->delecatesection);
|
|
#endif
|
|
}
|
|
|
|
void X_SendNotification(xEvent *data)
|
|
{
|
|
xclient_t *cl;
|
|
for (cl = xclients; cl; cl = cl->nextclient)
|
|
{
|
|
if (cl->stillinitialising)
|
|
continue;
|
|
if (cl->tobedropped)
|
|
continue;
|
|
if (cl->outbufferlen > MAXREQUESTSIZE*4)
|
|
continue;
|
|
|
|
data->u.u.sequenceNumber = cl->requestnum;
|
|
X_SendData(cl, data, sizeof(xEvent));
|
|
}
|
|
}
|
|
|
|
|
|
qboolean X_NotifcationMaskPresent(xwindow_t *window, int mask, xclient_t *notfor)
|
|
{
|
|
xnotificationmask_t *nm;
|
|
nm = window->notificationmask;
|
|
|
|
if (mask == SubstructureNotifyMask || mask == SubstructureRedirectMask)
|
|
{
|
|
window = window->parent;
|
|
// for(;window;window=window->parent)
|
|
{
|
|
for (nm = window->notificationmask; nm; nm = nm->next)
|
|
{
|
|
if (nm->mask & mask)
|
|
if (nm->client != notfor)
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
for (nm = window->notificationmask; nm; nm = nm->next)
|
|
{
|
|
if (nm->mask & mask)
|
|
if (nm->client != notfor)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int X_SendNotificationMasked(xEvent *data, xwindow_t *window, unsigned int mask)
|
|
{
|
|
int count=0;
|
|
xclient_t *cl;
|
|
xnotificationmask_t *nm;
|
|
|
|
xwindow_t *child = window;
|
|
|
|
if (mask == SubstructureNotifyMask || mask == SubstructureRedirectMask)
|
|
{
|
|
for (cl = xclients; cl; cl = cl->nextclient)
|
|
{
|
|
//don't send to if...
|
|
if (cl->stillinitialising)
|
|
continue;
|
|
if (cl->tobedropped)
|
|
continue;
|
|
if (cl->outbufferlen > MAXREQUESTSIZE*4)
|
|
{
|
|
cl->tobedropped = true;
|
|
continue;
|
|
}
|
|
window = child->parent;
|
|
|
|
// for (window = child; window; window = window->parent)
|
|
{
|
|
for (nm = window->notificationmask; nm; nm = nm->next)
|
|
{
|
|
if (nm->client != cl)
|
|
continue;
|
|
if (!(nm->mask & mask))
|
|
continue;
|
|
|
|
data->u.reparent.event = window->res.id; //so the request/notification/whatever knows who asked for it.
|
|
|
|
data->u.u.sequenceNumber = cl->requestnum;
|
|
X_SendData(cl, data, sizeof(xEvent));
|
|
count++;
|
|
break;
|
|
}
|
|
// if (nm)
|
|
// break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (nm = window->notificationmask; nm; nm = nm->next)
|
|
{
|
|
if (!(nm->mask & mask))
|
|
continue;
|
|
cl = nm->client;
|
|
|
|
if (cl->stillinitialising)
|
|
continue;
|
|
if (cl->tobedropped)
|
|
continue;
|
|
if (cl->outbufferlen > MAXREQUESTSIZE*4)
|
|
{
|
|
cl->tobedropped = true;
|
|
continue;
|
|
}
|
|
|
|
data->u.u.sequenceNumber = cl->requestnum;
|
|
X_SendData(cl, data, sizeof(xEvent));
|
|
count++;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
int X_SendInputNotification(xEvent *data, xwindow_t *window, unsigned int mask)
|
|
{
|
|
int count=0;
|
|
xclient_t *cl;
|
|
xnotificationmask_t *nm;
|
|
|
|
xwindow_t *child = window;
|
|
xwindow_t *focus;
|
|
|
|
//we go all the way to the root if needed.
|
|
|
|
for (cl = xclients; cl; cl = cl->nextclient)
|
|
{
|
|
//don't send to if...
|
|
if (cl->stillinitialising)
|
|
continue;
|
|
if (cl->tobedropped)
|
|
continue;
|
|
if (cl->outbufferlen > MAXREQUESTSIZE*4)
|
|
{
|
|
cl->tobedropped = true;
|
|
continue;
|
|
}
|
|
window = child->parent;
|
|
|
|
for (window = child; window; window = window->parent)
|
|
{
|
|
for (nm = window->notificationmask; nm; nm = nm->next)
|
|
{
|
|
if (nm->client != cl)
|
|
continue;
|
|
if (!(nm->mask & mask))
|
|
continue;
|
|
|
|
Con_Printf("Sending input %i\n", data->u.u.type);
|
|
|
|
if (data->u.u.type == FocusIn || data->u.u.type == FocusOut)
|
|
{
|
|
data->u.u.sequenceNumber = cl->requestnum;
|
|
X_SendData(cl, data, sizeof(xEvent));
|
|
count++;
|
|
break;
|
|
}
|
|
|
|
data->u.keyButtonPointer.event = window->res.id; //so the request/notification/whatever knows who asked for it.
|
|
data->u.keyButtonPointer.eventX = data->u.keyButtonPointer.rootX;
|
|
data->u.keyButtonPointer.eventY = data->u.keyButtonPointer.rootY;
|
|
for (window = window; window; window = window->parent) //adjust event's xpos/ypos
|
|
{
|
|
data->u.keyButtonPointer.eventX -= window->xpos;
|
|
data->u.keyButtonPointer.eventY -= window->ypos;
|
|
}
|
|
|
|
if (data->u.u.type == EnterNotify || data->u.u.type == LeaveNotify)
|
|
{
|
|
data->u.enterLeave.flags &= ~ELFlagFocus;
|
|
|
|
focus = xfocusedwindow;
|
|
while(focus)
|
|
{
|
|
if (focus->res.id == data->u.enterLeave.event)
|
|
{
|
|
data->u.enterLeave.flags |= ELFlagFocus;
|
|
break;
|
|
}
|
|
focus = focus->parent;
|
|
}
|
|
}
|
|
|
|
data->u.u.sequenceNumber = cl->requestnum;
|
|
if (data->u.keyButtonPointer.event == data->u.keyButtonPointer.child)
|
|
{
|
|
data->u.keyButtonPointer.child = None;
|
|
X_SendData(cl, data, sizeof(xEvent));
|
|
data->u.keyButtonPointer.child = data->u.keyButtonPointer.event;
|
|
}
|
|
else
|
|
X_SendData(cl, data, sizeof(xEvent));
|
|
count++;
|
|
break;
|
|
}
|
|
if (nm || (window->donotpropagate & mask))
|
|
break;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
void X_SendError(xclient_t *cl, int errorcode, int assocresource, int major, int minor)
|
|
{
|
|
xError err;
|
|
err.type = X_Error;
|
|
err.errorCode = errorcode;
|
|
err.sequenceNumber = cl->requestnum; /* the nth request from this client */
|
|
err.resourceID = assocresource;
|
|
err.minorCode = minor;
|
|
err.majorCode = major;
|
|
err.pad1 = 0;
|
|
err.pad3 = 0;
|
|
err.pad4 = 0;
|
|
err.pad5 = 0;
|
|
err.pad6 = 0;
|
|
err.pad7 = 0;
|
|
|
|
X_SendData(cl, &err, sizeof(err));
|
|
}
|
|
|
|
int X_NewRIDBase(void)
|
|
{
|
|
xclient_t *cl;
|
|
int ridbase = 0x200000;
|
|
while(ridbase) //it'll wrap at some point...
|
|
{
|
|
for (cl = xclients; cl; cl = cl->nextclient)
|
|
{
|
|
if (cl->ridbase == ridbase) //someone has this range...
|
|
{
|
|
ridbase+=0x200000;
|
|
break;
|
|
}
|
|
}
|
|
if (!cl)
|
|
return ridbase;
|
|
}
|
|
|
|
//err... bugger... that could be problematic...
|
|
//try again, but start allocating half quantities and hope a client drops soon...
|
|
|
|
ridbase = 0x200000;
|
|
while(ridbase)
|
|
{
|
|
for (cl = xclients; cl; cl = cl->nextclient)
|
|
{
|
|
if (cl->ridbase == ridbase) //someone has this range...
|
|
{
|
|
ridbase+=0x100000;
|
|
break;;
|
|
}
|
|
}
|
|
if (!cl)
|
|
return ridbase;
|
|
}
|
|
|
|
if (ridbase)
|
|
return ridbase;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void X_SendIntialResponse(xclient_t *cl)
|
|
{
|
|
int rid;
|
|
char buffer[8192];
|
|
xConnSetupPrefix *prefix;
|
|
xConnSetup *setup;
|
|
char *vendor;
|
|
xPixmapFormat *pixmapformats;
|
|
xnotificationmask_t *nm;
|
|
|
|
xWindowRoot *root;
|
|
xDepth *depth;
|
|
xVisualType *visualtype;
|
|
|
|
rid = X_NewRIDBase();
|
|
cl->ridbase = rid;
|
|
|
|
if (!rid)
|
|
{
|
|
prefix = (xConnSetupPrefix *)buffer;
|
|
prefix->success = 0;
|
|
prefix->lengthReason = 22;
|
|
prefix->majorVersion = 11; //protocol version.
|
|
prefix->minorVersion = 0;
|
|
prefix->length = (prefix->lengthReason/4+3)&~3;
|
|
strcpy((char *)(prefix+1), "No free resource range");
|
|
X_SendData(cl, prefix, sizeof(prefix)+(prefix->length+1)*4);
|
|
cl->tobedropped = true;
|
|
}
|
|
else
|
|
{
|
|
prefix = (xConnSetupPrefix *)buffer;
|
|
prefix->success = 1;
|
|
prefix->lengthReason = 0;
|
|
prefix->majorVersion = 11; //protocol version.
|
|
prefix->minorVersion = 0;
|
|
|
|
setup = (xConnSetup *)(prefix+1);
|
|
setup->release = build_number(); //our version number
|
|
setup->ridBase = rid;
|
|
setup->ridMask = 0x1fffff;
|
|
setup->motionBufferSize = 1;
|
|
setup->maxRequestSize = MAXREQUESTSIZE;
|
|
setup->numRoots = 1; //we only have one display. so only one root window please.
|
|
setup->imageByteOrder = LSBFirst; /* LSBFirst, MSBFirst */
|
|
setup->bitmapBitOrder = LSBFirst; /* LeastSignificant, MostSign...*/
|
|
setup->bitmapScanlineUnit = 32, /* 8, 16, 32 */
|
|
setup->bitmapScanlinePad = 32; /* 8, 16, 32 */
|
|
setup->minKeyCode = 1;
|
|
setup->maxKeyCode = 255;
|
|
|
|
vendor = (char *)(setup+1);
|
|
strcpy(vendor, "FTE QuakeWorld X");
|
|
setup->nbytesVendor = (strlen(vendor)+3)&~3;
|
|
|
|
pixmapformats = (xPixmapFormat *)(vendor + setup->nbytesVendor);
|
|
setup->numFormats = 0;
|
|
|
|
/* pixmapformats[setup->numFormats].depth = 16;
|
|
pixmapformats[setup->numFormats].bitsPerPixel = 16;
|
|
pixmapformats[setup->numFormats].scanLinePad = 16;
|
|
pixmapformats[setup->numFormats].pad1=0;
|
|
pixmapformats[setup->numFormats].pad2=0;
|
|
setup->numFormats++;*/
|
|
|
|
pixmapformats[setup->numFormats].depth = 24;
|
|
pixmapformats[setup->numFormats].bitsPerPixel = 32;
|
|
pixmapformats[setup->numFormats].scanLinePad = 32;
|
|
pixmapformats[setup->numFormats].pad1=0;
|
|
pixmapformats[setup->numFormats].pad2=0;
|
|
setup->numFormats++;
|
|
|
|
root = (xWindowRoot *)(pixmapformats + setup->numFormats);
|
|
root->windowId = rootwindow->res.id;
|
|
root->defaultColormap = 32;
|
|
root->whitePixel = 0xffffff;
|
|
root->blackPixel = 0;
|
|
root->currentInputMask = 0;
|
|
for (nm = rootwindow->notificationmask; nm; nm = nm->next)
|
|
root->currentInputMask |= nm->mask;
|
|
root->pixWidth = rootwindow->width;
|
|
root->pixHeight = rootwindow->height;
|
|
root->mmWidth = rootwindow->width/3;
|
|
root->mmHeight = rootwindow->height/3;
|
|
root->minInstalledMaps = 1;
|
|
root->maxInstalledMaps = 1;
|
|
root->rootVisualID = 0x22;
|
|
root->backingStore = 0;
|
|
root->saveUnders = false;
|
|
root->rootDepth = 24;
|
|
root->nDepths = 0;
|
|
|
|
depth = (xDepth*)(root + 1);
|
|
depth->depth = 24;
|
|
depth->pad1 = 0;
|
|
depth->nVisuals = 1;
|
|
depth->pad2 = 0;
|
|
root->nDepths++;
|
|
|
|
visualtype = (xVisualType*)(depth+1);
|
|
visualtype->visualID = root->rootVisualID;
|
|
visualtype->class = TrueColor;
|
|
visualtype->bitsPerRGB = 24;
|
|
visualtype->colormapEntries = 256;
|
|
visualtype->redMask = 0x0000ff;
|
|
visualtype->greenMask = 0x00ff00;
|
|
visualtype->blueMask = 0xff0000;
|
|
visualtype->pad = 0;
|
|
|
|
visualtype++;
|
|
prefix->length = ((char *)visualtype - (char *)setup)/4;
|
|
|
|
X_SendData(cl, prefix, (char *)visualtype - (char *)prefix);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
qboolean XWindows_TendToClient(xclient_t *cl) //true says drop
|
|
{
|
|
int err;
|
|
int len;
|
|
unsigned int inlen;
|
|
char *input;
|
|
|
|
if (!xgrabbedclient || xgrabbedclient == cl) //someone grabbed the server
|
|
if (cl->outbufferlen < 256 && !cl->tobedropped) //don't accept new messages if we still have a lot to write.
|
|
{
|
|
#ifdef MULTITHREADWIN32
|
|
if (!cl->threadhandle)
|
|
#endif
|
|
{
|
|
if (cl->inbuffermaxlen - cl->inbufferlen < 1000) //do we need to expand this message?
|
|
{
|
|
char *newbuffer;
|
|
cl->inbuffermaxlen += 1000;
|
|
newbuffer = malloc(cl->inbuffermaxlen);
|
|
if (cl->inbuffer)
|
|
{
|
|
memcpy(newbuffer, cl->inbuffer, cl->inbufferlen);
|
|
free(cl->inbuffer);
|
|
}
|
|
cl->inbuffer = newbuffer;
|
|
}
|
|
len = cl->inbuffermaxlen - cl->inbufferlen;
|
|
Con_Printf("recving\n");
|
|
len = recv(cl->socket, cl->inbuffer + cl->inbufferlen, len, 0);
|
|
Con_Printf("recved %i\n", len);
|
|
if (len == 0) //connection was closed. bummer.
|
|
{
|
|
Con_Printf("Closed\n");
|
|
return true;
|
|
}
|
|
if (len > 0)
|
|
{
|
|
cl->inbufferlen += len;
|
|
}
|
|
else
|
|
{
|
|
err = qerrno;
|
|
if (err != EWOULDBLOCK)
|
|
{
|
|
Con_Printf("X read error %i\n", err);
|
|
cl->tobedropped = true;
|
|
}
|
|
}
|
|
}
|
|
#ifdef MULTITHREADWIN32
|
|
else
|
|
EnterCriticalSection(&cl->delecatesection);
|
|
#endif
|
|
|
|
// if (len > 0) //the correct version
|
|
if (cl->inbufferlen > 0) //temp
|
|
{
|
|
input = cl->inbuffer;
|
|
nextmessage:
|
|
inlen = cl->inbufferlen - (input - cl->inbuffer);
|
|
if (cl->stillinitialising)
|
|
{
|
|
if (inlen >= sizeof(xConnClientPrefix))
|
|
{
|
|
xConnClientPrefix *prefix = (xConnClientPrefix *)input;
|
|
input += sizeof(xConnClientPrefix);
|
|
cl->stillinitialising = false;
|
|
if (prefix->byteOrder != 'l') //egad no. horrible.
|
|
{
|
|
#ifdef MULTITHREADWIN32
|
|
LeaveCriticalSection(&cl->delecatesection);
|
|
#endif
|
|
return true;
|
|
}
|
|
if (prefix->majorVersion != 11) //x11 only. Sorry.
|
|
{
|
|
#ifdef MULTITHREADWIN32
|
|
LeaveCriticalSection(&cl->delecatesection);
|
|
#endif
|
|
return true;
|
|
}
|
|
if (prefix->minorVersion != 0) //we don't know of any variations.
|
|
{
|
|
#ifdef MULTITHREADWIN32
|
|
LeaveCriticalSection(&cl->delecatesection);
|
|
#endif
|
|
return true;
|
|
}
|
|
if (prefix->nbytesAuthProto != 0) //we can't handle this
|
|
{
|
|
#ifdef MULTITHREADWIN32
|
|
LeaveCriticalSection(&cl->delecatesection);
|
|
#endif
|
|
return true;
|
|
}
|
|
if (prefix->nbytesAuthString != 0) //we can't handle this
|
|
{
|
|
#ifdef MULTITHREADWIN32
|
|
LeaveCriticalSection(&cl->delecatesection);
|
|
#endif
|
|
return true;
|
|
}
|
|
X_SendIntialResponse(cl);
|
|
goto nextmessage;
|
|
}
|
|
}
|
|
else if (inlen >= sizeof(xReq))
|
|
{
|
|
int rlen;
|
|
xReq *req;
|
|
req = (xReq *)input;
|
|
|
|
rlen = req->length;
|
|
if (!rlen && inlen >= sizeof(xReq)+sizeof(CARD32)) //BIG-REQUESTS says that if the length of a request is 0, then there's an extra 32bit int with the correct length imediatly after the 0.
|
|
rlen = *(CARD32 *)(req+1);
|
|
if (rlen && inlen >= rlen*4)
|
|
{
|
|
cl->requestnum++;
|
|
|
|
if (/*req->reqType < 0 || req->reqType >= 256 ||*/ !XRequests[req->reqType])
|
|
{
|
|
// Con_Printf("X request %i, len %i - NOT SUPPORTED\n", req->reqType, rlen*4);
|
|
|
|
//this is a minimal implementation...
|
|
X_SendError(cl, BadImplementation, 0, req->reqType, 0);
|
|
// cl->tobedropped = true;
|
|
}
|
|
else
|
|
{
|
|
// Con_Printf("X request %i, len %i\n", req->reqType, rlen*4);
|
|
|
|
//Con_Printf("Request %i\n", req->reqType);
|
|
// Z_CheckSentinals();
|
|
XS_CheckResourceSentinals();
|
|
if (!req->length)
|
|
{
|
|
int rt, data;
|
|
|
|
rt = req->reqType; //save these off
|
|
data = req->data;
|
|
|
|
req = (xReq *)((char *)req+sizeof(CARD32)); //adjust correctly.
|
|
|
|
req->reqType = rt; //and restore them into the space taken by the longer size.
|
|
req->data = data;
|
|
req->length = 0; //Don't rely on this. This isn't really needed.
|
|
|
|
XRequests[req->reqType](cl, req);
|
|
}
|
|
else
|
|
XRequests[req->reqType](cl, req);
|
|
XS_CheckResourceSentinals();
|
|
// Z_CheckSentinals();
|
|
//Con_Printf("Done request\n");
|
|
}
|
|
|
|
input += rlen*4;
|
|
|
|
goto nextmessage;
|
|
}
|
|
}
|
|
|
|
len = input - cl->inbuffer;
|
|
memmove(cl->inbuffer, input, cl->inbufferlen - len);
|
|
cl->inbufferlen -= len;
|
|
}
|
|
#ifdef MULTITHREADWIN32
|
|
if (cl->threadhandle)
|
|
LeaveCriticalSection(&cl->delecatesection);
|
|
#endif
|
|
}
|
|
|
|
if (cl->outbufferlen) //still send if grabbed. don't let things build up this side.
|
|
{
|
|
#ifdef MULTITHREADWIN32
|
|
if (!cl->threadhandle)
|
|
#endif
|
|
{
|
|
len = cl->outbufferlen;
|
|
if (len > 8000)
|
|
len = 8000;
|
|
len = send(cl->socket, cl->outbuffer, len, 0);
|
|
if (len>0)
|
|
{
|
|
memmove(cl->outbuffer, cl->outbuffer+len, cl->outbufferlen - len);
|
|
cl->outbufferlen -= len;
|
|
}
|
|
if (len == 0)
|
|
cl->tobedropped = true;
|
|
if (len < 0)
|
|
{
|
|
err = qerrno;
|
|
if (err != EWOULDBLOCK)
|
|
{
|
|
Con_Printf("X send error %i\n", err);
|
|
cl->tobedropped = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ((!xgrabbedclient || xgrabbedclient == cl) && cl->tobedropped)
|
|
return true; //grabbed servers do not allow altering state if a client drops
|
|
return false;
|
|
}
|
|
|
|
#ifdef MULTITHREAD
|
|
|
|
#ifdef _WIN32
|
|
DWORD WINAPI X_RunClient(void *parm)
|
|
#else
|
|
void X_RunClient(void *parm)
|
|
#endif
|
|
{
|
|
char buffer[8192*64];
|
|
int read, len, err;
|
|
xclient_t *cl = parm;
|
|
|
|
while(cl->threadhandle)
|
|
{
|
|
if (cl->tobedropped)
|
|
{ //don't bother reading more.
|
|
read = 0;
|
|
}
|
|
else
|
|
{
|
|
read = recv(cl->socket, buffer, sizeof(buffer), 0);
|
|
if (read<0 && !cl->outbufferlen)
|
|
{
|
|
if (qerrno != EWOULDBLOCK)
|
|
cl->tobedropped = true;
|
|
else
|
|
{
|
|
Sleep(1);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef MULTITHREADWIN32
|
|
EnterCriticalSection(&cl->delecatesection);
|
|
#endif
|
|
|
|
if (read > 0)
|
|
{
|
|
if (cl->inbuffermaxlen < cl->inbufferlen+read) //expand in buffer
|
|
{
|
|
cl->inbuffermaxlen = cl->inbufferlen+read + 1000; //add breathing room.
|
|
cl->inbuffer = realloc(cl->inbuffer, cl->inbuffermaxlen);
|
|
}
|
|
memcpy(cl->inbuffer+cl->inbufferlen, buffer, read);
|
|
cl->inbufferlen += read;
|
|
}
|
|
else if (!read) //no more socket.
|
|
cl->tobedropped = true;
|
|
else
|
|
{ //error of some sort
|
|
err = qerrno;
|
|
if (err != EWOULDBLOCK)
|
|
cl->tobedropped = true;
|
|
}
|
|
|
|
if (cl->outbufferlen)
|
|
{
|
|
len = cl->outbufferlen;
|
|
if (len > 8000)
|
|
len = 8000;
|
|
len = send(cl->socket, cl->outbuffer, len, 0); //move out of critical section?
|
|
if (len>0)
|
|
{
|
|
memmove(cl->outbuffer, cl->outbuffer+len, cl->outbufferlen - len);
|
|
cl->outbufferlen -= len;
|
|
}
|
|
if (len == 0)
|
|
{
|
|
cl->tobedropped = true;
|
|
cl->outbufferlen=0;
|
|
}
|
|
if (len < 0)
|
|
{
|
|
err = qerrno;
|
|
if (err != EWOULDBLOCK)
|
|
{
|
|
cl->tobedropped = true;
|
|
cl->outbufferlen=0;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef MULTITHREADWIN32
|
|
LeaveCriticalSection(&cl->delecatesection);
|
|
#endif
|
|
}
|
|
|
|
DeleteCriticalSection (&cl->delecatesection);
|
|
|
|
closesocket(cl->socket);
|
|
if (cl->inbuffer)
|
|
free(cl->inbuffer);
|
|
if (cl->outbuffer)
|
|
free(cl->outbuffer);
|
|
free(cl);
|
|
|
|
#ifdef MULTITHREADWIN32
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
#endif
|
|
|
|
void XWindows_TendToClients(void)
|
|
{
|
|
struct sockaddr_in address;
|
|
int addrlen;
|
|
xclient_t *cl, *prev=NULL;
|
|
int newclient;
|
|
#ifndef MULTITHREADWIN32
|
|
unsigned int _true = 1;
|
|
#endif
|
|
|
|
if (xlistensocket != -1)
|
|
{
|
|
addrlen = sizeof(address);
|
|
newclient = accept(xlistensocket, (struct sockaddr *)&address, &addrlen);
|
|
if (newclient != -1)
|
|
{
|
|
cl = malloc(sizeof(xclient_t));
|
|
memset(cl, 0, sizeof(xclient_t));
|
|
cl->socket = newclient;
|
|
cl->nextclient = xclients;
|
|
cl->stillinitialising = 1;
|
|
xclients = cl;
|
|
|
|
|
|
#ifdef MULTITHREADWIN32
|
|
InitializeCriticalSection (&cl->delecatesection);
|
|
{DWORD tid;
|
|
cl->threadhandle = CreateThread(NULL, 0, X_RunClient, cl, 0, &tid);
|
|
}
|
|
|
|
if (!cl->threadhandle)
|
|
DeleteCriticalSection (&cl->delecatesection);
|
|
#else
|
|
if (ioctlsocket(cl->socket, FIONBIO, &_true) == -1)
|
|
Sys_Error("Nonblocking failed\n");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
for (cl = xclients; cl; cl = cl->nextclient)
|
|
{
|
|
if (XWindows_TendToClient(cl))
|
|
{
|
|
if (prev)
|
|
{
|
|
prev->nextclient = cl->nextclient;
|
|
}
|
|
else
|
|
xclients = cl->nextclient;
|
|
|
|
XS_DestroyResourcesOfClient(cl);
|
|
|
|
#ifdef MULTITHREADWIN32
|
|
if (cl->threadhandle)
|
|
{
|
|
cl->threadhandle = NULL;
|
|
break;
|
|
}
|
|
#endif
|
|
closesocket(cl->socket);
|
|
if (cl->inbuffer)
|
|
free(cl->inbuffer);
|
|
if (cl->outbuffer)
|
|
free(cl->outbuffer);
|
|
free(cl);
|
|
break;
|
|
}
|
|
|
|
prev = cl;
|
|
}
|
|
}
|
|
|
|
void XWindows_Startup(void) //initialise the server socket and do any initial setup as required.
|
|
{
|
|
struct sockaddr_in address;
|
|
unsigned long _true = true;
|
|
|
|
int port = 6000;
|
|
|
|
port += atoi(Cmd_Argv(1));
|
|
|
|
if (xlistensocket == -1)
|
|
{
|
|
if ((xlistensocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
|
|
{
|
|
Con_Printf("Failed to create socket\n");
|
|
return;
|
|
}
|
|
if (ioctlsocket (xlistensocket, FIONBIO, &_true) == -1)
|
|
{
|
|
closesocket(xlistensocket);
|
|
Con_Printf("Failed to create socket\n");
|
|
xlistensocket = -1;
|
|
return;
|
|
}
|
|
|
|
address.sin_family = AF_INET;
|
|
address.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
if (port == PORT_ANY)
|
|
address.sin_port = 0;
|
|
else
|
|
address.sin_port = htons((short)port);
|
|
|
|
if( bind (xlistensocket, (void *)&address, sizeof(address)) == -1)
|
|
{
|
|
Con_Printf("Couldn't bind socket to port %i\n", port);
|
|
closesocket(xlistensocket);
|
|
xlistensocket = -1;
|
|
return;
|
|
}
|
|
if( listen (xlistensocket, 3) == -1)
|
|
{
|
|
Con_Printf("Couldn't listen on port %i\n", port);
|
|
closesocket(xlistensocket);
|
|
xlistensocket = -1;
|
|
return;
|
|
}
|
|
|
|
X_InitRequests();
|
|
XS_CreateInitialResources();
|
|
}
|
|
|
|
XS_CheckResourceSentinals();
|
|
|
|
//quakie stuph
|
|
key_dest = key_menu;
|
|
m_state = m_xwindows;
|
|
m_entersound = true;
|
|
}
|
|
|
|
extern int x_windowwithfocus;
|
|
extern int x_windowwithcursor;
|
|
void XWindows_RefreshWindow(xwindow_t *wnd)
|
|
{
|
|
xwindow_t *p;
|
|
short xpos;
|
|
short ypos;
|
|
unsigned int *out, *in;
|
|
|
|
int x, y;
|
|
int maxx, maxy;
|
|
|
|
if (wnd->inputonly) //no thanks.
|
|
return;
|
|
|
|
xpos = 0;
|
|
ypos = 0;
|
|
for (p = wnd->parent; p; p = p->parent)
|
|
{
|
|
xpos += p->xpos;
|
|
ypos += p->ypos;
|
|
}
|
|
|
|
y = ypos + wnd->ypos;
|
|
maxy = y + wnd->height;
|
|
if (y < ypos+wnd->ypos)
|
|
{
|
|
y = ypos+wnd->ypos;
|
|
}
|
|
if (y < 0)
|
|
y = 0;
|
|
if (maxy >= xscreenheight)
|
|
maxy = xscreenheight-1;
|
|
|
|
if (!wnd->mapped)//&&rand()&1)
|
|
{ //unmapped windows are invisible.
|
|
return;
|
|
}
|
|
|
|
|
|
{
|
|
if (wnd->buffer)// && x_windowwithfocus != wnd->res.id)
|
|
{
|
|
for (; y < maxy; y++)
|
|
{
|
|
x = xpos + wnd->xpos;
|
|
maxx = x + wnd->width;
|
|
if (x < xpos+wnd->xpos)
|
|
{
|
|
x = xpos+wnd->xpos;
|
|
}
|
|
if (x < 0)
|
|
x = 0;
|
|
if (maxx > xscreenwidth)
|
|
maxx = xscreenwidth;
|
|
|
|
out = (unsigned int *)xscreen + (x+(y*xscreenwidth));
|
|
in = (unsigned int *)wnd->buffer + (x-xpos-wnd->xpos) + (y-ypos-wnd->ypos)*wnd->width;
|
|
|
|
for (; x < maxx; x++)
|
|
{
|
|
*out++ = *in++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
|
|
for (; y < maxy; y++)
|
|
{
|
|
x = xpos + wnd->xpos;
|
|
maxx = x + wnd->width;
|
|
if (x < xpos+wnd->xpos)
|
|
{
|
|
x = xpos+wnd->xpos;
|
|
}
|
|
if (x < 0)
|
|
{
|
|
x = 0;
|
|
}
|
|
if (maxx > xscreenwidth)
|
|
maxx = xscreenwidth;
|
|
|
|
out = (unsigned int *)xscreen + (x+(y*xscreenwidth));
|
|
|
|
for (; x < maxx; x++)
|
|
{
|
|
*out++ = wnd->backpixel;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
wnd = wnd->child;
|
|
while(wnd)
|
|
{
|
|
XWindows_RefreshWindow(wnd);
|
|
wnd = wnd->sibling;
|
|
}
|
|
}
|
|
/*
|
|
void XWindows_DrawWindowTree(xwindow_t *wnd, short xofs, short yofs)
|
|
{
|
|
int x, y;
|
|
int maxx, maxy;
|
|
unsigned int *out;
|
|
|
|
if (wnd->res.owner)
|
|
{
|
|
y = yofs + wnd->ypos;
|
|
maxy = y + wnd->width;
|
|
if (y < 0)
|
|
{
|
|
y = 0;
|
|
}
|
|
if (maxy >= xscreenheight)
|
|
maxy = xscreenheight-1;
|
|
for (y = 0; y < wnd->height; y++)
|
|
{
|
|
x = xofs + wnd->xpos;
|
|
maxx = x + wnd->height;
|
|
if (x < 0)
|
|
{
|
|
x = 0;
|
|
}
|
|
if (maxx >= xscreenwidth)
|
|
maxx = xscreenwidth-1;
|
|
|
|
out = (unsigned int *)xscreen + (x+(y*xscreenwidth));
|
|
|
|
for (; x < maxx; x++)
|
|
{
|
|
*out = rand();
|
|
out++;
|
|
}
|
|
}
|
|
}
|
|
|
|
xofs += wnd->xpos;
|
|
yofs += wnd->ypos;
|
|
|
|
wnd = wnd->child;
|
|
while(wnd)
|
|
{
|
|
XWindows_DrawWindowTree(wnd, xofs, yofs);
|
|
wnd = wnd->sibling;
|
|
}
|
|
}
|
|
*/
|
|
|
|
//quakie functions
|
|
void XWindows_Init(void)
|
|
{
|
|
Cmd_AddCommand("startx", XWindows_Startup);
|
|
}
|
|
|
|
int x_mousex;
|
|
int x_mousey;
|
|
int x_windowwithcursor;
|
|
int x_windowwithfocus;
|
|
|
|
int mousestate;
|
|
|
|
void X_EvalutateCursorOwner(int movemode)
|
|
{
|
|
xEvent ev;
|
|
xwindow_t *cursorowner, *wnd, *use;
|
|
int mx, my;
|
|
int wcx;
|
|
int wcy;
|
|
|
|
extern xwindow_t *xpconfinewindow;
|
|
|
|
{
|
|
extern int mousecursor_x, mousecursor_y;
|
|
mx = mousecursor_x * ((float)rootwindow->width/vid.width);
|
|
my = mousecursor_y * ((float)rootwindow->height/vid.height);
|
|
}
|
|
if (mx >= xscreenwidth)
|
|
mx = xscreenwidth-1;
|
|
if (my >= xscreenheight)
|
|
my = xscreenheight-1;
|
|
if (mx < 0)
|
|
mx = 0;
|
|
if (my < 0)
|
|
my = 0;
|
|
|
|
if (xpconfinewindow) //don't leave me!
|
|
{
|
|
cursorowner = xpconfinewindow;
|
|
|
|
wcx = 0; wcy = 0;
|
|
|
|
for (wnd = cursorowner; wnd; wnd = wnd->parent)
|
|
{
|
|
wcx += wnd->xpos;
|
|
wcy += wnd->ypos;
|
|
}
|
|
|
|
if (movemode == NotifyNormal)
|
|
movemode = NotifyWhileGrabbed;
|
|
}
|
|
else
|
|
{
|
|
cursorowner = rootwindow;
|
|
wcx = 0; wcy = 0;
|
|
while(1)
|
|
{
|
|
use = NULL;
|
|
//find the last window that contains the pointer (lower windows come first)
|
|
for (wnd = cursorowner->child; wnd; wnd = wnd->sibling)
|
|
{
|
|
if (/*!wnd->inputonly && */wnd->mapped)
|
|
if (wcx+wnd->xpos <= mx && wcx+wnd->xpos+wnd->width >= mx)
|
|
{
|
|
if (wcy+wnd->ypos <= my && wcy+wnd->ypos+wnd->height >= my)
|
|
{
|
|
use = wnd;
|
|
}
|
|
}
|
|
}
|
|
wnd = use;
|
|
|
|
if (wnd)
|
|
{
|
|
cursorowner = wnd;
|
|
wcx += wnd->xpos;
|
|
wcy += wnd->ypos;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (mx != x_mousex || my != x_mousey || x_windowwithcursor != cursorowner->res.id)
|
|
{
|
|
// extern qboolean keydown[256];
|
|
|
|
// Con_Printf("move %i %i\n", mx, my);
|
|
|
|
ev.u.u.detail = 0;
|
|
ev.u.u.sequenceNumber = 0;
|
|
ev.u.keyButtonPointer.time = Sys_DoubleTime()*1000;
|
|
ev.u.keyButtonPointer.root = rootwindow->res.id;
|
|
ev.u.keyButtonPointer.child = None;
|
|
ev.u.keyButtonPointer.rootX = mx;
|
|
ev.u.keyButtonPointer.rootY = my;
|
|
ev.u.keyButtonPointer.state = mousestate;
|
|
if (cursorowner->res.id != x_windowwithcursor) //changed window
|
|
{
|
|
xwindow_t *a,*b;
|
|
int d1,d2;
|
|
|
|
if (XS_GetResource(x_windowwithcursor, (void**)&wnd) != x_window)
|
|
wnd = rootwindow;
|
|
|
|
x_windowwithcursor = cursorowner->res.id;
|
|
|
|
//count how deep the windows are
|
|
for (a = wnd,d1=0; a; a = a->parent)
|
|
d1++;
|
|
for (b = cursorowner,d2=0; b; b = b->parent)
|
|
d2++;
|
|
|
|
a = wnd;
|
|
b = cursorowner;
|
|
|
|
if (d1>d2)
|
|
{
|
|
while(d1>d2) //a is too deep
|
|
{
|
|
a = a->parent;
|
|
d1--;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while(d2>d1)
|
|
{
|
|
b = b->parent;
|
|
d2--;
|
|
}
|
|
}
|
|
while(a != b) //find the common ancestor.
|
|
{
|
|
a = a->parent;
|
|
b = b->parent;
|
|
}
|
|
|
|
ev.u.enterLeave.mode = movemode;
|
|
ev.u.enterLeave.flags = ELFlagSameScreen; /* sameScreen and focus booleans, packed together */
|
|
|
|
//the cursor moved from a to b via:
|
|
// if (!a) //changed screen...
|
|
// {
|
|
// } else
|
|
if (a != wnd && b != cursorowner)
|
|
{ //changed via a common root, indirectly.
|
|
|
|
//o LeaveNotify with detail Nonlinear is generated on A.
|
|
|
|
ev.u.u.type = LeaveNotify;
|
|
ev.u.u.detail = NotifyNonlinear;
|
|
ev.u.keyButtonPointer.child = wnd->res.id;
|
|
X_SendInputNotification(&ev, wnd, LeaveWindowMask);
|
|
|
|
//o LeaveNotify with detail NonlinearVirtual is generated
|
|
// on each window between A and C exclusive (in that
|
|
// order).
|
|
|
|
for (a = wnd->parent; a != b; a = a->parent)
|
|
{
|
|
ev.u.u.type = LeaveNotify;
|
|
ev.u.u.detail = NotifyNonlinearVirtual;
|
|
ev.u.keyButtonPointer.child = a->res.id;
|
|
X_SendInputNotification(&ev, a, LeaveWindowMask);
|
|
}
|
|
|
|
//o EnterNotify with detail NonlinearVirtual is generated
|
|
// on each window between C and B exclusive (in that
|
|
// order).
|
|
|
|
for (; b != cursorowner; )
|
|
{
|
|
for (a = cursorowner; ; a = a->parent) //we need to go through the children.
|
|
{
|
|
if (a->parent == b)
|
|
{
|
|
b = a;
|
|
break;
|
|
}
|
|
}
|
|
if (b == cursorowner)
|
|
break;
|
|
|
|
ev.u.u.type = EnterNotify;
|
|
ev.u.u.detail = NotifyNonlinearVirtual;
|
|
ev.u.keyButtonPointer.child = a->res.id;
|
|
X_SendInputNotification(&ev, a, EnterWindowMask);
|
|
}
|
|
|
|
//o EnterNotify with detail Nonlinear is generated on B.
|
|
|
|
ev.u.u.type = EnterNotify;
|
|
ev.u.u.detail = NotifyNonlinear;
|
|
ev.u.keyButtonPointer.child = cursorowner->res.id;
|
|
X_SendInputNotification(&ev, cursorowner, EnterWindowMask);
|
|
}
|
|
else if (a == wnd)
|
|
{ //b is a child of a
|
|
|
|
//o LeaveNotify with detail Inferior is generated on A.
|
|
|
|
ev.u.u.type = LeaveNotify;
|
|
ev.u.u.detail = NotifyInferior;
|
|
ev.u.keyButtonPointer.child = wnd->res.id;
|
|
X_SendInputNotification(&ev, wnd, LeaveWindowMask);
|
|
|
|
//o EnterNotify with detail Virtual is generated on each
|
|
// window between A and B exclusive (in that order).
|
|
|
|
if (wnd != cursorowner)
|
|
for (b = wnd; ; )
|
|
{
|
|
for (a = cursorowner; ; a = a->parent) //we need to go through the children.
|
|
{
|
|
if (a->parent == b)
|
|
{
|
|
b = a;
|
|
break;
|
|
}
|
|
}
|
|
if (b == cursorowner)
|
|
break;
|
|
|
|
ev.u.u.type = EnterNotify;
|
|
ev.u.u.detail = NotifyVirtual;
|
|
ev.u.keyButtonPointer.child = b->res.id;
|
|
X_SendInputNotification(&ev, b, EnterWindowMask);
|
|
}
|
|
|
|
//o EnterNotify with detail Ancestor is generated on B.
|
|
|
|
ev.u.u.type = EnterNotify;
|
|
ev.u.u.detail = NotifyAncestor;
|
|
ev.u.keyButtonPointer.child = cursorowner->res.id;
|
|
X_SendInputNotification(&ev, cursorowner, EnterWindowMask);
|
|
}
|
|
else// if (b == cursorowner)
|
|
{ //a is a child of b
|
|
|
|
//o LeaveNotify with detail Ancestor is generated on A.
|
|
|
|
ev.u.u.type = LeaveNotify;
|
|
ev.u.u.detail = NotifyAncestor;
|
|
ev.u.keyButtonPointer.child = wnd->res.id;
|
|
X_SendInputNotification(&ev, wnd, LeaveWindowMask);
|
|
|
|
//o LeaveNotify with detail Virtual is generated on each
|
|
// window between A and B exclusive (in that order).
|
|
|
|
for (b = wnd; ; )
|
|
{
|
|
b = b->parent;
|
|
if (b == cursorowner)
|
|
break;
|
|
|
|
ev.u.u.type = LeaveNotify;
|
|
ev.u.u.detail = NotifyVirtual;
|
|
ev.u.keyButtonPointer.child = b->res.id;
|
|
X_SendInputNotification(&ev, b, LeaveWindowMask);
|
|
}
|
|
|
|
|
|
//o EnterNotify with detail Inferior is generated on B.
|
|
|
|
ev.u.u.type = EnterNotify;
|
|
ev.u.u.detail = NotifyInferior;
|
|
ev.u.keyButtonPointer.child = cursorowner->res.id;
|
|
X_SendInputNotification(&ev, cursorowner, EnterWindowMask);
|
|
}
|
|
|
|
{
|
|
char title[1024];
|
|
Atom type;
|
|
int extrabytes;
|
|
int format;
|
|
while(cursorowner)
|
|
{
|
|
title[XS_GetProperty(cursorowner, 39, &type, title, sizeof(title), 0, &extrabytes, &format)] = '\0';
|
|
if (*title)
|
|
break;
|
|
cursorowner = cursorowner->parent;
|
|
}
|
|
Con_Printf("Entered \"%s\"\n", title);
|
|
}
|
|
}
|
|
|
|
{ //same window
|
|
ev.u.keyButtonPointer.child = x_windowwithcursor;
|
|
|
|
if (XS_GetResource(x_windowwithcursor, (void**)&wnd) == x_window)
|
|
{ //cursor still in the same child.
|
|
int mask = PointerMotionMask;
|
|
if (mousestate)
|
|
mask |= ButtonMotionMask;
|
|
if (mousestate & Button1Mask)
|
|
mask |= Button1MotionMask;
|
|
if (mousestate & Button2Mask)
|
|
mask |= Button2MotionMask;
|
|
if (mousestate & Button3Mask)
|
|
mask |= Button3MotionMask;
|
|
if (mousestate & Button4Mask)
|
|
mask |= Button4MotionMask;
|
|
if (mousestate & Button5Mask)
|
|
mask |= Button5MotionMask;
|
|
ev.u.u.type = MotionNotify;
|
|
X_SendInputNotification(&ev, wnd, mask);
|
|
}
|
|
}
|
|
|
|
x_mousex = mx;
|
|
x_mousey = my;
|
|
}
|
|
}
|
|
|
|
void X_EvalutateFocus(int movemode)
|
|
{
|
|
xEvent ev;
|
|
xwindow_t *fo, *po, *wnd;
|
|
|
|
if (XS_GetResource(x_windowwithcursor, (void**)&po) != x_window)
|
|
po = rootwindow;
|
|
|
|
// xfocusedwindow = NULL;
|
|
|
|
|
|
if (!xfocusedwindow)
|
|
{
|
|
if (XS_GetResource(x_windowwithcursor, (void**)&fo) != x_window)
|
|
fo = rootwindow;
|
|
}
|
|
else
|
|
{
|
|
fo = xfocusedwindow;
|
|
}
|
|
|
|
if (x_windowwithfocus != fo->res.id)
|
|
{
|
|
ev.u.u.detail = 0;
|
|
ev.u.u.sequenceNumber = 0;
|
|
ev.u.focus.mode = movemode;
|
|
{
|
|
xwindow_t *a,*b;
|
|
int d1,d2;
|
|
|
|
if (XS_GetResource(x_windowwithfocus, (void**)&wnd) != x_window)
|
|
wnd = rootwindow;
|
|
|
|
x_windowwithfocus = fo->res.id;
|
|
|
|
//count how deep the windows are
|
|
for (a = wnd,d1=0; a; a = a->parent)
|
|
d1++;
|
|
for (b = fo,d2=0; b; b = b->parent)
|
|
d2++;
|
|
|
|
a = wnd;
|
|
b = fo;
|
|
|
|
if (d1>d2)
|
|
{
|
|
while(d1>d2) //a is too deep
|
|
{
|
|
a = a->parent;
|
|
d1--;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while(d2>d1)
|
|
{
|
|
b = b->parent;
|
|
d2--;
|
|
}
|
|
}
|
|
while(a != b) //find the common ancestor.
|
|
{
|
|
a = a->parent;
|
|
b = b->parent;
|
|
}
|
|
|
|
ev.u.enterLeave.mode = movemode;
|
|
ev.u.enterLeave.flags = ELFlagSameScreen; /* sameScreen and focus booleans, packed together */
|
|
|
|
//the cursor moved from a to b via:
|
|
// if (!a) //changed screen...
|
|
// {
|
|
// } else
|
|
if (a != wnd && b != fo)
|
|
{ //changed via a common root, indirectly.
|
|
|
|
//When the focus moves from window A to window B, window C is
|
|
//their least common ancestor, and the pointer is in window P:
|
|
|
|
//o If P is an inferior of A, FocusOut with detail Pointer
|
|
// is generated on each window from P up to but not
|
|
// including A (in order).
|
|
|
|
//FIXME
|
|
|
|
//o FocusOut with detail Nonlinear is generated on A.
|
|
|
|
ev.u.u.type = FocusOut;
|
|
ev.u.u.detail = NotifyNonlinear;
|
|
ev.u.focus.window = wnd->res.id;
|
|
X_SendInputNotification(&ev, wnd, FocusChangeMask);
|
|
|
|
|
|
|
|
|
|
//o FocusOut with detail NonlinearVirtual is generated on
|
|
// each window between A and C exclusive (in order).
|
|
|
|
for (a = wnd->parent; a != b; a = a->parent)
|
|
{
|
|
ev.u.u.type = FocusOut;
|
|
ev.u.u.detail = NotifyNonlinearVirtual;
|
|
ev.u.focus.window = a->res.id;
|
|
X_SendInputNotification(&ev, a, FocusChangeMask);
|
|
}
|
|
|
|
//o FocusIn with detail NonlinearVirtual is generated on
|
|
// each window between C and B exclusive (in order).
|
|
|
|
for (; b != fo; )
|
|
{
|
|
ev.u.u.type = FocusIn;
|
|
ev.u.u.detail = NotifyNonlinearVirtual;
|
|
ev.u.focus.window = a->res.id;
|
|
X_SendInputNotification(&ev, a, FocusChangeMask);
|
|
|
|
for (a = fo; ; a = a->parent) //we need to go through the children.
|
|
{
|
|
if (a->parent == b)
|
|
{
|
|
b = a;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//o FocusIn with detail Nonlinear is generated on B.
|
|
|
|
ev.u.u.type = FocusIn;
|
|
ev.u.u.detail = NotifyNonlinear;
|
|
ev.u.focus.window = fo->res.id;
|
|
X_SendInputNotification(&ev, fo, FocusChangeMask);
|
|
|
|
//o If P is an inferior of B, FocusIn with detail Pointer
|
|
// is generated on each window below B down to and includ-
|
|
// ing P (in order).
|
|
|
|
|
|
//FIXME:
|
|
|
|
}
|
|
else if (a == wnd)
|
|
{ //b is a child of a
|
|
|
|
//When the focus moves from window A to window B, B is an
|
|
//inferior of A, and the pointer is in window P:
|
|
|
|
//o If P is an inferior of A but P is not an inferior of B
|
|
// or an ancestor of B, FocusOut with detail Pointer is
|
|
// generated on each window from P up to but not including
|
|
// A (in order).
|
|
|
|
//FIXME
|
|
|
|
//o FocusOut with detail Inferior is generated on A.
|
|
|
|
ev.u.u.type = FocusOut;
|
|
ev.u.u.detail = NotifyInferior;
|
|
ev.u.focus.window = wnd->res.id;
|
|
X_SendInputNotification(&ev, wnd, FocusChangeMask);
|
|
|
|
//o FocusIn with detail Virtual is generated on each window
|
|
// between A and B exclusive (in order).
|
|
|
|
if (wnd != fo)
|
|
for (b = wnd; ; )
|
|
{
|
|
for (a = fo; ; a = a->parent) //we need to go through the children.
|
|
{
|
|
if (a->parent == b)
|
|
{
|
|
b = a;
|
|
break;
|
|
}
|
|
}
|
|
if (b == fo)
|
|
break;
|
|
|
|
ev.u.u.type = FocusIn;
|
|
ev.u.u.detail = NotifyVirtual;
|
|
ev.u.focus.window = b->res.id;
|
|
X_SendInputNotification(&ev, b, FocusChangeMask);
|
|
}
|
|
|
|
//o FocusIn with detail Ancestor is generated on B.
|
|
|
|
ev.u.u.type = FocusIn;
|
|
ev.u.u.detail = NotifyAncestor;
|
|
ev.u.focus.window = fo->res.id;
|
|
X_SendInputNotification(&ev, fo, FocusChangeMask);
|
|
}
|
|
else// if (b == cursorowner)
|
|
{ //a is a child of b
|
|
|
|
//When the focus moves from window A to window B, A is an
|
|
//inferior of B, and the pointer is in window P:
|
|
|
|
//o FocusOut with detail Ancestor is generated on A.
|
|
|
|
ev.u.u.type = FocusOut;
|
|
ev.u.u.detail = NotifyAncestor;
|
|
ev.u.focus.window = wnd->res.id;
|
|
X_SendInputNotification(&ev, wnd, FocusChangeMask);
|
|
|
|
//o FocusOut with detail Virtual is generated on each win-
|
|
// dow between A and B exclusive (in order).
|
|
|
|
for (b = wnd; ; )
|
|
{
|
|
b = b->parent;
|
|
if (b == fo)
|
|
break;
|
|
|
|
ev.u.u.type = FocusOut;
|
|
ev.u.u.detail = NotifyVirtual;
|
|
ev.u.focus.window = a->res.id;
|
|
X_SendInputNotification(&ev, a, FocusChangeMask);
|
|
}
|
|
|
|
|
|
//o FocusIn with detail Inferior is generated on B.
|
|
|
|
ev.u.u.type = FocusIn;
|
|
ev.u.u.detail = NotifyInferior;
|
|
ev.u.focus.window = fo->res.id;
|
|
X_SendInputNotification(&ev, fo, FocusChangeMask);
|
|
|
|
//o If P is an inferior of B but P is not A or an inferior
|
|
// of A or an ancestor of A, FocusIn with detail Pointer
|
|
// is generated on each window below B down to and includ-
|
|
// ing P (in order).
|
|
|
|
//FIXME: code missing
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void XWindows_Draw(void)
|
|
{
|
|
XS_CheckResourceSentinals();
|
|
{
|
|
X_EvalutateCursorOwner(NotifyNormal);
|
|
}
|
|
|
|
XWindows_TendToClients();
|
|
|
|
/* if (rand()&15 == 15)
|
|
xrefreshed = true;*/
|
|
|
|
// memset(xscreen, 0, xscreenwidth*4*xscreenheight);
|
|
|
|
XWindows_TendToClients();
|
|
|
|
// XW_ExposeWindow(rootwindow, 0, 0, rootwindow->width, rootwindow->height);
|
|
|
|
// XWindows_DrawWindowTree(rootwindow, 0, 0);
|
|
if (xrefreshed)
|
|
{
|
|
XWindows_RefreshWindow(rootwindow);
|
|
xrefreshed = false;
|
|
// Con_Printf("updated screen\n");
|
|
}
|
|
|
|
{
|
|
unsigned int *out = (unsigned int *)xscreen + (x_mousex+(x_mousey*xscreenwidth));
|
|
*out = rand();
|
|
// out[64] = rand();
|
|
}
|
|
|
|
XWindows_TendToClients();
|
|
Media_ShowFrameRGBA_32 (xscreen, xscreenwidth, xscreenheight);
|
|
|
|
Con_DrawNotify();
|
|
|
|
XWindows_TendToClients();
|
|
XS_CheckResourceSentinals();
|
|
}
|
|
|
|
void XWindows_Key(int key)
|
|
{
|
|
extern qboolean keydown[256];
|
|
XS_CheckResourceSentinals();
|
|
|
|
if (key == 'q' || (key == K_BACKSPACE && keydown[K_CTRL] && keydown[K_ALT])) //kill off the server
|
|
{
|
|
m_state = m_none;
|
|
key_dest = key_game;
|
|
|
|
closesocket(xlistensocket);
|
|
xlistensocket = -1;
|
|
}
|
|
|
|
|
|
|
|
{
|
|
xEvent ev;
|
|
xwindow_t *wnd;
|
|
|
|
X_EvalutateCursorOwner(NotifyNormal);
|
|
|
|
X_EvalutateFocus(NotifyNormal);
|
|
|
|
if (key >= K_MOUSE1 && key <= K_MOUSE5)
|
|
{
|
|
ev.u.u.type = ButtonPress;
|
|
switch(key)
|
|
{
|
|
case K_MOUSE1:
|
|
ev.u.u.detail = 1;
|
|
mousestate |= Button1Mask;
|
|
break;
|
|
|
|
case K_MOUSE3:
|
|
ev.u.u.detail = 2;
|
|
mousestate |= Button2Mask;
|
|
break;
|
|
|
|
case K_MOUSE2:
|
|
ev.u.u.detail = 3;
|
|
mousestate |= Button3Mask;
|
|
break;
|
|
|
|
case K_MOUSE4:
|
|
ev.u.u.detail = 4;
|
|
mousestate |= Button4Mask;
|
|
break;
|
|
|
|
default:
|
|
ev.u.u.detail = 5;
|
|
mousestate |= Button5Mask;
|
|
break;
|
|
}
|
|
ev.u.keyButtonPointer.state = mousestate;
|
|
ev.u.keyButtonPointer.child = x_windowwithcursor;
|
|
}
|
|
else
|
|
{
|
|
ev.u.u.type = KeyPress;
|
|
ev.u.u.detail = key;
|
|
ev.u.keyButtonPointer.state = 0;
|
|
ev.u.keyButtonPointer.child = x_windowwithfocus;
|
|
}
|
|
ev.u.u.sequenceNumber = 0;
|
|
ev.u.keyButtonPointer.time = Sys_DoubleTime()*1000;
|
|
ev.u.keyButtonPointer.rootX = x_mousex;
|
|
ev.u.keyButtonPointer.rootY = x_mousey;
|
|
ev.u.keyButtonPointer.sameScreen= true;
|
|
ev.u.keyButtonPointer.pad1 = 0;
|
|
|
|
// Con_Printf("key %i, %i %i\n", key, x_mousex, x_mousey);
|
|
|
|
if (xpointergrabclient)
|
|
{
|
|
ev.u.keyButtonPointer.event = ev.u.keyButtonPointer.child;
|
|
ev.u.keyButtonPointer.eventX = ev.u.keyButtonPointer.rootX;
|
|
ev.u.keyButtonPointer.eventY = ev.u.keyButtonPointer.rootY;
|
|
if (XS_GetResource(x_windowwithcursor, (void**)&wnd) == x_window)
|
|
{
|
|
ev.u.u.sequenceNumber = xpointergrabclient->requestnum;
|
|
while(wnd)
|
|
{
|
|
ev.u.keyButtonPointer.eventX -= wnd->xpos;
|
|
ev.u.keyButtonPointer.eventY -= wnd->ypos;
|
|
wnd = wnd->parent;
|
|
}
|
|
X_SendData(xpointergrabclient, &ev, sizeof(ev));
|
|
}
|
|
}
|
|
else if (XS_GetResource(ev.u.keyButtonPointer.child, (void**)&wnd) == x_window)
|
|
X_SendInputNotification(&ev, wnd, (ev.u.u.type==ButtonPress)?ButtonPressMask:KeyPressMask);
|
|
}
|
|
XS_CheckResourceSentinals();
|
|
}
|
|
void XWindows_Keyup(int key)
|
|
{
|
|
XS_CheckResourceSentinals();
|
|
{
|
|
xEvent ev;
|
|
xwindow_t *wnd;
|
|
|
|
X_EvalutateCursorOwner(NotifyNormal);
|
|
|
|
X_EvalutateFocus(NotifyNormal);
|
|
|
|
if (key >= K_MOUSE1 && key <= K_MOUSE5)
|
|
{
|
|
ev.u.u.type = ButtonRelease;
|
|
ev.u.keyButtonPointer.state = mousestate;
|
|
switch(key)
|
|
{
|
|
case K_MOUSE1:
|
|
ev.u.u.detail = 1;
|
|
mousestate &= ~Button1Mask;
|
|
break;
|
|
|
|
case K_MOUSE3:
|
|
ev.u.u.detail = 2;
|
|
mousestate &= ~Button2Mask;
|
|
break;
|
|
|
|
case K_MOUSE2:
|
|
ev.u.u.detail = 3;
|
|
mousestate &= ~Button3Mask;
|
|
break;
|
|
|
|
case K_MOUSE4:
|
|
ev.u.u.detail = 4;
|
|
mousestate &= ~Button4Mask;
|
|
break;
|
|
|
|
default:
|
|
ev.u.u.detail = 5;
|
|
mousestate &= ~Button5Mask;
|
|
break;
|
|
}
|
|
ev.u.keyButtonPointer.state = mousestate;
|
|
ev.u.keyButtonPointer.child = x_windowwithcursor;
|
|
}
|
|
else
|
|
{
|
|
ev.u.u.type = KeyRelease;
|
|
ev.u.u.detail = key;
|
|
ev.u.keyButtonPointer.child = x_windowwithfocus;
|
|
}
|
|
ev.u.u.sequenceNumber = 0;
|
|
ev.u.keyButtonPointer.time = Sys_DoubleTime()*1000;
|
|
ev.u.keyButtonPointer.rootX = x_mousex;
|
|
ev.u.keyButtonPointer.rootY = x_mousey;
|
|
ev.u.keyButtonPointer.state = 0;
|
|
ev.u.keyButtonPointer.sameScreen= true;
|
|
ev.u.keyButtonPointer.pad1 = 0;
|
|
|
|
// Con_Printf("keyup %i, %i %i\n", key, x_mousex, x_mousey);
|
|
|
|
if (xpointergrabclient)
|
|
{
|
|
ev.u.keyButtonPointer.event = ev.u.keyButtonPointer.child;
|
|
ev.u.keyButtonPointer.eventX = ev.u.keyButtonPointer.rootX;
|
|
ev.u.keyButtonPointer.eventY = ev.u.keyButtonPointer.rootY;
|
|
if (XS_GetResource(x_windowwithcursor, (void**)&wnd) == x_window)
|
|
{
|
|
ev.u.u.sequenceNumber = xpointergrabclient->requestnum;
|
|
while(wnd)
|
|
{
|
|
ev.u.keyButtonPointer.eventX -= wnd->xpos;
|
|
ev.u.keyButtonPointer.eventY -= wnd->ypos;
|
|
wnd = wnd->parent;
|
|
}
|
|
X_SendData(xpointergrabclient, &ev, sizeof(ev));
|
|
}
|
|
}
|
|
else if (XS_GetResource(ev.u.keyButtonPointer.child, (void**)&wnd) == x_window)
|
|
{
|
|
X_SendInputNotification(&ev, wnd, (ev.u.u.type==ButtonRelease)?ButtonReleaseMask:KeyReleaseMask);
|
|
}
|
|
}
|
|
XS_CheckResourceSentinals();
|
|
}
|
|
|
|
#else
|
|
//quakie functions
|
|
void XWindows_Init(void){}
|
|
void XWindows_Draw(void){}
|
|
void XWindows_Key(int key){}
|
|
void XWindows_Keyup(int key){}
|
|
#endif
|