dixutils.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838
  1. /***********************************************************
  2. Copyright 1987, 1998 The Open Group
  3. Permission to use, copy, modify, distribute, and sell this software and its
  4. documentation for any purpose is hereby granted without fee, provided that
  5. the above copyright notice appear in all copies and that both that
  6. copyright notice and this permission notice appear in supporting
  7. documentation.
  8. The above copyright notice and this permission notice shall be included in
  9. all copies or substantial portions of the Software.
  10. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  11. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  12. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  13. OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  14. AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  15. CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  16. Except as contained in this notice, the name of The Open Group shall not be
  17. used in advertising or otherwise to promote the sale, use or other dealings
  18. in this Software without prior written authorization from The Open Group.
  19. Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
  20. All Rights Reserved
  21. Permission to use, copy, modify, and distribute this software and its
  22. documentation for any purpose and without fee is hereby granted,
  23. provided that the above copyright notice appear in all copies and that
  24. both that copyright notice and this permission notice appear in
  25. supporting documentation, and that the name of Digital not be
  26. used in advertising or publicity pertaining to distribution of the
  27. software without specific, written prior permission.
  28. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  29. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  30. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  31. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  32. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  33. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  34. SOFTWARE.
  35. ******************************************************************/
  36. /*
  37. (c)Copyright 1988,1991 Adobe Systems Incorporated. All rights reserved.
  38. Permission to use, copy, modify, distribute, and sublicense this software and its
  39. documentation for any purpose and without fee is hereby granted, provided that
  40. the above copyright notices appear in all copies and that both those copyright
  41. notices and this permission notice appear in supporting documentation and that
  42. the name of Adobe Systems Incorporated not be used in advertising or publicity
  43. pertaining to distribution of the software without specific, written prior
  44. permission. No trademark license to use the Adobe trademarks is hereby
  45. granted. If the Adobe trademark "Display PostScript"(tm) is used to describe
  46. this software, its functionality or for any other purpose, such use shall be
  47. limited to a statement that this software works in conjunction with the Display
  48. PostScript system. Proper trademark attribution to reflect Adobe's ownership
  49. of the trademark shall be given whenever any such reference to the Display
  50. PostScript system is made.
  51. ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR ANY
  52. PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. ADOBE
  53. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
  54. WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-
  55. INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL ADOBE BE LIABLE TO YOU
  56. OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
  57. DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT,NEGLIGENCE, STRICT
  58. LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  59. PERFORMANCE OF THIS SOFTWARE. ADOBE WILL NOT PROVIDE ANY TRAINING OR OTHER
  60. SUPPORT FOR THE SOFTWARE.
  61. Adobe, PostScript, and Display PostScript are trademarks of Adobe Systems
  62. Incorporated which may be registered in certain jurisdictions.
  63. Author: Adobe Systems Incorporated
  64. */
  65. #ifdef HAVE_DIX_CONFIG_H
  66. #include <dix-config.h>
  67. #endif
  68. #include <X11/X.h>
  69. #include <X11/Xmd.h>
  70. #include "misc.h"
  71. #include "windowstr.h"
  72. #include "dixstruct.h"
  73. #include "pixmapstr.h"
  74. #include "scrnintstr.h"
  75. #define XK_LATIN1
  76. #include <X11/keysymdef.h>
  77. /*
  78. * CompareTimeStamps returns -1, 0, or +1 depending on if the first
  79. * argument is less than, equal to or greater than the second argument.
  80. */
  81. _X_EXPORT int
  82. CompareTimeStamps(TimeStamp a, TimeStamp b)
  83. {
  84. if (a.months < b.months)
  85. return EARLIER;
  86. if (a.months > b.months)
  87. return LATER;
  88. if (a.milliseconds < b.milliseconds)
  89. return EARLIER;
  90. if (a.milliseconds > b.milliseconds)
  91. return LATER;
  92. return SAMETIME;
  93. }
  94. /*
  95. * convert client times to server TimeStamps
  96. */
  97. #define HALFMONTH ((unsigned long) 1<<31)
  98. _X_EXPORT TimeStamp
  99. ClientTimeToServerTime(CARD32 c)
  100. {
  101. TimeStamp ts;
  102. if (c == CurrentTime)
  103. return currentTime;
  104. ts.months = currentTime.months;
  105. ts.milliseconds = c;
  106. if (c > currentTime.milliseconds) {
  107. if (((unsigned long) c - currentTime.milliseconds) > HALFMONTH)
  108. ts.months -= 1;
  109. }
  110. else if (c < currentTime.milliseconds) {
  111. if (((unsigned long) currentTime.milliseconds - c) > HALFMONTH)
  112. ts.months += 1;
  113. }
  114. return ts;
  115. }
  116. /*
  117. * ISO Latin-1 case conversion routine
  118. *
  119. * this routine always null-terminates the result, so
  120. * beware of too-small buffers
  121. */
  122. static unsigned char
  123. ISOLatin1ToLower(unsigned char source)
  124. {
  125. unsigned char dest;
  126. if ((source >= XK_A) && (source <= XK_Z))
  127. dest = source + (XK_a - XK_A);
  128. else if ((source >= XK_Agrave) && (source <= XK_Odiaeresis))
  129. dest = source + (XK_agrave - XK_Agrave);
  130. else if ((source >= XK_Ooblique) && (source <= XK_Thorn))
  131. dest = source + (XK_oslash - XK_Ooblique);
  132. else
  133. dest = source;
  134. return dest;
  135. }
  136. int
  137. CompareISOLatin1Lowered(unsigned char *s1, int s1len,
  138. unsigned char *s2, int s2len)
  139. {
  140. unsigned char c1, c2;
  141. for (;;) {
  142. /* note -- compare against zero so that -1 ignores len */
  143. c1 = s1len-- ? *s1++ : '\0';
  144. c2 = s2len-- ? *s2++ : '\0';
  145. if (!c1 ||
  146. (c1 != c2 &&
  147. (c1 = ISOLatin1ToLower(c1)) != (c2 = ISOLatin1ToLower(c2))))
  148. break;
  149. }
  150. return (int) c1 - (int) c2;
  151. }
  152. WindowPtr
  153. LookupWindow(XID rid, ClientPtr client)
  154. {
  155. WindowPtr pWin;
  156. client->errorValue = rid;
  157. if (rid == INVALID)
  158. return NULL;
  159. if (client->lastDrawableID == rid) {
  160. if (client->lastDrawable->type == DRAWABLE_WINDOW)
  161. return ((WindowPtr) client->lastDrawable);
  162. return (WindowPtr) NULL;
  163. }
  164. pWin = (WindowPtr) LookupIDByType(rid, RT_WINDOW);
  165. if (pWin && pWin->drawable.type == DRAWABLE_WINDOW) {
  166. client->lastDrawable = (DrawablePtr) pWin;
  167. client->lastDrawableID = rid;
  168. client->lastGCID = INVALID;
  169. client->lastGC = (GCPtr) NULL;
  170. }
  171. return pWin;
  172. }
  173. pointer
  174. LookupDrawable(XID rid, ClientPtr client)
  175. {
  176. DrawablePtr pDraw;
  177. if (rid == INVALID)
  178. return (pointer) NULL;
  179. if (client->lastDrawableID == rid)
  180. return ((pointer) client->lastDrawable);
  181. pDraw = (DrawablePtr) LookupIDByClass(rid, RC_DRAWABLE);
  182. if (pDraw && (pDraw->type != UNDRAWABLE_WINDOW))
  183. return (pointer) pDraw;
  184. return (pointer) NULL;
  185. }
  186. _X_EXPORT ClientPtr
  187. LookupClient(XID rid, ClientPtr client)
  188. {
  189. pointer pRes = (pointer) SecurityLookupIDByClass(client, rid, RC_ANY,
  190. SecurityReadAccess);
  191. int clientIndex = CLIENT_ID(rid);
  192. if (clientIndex && pRes && clients[clientIndex] && !(rid & SERVER_BIT)) {
  193. return clients[clientIndex];
  194. }
  195. return (ClientPtr) NULL;
  196. }
  197. int
  198. AlterSaveSetForClient(ClientPtr client, WindowPtr pWin, unsigned mode,
  199. Bool toRoot, Bool remap)
  200. {
  201. int numnow;
  202. SaveSetElt *pTmp = NULL;
  203. int j;
  204. numnow = client->numSaved;
  205. j = 0;
  206. if (numnow) {
  207. pTmp = client->saveSet;
  208. while ((j < numnow) && (SaveSetWindow(pTmp[j]) != (pointer) pWin))
  209. j++;
  210. }
  211. if (mode == SetModeInsert) {
  212. if (j < numnow) /* duplicate */
  213. return (Success);
  214. numnow++;
  215. pTmp = (SaveSetElt *) realloc(client->saveSet, sizeof(*pTmp) * numnow);
  216. if (!pTmp)
  217. return (BadAlloc);
  218. client->saveSet = pTmp;
  219. client->numSaved = numnow;
  220. SaveSetAssignWindow(client->saveSet[numnow - 1], pWin);
  221. SaveSetAssignToRoot(client->saveSet[numnow - 1], toRoot);
  222. SaveSetAssignRemap(client->saveSet[numnow - 1], remap);
  223. return (Success);
  224. }
  225. else if ((mode == SetModeDelete) && (j < numnow)) {
  226. while (j < numnow - 1) {
  227. pTmp[j] = pTmp[j + 1];
  228. j++;
  229. }
  230. numnow--;
  231. if (numnow) {
  232. pTmp =
  233. (SaveSetElt *) realloc(client->saveSet,
  234. sizeof(*pTmp) * numnow);
  235. if (pTmp)
  236. client->saveSet = pTmp;
  237. }
  238. else {
  239. free(client->saveSet);
  240. client->saveSet = (SaveSetElt *) NULL;
  241. }
  242. client->numSaved = numnow;
  243. return (Success);
  244. }
  245. return (Success);
  246. }
  247. void
  248. DeleteWindowFromAnySaveSet(WindowPtr pWin)
  249. {
  250. int i;
  251. ClientPtr client;
  252. for (i = 0; i < currentMaxClients; i++) {
  253. client = clients[i];
  254. if (client && client->numSaved)
  255. (void) AlterSaveSetForClient(client, pWin, SetModeDelete, FALSE,
  256. TRUE);
  257. }
  258. }
  259. /* No-op Don't Do Anything : sometimes we need to be able to call a procedure
  260. * that doesn't do anything. For example, on screen with only static
  261. * colormaps, if someone calls install colormap, it's easier to have a dummy
  262. * procedure to call than to check if there's a procedure
  263. */
  264. _X_EXPORT void
  265. NoopDDA(void)
  266. {
  267. }
  268. typedef struct _BlockHandler {
  269. BlockHandlerProcPtr BlockHandler;
  270. WakeupHandlerProcPtr WakeupHandler;
  271. pointer blockData;
  272. Bool deleted;
  273. } BlockHandlerRec, *BlockHandlerPtr;
  274. static BlockHandlerPtr handlers;
  275. static int numHandlers;
  276. static int sizeHandlers;
  277. static Bool inHandler;
  278. static Bool handlerDeleted;
  279. /**
  280. *
  281. * \param pTimeout DIX doesn't want to know how OS represents time
  282. * \param pReadMask nor how it represents the det of descriptors
  283. */
  284. void
  285. BlockHandler(pointer pTimeout, pointer pReadmask)
  286. {
  287. int i, j;
  288. ++inHandler;
  289. for (i = 0; i < screenInfo.numScreens; i++)
  290. (*screenInfo.screens[i]->BlockHandler) (i,
  291. screenInfo.screens[i]->
  292. blockData, pTimeout, pReadmask);
  293. for (i = 0; i < numHandlers; i++)
  294. (*handlers[i].BlockHandler) (handlers[i].blockData,
  295. pTimeout, pReadmask);
  296. if (handlerDeleted) {
  297. for (i = 0; i < numHandlers;)
  298. if (handlers[i].deleted) {
  299. for (j = i; j < numHandlers - 1; j++)
  300. handlers[j] = handlers[j + 1];
  301. numHandlers--;
  302. }
  303. else
  304. i++;
  305. handlerDeleted = FALSE;
  306. }
  307. --inHandler;
  308. }
  309. /**
  310. *
  311. * \param result 32 bits of undefined result from the wait
  312. * \param pReadmask the resulting descriptor mask
  313. */
  314. void
  315. WakeupHandler(int result, pointer pReadmask)
  316. {
  317. int i, j;
  318. ++inHandler;
  319. for (i = numHandlers - 1; i >= 0; i--)
  320. (*handlers[i].WakeupHandler) (handlers[i].blockData, result, pReadmask);
  321. for (i = 0; i < screenInfo.numScreens; i++)
  322. (*screenInfo.screens[i]->WakeupHandler) (i,
  323. screenInfo.screens[i]->
  324. wakeupData, result, pReadmask);
  325. if (handlerDeleted) {
  326. for (i = 0; i < numHandlers;)
  327. if (handlers[i].deleted) {
  328. for (j = i; j < numHandlers - 1; j++)
  329. handlers[j] = handlers[j + 1];
  330. numHandlers--;
  331. }
  332. else
  333. i++;
  334. handlerDeleted = FALSE;
  335. }
  336. --inHandler;
  337. }
  338. /**
  339. * Reentrant with BlockHandler and WakeupHandler, except wakeup won't
  340. * get called until next time
  341. */
  342. _X_EXPORT Bool
  343. RegisterBlockAndWakeupHandlers(BlockHandlerProcPtr blockHandler,
  344. WakeupHandlerProcPtr wakeupHandler,
  345. pointer blockData)
  346. {
  347. BlockHandlerPtr new;
  348. if (numHandlers >= sizeHandlers) {
  349. new = (BlockHandlerPtr) realloc(handlers, (numHandlers + 1) *
  350. sizeof(BlockHandlerRec));
  351. if (!new)
  352. return FALSE;
  353. handlers = new;
  354. sizeHandlers = numHandlers + 1;
  355. }
  356. handlers[numHandlers].BlockHandler = blockHandler;
  357. handlers[numHandlers].WakeupHandler = wakeupHandler;
  358. handlers[numHandlers].blockData = blockData;
  359. handlers[numHandlers].deleted = FALSE;
  360. numHandlers = numHandlers + 1;
  361. return TRUE;
  362. }
  363. _X_EXPORT void
  364. RemoveBlockAndWakeupHandlers(BlockHandlerProcPtr blockHandler,
  365. WakeupHandlerProcPtr wakeupHandler,
  366. pointer blockData)
  367. {
  368. int i;
  369. for (i = 0; i < numHandlers; i++)
  370. if (handlers[i].BlockHandler == blockHandler &&
  371. handlers[i].WakeupHandler == wakeupHandler &&
  372. handlers[i].blockData == blockData) {
  373. if (inHandler) {
  374. handlerDeleted = TRUE;
  375. handlers[i].deleted = TRUE;
  376. }
  377. else {
  378. for (; i < numHandlers - 1; i++)
  379. handlers[i] = handlers[i + 1];
  380. numHandlers--;
  381. }
  382. break;
  383. }
  384. }
  385. void
  386. InitBlockAndWakeupHandlers()
  387. {
  388. free(handlers);
  389. handlers = (BlockHandlerPtr) 0;
  390. numHandlers = 0;
  391. sizeHandlers = 0;
  392. }
  393. /*
  394. * A general work queue. Perform some task before the server
  395. * sleeps for input.
  396. */
  397. WorkQueuePtr workQueue;
  398. static WorkQueuePtr *workQueueLast = &workQueue;
  399. void
  400. ProcessWorkQueue(void)
  401. {
  402. WorkQueuePtr q, *p;
  403. p = &workQueue;
  404. /*
  405. * Scan the work queue once, calling each function. Those
  406. * which return TRUE are removed from the queue, otherwise
  407. * they will be called again. This must be reentrant with
  408. * QueueWorkProc.
  409. */
  410. while ((q = *p)) {
  411. if ((*q->function) (q->client, q->closure)) {
  412. /* remove q from the list */
  413. *p = q->next; /* don't fetch until after func called */
  414. free(q);
  415. }
  416. else {
  417. p = &q->next; /* don't fetch until after func called */
  418. }
  419. }
  420. workQueueLast = p;
  421. }
  422. void
  423. ProcessWorkQueueZombies(void)
  424. {
  425. WorkQueuePtr q, *p;
  426. p = &workQueue;
  427. while ((q = *p)) {
  428. if (q->client && q->client->clientGone) {
  429. (void) (*q->function) (q->client, q->closure);
  430. /* remove q from the list */
  431. *p = q->next; /* don't fetch until after func called */
  432. free(q);
  433. }
  434. else {
  435. p = &q->next; /* don't fetch until after func called */
  436. }
  437. }
  438. workQueueLast = p;
  439. }
  440. _X_EXPORT Bool
  441. QueueWorkProc(Bool (*function)
  442. (ClientPtr /* pClient */ , pointer /* closure */ ),
  443. ClientPtr client, pointer closure)
  444. {
  445. WorkQueuePtr q;
  446. q = malloc(sizeof *q);
  447. if (!q)
  448. return FALSE;
  449. q->function = function;
  450. q->client = client;
  451. q->closure = closure;
  452. q->next = NULL;
  453. *workQueueLast = q;
  454. workQueueLast = &q->next;
  455. return TRUE;
  456. }
  457. /*
  458. * Manage a queue of sleeping clients, awakening them
  459. * when requested, by using the OS functions IgnoreClient
  460. * and AttendClient. Note that this *ignores* the troubles
  461. * with request data interleaving itself with events, but
  462. * we'll leave that until a later time.
  463. */
  464. typedef struct _SleepQueue {
  465. struct _SleepQueue *next;
  466. ClientPtr client;
  467. ClientSleepProcPtr function;
  468. pointer closure;
  469. } SleepQueueRec, *SleepQueuePtr;
  470. static SleepQueuePtr sleepQueue = NULL;
  471. _X_EXPORT Bool
  472. ClientSleep(ClientPtr client, ClientSleepProcPtr function, pointer closure)
  473. {
  474. SleepQueuePtr q;
  475. q = malloc(sizeof *q);
  476. if (!q)
  477. return FALSE;
  478. IgnoreClient(client);
  479. q->next = sleepQueue;
  480. q->client = client;
  481. q->function = function;
  482. q->closure = closure;
  483. sleepQueue = q;
  484. return TRUE;
  485. }
  486. Bool
  487. ClientSignal(ClientPtr client)
  488. {
  489. SleepQueuePtr q;
  490. for (q = sleepQueue; q; q = q->next)
  491. if (q->client == client) {
  492. return QueueWorkProc(q->function, q->client, q->closure);
  493. }
  494. return FALSE;
  495. }
  496. _X_EXPORT void
  497. ClientWakeup(ClientPtr client)
  498. {
  499. SleepQueuePtr q, *prev;
  500. prev = &sleepQueue;
  501. while ((q = *prev)) {
  502. if (q->client == client) {
  503. *prev = q->next;
  504. free(q);
  505. if (client->clientGone)
  506. /* Oops -- new zombie cleanup code ensures this only
  507. * happens from inside CloseDownClient; don't want to
  508. * recurse here...
  509. */
  510. /* CloseDownClient(client) */ ;
  511. else
  512. AttendClient(client);
  513. break;
  514. }
  515. prev = &q->next;
  516. }
  517. }
  518. Bool
  519. ClientIsAsleep(ClientPtr client)
  520. {
  521. SleepQueuePtr q;
  522. for (q = sleepQueue; q; q = q->next)
  523. if (q->client == client)
  524. return TRUE;
  525. return FALSE;
  526. }
  527. /*
  528. * Generic Callback Manager
  529. */
  530. /* ===== Private Procedures ===== */
  531. static int numCallbackListsToCleanup = 0;
  532. static CallbackListPtr **listsToCleanup = NULL;
  533. static Bool
  534. _AddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data)
  535. {
  536. CallbackPtr cbr;
  537. cbr = malloc(sizeof(CallbackRec));
  538. if (!cbr)
  539. return FALSE;
  540. cbr->proc = callback;
  541. cbr->data = data;
  542. cbr->next = (*pcbl)->list;
  543. cbr->deleted = FALSE;
  544. (*pcbl)->list = cbr;
  545. return TRUE;
  546. }
  547. static Bool
  548. _DeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data)
  549. {
  550. CallbackListPtr cbl = *pcbl;
  551. CallbackPtr cbr, pcbr;
  552. for (pcbr = NULL, cbr = cbl->list; cbr != NULL; pcbr = cbr, cbr = cbr->next) {
  553. if ((cbr->proc == callback) && (cbr->data == data))
  554. break;
  555. }
  556. if (cbr != NULL) {
  557. if (cbl->inCallback) {
  558. ++(cbl->numDeleted);
  559. cbr->deleted = TRUE;
  560. }
  561. else {
  562. if (pcbr == NULL)
  563. cbl->list = cbr->next;
  564. else
  565. pcbr->next = cbr->next;
  566. free(cbr);
  567. }
  568. return TRUE;
  569. }
  570. return FALSE;
  571. }
  572. static void
  573. _CallCallbacks(CallbackListPtr *pcbl, pointer call_data)
  574. {
  575. CallbackListPtr cbl = *pcbl;
  576. CallbackPtr cbr, pcbr;
  577. ++(cbl->inCallback);
  578. for (cbr = cbl->list; cbr != NULL; cbr = cbr->next) {
  579. (*(cbr->proc)) (pcbl, cbr->data, call_data);
  580. }
  581. --(cbl->inCallback);
  582. if (cbl->inCallback)
  583. return;
  584. /* Was the entire list marked for deletion? */
  585. if (cbl->deleted) {
  586. DeleteCallbackList(pcbl);
  587. return;
  588. }
  589. /* Were some individual callbacks on the list marked for deletion?
  590. * If so, do the deletions.
  591. */
  592. if (cbl->numDeleted) {
  593. for (pcbr = NULL, cbr = cbl->list; (cbr != NULL) && cbl->numDeleted;) {
  594. if (cbr->deleted) {
  595. if (pcbr) {
  596. cbr = cbr->next;
  597. free(pcbr->next);
  598. pcbr->next = cbr;
  599. }
  600. else {
  601. cbr = cbr->next;
  602. free(cbl->list);
  603. cbl->list = cbr;
  604. }
  605. cbl->numDeleted--;
  606. }
  607. else { /* this one wasn't deleted */
  608. pcbr = cbr;
  609. cbr = cbr->next;
  610. }
  611. }
  612. }
  613. }
  614. static void
  615. _DeleteCallbackList(CallbackListPtr *pcbl)
  616. {
  617. CallbackListPtr cbl = *pcbl;
  618. CallbackPtr cbr, nextcbr;
  619. int i;
  620. if (cbl->inCallback) {
  621. cbl->deleted = TRUE;
  622. return;
  623. }
  624. for (i = 0; i < numCallbackListsToCleanup; i++) {
  625. if ((listsToCleanup[i] = pcbl) != 0) {
  626. listsToCleanup[i] = NULL;
  627. break;
  628. }
  629. }
  630. for (cbr = cbl->list; cbr != NULL; cbr = nextcbr) {
  631. nextcbr = cbr->next;
  632. free(cbr);
  633. }
  634. free(cbl);
  635. *pcbl = NULL;
  636. }
  637. static CallbackFuncsRec default_cbfuncs = {
  638. _AddCallback,
  639. _DeleteCallback,
  640. _CallCallbacks,
  641. _DeleteCallbackList
  642. };
  643. /* ===== Public Procedures ===== */
  644. Bool
  645. CreateCallbackList(CallbackListPtr *pcbl, CallbackFuncsPtr cbfuncs)
  646. {
  647. CallbackListPtr cbl;
  648. int i;
  649. if (!pcbl)
  650. return FALSE;
  651. cbl = malloc(sizeof(CallbackListRec));
  652. if (!cbl)
  653. return FALSE;
  654. cbl->funcs = cbfuncs ? *cbfuncs : default_cbfuncs;
  655. cbl->inCallback = 0;
  656. cbl->deleted = FALSE;
  657. cbl->numDeleted = 0;
  658. cbl->list = NULL;
  659. *pcbl = cbl;
  660. for (i = 0; i < numCallbackListsToCleanup; i++) {
  661. if (!listsToCleanup[i]) {
  662. listsToCleanup[i] = pcbl;
  663. return TRUE;
  664. }
  665. }
  666. listsToCleanup = (CallbackListPtr **) realloc(listsToCleanup,
  667. sizeof(CallbackListPtr *) *
  668. (numCallbackListsToCleanup
  669. + 1));
  670. listsToCleanup[numCallbackListsToCleanup] = pcbl;
  671. numCallbackListsToCleanup++;
  672. return TRUE;
  673. }
  674. _X_EXPORT Bool
  675. AddCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data)
  676. {
  677. if (!pcbl)
  678. return FALSE;
  679. if (!*pcbl) { /* list hasn't been created yet; go create it */
  680. if (!CreateCallbackList(pcbl, (CallbackFuncsPtr) NULL))
  681. return FALSE;
  682. }
  683. return ((*(*pcbl)->funcs.AddCallback) (pcbl, callback, data));
  684. }
  685. _X_EXPORT Bool
  686. DeleteCallback(CallbackListPtr *pcbl, CallbackProcPtr callback, pointer data)
  687. {
  688. if (!pcbl || !*pcbl)
  689. return FALSE;
  690. return ((*(*pcbl)->funcs.DeleteCallback) (pcbl, callback, data));
  691. }
  692. void
  693. CallCallbacks(CallbackListPtr *pcbl, pointer call_data)
  694. {
  695. if (!pcbl || !*pcbl)
  696. return;
  697. (*(*pcbl)->funcs.CallCallbacks) (pcbl, call_data);
  698. }
  699. void
  700. DeleteCallbackList(CallbackListPtr *pcbl)
  701. {
  702. if (!pcbl || !*pcbl)
  703. return;
  704. (*(*pcbl)->funcs.DeleteCallbackList) (pcbl);
  705. }
  706. void
  707. InitCallbackManager()
  708. {
  709. int i;
  710. for (i = 0; i < numCallbackListsToCleanup; i++) {
  711. DeleteCallbackList(listsToCleanup[i]);
  712. }
  713. if (listsToCleanup)
  714. free(listsToCleanup);
  715. numCallbackListsToCleanup = 0;
  716. listsToCleanup = NULL;
  717. }