Home | History | Annotate | Line # | Download | only in src
      1 /***********************************************************
      2 Copyright (c) 1993, Oracle and/or its affiliates.
      3 
      4 Permission is hereby granted, free of charge, to any person obtaining a
      5 copy of this software and associated documentation files (the "Software"),
      6 to deal in the Software without restriction, including without limitation
      7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 and/or sell copies of the Software, and to permit persons to whom the
      9 Software is furnished to do so, subject to the following conditions:
     10 
     11 The above copyright notice and this permission notice (including the next
     12 paragraph) shall be included in all copies or substantial portions of the
     13 Software.
     14 
     15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     21 DEALINGS IN THE SOFTWARE.
     22 
     23 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
     24 
     25                         All Rights Reserved
     26 
     27 Permission to use, copy, modify, and distribute this software and its
     28 documentation for any purpose and without fee is hereby granted,
     29 provided that the above copyright notice appear in all copies and that
     30 both that copyright notice and this permission notice appear in
     31 supporting documentation, and that the name of Digital not be
     32 used in advertising or publicity pertaining to distribution of the
     33 software without specific, written prior permission.
     34 
     35 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
     36 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
     37 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
     38 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
     39 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
     40 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
     41 SOFTWARE.
     42 
     43 ******************************************************************/
     44 
     45 /*
     46 
     47 Copyright 1987, 1988, 1994, 1998  The Open Group
     48 
     49 Permission to use, copy, modify, distribute, and sell this software and its
     50 documentation for any purpose is hereby granted without fee, provided that
     51 the above copyright notice appear in all copies and that both that
     52 copyright notice and this permission notice appear in supporting
     53 documentation.
     54 
     55 The above copyright notice and this permission notice shall be included in
     56 all copies or substantial portions of the Software.
     57 
     58 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     59 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     60 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     61 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     62 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     63 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     64 
     65 Except as contained in this notice, the name of The Open Group shall not be
     66 used in advertising or otherwise to promote the sale, use or other dealings
     67 in 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 
     76 struct _DestroyRec {
     77     int dispatch_level;
     78     Widget widget;
     79 };
     80 
     81 static void
     82 Recursive(Widget widget, XtWidgetProc proc)
     83 {
     84     register Cardinal i;
     85 
     86     /* Recurse down normal children */
     87     if (XtIsComposite(widget)) {
     88         CompositePart *cwp = &(((CompositeWidget) widget)->composite);
     89 
     90         for (i = 0; i < cwp->num_children; i++) {
     91             Recursive(cwp->children[i], proc);
     92         }
     93     }
     94 
     95     /* Recurse down popup children */
     96     if (XtIsWidget(widget)) {
     97         for (i = 0; i < widget->core.num_popups; i++) {
     98             Recursive(widget->core.popup_list[i], proc);
     99         }
    100     }
    101 
    102     /* Finally, apply procedure to this widget */
    103     (*proc) (widget);
    104 }                               /* Recursive */
    105 
    106 static void
    107 Phase1Destroy(Widget widget)
    108 {
    109     Widget hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget));
    110 
    111     widget->core.being_destroyed = TRUE;
    112     if (XtHasCallbacks(hookobj, XtNdestroyHook) == XtCallbackHasSome) {
    113         XtDestroyHookDataRec call_data;
    114 
    115         call_data.type = XtHdestroy;
    116         call_data.widget = widget;
    117         XtCallCallbackList(hookobj,
    118                            ((HookObject) hookobj)->hooks.destroyhook_callbacks,
    119                            (XtPointer) &call_data);
    120     }
    121 }                               /* Phase1Destroy */
    122 
    123 static void
    124 Phase2Callbacks(Widget widget)
    125 {
    126     if (widget->core.destroy_callbacks != NULL) {
    127         XtCallCallbackList(widget,
    128                            widget->core.destroy_callbacks, (XtPointer) NULL);
    129     }
    130 }                               /* Phase2Callbacks */
    131 
    132 static void
    133 Phase2Destroy(register Widget widget)
    134 {
    135     register WidgetClass class;
    136     register ConstraintWidgetClass cwClass;
    137     ObjectClassExtension ext;
    138 
    139     /* Call constraint destroy procedures */
    140     if (XtParent(widget) != NULL && !XtIsShell(widget) &&
    141         XtIsConstraint(XtParent(widget))) {
    142         LOCK_PROCESS;
    143         cwClass = (ConstraintWidgetClass) XtParent(widget)->core.widget_class;
    144         UNLOCK_PROCESS;
    145         for (;;) {
    146             XtWidgetProc destroy;
    147 
    148             LOCK_PROCESS;
    149             destroy = cwClass->constraint_class.destroy;
    150             UNLOCK_PROCESS;
    151             if (destroy)
    152                 (*destroy) (widget);
    153             if (cwClass == (ConstraintWidgetClass) constraintWidgetClass)
    154                 break;
    155             LOCK_PROCESS;
    156             cwClass = (ConstraintWidgetClass) cwClass->core_class.superclass;
    157             UNLOCK_PROCESS;
    158         }
    159     }
    160 
    161     /* Call widget destroy procedures */
    162     LOCK_PROCESS;
    163     for (class = widget->core.widget_class;
    164          class != NULL; class = class->core_class.superclass) {
    165         XtWidgetProc destroy;
    166 
    167         destroy = class->core_class.destroy;
    168         UNLOCK_PROCESS;
    169         if (destroy)
    170             (*destroy) (widget);
    171         LOCK_PROCESS;
    172     }
    173 
    174     /* Call widget deallocate procedure */
    175     ext = (ObjectClassExtension) XtGetClassExtension(widget->core.widget_class,
    176                                                      XtOffsetOf(CoreClassPart,
    177                                                                 extension),
    178                                                      NULLQUARK,
    179                                                      XtObjectExtensionVersion,
    180                                                      sizeof
    181                                                      (ObjectClassExtensionRec));
    182     if (ext && ext->deallocate) {
    183         XtDeallocateProc deallocate;
    184 
    185         deallocate = ext->deallocate;
    186         UNLOCK_PROCESS;
    187         (*deallocate) (widget, NULL);
    188     }
    189     else {
    190         UNLOCK_PROCESS;
    191         XtFree((char *) widget);
    192     }
    193 }                               /* Phase2Destroy */
    194 
    195 static Boolean
    196 IsDescendant(Widget widget, const Widget root)
    197 {
    198     while (widget != NULL && (widget = XtParent(widget)) != root) {
    199         ;
    200     }
    201     return (widget != NULL) ? True : False;
    202 }
    203 
    204 static void
    205 XtPhase2Destroy(Widget widget)
    206 {
    207     Display *display = NULL;
    208     Window window;
    209     Widget parent;
    210     XtAppContext app = XtWidgetToApplicationContext(widget);
    211     Widget outerInPhase2Destroy = app->in_phase2_destroy;
    212     int starting_count = app->destroy_count;
    213     Boolean isPopup = False;
    214 
    215     /* invalidate focus trace cache for this display */
    216     _XtGetPerDisplay(XtDisplayOfObject(widget))->pdi.traceDepth = 0;
    217 
    218     parent = widget->core.parent;
    219 
    220     if (parent && XtIsWidget(parent) && parent->core.num_popups) {
    221         Cardinal i;
    222 
    223         for (i = 0; i < parent->core.num_popups; i++) {
    224             if (parent->core.popup_list[i] == widget) {
    225                 isPopup = True;
    226                 break;
    227             }
    228         }
    229     }
    230 
    231     if (!isPopup && parent && XtIsComposite(parent)) {
    232         XtWidgetProc delete_child;
    233 
    234         LOCK_PROCESS;
    235         delete_child =
    236             ((CompositeWidgetClass) parent->core.widget_class)->composite_class.
    237             delete_child;
    238         UNLOCK_PROCESS;
    239         if (XtIsRectObj(widget)) {
    240             XtUnmanageChild(widget);
    241         }
    242         if (delete_child == NULL) {
    243             String param;
    244             Cardinal num_params = 1;
    245 
    246             LOCK_PROCESS;
    247             param = parent->core.widget_class->core_class.class_name;
    248             UNLOCK_PROCESS;
    249             XtAppWarningMsg(XtWidgetToApplicationContext(widget),
    250                             "invalidProcedure", "deleteChild",
    251                             XtCXtToolkitError,
    252                             "null delete_child procedure for class %s in XtDestroy",
    253                             &param, &num_params);
    254         }
    255         else {
    256             (*delete_child) (widget);
    257         }
    258     }
    259 
    260     /* widget is freed in Phase2Destroy, so retrieve window now.
    261      * Shells destroy their own windows, to prevent window leaks in
    262      * popups; this test is practical only when XtIsShell() is cheap.
    263      */
    264     if (XtIsShell(widget) || !XtIsWidget(widget)) {
    265         window = 0;
    266     }
    267     else {
    268         display = XtDisplay(widget);
    269 
    270         window = widget->core.window;
    271     }
    272 
    273     Recursive(widget, Phase2Callbacks);
    274     if (app->destroy_count > starting_count) {
    275         int i = starting_count;
    276 
    277         while (i < app->destroy_count) {
    278 
    279             DestroyRec *dr = app->destroy_list + i;
    280 
    281             if (IsDescendant(dr->widget, widget)) {
    282                 Widget descendant = dr->widget;
    283                 register int j;
    284 
    285                 app->destroy_count--;
    286                 for (j = app->destroy_count - i; --j >= 0; dr++)
    287                     *dr = *(dr + 1);
    288                 XtPhase2Destroy(descendant);
    289             }
    290             else
    291                 i++;
    292         }
    293     }
    294 
    295     app->in_phase2_destroy = widget;
    296     Recursive(widget, Phase2Destroy);
    297     app->in_phase2_destroy = outerInPhase2Destroy;
    298 
    299     if (isPopup) {
    300         Cardinal i;
    301 
    302         for (i = 0; i < parent->core.num_popups; i++)
    303             if (parent->core.popup_list[i] == widget) {
    304                 parent->core.num_popups--;
    305                 while (i < parent->core.num_popups) {
    306                     parent->core.popup_list[i] = parent->core.popup_list[i + 1];
    307                     i++;
    308                 }
    309                 break;
    310             }
    311     }
    312 
    313     /* %%% the following parent test hides a more serious problem,
    314        but it avoids breaking those who depended on the old bug
    315        until we have time to fix it properly. */
    316 
    317     if (window && (parent == NULL || !parent->core.being_destroyed))
    318         XDestroyWindow(display, window);
    319 }                               /* XtPhase2Destroy */
    320 
    321 void
    322 _XtDoPhase2Destroy(XtAppContext app, int dispatch_level)
    323 {
    324     /* Phase 2 must occur in fifo order.  List is not necessarily
    325      * contiguous in dispatch_level.
    326      */
    327 
    328     int i = 0;
    329 
    330     while (i < app->destroy_count) {
    331 
    332         /* XtPhase2Destroy can result in calls to XtDestroyWidget,
    333          * and these could cause app->destroy_list to be reallocated.
    334          */
    335 
    336         DestroyRec *dr = app->destroy_list + i;
    337 
    338         if (dr->dispatch_level >= dispatch_level) {
    339             Widget w = dr->widget;
    340             register int j;
    341 
    342             app->destroy_count--;
    343             for (j = app->destroy_count - i; --j >= 0; dr++)
    344                 *dr = *(dr + 1);
    345             XtPhase2Destroy(w);
    346         }
    347         else
    348             i++;
    349     }
    350 }
    351 
    352 void
    353 XtDestroyWidget(Widget widget)
    354 {
    355     XtAppContext app;
    356     DestroyRec *dr;
    357 
    358     app = XtWidgetToApplicationContext(widget);
    359     LOCK_APP(app);
    360     if (widget->core.being_destroyed) {
    361         UNLOCK_APP(app);
    362         return;
    363     }
    364     Recursive(widget, Phase1Destroy);
    365 
    366     if (app->in_phase2_destroy && IsDescendant(widget, app->in_phase2_destroy)) {
    367         XtPhase2Destroy(widget);
    368         UNLOCK_APP(app);
    369         return;
    370     }
    371 
    372     if (app->destroy_count == app->destroy_list_size) {
    373         app->destroy_list_size += 10;
    374         app->destroy_list = XtReallocArray(app->destroy_list,
    375                                            (Cardinal) app->destroy_list_size,
    376                                            (Cardinal) sizeof(DestroyRec));
    377     }
    378     dr = app->destroy_list + app->destroy_count++;
    379     dr->dispatch_level = app->dispatch_level;
    380     dr->widget = widget;
    381 
    382     if (app->dispatch_level > 1) {
    383         int i;
    384 
    385         for (i = app->destroy_count - 1; i;) {
    386             /* this handles only one case of nesting difficulties */
    387             dr = app->destroy_list + (--i);
    388             if (dr->dispatch_level < app->dispatch_level &&
    389                 IsDescendant(dr->widget, widget)) {
    390                 DestroyRec *dr2 = app->destroy_list + (app->destroy_count - 1);
    391 
    392                 dr2->dispatch_level = dr->dispatch_level;
    393                 break;
    394             }
    395         }
    396     }
    397 
    398     if (_XtSafeToDestroy(app)) {
    399         app->dispatch_level = 1;        /* avoid nested _XtDoPhase2Destroy */
    400         _XtDoPhase2Destroy(app, 0);
    401         app->dispatch_level = 0;
    402     }
    403     UNLOCK_APP(app);
    404 
    405 }                               /* XtDestroyWidget */
    406