fteqw/plugins/xsv/m_x.c
Spoike 27a59a0cbc LOTS OF CHANGES. was hoping to get revision 5000 perfect, but really that's never going to happen. this has gone on for too long now.
vulkan, wasapi, quake injector features added.
irc, avplug, cef plugins/drivers reworked/updated/added
openal reverb, doppler effects added.
'dir' console command now attempts to view clicked files.
lots of warning fixes, should now only be deprecation warnings for most targets (depending on compiler version anyway...).
SendEntity finally reworked to use flags properly.
effectinfo improved, other smc-targetted fixes.
mapcluster stuff now has support for linux.
.basebone+.baseframe now exist in ssqc.
qcc: -Fqccx supports qccx syntax, including qccx hacks. don't expect these to work in fteqw nor dp though.
qcc: rewrote function call handling to use refs rather than defs. this makes struct passing more efficient and makes the __out keyword usable with fields etc.
qccgui: can cope a little better with non-unicode files. can now represent most quake chars.
qcc: suppressed warnings from *extensions.qc

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5000 fc73d0e0-1445-4013-8a0c-d673dee63da5
2016-07-12 00:40:13 +00:00

2069 lines
No EOL
48 KiB
C

//network interface+main module
//this code should work okay as a host server for Xepher.
//issue these two commands and Xephyr will do all the stuff we don't support properly.
//DISPLAY=127.0.0.1:0 Xephyr :1
//wmaker -display :1 (or xterm or whatever)
#include "../plugin.h"
#include "../engine.h"
#include "qux.h"
int mousecursor_x, mousecursor_y;
static xclient_t *xclients;
static qhandle_t xlistensocket;
xwindow_t *xfocusedwindow;
qboolean xrefreshed;
qboolean xscreenmodified; //texture updated
xclient_t *xgrabbedclient; //clients can ask the server to ignore other clients
extern xwindow_t *xpgrabbedwindow;
#define MAXREQUESTSIZE 65535
int ctrldown, altdown;
int K_BACKSPACE;
int K_CTRL;
int K_ALT;
int K_MOUSE1;
int K_MOUSE2;
int K_MOUSE3;
int K_MOUSE4;
int K_MOUSE5;
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 = 0;//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 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 = 0xff0000;
visualtype->greenMask = 0x00ff00;
visualtype->blueMask = 0x0000ff;
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 = pNet_Recv(cl->socket, cl->inbuffer + cl->inbufferlen, len);
//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 = len;
if (err != N_WOULDBLOCK)
{
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))
{
unsigned 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 = pNet_Send(cl->socket, cl->outbuffer, len);
if (len>0)
{
memmove(cl->outbuffer, cl->outbuffer+len, cl->outbufferlen - len);
cl->outbufferlen -= len;
}
if (len == 0)
cl->tobedropped = true;
if (len < 0)
{
if (len != N_WOULDBLOCK)
{
Con_Printf("X send error %i\n", len);
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)
{
xclient_t *cl, *prev=NULL;
qhandle_t newclient;
#ifndef MULTITHREADWIN32
unsigned int _true = 1;
unsigned int _false = 0;
#endif
if (xlistensocket)
{
newclient = pNet_Accept(xlistensocket, NULL, 0);
if ((int)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);
if (ioctlsocket(cl->socket, FIONBIO, &_false) == -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
pNet_Close(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.
{
char buffer[64];
int port = 6000;
pCmd_Argv(1, buffer, sizeof(buffer));
port += atoi(buffer);
if (!xlistensocket)
{
xlistensocket = pNet_TCPListen(NULL, port, 3);
if (xlistensocket < 0)
{
xlistensocket = 0;
Con_Printf("Failed to create tcp listen socket\n");
return;
}
X_InitRequests();
XS_CreateInitialResources();
}
XS_CheckResourceSentinals();
// Menu_Control(MENU_GRAB);
}
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 (x_windowwithcursor == 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));
for (; x < maxx; x++)
{
*out++ = ((rand()&0xff)<<16)|((rand()&0xff)<<8)|(rand() & 0xff);
}
}
}
else */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_mousestate;
int x_windowwithcursor;
int x_windowwithfocus;
int mousestate;
void X_MoveCursorWindow(xwindow_t *ew, int mx, int my, int movemode)
{
xEvent ev;
#define MAX_WINDOW_CHAIN 64
int od, nd;
int d, i;
xwindow_t *ow;
xwindow_t *nw = ew;
xwindow_t *oc[MAX_WINDOW_CHAIN];
xwindow_t *nc[MAX_WINDOW_CHAIN];
unsigned int curtime = pSys_Milliseconds();
if (!nw)
nw = rootwindow;
/*its already got it*/
if (nw->res.id == x_windowwithcursor)
return;
if (XS_GetResource(x_windowwithcursor, (void**)&ow) != x_window)
return;
//build the window chains into a simple list
od = 0;
while(ow && od < MAX_WINDOW_CHAIN)
{
oc[od++] = ow;
ow = ow->parent;
}
nd = 0;
while(nw && nd < MAX_WINDOW_CHAIN)
{
nc[nd++] = nw;
nw = nw->parent;
}
//both chains have the root at the end
//walk from the parent (last) window up to the top. if they diverge then we have the relevent common ancestor
for (d = 0; d < nd && d < od; )
{
d++;
if (nc[nd-d] != oc[od-d])
break;
}
nd -= d;
od -= d;
if (!nd)
{
/*moved to a parent*/
//LeaveNotify with detail Inferior is generated on A.
ev.u.u.type = LeaveNotify;
ev.u.u.detail = NotifyInferior;
ev.u.enterLeave.time = pSys_Milliseconds();
ev.u.enterLeave.root = rootwindow->res.id;
ev.u.enterLeave.event = oc[0]->res.id;
ev.u.enterLeave.child = None;
ev.u.enterLeave.rootX = mx;
ev.u.enterLeave.rootY = my;
ev.u.enterLeave.eventX = mx - oc[0]->xpos;
ev.u.enterLeave.eventY = my - oc[0]->ypos;
ev.u.enterLeave.state = mousestate;
ev.u.enterLeave.mode = movemode;
ev.u.enterLeave.flags = ELFlagSameScreen;
X_SendInputNotification(&ev, oc[0], LeaveWindowMask);
//EnterNotify with detail Virtual is generated on each window between A and B exclusive (in that order).
for (i = od-1; i > 0; i--)
{
ev.u.u.type = EnterNotify;
ev.u.u.detail = NotifyVirtual;
ev.u.enterLeave.time = pSys_Milliseconds();
ev.u.enterLeave.root = rootwindow->res.id;
ev.u.enterLeave.event = oc[i]->res.id;
ev.u.enterLeave.child = oc[i-1]->res.id;
ev.u.enterLeave.rootX = mx;
ev.u.enterLeave.rootY = my;
ev.u.enterLeave.eventX = mx - oc[i]->xpos;
ev.u.enterLeave.eventY = my - oc[i]->ypos;
ev.u.enterLeave.state = mousestate;
ev.u.enterLeave.mode = movemode;
ev.u.enterLeave.flags = ELFlagSameScreen;
X_SendInputNotification(&ev, oc[i], EnterWindowMask);
}
//EnterNotify with detail Ancestor is generated on B.
ev.u.u.type = EnterNotify;
ev.u.u.detail = NotifyInferior;
ev.u.enterLeave.time = pSys_Milliseconds();
ev.u.enterLeave.root = rootwindow->res.id;
ev.u.enterLeave.event = nc[0]->res.id;
ev.u.enterLeave.child = None;
ev.u.enterLeave.rootX = mx;
ev.u.enterLeave.rootY = my;
ev.u.enterLeave.eventX = mx - nc[0]->xpos;
ev.u.enterLeave.eventY = my - nc[0]->ypos;
ev.u.enterLeave.state = mousestate;
ev.u.enterLeave.mode = movemode;
ev.u.enterLeave.flags = ELFlagSameScreen;
X_SendInputNotification(&ev, nc[0], EnterWindowMask);
}
else if (!od)
{
/*moved to a child*/
//LeaveNotify with detail Ancestor is generated on A.
ev.u.u.type = LeaveNotify;
ev.u.u.detail = NotifyAncestor;
ev.u.enterLeave.time = pSys_Milliseconds();
ev.u.enterLeave.root = rootwindow->res.id;
ev.u.enterLeave.event = oc[0]->res.id;
ev.u.enterLeave.child = None;
ev.u.enterLeave.rootX = mx;
ev.u.enterLeave.rootY = my;
ev.u.enterLeave.eventX = mx - oc[0]->xpos;
ev.u.enterLeave.eventY = my - oc[0]->ypos;
ev.u.enterLeave.state = mousestate;
ev.u.enterLeave.mode = movemode;
ev.u.enterLeave.flags = ELFlagSameScreen;
X_SendInputNotification(&ev, oc[0], LeaveWindowMask);
//LeaveNotify with detail Virtual is generated on each window between A and B exclusive (in that order).
for (i = 1; i < nd; i++)
{
ev.u.u.type = LeaveNotify;
ev.u.u.detail = NotifyVirtual;
ev.u.enterLeave.time = pSys_Milliseconds();
ev.u.enterLeave.root = rootwindow->res.id;
ev.u.enterLeave.event = nc[i]->res.id;
ev.u.enterLeave.child = nc[i-1]->res.id;
ev.u.enterLeave.rootX = mx;
ev.u.enterLeave.rootY = my;
ev.u.enterLeave.eventX = mx - nc[i]->xpos;
ev.u.enterLeave.eventY = my - nc[i]->ypos;
ev.u.enterLeave.state = mousestate;
ev.u.enterLeave.mode = movemode;
ev.u.enterLeave.flags = ELFlagSameScreen;
X_SendInputNotification(&ev, nc[i], LeaveWindowMask);
}
//EnterNotify with detail Inferior is generated on B.
ev.u.u.type = EnterNotify;
ev.u.u.detail = NotifyInferior;
ev.u.enterLeave.time = pSys_Milliseconds();
ev.u.enterLeave.root = rootwindow->res.id;
ev.u.enterLeave.event = nc[0]->res.id;
ev.u.enterLeave.child = None;
ev.u.enterLeave.rootX = mx;
ev.u.enterLeave.rootY = my;
ev.u.enterLeave.eventX = mx - nc[0]->xpos;
ev.u.enterLeave.eventY = my - nc[0]->ypos;
ev.u.enterLeave.state = mousestate;
ev.u.enterLeave.mode = movemode;
ev.u.enterLeave.flags = ELFlagSameScreen;
X_SendInputNotification(&ev, nc[0], EnterWindowMask);
}
else
{
/*moved up then down*/
//LeaveNotify with detail Nonlinear is generated on A.
ev.u.u.type = LeaveNotify;
ev.u.u.detail = NotifyNonlinear;
ev.u.enterLeave.time = pSys_Milliseconds();
ev.u.enterLeave.root = rootwindow->res.id;
ev.u.enterLeave.event = oc[0]->res.id;
ev.u.enterLeave.child = None;
ev.u.enterLeave.rootX = mx;
ev.u.enterLeave.rootY = my;
ev.u.enterLeave.eventX = mx - oc[0]->xpos;
ev.u.enterLeave.eventY = my - oc[0]->ypos;
ev.u.enterLeave.state = mousestate;
ev.u.enterLeave.mode = movemode;
ev.u.enterLeave.flags = ELFlagSameScreen;
X_SendInputNotification(&ev, oc[0], LeaveWindowMask);
//LeaveNotify with detail NonlinearVirtual is generated on each window between A and C exclusive (in that order).
for (i = 1; i < nd; i++)
{
ev.u.u.type = LeaveNotify;
ev.u.u.detail = NotifyNonlinearVirtual;
ev.u.enterLeave.time = pSys_Milliseconds();
ev.u.enterLeave.root = rootwindow->res.id;
ev.u.enterLeave.event = nc[i]->res.id;
ev.u.enterLeave.child = nc[i-1]->res.id;
ev.u.enterLeave.rootX = mx;
ev.u.enterLeave.rootY = my;
ev.u.enterLeave.eventX = mx - nc[i]->xpos;
ev.u.enterLeave.eventY = my - nc[i]->ypos;
ev.u.enterLeave.state = mousestate;
ev.u.enterLeave.mode = movemode;
ev.u.enterLeave.flags = ELFlagSameScreen;
X_SendInputNotification(&ev, nc[i], LeaveWindowMask);
}
//EnterNotify with detail NonlinearVirtual is generated on each window between C and B exclusive (in that order).
for (i = od-1; i > 0; i--)
{
ev.u.u.type = EnterNotify;
ev.u.u.detail = NotifyNonlinearVirtual;
ev.u.enterLeave.time = pSys_Milliseconds();
ev.u.enterLeave.root = rootwindow->res.id;
ev.u.enterLeave.event = oc[i]->res.id;
ev.u.enterLeave.child = oc[i-1]->res.id;
ev.u.enterLeave.rootX = mx;
ev.u.enterLeave.rootY = my;
ev.u.enterLeave.eventX = mx - oc[i]->xpos;
ev.u.enterLeave.eventY = my - oc[i]->ypos;
ev.u.enterLeave.state = mousestate;
ev.u.enterLeave.mode = movemode;
ev.u.enterLeave.flags = ELFlagSameScreen;
X_SendInputNotification(&ev, oc[i], EnterWindowMask);
}
//EnterNotify with detail Nonlinear is generated on B.
ev.u.u.type = EnterNotify;
ev.u.u.detail = NotifyNonlinear;
ev.u.enterLeave.time = pSys_Milliseconds();
ev.u.enterLeave.root = rootwindow->res.id;
ev.u.enterLeave.event = nc[0]->res.id;
ev.u.enterLeave.child = None;
ev.u.enterLeave.rootX = mx;
ev.u.enterLeave.rootY = my;
ev.u.enterLeave.eventX = mx - nc[0]->xpos;
ev.u.enterLeave.eventY = my - nc[0]->ypos;
ev.u.enterLeave.state = mousestate;
ev.u.enterLeave.mode = movemode;
ev.u.enterLeave.flags = ELFlagSameScreen;
X_SendInputNotification(&ev, nc[0], EnterWindowMask);
}
}
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;
my = mousecursor_y;
}
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_mousestate != mousestate || x_windowwithcursor != cursorowner->res.id)
{
int mask = 0;
// extern qboolean keydown[256];
// Con_Printf("move %i %i\n", mx, my);
X_MoveCursorWindow(cursorowner, mx, my, movemode);
x_windowwithcursor = cursorowner->res.id;
if (mx != x_mousex || my != x_mousey)
{
mask |= PointerMotionMask;
if (mousestate)
mask |= ButtonMotionMask;
}
if ((mousestate^x_mousestate) & Button1Mask)
mask |= Button1MotionMask;
if ((mousestate^x_mousestate) & Button2Mask)
mask |= Button2MotionMask;
if ((mousestate^x_mousestate) & Button3Mask)
mask |= Button3MotionMask;
if ((mousestate^x_mousestate) & Button4Mask)
mask |= Button4MotionMask;
if ((mousestate^x_mousestate) & Button5Mask)
mask |= Button5MotionMask;
x_mousex = mx;
x_mousey = my;
x_mousestate = mousestate;
for (; cursorowner && mask; cursorowner = cursorowner->parent)
{ //same window
if (cursorowner->notificationmasks & mask)
{
ev.u.keyButtonPointer.child = x_windowwithcursor;
/* #define ButtonPress 4
#define ButtonRelease 5
#define MotionNotify 6
*/
ev.u.u.type = MotionNotify;
ev.u.u.detail = 0;
ev.u.u.sequenceNumber = 0;
ev.u.keyButtonPointer.time = pSys_Milliseconds();
ev.u.keyButtonPointer.root = rootwindow->res.id;
ev.u.keyButtonPointer.event = cursorowner->res.id;
ev.u.keyButtonPointer.child = (x_windowwithcursor == cursorowner->res.id)?None:x_windowwithcursor;
ev.u.keyButtonPointer.rootX = mx;
ev.u.keyButtonPointer.rootY = my;
ev.u.keyButtonPointer.eventX = mx - cursorowner->xpos;
ev.u.keyButtonPointer.eventY = my - cursorowner->ypos;
ev.u.keyButtonPointer.state = mousestate;
ev.u.keyButtonPointer.sameScreen= true;
X_SendNotificationMasked(&ev, cursorowner, cursorowner->notificationmasks&mask);
mask &= ~cursorowner->notificationmasks;
}
}
}
}
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;
xscreenmodified = true;
// Con_Printf("updated screen\n");
}
{
unsigned int *out = (unsigned int *)xscreen + (x_mousex+(x_mousey*xscreenwidth));
*out = rand();
// out[64] = rand();
}
XWindows_TendToClients();
// Con_DrawNotify();
XWindows_TendToClients();
XS_CheckResourceSentinals();
}
void XWindows_KeyDown(int key)
{
XS_CheckResourceSentinals();
if (!key) //hrm
return;
/*
if (key == 'q' || (key == K_BACKSPACE && ctrldown && altdown)) //kill off the server
{ //explicit kill
Menu_Control(MENU_CLEAR);
return;
}
*/
if (key == K_CTRL)
ctrldown = true;
if (key == K_ALT)
altdown = true;
{
xEvent ev;
xwindow_t *wnd;
X_EvalutateCursorOwner(NotifyNormal);
X_EvalutateFocus(NotifyNormal);
if (key == K_MOUSE1)
{
ev.u.u.type = ButtonPress;
ev.u.u.detail = 1;
mousestate |= Button1Mask;
ev.u.keyButtonPointer.state = mousestate;
ev.u.keyButtonPointer.child = x_windowwithcursor;
}
else if (key == K_MOUSE3)
{
ev.u.u.type = ButtonPress;
ev.u.u.detail = 2;
mousestate |= Button2Mask;
ev.u.keyButtonPointer.state = mousestate;
ev.u.keyButtonPointer.child = x_windowwithcursor;
}
else if (key == K_MOUSE2)
{
ev.u.u.type = ButtonPress;
ev.u.u.detail = 3;
mousestate |= Button3Mask;
ev.u.keyButtonPointer.state = mousestate;
ev.u.keyButtonPointer.child = x_windowwithcursor;
}
else if (key == K_MOUSE4)
{
ev.u.u.type = ButtonPress;
ev.u.u.detail = 4;
mousestate |= Button4Mask;
ev.u.keyButtonPointer.state = mousestate;
ev.u.keyButtonPointer.child = x_windowwithcursor;
}
else if (key == K_MOUSE5)
{
ev.u.u.type = ButtonPress;
ev.u.u.detail = 5;
mousestate |= Button5Mask;
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 = pSys_Milliseconds();
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 (0)//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)
{
if (key == K_CTRL)
ctrldown = false;
if (key == K_ALT)
altdown = false;
XS_CheckResourceSentinals();
{
xEvent ev;
xwindow_t *wnd;
X_EvalutateCursorOwner(NotifyNormal);
X_EvalutateFocus(NotifyNormal);
if (key == K_MOUSE1)
{
ev.u.u.type = ButtonRelease;
ev.u.keyButtonPointer.state = mousestate;
ev.u.u.detail = 1;
mousestate &= ~Button1Mask;
ev.u.keyButtonPointer.state = mousestate;
ev.u.keyButtonPointer.child = x_windowwithcursor;
}
else if (key == K_MOUSE3)
{
ev.u.u.type = ButtonRelease;
ev.u.keyButtonPointer.state = mousestate;
ev.u.u.detail = 2;
mousestate &= ~Button2Mask;
ev.u.keyButtonPointer.state = mousestate;
ev.u.keyButtonPointer.child = x_windowwithcursor;
}
else if (key == K_MOUSE2)
{
ev.u.u.type = ButtonRelease;
ev.u.keyButtonPointer.state = mousestate;
ev.u.u.detail = 3;
mousestate &= ~Button3Mask;
ev.u.keyButtonPointer.state = mousestate;
ev.u.keyButtonPointer.child = x_windowwithcursor;
}
else if (key == K_MOUSE4)
{
ev.u.u.type = ButtonRelease;
ev.u.keyButtonPointer.state = mousestate;
ev.u.u.detail = 4;
mousestate &= ~Button4Mask;
ev.u.keyButtonPointer.state = mousestate;
ev.u.keyButtonPointer.child = x_windowwithcursor;
}
else if (key == K_MOUSE5)
{
ev.u.u.type = ButtonRelease;
ev.u.keyButtonPointer.state = mousestate;
ev.u.u.detail = 5;
mousestate &= ~Button5Mask;
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 = pSys_Milliseconds();
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();
}
int Plug_MenuEvent(int *args)
{
mousecursor_x = args[2];
mousecursor_y = args[3];
switch(args[0])
{
case 0: //draw
XWindows_Draw();
break;
case 1: //keydown
XWindows_KeyDown(args[1]);
break;
case 2: //keyup
XWindows_Keyup(args[1]);
break;
case 3: //menu closed (this is called even if we change it).
break;
}
return 0;
}
qintptr_t Plug_ExecuteCommand(qintptr_t *args)
{
char cmd[256];
pCmd_Argv(0, cmd, sizeof(cmd));
if (!strcmp("startx", cmd))
{
XWindows_Startup();
return 1;
}
return 0;
}
qintptr_t Plug_Tick(qintptr_t *args)
{
XWindows_TendToClients();
return 0;
}
static void *XWindows_Create(const char *medianame) //initialise the server socket and do any initial setup as required.
{
if (!strcmp(medianame, "x11"))
{
XWindows_Startup();
return xscreen;
}
return NULL;
}
static qboolean VARGS XWindows_DisplayFrame(void *ctx, qboolean nosound, qboolean forcevideo, double mediatime, void (QDECL *uploadtexture)(void *ectx, uploadfmt_t fmt, int width, int height, void *data, void *palette), void *ectx)
{
XWindows_Draw();
if (forcevideo || xscreenmodified)
uploadtexture(ectx, TF_BGRX32, xscreenwidth, xscreenheight, xscreen, NULL);
xscreenmodified = false;
return true;
}
static void XWindows_Shutdown(void *ctx)
{
pNet_Close(xlistensocket);
xlistensocket = 0;
}
static qboolean XWindows_SetSize (void *ctx, int width, int height)
{
qbyte *ns;
if (width < 64 || height < 64 || width > 2048 || height > 2048)
return false;
ns = realloc(xscreen, width*4*height);
if (ns)
{
xscreen = ns;
xscreenwidth = width;
xscreenheight = height;
xscreenmodified = true;
//FIXME: resize root window + send notify
return true;
}
return false;
}
static void XWindows_GetSize (void *ctx, int *width, int *height) //retrieves the screen-space size
{
*width = xscreenwidth;
*height = xscreenheight;
}
static void XWindows_CursorMove (void *ctx, float posx, float posy)
{
mousecursor_x = (int)(posx * xscreenwidth);
mousecursor_y = (int)(posy * xscreenheight);
}
static void XWindows_Key (void *ctx, int code, int unicode, int isup)
{
if (isup)
XWindows_Keyup(code);
else
XWindows_KeyDown(code);
}
media_decoder_funcs_t decoderfuncs =
{
sizeof(media_decoder_funcs_t),
"x11",
XWindows_Create,
XWindows_DisplayFrame,
XWindows_Shutdown,
NULL,//rewind
XWindows_CursorMove,
XWindows_Key,
XWindows_SetSize,
XWindows_GetSize,
NULL//changestream
};
qintptr_t Plug_Init(qintptr_t *args)
{
if (!Plug_Export("ExecuteCommand", Plug_ExecuteCommand) ||
// !Plug_Export("MenuEvent", Plug_MenuEvent) ||
!Plug_Export("Tick", Plug_Tick))
{
Con_Printf("XServer plugin failed\n");
return false;
}
if (!pPlug_ExportNative("Media_VideoDecoder", &decoderfuncs))
{
Con_Printf("XServer plugin failed: Engine doesn't support media decoder plugins\n");
return false;
}
Con_Printf("XServer plugin started\n");
pCmd_AddCommand("startx");
K_CTRL = pKey_GetKeyCode("ctrl");
K_ALT = pKey_GetKeyCode("alt");
K_MOUSE1 = pKey_GetKeyCode("mouse1");
K_MOUSE2 = pKey_GetKeyCode("mouse2");
K_MOUSE3 = pKey_GetKeyCode("mouse3");
K_MOUSE4 = pKey_GetKeyCode("mouse4");
K_MOUSE5 = pKey_GetKeyCode("mouse5");
K_BACKSPACE = pKey_GetKeyCode("backspace");
/*
K_UPARROW = Key_GetKeyCode("uparrow");
K_DOWNARROW = Key_GetKeyCode("downarrow");
K_ENTER = Key_GetKeyCode("enter");
K_DEL = Key_GetKeyCode("del");
K_ESCAPE = Key_GetKeyCode("escape");
K_PGDN = Key_GetKeyCode("pgdn");
K_PGUP = Key_GetKeyCode("pgup");
K_SPACE = Key_GetKeyCode("space");
K_LEFTARROW = Key_GetKeyCode("leftarrow");
K_RIGHTARROW = Key_GetKeyCode("rightarrow");
*/
return true;
}