Search the FAQ Archives

3 - A - B - C - D - E - F - G - H - I - J - K - L - M
N - O - P - Q - R - S - T - U - V - W - X - Y - Z
faqs.org - Internet FAQ Archives

Motif FAQ (Part 4 of 9)
Section - 82) Why do composite widgets (including dialogs) that were created

( Part1 - Part2 - Part3 - Part4 - Part5 - Part6 - Part7 - Part8 - Part9 - Single Page )
[ Usenet FAQs | Web FAQs | Documents | RFC Index | Forum ]


Top Document: Motif FAQ (Part 4 of 9)
Previous Document: 81) Does XmRowColumn support multiple columns with different column
Next Document: 83) How does the ScrolledWindow manage resizing?
See reader questions & answers on this topic! - Help others by sharing your knowledge
after their parents were realized appear smaller under 1.2.3 and later?
[Last modified: Dec 97]

A. Thanks to David Brooks (dbrooks@ics.com) for pointing me to Daniel
Dardailler (daniel@x.org) who wrote this scholarly treatise:

      Application's Geometry Management Advanced Guidelines:
      =====================================================
      (or "How to properly manage children of already realized parent")

Xt Background:
-------------

    XtCreateWidget:        call Initialize ;

    XtManageChild:         if (parent realized)
                              call ChangeManaged ;
                              call Realize ;

    XtRealizeWidget:       postorder ChangeManaged loop ;
                           preorder Window-creation loop ;

Creating a widget only invokes its Initialize method (its parent's
InsertPosition method too, but that has nothing to do with GM).
Composite widgets, by opposition to Primitive, does
not usually get a correct size at initialization time, since their
correct size is based on their children sizes, which do not exist yet
at this time.

Applications usually create an entire tree of managed but
unrealized widgets and then realize their top level widget, which recursively
realize every widgets in the tree. During the creation process, the
managing of the unrealized widgets is a no-op (only mark them managed).

When XtRealizeWidget(toplevel) happens, the change_managed methods of
all the composite widgets in the tree are called in bottom-to-top
order, thus giving each of them a chance to determine their own size
based on their children *current* sizes (composite or not).
Using the current size of the children in this situation is fine,
since they should also be the children's preferred size, not
yet constrained by the parents layout (post-order traversal).

When one create a widget inside an already realized parent, this is
a different story and the order of management vs realization is important.

Consider a MessageBox created in a realized Frame.
The MessageBox itself creates a bunch of managed children
inside its Initialize method.
If you manage the MessageBox right after its creation, the Frame
ChangeManaged will be called (since it is realized), and its will use
the MessageBox current size as its base for its own size.
Unfortunately, the MessageBox ChangeManaged proc has never been called!
so its current size is whatever the default is, usually a non-settable
value (needed for tracking real initial size setting).
The MessageBox ChangeManaged has not been called because its children
were created and managed at a time where it wasn't realized.

What to do ?

