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