~brandontschaefer/+junk/break-x

« back to all changes in this revision

Viewing changes to dix/dixutils.c

  • Committer: Brandon Schaefer
  • Date: 2014-09-30 19:38:40 UTC
  • Revision ID: brandon.schaefer@canonical.com-20140930193840-a65z6qk8ze02cgsb
* Init commit to back this up

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***********************************************************
 
2
 
 
3
Copyright 1987, 1998  The Open Group
 
4
 
 
5
Permission to use, copy, modify, distribute, and sell this software and its
 
6
documentation for any purpose is hereby granted without fee, provided that
 
7
the above copyright notice appear in all copies and that both that
 
8
copyright notice and this permission notice appear in supporting
 
9
documentation.
 
10
 
 
11
The above copyright notice and this permission notice shall be included in
 
12
all copies or substantial portions of the Software.
 
13
 
 
14
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
15
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
16
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 
17
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 
18
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 
19
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
20
 
 
21
Except as contained in this notice, the name of The Open Group shall not be
 
22
used in advertising or otherwise to promote the sale, use or other dealings
 
23
in this Software without prior written authorization from The Open Group.
 
24
 
 
25
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
 
26
 
 
27
                        All Rights Reserved
 
28
 
 
29
Permission to use, copy, modify, and distribute this software and its 
 
30
documentation for any purpose and without fee is hereby granted, 
 
31
provided that the above copyright notice appear in all copies and that
 
32
both that copyright notice and this permission notice appear in 
 
33
supporting documentation, and that the name of Digital not be
 
34
used in advertising or publicity pertaining to distribution of the
 
35
software without specific, written prior permission.  
 
36
 
 
37
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 
38
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
 
39
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
 
40
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 
41
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 
42
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 
43
SOFTWARE.
 
44
 
 
45
******************************************************************/
 
46
 
 
47
/*
 
48
 
 
49
(c)Copyright 1988,1991 Adobe Systems Incorporated. All rights reserved.
 
50
 
 
51
Permission to use, copy, modify, distribute, and sublicense this software and its
 
52
documentation for any purpose and without fee is hereby granted, provided that
 
53
the above copyright notices appear in all copies and that both those copyright
 
54
notices and this permission notice appear in supporting documentation and that
 
55
the name of Adobe Systems Incorporated not be used in advertising or publicity
 
56
pertaining to distribution of the software without specific, written prior
 
57
permission.  No trademark license to use the Adobe trademarks is hereby
 
58
granted.  If the Adobe trademark "Display PostScript"(tm) is used to describe
 
59
this software, its functionality or for any other purpose, such use shall be
 
60
limited to a statement that this software works in conjunction with the Display
 
61
PostScript system.  Proper trademark attribution to reflect Adobe's ownership
 
62
of the trademark shall be given whenever any such reference to the Display
 
63
PostScript system is made.
 
64
 
 
65
ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR ANY
 
66
PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.  ADOBE
 
67
DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
 
68
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-
 
69
INFRINGEMENT OF THIRD PARTY RIGHTS.  IN NO EVENT SHALL ADOBE BE LIABLE TO YOU
 
70
OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
 
71
DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT,NEGLIGENCE, STRICT
 
72
LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 
73
PERFORMANCE OF THIS SOFTWARE.  ADOBE WILL NOT PROVIDE ANY TRAINING OR OTHER
 
74
SUPPORT FOR THE SOFTWARE.
 
75
 
 
76
Adobe, PostScript, and Display PostScript are trademarks of Adobe Systems
 
77
Incorporated which may be registered in certain jurisdictions.
 
78
 
 
79
Author:  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
 
 
104
int
 
105
CompareTimeStamps(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)
 
123
TimeStamp
 
124
ClientTimeToServerTime(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
 
 
150
static unsigned char
 
151
ISOLatin1ToLower(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
 
 
166
int
 
167
CompareISOLatin1Lowered(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
 */
 
193
int
 
