dixutils.c revision 4642e01f
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 "scrnintstr.h" 96#define XK_LATIN1 97#include <X11/keysymdef.h> 98#include "xace.h" 99 100/* 101 * CompareTimeStamps returns -1, 0, or +1 depending on if the first 102 * argument is less than, equal to or greater than the second argument. 103 */ 104 105_X_EXPORT int 106CompareTimeStamps(TimeStamp a, TimeStamp b) 107{ 108 if (a.months < b.months) 109 return EARLIER; 110 if (a.months > b.months) 111 return LATER; 112 if (a.milliseconds < b.milliseconds) 113 return EARLIER; 114 if (a.milliseconds > b.milliseconds) 115 return LATER; 116 return SAMETIME; 117} 118 119/* 120 * convert client times to server TimeStamps 121 */ 122 123#define HALFMONTH ((unsigned long) 1<<31) 124_X_EXPORT TimeStamp 125ClientTimeToServerTime(CARD32 c) 126{ 127 TimeStamp ts; 128 if (c == CurrentTime) 129 return currentTime; 130 ts.months = currentTime.months; 131 ts.milliseconds = c; 132 if (c > currentTime.milliseconds) 133 { 134 if (((unsigned long) c - currentTime.milliseconds) > HALFMONTH) 135 ts.months -= 1; 136 } 137 else if (c < currentTime.milliseconds) 138 { 139 if (((unsigned long)currentTime.milliseconds - c) > HALFMONTH) 140 ts.months += 1; 141 } 142 return ts; 143} 144 145/* 146 * ISO Latin-1 case conversion routine 147 * 148 * this routine always null-terminates the result, so 149 * beware of too-small buffers 150 */ 151 152static unsigned char 153ISOLatin1ToLower (unsigned char source) 154{ 155 unsigned char dest; 156 if ((source >= XK_A) && (source <= XK_Z)) 157 dest = source + (XK_a - XK_A); 158 else if ((source >= XK_Agrave) && (source <= XK_Odiaeresis)) 159 dest = source + (XK_agrave - XK_Agrave); 160 else if ((source >= XK_Ooblique) && (source <= XK_Thorn)) 161 dest = source + (XK_oslash - XK_Ooblique); 162 else 163 dest = source; 164 return dest; 165} 166 167 168_X_EXPORT void 169CopyISOLatin1Lowered(unsigned char *dest, unsigned char *source, int length) 170{ 171 int i; 172 173 for (i = 0; i < length; i++, source++, dest++) 174 *dest = ISOLatin1ToLower (*source); 175 *dest = '\0'; 176} 177 178int 179CompareISOLatin1Lowered(unsigned char *s1, int s1len, 180 unsigned char *s2, int s2len) 181{ 182 unsigned char c1, c2; 183 184 for (;;) 185 { 186 /* note -- compare against zero so that -1 ignores len */ 187 c1 = s1len-- ? *s1++ : '\0'; 188 c2 = s2len-- ? *s2++ : '\0'; 189 if (!c1 || 190 (c1 != c2 && 191 (c1 = ISOLatin1ToLower (c1)) != (c2 = ISOLatin1ToLower (c2)))) 192 break; 193 } 194 return (int) c1 - (int) c2; 195} 196 197/* 198 * dixLookupWindow and dixLookupDrawable: 199 * Look up the window/drawable taking into account the client doing the 200 * lookup, the type of drawable desired, and the type of access desired. 201 * Return Success with *pDraw set if the window/drawable exists and the client 202 * is allowed access, else return an error code with *pDraw set to NULL. The 203 * access mask values are defined in resource.h. The type mask values are 204 * defined in pixmap.h, with zero equivalent to M_DRAWABLE. 205 */ 206_X_EXPORT int 207dixLookupDrawable(DrawablePtr *pDraw, XID id, ClientPtr client, 208 Mask type, Mask access) 209{ 210 DrawablePtr pTmp; 211 int rc; 212 213 *pDraw = NULL; 214 client->errorValue = id; 215 216 if (id == INVALID) 217 return BadDrawable; 218 219 rc = dixLookupResource((pointer *)&pTmp, id, RC_DRAWABLE, client, access); 220 221 if (rc == BadValue) 222 return BadDrawable; 223 if (rc != Success) 224 return rc; 225 if (!((1 << pTmp->type) & (type ? type : M_DRAWABLE))) 226 return BadMatch; 227 228 *pDraw = pTmp; 229 return Success; 230} 231 232_X_EXPORT int 233dixLookupWindow(WindowPtr *pWin, XID id, ClientPtr client, Mask access) 234{ 235 int rc; 236 rc = dixLookupDrawable((DrawablePtr*)pWin, id, client, M_WINDOW, access); 237 return (rc == BadDrawable) ? BadWindow : rc; 238} 239 240_X_EXPORT int 241dixLookupGC(GCPtr *pGC, XID id, ClientPtr client, Mask access) 242{ 243 GCPtr pTmp = (GCPtr)SecurityLookupIDByType(client, id, RT_GC, access); 244 if (pTmp) { 245 *pGC = pTmp; 246 return Success; 247 } 248 client->errorValue = id; 249 *pGC = NULL; 250 return BadGC; 251} 252 253_X_EXPORT int 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 = dixLookupResource(&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 *)xrealloc(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 *)xrealloc(client->saveSet, sizeof(*pTmp) * numnow); 321 if (pTmp) 322 client->saveSet = pTmp; 323 } 324 else 325 { 326 xfree(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 */ 354_X_EXPORT void 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 */ 444_X_EXPORT Bool 445RegisterBlockAndWakeupHandlers (BlockHandlerProcPtr blockHandler, 446 WakeupHandlerProcPtr wakeupHandler, 447 pointer blockData) 448{ 449 BlockHandlerPtr new; 450 451 if (numHandlers >= sizeHandlers) 452 { 453 new = (BlockHandlerPtr) xrealloc (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 468_X_EXPORT void 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 xfree (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 xfree (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 xfree (q); 554 } 555 else 556 { 557 p = &q->next; /* don't fetch until after func called */ 558 } 559 } 560 workQueueLast = p; 561} 562 563_X_EXPORT Bool 564QueueWorkProc ( 565 Bool (*function)(ClientPtr /* pClient */, pointer /* closure */), 566 ClientPtr client, pointer closure) 567{ 568 WorkQueuePtr q; 569 570 q = (WorkQueuePtr) xalloc (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 599_X_EXPORT Bool 600ClientSleep (ClientPtr client, ClientSleepProcPtr function, pointer closure) 601{ 602 SleepQueuePtr q; 603 604 q = (SleepQueuePtr) xalloc (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 630_X_EXPORT void 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 xfree (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 = (CallbackPtr) xalloc(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 xfree(cbr); 725 } 726 return TRUE; 727 } 728 return FALSE; 729} 730 731static void 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 xfree(pcbr->next); 770 pcbr->next = cbr; 771 } else 772 { 773 cbr = cbr->next; 774 xfree(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 xfree(cbr); 815 } 816 xfree(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 = (CallbackListPtr) xalloc(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 853_X_EXPORT Bool 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 865_X_EXPORT Bool 866DeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data) 867{ 868 if (!pcbl || !*pcbl) return FALSE; 869 return _DeleteCallback(pcbl, callback, data); 870} 871 872void 873CallCallbacks(CallbackListPtr *pcbl, pointer call_data) 874{ 875 if (!pcbl || !*pcbl) return; 876 _CallCallbacks(pcbl, call_data); 877} 878 879void 880DeleteCallbackList(CallbackListPtr *pcbl) 881{ 882 if (!pcbl || !*pcbl) return; 883 _DeleteCallbackList(pcbl); 884} 885 886void 887InitCallbackManager(void) 888{ 889 int i; 890 891 for (i = 0; i < numCallbackListsToCleanup; i++) 892 { 893 DeleteCallbackList(listsToCleanup[i]); 894 } 895 if (listsToCleanup) xfree(listsToCleanup); 896 897 numCallbackListsToCleanup = 0; 898 listsToCleanup = NULL; 899} 900