The first solution would be to have all the ChangeManaged methods in
Motif call XtQueryGeometry instead of using the current size if it's
not the first time (i.e. if they're already realized).
But this is a lot of code to change and a kind of expensive run-time
process as it results in non-linear traversal order of the realized
tree (looks like an O(n!) but I'm not sure).
It's not even guaranteed that it will always work fine, since it relies on
the assumption that the geometry queried is the same that the geometry
asked for any manager (I mean, it might be the case, but if it's not,
it's just more code to fix in a very "bc-sensitive" part of Xm).

This other solution lies into the application, and is to realize a
manager first and then to manage it.
By realizing it, you are forcing its ChangeManaged proc to be
called (XtRealizeWidget does that), it will get a correct size and
this size will be used by its parent ChangeManaged when
you'll manage the manager. By explicitly realizing the branch
before managing its root, you are reproducing the ordering that
is typical of most applications at startup.

So the trick is:

    XtCreateWidget(realize_parent, MessageBox);
    XtRealizeWidget(MessageBox);  /* needed */
    XtManageChild(MessageBox);

and the model is:

    "Always explicitly realize a composite widget child of an already
     realized parent before managing it if all its children have been
     already managed"

One can always realize every widget children of realized parents, that
won't hurt, but it's useless for Primitives and Composites that
get more children added later in the program.
Why? because Primitives get their correct size at initialization
time anyway and adding a child to a Composite will generate a geometry
request and a layout that will have the same effect as if the
ChangeManaged method had been called (well, nearly the same effect,
that a complication I will address later).

If we consider Motif, this trick is only useful for MessageBox,
SelectionBox and subclasses, and Scale, since those are the only
Composites that create managed children in their Initialize method and
don't usually get additional kids from the application.

However, any application that re-creates this order of actions will
need to apply the "realize<manage" method too.
For instance:

    XtCreateWidget(realize_parent, DrawingArea);
    XtRealizeWidget(DrawingArea);   /* not needed */
    XtManageChild(DrawingArea);
    XtCreateWidget(DrawingArea, any_child) ;
    XtManageChild(any_child);
but
    XtCreateWidget(realize_parent, DrawingArea);
    XtCreateWidget(DrawingArea, any_child) ;
    XtManageChild(any_child);
    XtRealizeWidget(DrawingArea);   /* needed */
    XtManageChild(DrawingArea);

Now this is becoming interesting: there are exceptions to the model :-)

The first one is the Xt Shell widget, which has what I consider to be a
bug, but what MIT has, until recently, always considered to be a specific
behavior overridable by a subclass (like our VendorShell):
the ChangeManaged method always resizes the child to its own size
when the Shell is realized.

A side effect of this behavior is that even the realized<managed trick
won't work for direct descendant of Shell widget:

    XtCreateWidget(realize_shell, MessageBox);
    XtRealizeWidget(MessageBox);  /* needless */
    XtManageChild(MessageBox);    /* will get resized anyway */

To get rid of this problem, one needs to add a regular manager
between the Shell and the MessageBox in this case, for the sake
of having this manager doing a request to the Shell from its
ChangeManaged proc. This request will then be handled by the Shell
geometry manager, not its ChangeManaged proc, and it will take into
account the child size.
Note that we could also change our VendorShell ChangeManaged code to not
systematically envelop the Xt Shell ChangeManaged class method, and
check for the already realized case, but I would rather wait
for an Xt fix instead (I'm working on it).

If you broader the scope of the Xt Shell situation, you find that there are
also some resources in Xm that come into effect upon geometry request
reception but are not used in the ChangeManaged method.

Take the PanedWindow constraint resource XmNallowResize for instance,
which controls the validity of a geometry request made by a PW child.

If you do:

    XtCreateWidget(realize_shell, PanedWindow);
    XtManageChild(PanedWindow);

    XtCreateWidget(PanedWindow, button);
    XtManageChild(button);

that works fine since the ChangeManaged of the PanedWindow will
handle the insertion of the button and allowResize won't be used.

But if you add a manager in this hierarchy:

    XtCreateWidget(realize_parent, PanedWindow);
    XtManageChild(PanedWindow);

    XtCreateWidget(PanedWindow, manager);
    XtManageChild(manager);

    XtCreateWidget(manager, button);
    XtManageChild(button);

That doesn't work anymore since the button management results in
its parent manager's ChangeManaged being called, which in turn makes a
*request* to the PanedWindow, resulting in a No reply because
of allowResize (set to False by default).

The PanedWindow parent wouldn't have been realized that everything
would have worked fine, since no request would have been made.
It really depends on the early realization scheme.

I think XmNresizable in Form is the only other resource to present
this problem. There is not much to do in those cases except than
setting the corresponding resource to True, which makes sense.

- Daniel Dardailler (daniel@x.org)


In addition, John Michael Davison <davisonj@panix.com> sends this suggestion.
I think it's overkill for most people, but you may want to consider it if you
have problems in this area:

/* Workaround for motif 1.2.3-style geometry management */
void
smart_manage_child(Widget widget)
{
    assert(widget != 0);

#if XmVersion >= 1002 && XmUPDATE_LEVEL >= 3
    /* In Motif 1.2.3 and later:
    /*     "Always explicitly realize a composite widget child of an already
    /*     realized parent before managing it..."
    /* Note that this is unnecessary for simple UI objects (i.e. wrappers for
    /* Motif "Primitive" widgets.)
    */
    if (XtIsManaged(widget))
        return;
    if (!XtIsRealized(widget) && XtIsComposite(widget))
    {
        Widget parent_widget = XtParent(widget);
        if (parent_widget && XtIsRealized(parent_widget))
            XtRealizeWidget(widget);
    }
#endif  /* XmVersion >= 1002 && XmUPDATE_LEVEL >= 3 */
    XtManageChild(widget);
}

- John Michael Davison <davisonj@panix.com>


FYI - Asente & Swick (p. 207) says:

If the child's parent is realized, XtManageChild and XtManageChildren
automatically realize any widgets passed to them that are not currently
realized, causing the creation of their windows.  However, you should
explicitly realize a composite child of a realized widget before managing the
child to ensure that the child appears with its correct size.

- Ken Lee, http://www.rahul.net/kenton/

User Contributions:

Comment about this article, ask questions, or add new information about this topic:




Top Document: Motif FAQ (Part 4 of 9)
Previous Document: 81) Does XmRowColumn support multiple columns with different column
Next Document: 83) How does the ScrolledWindow manage resizing?

Part1 - Part2 - Part3 - Part4 - Part5 - Part6 - Part7 - Part8 - Part9 - Single Page

[ Usenet FAQs | Web FAQs | Documents | RFC Index ]

Send corrections/additions to the FAQ Maintainer:
kenton@rahul.net (Ken Lee)





Last Update March 27 2014 @ 02:11 PM