Destroy.c revision fdf6a26f
1/*********************************************************** 2Copyright (c) 1993, Oracle and/or its affiliates. 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, const Widget root) 197{ 198 while (widget != NULL && (widget = XtParent(widget)) != root) { 199 ; 200 } 201 return (widget != NULL) ? True : False; 202} 203 204static void 205XtPhase2Destroy(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 ¶m, &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 321void 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 352void 353XtDestroyWidget(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