Manage.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
76static _Xconst _XtString XtNinvalidChild = "invalidChild";
77static _Xconst _XtString XtNxtUnmanageChildren = "xtUnmanageChildren";
78static _Xconst _XtString XtNxtManageChildren = "xtManageChildren";
79static _Xconst _XtString XtNxtChangeManagedSet = "xtChangeManagedSet";
80
81static void UnmanageChildren(
82    WidgetList children,
83    Cardinal num_children,
84    Widget parent,
85    Cardinal* num_unique_children,
86    Boolean call_change_managed,
87    _Xconst _XtString caller_func)
88{
89    Widget		child;
90    Cardinal		i;
91    XtWidgetProc	change_managed = NULL;
92    Bool		parent_realized = False;
93
94    *num_unique_children = 0;
95
96    if (XtIsComposite((Widget) parent)) {
97	LOCK_PROCESS;
98        change_managed = ((CompositeWidgetClass) parent->core.widget_class)
99		    ->composite_class.change_managed;
100	UNLOCK_PROCESS;
101	parent_realized = XtIsRealized((Widget)parent);
102    } else {
103        XtAppErrorMsg(XtWidgetToApplicationContext((Widget)parent),
104		      "invalidParent",caller_func, XtCXtToolkitError,
105		   "Attempt to unmanage a child when parent is not Composite",
106		      NULL, NULL);
107    }
108
109    for (i = 0; i < num_children; i++) {
110	child = children[i];
111	if (child == NULL) {
112	    XtAppWarningMsg(XtWidgetToApplicationContext(parent),
113		  XtNinvalidChild,caller_func,XtCXtToolkitError,
114                  "Null child passed to XtUnmanageChildren",
115		  NULL, NULL);
116	    return;
117	}
118        if (child->core.parent != parent) {
119	   XtAppWarningMsg(XtWidgetToApplicationContext(parent),
120		   "ambiguousParent",caller_func,XtCXtToolkitError,
121           "Not all children have same parent in UnmanageChildren",
122             NULL, NULL);
123	} else
124        if (child->core.managed) {
125            (*num_unique_children)++;
126	    CALLGEOTAT(_XtGeoTrace(child,"Child \"%s\" is marked unmanaged\n",
127			   XtName(child)));
128	    child->core.managed = FALSE;
129            if (XtIsWidget(child)
130		&& XtIsRealized(child)
131		&& child->core.mapped_when_managed)
132                    XtUnmapWidget(child);
133            else
134	    { /* RectObj child */
135		Widget pw = child->core.parent;
136		RectObj r = (RectObj) child;
137		while ((pw!=NULL) && (!XtIsWidget(pw))) pw = pw->core.parent;
138		if ((pw!=NULL) && XtIsRealized (pw))
139		    XClearArea (XtDisplay (pw), XtWindow (pw),
140			r->rectangle.x, r->rectangle.y,
141			(unsigned) (r->rectangle.width + (r->rectangle.border_width << 1)),
142			(unsigned) (r->rectangle.height + (r->rectangle.border_width << 1)),
143			TRUE);
144	    }
145
146        }
147    }
148    if (call_change_managed && *num_unique_children != 0 &&
149	change_managed != NULL && parent_realized) {
150	CALLGEOTAT(_XtGeoTrace((Widget)parent,
151		       "Call parent: \"%s\"[%d,%d]'s changemanaged proc\n",
152		       XtName((Widget)parent),
153		       parent->core.width,parent->core.height));
154	(*change_managed) (parent);
155    }
156} /* UnmanageChildren */
157
158void XtUnmanageChildren (
159    WidgetList children,
160    Cardinal num_children)
161{
162    Widget parent, hookobj;
163    Cardinal ii;
164#ifdef XTHREADS
165    XtAppContext app;
166#endif
167
168    if (num_children == 0) return;
169    if (children[0] == NULL) {
170	XtWarningMsg(XtNinvalidChild,XtNxtUnmanageChildren,XtCXtToolkitError,
171		     "Null child found in argument list to unmanage",
172		     NULL, NULL);
173	return;
174    }
175#ifdef XTHREADS
176    app = XtWidgetToApplicationContext(children[0]);
177#endif
178    LOCK_APP(app);
179    parent = children[0]->core.parent;
180    if (parent->core.being_destroyed) {
181	UNLOCK_APP(app);
182	return;
183    }
184    UnmanageChildren(children, num_children, parent, &ii,
185		     (Boolean)True, XtNxtUnmanageChildren);
186    hookobj = XtHooksOfDisplay(XtDisplayOfObject(children[0]));
187    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
188	XtChangeHookDataRec call_data;
189
190	call_data.type = XtHunmanageChildren;
191	call_data.widget = parent;
192	call_data.event_data = (XtPointer) children;
193	call_data.num_event_data = num_children;
194	XtCallCallbackList(hookobj,
195		((HookObject)hookobj)->hooks.changehook_callbacks,
196		(XtPointer)&call_data);
197    }
198    UNLOCK_APP(app);
199} /* XtUnmanageChildren */
200
201void XtUnmanageChild(
202    Widget child)
203{
204    XtUnmanageChildren(&child, (Cardinal)1);
205} /* XtUnmanageChild */
206
207
208static void ManageChildren(
209    WidgetList  children,
210    Cardinal    num_children,
211    Widget	parent,
212    Boolean	call_change_managed,
213    _Xconst _XtString	caller_func)
214{
215#define MAXCHILDREN 100
216    Widget		child;
217    Cardinal		num_unique_children, i;
218    XtWidgetProc	change_managed = NULL;
219    WidgetList		unique_children;
220    Widget		cache[MAXCHILDREN];
221    Bool		parent_realized = False;
222
223    if (XtIsComposite((Widget) parent)) {
224	LOCK_PROCESS;
225        change_managed = ((CompositeWidgetClass) parent->core.widget_class)
226		    ->composite_class.change_managed;
227	UNLOCK_PROCESS;
228	parent_realized = XtIsRealized((Widget)parent);
229    } else {
230	XtAppErrorMsg(XtWidgetToApplicationContext((Widget)parent),
231		"invalidParent",caller_func, XtCXtToolkitError,
232	    "Attempt to manage a child when parent is not Composite",
233	    NULL, NULL);
234    }
235
236    /* Construct new list of children that really need to be operated upon. */
237    if (num_children <= MAXCHILDREN) {
238	unique_children = cache;
239    } else {
240	unique_children = (WidgetList) __XtMalloc((Cardinal) ((size_t)num_children * sizeof(Widget)));
241    }
242    num_unique_children = 0;
243    for (i = 0; i < num_children; i++) {
244	child = children[i];
245	if (child == NULL) {
246	    XtAppWarningMsg(XtWidgetToApplicationContext((Widget)parent),
247		XtNinvalidChild,caller_func,XtCXtToolkitError,
248		"null child passed to ManageChildren",
249		NULL, NULL);
250	    if (unique_children != cache) XtFree((char *) unique_children);
251	    return;
252	}
253#ifdef DEBUG
254	if (!XtIsRectObj(child)) {
255	    String params[2];
256	    Cardinal num_params = 2;
257	    params[0] = XtName(child);
258	    params[1] = child->core.widget_class->core_class.class_name;
259	    XtAppWarningMsg(XtWidgetToApplicationContext((Widget)parent),
260			    "notRectObj",caller_func,XtCXtToolkitError,
261			    "child \"%s\", class %s is not a RectObj",
262			    params, &num_params);
263	    continue;
264	}
265#endif /*DEBUG*/
266        if (child->core.parent != parent) {
267	    XtAppWarningMsg(XtWidgetToApplicationContext((Widget)parent),
268		    "ambiguousParent",caller_func,XtCXtToolkitError,
269		"Not all children have same parent in XtManageChildren",
270		NULL, NULL);
271	} else if (! child->core.managed && !child->core.being_destroyed) {
272	    unique_children[num_unique_children++] = child;
273	    CALLGEOTAT(_XtGeoTrace(child,
274			   "Child \"%s\"[%d,%d] is marked managed\n",
275			   XtName(child),
276			   child->core.width,child->core.height));
277	    child->core.managed = TRUE;
278	}
279    }
280
281    if ((call_change_managed || num_unique_children != 0) && parent_realized) {
282	/* Compute geometry of new managed set of children. */
283	if (change_managed != NULL) {
284	    CALLGEOTAT(_XtGeoTrace((Widget)parent,
285			   "Call parent: \"%s\"[%d,%d]'s changemanaged\n",
286			   XtName((Widget)parent),
287			   parent->core.width,parent->core.height));
288	    (*change_managed) ((Widget)parent);
289	}
290
291	/* Realize each child if necessary, then map if necessary */
292	for (i = 0; i < num_unique_children; i++) {
293	    child = unique_children[i];
294	    if (XtIsWidget(child)) {
295		if (! XtIsRealized(child)) XtRealizeWidget(child);
296		if (child->core.mapped_when_managed) XtMapWidget(child);
297	    } else { /* RectObj child */
298		Widget pw = child->core.parent;
299		RectObj r = (RectObj) child;
300		while ((pw!=NULL) && (!XtIsWidget(pw)))
301		    pw = pw->core.parent;
302		if (pw != NULL)
303		    XClearArea (XtDisplay (pw), XtWindow (pw),
304		    r->rectangle.x, r->rectangle.y,
305		    (unsigned) (r->rectangle.width + (r->rectangle.border_width << 1)),
306		    (unsigned) (r->rectangle.height + (r->rectangle.border_width << 1)),
307		    TRUE);
308            }
309        }
310    }
311
312    if (unique_children != cache) XtFree((char *) unique_children);
313} /* ManageChildren */
314
315void XtManageChildren(
316    WidgetList children,
317    Cardinal num_children)
318{
319    Widget parent, hookobj;
320#ifdef XTHREADS
321    XtAppContext app;
322#endif
323
324    if (num_children == 0) return;
325    if (children[0] == NULL) {
326	XtWarningMsg(XtNinvalidChild, XtNxtManageChildren, XtCXtToolkitError,
327		     "null child passed to XtManageChildren",
328		     NULL, NULL);
329	return;
330    }
331#ifdef XTHREADS
332    app = XtWidgetToApplicationContext(children[0]);
333#endif
334    LOCK_APP(app);
335    parent = children[0]->core.parent;
336    if (parent->core.being_destroyed) {
337	UNLOCK_APP(app);
338	return;
339    }
340    ManageChildren(children, num_children, parent, (Boolean)False,
341		   XtNxtManageChildren);
342    hookobj = XtHooksOfDisplay(XtDisplayOfObject(children[0]));
343    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
344	XtChangeHookDataRec call_data;
345
346	call_data.type = XtHmanageChildren;
347	call_data.widget = parent;
348	call_data.event_data = (XtPointer) children;
349	call_data.num_event_data = num_children;
350	XtCallCallbackList(hookobj,
351		((HookObject)hookobj)->hooks.changehook_callbacks,
352		(XtPointer)&call_data);
353    }
354    UNLOCK_APP(app);
355} /* XtManageChildren */
356
357void XtManageChild(
358    Widget child)
359{
360    XtManageChildren(&child, (Cardinal) 1);
361} /* XtManageChild */
362
363
364void XtSetMappedWhenManaged(
365    Widget widget,
366    _XtBoolean mapped_when_managed)
367{
368    Widget hookobj;
369    WIDGET_TO_APPCON(widget);
370
371    LOCK_APP(app);
372    if (widget->core.mapped_when_managed == mapped_when_managed) {
373	UNLOCK_APP(app);
374	return;
375    }
376    widget->core.mapped_when_managed = (Boolean) mapped_when_managed;
377
378    hookobj = XtHooksOfDisplay(XtDisplay(widget));
379    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
380	XtChangeHookDataRec call_data;
381
382	call_data.type = XtHsetMappedWhenManaged;
383	call_data.widget = widget;
384	call_data.event_data = (XtPointer) (unsigned long) mapped_when_managed;
385	XtCallCallbackList(hookobj,
386		((HookObject)hookobj)->hooks.changehook_callbacks,
387		(XtPointer)&call_data);
388    }
389
390    if (! XtIsManaged(widget)) {
391	UNLOCK_APP(app);
392	return;
393    }
394
395    if (mapped_when_managed) {
396	/* Didn't used to be mapped when managed.		*/
397	if (XtIsRealized(widget)) XtMapWidget(widget);
398    } else {
399	/* Used to be mapped when managed.			*/
400	if (XtIsRealized(widget)) XtUnmapWidget(widget);
401    }
402    UNLOCK_APP(app);
403} /* XtSetMappedWhenManaged */
404
405
406void XtChangeManagedSet(
407    WidgetList unmanage_children,
408    Cardinal num_unmanage,
409    XtDoChangeProc do_change_proc,
410    XtPointer client_data,
411    WidgetList manage_children,
412    Cardinal num_manage)
413{
414    WidgetList childp;
415    Widget parent;
416    int i;
417    Cardinal some_unmanaged;
418    Boolean call_out;
419    XtAppContext app;
420    Widget hookobj;
421    XtChangeHookDataRec call_data;
422
423    if (num_unmanage == 0 && num_manage == 0)
424	return;
425
426    /* specification doesn't state that library will check for NULL in list */
427
428    childp = num_unmanage ? unmanage_children : manage_children;
429    app = XtWidgetToApplicationContext(*childp);
430    LOCK_APP(app);
431
432    parent = XtParent(*childp);
433    childp = unmanage_children;
434    for (i = (int) num_unmanage; --i >= 0 && XtParent(*childp) == parent; childp++);
435    call_out = (i >= 0);
436    childp = manage_children;
437    for (i = (int) num_manage;   --i >= 0 && XtParent(*childp) == parent; childp++);
438    if (call_out || i >= 0) {
439	XtAppWarningMsg(app, "ambiguousParent", XtNxtChangeManagedSet,
440			XtCXtToolkitError, "Not all children have same parent",
441			NULL, NULL);
442    }
443    if (! XtIsComposite(parent)) {
444	UNLOCK_APP(app);
445	XtAppErrorMsg(app, "invalidParent", XtNxtChangeManagedSet,
446		      XtCXtToolkitError,
447		      "Attempt to manage a child when parent is not Composite",
448		      NULL, NULL);
449    }
450    if (parent->core.being_destroyed) {
451	UNLOCK_APP(app);
452	return;
453    }
454
455    call_out = False;
456    if (do_change_proc) {
457	CompositeClassExtension ext = (CompositeClassExtension)
458	    XtGetClassExtension(parent->core.widget_class,
459				XtOffsetOf(CompositeClassRec,
460					   composite_class.extension),
461				NULLQUARK, XtCompositeExtensionVersion,
462				sizeof(CompositeClassExtensionRec));
463	if (!ext || !ext->allows_change_managed_set)
464	    call_out = True;
465    }
466
467    UnmanageChildren(unmanage_children, num_unmanage, parent,
468		     &some_unmanaged, call_out, XtNxtChangeManagedSet);
469
470    hookobj = XtHooksOfDisplay(XtDisplay(parent));
471    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
472	call_data.type = XtHunmanageSet;
473	call_data.widget = parent;
474	call_data.event_data = (XtPointer) unmanage_children;
475	call_data.num_event_data = num_unmanage;
476	XtCallCallbackList(hookobj,
477		((HookObject)hookobj)->hooks.changehook_callbacks,
478		(XtPointer) &call_data);
479    }
480
481    if (do_change_proc)
482	(*do_change_proc)(parent, unmanage_children, &num_unmanage,
483			  manage_children, &num_manage, client_data);
484
485    call_out = (some_unmanaged && !call_out);
486    ManageChildren(manage_children, num_manage, parent, call_out,
487		   XtNxtChangeManagedSet);
488
489    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
490	call_data.type = XtHmanageSet;
491	call_data.event_data = (XtPointer) manage_children;
492	call_data.num_event_data = num_manage;
493	XtCallCallbackList(hookobj,
494		((HookObject)hookobj)->hooks.changehook_callbacks,
495		(XtPointer) &call_data);
496    }
497    UNLOCK_APP(app);
498} /* XtChangeManagedSet */
499