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 206 rc = dixLookupResourceByClass((pointer *)&pTmp, id, RC_DRAWABLE, client, access); 207 208 if (rc != Success) 209 client->errorValue = id; 210 211 if (rc == BadValue) 212 return BadDrawable; 213 if (rc != Success) 214 return rc; 215 if (!((1 << pTmp->type) & (type ? type : M_DRAWABLE))) 216 return BadMatch; 217 218 *pDraw = pTmp; 219 return Success; 220} 221 222int 223dixLookupWindow(WindowPtr *pWin, XID id, ClientPtr client, Mask access) 224{ 225 int rc; 226 rc = dixLookupDrawable((DrawablePtr*)pWin, id, client, M_WINDOW, access); 227 return (rc == BadDrawable) ? BadWindow : rc; 228} 229 230int 231dixLookupGC(GCPtr *pGC, XID id, ClientPtr client, Mask access) 232{ 233 return dixLookupResourceByType((pointer *)pGC, id, RT_GC, client, access); 234} 235 236int 237dixLookupFontable(FontPtr *pFont, XID id, ClientPtr client, Mask access) 238{ 239 int rc; 240 GC *pGC; 241 client->errorValue = id; /* EITHER font or gc */ 242 rc = dixLookupResourceByType((pointer *) pFont, id, RT_FONT, client, access); 243 if (rc != BadFont) 244 return rc; 245 rc = dixLookupResourceByType((pointer *) &pGC, id, RT_GC, client, access); 246 if (rc == BadGC) 247 return BadFont; 248 if (rc == Success) 249 *pFont = pGC->font; 250 return rc; 251} 252 253int 254dixLookupClient(ClientPtr *pClient, XID rid, ClientPtr client, Mask access) 255{ 256 pointer pRes; 257 int rc = BadValue, clientIndex = CLIENT_ID(rid); 258 259 if (!clientIndex || !clients[clientIndex] || (rid & SERVER_BIT)) 260 goto bad; 261 262 rc = dixLookupResourceByClass(&pRes, rid, RC_ANY, client, DixGetAttrAccess); 263 if (rc != Success) 264 goto bad; 265 266 rc = XaceHook(XACE_CLIENT_ACCESS, client, clients[clientIndex], access); 267 if (rc != Success) 268 goto bad; 269 270 *pClient = clients[clientIndex]; 271 return Success; 272bad: 273 if(client) 274 client->errorValue = rid; 275 *pClient = NULL; 276 return rc; 277} 278 279int 280AlterSaveSetForClient(ClientPtr client, WindowPtr pWin, unsigned mode, 281 Bool toRoot, Bool map) 282{ 283 int numnow; 284 SaveSetElt *pTmp = NULL; 285 int j; 286 287 numnow = client->numSaved; 288 j = 0; 289 if (numnow) 290 { 291 pTmp = client->saveSet; 292 while ((j < numnow) && (SaveSetWindow(pTmp[j]) != (pointer)pWin)) 293 j++; 294 } 295 if (mode == SetModeInsert) 296 { 297 if (j < numnow) /* duplicate */ 298 return Success; 299 numnow++; 300 pTmp = (SaveSetElt *)realloc(client->saveSet, sizeof(*pTmp) * numnow); 301 if (!pTmp) 302 return BadAlloc; 303 client->saveSet = pTmp; 304 client->numSaved = numnow; 305 SaveSetAssignWindow(client->saveSet[numnow - 1], pWin); 306 SaveSetAssignToRoot(client->saveSet[numnow - 1], toRoot); 307 SaveSetAssignMap(client->saveSet[numnow - 1], map); 308 return Success; 309 } 310 else if ((mode == SetModeDelete) && (j < numnow)) 311 { 312 while (j < numnow-1) 313 { 314 pTmp[j] = pTmp[j+1]; 315 j++; 316 } 317 numnow--; 318 if (numnow) 319 { 320 pTmp = (SaveSetElt *)realloc(client->saveSet, sizeof(*pTmp) * numnow); 321 if (pTmp) 322 client->saveSet = pTmp; 323 } 324 else 325 { 326 free(client->saveSet); 327 client->saveSet = (SaveSetElt *)NULL; 328 } 329 client->numSaved = numnow; 330 return Success; 331 } 332 return Success; 333} 334 335void 336DeleteWindowFromAnySaveSet(WindowPtr pWin) 337{ 338 int i; 339 ClientPtr client; 340 341 for (i = 0; i< currentMaxClients; i++) 342 { 343 client = clients[i]; 344 if (client && client->numSaved) 345 (void)AlterSaveSetForClient(client, pWin, SetModeDelete, FALSE, TRUE); 346 } 347} 348 349/* No-op Don't Do Anything : sometimes we need to be able to call a procedure 350 * that doesn't do anything. For example, on screen with only static 351 * colormaps, if someone calls install colormap, it's easier to have a dummy 352 * procedure to call than to check if there's a procedure 353 */ 354void 355NoopDDA(void) 356{ 357} 358 359typedef struct _BlockHandler { 360 BlockHandlerProcPtr BlockHandler; 361 WakeupHandlerProcPtr WakeupHandler; 362 pointer blockData; 363 Bool deleted; 364} BlockHandlerRec, *BlockHandlerPtr; 365 366static BlockHandlerPtr handlers; 367static int numHandlers; 368static int sizeHandlers; 369static Bool inHandler; 370static Bool handlerDeleted; 371 372/** 373 * 374 * \param pTimeout DIX doesn't want to know how OS represents time 375 * \param pReadMask nor how it represents the det of descriptors 376 */ 377void 378BlockHandler(pointer pTimeout, pointer pReadmask) 379{ 380 int i, j; 381 382 ++inHandler; 383 for (i = 0; i < screenInfo.numScreens; i++) 384 (* screenInfo.screens[i]->BlockHandler)(i, 385 screenInfo.screens[i]->blockData, 386 pTimeout, pReadmask); 387 for (i = 0; i < numHandlers; i++) 388 (*handlers[i].BlockHandler) (handlers[i].blockData, 389 pTimeout, pReadmask); 390 if (handlerDeleted) 391 { 392 for (i = 0; i < numHandlers;) 393 if (handlers[i].deleted) 394 { 395 for (j = i; j < numHandlers - 1; j++) 396 handlers[j] = handlers[j+1]; 397 numHandlers--; 398 } 399 else 400 i++; 401 handlerDeleted = FALSE; 402 } 403 --inHandler; 404} 405 406/** 407 * 408 * \param result 32 bits of undefined result from the wait 409 * \param pReadmask the resulting descriptor mask 410 */ 411void 412WakeupHandler(int result, pointer pReadmask) 413{ 414 int i, j; 415 416 ++inHandler; 417 for (i = numHandlers - 1; i >= 0; i--) 418 (*handlers[i].WakeupHandler) (handlers[i].blockData, 419 result, pReadmask); 420 for (i = 0; i < screenInfo.numScreens; i++) 421 (* screenInfo.screens[i]->WakeupHandler)(i, 422 screenInfo.screens[i]->wakeupData, 423 result, pReadmask); 424 if (handlerDeleted) 425 { 426 for (i = 0; i < numHandlers;) 427 if (handlers[i].deleted) 428 { 429 for (j = i; j < numHandlers - 1; j++) 430 handlers[j] = handlers[j+1]; 431 numHandlers--; 432 } 433 else 434 i++; 435 handlerDeleted = FALSE; 436 } 437 --inHandler; 438} 439 440/** 441 * Reentrant with BlockHandler and WakeupHandler, except wakeup won't 442 * get called until next time 443 */ 444Bool 445RegisterBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler, 446 WakeupHandlerProcPtr wakeupHandler, 447 pointer blockData) 448{ 449 BlockHandlerPtr new; 450 451 if (numHandlers >= sizeHandlers) 452 { 453 new = (BlockHandlerPtr) realloc(handlers, (numHandlers + 1) * 454 sizeof (BlockHandlerRec)); 455 if (!new) 456 return FALSE; 457 handlers = new; 458 sizeHandlers = numHandlers + 1; 459 } 460 handlers[numHandlers].BlockHandler = blockHandler; 461 handlers[numHandlers].WakeupHandler = wakeupHandler; 462 handlers[numHandlers].blockData = blockData; 463 handlers[numHandlers].deleted = FALSE; 464 numHandlers = numHandlers + 1; 465 return TRUE; 466} 467 468void 469RemoveBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler, 470 WakeupHandlerProcPtr wakeupHandler, 471 pointer blockData) 472{ 473 int i; 474 475 for (i = 0; i < numHandlers; i++) 476 if (handlers[i].BlockHandler == blockHandler && 477 handlers[i].WakeupHandler == wakeupHandler && 478 handlers[i].blockData == blockData) 479 { 480 if (inHandler) 481 { 482 handlerDeleted = TRUE; 483 handlers[i].deleted = TRUE; 484 } 485 else 486 { 487 for (; i < numHandlers - 1; i++) 488 handlers[i] = handlers[i+1]; 489 numHandlers--; 490 } 491 break; 492 } 493} 494 495void 496InitBlockAndWakeupHandlers (void) 497{ 498 free(handlers); 499 handlers = (BlockHandlerPtr) 0; 500 numHandlers = 0; 501 sizeHandlers = 0; 502} 503 504/* 505 * A general work queue. Perform some task before the server 506 * sleeps for input. 507 */ 508 509WorkQueuePtr workQueue; 510static WorkQueuePtr *workQueueLast = &workQueue; 511 512void 513ProcessWorkQueue(void) 514{ 515 WorkQueuePtr q, *p; 516 517 p = &workQueue; 518 /* 519 * Scan the work queue once, calling each function. Those 520 * which return TRUE are removed from the queue, otherwise 521 * they will be called again. This must be reentrant with 522 * QueueWorkProc. 523 */ 524 while ((q = *p)) 525 { 526 if ((*q->function) (q->client, q->closure)) 527 { 528 /* remove q from the list */ 529 *p = q->next; /* don't fetch until after func called */ 530 free(q); 531 } 532 else 533 { 534 p = &q->next; /* don't fetch until after func called */ 535 } 536 } 537 workQueueLast = p; 538} 539 540void 541ProcessWorkQueueZombies(void) 542{ 543 WorkQueuePtr q, *p; 544 545 p = &workQueue; 546 while ((q = *p)) 547 { 548 if (q->client && q->client->clientGone) 549 { 550 (void) (*q->function) (q->client, q->closure); 551 /* remove q from the list */ 552 *p = q->next; /* don't fetch until after func called */ 553 free(q); 554 } 555 else 556 { 557 p = &q->next; /* don't fetch until after func called */ 558 } 559 } 560 workQueueLast = p; 561} 562 563Bool 564QueueWorkProc ( 565 Bool (*function)(ClientPtr /* pClient */, pointer /* closure */), 566 ClientPtr client, pointer closure) 567{ 568 WorkQueuePtr q; 569 570 q = malloc(sizeof *q); 571 if (!q) 572 return FALSE; 573 q->function = function; 574 q->client = client; 575 q->closure = closure; 576 q->next = NULL; 577 *workQueueLast = q; 578 workQueueLast = &q->next; 579 return TRUE; 580} 581 582/* 583 * Manage a queue of sleeping clients, awakening them 584 * when requested, by using the OS functions IgnoreClient 585 * and AttendClient. Note that this *ignores* the troubles 586 * with request data interleaving itself with events, but 587 * we'll leave that until a later time. 588 */ 589 590typedef struct _SleepQueue { 591 struct _SleepQueue *next; 592 ClientPtr client; 593 ClientSleepProcPtr function; 594 pointer closure; 595} SleepQueueRec, *SleepQueuePtr; 596 597static SleepQueuePtr sleepQueue = NULL; 598 599Bool 600ClientSleep (ClientPtr client, ClientSleepProcPtr function, pointer closure) 601{ 602 SleepQueuePtr q; 603 604 q = malloc(sizeof *q); 605 if (!q) 606 return FALSE; 607 608 IgnoreClient (client); 609 q->next = sleepQueue; 610 q->client = client; 611 q->function = function; 612 q->closure = closure; 613 sleepQueue = q; 614 return TRUE; 615} 616 617Bool 618ClientSignal (ClientPtr client) 619{ 620 SleepQueuePtr q; 621 622 for (q = sleepQueue; q; q = q->next) 623 if (q->client == client) 624 { 625 return QueueWorkProc (q->function, q->client, q->closure); 626 } 627 return FALSE; 628} 629 630void 631ClientWakeup (ClientPtr client) 632{ 633 SleepQueuePtr q, *prev; 634 635 prev = &sleepQueue; 636 while ( (q = *prev) ) 637 { 638 if (q->client == client) 639 { 640 *prev = q->next; 641 free(q); 642 if (client->clientGone) 643 /* Oops -- new zombie cleanup code ensures this only 644 * happens from inside CloseDownClient; don't want to 645 * recurse here... 646 */ 647 /* CloseDownClient(client) */; 648 else 649 AttendClient (client); 650 break; 651 } 652 prev = &q->next; 653 } 654} 655 656Bool 657ClientIsAsleep (ClientPtr client) 658{ 659 SleepQueuePtr q; 660 661 for (q = sleepQueue; q; q = q->next) 662 if (q->client == client) 663 return TRUE; 664 return FALSE; 665} 666 667/* 668 * Generic Callback Manager 669 */ 670 671/* ===== Private Procedures ===== */ 672 673static int numCallbackListsToCleanup = 0; 674static CallbackListPtr **listsToCleanup = NULL; 675 676static Bool 677_AddCallback( 678 CallbackListPtr *pcbl, 679 CallbackProcPtr callback, 680 pointer data) 681{ 682 CallbackPtr cbr; 683 684 cbr = malloc(sizeof(CallbackRec)); 685 if (!cbr) 686 return FALSE; 687 cbr->proc = callback; 688 cbr->data = data; 689 cbr->next = (*pcbl)->list; 690 cbr->deleted = FALSE; 691 (*pcbl)->list = cbr; 692 return TRUE; 693} 694 695static Bool 696_DeleteCallback( 697 CallbackListPtr *pcbl, 698 CallbackProcPtr callback, 699 pointer data) 700{ 701 CallbackListPtr cbl = *pcbl; 702 CallbackPtr cbr, pcbr; 703 704 for (pcbr = NULL, cbr = cbl->list; 705 cbr != NULL; 706 pcbr = cbr, cbr = cbr->next) 707 { 708 if ((cbr->proc == callback) && (cbr->data == data)) 709 break; 710 } 711 if (cbr != NULL) 712 { 713 if (cbl->inCallback) 714 { 715 ++(cbl->numDeleted); 716 cbr->deleted = TRUE; 717 } 718 else 719 { 720 if (pcbr == NULL) 721 cbl->list = cbr->next; 722 else 723 pcbr->next = cbr->next; 724 free(cbr); 725 } 726 return TRUE; 727 } 728 return FALSE; 729} 730 731void 732_CallCallbacks( 733 CallbackListPtr *pcbl, 734 pointer call_data) 735{ 736 CallbackListPtr cbl = *pcbl; 737 CallbackPtr cbr, pcbr; 738 739 ++(cbl->inCallback); 740 for (cbr = cbl->list; cbr != NULL; cbr = cbr->next) 741 { 742 (*(cbr->proc)) (pcbl, cbr->data, call_data); 743 } 744 --(cbl->inCallback); 745 746 if (cbl->inCallback) return; 747 748 /* Was the entire list marked for deletion? */ 749 750 if (cbl->deleted) 751 { 752 DeleteCallbackList(pcbl); 753 return; 754 } 755 756 /* Were some individual callbacks on the list marked for deletion? 757 * If so, do the deletions. 758 */ 759 760 if (cbl->numDeleted) 761 { 762 for (pcbr = NULL, cbr = cbl->list; (cbr != NULL) && cbl->numDeleted; ) 763 { 764 if (cbr->deleted) 765 { 766 if (pcbr) 767 { 768 cbr = cbr->next; 769 free(pcbr->next); 770 pcbr->next = cbr; 771 } else 772 { 773 cbr = cbr->next; 774 free(cbl->list); 775 cbl->list = cbr; 776 } 777 cbl->numDeleted--; 778 } 779 else /* this one wasn't deleted */ 780 { 781 pcbr = cbr; 782 cbr = cbr->next; 783 } 784 } 785 } 786} 787 788static void 789_DeleteCallbackList( 790 CallbackListPtr *pcbl) 791{ 792 CallbackListPtr cbl = *pcbl; 793 CallbackPtr cbr, nextcbr; 794 int i; 795 796 if (cbl->inCallback) 797 { 798 cbl->deleted = TRUE; 799 return; 800 } 801 802 for (i = 0; i < numCallbackListsToCleanup; i++) 803 { 804 if (listsToCleanup[i] == pcbl) 805 { 806 listsToCleanup[i] = NULL; 807 break; 808 } 809 } 810 811 for (cbr = cbl->list; cbr != NULL; cbr = nextcbr) 812 { 813 nextcbr = cbr->next; 814 free(cbr); 815 } 816 free(cbl); 817 *pcbl = NULL; 818} 819 820static Bool 821CreateCallbackList(CallbackListPtr *pcbl) 822{ 823 CallbackListPtr cbl; 824 int i; 825 826 if (!pcbl) return FALSE; 827 cbl = malloc(sizeof(CallbackListRec)); 828 if (!cbl) return FALSE; 829 cbl->inCallback = 0; 830 cbl->deleted = FALSE; 831 cbl->numDeleted = 0; 832 cbl->list = NULL; 833 *pcbl = cbl; 834 835 for (i = 0; i < numCallbackListsToCleanup; i++) 836 { 837 if (!listsToCleanup[i]) 838 { 839 listsToCleanup[i] = pcbl; 840 return TRUE; 841 } 842 } 843 844 listsToCleanup = (CallbackListPtr **)xnfrealloc(listsToCleanup, 845 sizeof(CallbackListPtr *) * (numCallbackListsToCleanup+1)); 846 listsToCleanup[numCallbackListsToCleanup] = pcbl; 847 numCallbackListsToCleanup++; 848 return TRUE; 849} 850 851/* ===== Public Procedures ===== */ 852 853Bool 854AddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data) 855{ 856 if (!pcbl) return FALSE; 857 if (!*pcbl) 858 { /* list hasn't been created yet; go create it */ 859 if (!CreateCallbackList(pcbl)) 860 return FALSE; 861 } 862 return _AddCallback(pcbl, callback, data); 863} 864 865Bool 866DeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data) 867{ 868 if (!pcbl || !*pcbl) return FALSE; 869 return _DeleteCallback(pcbl, callback, data); 870} 871 872void 873DeleteCallbackList(CallbackListPtr *pcbl) 874{ 875 if (!pcbl || !*pcbl) return; 876 _DeleteCallbackList(pcbl); 877} 878 879void 880InitCallbackManager(void) 881{ 882 int i; 883 884 for (i = 0; i < numCallbackListsToCleanup; i++) 885 { 886 DeleteCallbackList(listsToCleanup[i]); 887 } 888 free(listsToCleanup); 889 890 numCallbackListsToCleanup = 0; 891 listsToCleanup = NULL; 892} 893