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