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