194
dixLookupDrawable(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
 
 
219
int
 
220
dixLookupWindow(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
 
 
236
int
 
237
dixLookupGC(GCPtr *pGC, XID id, ClientPtr client, Mask access)
 
238
{
 
239
    return dixLookupResourceByType((void **) pGC, id, RT_GC, client, access);
 
240
}
 
241
 
 
242
int
 
243
dixLookupFontable(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
 
 
261
int
 
262
dixLookupClient(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
 
 
287
int
 
288
AlterSaveSetForClient(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
 
 
338
void
 
339
DeleteWindowFromAnySaveSet(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
 */
 
357
void
 
358
NoopDDA(void)
 
359
{
 
360
}
 
361
 
 
362
typedef struct _BlockHandler {
 
363
    BlockHandlerProcPtr BlockHandler;
 
364
    WakeupHandlerProcPtr WakeupHandler;
 
365
    void *blockData;
 
366
    Bool deleted;
 
367
} BlockHandlerRec, *BlockHandlerPtr;
 
368
 
 
369
static BlockHandlerPtr handlers;
 
370
static int numHandlers;
 
371
static int sizeHandlers;
 
372
static Bool inHandler;
 
373
static 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
 */
 
380
void
 
381
BlockHandler(void *pTimeout, void *pReadmask)
 
382
{
 
383
    int i, j;
 
384
 
 
385
    ++inHandler;
 
386
    for (i = 0; i < screenInfo.numScreens; i++)
 
387
        (*screenInfo.screens[i]->BlockHandler) (screenInfo.screens[i],
 
388
                                                pTimeout, pReadmask);
 
389
    for (i = 0; i < screenInfo.numGPUScreens; i++)
 
390
        (*screenInfo.gpuscreens[i]->BlockHandler) (screenInfo.gpuscreens[i],
 
391
                                                   pTimeout, pReadmask);
 
392
    for (i = 0; i < numHandlers; i++)
 
393
        if (!handlers[i].deleted)
 
394
            (*handlers[i].BlockHandler) (handlers[i].blockData,
 
395
                                         pTimeout, pReadmask);
 
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
 */
 
415
void
 
416
WakeupHandler(int result, void *pReadmask)
 
417
{
 
418
    int i, j;
 
419
 
 
420
    ++inHandler;
 
421
    for (i = numHandlers - 1; i >= 0; i--)
 
422
        if (!handlers[i].deleted)
 
423
            (*handlers[i].WakeupHandler) (handlers[i].blockData,
 
424
                                          result, pReadmask);
 
425
    for (i = 0; i < screenInfo.numScreens; i++)
 
426
        (*screenInfo.screens[i]->WakeupHandler) (screenInfo.screens[i],
 
427
                                                 result, pReadmask);
 
428
    for (i = 0; i < screenInfo.numGPUScreens; i++)
 
429
        (*screenInfo.gpuscreens[i]->WakeupHandler) (screenInfo.gpuscreens[i],
 
430
                                                    result, pReadmask);
 
431
    if (handlerDeleted) {
 
432
        for (i = 0; i < numHandlers;)
 
433
            if (handlers[i].deleted) {
 
434
                for (j = i; j < numHandlers - 1; j++)
 
435
                    handlers[j] = handlers[j + 1];
 
436
                numHandlers--;
 
437
            }
 
438
            else
 
439
                i++;
 
440
        handlerDeleted = FALSE;
 
441
    }
 
442
    --inHandler;
 
443
}
 
444
 
 
445
/**
 
446
 * Reentrant with BlockHandler and WakeupHandler, except wakeup won't
 
447
 * get called until next time
 
448
 */
 
449
Bool
 
450
RegisterBlockAndWakeupHandlers(BlockHandlerProcPtr blockHandler,
 
451
                               WakeupHandlerProcPtr wakeupHandler,
 
452
                               void *blockData)
 
453
{
 
454
    BlockHandlerPtr new;
 
455
 
 
456
    if (numHandlers >= sizeHandlers) {
 
457
        new = (BlockHandlerPtr) realloc(handlers, (numHandlers + 1) *
 
458
                                        sizeof(BlockHandlerRec));
 
459
        if (!new)
 
460
            return FALSE;
 
461
        handlers = new;
 
462
        sizeHandlers = numHandlers + 1;
 
463
    }
 
464
    handlers[numHandlers].BlockHandler = blockHandler;
 
465
    handlers[numHandlers].WakeupHandler = wakeupHandler;
 
466
    handlers[numHandlers].blockData = blockData;
 
467
    handlers[numHandlers].deleted = FALSE;
 
468
    numHandlers = numHandlers + 1;
 
469
    return TRUE;
 
470
}
 
471
 
 
472
void
 
473
RemoveBlockAndWakeupHandlers(BlockHandlerProcPtr blockHandler,
 
474
                             WakeupHandlerProcPtr wakeupHandler,
 
475
                             void *blockData)
 
476
{
 
477
    int i;
 
478
 
 
479
    for (i = 0; i < numHandlers; i++)
 
480
        if (handlers[i].BlockHandler == blockHandler &&
 
481
            handlers[i].WakeupHandler == wakeupHandler &&
 
482
            handlers[i].blockData == blockData) {
 
483
            if (inHandler) {
 
484
                handlerDeleted = TRUE;
 
485
                handlers[i].deleted = TRUE;
 
486
            }
 
487
            else {
 
488
                for (; i < numHandlers - 1; i++)
 
489
                    handlers[i] = handlers[i + 1];
 
490
                numHandlers--;
 
491
            }
 
492
            break;
 
493
        }
 
494
}
 
495
 
 
496
void
 
497
InitBlockAndWakeupHandlers(void)
 
498
{
 
499
    free(handlers);
 
500
    handlers = (BlockHandlerPtr) 0;
 
501
    numHandlers = 0;
 
502
    sizeHandlers = 0;
 
503
}
 
504
 
 
505
/*
 
506
 * A general work queue.  Perform some task before the server
 
507
 * sleeps for input.
 
508
 */
 
509
 
 
510
WorkQueuePtr workQueue;
 
511
static WorkQueuePtr *workQueueLast = &workQueue;
 
512
 
 
513
void
 
514
ProcessWorkQueue(void)
 
515
{
 
516
    WorkQueuePtr q, *p;
 
517
 
 
518
    p = &workQueue;
 
519
    /*
 
520
     * Scan the work queue once, calling each function.  Those
 
521
     * which return TRUE are removed from the queue, otherwise
 
522
     * they will be called again.  This must be reentrant with
 
523
     * QueueWorkProc.
 
524
     */
 
525
    while ((q = *p)) {
 
526
        if ((*q->function) (q->client, q->closure)) {
 
527
            /* remove q from the list */
 
528
            *p = q->next;       /* don't fetch until after func called */
 
529
            free(q);
 
530
        }
 
531
        else {
 
532
            p = &q->next;       /* don't fetch until after func called */
 
533
        }
 
534
    }
 
535
    workQueueLast = p;
 
536
}
 
537
 
 
538
void
 
539
ProcessWorkQueueZombies(void)
 
540
{
 
541
    WorkQueuePtr q, *p;
 
542
 
 
543
    p = &workQueue;
 
544
    while ((q = *p)) {
 
545
        if (q->client && q->client->clientGone) {
 
546
            (void) (*q->function) (q->client, q->closure);
 
547
            /* remove q from the list */
 
548
            *p = q->next;       /* don't fetch until after func called */
 
549
            free(q);
 
550
        }
 
551
        else {
 
552
            p = &q->next;       /* don't fetch until after func called */
 
553
        }
 
554
    }
 
555
    workQueueLast = p;
 
556
}
 
557
 
 
558
Bool
 
559
QueueWorkProc(Bool (*function) (ClientPtr pClient, void *closure),
 
560
              ClientPtr client, void *closure)
 
561
{
 
562
    WorkQueuePtr q;
 
563
 
 
564
    q = malloc(sizeof *q);
 
565
    if (!q)
 
566
        return FALSE;
 
567
    q->function = function;
 
568
    q->client = client;
 
569
    q->closure = closure;
 
570
    q->next = NULL;
 
571
    *workQueueLast = q;
 
572
    workQueueLast = &q->next;
 
573
    return TRUE;
 
574
}
 
575
 
 
576
/*
 
577
 * Manage a queue of sleeping clients, awakening them
 
578
 * when requested, by using the OS functions IgnoreClient
 
579
 * and AttendClient.  Note that this *ignores* the troubles
 
580
 * with request data interleaving itself with events, but
 
581
 * we'll leave that until a later time.
 
582
 */
 
583
 
 
584
typedef struct _SleepQueue {
 
585
    struct _SleepQueue *next;
 
586
    ClientPtr client;
 
587
    ClientSleepProcPtr function;
 
588
    void *closure;
 
589
} SleepQueueRec, *SleepQueuePtr;
 
590
 
 
591
static SleepQueuePtr sleepQueue = NULL;
 
592
 
 
593
Bool
 
594
ClientSleep(ClientPtr client, ClientSleepProcPtr function, void *closure)
 
595
{
 
596
    SleepQueuePtr q;
 
597
 
 
598
    q = malloc(sizeof *q);
 
599
    if (!q)
 
600
        return FALSE;
 
601
 
 
602
    IgnoreClient(client);
 
603
    q->next = sleepQueue;
 
604
    q->client = client;
 
605
    q->function = function;
 
606
    q->closure = closure;
 
607
    sleepQueue = q;
 
608
    return TRUE;
 
609
}
 
610
 
 
611
Bool
 
612
ClientSignal(ClientPtr client)
 
613
{
 
614
    SleepQueuePtr q;
 
615
 
 
616
    for (q = sleepQueue; q; q = q->next)
 
617
        if (q->client == client) {
 
618
            return QueueWorkProc(q->function, q->client, q->closure);
 
619
        }
 
620
    return FALSE;
 
621
}
 
622
 
 
623
void
 
624
ClientWakeup(ClientPtr client)
 
625
{
 
626
    SleepQueuePtr q, *prev;
 
627
 
 
628
    prev = &sleepQueue;
 
629
    while ((q = *prev)) {
 
630
        if (q->client == client) {
 
631
            *prev = q->next;
 
632
            free(q);
 
633
            if (client->clientGone)
 
634
                /* Oops -- new zombie cleanup code ensures this only
 
635
                 * happens from inside CloseDownClient; don't want to
 
636
                 * recurse here...
 
637
                 */
 
638
                /* CloseDownClient(client) */ ;
 
639
            else
 
640
                AttendClient(client);
 
641
            break;
 
642
        }
 
643
        prev = &q->next;
 
644
    }
 
645
}
 
646
 
 
647
Bool
 
648
ClientIsAsleep(ClientPtr client)
 
649
{
 
650
    SleepQueuePtr q;
 
651
 
 
652
    for (q = sleepQueue; q; q = q->next)
 
653
        if (q->client == client)
 
654
            return TRUE;
 
655
    return FALSE;
 
656
}
 
657
 
 
658
/*
 
659
 *  Generic Callback Manager
 
660
 */
 
661
 
 
662
/* ===== Private Procedures ===== */
 
663
 
 
664
static int numCallbackListsToCleanup = 0;
 
665
static CallbackListPtr **listsToCleanup = NULL;
 
666
 
 
667
static Bool
 
668
_AddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, void *data)
 
669
{
 
670
    CallbackPtr cbr;
 
671
 
 
672
    cbr = malloc(sizeof(CallbackRec));
 
673
    if (!cbr)
 
674
        return FALSE;
 
675
    cbr->proc = callback;
 
676
    cbr->data = data;
 
677
    cbr->next = (*pcbl)->list;
 
678
    cbr->deleted = FALSE;
 
679
    (*pcbl)->list = cbr;
 
680
    return TRUE;
 
681
}
 
682
 
 
683
static Bool
 
684
_DeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, void *data)
 
685
{
 
686
    CallbackListPtr cbl = *pcbl;
 
687
    CallbackPtr cbr, pcbr;
 
688
 
 
689
    for (pcbr = NULL, cbr = cbl->list; cbr != NULL; pcbr = cbr, cbr = cbr->next) {
 
690
        if ((cbr->proc == callback) && (cbr->data == data))
 
691
            break;
 
692
    }
 
693
    if (cbr != NULL) {
 
694
        if (cbl->inCallback) {
 
695
            ++(cbl->numDeleted);
 
696
            cbr->deleted = TRUE;
 
697
        }
 
698
        else {
 
699
            if (pcbr == NULL)
 
700
                cbl->list = cbr->next;
 
701
            else
 
702
                pcbr->next = cbr->next;
 
703
            free(cbr);
 
704
        }
 
705
        return TRUE;
 
706
    }
 
707
    return FALSE;
 
708
}
 
709
 
 
710
void
 
711
_CallCallbacks(CallbackListPtr *pcbl, void *call_data)
 
712
{
 
713
    CallbackListPtr cbl = *pcbl;
 
714
    CallbackPtr cbr, pcbr;
 
715
 
 
716
    ++(cbl->inCallback);
 
717
    for (cbr = cbl->list; cbr != NULL; cbr = cbr->next) {
 
718
        (*(cbr->proc)) (pcbl, cbr->data, call_data);
 
719
    }
 
720
    --(cbl->inCallback);
 
721
 
 
722
    if (cbl->inCallback)
 
723
        return;
 
724
 
 
725
    /* Was the entire list marked for deletion? */
 
726
 
 
727
    if (cbl->deleted) {
 
728
        DeleteCallbackList(pcbl);
 
729
        return;
 
730
    }
 
731
 
 
732
    /* Were some individual callbacks on the list marked for deletion?
 
733
     * If so, do the deletions.
 
734
     */
 
735
 
 
736
    if (cbl->numDeleted) {
 
737
        for (pcbr = NULL, cbr = cbl->list; (cbr != NULL) && cbl->numDeleted;) {
 
738
            if (cbr->deleted) {
 
739
                if (pcbr) {
 
740
                    cbr = cbr->next;
 
741
                    free(pcbr->next);
 
742
                    pcbr->next = cbr;
 
743
                }
 
744
                else {
 
745
                    cbr = cbr->next;
 
746
                    free(cbl->list);
 
747
                    cbl->list = cbr;
 
748
                }
 
749
                cbl->numDeleted--;
 
750
            }
 
751
            else {              /* this one wasn't deleted */
 
752
 
 
753
                pcbr = cbr;
 
754
                cbr = cbr->next;
 
755
            }
 
756
        }
 
757
    }
 
758
}
 
759
 
 
760
static void
 
761
_DeleteCallbackList(CallbackListPtr *pcbl)
 
762
{
 
763
    CallbackListPtr cbl = *pcbl;
 
764
    CallbackPtr cbr, nextcbr;
 
765
    int i;
 
766
 
 
767
    if (cbl->inCallback) {
 
768
        cbl->deleted = TRUE;
 
769
        return;
 
770
    }
 
771
 
 
772
    for (i = 0; i < numCallbackListsToCleanup; i++) {
 
773
        if (listsToCleanup[i] == pcbl) {
 
774
            listsToCleanup[i] = NULL;
 
775
            break;
 
776
        }
 
777
    }
 
778
 
 
779
    for (cbr = cbl->list; cbr != NULL; cbr = nextcbr) {
 
780
        nextcbr = cbr->next;
 
781
        free(cbr);
 
782
    }
 
783
    free(cbl);
 
784
    *pcbl = NULL;
 
785
}
 
786
 
 
787
static Bool
 
788
CreateCallbackList(CallbackListPtr *pcbl)
 
789
{
 
790
    CallbackListPtr cbl;
 
791
    int i;
 
792
 
 
793
    if (!pcbl)
 
794
        return FALSE;
 
795
    cbl = malloc(sizeof(CallbackListRec));
 
796
    if (!cbl)
 
797
        return FALSE;
 
798
    cbl->inCallback = 0;
 
799
    cbl->deleted = FALSE;
 
800
    cbl->numDeleted = 0;
 
801
    cbl->list = NULL;
 
802
    *pcbl = cbl;
 
803
 
 
804
    for (i = 0; i < numCallbackListsToCleanup; i++) {
 
805
        if (!listsToCleanup[i]) {
 
806
            listsToCleanup[i] = pcbl;
 
807
            return TRUE;
 
808
        }
 
809
    }
 
810
 
 
811
    listsToCleanup = (CallbackListPtr **) xnfrealloc(listsToCleanup,
 
812
                                                     sizeof(CallbackListPtr *) *
 
813
                                                     (numCallbackListsToCleanup
 
814
                                                      + 1));
 
815
    listsToCleanup[numCallbackListsToCleanup] = pcbl;
 
816
    numCallbackListsToCleanup++;
 
817
    return TRUE;
 
818
}
 
819
 
 
820
/* ===== Public Procedures ===== */
 
821
 
 
822
Bool
 
823
AddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, void *data)
 
824
{
 
825
    if (!pcbl)
 
826
        return FALSE;
 
827
    if (!*pcbl) {               /* list hasn't been created yet; go create it */
 
828
        if (!CreateCallbackList(pcbl))
 
829
            return FALSE;
 
830
    }
 
831
    return _AddCallback(pcbl, callback, data);
 
832
}
 
833
 
 
834
Bool
 
835
DeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, void *data)
 
836
{
 
837
    if (!pcbl || !*pcbl)
 
838
        return FALSE;
 
839
    return _DeleteCallback(pcbl, callback, data);
 
840
}
 
841
 
 
842
void
 
843
DeleteCallbackList(CallbackListPtr *pcbl)
 
844
{
 
845
    if (!pcbl || !*pcbl)
 
846
        return;
 
847
    _DeleteCallbackList(pcbl);
 
848
}
 
849
 
 
850
void
 
851
DeleteCallbackManager(void)
 
852
{
 
853
    int i;
 
854
 
 
855
    for (i = 0; i < numCallbackListsToCleanup; i++) {
 
856
        DeleteCallbackList(listsToCleanup[i]);
 
857
    }
 
858
    free(listsToCleanup);
 
859
 
 
860
    numCallbackListsToCleanup = 0;
 
861
    listsToCleanup = NULL;
 
862
}
 
863
 
 
864
void
 
865
InitCallbackManager(void)
 
866
{
 
867
    DeleteCallbackManager();
 
868
}
 
869
 
 
870
/**
 
871
 * Coordinates the global GL context used by modules in the X Server
 
872
 * doing rendering with OpenGL.
 
873
 *
 
874
 * When setting a GL context (glXMakeCurrent() or eglMakeCurrent()),
 
875
 * there is an expensive implied glFlush() required by the GLX and EGL
 
876
 * APIs, so modules don't want to have to do it on every request.  But
 
877
 * the individual modules using GL also don't know about each other,
 
878
 * so they have to coordinate who owns the current context.
 
879
 *
 
880
 * When you're about to do a MakeCurrent, you should set this variable
 
881
 * to your context's address, and you can skip MakeCurrent if it's
 
882
 * already set to yours.
 
883
 *
 
884
 * When you're about to do a DestroyContext, you should set this to
 
885
 * NULL if it's set to your context.
 
886
 *
 
887
 * When you're about to do an unbindContext on a DRI driver, you
 
888
 * should set this to NULL.  Despite the unbindContext interface
 
889
 * sounding like it only unbinds the passed in context, it actually
 
890
 * unconditionally clears the dispatch table even if the given
 
891
 * context wasn't current.
 
892
 */
 
893
void *lastGLContext = NULL;