Destroy.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, 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 82Recursive(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 106static void 107Phase1Destroy(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 123static void 124Phase2Callbacks(Widget widget) 125{ 126 if (widget->core.destroy_callbacks != NULL) { 127 XtCallCallbackList(widget, 128 widget->core.destroy_callbacks, (XtPointer) NULL); 129 } 130} /* Phase2Callbacks */ 131 132static void 133Phase2Destroy(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 195static Boolean 196IsDescendant(Widget widget, Widget root) 197{ 198 while ((widget = XtParent(widget)) != root) { 199 if (widget == NULL) 200 return False; 201 } 202 return True; 203} 204 205static void 206XtPhase2Destroy(Widget widget) 207{ 208 Display *display = NULL; 209 Window window; 210 Widget parent; 211 XtAppContext app = XtWidgetToApplicationContext(widget); 212 Widget outerInPhase2Destroy = app->in_phase2_destroy; 213 int starting_count = app->destroy_count; 214 Boolean isPopup = False; 215 216 /* invalidate focus trace cache for this display */ 217 _XtGetPerDisplay(XtDisplayOfObject(widget))->pdi.traceDepth = 0; 218 219 parent = widget->core.parent; 220 221 if (parent && XtIsWidget(parent) && parent->core.num_popups) { 222 Cardinal i; 223 224 for (i = 0; i < parent->core.num_popups; i++) { 225 if (parent->core.popup_list[i] == widget) { 226 isPopup = True; 227 break; 228 } 229 } 230 } 231 232 if (!isPopup && parent && XtIsComposite(parent)) { 233 XtWidgetProc delete_child; 234 235 LOCK_PROCESS; 236 delete_child = 237 ((CompositeWidgetClass) parent->core.widget_class)->composite_class. 238 delete_child; 239 UNLOCK_PROCESS; 240 if (XtIsRectObj(widget)) { 241 XtUnmanageChild(widget); 242 } 243 if (delete_child == NULL) { 244 String param; 245 Cardinal num_params = 1; 246 247 LOCK_PROCESS; 248 param = parent->core.widget_class->core_class.class_name; 249 UNLOCK_PROCESS; 250 XtAppWarningMsg(XtWidgetToApplicationContext(widget), 251 "invalidProcedure", "deleteChild", 252 XtCXtToolkitError, 253 "null delete_child procedure for class %s in XtDestroy", 254 ¶m, &num_params); 255 } 256 else { 257 (*delete_child) (widget); 258 } 259 } 260 261 /* widget is freed in Phase2Destroy, so retrieve window now. 262 * Shells destroy their own windows, to prevent window leaks in 263 * popups; this test is practical only when XtIsShell() is cheap. 264 */ 265 if (XtIsShell(widget) || !XtIsWidget(widget)) { 266 window = 0; 267 } 268 else { 269 display = XtDisplay(widget); 270 271 window = widget->core.window; 272 } 273 274 Recursive(widget, Phase2Callbacks); 275 if (app->destroy_count > starting_count) { 276 int i = starting_count; 277 278 while (i < app->destroy_count) { 279 280 DestroyRec *dr = app->destroy_list + i; 281 282 if (IsDescendant(dr->widget, widget)) { 283 Widget descendant = dr->widget; 284 register int j; 285 286 app->destroy_count--; 287 for (j = app->destroy_count - i; --j >= 0; dr++) 288 *dr = *(dr + 1); 289 XtPhase2Destroy(descendant); 290 } 291 else 292 i++; 293 } 294 } 295 296 app->in_phase2_destroy = widget; 297 Recursive(widget, Phase2Destroy); 298 app->in_phase2_destroy = outerInPhase2Destroy; 299 300 if (isPopup) { 301 Cardinal i; 302 303 for (i = 0; i < parent->core.num_popups; i++) 304 if (parent->core.popup_list[i] == widget) { 305 parent->core.num_popups--; 306 while (i < parent->core.num_popups) { 307 parent->core.popup_list[i] = parent->core.popup_list[i + 1]; 308 i++; 309 } 310 break; 311 } 312 } 313 314 /* %%% the following parent test hides a more serious problem, 315 but it avoids breaking those who depended on the old bug 316 until we have time to fix it properly. */ 317 318 if (window && (parent == NULL || !parent->core.being_destroyed)) 319 XDestroyWindow(display, window); 320} /* XtPhase2Destroy */ 321 322void 323_XtDoPhase2Destroy(XtAppContext app, int dispatch_level) 324{ 325 /* Phase 2 must occur in fifo order. List is not necessarily 326 * contiguous in dispatch_level. 327 */ 328 329 int i = 0; 330 331 while (i < app->destroy_count) { 332 333 /* XtPhase2Destroy can result in calls to XtDestroyWidget, 334 * and these could cause app->destroy_list to be reallocated. 335 */ 336 337 DestroyRec *dr = app->destroy_list + i; 338 339 if (dr->dispatch_level >= dispatch_level) { 340 Widget w = dr->widget; 341 register int j; 342 343 app->destroy_count--; 344 for (j = app->destroy_count - i; --j >= 0; dr++) 345 *dr = *(dr + 1); 346 XtPhase2Destroy(w); 347 } 348 else 349 i++; 350 } 351} 352 353void 354XtDestroyWidget(Widget widget) 355{ 356 XtAppContext app; 357 DestroyRec *dr; 358 359 app = XtWidgetToApplicationContext(widget); 360 LOCK_APP(app); 361 if (widget->core.being_destroyed) { 362 UNLOCK_APP(app); 363 return; 364 } 365 Recursive(widget, Phase1Destroy); 366 367 if (app->in_phase2_destroy && IsDescendant(widget, app->in_phase2_destroy)) { 368 XtPhase2Destroy(widget); 369 UNLOCK_APP(app); 370 return; 371 } 372 373 if (app->destroy_count == app->destroy_list_size) { 374 app->destroy_list_size += 10; 375 app->destroy_list = (DestroyRec *) 376 XtRealloc((char *) app->destroy_list, 377 (Cardinal) (sizeof(DestroyRec) * 378 (size_t) app->destroy_list_size) 379 ); 380 } 381 dr = app->destroy_list + app->destroy_count++; 382 dr->dispatch_level = app->dispatch_level; 383 dr->widget = widget; 384 385 if (app->dispatch_level > 1) { 386 int i; 387 388 for (i = app->destroy_count - 1; i;) { 389 /* this handles only one case of nesting difficulties */ 390 dr = app->destroy_list + (--i); 391 if (dr->dispatch_level < app->dispatch_level && 392 IsDescendant(dr->widget, widget)) { 393 DestroyRec *dr2 = app->destroy_list + (app->destroy_count - 1); 394 395 dr2->dispatch_level = dr->dispatch_level; 396 break; 397 } 398 } 399 } 400 401 if (_XtSafeToDestroy(app)) { 402 app->dispatch_level = 1; /* avoid nested _XtDoPhase2Destroy */ 403 _XtDoPhase2Destroy(app, 0); 404 app->dispatch_level = 0; 405 } 406 UNLOCK_APP(app); 407 408} /* XtDestroyWidget */ 409