1/***********************************************************
2
3Copyright 1987, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
26
27                        All Rights Reserved
28
29Permission to use, copy, modify, and distribute this software and its
30documentation for any purpose and without fee is hereby granted,
31provided that the above copyright notice appear in all copies and that
32both that copyright notice and this permission notice appear in
33supporting documentation, and that the name of Digital not be
34used in advertising or publicity pertaining to distribution of the
35software without specific, written prior permission.
36
37DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43SOFTWARE.
44
45******************************************************************/
46
47/*
48
49(c)Copyright 1988,1991 Adobe Systems Incorporated. All rights reserved.
50
51Permission to use, copy, modify, distribute, and sublicense this software and its
52documentation for any purpose and without fee is hereby granted, provided that
53the above copyright notices appear in all copies and that both those copyright
54notices and this permission notice appear in supporting documentation and that
55the name of Adobe Systems Incorporated not be used in advertising or publicity
56pertaining to distribution of the software without specific, written prior
57permission.  No trademark license to use the Adobe trademarks is hereby
58granted.  If the Adobe trademark "Display PostScript"(tm) is used to describe
59this software, its functionality or for any other purpose, such use shall be
60limited to a statement that this software works in conjunction with the Display
61PostScript system.  Proper trademark attribution to reflect Adobe's ownership
62of the trademark shall be given whenever any such reference to the Display
63PostScript system is made.
64
65ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR ANY
66PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.  ADOBE
67DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
68WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-
69INFRINGEMENT OF THIRD PARTY RIGHTS.  IN NO EVENT SHALL ADOBE BE LIABLE TO YOU
70OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
71DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT,NEGLIGENCE, STRICT
72LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN CONNECTION WITH THE USE OR
73PERFORMANCE OF THIS SOFTWARE.  ADOBE WILL NOT PROVIDE ANY TRAINING OR OTHER
74SUPPORT FOR THE SOFTWARE.
75
76Adobe, PostScript, and Display PostScript are trademarks of Adobe Systems
77Incorporated which may be registered in certain jurisdictions.
78
79Author:  Adobe Systems Incorporated
80
81*/
82
83#ifdef HAVE_DIX_CONFIG_H
84#include <dix-config.h>
85#endif
86
87#include <X11/X.h>
88#include <X11/Xmd.h>
89#include "misc.h"
90#include "windowstr.h"
91#include "dixstruct.h"
92#include "pixmapstr.h"
93#include "gcstruct.h"
94#include "scrnintstr.h"
95#define  XK_LATIN1
96#include <X11/keysymdef.h>
97#include "xace.h"
98
99/*
100 * CompareTimeStamps returns -1, 0, or +1 depending on if the first
101 * argument is less than, equal to or greater than the second argument.
102 */
103
104int
105CompareTimeStamps(TimeStamp a, TimeStamp b)
106{
107    if (a.months < b.months)
108        return EARLIER;
109    if (a.months > b.months)
110        return LATER;
111    if (a.milliseconds < b.milliseconds)
112        return EARLIER;
113    if (a.milliseconds > b.milliseconds)
114        return LATER;
115    return SAMETIME;
116}
117
118/*
119 * convert client times to server TimeStamps
120 */
121
122#define HALFMONTH ((unsigned long) 1<<31)
123TimeStamp
124ClientTimeToServerTime(CARD32 c)
125{
126    TimeStamp ts;
127
128    if (c == CurrentTime)
129        return currentTime;
130    ts.months = currentTime.months;
131    ts.milliseconds = c;
132    if (c > currentTime.milliseconds) {
133        if (((unsigned long) c - currentTime.milliseconds) > HALFMONTH)
134            ts.months -= 1;
135    }
136    else if (c < currentTime.milliseconds) {
137        if (((unsigned long) currentTime.milliseconds - c) > HALFMONTH)
138            ts.months += 1;
139    }
140    return ts;
141}
142
143/*
144 * ISO Latin-1 case conversion routine
145 *
146 * this routine always null-terminates the result, so
147 * beware of too-small buffers
148 */
149
150static unsigned char
151ISOLatin1ToLower(unsigned char source)
152{
153    unsigned char dest;
154
155    if ((source >= XK_A) && (source <= XK_Z))
156        dest = source + (XK_a - XK_A);
157    else if ((source >= XK_Agrave) && (source <= XK_Odiaeresis))
158        dest = source + (XK_agrave - XK_Agrave);
159    else if ((source >= XK_Ooblique) && (source <= XK_Thorn))
160        dest = source + (XK_oslash - XK_Ooblique);
161    else
162        dest = source;
163    return dest;
164}
165
166int
167CompareISOLatin1Lowered(const unsigned char *s1, int s1len,
168                        const unsigned char *s2, int s2len)
169{
170    unsigned char c1, c2;
171
172    for (;;) {
173        /* note -- compare against zero so that -1 ignores len */
174        c1 = s1len-- ? *s1++ : '\0';
175        c2 = s2len-- ? *s2++ : '\0';
176        if (!c1 ||
177            (c1 != c2 &&
178             (c1 = ISOLatin1ToLower(c1)) != (c2 = ISOLatin1ToLower(c2))))
179            break;
180    }
181    return (int) c1 - (int) c2;
182}
183
184/*
185 * dixLookupWindow and dixLookupDrawable:
186 * Look up the window/drawable taking into account the client doing the
187 * lookup, the type of drawable desired, and the type of access desired.
188 * Return Success with *pDraw set if the window/drawable exists and the client
189 * is allowed access, else return an error code with *pDraw set to NULL.  The
190 * access mask values are defined in resource.h.  The type mask values are
191 * defined in pixmap.h, with zero equivalent to M_DRAWABLE.
192 */
193int
194dixLookupDrawable(DrawablePtr *pDraw, XID id, ClientPtr client,
195                  Mask type, Mask access)
196{
197    DrawablePtr pTmp;
198    int rc;
199
200    *pDraw = NULL;
201
202    rc = dixLookupResourceByClass((void **) &pTmp, id, RC_DRAWABLE, client,
203                                  access);
204
205    if (rc != Success)
206        client->errorValue = id;
207
208    if (rc == BadValue)
209        return BadDrawable;
210    if (rc != Success)
211        return rc;
212    if (!((1 << pTmp->type) & (type ? type : M_DRAWABLE)))
213        return BadMatch;
214
215    *pDraw = pTmp;
216    return Success;
217}
218
219int
220dixLookupWindow(WindowPtr *pWin, XID id, ClientPtr client, Mask access)
221{
222    int rc;
223
224    rc = dixLookupDrawable((DrawablePtr *) pWin, id, client, M_WINDOW, access);
225    /* dixLookupDrawable returns BadMatch iff id is a valid Drawable
226       but is not a Window. Users of dixLookupWindow expect a BadWindow
227       error in this case; they don't care that it's a valid non-Window XID */
228    if (rc == BadMatch)
229        rc = BadWindow;
230    /* Similarly, users of dixLookupWindow don't want BadDrawable. */
231    if (rc == BadDrawable)
232        rc = BadWindow;
233    return rc;
234}
235
236int
237dixLookupGC(GCPtr *pGC, XID id, ClientPtr client, Mask access)
238{
239    return dixLookupResourceByType((void **) pGC, id, RT_GC, client, access);
240}
241
242int
243dixLookupFontable(FontPtr *pFont, XID id, ClientPtr client, Mask access)
244{
245    int rc;
246    GC *pGC;
247
248    client->errorValue = id;    /* EITHER font or gc */
249    rc = dixLookupResourceByType((void **) pFont, id, RT_FONT, client,
250                                 access);
251    if (rc != BadFont)
252        return rc;
253    rc = dixLookupResourceByType((void **) &pGC, id, RT_GC, client, access);
254    if (rc == BadGC)
255        return BadFont;
256    if (rc == Success)
257        *pFont = pGC->font;
258    return rc;
259}
260
261int
262dixLookupClient(ClientPtr *pClient, XID rid, ClientPtr client, Mask access)
263{
264    void *pRes;
265    int rc = BadValue, clientIndex = CLIENT_ID(rid);
266
267    if (!clientIndex || !clients[clientIndex] || (rid & SERVER_BIT))
268        goto bad;
269
270    rc = dixLookupResourceByClass(&pRes, rid, RC_ANY, client, DixGetAttrAccess);
271    if (rc != Success)
272        goto bad;
273
274    rc = XaceHook(XACE_CLIENT_ACCESS, client, clients[clientIndex], access);
275    if (rc != Success)
276        goto bad;
277
278    *pClient = clients[clientIndex];
279    return Success;
280 bad:
281    if (client)
282        client->errorValue = rid;
283    *pClient = NULL;
284    return rc;
285}
286
287int
288AlterSaveSetForClient(ClientPtr client, WindowPtr pWin, unsigned mode,
289                      Bool toRoot, Bool map)
290{
291    int numnow;
292    SaveSetElt *pTmp = NULL;
293    int j;
294
295    numnow = client->numSaved;
296    j = 0;
297    if (numnow) {
298        pTmp = client->saveSet;
299        while ((j < numnow) && (SaveSetWindow(pTmp[j]) != (void *) pWin))
300            j++;
301    }
302    if (mode == SetModeInsert) {
303        if (j < numnow)         /* duplicate */
304            return Success;
305        numnow++;
306        pTmp = (SaveSetElt *) realloc(client->saveSet, sizeof(*pTmp) * numnow);
307        if (!pTmp)
308            return BadAlloc;
309        client->saveSet = pTmp;
310        client->numSaved = numnow;
311        SaveSetAssignWindow(client->saveSet[numnow - 1], pWin);
312        SaveSetAssignToRoot(client->saveSet[numnow - 1], toRoot);
313        SaveSetAssignMap(client->saveSet[numnow - 1], map);
314        return Success;
315    }
316    else if ((mode == SetModeDelete) && (j < numnow)) {
317        while (j < numnow - 1) {
318            pTmp[j] = pTmp[j + 1];
319            j++;
320        }
321        numnow--;
322        if (numnow) {
323            pTmp =
324                (SaveSetElt *) realloc(client->saveSet, sizeof(*pTmp) * numnow);
325            if (pTmp)
326                client->saveSet = pTmp;
327        }
328        else {
329            free(client->saveSet);
330            client->saveSet = (SaveSetElt *) NULL;
331        }
332        client->numSaved = numnow;
333        return Success;
334    }
335    return Success;
336}
337
338void
339DeleteWindowFromAnySaveSet(WindowPtr pWin)
340{
341    int i;
342    ClientPtr client;
343
344    for (i = 0; i < currentMaxClients; i++) {
345        client = clients[i];
346        if (client && client->numSaved)
347            (void) AlterSaveSetForClient(client, pWin, SetModeDelete, FALSE,
348                                         TRUE);
349    }
350}
351
352/* No-op Don't Do Anything : sometimes we need to be able to call a procedure
353 * that doesn't do anything.  For example, on screen with only static
354 * colormaps, if someone calls install colormap, it's easier to have a dummy
355 * procedure to call than to check if there's a procedure
356 */
357void
358NoopDDA(void)
359{
360}
361
362typedef struct _BlockHandler {
363    ServerBlockHandlerProcPtr BlockHandler;
364    ServerWakeupHandlerProcPtr WakeupHandler;
365    void *blockData;
366    Bool deleted;
367} BlockHandlerRec, *BlockHandlerPtr;
368
369static BlockHandlerPtr handlers;
370static int numHandlers;
371static int sizeHandlers;
372static Bool inHandler;
373static Bool handlerDeleted;
374
375/**
376 *
377 *  \param pTimeout   DIX doesn't want to know how OS represents time
378 *  \param pReadMask  nor how it represents the det of descriptors
379 */
380void
381BlockHandler(void *pTimeout)
382{
383    int i, j;
384
385    ++inHandler;
386    for (i = 0; i < numHandlers; i++)
387        if (!handlers[i].deleted)
388            (*handlers[i].BlockHandler) (handlers[i].blockData, pTimeout);
389
390    for (i = 0; i < screenInfo.numGPUScreens; i++)
391        (*screenInfo.gpuscreens[i]->BlockHandler) (screenInfo.gpuscreens[i], pTimeout);
392
393    for (i = 0; i < screenInfo.numScreens; i++)
394        (*screenInfo.screens[i]->BlockHandler) (screenInfo.screens[i], pTimeout);
395
396    if (handlerDeleted) {
397        for (i = 0; i < numHandlers;)
398            if (handlers[i].deleted) {
399                for (j = i; j < numHandlers - 1; j++)
400                    handlers[j] = handlers[j + 1];
401                numHandlers--;
402            }
403            else
404                i++;
405        handlerDeleted = FALSE;
406    }
407    --inHandler;
408}
409
410/**
411 *
412 *  \param result    32 bits of undefined result from the wait
413 *  \param pReadmask the resulting descriptor mask
414 */
415void
416WakeupHandler(int result)
417{
418    int i, j;
419
420    ++inHandler;
421    for (i = 0; i < screenInfo.numScreens; i++)
422        (*screenInfo.screens[i]->WakeupHandler) (screenInfo.screens[i], result);
423    for (i = 0; i < screenInfo.numGPUScreens; i++)
424        (*screenInfo.gpuscreens[i]->WakeupHandler) (screenInfo.gpuscreens[i], result);
425    for (i = numHandlers - 1; i >= 0; i--)
426        if (!handlers[i].deleted)
427            (*handlers[i].WakeupHandler) (handlers[i].blockData, result);
428    if (handlerDeleted) {
429        for (i = 0; i < numHandlers;)
430            if (handlers[i].deleted) {
431                for (j = i; j < numHandlers - 1; j++)
432                    handlers[j] = handlers[j + 1];
433                numHandlers--;
434            }
435            else
436                i++;
437        handlerDeleted = FALSE;
438    }
439    --inHandler;
440}
441
442/**
443 * Reentrant with BlockHandler and WakeupHandler, except wakeup won't
444 * get called until next time
445 */
446Bool
447RegisterBlockAndWakeupHandlers(ServerBlockHandlerProcPtr blockHandler,
448                               ServerWakeupHandlerProcPtr wakeupHandler,
449                               void *blockData)
450{
451    BlockHandlerPtr new;
452
453    if (numHandlers >= sizeHandlers) {
454        new = (BlockHandlerPtr) realloc(handlers, (numHandlers + 1) *
455                                        sizeof(BlockHandlerRec));
456        if (!new)
457            return FALSE;
458        handlers = new;
459        sizeHandlers = numHandlers + 1;
460    }
461    handlers[numHandlers].BlockHandler = blockHandler;
462    handlers[numHandlers].WakeupHandler = wakeupHandler;
463    handlers[numHandlers].blockData = blockData;
464    handlers[numHandlers].deleted = FALSE;
465    numHandlers = numHandlers + 1;
466    return TRUE;
467}
468
469void
470RemoveBlockAndWakeupHandlers(ServerBlockHandlerProcPtr blockHandler,
471                             ServerWakeupHandlerProcPtr wakeupHandler,
472                             void *blockData)
473{
474    int i;
475
476    for (i = 0; i < numHandlers; i++)
477        if (handlers[i].BlockHandler == blockHandler &&
478            handlers[i].WakeupHandler == wakeupHandler &&
479            handlers[i].blockData == blockData) {
480            if (inHandler) {
481                handlerDeleted = TRUE;
482                handlers[i].deleted = TRUE;
483            }
484            else {
485                for (; i < numHandlers - 1; i++)
486                    handlers[i] = handlers[i + 1];
487                numHandlers--;
488            }
489            break;
490        }
491}
492
493void
494InitBlockAndWakeupHandlers(void)
495{
496    free(handlers);
497    handlers = (BlockHandlerPtr) 0;
498    numHandlers = 0;
499    sizeHandlers = 0;
500}
501
502/*
503 * A general work queue.  Perform some task before the server
504 * sleeps for input.
505 */
506
507WorkQueuePtr workQueue;
508static WorkQueuePtr *workQueueLast = &workQueue;
509
510void
511ClearWorkQueue(void)
512{
513    WorkQueuePtr q, *p;
514
515    p = &workQueue;
516    while ((q = *p)) {
517        *p = q->next;
518        free(q);
519    }
520    workQueueLast = p;
521}
522
523void
524ProcessWorkQueue(void)
525{
526    WorkQueuePtr q, *p;
527
528    p = &workQueue;
529    /*
530     * Scan the work queue once, calling each function.  Those
531     * which return TRUE are removed from the queue, otherwise
532     * they will be called again.  This must be reentrant with
533     * QueueWorkProc.
534     */
535    while ((q = *p)) {
536        if ((*q->function) (q->client, q->closure)) {
537            /* remove q from the list */
538            *p = q->next;       /* don't fetch until after func called */
539            free(q);
540        }
541        else {
542            p = &q->next;       /* don't fetch until after func called */
543        }
544    }
545    workQueueLast = p;
546}
547
548void
549ProcessWorkQueueZombies(void)
550{
551    WorkQueuePtr q, *p;
552
553    p = &workQueue;
554    while ((q = *p)) {
555        if (q->client && q->client->clientGone) {
556            (void) (*q->function) (q->client, q->closure);
557            /* remove q from the list */
558            *p = q->next;       /* don't fetch until after func called */
559            free(q);
560        }
561        else {
562            p = &q->next;       /* don't fetch until after func called */
563        }
564    }
565    workQueueLast = p;
566}
567
568Bool
569QueueWorkProc(Bool (*function) (ClientPtr pClient, void *closure),
570              ClientPtr client, void *closure)
571{
572    WorkQueuePtr q;
573
574    q = malloc(sizeof *q);
575    if (!q)
576        return FALSE;
577    q->function = function;
578    q->client = client;
579    q->closure = closure;
580    q->next = NULL;
581    *workQueueLast = q;
582    workQueueLast = &q->next;
583    return TRUE;
584}
585
586/*
587 * Manage a queue of sleeping clients, awakening them
588 * when requested, by using the OS functions IgnoreClient
589 * and AttendClient.  Note that this *ignores* the troubles
590 * with request data interleaving itself with events, but
591 * we'll leave that until a later time.
592 */
593
594typedef struct _SleepQueue {
595    struct _SleepQueue *next;
596    ClientPtr client;
597    ClientSleepProcPtr function;
598    void *closure;
599} SleepQueueRec, *SleepQueuePtr;
600
601static SleepQueuePtr sleepQueue = NULL;
602
603Bool
604ClientSleep(ClientPtr client, ClientSleepProcPtr function, void *closure)
605{
606    SleepQueuePtr q;
607
608    q = malloc(sizeof *q);
609    if (!q)
610        return FALSE;
611
612    IgnoreClient(client);
613    q->next = sleepQueue;
614    q->client = client;
615    q->function = function;
616    q->closure = closure;
617    sleepQueue = q;
618    return TRUE;
619}
620
621Bool
622ClientSignal(ClientPtr client)
623{
624    SleepQueuePtr q;
625
626    for (q = sleepQueue; q; q = q->next)
627        if (q->client == client) {
628            return QueueWorkProc(q->function, q->client, q->closure);
629        }
630    return FALSE;
631}
632
633int
634ClientSignalAll(ClientPtr client, ClientSleepProcPtr function, void *closure)
635{
636    SleepQueuePtr q;
637    int count = 0;
638
639    for (q = sleepQueue; q; q = q->next) {
640        if (!(client == CLIENT_SIGNAL_ANY || q->client == client))
641            continue;
642
643        if (!(function == CLIENT_SIGNAL_ANY || q->function == function))
644            continue;
645
646        if (!(closure == CLIENT_SIGNAL_ANY || q->closure == closure))
647            continue;
648
649        count += QueueWorkProc(q->function, q->client, q->closure);
650    }
651
652    return count;
653}
654
655void
656ClientWakeup(ClientPtr client)
657{
658    SleepQueuePtr q, *prev;
659
660    prev = &sleepQueue;
661    while ((q = *prev)) {
662        if (q->client == client) {
663            *prev = q->next;
664            free(q);
665            AttendClient(client);
666            break;
667        }
668        prev = &q->next;
669    }
670}
671
672Bool
673ClientIsAsleep(ClientPtr client)
674{
675    SleepQueuePtr q;
676
677    for (q = sleepQueue; q; q = q->next)
678        if (q->client == client)
679            return TRUE;
680    return FALSE;
681}
682
683/*
684 *  Generic Callback Manager
685 */
686
687/* ===== Private Procedures ===== */
688
689static int numCallbackListsToCleanup = 0;
690static CallbackListPtr **listsToCleanup = NULL;
691
692static Bool
693_AddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, void *data)
694{
695    CallbackPtr cbr;
696
697    cbr = malloc(sizeof(CallbackRec));
698    if (!cbr)
699        return FALSE;
700    cbr->proc = callback;
701    cbr->data = data;
702    cbr->next = (*pcbl)->list;
703    cbr->deleted = FALSE;
704    (*pcbl)->list = cbr;
705    return TRUE;
706}
707
708static Bool
709_DeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, void *data)
710{
711    CallbackListPtr cbl = *pcbl;
712    CallbackPtr cbr, pcbr;
713
714    for (pcbr = NULL, cbr = cbl->list; cbr != NULL; pcbr = cbr, cbr = cbr->next) {
715        if ((cbr->proc == callback) && (cbr->data == data))
716            break;
717    }
718    if (cbr != NULL) {
719        if (cbl->inCallback) {
720            ++(cbl->numDeleted);
721            cbr->deleted = TRUE;
722        }
723        else {
724            if (pcbr == NULL)
725                cbl->list = cbr->next;
726            else
727                pcbr->next = cbr->next;
728            free(cbr);
729        }
730        return TRUE;
731    }
732    return FALSE;
733}
734
735void
736_CallCallbacks(CallbackListPtr *pcbl, void *call_data)
737{
738    CallbackListPtr cbl = *pcbl;
739    CallbackPtr cbr, pcbr;
740
741    ++(cbl->inCallback);
742    for (cbr = cbl->list; cbr != NULL; cbr = cbr->next) {
743        (*(cbr->proc)) (pcbl, cbr->data, call_data);
744    }
745    --(cbl->inCallback);
746
747    if (cbl->inCallback)
748        return;
749
750    /* Was the entire list marked for deletion? */
751
752    if (cbl->deleted) {
753        DeleteCallbackList(pcbl);
754        return;
755    }
756
757    /* Were some individual callbacks on the list marked for deletion?
758     * If so, do the deletions.
759     */
760
761    if (cbl->numDeleted) {
762        for (pcbr = NULL, cbr = cbl->list; (cbr != NULL) && cbl->numDeleted;) {
763            if (cbr->deleted) {
764                if (pcbr) {
765                    cbr = cbr->next;
766                    free(pcbr->next);
767                    pcbr->next = cbr;
768                }
769                else {
770                    cbr = cbr->next;
771                    free(cbl->list);
772                    cbl->list = cbr;
773                }
774                cbl->numDeleted--;
775            }
776            else {              /* this one wasn't deleted */
777
778                pcbr = cbr;
779                cbr = cbr->next;
780            }
781        }
782    }
783}
784
785static void
786_DeleteCallbackList(CallbackListPtr *pcbl)
787{
788    CallbackListPtr cbl = *pcbl;
789    CallbackPtr cbr, nextcbr;
790    int i;
791
792    if (cbl->inCallback) {
793        cbl->deleted = TRUE;
794        return;
795    }
796
797    for (i = 0; i < numCallbackListsToCleanup; i++) {
798        if (listsToCleanup[i] == pcbl) {
799            listsToCleanup[i] = NULL;
800            break;
801        }
802    }
803
804    for (cbr = cbl->list; cbr != NULL; cbr = nextcbr) {
805        nextcbr = cbr->next;
806        free(cbr);
807    }
808    free(cbl);
809    *pcbl = NULL;
810}
811
812static Bool
813CreateCallbackList(CallbackListPtr *pcbl)
814{
815    CallbackListPtr cbl;
816    int i;
817
818    if (!pcbl)
819        return FALSE;
820    cbl = malloc(sizeof(CallbackListRec));
821    if (!cbl)
822        return FALSE;
823    cbl->inCallback = 0;
824    cbl->deleted = FALSE;
825    cbl->numDeleted = 0;
826    cbl->list = NULL;
827    *pcbl = cbl;
828
829    for (i = 0; i < numCallbackListsToCleanup; i++) {
830        if (!listsToCleanup[i]) {
831            listsToCleanup[i] = pcbl;
832            return TRUE;
833        }
834    }
835
836    listsToCleanup = (CallbackListPtr **) xnfrealloc(listsToCleanup,
837                                                     sizeof(CallbackListPtr *) *
838                                                     (numCallbackListsToCleanup
839                                                      + 1));
840    listsToCleanup[numCallbackListsToCleanup] = pcbl;
841    numCallbackListsToCleanup++;
842    return TRUE;
843}
844
845/* ===== Public Procedures ===== */
846
847Bool
848AddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, void *data)
849{
850    if (!pcbl)
851        return FALSE;
852    if (!*pcbl) {               /* list hasn't been created yet; go create it */
853        if (!CreateCallbackList(pcbl))
854            return FALSE;
855    }
856    return _AddCallback(pcbl, callback, data);
857}
858
859Bool
860DeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, void *data)
861{
862    if (!pcbl || !*pcbl)
863        return FALSE;
864    return _DeleteCallback(pcbl, callback, data);
865}
866
867void
868DeleteCallbackList(CallbackListPtr *pcbl)
869{
870    if (!pcbl || !*pcbl)
871        return;
872    _DeleteCallbackList(pcbl);
873}
874
875void
876DeleteCallbackManager(void)
877{
878    int i;
879
880    for (i = 0; i < numCallbackListsToCleanup; i++) {
881        DeleteCallbackList(listsToCleanup[i]);
882    }
883    free(listsToCleanup);
884
885    numCallbackListsToCleanup = 0;
886    listsToCleanup = NULL;
887}
888
889void
890InitCallbackManager(void)
891{
892    DeleteCallbackManager();
893}
894
895/**
896 * Coordinates the global GL context used by modules in the X Server
897 * doing rendering with OpenGL.
898 *
899 * When setting a GL context (glXMakeCurrent() or eglMakeCurrent()),
900 * there is an expensive implied glFlush() required by the GLX and EGL
901 * APIs, so modules don't want to have to do it on every request.  But
902 * the individual modules using GL also don't know about each other,
903 * so they have to coordinate who owns the current context.
904 *
905 * When you're about to do a MakeCurrent, you should set this variable
906 * to your context's address, and you can skip MakeCurrent if it's
907 * already set to yours.
908 *
909 * When you're about to do a DestroyContext, you should set this to
910 * NULL if it's set to your context.
911 *
912 * When you're about to do an unbindContext on a DRI driver, you
913 * should set this to NULL.  Despite the unbindContext interface
914 * sounding like it only unbinds the passed in context, it actually
915 * unconditionally clears the dispatch table even if the given
916 * context wasn't current.
917 */
918void *lastGLContext = NULL;
919