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: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
|
Comment about this article, ask questions, or add new information about this topic: