Author: M. A. Sridhar
Last updated: June 17th, 1997
This document describes YACL's known quirks, bugs, limitations and the like under the window systems that it supports. In some cases, YACL includes necessary workarounds, and these are also documented here.
Executable size. Currently YACL's makefiles do not include support for building it as a shared library (or DLL). (The one exception is the Sun Solaris 2.5 platform using GNU C++; in this one case the makefiles include support for building shared libraries.) Consequently much of YACL is linked into the executable. So for the typical GUI demo, the executable size is around 500K (under Windows or OS/2). This figure varies quite a bit: Under Borland C++ 4.0, it's about 700K, while under Watcom C++ with OS/2 and Windows NT, it's about 275K. In any case, it will reduce drastically when YACL is built as a shared library. (I hope to add support for shared libraries under Windows and OS/2, real soon now. :-)
CompositeVObjects with menu bars. If a CompositeVObject has a MenuBar, then it increases its height (over and above the programmer-requested height) by the MenuBar's height. This way, the actual visible area of the CompositeVObject equals the height requested by the programmer. In order to implement this correctly, the CompositeVObject's CreateVisualElement method (which is, of course, called before those of any of its children) calls each child's AdjustPosition method. The latter adjusts the child's vertical position by an amount that is platform-specific and hard-wired into the code. Note, however, that the Composite calls AdjustPosition only for those children that have non-negative view id's. This is another reason to ensure that all simple visual objects have non-negative view id's.
Note also that this mechanism of position adjustment will only work if you create the MenuBar before the Composite's visual element is created. If you do things like creating menu bars on the fly, this adjustment will not work. (Well, it does under Windows and Unix, for different reasons; it doesn't under OS/2.)
Button groups. Positioning buttons within a button group is very hard to do in a platform-independent manner. Under Motif, the group looks best (with fairly small fonts) if the top button in the group is 15 pixels below the parent's top border. But this setting is unsatisfactory under Windows with the default font, because it obscures the button group's label. And it is barely satisfactory under OS/2. You can't win 'em all. :-(
Default push buttons. If you run a dialog modally, and designate one of its push buttons as the default push button, then the modal execution terminates if the user hits the enter key, with the dialog pretending that the default push button was pressed. There is one exception: the dialog does not terminate if it is itself the main window. This is because "termination" of the main window is not detected by the dialog but by the controller.
Shared libraries/DLLs. I have had minimal success with building YACL as DLLs. Here's the (short) list of successes:
And here's the list of failures (I would greatly appreciate any help in fixing these problems):
I couldn't get the Watcom compiler to link to the generated DLLs.
CompositeVObject's title bar and border. Currently, the CompositeVObject's title bar manipulation methods ShowTitleBar and HideTitleBar, and the border manipulation methods ShowBorder and HideBorder, only work if called before the CompositeVObject is displayed. Effectively, that means they work if either you call them immediately after the Composite is created, or you derive a class from CompositeVObject and call them in your derived class constructor. Otherwise they don't work. And, of course, they don't work at all if your window manager does not respect MWM hints. I know they work under MWM and FVWM, but I don't know about other window managers. Note that for non-sticky composites, HideBorder/ShowBorder applies to the sizing border.
CompositeVObject's Initialize method. YACL stipulates that a VisualObject's Initialize method is called immediately after it first becomes visible. (The reason for this is that the derived classes might want to draw on the VisualObject in the Initialize method.) This causes problems under X, because there does not seem to be a reliable way to tell when a widget becomes visible, other than waiting for the first Expose event. MapNotify doesn't meet this need; for example, if we try to use image operations in the Initialize method (such as the animate demo does), the app crashes with a BadMatch error (particularly if the app is run on a remote machine) unless Initialize is done on the first Expose event. So YACL's Controller code waits until the first Expose event for a CompositeVObject before calling its Initialize method. Bear in mind, though, that this means that the CompositeVObject should not be initially invisible; if it is, it won't be initialized until it becomes visible.
Tabbing. Under Motif, tab stops are managed by the Motif library. This is unlike the OS/2 and Windows implementations, where tab stops are managed by YACL's code (specifically the methods in CompositeVObject). This means that the tabbing behavior is different under Motif from what it is under Windows and OS/2. For example, the left and right arrow keys work under Motif, but they are currently unused (by YACL) under Windows and OS/2.
StringViews. StringView is implemented not just as a ScrolledList, but as a ScrolledList which is a child of a Frame. This is because of the following: If you create a ScrolledList as a child of a BulletinBoard, make it invisible, and create other widgets in the same area, the other widgets remain invisible until the ScrolledList is made visible once and then made invisible. Weird. With the workaround, the ScrolledList is a child of a Frame, which in turn is child of the BulletinBoard (CompositeVObject), so when MakeInvisible is called on the StringView, I make the frame invisible by unmanaging it.
Resources. You can use a resource file for setting individual resources of widgets. The widget names are internally generated; if you want to assign your own names, look into the InstanceName methods on Application and VisualObject. For example, you can set foreground and background colors via command line using the -fg and -bg switches. Remember also that under Motif, setting the font resource via the command line needs a special syntax. For example, if you want say 9x15 to be the default font, you must invoke the app with a command such as
myapp -xrm "*fontList: 9x15" for the font name to take effect.
Standard dialogs. The parent of a StandardDialog *must* be a non-null, currently-displayed window. Otherwise you might not get the StandardDialog displayed properly. This is because the XmCreate...Dialog API calls require a non-null widget as parent.
Titles for standard dialogs (message boxes). Make sure you have the "decorateTransients" (or equivalent) property set by your window manager. Otherwise you will not see the titles on any of the standard dialogs.
Fonts for menus. Currently, you cannot change the font of the items of a menu bar or popup menu under program control (i.e., using the Font() method.) You can, however, set these fonts using the X resource mechanism.
Checkable menu items. (Added May 19, 1996.) Ideally, we would want to have any menu item checkable. In other words, the application should be able to set or remove the check mark on a menu item at any time. This is in fact the case under Windows and OS/2. But under Motif, the kind of visual element created for a MenuItem depends on whether or not the item is checkable. (Checkable items need ToggleButton widgets, while non-checkable ones need PushButton widgets.) Therefore, YACL imposes the restriction (at least for those YACL programs that must run under Motif) that if you want a MenuItem to be checkable, you must set its state to either Checked or NotChecked before the item's visual element is created. In other words, after a menu's visual elements have been created, you cannot change a checkable MenuItem to a non-checkable one or vice versa. (By default, the MenuItem's state is NotCheckable.) This is not a serious restriction; as soon as you create your Menu (via new), you simply need to invoke SetCheck on those menu items that you want to be checkable. See the demo in uidemo/menu1 or the dialog editor application in apps/dlged for examples illustrating this.
Popup menus and right mouse buttons. If you create a CompositeVObject that has both a PopupMenu and a PushButton child, then right mouse clicks on the PushButton go to the CompositeVObject, not to the PushButton. Seems like a Motif "feature" because I tracked the origin of the event -- X seems to give me the widget id of the Composite rather than the PushButton. The problem does not arise if the Composite does not have a PopupMenu. (Thanks to Holger Pfaff (holger.pfaff@class.de) for pointing this out.)
String editors. Motif refuses to change the cursor position from within a callback. I have worked around this irritating problem. For the StringEditor's FilterChar method, the workaround is to assign explicitly to the fields of the XmTextVerifyCallbackStruct (see ui/stred.cxx). For the Update method, the workaround uses a special event (Event_StrEdChanged) enqueued by the callback function. This event is processed by the Controller, in the method UI_Controller::ProcessSoftEvents.
Arguments to Main. If the user types X-windows-specific parameters as part of the command line (e.g., -bg yellow -fg blue), they don't show up in the arguments to UI_Application :: Main. This is because they are already eaten up by the X resource mechanism before Main is called.
Dialog movement events. For some reason, I don't get the ConfigureNotify event from X when the user repositions a Dialog. The event comes through just fine for the main window; I also get the event when the user resizes a Dialog. There is, however, the difficulty that X does not provide a good way to distinguish between moving and resizing. You'll see a consequence of this problem in the window demo (in the directory uidemo/window). In this demo, if you resize the window by dragging its top left corner, the new position always shows up as (0, 0). I'm still trying to figure out how to solve these problems. As usual, all suggestions are welcome.
ScrollableWindow problems. The ScrollableWindow class doesn't yet work satisfactorily under Motif. If you resize the main window, the scroll bars should be repositioned, but Motif doesn't seem to get this right. It seems as if the only way out the geometry management problems under X is to write a Composite widget that allows arbitrary positioning without dictating geometry. One of these days, I'll probably do just that.
Termination of modal dialogs. (Added Feb 18th, 1996.) The application code should ensure that the event handler called in response to a modal dialog's completion doesn't take very long to execute. This is because of the following: if the user presses a button that terminates the dialog, the button will appear to remain pressed as long as the event handler is running. See the comment in the SelectionCallback code in ui/pushbtn.cxx for the reason why this is so.
RLE-encoded MS Windows bitmaps. (Added Feb 18th, 1996.) The YACL code does not support run-length-encoded Windows bitmaps; if the application attempts to read such a bitmap, the code (in ui/bitmap.cxx) issues an error message.
VisualObject's Foreground and Background methods. (Added March 2, 1996.) The VisualObject methods for setting and getting its foreground and background colors don't work correctly under X. I'm not yet certain that this is really an issue, because the user can always set widget colors explicitly via the resource mechanism. This is why I haven't paid attention to this question.
ComboBox under Motif 2.0. (Added October 11, 1996.) I have not ported YACL to use Motif 2.0's combo box instead of the freeware widget that YACL relies on. But if you use this freeware widget with Motif 2.0, Motif gives a warning about the StringDirection resource. Hopefully someone knowledgeable about the freeware ComboBox will fix this.
Message boxes and de-iconfication. If you try to put up a StandardDialog (i.e., MessageBox) in the handler of a Deiconify event, the MessageBox will show up, and then your app will hang. Looks like an OS/2 bug. In general, it's a bad idea to use standard dialogs in code that responds to any event that might cause screen repainting.
Message box parent. Make sure you specify a parent for the StandardDialog under OS/2. If you don't, the dialog becomes non-modal, and this can result in some very unexpected effects!
General: view id's. OS/2 is very picky about view id's. Make sure that all children of a Composite or Dialog have distinct view id's and that all of them are in the range 1 to 32700. (Remember that this includes any menu items of menus used by the Composite, because menu items are treated as children of the Composite in the view tree.) View id's above 32700 seem to be used by OS/2 internals (e.g., FID_MENU). OS/2 Warp lets you have long values (4 bytes) for view id's, but OS/2 2.1 can only handle a short (2 bytes) as a view id.
OS/2 2.1 specific stuff. Under OS/2 2.1, if you start up a YACL PM application from an OS/2 command window, the following happens: after the YACL app terminates, the command window seems completely unresponsive. But if you then click on some other window (making the command window lose focus), and click back again on the command window, it behaves ok. I have no idea why this happens; if you can tell me why (and better yet, give me a workaround), I'd be delighted. This does not happen under Warp. It also does not happen under 2.1 if you start up the YACL app directly from the desktop (e.g. by opening the folder via the "drives" icon and starting up the app).
Trouble with CompositeVObjects. Under both Windows and OS/2, if you create Composite B as a sticky child of Composite A, and then have a button group as child of Composite B, the interior of the button group will not be repainted correctly after it is temporarily obscured.
Co-ordinate system. OS/2 reckons its co-ordinate system from the bottom left corner, not the top left corner. The result is that if you create a Composite with some children, and then resize the Composite, the children appear to move downwards, because their positions are tied to the bottom of the window, not the top. This doesn't happen under X or MS Windows.
Fonts for menus. You cannot change the font of a menu item or menu bar under program control (i.e., via its Font() method). The reason for this restriction is some rather peculiar behaviour I observed when trying to change the font of a menu while responding to its parent window's PAINT message.
Bitmap buttons. Bitmap buttons are implemented not via OS/2's button class but by using a special window class registered by YACL. This is because I couldn't find a way to use OS/2's Button class to implement both the toggle and the push button variety. Bitmap buttons work ok, except that their Disable() method does nothing. This will be fixed later.
The DateEditor class. Sometimes, when the DateEditor gains focus, it sets itself into overwrite mode rather than insert mode. (This is shown by a block caret rather than a thin i-beam caret.) The result is that typing into the DateEditor results in no action at all. Hit the insert key and put it into insert mode before typing in, and that'll fix it. This is merely a temporary workaround until a better way to ensure insert mode is added into YACL.
Font problems. OS/2 seems to lie about font attributes sometimes. For example, in the list of fonts returned by GpiQueryFonts (in FontInfo::AvailableFonts --- see file ui/font.cxx), when it gives the face name as Courier Bold Italic, it only sets the italic attribute in fsSelection, not the bold attribute. The result is to make it seem as if the Font demo doesn't work right: clicking on the Courier Bold Italic font produces the system font in italic mode. However, if you explicitly select a Courier Bold Italic font for use on your DisplaySurface, it works fine.
Multi-color bitmaps. OS/2 absolutely requires, when creating a Bitmap from a file, that before you call GpiCreateBitmap you must have selected the bitmap's palette into the presentation space via GpiSelectPalette. Discovered this by lots of experimentation. So the code for UI_Bitmap::BuildFrom selects the palette, creates the bitmap and then deselects the palette. Just before painting a bitmap, the DisplaySurface::DrawBitmap method actually does the palette selection. The reason for this setup is that the presentation space is a common resource on which the application might want to draw several different bitmaps, so we cannot have the Bitmap class dictating what palette is selected on the DisplaySurface.
The 3DLabel class. (Added March 4, 1996.) Under OS/2, the 3DLabel class does *not* use an in-memory display surface, unlike on the other platforms. The reason for this is the following. If the 3DLabel did use an in-memory DS, and if its parent doesn't create a DisplaySurface for itself when a paint event is received, then each 3DLabel instance will create and destroy a DisplaySurface for its parent on each paint event. The result is that more than one WinGetPS call occurs for the parent window during its paint event. OS/2 doesn't seem to like that; it reacts in a peculiar way --- the label's font seems to shrink on each consecutive call.
Multiple Document Interface. (Added March 4th, 1996.) MDI support under OS/2 is still somewhat flaky. The MDI children get created, but don't get added to the menu bar or repainted correctly. Also, tiling is not supported yet.
The TextEditor class. The TextEditor class is realized using OS/2's MLE control, and the latter is subject to a limit of 4K on its content size. Therefore, under OS/2, the TextEditor class cannot handle a model size larger than 4K.
Also, the MLE control is peculiar in the way it responds to queries about its contents. It reckons hard line breaks as single characters, even though a hard line break under OS/2 consists of the two characters CR and LF. So the YACL code asks the MLE twice for each position index, once using the MLM_QUERYTEXTLENGTH message and once using the MLM_QUERYFORMATTEXTLENGTH message.
The TreeView class. (Added February 14th, 1997.) When the user selects a node of the TreeView by clicking on it, OS/2 sends a WM_CONTROL message with a CN_EMPHASIS parameter, saying that the node is selected; this results in the YACL Event_Select event being generated. If the node happens to be an internal node, and the user expands its subtree, then OS/2 also sends a TreeNodeExpanded message. The only exception to this seems to be when the root is first clicked on: At that time, OS/2 for some reason does *not* send the Select event, it only sends the TreeNodeExpanded event. Oddly enough, it sends that Select event when one of the children of the root is selected; so at that point, *two* Select events are sent, one for the root and one for the child. I believe this is an OS/2 bug.
Trouble with CompositeVObjects. Under both Windows and OS/2, if you create Composite B as a sticky child of Composite A, and then have a button group as child of Composite B, the interior of the button group will not be repainted correctly after it is temporarily obscured.
Three-dimensional look. If you try to create CompositeVObjects with the 3-D look, you'll find that the system menu for such a window is not displayed properly -- it will be about 3 pixels below and to the right of where it should be. The window positions will also be off by a little, i.e., the values your app will get for the client area's position and size will be about 3 pixels off the correct value. Moral: don't use the 3-D look on CompositeVObjects. The 3-D look works fine with Dialogs, though. I think that's because Dialogs are not resizable.
Note also that a MenuBar attached to a Dialog doesn't look right under Windows with the 3-d look. Again, I think this is because of a CTL3D bug.
Fonts for menus. Windows does not include inherent support for changing the fonts of menu bars and popup menus. YACL could include such support, but at the moment it doesn't. In other words, attempting to use the Font() method on a menu bar has no effect.
Arguments to Main. Under Windows, the argv[0] value of the parameters to UI_Application :: Main is always the full path name of the executable file, never a relative path name. This is because it is obtained via the GetModuleFileName API call. The remaining argv values are the command line parameters, as is usual on Unix and OS/2 systems.
Bitmap buttons. Bitmap buttons are implemented not via Windows' button class but by using a special window class registered by YACL. This is because I couldn't find a way to use Windows' Button class to implement both the toggle and the push button variety. Bitmap buttons work ok, except that their Disable() method does nothing. This will be fixed later.