#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <X11/X.h>
#include <X11/Xmd.h>
#include "misc.h"
#include "windowstr.h"
#include "dixstruct.h"
#include "pixmapstr.h"
#include "scrnintstr.h"
#define XK_LATIN1
#include <X11/keysymdef.h>
#include "xace.h"
_X_EXPORT int
CompareTimeStamps(TimeStamp a, TimeStamp b)
{
if (a.months < b.months)
return EARLIER;
if (a.months > b.months)
return LATER;
if (a.milliseconds < b.milliseconds)
return EARLIER;
if (a.milliseconds > b.milliseconds)
return LATER;
return SAMETIME;
}
#define HALFMONTH ((unsigned long) 1<<31)
_X_EXPORT TimeStamp
ClientTimeToServerTime(CARD32 c)
{
TimeStamp ts;
if (c == CurrentTime)
return currentTime;
ts.months = currentTime.months;
ts.milliseconds = c;
if (c > currentTime.milliseconds)
{
if (((unsigned long) c - currentTime.milliseconds) > HALFMONTH)
ts.months -= 1;
}
else if (c < currentTime.milliseconds)
{
if (((unsigned long)currentTime.milliseconds - c) > HALFMONTH)
ts.months += 1;
}
return ts;
}
static unsigned char
ISOLatin1ToLower (unsigned char source)
{
unsigned char dest;
if ((source >= XK_A) && (source <= XK_Z))
dest = source + (XK_a - XK_A);
else if ((source >= XK_Agrave) && (source <= XK_Odiaeresis))
dest = source + (XK_agrave - XK_Agrave);
else if ((source >= XK_Ooblique) && (source <= XK_Thorn))
dest = source + (XK_oslash - XK_Ooblique);
else
dest = source;
return dest;
}
_X_EXPORT void
CopyISOLatin1Lowered(unsigned char *dest, unsigned char *source, int length)
{
int i;
for (i = 0; i < length; i++, source++, dest++)
*dest = ISOLatin1ToLower (*source);
*dest = '\0';
}
int
CompareISOLatin1Lowered(unsigned char *s1, int s1len,
unsigned char *s2, int s2len)
{
unsigned char c1, c2;
for (;;)
{
c1 = s1len-- ? *s1++ : '\0';
c2 = s2len-- ? *s2++ : '\0';
if (!c1 ||
(c1 != c2 &&
(c1 = ISOLatin1ToLower (c1)) != (c2 = ISOLatin1ToLower (c2))))
break;
}
return (int) c1 - (int) c2;
}
_X_EXPORT int
dixLookupDrawable(DrawablePtr *pDraw, XID id, ClientPtr client,
Mask type, Mask access)
{
DrawablePtr pTmp;
RESTYPE rtype;
*pDraw = NULL;
client->errorValue = id;
if (id == INVALID)
return BadDrawable;
if (id == client->lastDrawableID) {
pTmp = client->lastDrawable;
rtype = (type & M_WINDOW) ? RT_WINDOW : RT_PIXMAP;
if (!XaceHook(XACE_RESOURCE_ACCESS, client, id, rtype, access, pTmp))
return BadDrawable;
} else
pTmp = (DrawablePtr)SecurityLookupIDByClass(client, id, RC_DRAWABLE,
access);
if (!pTmp)
return BadDrawable;
if (!((1 << pTmp->type) & (type ? type : M_DRAWABLE)))
return BadMatch;
if (type & M_DRAWABLE) {
client->lastDrawable = pTmp;
client->lastDrawableID = id;
client->lastGCID = INVALID;
client->lastGC = (GCPtr)NULL;
}
*pDraw = pTmp;
return Success;
}
_X_EXPORT int
dixLookupWindow(WindowPtr *pWin, XID id, ClientPtr client, Mask access)
{
int rc;
rc = dixLookupDrawable((DrawablePtr*)pWin, id, client, M_WINDOW, access);
return (rc == BadDrawable) ? BadWindow : rc;
}
_X_EXPORT int
dixLookupGC(GCPtr *pGC, XID id, ClientPtr client, Mask access)
{
GCPtr pTmp = (GCPtr)SecurityLookupIDByType(client, id, RT_GC, access);
if (pTmp) {
*pGC = pTmp;
return Success;
}
client->errorValue = id;
*pGC = NULL;
return BadGC;
}
_X_EXPORT int
dixLookupClient(ClientPtr *pClient, XID rid, ClientPtr client, Mask access)
{
pointer pRes = (pointer)SecurityLookupIDByClass(client, rid, RC_ANY,
access);
int clientIndex = CLIENT_ID(rid);
if(client)
client->errorValue = rid;
if (clientIndex && pRes && clients[clientIndex] && !(rid & SERVER_BIT)) {
*pClient = clients[clientIndex];
return Success;
}
*pClient = NULL;
return BadValue;
}
_X_EXPORT _X_DEPRECATED WindowPtr
SecurityLookupWindow(XID id, ClientPtr client, Mask access_mode)
{
WindowPtr pWin;
int i = dixLookupWindow(&pWin, id, client, access_mode);
static int warn = 1;
if (warn-- > 0)
ErrorF("Warning: LookupWindow()/SecurityLookupWindow() "
"are deprecated. Please convert your driver/module "
"to use dixLookupWindow().\n");
return (i == Success) ? pWin : NULL;
}
_X_EXPORT _X_DEPRECATED WindowPtr
LookupWindow(XID id, ClientPtr client)
{
return SecurityLookupWindow(id, client, DixUnknownAccess);
}
_X_EXPORT _X_DEPRECATED pointer
SecurityLookupDrawable(XID id, ClientPtr client, Mask access_mode)
{
DrawablePtr pDraw;
int i = dixLookupDrawable(&pDraw, id, client, M_DRAWABLE, access_mode);
static int warn = 1;
if (warn-- > 0)
ErrorF("Warning: LookupDrawable()/SecurityLookupDrawable() "
"are deprecated. Please convert your driver/module "
"to use dixLookupDrawable().\n");
return (i == Success) ? pDraw : NULL;
}
_X_EXPORT _X_DEPRECATED pointer
LookupDrawable(XID id, ClientPtr client)
{
return SecurityLookupDrawable(id, client, DixUnknownAccess);
}
_X_EXPORT _X_DEPRECATED ClientPtr
LookupClient(XID id, ClientPtr client)
{
ClientPtr pClient;
int i = dixLookupClient(&pClient, id, client, DixUnknownAccess);
static int warn = 1;
if (warn-- > 0)
ErrorF("Warning: LookupClient() is deprecated. Please convert your "
"driver/module to use dixLookupClient().\n");
return (i == Success) ? pClient : NULL;
}
int
AlterSaveSetForClient(ClientPtr client, WindowPtr pWin, unsigned mode,
Bool toRoot, Bool remap)
{
int numnow;
SaveSetElt *pTmp = NULL;
int j;
numnow = client->numSaved;
j = 0;
if (numnow)
{
pTmp = client->saveSet;
while ((j < numnow) && (SaveSetWindow(pTmp[j]) != (pointer)pWin))
j++;
}
if (mode == SetModeInsert)
{
if (j < numnow)
return(Success);
numnow++;
pTmp = (SaveSetElt *)xrealloc(client->saveSet, sizeof(*pTmp) * numnow);
if (!pTmp)
return(BadAlloc);
client->saveSet = pTmp;
client->numSaved = numnow;
SaveSetAssignWindow(client->saveSet[numnow - 1], pWin);
SaveSetAssignToRoot(client->saveSet[numnow - 1], toRoot);
SaveSetAssignRemap(client->saveSet[numnow - 1], remap);
return(Success);
}
else if ((mode == SetModeDelete) && (j < numnow))
{
while (j < numnow-1)
{
pTmp[j] = pTmp[j+1];
j++;
}
numnow--;
if (numnow)
{
pTmp = (SaveSetElt *)xrealloc(client->saveSet, sizeof(*pTmp) * numnow);
if (pTmp)
client->saveSet = pTmp;
}
else
{
xfree(client->saveSet);
client->saveSet = (SaveSetElt *)NULL;
}
client->numSaved = numnow;
return(Success);
}
return(Success);
}
void
DeleteWindowFromAnySaveSet(WindowPtr pWin)
{
int i;
ClientPtr client;
for (i = 0; i< currentMaxClients; i++)
{
client = clients[i];
if (client && client->numSaved)
(void)AlterSaveSetForClient(client, pWin, SetModeDelete, FALSE, TRUE);
}
}
_X_EXPORT void
NoopDDA(void)
{
}
typedef struct _BlockHandler {
BlockHandlerProcPtr BlockHandler;
WakeupHandlerProcPtr WakeupHandler;
pointer blockData;
Bool deleted;
} BlockHandlerRec, *BlockHandlerPtr;
static BlockHandlerPtr handlers;
static int numHandlers;
static int sizeHandlers;
static Bool inHandler;
static Bool handlerDeleted;
void
BlockHandler(pointer pTimeout, pointer pReadmask)
{
int i, j;
++inHandler;
for (i = 0; i < screenInfo.numScreens; i++)
(* screenInfo.screens[i]->BlockHandler)(i,
screenInfo.screens[i]->blockData,
pTimeout, pReadmask);
for (i = 0; i < numHandlers; i++)
(*handlers[i].BlockHandler) (handlers[i].blockData,
pTimeout, pReadmask);
if (handlerDeleted)
{
for (i = 0; i < numHandlers;)
if (handlers[i].deleted)
{
for (j = i; j < numHandlers - 1; j++)
handlers[j] = handlers[j+1];
numHandlers--;
}
else
i++;
handlerDeleted = FALSE;
}
--inHandler;
}
void
WakeupHandler(int result, pointer pReadmask)
{
int i, j;
++inHandler;
for (i = numHandlers - 1; i >= 0; i--)
(*handlers[i].WakeupHandler) (handlers[i].blockData,
result, pReadmask);
for (i = 0; i < screenInfo.numScreens; i++)
(* screenInfo.screens[i]->WakeupHandler)(i,
screenInfo.screens[i]->wakeupData,
result, pReadmask);
if (handlerDeleted)
{
for (i = 0; i < numHandlers;)
if (handlers[i].deleted)
{
for (j = i; j < numHandlers - 1; j++)
handlers[j] = handlers[j+1];
numHandlers--;
}
else
i++;
handlerDeleted = FALSE;
}
--inHandler;
}
_X_EXPORT Bool
RegisterBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler,
WakeupHandlerProcPtr wakeupHandler,
pointer blockData)
{
BlockHandlerPtr new;
if (numHandlers >= sizeHandlers)
{
new = (BlockHandlerPtr) xrealloc (handlers, (numHandlers + 1) *
sizeof (BlockHandlerRec));
if (!new)
return FALSE;
handlers = new;
sizeHandlers = numHandlers + 1;
}
handlers[numHandlers].BlockHandler = blockHandler;
handlers[numHandlers].WakeupHandler = wakeupHandler;
handlers[numHandlers].blockData = blockData;
handlers[numHandlers].deleted = FALSE;
numHandlers = numHandlers + 1;
return TRUE;
}
_X_EXPORT void
RemoveBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler,
WakeupHandlerProcPtr wakeupHandler,
pointer blockData)
{
int i;
for (i = 0; i < numHandlers; i++)
if (handlers[i].BlockHandler == blockHandler &&
handlers[i].WakeupHandler == wakeupHandler &&
handlers[i].blockData == blockData)
{
if (inHandler)
{
handlerDeleted = TRUE;
handlers[i].deleted = TRUE;
}
else
{
for (; i < numHandlers - 1; i++)
handlers[i] = handlers[i+1];
numHandlers--;
}
break;
}
}
void
InitBlockAndWakeupHandlers (void)
{
xfree (handlers);
handlers = (BlockHandlerPtr) 0;
numHandlers = 0;
sizeHandlers = 0;
}
WorkQueuePtr workQueue;
static WorkQueuePtr *workQueueLast = &workQueue;
void
ProcessWorkQueue(void)
{
WorkQueuePtr q, *p;
p = &workQueue;
while ((q = *p))
{
if ((*q->function) (q->client, q->closure))
{
*p = q->next;
xfree (q);
}
else
{
p = &q->next;
}
}
workQueueLast = p;
}
void
ProcessWorkQueueZombies(void)
{
WorkQueuePtr q, *p;
p = &workQueue;
while ((q = *p))
{
if (q->client && q->client->clientGone)
{
(void) (*q->function) (q->client, q->closure);
*p = q->next;
xfree (q);
}
else
{
p = &q->next;
}
}
workQueueLast = p;
}
_X_EXPORT Bool
QueueWorkProc (
Bool (*function)(ClientPtr , pointer ),
ClientPtr client, pointer closure)
{
WorkQueuePtr q;
q = (WorkQueuePtr) xalloc (sizeof *q);
if (!q)
return FALSE;
q->function = function;
q->client = client;
q->closure = closure;
q->next = NULL;
*workQueueLast = q;
workQueueLast = &q->next;
return TRUE;
}
typedef struct _SleepQueue {
struct _SleepQueue *next;
ClientPtr client;
ClientSleepProcPtr function;
pointer closure;
} SleepQueueRec, *SleepQueuePtr;
static SleepQueuePtr sleepQueue = NULL;
_X_EXPORT Bool
ClientSleep (ClientPtr client, ClientSleepProcPtr function, pointer closure)
{
SleepQueuePtr q;
q = (SleepQueuePtr) xalloc (sizeof *q);
if (!q)
return FALSE;
IgnoreClient (client);
q->next = sleepQueue;
q->client = client;
q->function = function;
q->closure = closure;
sleepQueue = q;
return TRUE;
}
Bool
ClientSignal (ClientPtr client)
{
SleepQueuePtr q;
for (q = sleepQueue; q; q = q->next)
if (q->client == client)
{
return QueueWorkProc (q->function, q->client, q->closure);
}
return FALSE;
}
_X_EXPORT void
ClientWakeup (ClientPtr client)
{
SleepQueuePtr q, *prev;
prev = &sleepQueue;
while ( (q = *prev) )
{
if (q->client == client)
{
*prev = q->next;
xfree (q);
if (client->clientGone)
;
else
AttendClient (client);
break;
}
prev = &q->next;
}
}
Bool
ClientIsAsleep (ClientPtr client)
{
SleepQueuePtr q;
for (q = sleepQueue; q; q = q->next)
if (q->client == client)
return TRUE;
return FALSE;
}
static int numCallbackListsToCleanup = 0;
static CallbackListPtr **listsToCleanup = NULL;
static Bool
_AddCallback(
CallbackListPtr *pcbl,
CallbackProcPtr callback,
pointer data)
{
CallbackPtr cbr;
cbr = (CallbackPtr) xalloc(sizeof(CallbackRec));
if (!cbr)
return FALSE;
cbr->proc = callback;
cbr->data = data;
cbr->next = (*pcbl)->list;
cbr->deleted = FALSE;
(*pcbl)->list = cbr;
return TRUE;
}
static Bool
_DeleteCallback(
CallbackListPtr *pcbl,
CallbackProcPtr callback,
pointer data)
{
CallbackListPtr cbl = *pcbl;
CallbackPtr cbr, pcbr;
for (pcbr = NULL, cbr = cbl->list;
cbr != NULL;
pcbr = cbr, cbr = cbr->next)
{
if ((cbr->proc == callback) && (cbr->data == data))
break;
}
if (cbr != NULL)
{
if (cbl->inCallback)
{
++(cbl->numDeleted);
cbr->deleted = TRUE;
}
else
{
if (pcbr == NULL)
cbl->list = cbr->next;
else
pcbr->next = cbr->next;
xfree(cbr);
}
return TRUE;
}
return FALSE;
}
static void
_CallCallbacks(
CallbackListPtr *pcbl,
pointer call_data)
{
CallbackListPtr cbl = *pcbl;
CallbackPtr cbr, pcbr;
++(cbl->inCallback);
for (cbr = cbl->list; cbr != NULL; cbr = cbr->next)
{
(*(cbr->proc)) (pcbl, cbr->data, call_data);
}
--(cbl->inCallback);
if (cbl->inCallback) return;
if (cbl->deleted)
{
DeleteCallbackList(pcbl);
return;
}
if (cbl->numDeleted)
{
for (pcbr = NULL, cbr = cbl->list; (cbr != NULL) && cbl->numDeleted; )
{
if (cbr->deleted)
{
if (pcbr)
{
cbr = cbr->next;
xfree(pcbr->next);
pcbr->next = cbr;
} else
{
cbr = cbr->next;
xfree(cbl->list);
cbl->list = cbr;
}
cbl->numDeleted--;
}
else
{
pcbr = cbr;
cbr = cbr->next;
}
}
}
}
static void
_DeleteCallbackList(
CallbackListPtr *pcbl)
{
CallbackListPtr cbl = *pcbl;
CallbackPtr cbr, nextcbr;
int i;
if (cbl->inCallback)
{
cbl->deleted = TRUE;
return;
}
for (i = 0; i < numCallbackListsToCleanup; i++)
{
if ((listsToCleanup[i] = pcbl) != 0)
{
listsToCleanup[i] = NULL;
break;
}
}
for (cbr = cbl->list; cbr != NULL; cbr = nextcbr)
{
nextcbr = cbr->next;
xfree(cbr);
}
xfree(cbl);
*pcbl = NULL;
}
static CallbackFuncsRec default_cbfuncs =
{
_AddCallback,
_DeleteCallback,
_CallCallbacks,
_DeleteCallbackList
};
static Bool
CreateCallbackList(CallbackListPtr *pcbl, CallbackFuncsPtr cbfuncs)
{
CallbackListPtr cbl;
int i;
if (!pcbl) return FALSE;
cbl = (CallbackListPtr) xalloc(sizeof(CallbackListRec));
if (!cbl) return FALSE;
cbl->funcs = cbfuncs ? *cbfuncs : default_cbfuncs;
cbl->inCallback = 0;
cbl->deleted = FALSE;
cbl->numDeleted = 0;
cbl->list = NULL;
*pcbl = cbl;
for (i = 0; i < numCallbackListsToCleanup; i++)
{
if (!listsToCleanup[i])
{
listsToCleanup[i] = pcbl;
return TRUE;
}
}
listsToCleanup = (CallbackListPtr **)xnfrealloc(listsToCleanup,
sizeof(CallbackListPtr *) * (numCallbackListsToCleanup+1));
listsToCleanup[numCallbackListsToCleanup] = pcbl;
numCallbackListsToCleanup++;
return TRUE;
}
_X_EXPORT Bool
AddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data)
{
if (!pcbl) return FALSE;
if (!*pcbl)
{
if (!CreateCallbackList(pcbl, (CallbackFuncsPtr)NULL))
return FALSE;
}
return ((*(*pcbl)->funcs.AddCallback) (pcbl, callback, data));
}
_X_EXPORT Bool
DeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data)
{
if (!pcbl || !*pcbl) return FALSE;
return ((*(*pcbl)->funcs.DeleteCallback) (pcbl, callback, data));
}
void
CallCallbacks(CallbackListPtr *pcbl, pointer call_data)
{
if (!pcbl || !*pcbl) return;
(*(*pcbl)->funcs.CallCallbacks) (pcbl, call_data);
}
void
DeleteCallbackList(CallbackListPtr *pcbl)
{
if (!pcbl || !*pcbl) return;
(*(*pcbl)->funcs.DeleteCallbackList) (pcbl);
}
void
InitCallbackManager(void)
{
int i;
for (i = 0; i < numCallbackListsToCleanup; i++)
{
DeleteCallbackList(listsToCleanup[i]);
}
if (listsToCleanup) xfree(listsToCleanup);
numCallbackListsToCleanup = 0;
listsToCleanup = NULL;
}