Manage.c revision 444c061a
1/* $Xorg: Manage.c,v 1.4 2001/02/09 02:03:55 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/* $XFree86: xc/lib/Xt/Manage.c,v 3.10tsi Exp $ */
36
37/*
38
39Copyright 1987, 1988, 1994, 1998  The Open Group
40
41Permission to use, copy, modify, distribute, and sell this software and its
42documentation for any purpose is hereby granted without fee, provided that
43the above copyright notice appear in all copies and that both that
44copyright notice and this permission notice appear in supporting
45documentation.
46
47The above copyright notice and this permission notice shall be included in
48all copies or substantial portions of the Software.
49
50THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
51IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
52FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
53OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
54AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
55CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
56
57Except as contained in this notice, the name of The Open Group shall not be
58used in advertising or otherwise to promote the sale, use or other dealings
59in this Software without prior written authorization from The Open Group.
60
61*/
62
63#ifdef HAVE_CONFIG_H
64#include <config.h>
65#endif
66#include "IntrinsicI.h"
67
68static String XtNinvalidChild = "invalidChild";
69static String XtNxtUnmanageChildren = "xtUnmanageChildren";
70static String XtNxtManageChildren = "xtManageChildren";
71static String XtNxtChangeManagedSet = "xtChangeManagedSet";
72
73static void UnmanageChildren(
74    WidgetList children,
75    Cardinal num_children,
76    Widget parent,
77    Cardinal* num_unique_children,
78    Boolean call_change_managed,
79    String caller_func)
80{
81    Widget		child;
82    Cardinal		i;
83    XtWidgetProc	change_managed = NULL;
84    Bool		parent_realized = False;
85
86    *num_unique_children = 0;
87
88    if (XtIsComposite((Widget) parent)) {
89	LOCK_PROCESS;
90        change_managed = ((CompositeWidgetClass) parent->core.widget_class)
91		    ->composite_class.change_managed;
92	UNLOCK_PROCESS;
93	parent_realized = XtIsRealized((Widget)parent);
94    } else {
95        XtAppErrorMsg(XtWidgetToApplicationContext((Widget)parent),
96		      "invalidParent",caller_func, XtCXtToolkitError,
97		   "Attempt to unmanage a child when parent is not Composite",
98		      (String *) NULL, (Cardinal *) NULL);
99    }
100
101    for (i = 0; i < num_children; i++) {
102	child = children[i];
103	if (child == NULL) {
104	    XtAppWarningMsg(XtWidgetToApplicationContext(parent),
105		  XtNinvalidChild,caller_func,XtCXtToolkitError,
106                  "Null child passed to XtUnmanageChildren",
107		  (String *)NULL, (Cardinal *)NULL);
108	    return;
109	}
110        if (child->core.parent != parent) {
111	   XtAppWarningMsg(XtWidgetToApplicationContext(parent),
112		   "ambiguousParent",caller_func,XtCXtToolkitError,
113           "Not all children have same parent in UnmanageChildren",
114             (String *)NULL, (Cardinal *)NULL);
115	} else
116        if (child->core.managed) {
117            (*num_unique_children)++;
118	    CALLGEOTAT(_XtGeoTrace(child,"Child \"%s\" is marked unmanaged\n",
119			   XtName(child)));
120	    child->core.managed = FALSE;
121            if (XtIsWidget(child)
122		&& XtIsRealized(child)
123		&& child->core.mapped_when_managed)
124                    XtUnmapWidget(child);
125            else
126	    { /* RectObj child */
127		Widget pw = child->core.parent;
128		RectObj r = (RectObj) child;
129		while ((pw!=NULL) && (!XtIsWidget(pw))) pw = pw->core.parent;
130		if ((pw!=NULL) && XtIsRealized (pw))
131		    XClearArea (XtDisplay (pw), XtWindow (pw),
132			r->rectangle.x, r->rectangle.y,
133			r->rectangle.width + (r->rectangle.border_width << 1),
134			r->rectangle.height + (r->rectangle.border_width << 1),
135			TRUE);
136	    }
137
138        }
139    }
140    if (call_change_managed && *num_unique_children != 0 &&
141	change_managed != NULL && parent_realized) {
142	CALLGEOTAT(_XtGeoTrace((Widget)parent,
143		       "Call parent: \"%s\"[%d,%d]'s changemanaged proc\n",
144		       XtName((Widget)parent),
145		       parent->core.width,parent->core.height));
146	(*change_managed) (parent);
147    }
148} /* UnmanageChildren */
149
150void XtUnmanageChildren (
151    WidgetList children,
152    Cardinal num_children)
153{
154    Widget parent, hookobj;
155    Cardinal ii;
156#ifdef XTHREADS
157    XtAppContext app;
158#endif
159
160    if (num_children == 0) return;
161    if (children[0] == NULL) {
162	XtWarningMsg(XtNinvalidChild,XtNxtUnmanageChildren,XtCXtToolkitError,
163		     "Null child found in argument list to unmanage",
164		     (String *)NULL, (Cardinal *)NULL);
165	return;
166    }
167#ifdef XTHREADS
168    app = XtWidgetToApplicationContext(children[0]);
169#endif
170    LOCK_APP(app);
171    parent = children[0]->core.parent;
172    if (parent->core.being_destroyed) {
173	UNLOCK_APP(app);
174	return;
175    }
176    UnmanageChildren(children, num_children, parent, &ii,
177		     (Boolean)True, XtNxtUnmanageChildren);
178    hookobj = XtHooksOfDisplay(XtDisplayOfObject(children[0]));
179    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
180	XtChangeHookDataRec call_data;
181
182	call_data.type = XtHunmanageChildren;
183	call_data.widget = parent;
184	call_data.event_data = (XtPointer) children;
185	call_data.num_event_data = num_children;
186	XtCallCallbackList(hookobj,
187		((HookObject)hookobj)->hooks.changehook_callbacks,
188		(XtPointer)&call_data);
189    }
190    UNLOCK_APP(app);
191} /* XtUnmanageChildren */
192
193void XtUnmanageChild(
194    Widget child)
195{
196    XtUnmanageChildren(&child, (Cardinal)1);
197} /* XtUnmanageChild */
198
199
200static void ManageChildren(
201    WidgetList  children,
202    Cardinal    num_children,
203    Widget	parent,
204    Boolean	call_change_managed,
205    String	caller_func)
206{
207#define MAXCHILDREN 100
208    Widget		child;
209    Cardinal		num_unique_children, i;
210    XtWidgetProc	change_managed = NULL;
211    WidgetList		unique_children;
212    Widget		cache[MAXCHILDREN];
213    Bool		parent_realized = False;
214
215    if (XtIsComposite((Widget) parent)) {
216	LOCK_PROCESS;
217        change_managed = ((CompositeWidgetClass) parent->core.widget_class)
218		    ->composite_class.change_managed;
219	UNLOCK_PROCESS;
220	parent_realized = XtIsRealized((Widget)parent);
221    } else {
222	XtAppErrorMsg(XtWidgetToApplicationContext((Widget)parent),
223		"invalidParent",caller_func, XtCXtToolkitError,
224	    "Attempt to manage a child when parent is not Composite",
225	    (String *) NULL, (Cardinal *) NULL);
226    }
227
228    /* Construct new list of children that really need to be operated upon. */
229    if (num_children <= MAXCHILDREN) {
230	unique_children = cache;
231    } else {
232	unique_children = (WidgetList) __XtMalloc(num_children * sizeof(Widget));
233    }
234    num_unique_children = 0;
235    for (i = 0; i < num_children; i++) {
236	child = children[i];
237	if (child == NULL) {
238	    XtAppWarningMsg(XtWidgetToApplicationContext((Widget)parent),
239		XtNinvalidChild,caller_func,XtCXtToolkitError,
240		"null child passed to ManageChildren",
241		(String *)NULL, (Cardinal *)NULL);
242	    if (unique_children != cache) XtFree((char *) unique_children);
243	    return;
244	}
245#ifdef DEBUG
246	if (!XtIsRectObj(child)) {
247	    String params[2];
248	    Cardinal num_params = 2;
249	    params[0] = XtName(child);
250	    params[1] = child->core.widget_class->core_class.class_name;
251	    XtAppWarningMsg(XtWidgetToApplicationContext((Widget)parent),
252			    "notRectObj",caller_func,XtCXtToolkitError,
253			    "child \"%s\", class %s is not a RectObj",
254			    params, &num_params);
255	    continue;
256	}
257#endif /*DEBUG*/
258        if (child->core.parent != parent) {
259	    XtAppWarningMsg(XtWidgetToApplicationContext((Widget)parent),
260		    "ambiguousParent",caller_func,XtCXtToolkitError,
261		"Not all children have same parent in XtManageChildren",
262		(String *)NULL, (Cardinal *)NULL);
263	} else if (! child->core.managed && !child->core.being_destroyed) {
264	    unique_children[num_unique_children++] = child;
265	    CALLGEOTAT(_XtGeoTrace(child,
266			   "Child \"%s\"[%d,%d] is marked managed\n",
267			   XtName(child),
268			   child->core.width,child->core.height));
269	    child->core.managed = TRUE;
270	}
271    }
272
273    if ((call_change_managed || num_unique_children != 0) && parent_realized) {
274	/* Compute geometry of new managed set of children. */
275	if (change_managed != NULL) {
276	    CALLGEOTAT(_XtGeoTrace((Widget)parent,
277			   "Call parent: \"%s\"[%d,%d]'s changemanaged\n",
278			   XtName((Widget)parent),
279			   parent->core.width,parent->core.height));
280	    (*change_managed) ((Widget)parent);
281	}
282
283	/* Realize each child if necessary, then map if necessary */
284	for (i = 0; i < num_unique_children; i++) {
285	    child = unique_children[i];
286	    if (XtIsWidget(child)) {
287		if (! XtIsRealized(child)) XtRealizeWidget(child);
288		if (child->core.mapped_when_managed) XtMapWidget(child);
289	    } else { /* RectObj child */
290		Widget pw = child->core.parent;
291		RectObj r = (RectObj) child;
292		while ((pw!=NULL) && (!XtIsWidget(pw)))
293		    pw = pw->core.parent;
294		if (pw != NULL)
295		    XClearArea (XtDisplay (pw), XtWindow (pw),
296		    r->rectangle.x, r->rectangle.y,
297		    r->rectangle.width + (r->rectangle.border_width << 1),
298		    r->rectangle.height + (r->rectangle.border_width << 1),
299		    TRUE);
300            }
301        }
302    }
303
304    if (unique_children != cache) XtFree((char *) unique_children);
305} /* ManageChildren */
306
307void XtManageChildren(
308    WidgetList children,
309    Cardinal num_children)
310{
311    Widget parent, hookobj;
312#ifdef XTHREADS
313    XtAppContext app;
314#endif
315
316    if (num_children == 0) return;
317    if (children[0] == NULL) {
318	XtWarningMsg(XtNinvalidChild, XtNxtManageChildren, XtCXtToolkitError,
319		     "null child passed to XtManageChildren",
320		     (String*)NULL, (Cardinal*)NULL);
321	return;
322    }
323#ifdef XTHREADS
324    app = XtWidgetToApplicationContext(children[0]);
325#endif
326    LOCK_APP(app);
327    parent = children[0]->core.parent;
328    if (parent->core.being_destroyed) {
329	UNLOCK_APP(app);
330	return;
331    }
332    ManageChildren(children, num_children, parent, (Boolean)False,
333		   XtNxtManageChildren);
334    hookobj = XtHooksOfDisplay(XtDisplayOfObject(children[0]));
335    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
336	XtChangeHookDataRec call_data;
337
338	call_data.type = XtHmanageChildren;
339	call_data.widget = parent;
340	call_data.event_data = (XtPointer) children;
341	call_data.num_event_data = num_children;
342	XtCallCallbackList(hookobj,
343		((HookObject)hookobj)->hooks.changehook_callbacks,
344		(XtPointer)&call_data);
345    }
346    UNLOCK_APP(app);
347} /* XtManageChildren */
348
349void XtManageChild(
350    Widget child)
351{
352    XtManageChildren(&child, (Cardinal) 1);
353} /* XtManageChild */
354
355
356void XtSetMappedWhenManaged(
357    Widget widget,
358    _XtBoolean mapped_when_managed)
359{
360    Widget hookobj;
361    WIDGET_TO_APPCON(widget);
362
363    LOCK_APP(app);
364    if (widget->core.mapped_when_managed == mapped_when_managed) {
365	UNLOCK_APP(app);
366	return;
367    }
368    widget->core.mapped_when_managed = mapped_when_managed;
369
370    hookobj = XtHooksOfDisplay(XtDisplay(widget));
371    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
372	XtChangeHookDataRec call_data;
373
374	call_data.type = XtHsetMappedWhenManaged;
375	call_data.widget = widget;
376	call_data.event_data = (XtPointer) (unsigned long) mapped_when_managed;
377	XtCallCallbackList(hookobj,
378		((HookObject)hookobj)->hooks.changehook_callbacks,
379		(XtPointer)&call_data);
380    }
381
382    if (! XtIsManaged(widget)) {
383	UNLOCK_APP(app);
384	return;
385    }
386
387    if (mapped_when_managed) {
388	/* Didn't used to be mapped when managed.		*/
389	if (XtIsRealized(widget)) XtMapWidget(widget);
390    } else {
391	/* Used to be mapped when managed.			*/
392	if (XtIsRealized(widget)) XtUnmapWidget(widget);
393    }
394    UNLOCK_APP(app);
395} /* XtSetMappedWhenManaged */
396
397
398void XtChangeManagedSet(
399    WidgetList unmanage_children,
400    Cardinal num_unmanage,
401    XtDoChangeProc do_change_proc,
402    XtPointer client_data,
403    WidgetList manage_children,
404    Cardinal num_manage)
405{
406    WidgetList childp;
407    Widget parent;
408    int i;
409    Cardinal some_unmanaged;
410    Boolean call_out;
411    CompositeClassExtension ext;
412    XtAppContext app;
413    Widget hookobj;
414    XtChangeHookDataRec call_data;
415
416    if (num_unmanage == 0 && num_manage == 0)
417	return;
418
419    /* specification doesn't state that library will check for NULL in list */
420
421    childp = num_unmanage ? unmanage_children : manage_children;
422    app = XtWidgetToApplicationContext(*childp);
423    LOCK_APP(app);
424
425    parent = XtParent(*childp);
426    childp = unmanage_children;
427    for (i = num_unmanage; --i >= 0 && XtParent(*childp) == parent; childp++);
428    call_out = (i >= 0);
429    childp = manage_children;
430    for (i = num_manage;   --i >= 0 && XtParent(*childp) == parent; childp++);
431    if (call_out || i >= 0) {
432	XtAppWarningMsg(app, "ambiguousParent", XtNxtChangeManagedSet,
433			XtCXtToolkitError, "Not all children have same parent",
434			(String *)NULL, (Cardinal *)NULL);
435    }
436    if (! XtIsComposite(parent)) {
437	UNLOCK_APP(app);
438	XtAppErrorMsg(app, "invalidParent", XtNxtChangeManagedSet,
439		      XtCXtToolkitError,
440		      "Attempt to manage a child when parent is not Composite",
441		      (String *) NULL, (Cardinal *) NULL);
442    }
443    if (parent->core.being_destroyed) {
444	UNLOCK_APP(app);
445	return;
446    }
447
448    call_out = False;
449    if (do_change_proc) {
450	ext = (CompositeClassExtension)
451	    XtGetClassExtension(parent->core.widget_class,
452				XtOffsetOf(CompositeClassRec,
453					   composite_class.extension),
454				NULLQUARK, XtCompositeExtensionVersion,
455				sizeof(CompositeClassExtensionRec));
456	if (!ext || !ext->allows_change_managed_set)
457	    call_out = True;
458    }
459
460    UnmanageChildren(unmanage_children, num_unmanage, parent,
461		     &some_unmanaged, call_out, XtNxtChangeManagedSet);
462
463    hookobj = XtHooksOfDisplay(XtDisplay(parent));
464    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
465	call_data.type = XtHunmanageSet;
466	call_data.widget = parent;
467	call_data.event_data = (XtPointer) unmanage_children;
468	call_data.num_event_data = num_unmanage;
469	XtCallCallbackList(hookobj,
470		((HookObject)hookobj)->hooks.changehook_callbacks,
471		(XtPointer) &call_data);
472    }
473
474    if (do_change_proc)
475	(*do_change_proc)(parent, unmanage_children, &num_unmanage,
476			  manage_children, &num_manage, client_data);
477
478    call_out = (some_unmanaged && !call_out);
479    ManageChildren(manage_children, num_manage, parent, call_out,
480		   XtNxtChangeManagedSet);
481
482    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
483	call_data.type = XtHmanageSet;
484	call_data.event_data = (XtPointer) manage_children;
485	call_data.num_event_data = num_manage;
486	XtCallCallbackList(hookobj,
487		((HookObject)hookobj)->hooks.changehook_callbacks,
488		(XtPointer) &call_data);
489    }
490    UNLOCK_APP(app);
491} /* XtChangeManagedSet */
492