Destroy.c revision 0568f49b
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, 1994, 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 76struct _DestroyRec { 77 int dispatch_level; 78 Widget widget; 79}; 80 81static void Recursive(Widget widget, XtWidgetProc proc) 82{ 83 register Cardinal i; 84 85 /* Recurse down normal children */ 86 if (XtIsComposite(widget)) { 87 CompositePart *cwp = &(((CompositeWidget) widget)->composite); 88 for (i = 0; i < cwp->num_children; i++) { 89 Recursive(cwp->children[i], proc); 90 } 91 } 92 93 /* Recurse down popup children */ 94 if (XtIsWidget(widget)) { 95 for (i = 0; i < widget->core.num_popups; i++) { 96 Recursive(widget->core.popup_list[i], proc); 97 } 98 } 99 100 /* Finally, apply procedure to this widget */ 101 (*proc) (widget); 102} /* Recursive */ 103 104static void Phase1Destroy (Widget widget) 105{ 106 Widget hookobj = XtHooksOfDisplay(XtDisplayOfObject(widget)); 107 108 widget->core.being_destroyed = TRUE; 109 if (XtHasCallbacks(hookobj, XtNdestroyHook) == XtCallbackHasSome) { 110 XtDestroyHookDataRec call_data; 111 112 call_data.type = XtHdestroy; 113 call_data.widget = widget; 114 XtCallCallbackList(hookobj, 115 ((HookObject)hookobj)->hooks.destroyhook_callbacks, 116 (XtPointer) &call_data); 117 } 118} /* Phase1Destroy */ 119 120static void Phase2Callbacks(Widget widget) 121{ 122 if (widget->core.destroy_callbacks != NULL) { 123 XtCallCallbackList(widget, 124 widget->core.destroy_callbacks, (XtPointer) NULL); 125 } 126} /* Phase2Callbacks */ 127 128static void Phase2Destroy(register Widget widget) 129{ 130 register WidgetClass class; 131 register ConstraintWidgetClass cwClass; 132 ObjectClassExtension ext; 133 134 /* Call constraint destroy procedures */ 135 if (XtParent(widget) != NULL && !XtIsShell(widget) && XtIsConstraint(XtParent(widget))) { 136 LOCK_PROCESS; 137 cwClass = (ConstraintWidgetClass)XtParent(widget)->core.widget_class; 138 UNLOCK_PROCESS; 139 for (;;) { 140 XtWidgetProc destroy; 141 142 LOCK_PROCESS; 143 destroy = cwClass->constraint_class.destroy; 144 UNLOCK_PROCESS; 145 if (destroy) 146 (*destroy) (widget); 147 if (cwClass == (ConstraintWidgetClass)constraintWidgetClass) break; 148 LOCK_PROCESS; 149 cwClass = (ConstraintWidgetClass) cwClass->core_class.superclass; 150 UNLOCK_PROCESS; 151 } 152 } 153 154 /* Call widget destroy procedures */ 155 LOCK_PROCESS; 156 for (class = widget->core.widget_class; 157 class != NULL; 158 class = class->core_class.superclass) { 159 XtWidgetProc destroy; 160 161 destroy = class->core_class.destroy; 162 UNLOCK_PROCESS; 163 if (destroy) 164 (*destroy) (widget); 165 LOCK_PROCESS; 166 } 167 168 /* Call widget deallocate procedure */ 169 ext = (ObjectClassExtension) 170 XtGetClassExtension(widget->core.widget_class, 171 XtOffsetOf(CoreClassPart, extension), 172 NULLQUARK, XtObjectExtensionVersion, 173 sizeof(ObjectClassExtensionRec)); 174 if (ext && ext->deallocate) { 175 XtDeallocateProc deallocate; 176 deallocate = ext->deallocate; 177 UNLOCK_PROCESS; 178 (*deallocate)(widget, NULL); 179 } else { 180 UNLOCK_PROCESS; 181 XtFree((char *)widget); 182 } 183} /* Phase2Destroy */ 184 185static Boolean IsDescendant(Widget widget, Widget root) 186{ 187 while ((widget = XtParent(widget)) != root) { 188 if (widget == NULL) return False; 189 } 190 return True; 191} 192 193static void XtPhase2Destroy (Widget widget) 194{ 195 Display *display = NULL; 196 Window window; 197 Widget parent; 198 XtAppContext app = XtWidgetToApplicationContext(widget); 199 Widget outerInPhase2Destroy = app->in_phase2_destroy; 200 int starting_count = app->destroy_count; 201 Boolean isPopup = False; 202 203 /* invalidate focus trace cache for this display */ 204 _XtGetPerDisplay(XtDisplayOfObject(widget))->pdi.traceDepth = 0; 205 206 parent = widget->core.parent; 207 208 if (parent && XtIsWidget(parent) && parent->core.num_popups) { 209 Cardinal i; 210 for (i = 0; i < parent->core.num_popups; i++) { 211 if (parent->core.popup_list[i] == widget) { 212 isPopup = True; 213 break; 214 } 215 } 216 } 217 218 if (!isPopup && parent && XtIsComposite(parent)) { 219 XtWidgetProc delete_child; 220 221 LOCK_PROCESS; 222 delete_child = 223 ((CompositeWidgetClass) parent->core.widget_class)-> 224 composite_class.delete_child; 225 UNLOCK_PROCESS; 226 if (XtIsRectObj(widget)) { 227 XtUnmanageChild(widget); 228 } 229 if (delete_child == NULL) { 230 String param; 231 Cardinal num_params = 1; 232 233 LOCK_PROCESS; 234 param = parent->core.widget_class->core_class.class_name; 235 UNLOCK_PROCESS; 236 XtAppWarningMsg(XtWidgetToApplicationContext(widget), 237 "invalidProcedure","deleteChild",XtCXtToolkitError, 238 "null delete_child procedure for class %s in XtDestroy", 239 ¶m, &num_params); 240 } else { 241 (*delete_child) (widget); 242 } 243 } 244 245 /* widget is freed in Phase2Destroy, so retrieve window now. 246 * Shells destroy their own windows, to prevent window leaks in 247 * popups; this test is practical only when XtIsShell() is cheap. 248 */ 249 if (XtIsShell(widget) || !XtIsWidget(widget)) { 250 window = 0; 251 } 252 else { 253 display = XtDisplay(widget); 254 window = widget->core.window; 255 } 256 257 Recursive(widget, Phase2Callbacks); 258 if (app->destroy_count > starting_count) { 259 int i = starting_count; 260 while (i < app->destroy_count) { 261 262 DestroyRec * dr = app->destroy_list + i; 263 if (IsDescendant(dr->widget, widget)) { 264 Widget descendant = dr->widget; 265 register int j; 266 app->destroy_count--; 267 for (j = app->destroy_count - i; --j >= 0; dr++) 268 *dr = *(dr + 1); 269 XtPhase2Destroy(descendant); 270 } 271 else i++; 272 } 273 } 274 275 app->in_phase2_destroy = widget; 276 Recursive(widget, Phase2Destroy); 277 app->in_phase2_destroy = outerInPhase2Destroy; 278 279 if (isPopup) { 280 Cardinal i; 281 for (i = 0; i < parent->core.num_popups; i++) 282 if (parent->core.popup_list[i] == widget) { 283 parent->core.num_popups--; 284 while (i < parent->core.num_popups) { 285 parent->core.popup_list[i] = parent->core.popup_list[i+1]; 286 i++; 287 } 288 break; 289 } 290 } 291 292 /* %%% the following parent test hides a more serious problem, 293 but it avoids breaking those who depended on the old bug 294 until we have time to fix it properly. */ 295 296 if (window && (parent == NULL || !parent->core.being_destroyed)) 297 XDestroyWindow(display, window); 298} /* XtPhase2Destroy */ 299 300 301void _XtDoPhase2Destroy(XtAppContext app, int dispatch_level) 302{ 303 /* Phase 2 must occur in fifo order. List is not necessarily 304 * contiguous in dispatch_level. 305 */ 306 307 int i = 0; 308 while (i < app->destroy_count) { 309 310 /* XtPhase2Destroy can result in calls to XtDestroyWidget, 311 * and these could cause app->destroy_list to be reallocated. 312 */ 313 314 DestroyRec* dr = app->destroy_list + i; 315 if (dr->dispatch_level >= dispatch_level) { 316 Widget w = dr->widget; 317 register int j; 318 app->destroy_count--; 319 for (j = app->destroy_count - i; --j >=0; dr++) 320 *dr = *(dr + 1); 321 XtPhase2Destroy(w); 322 } 323 else i++; 324 } 325} 326 327 328void XtDestroyWidget (Widget widget) 329{ 330 XtAppContext app; 331 DestroyRec *dr; 332 333 app = XtWidgetToApplicationContext(widget); 334 LOCK_APP(app); 335 if (widget->core.being_destroyed) { 336 UNLOCK_APP(app); 337 return; 338 } 339 Recursive(widget, Phase1Destroy); 340 341 if (app->in_phase2_destroy && 342 IsDescendant(widget, app->in_phase2_destroy)) 343 { 344 XtPhase2Destroy(widget); 345 UNLOCK_APP(app); 346 return; 347 } 348 349 if (app->destroy_count == app->destroy_list_size) { 350 app->destroy_list_size += 10; 351 app->destroy_list = (DestroyRec*) 352 XtRealloc( (char*)app->destroy_list, 353 (Cardinal)(sizeof(DestroyRec) * (size_t)app->destroy_list_size) 354 ); 355 } 356 dr = app->destroy_list + app->destroy_count++; 357 dr->dispatch_level = app->dispatch_level; 358 dr->widget = widget; 359 360 if (app->dispatch_level > 1) { 361 int i; 362 for (i = app->destroy_count - 1; i;) { 363 /* this handles only one case of nesting difficulties */ 364 dr = app->destroy_list + (--i); 365 if (dr->dispatch_level < app->dispatch_level && 366 IsDescendant(dr->widget, widget)) { 367 DestroyRec *dr2 = app->destroy_list + (app->destroy_count-1); 368 dr2->dispatch_level = dr->dispatch_level; 369 break; 370 } 371 } 372 } 373 374 if (_XtSafeToDestroy(app)) { 375 app->dispatch_level = 1; /* avoid nested _XtDoPhase2Destroy */ 376 _XtDoPhase2Destroy(app, 0); 377 app->dispatch_level = 0; 378 } 379 UNLOCK_APP(app); 380 381} /* XtDestroyWidget */ 382