Manage.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
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 = XtMallocArray(num_children, (Cardinal) sizeof(Widget));
247    }
248    num_unique_children = 0;
249    for (i = 0; i < num_children; i++) {
250        child = children[i];
251        if (child == NULL) {
252            XtAppWarningMsg(XtWidgetToApplicationContext((Widget) parent),
253                            XtNinvalidChild, caller_func, XtCXtToolkitError,
254                            "null child passed to ManageChildren", NULL, NULL);
255            if (unique_children != cache)
256                XtFree((char *) unique_children);
257            return;
258        }
259#ifdef DEBUG
260        if (!XtIsRectObj(child)) {
261            String params[2];
262            Cardinal num_params = 2;
263
264            params[0] = XtName(child);
265            params[1] = child->core.widget_class->core_class.class_name;
266            XtAppWarningMsg(XtWidgetToApplicationContext((Widget) parent),
267                            "notRectObj", caller_func, XtCXtToolkitError,
268                            "child \"%s\", class %s is not a RectObj",
269                            params, &num_params);
270            continue;
271        }
272#endif   /*DEBUG*/
273            if (child->core.parent != parent) {
274            XtAppWarningMsg(XtWidgetToApplicationContext((Widget) parent),
275                            "ambiguousParent", caller_func, XtCXtToolkitError,
276                            "Not all children have same parent in XtManageChildren",
277                            NULL, NULL);
278        }
279        else if (!child->core.managed && !child->core.being_destroyed) {
280            unique_children[num_unique_children++] = child;
281            CALLGEOTAT(_XtGeoTrace(child,
282                                   "Child \"%s\"[%d,%d] is marked managed\n",
283                                   XtName(child),
284                                   child->core.width, child->core.height));
285            child->core.managed = TRUE;
286        }
287    }
288
289    if ((call_change_managed || num_unique_children != 0) && parent_realized) {
290        /* Compute geometry of new managed set of children. */
291        if (change_managed != NULL) {
292            CALLGEOTAT(_XtGeoTrace((Widget) parent,
293                                   "Call parent: \"%s\"[%d,%d]'s changemanaged\n",
294                                   XtName((Widget) parent),
295                                   parent->core.width, parent->core.height));
296            (*change_managed) ((Widget) parent);
297        }
298
299        /* Realize each child if necessary, then map if necessary */
300        for (i = 0; i < num_unique_children; i++) {
301            child = unique_children[i];
302            if (XtIsWidget(child)) {
303                if (!XtIsRealized(child))
304                    XtRealizeWidget(child);
305                if (child->core.mapped_when_managed)
306                    XtMapWidget(child);
307            }
308            else {              /* RectObj child */
309                Widget pw = child->core.parent;
310                RectObj r = (RectObj) child;
311
312                while ((pw != NULL) && (!XtIsWidget(pw)))
313                    pw = pw->core.parent;
314                if (pw != NULL)
315                    XClearArea(XtDisplay(pw), XtWindow(pw),
316                               r->rectangle.x, r->rectangle.y,
317                               (unsigned) (r->rectangle.width +
318                                           (r->rectangle.border_width << 1)),
319                               (unsigned) (r->rectangle.height +
320                                           (r->rectangle.border_width << 1)),
321                               TRUE);
322            }
323        }
324    }
325
326    if (unique_children != cache)
327        XtFree((char *) unique_children);
328}                               /* ManageChildren */
329
330void
331XtManageChildren(WidgetList children, Cardinal num_children)
332{
333    Widget parent, hookobj;
334
335#ifdef XTHREADS
336    XtAppContext app;
337#endif
338
339    if (num_children == 0)
340        return;
341    if (children[0] == NULL) {
342        XtWarningMsg(XtNinvalidChild, XtNxtManageChildren, XtCXtToolkitError,
343                     "null child passed to XtManageChildren", NULL, NULL);
344        return;
345    }
346#ifdef XTHREADS
347    app = XtWidgetToApplicationContext(children[0]);
348#endif
349    LOCK_APP(app);
350    parent = children[0]->core.parent;
351    if (parent->core.being_destroyed) {
352        UNLOCK_APP(app);
353        return;
354    }
355    ManageChildren(children, num_children, parent, (Boolean) False,
356                   XtNxtManageChildren);
357    hookobj = XtHooksOfDisplay(XtDisplayOfObject(children[0]));
358    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
359        XtChangeHookDataRec call_data;
360
361        call_data.type = XtHmanageChildren;
362        call_data.widget = parent;
363        call_data.event_data = (XtPointer) children;
364        call_data.num_event_data = num_children;
365        XtCallCallbackList(hookobj,
366                           ((HookObject) hookobj)->hooks.changehook_callbacks,
367                           (XtPointer) &call_data);
368    }
369    UNLOCK_APP(app);
370}                               /* XtManageChildren */
371
372void
373XtManageChild(Widget child)
374{
375    XtManageChildren(&child, (Cardinal) 1);
376}                               /* XtManageChild */
377
378void
379XtSetMappedWhenManaged(Widget widget, _XtBoolean mapped_when_managed)
380{
381    Widget hookobj;
382
383    WIDGET_TO_APPCON(widget);
384
385    LOCK_APP(app);
386    if (widget->core.mapped_when_managed == mapped_when_managed) {
387        UNLOCK_APP(app);
388        return;
389    }
390    widget->core.mapped_when_managed = (Boolean) mapped_when_managed;
391
392    hookobj = XtHooksOfDisplay(XtDisplay(widget));
393    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
394        XtChangeHookDataRec call_data;
395
396        call_data.type = XtHsetMappedWhenManaged;
397        call_data.widget = widget;
398        call_data.event_data = (XtPointer) (XtUIntPtr) mapped_when_managed;
399        XtCallCallbackList(hookobj,
400                           ((HookObject) hookobj)->hooks.changehook_callbacks,
401                           (XtPointer) &call_data);
402    }
403
404    if (!XtIsManaged(widget)) {
405        UNLOCK_APP(app);
406        return;
407    }
408
409    if (mapped_when_managed) {
410        /* Didn't used to be mapped when managed.               */
411        if (XtIsRealized(widget))
412            XtMapWidget(widget);
413    }
414    else {
415        /* Used to be mapped when managed.                      */
416        if (XtIsRealized(widget))
417            XtUnmapWidget(widget);
418    }
419    UNLOCK_APP(app);
420}                               /* XtSetMappedWhenManaged */
421
422void
423XtChangeManagedSet(WidgetList unmanage_children,
424                   Cardinal num_unmanage,
425                   XtDoChangeProc do_change_proc,
426                   XtPointer client_data,
427                   WidgetList manage_children,
428                   Cardinal num_manage)
429{
430    WidgetList childp;
431    Widget parent;
432    int i;
433    Cardinal some_unmanaged;
434    Boolean call_out;
435    XtAppContext app;
436    Widget hookobj;
437    XtChangeHookDataRec call_data;
438
439    if (num_unmanage == 0 && num_manage == 0)
440        return;
441
442    /* specification doesn't state that library will check for NULL in list */
443
444    childp = num_unmanage ? unmanage_children : manage_children;
445    app = XtWidgetToApplicationContext(*childp);
446    LOCK_APP(app);
447
448    parent = XtParent(*childp);
449    childp = unmanage_children;
450    for (i = (int) num_unmanage; --i >= 0 && XtParent(*childp) == parent;
451         childp++);
452    call_out = (i >= 0);
453    childp = manage_children;
454    for (i = (int) num_manage; --i >= 0 && XtParent(*childp) == parent;
455         childp++);
456    if (call_out || i >= 0) {
457        XtAppWarningMsg(app, "ambiguousParent", XtNxtChangeManagedSet,
458                        XtCXtToolkitError, "Not all children have same parent",
459                        NULL, NULL);
460    }
461    if (!XtIsComposite(parent)) {
462        UNLOCK_APP(app);
463        XtAppErrorMsg(app, "invalidParent", XtNxtChangeManagedSet,
464                      XtCXtToolkitError,
465                      "Attempt to manage a child when parent is not Composite",
466                      NULL, NULL);
467    }
468    if (parent->core.being_destroyed) {
469        UNLOCK_APP(app);
470        return;
471    }
472
473    call_out = False;
474    if (do_change_proc) {
475        CompositeClassExtension ext = (CompositeClassExtension)
476            XtGetClassExtension(parent->core.widget_class,
477                                XtOffsetOf(CompositeClassRec,
478                                           composite_class.extension),
479                                NULLQUARK, XtCompositeExtensionVersion,
480                                sizeof(CompositeClassExtensionRec));
481
482        if (!ext || !ext->allows_change_managed_set)
483            call_out = True;
484    }
485
486    UnmanageChildren(unmanage_children, num_unmanage, parent,
487                     &some_unmanaged, call_out, XtNxtChangeManagedSet);
488
489    hookobj = XtHooksOfDisplay(XtDisplay(parent));
490    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
491        call_data.type = XtHunmanageSet;
492        call_data.widget = parent;
493        call_data.event_data = (XtPointer) unmanage_children;
494        call_data.num_event_data = num_unmanage;
495        XtCallCallbackList(hookobj,
496                           ((HookObject) hookobj)->hooks.changehook_callbacks,
497                           (XtPointer) &call_data);
498    }
499
500    if (do_change_proc)
501        (*do_change_proc) (parent, unmanage_children, &num_unmanage,
502                           manage_children, &num_manage, client_data);
503
504    call_out = (some_unmanaged && !call_out);
505    ManageChildren(manage_children, num_manage, parent, call_out,
506                   XtNxtChangeManagedSet);
507
508    if (XtHasCallbacks(hookobj, XtNchangeHook) == XtCallbackHasSome) {
509        call_data.type = XtHmanageSet;
510        call_data.event_data = (XtPointer) manage_children;
511        call_data.num_event_data = num_manage;
512        XtCallCallbackList(hookobj,
513                           ((HookObject) hookobj)->hooks.changehook_callbacks,
514                           (XtPointer) &call_data);
515    }
516    UNLOCK_APP(app);
517}                               /* XtChangeManagedSet */
518