Callback.c revision a3bd7f05
1/***********************************************************
2Copyright (c) 1993, Oracle and/or its affiliates. All rights reserved.
3
4Permission is hereby granted, free of charge, to any person obtaining a
5copy of this software and associated documentation files (the "Software"),
6to deal in the Software without restriction, including without limitation
7the rights to use, copy, modify, merge, publish, distribute, sublicense,
8and/or sell copies of the Software, and to permit persons to whom the
9Software is furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice (including the next
12paragraph) shall be included in all copies or substantial portions of the
13Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21DEALINGS IN THE SOFTWARE.
22
23Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
24
25                        All Rights Reserved
26
27Permission to use, copy, modify, and distribute this software and its
28documentation for any purpose and without fee is hereby granted,
29provided that the above copyright notice appear in all copies and that
30both that copyright notice and this permission notice appear in
31supporting documentation, and that the name of Digital not be
32used in advertising or publicity pertaining to distribution of the
33software without specific, written prior permission.
34
35DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
36ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
37DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
38ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
39WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
40ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
41SOFTWARE.
42
43******************************************************************/
44
45/*
46
47Copyright 1987, 1988, 1998  The Open Group
48
49Permission to use, copy, modify, distribute, and sell this software and its
50documentation for any purpose is hereby granted without fee, provided that
51the above copyright notice appear in all copies and that both that
52copyright notice and this permission notice appear in supporting
53documentation.
54
55The above copyright notice and this permission notice shall be included in
56all copies or substantial portions of the Software.
57
58THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
61OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
62AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
63CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
64
65Except as contained in this notice, the name of The Open Group shall not be
66used in advertising or otherwise to promote the sale, use or other dealings
67in this Software without prior written authorization from The Open Group.
68
69*/
70
71#ifdef HAVE_CONFIG_H
72#include <config.h>
73#endif
74#include "IntrinsicI.h"
75
76static _Xconst _XtString XtNinvalidCallbackList = "invalidCallbackList";
77static _Xconst _XtString XtNxtAddCallback = "xtAddCallback";
78static _Xconst _XtString XtNxtRemoveCallback = "xtRemoveCallback";
79static _Xconst _XtString XtNxtRemoveAllCallback = "xtRemoveAllCallback";
80static _Xconst _XtString XtNxtCallCallback = "xtCallCallback";
81
82/* However it doesn't contain a final NULL record */
83#define ToList(p) ((XtCallbackList) ((p)+1))
84
85static InternalCallbackList *
86FetchInternalList(Widget widget,
87                  _Xconst char *name)
88{
89    XrmQuark quark;
90    int n;
91    CallbackTable offsets;
92    InternalCallbackList *retval = NULL;
93
94    quark = StringToQuark(name);
95    LOCK_PROCESS;
96    offsets = (CallbackTable)
97        widget->core.widget_class->core_class.callback_private;
98
99    for (n = (int) (long) *(offsets++); --n >= 0; offsets++)
100        if (quark == (*offsets)->xrm_name) {
101            retval = (InternalCallbackList *)
102                ((char *) widget - (*offsets)->xrm_offset - 1);
103            break;
104        }
105    UNLOCK_PROCESS;
106    return retval;
107}
108
109void
110_XtAddCallback(InternalCallbackList *callbacks,
111               XtCallbackProc callback,
112               XtPointer closure)
113{
114    register InternalCallbackList icl;
115    register XtCallbackList cl;
116    register int count;
117
118    icl = *callbacks;
119    count = icl ? icl->count : 0;
120
121    if (icl && icl->call_state) {
122        icl->call_state |= _XtCBFreeAfterCalling;
123        icl = (InternalCallbackList)
124            __XtMalloc((Cardinal) (sizeof(InternalCallbackRec) +
125                                   sizeof(XtCallbackRec) * (size_t) (count +
126                                                                     1)));
127        (void) memmove((char *) ToList(icl), (char *) ToList(*callbacks),
128                       sizeof(XtCallbackRec) * (size_t) count);
129    }
130    else {
131        icl = (InternalCallbackList)
132            XtRealloc((char *) icl, (Cardinal) (sizeof(InternalCallbackRec) +
133                                                sizeof(XtCallbackRec) *
134                                                (size_t) (count + 1)));
135    }
136    *callbacks = icl;
137    icl->count = (unsigned short) (count + 1);
138    icl->is_padded = 0;
139    icl->call_state = 0;
140    cl = ToList(icl) + count;
141    cl->callback = callback;
142    cl->closure = closure;
143}                               /* _XtAddCallback */
144
145void
146_XtAddCallbackOnce(register InternalCallbackList *callbacks,
147                   XtCallbackProc callback,
148                   XtPointer closure)
149{
150    register XtCallbackList cl = ToList(*callbacks);
151    register int i;
152
153    for (i = (*callbacks)->count; --i >= 0; cl++)
154        if (cl->callback == callback && cl->closure == closure)
155            return;
156
157    _XtAddCallback(callbacks, callback, closure);
158}                               /* _XtAddCallbackOnce */
159
160void
161XtAddCallback(Widget widget,
162              _Xconst char *name,
163              XtCallbackProc callback,
164              XtPointer closure)
165{
166    InternalCallbackList *callbacks;
167    XtAppContext app = XtWidgetToApplicationContext(widget);
168
169    LOCK_APP(app);
170    callbacks = FetchInternalList(widget, name);
171    if (!callbacks) {
172        XtAppWarningMsg(app,
173                        XtNinvalidCallbackList, XtNxtAddCallback,
174                        XtCXtToolkitError,
175                        "Cannot find callback list in XtAddCallback", NULL,
176                        NULL);
177        UNLOCK_APP(app);
178        return;
179    }
180    _XtAddCallback(callbacks, callback, closure);
181    if (!_XtIsHookObject(widget)) {
182        Widget hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget));
183
184        if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
185            XtChangeHookDataRec call_data;
186
187            call_data.type = XtHaddCallback;
188            call_data.widget = widget;
189            call_data.event_data = (XtPointer) name;
190            XtCallCallbackList(hookobj,
191                               ((HookObject) hookobj)->hooks.
192                               changehook_callbacks, (XtPointer) &call_data);
193        }
194    }
195    UNLOCK_APP(app);
196}                               /* XtAddCallback */
197
198static void
199AddCallbacks(Widget widget _X_UNUSED,
200             InternalCallbackList *callbacks,
201             XtCallbackList newcallbacks)
202{
203    register InternalCallbackList icl;
204    register int i, j;
205    register XtCallbackList cl;
206
207    icl = *callbacks;
208    i = icl ? icl->count : 0;
209    for (j = 0, cl = newcallbacks; cl->callback; cl++, j++);
210    if (icl && icl->call_state) {
211        icl->call_state |= _XtCBFreeAfterCalling;
212        icl = (InternalCallbackList)
213            __XtMalloc((Cardinal)
214                       (sizeof(InternalCallbackRec) +
215                        sizeof(XtCallbackRec) * (size_t) (i + j)));
216        (void) memmove((char *) ToList(*callbacks), (char *) ToList(icl),
217                       sizeof(XtCallbackRec) * (size_t) i);
218    }
219    else {
220        icl = (InternalCallbackList) XtRealloc((char *) icl,
221                                               (Cardinal) (sizeof
222                                                           (InternalCallbackRec)
223                                                           +
224                                                           sizeof(XtCallbackRec)
225                                                           * (size_t) (i + j)));
226    }
227    *callbacks = icl;
228    icl->count = (unsigned short) (i + j);
229    icl->is_padded = 0;
230    icl->call_state = 0;
231    for (cl = ToList(icl) + i; --j >= 0;)
232        *cl++ = *newcallbacks++;
233}                               /* AddCallbacks */
234
235void
236XtAddCallbacks(Widget widget,
237               _Xconst char *name,
238               XtCallbackList xtcallbacks)
239{
240    InternalCallbackList *callbacks;
241    Widget hookobj;
242    XtAppContext app = XtWidgetToApplicationContext(widget);
243
244    LOCK_APP(app);
245    callbacks = FetchInternalList(widget, name);
246    if (!callbacks) {
247        XtAppWarningMsg(app,
248                        XtNinvalidCallbackList, XtNxtAddCallback,
249                        XtCXtToolkitError,
250                        "Cannot find callback list in XtAddCallbacks", NULL,
251                        NULL);
252        UNLOCK_APP(app);
253        return;
254    }
255    AddCallbacks(widget, callbacks, xtcallbacks);
256    hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget));
257    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
258        XtChangeHookDataRec call_data;
259
260        call_data.type = XtHaddCallbacks;
261        call_data.widget = widget;
262        call_data.event_data = (XtPointer) name;
263        XtCallCallbackList(hookobj,
264                           ((HookObject) hookobj)->hooks.changehook_callbacks,
265                           (XtPointer) &call_data);
266    }
267    UNLOCK_APP(app);
268}                               /* XtAddCallbacks */
269
270void
271_XtRemoveCallback(InternalCallbackList *callbacks,
272                  XtCallbackProc callback,
273                  XtPointer closure)
274{
275    register InternalCallbackList icl;
276    register int i, j;
277    register XtCallbackList cl, ncl, ocl;
278
279    icl = *callbacks;
280    if (!icl)
281        return;
282
283    cl = ToList(icl);
284    for (i = icl->count; --i >= 0; cl++) {
285        if (cl->callback == callback && cl->closure == closure) {
286            if (icl->call_state) {
287                icl->call_state |= _XtCBFreeAfterCalling;
288                if (icl->count == 1) {
289                    *callbacks = NULL;
290                }
291                else {
292                    j = icl->count - i - 1;
293                    ocl = ToList(icl);
294                    icl = (InternalCallbackList)
295                        __XtMalloc((Cardinal) (sizeof(InternalCallbackRec) +
296                                               sizeof(XtCallbackRec) *
297                                               (size_t) (i + j)));
298                    icl->count = (unsigned short) (i + j);
299                    icl->is_padded = 0;
300                    icl->call_state = 0;
301                    ncl = ToList(icl);
302                    while (--j >= 0)
303                        *ncl++ = *ocl++;
304                    while (--i >= 0)
305                        *ncl++ = *++cl;
306                    *callbacks = icl;
307                }
308            }
309            else {
310                if (--icl->count) {
311                    ncl = cl + 1;
312                    while (--i >= 0)
313                        *cl++ = *ncl++;
314                    icl = (InternalCallbackList)
315                        XtRealloc((char *) icl,
316                                  (Cardinal) (sizeof(InternalCallbackRec)
317                                              +
318                                              sizeof(XtCallbackRec) *
319                                              icl->count));
320                    icl->is_padded = 0;
321                    *callbacks = icl;
322                }
323                else {
324                    XtFree((char *) icl);
325                    *callbacks = NULL;
326                }
327            }
328            return;
329        }
330    }
331}                               /* _XtRemoveCallback */
332
333void
334XtRemoveCallback(Widget widget,
335                 _Xconst char *name,
336                 XtCallbackProc callback,
337                 XtPointer closure)
338{
339    InternalCallbackList *callbacks;
340    Widget hookobj;
341    XtAppContext app = XtWidgetToApplicationContext(widget);
342
343    LOCK_APP(app);
344    callbacks = FetchInternalList(widget, name);
345    if (!callbacks) {
346        XtAppWarningMsg(app,
347                        XtNinvalidCallbackList, XtNxtRemoveCallback,
348                        XtCXtToolkitError,
349                        "Cannot find callback list in XtRemoveCallback", NULL,
350                        NULL);
351        UNLOCK_APP(app);
352        return;
353    }
354    _XtRemoveCallback(callbacks, callback, closure);
355    hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget));
356    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
357        XtChangeHookDataRec call_data;
358
359        call_data.type = XtHremoveCallback;
360        call_data.widget = widget;
361        call_data.event_data = (XtPointer) name;
362        XtCallCallbackList(hookobj,
363                           ((HookObject) hookobj)->hooks.changehook_callbacks,
364                           (XtPointer) &call_data);
365    }
366    UNLOCK_APP(app);
367}                               /* XtRemoveCallback */
368
369void
370XtRemoveCallbacks(Widget widget,
371                  _Xconst char *name,
372                  XtCallbackList xtcallbacks)
373{
374    InternalCallbackList *callbacks;
375    Widget hookobj;
376    int i;
377    InternalCallbackList icl;
378    XtCallbackList cl, ccl, rcl;
379    XtAppContext app = XtWidgetToApplicationContext(widget);
380
381    LOCK_APP(app);
382    callbacks = FetchInternalList(widget, name);
383    if (!callbacks) {
384        XtAppWarningMsg(app,
385                        XtNinvalidCallbackList, XtNxtRemoveCallback,
386                        XtCXtToolkitError,
387                        "Cannot find callback list in XtRemoveCallbacks", NULL,
388                        NULL);
389        UNLOCK_APP(app);
390        return;
391    }
392
393    icl = *callbacks;
394    if (!icl) {
395        UNLOCK_APP(app);
396        return;
397    }
398
399    i = icl->count;
400    cl = ToList(icl);
401    if (icl->call_state) {
402        icl->call_state |= _XtCBFreeAfterCalling;
403        icl =
404            (InternalCallbackList)
405            __XtMalloc((Cardinal)
406                       (sizeof(InternalCallbackRec) +
407                        sizeof(XtCallbackRec) * (size_t) i));
408        icl->count = (unsigned short) i;
409        icl->call_state = 0;
410    }
411    ccl = ToList(icl);
412    while (--i >= 0) {
413        *ccl++ = *cl;
414        for (rcl = xtcallbacks; rcl->callback; rcl++) {
415            if (cl->callback == rcl->callback && cl->closure == rcl->closure) {
416                ccl--;
417                icl->count--;
418                break;
419            }
420        }
421        cl++;
422    }
423    if (icl->count) {
424        icl = (InternalCallbackList)
425            XtRealloc((char *) icl, (Cardinal) (sizeof(InternalCallbackRec) +
426                                                sizeof(XtCallbackRec) *
427                                                icl->count));
428        icl->is_padded = 0;
429        *callbacks = icl;
430    }
431    else {
432        XtFree((char *) icl);
433        *callbacks = NULL;
434    }
435    hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget));
436    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
437        XtChangeHookDataRec call_data;
438
439        call_data.type = XtHremoveCallbacks;
440        call_data.widget = widget;
441        call_data.event_data = (XtPointer) name;
442        XtCallCallbackList(hookobj,
443                           ((HookObject) hookobj)->hooks.changehook_callbacks,
444                           (XtPointer) &call_data);
445    }
446    UNLOCK_APP(app);
447}                               /* XtRemoveCallbacks */
448
449void
450_XtRemoveAllCallbacks(InternalCallbackList *callbacks)
451{
452    register InternalCallbackList icl = *callbacks;
453
454    if (icl) {
455        if (icl->call_state)
456            icl->call_state |= _XtCBFreeAfterCalling;
457        else
458            XtFree((char *) icl);
459        *callbacks = NULL;
460    }
461}                               /* _XtRemoveAllCallbacks */
462
463void
464XtRemoveAllCallbacks(Widget widget, _Xconst char *name)
465{
466    InternalCallbackList *callbacks;
467    Widget hookobj;
468    XtAppContext app = XtWidgetToApplicationContext(widget);
469
470    LOCK_APP(app);
471    callbacks = FetchInternalList(widget, name);
472    if (!callbacks) {
473        XtAppWarningMsg(app,
474                        XtNinvalidCallbackList, XtNxtRemoveAllCallback,
475                        XtCXtToolkitError,
476                        "Cannot find callback list in XtRemoveAllCallbacks",
477                        NULL, NULL);
478        UNLOCK_APP(app);
479        return;
480    }
481    _XtRemoveAllCallbacks(callbacks);
482    hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget));
483    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
484        XtChangeHookDataRec call_data;
485
486        call_data.type = XtHremoveAllCallbacks;
487        call_data.widget = widget;
488        call_data.event_data = (XtPointer) name;
489        XtCallCallbackList(hookobj,
490                           ((HookObject) hookobj)->hooks.changehook_callbacks,
491                           (XtPointer) &call_data);
492    }
493    UNLOCK_APP(app);
494}                               /* XtRemoveAllCallbacks */
495
496InternalCallbackList
497_XtCompileCallbackList(XtCallbackList xtcallbacks)
498{
499    register int n;
500    register XtCallbackList xtcl, cl;
501    register InternalCallbackList callbacks;
502
503    for (n = 0, xtcl = xtcallbacks; xtcl->callback; n++, xtcl++) {
504    };
505    if (n == 0)
506        return (InternalCallbackList) NULL;
507
508    callbacks =
509        (InternalCallbackList)
510        __XtMalloc((Cardinal)
511                   (sizeof(InternalCallbackRec) +
512                    sizeof(XtCallbackRec) * (size_t) n));
513    callbacks->count = (unsigned short) n;
514    callbacks->is_padded = 0;
515    callbacks->call_state = 0;
516    cl = ToList(callbacks);
517    while (--n >= 0)
518        *cl++ = *xtcallbacks++;
519    return (callbacks);
520}                               /* _XtCompileCallbackList */
521
522XtCallbackList
523_XtGetCallbackList(InternalCallbackList *callbacks)
524{
525    int i;
526    InternalCallbackList icl;
527    XtCallbackList cl;
528
529    icl = *callbacks;
530    if (!icl) {
531        static XtCallbackRec emptyList[1] = { {NULL, NULL} };
532        return (XtCallbackList) emptyList;
533    }
534    if (icl->is_padded)
535        return ToList(icl);
536    i = icl->count;
537    if (icl->call_state) {
538        XtCallbackList ocl;
539
540        icl->call_state |= _XtCBFreeAfterCalling;
541        ocl = ToList(icl);
542        icl = (InternalCallbackList)
543            __XtMalloc((Cardinal)
544                       (sizeof(InternalCallbackRec) +
545                        sizeof(XtCallbackRec) * (size_t) (i + 1)));
546        icl->count = (unsigned short) i;
547        icl->call_state = 0;
548        cl = ToList(icl);
549        while (--i >= 0)
550            *cl++ = *ocl++;
551    }
552    else {
553        icl = (InternalCallbackList)
554            XtRealloc((char *) icl, (Cardinal) (sizeof(InternalCallbackRec)
555                                                + sizeof(XtCallbackRec)
556                                                * (size_t) (i + 1)));
557        cl = ToList(icl) + i;
558    }
559    icl->is_padded = 1;
560    cl->callback = (XtCallbackProc) NULL;
561    cl->closure = NULL;
562    *callbacks = icl;
563    return ToList(icl);
564}
565
566void
567XtCallCallbacks(Widget widget,
568                _Xconst char *name,
569                XtPointer call_data)
570{
571    InternalCallbackList *callbacks;
572    InternalCallbackList icl;
573    XtCallbackList cl;
574    int i;
575    char ostate;
576    XtAppContext app = XtWidgetToApplicationContext(widget);
577
578    LOCK_APP(app);
579    callbacks = FetchInternalList(widget, name);
580    if (!callbacks) {
581        XtAppWarningMsg(app,
582                        XtNinvalidCallbackList, XtNxtCallCallback,
583                        XtCXtToolkitError,
584                        "Cannot find callback list in XtCallCallbacks", NULL,
585                        NULL);
586        UNLOCK_APP(app);
587        return;
588    }
589
590    icl = *callbacks;
591    if (!icl) {
592        UNLOCK_APP(app);
593        return;
594    }
595    cl = ToList(icl);
596    if (icl->count == 1) {
597        (*cl->callback) (widget, cl->closure, call_data);
598        UNLOCK_APP(app);
599        return;
600    }
601    ostate = icl->call_state;
602    icl->call_state = _XtCBCalling;
603    for (i = icl->count; --i >= 0; cl++)
604        (*cl->callback) (widget, cl->closure, call_data);
605    if (ostate)
606        icl->call_state |= ostate;
607    else if (icl->call_state & _XtCBFreeAfterCalling)
608        XtFree((char *) icl);
609    else
610        icl->call_state = ostate;
611    UNLOCK_APP(app);
612}                               /* XtCallCallbacks */
613
614XtCallbackStatus
615XtHasCallbacks(Widget widget,
616               _Xconst char *callback_name)
617{
618    InternalCallbackList *callbacks;
619    XtCallbackStatus retval = XtCallbackHasSome;
620
621    WIDGET_TO_APPCON(widget);
622
623    LOCK_APP(app);
624    callbacks = FetchInternalList(widget, callback_name);
625    if (!callbacks)
626        retval = XtCallbackNoList;
627    else if (!*callbacks)
628        retval = XtCallbackHasNone;
629    UNLOCK_APP(app);
630    return retval;
631}                               /* XtHasCallbacks */
632
633void
634XtCallCallbackList(Widget widget,
635                   XtCallbackList callbacks,
636                   XtPointer call_data)
637{
638    register InternalCallbackList icl;
639    register XtCallbackList cl;
640    register int i;
641    char ostate;
642
643    WIDGET_TO_APPCON(widget);
644
645    LOCK_APP(app);
646    if (!callbacks) {
647        UNLOCK_APP(app);
648        return;
649    }
650    icl = (InternalCallbackList) callbacks;
651    cl = ToList(icl);
652    if (icl->count == 1) {
653        (*cl->callback) (widget, cl->closure, call_data);
654        UNLOCK_APP(app);
655        return;
656    }
657    ostate = icl->call_state;
658    icl->call_state = _XtCBCalling;
659    for (i = icl->count; --i >= 0; cl++)
660        (*cl->callback) (widget, cl->closure, call_data);
661    if (ostate)
662        icl->call_state |= ostate;
663    else if (icl->call_state & _XtCBFreeAfterCalling)
664        XtFree((char *) icl);
665    else
666        icl->call_state = 0;
667    UNLOCK_APP(app);
668}                               /* XtCallCallbackList */
669
670void
671_XtPeekCallback(Widget widget _X_UNUSED,
672                XtCallbackList callbacks,
673                XtCallbackProc *callback,
674                XtPointer *closure)
675{
676    register InternalCallbackList icl = (InternalCallbackList) callbacks;
677    register XtCallbackList cl;
678
679    if (!callbacks) {
680        *callback = (XtCallbackProc) NULL;
681        return;
682    }
683    cl = ToList(icl);
684    *callback = cl->callback;
685    *closure = cl->closure;
686    return;
687}
688
689void
690_XtCallConditionalCallbackList(Widget widget,
691                               XtCallbackList callbacks,
692                               XtPointer call_data,
693                               _XtConditionProc cond_proc)
694{
695    register InternalCallbackList icl;
696    register XtCallbackList cl;
697    register int i;
698    char ostate;
699
700    WIDGET_TO_APPCON(widget);
701
702    LOCK_APP(app);
703    if (!callbacks) {
704        UNLOCK_APP(app);
705        return;
706    }
707    icl = (InternalCallbackList) callbacks;
708    cl = ToList(icl);
709    if (icl->count == 1) {
710        (*cl->callback) (widget, cl->closure, call_data);
711        (void) (*cond_proc) (call_data);
712        UNLOCK_APP(app);
713        return;
714    }
715    ostate = icl->call_state;
716    icl->call_state = _XtCBCalling;
717    for (i = icl->count; --i >= 0; cl++) {
718        (*cl->callback) (widget, cl->closure, call_data);
719        if (!(*cond_proc) (call_data))
720            break;
721    }
722    if (ostate)
723        icl->call_state |= ostate;
724    else if (icl->call_state & _XtCBFreeAfterCalling)
725        XtFree((char *) icl);
726    else
727        icl->call_state = 0;
728    UNLOCK_APP(app);
729}
730