Mastering Dialog Windows in Xbase++
Part 1 - Terminology And Window Types


Copyright © 2002-2008 Clayton Jones
by Clayton Jones
(with thanks to Greg Doran for his assistance with research)

Revised November 19, 2008

Introduction

One of the great things about Xbase++ is how it presents the underlying Windows API to us in a more simplified and easier to use interface.  This is never more true than when working with dialog windows.  In WIN32 API SuperBible by Richard Simon1, the introduction to Chapter 3 "Creating Windows" states "There is only one function needed to create windows, the CreateWindow function, which is the most complex function in the Windows API".  An attempt to study the chapter will validate his statement - it is quite complex and challenging to grasp.

Fortunately for us, Xbase++ distills this complexity down to several basic parent/owner configurations and some optional attributes, with which we can easily create many different kinds of interfaces in our applications.  However, these window types are not as clearly documented as they could be, and as a result there is some confusion and misunderstanding on this subject in the Xbase++ community.

When I first began working with Xbase++ (summer, 1997), I had a very difficult time understanding the different types of windows and how they worked.  Many of the terms used in discussion groups were not defined in the documentation and were often used in more than one context.  Nowhere in the documentation was there a thorough explanation of the window hierarchy.  It was very confusing and it took a long time to grasp the concepts - much longer than it should have.

Since that time, in addition to writing applications, my involvement with Xbase++ has included the development of Top-Down Library and its Tutorial, writing articles, conducting training sessions, and speaking at developer conferences in Europe and the US.  All of these activities have involved teaching, in one form or another.  I saw that new people beginning to use Xbase++ were having the same difficulties I had.  A great many of us are not C/C++ programmers, and I was motivated to find a way to make an easier transition into the language for "the common mortal".  Over time, as I learned more and developed new methods, I kept searching for new and better ways of explaining the concepts and techniques.
 

The First USA DevCon, New Hampshire, 2001
When I was asked to speak at the DevCon I knew immediately what the subject would be.  I had developed good techniques for controlling window behavior and, most importantly, a set of terms had evolved during training sessions which had proven very effective for conveying the concepts.  I pulled all the pieces together into a presentation for the conference and it received a very positive and enthusiastic response.   With urging from several people who attended the DevCon, I decided to expand the material into a series of web page articles, with the hope that it will help to clarify the subject and help new users get productive more quickly.
 

The Articles

The series of articles will cover the mechanics of windows, the concepts of control, and the role of threads and event loops.  Included will be techniques, tips and tricks for achieving the ultimate goal: being able to open as many layers of windows as we need, in any style of architecture, with complete control and predictable behavior.

Part 1,this article, discusses the terminology and the definitions of the six window types.
Part 2 will go into the details of controlling window behavior in MDI style applications. 
 

AppDeskTop() and SetAppWindow()

Before getting into the window terminology, some clarification is needed for these two functions.  Because they are used in the definitions of the different window types, it is important to define them clearly.
 

AppDesktop()

The AppDeskTop() function returns a reference to the invisible implicit window (XbpIWindow) which is created by the Xbase++ runtime engine at startup.  This is commonly referred to as "the application desktop" or "the desktop window".  Even though we cannot see it, it plays a crucial role in the windows hierarchy.
 

SetAppWindow()

There is some confusion about this function because it serves different purposes in GUI and CRT applications.  The function acts primarily as a Get/Set function, where a dialog window is passed into it as a parameter.  Calling the function later without a parameter retrieves a reference to the window.

In CRT, SetAppWindow() serves an additional purpose of allowing the "set" window to display output.  Therefore, it is necessary to pass into it each window that receives focus.  This, however, ruins its ability to serve as a Main window reference, since the "set" window is always changing.  Since a reference to the Main window is needed for various purposes, it is common to have a separate user defined Get/Set function for that.  This is commonly named RootWindow().

In GUI, the Main application window is passed into SetAppWindow() during startup.  After that, there is no need to send any other window into it.  Therefore, SetAppWindow() serves as the Get/Set function for the Main window throughout the life of the application, and a RootWindow() function is unnecessary.  This use is implied in the Xbase++ documentation where there are countless code samples using SetAppWindow() as a reference to Main.

Because of the general lack of clarity on the subject of window control, some developers who have moved from CRT to GUI erroneously continue to send different windows into SetAppWindow() in an attempt to control window behavior.  Some needlessly convoluted application designs have resulted from doing this.  Part 2 of the series will show how this practice is unnecessary, and how complete control of window behavior can be achieved without resorting to it.  Once the principles are understood, application design becomes very simple and straightforward.

For the remainder of the series, it is assumed that SetAppWindow() always returns a reference to the Main application window.
 

Terminology - Sorting Out The Confusion

Some of the terms presented here are not "official" terms from any reference book or Microsoft documentation (those that are, are so noted).  They are strictly for use in the context of Xbase++.  Some of them come from common use, some I made up or adopted.  This list is not presented as an authoritative technical reference, but is offered here solely for the purpose of giving Xbase++ developers a precise vocabulary so that we can communicate effectively.

I have categorized six types of windows: three primary types, commonly used in most applications, and three secondary types, used for special purposes.  The secondary types are merely variations of the primary windows.  The following eight terms are used to define these types and different ways of using them.
 

Top-Level
The term "top-level" refers to any window that has AppDeskTop() as both parent and owner.  There can be more than one top-level window open in an application.  Top-level, therefore, is a general term referring to any window with that parent/owner configuration.   It is a good, intuitive term for these windows since they are the highest ones in the windows hierarchy that are visible.  Top-level is used in this context in a MSDN article by Kyle Marsh2.

Referring to top-level windows, the Xbase++ documentation states that a GUI application can have "several application windows" (bottom paragraph in the topic "Windows and Relationships").  So "application window" is the only documented term synonymous with top-level.  However, it has never caught on in common use as a general term.  "The application window", as if there is only one, is often used to refer specifically to the primary controlling window of the application, usually called the Main window.
 

Main and SubMain

While there can be more than one top-level window open at once, only one of them is the primary controlling window which is created at startup, and which is programmed to terminate the application when it is closed.  This window usually has a menu bar or buttons to launch other parts of the program.  There is an important distinction between this window and any other top-level windows, and we need some dedicated terms to indicate which we are referring to.

"Main" has been commonly used to refer to this primary controlling window.  While "Main" is not formally defined this way in the Xbase++ documentation, it is used in some of the explanations and is also used that way by Simon, Marsh and Charles Petzold3.  Phrases such as "the Main application window" and "the Main window"  have been in common use for years.  The Main window is the first of the three primary window types. 

I chose the term "SubMain" to refer to any top-level window that is not the Main window.  It adequately conveys the proper meaning of being subservient to Main, in the sense that SubMain windows are called from within the application.  When Main is closed the application quits, and any open SubMains will automatically be closed.

We now have two terms which clearly differentiate between the primary controlling window and any other top-level windows.  If someone uses the term Main or SubMain in a discussion, others will know exactly what they mean.  SubMain is one of the secondary window types.
 

 Child

The next primary window type is one that is called from a top-level window (either Main or  SubMain), and has as parent and owner the drawingarea of the top-level window.  The Xbase++ documentation uses the term "MDI Client" to describe this window (see the topic XbpDialog), but it has never caught on.  Instead, the term "Child" has been universally used.  Indeed, "Child" is the name used for this window in Simon, Marsh and Petzold.

Since Child is not defined as a window type in our documentation, there exists some confusion about it in the Xbase++ community (every Xbase Part is a child of its parent, so, theoretically, every window is a child).   I have often seen it used by well-meaning people to describe any window that was called from an existing window, as if it were the offspring of the calling window, regardless of its parent/owner configuration.  This has been the source of much misunderstanding.  Hopefully, over time, the more precise meaning will become commonly understood.
 

 Modal

The third primary window type is one which has AppDeskTop() as parent and SetAppWindow() as owner, along with some other characteristics.  The term "modal" is universally used for this type of window.  Unfortunately, because it takes more than just the parent/owner configuration to make a Modal window, the term is often used to refer to windows that are not truly Modal.  A general description for Modal windows is found in the Xbase++ documentation for :SetModalState() under the topic for XbpWindow.  A more detailed definition is given in the outline below.
 

StepChild

Main, Child and Modal are the three primary window types commonly used in applications.  In addition, SubMain can be used for certain purposes.  The next secondary type is another variation which has special characteristics and is used for particular purposes.  It has the same parent/owner configuration as a Modal, but lacks the other conditions which would make it a Modal window.

This window is often called an "owned" window, and the term appears in this context in Marsh (could not be found in Simon or Petzold).  This term suffers the same handicap as "child", in that all windows have owners, therefore all can correctly be called owned windows.  Because the term is undocumented in Xbase++, and because of imprecise definitions of the window types,  these windows are often called Modals, which they are not, and sometimes are called Child, also incorrect.  What a mess!  Is there any wonder why people get confused?

In addition, the term "owned", conceptually, does not describe this window well.  So to avoid the confusion altogether I use the term "StepChild".  It describes the window's relationships very nicely:  like a Child, it is called from Main, but Main is not its real parent (parent is appDeskTop), hence, StepChild. 
 

  Layered Sibling

One of the important techniques discussed in Part 2 of the series is where we call a Child window from within an existing Child.  Technically, these two windows are identical - they both have the same parent/owner configuration and behavior.  In actual use, however, there is a difference.  Therefore we need a term which specifically means a Child window used in this manner, as opposed to one that is called from a top-level window.

The term "sibling" is used in the Xbase++ documentation to refer to any Xbase Parts which have the same parent.  By definition this includes dialog windows, and it is used similarly in Marsh.   So I have adopted the term "Layered Sibling" to describe this special way of using Child windows.  This is the last of the secondary window category.
 

Stream

"Stream" is a term used to describe a group of layered windows running in a separate thread. 
Beginning with a Child, any number of Layered Siblings may be called below it, one Sibling calling the next, hence a "stream" of windows emanating from the first one.  Any number of Streams may exist at one time.  The distinguishing element is that each Stream must exist in its own thread. 
 

Conclusion

Top-level, Main, SubMain, Child, Stepchild, Modal, Layered Sibling, Stream

A diverse collection of terms.  Together they provide a precise vocabulary for communication and discussion of window techniques in Xbase++.  With them we can express our ideas clearly and precisely and expect to be understood.  Below is an outline of the window types and their definitions.

The next article in the series will discuss the pros and cons of various techniques for achieving multiple Streams of layered windows.  It will encompass the use of these window types and the role of threads and event loops.
 

Six Types of Windows in GUI Applications

Three Primary Types - Main, Child, Modal

1) Definition of the Main Window

   Parent = appDeskTop()
   Owner  = appDeskTop()

2) Definition of a Child Window

   Parent = setAppWindow():drawingarea
   Owner  = setAppWindow():drawingarea



3)
Definition of a Modal Window - This is the only window type which requires more than a parent/owner configuration to define it.  A Modal actually must meet two conditions:

   a) Parent = appDeskTop()
   Owner  = setAppWindow()

   b) Set ModalState - this disables the owner, which is the Main window, so it effectively disables
        the entire application except itself, which is what a modal is supposed to do.

        The primary purpose of a Modal is to disable the rest of the application
        while the window is open.  A Modal disables its owner.  Therefore, the
        owner must be Main, so that the application gets disabled.  The parent
        must be different than the owner or else the Modal disables itself 
        (because any children of Main are disabled).  So we make AppDeskTop()
        the parent.

         NOTE: Under certain circumstances, a different window may be specified
         as the owner.  This is covered in Part 2.

    Note: In the original version of this article I had a 3rd condition listed here, stating that Modals require event loops.  However, it was brought to my attention that technically this is not correct and I have removed it.   But it is an important subject and deserves some explanation.  While it is technically correct that Modal windows do not need event loops (the Main window is disabled but its event loop continues to process events for the Modal window), for most practical purposes Modals do need event loops.  The reason for this is that in most cases Modals must behave in a procedural manner (the flow of program execution must halt where the Modal window is called and resume when it Returns).  An event loop is required for this behavior.  A good example of this is a dialog which asks the user which of two courses of action to take during a sequential routine.  AboutBoxes and other Modals called from the Main Menu can do without an event loop, but this is a small minority of typical Modal windows in a database program.  In addition, there is no harm in having an event loop in that type of Modal (because a Modal, by definition, is the only active window, so it doesn't matter).  Therefore, for the purpose of these articles it should be assumed that Modal windows have event loops and behave procedurally.  In real-world day-to-day programming I have found it to be a non-issue, and all of my Modals have event loops.  I don't even think about it, it's just a given.
 

Three Secondary Types - StepChild, SubMain and Layered Sibling

4) StepChild Window - this window is sometimes incorrectly called a Modal or a Child, and sometimes is called an "owned" window (confusing, because all windows are owned by something).  I chose this name because it describes it well - like a Child, it is usually called from Main, but Main is not its real parent, hence, StepChild). 

   Parent = appDeskTop()
   Owner  = setAppWindow()

Note: This is the same parent/owner configuration as a Modal, only it does not set the ModalState,
therefore it does not disable the owner, therefore it is not a Modal window.  This window has certain features, some good, some which require workarounds and special care:

   a) Can display outside the Main Window borders and responds to the :moveWithOwner attribute.

   b) Cannot be used along with a Child window inside the Main borders because it covers a Child,
       even when the Child has focus.  This is caused by its parent being AppDeskTop (a Modal
       does the same thing, but since it has disabled everything else it doesn't matter).

   c) A StepChild is not disabled by a Modal (because it is not a child of Main), but it can be
       specified as the owner of the Modal, which disables it.  But then the Main window is not
       disabled, so...be careful how you use it.

   d) There are more cautions about this window which will be covered in Part 2, but suffice it to say
       that it must be used with care and for specific purposes.  It is not a good general purpose MDI
       window.  A good example of StepChild use is the Xbase++ Form Designer, where the Main
       window is small and the StepChild windows exist outside its borders.
 

5) SubMain Window  - I chose this name because it is much like a Main window, but is called
    from within an existing application, and there can be only one Main controlling window, hence,
    SubMain.

   Parent = appDeskTop()
   Owner  = appDeskTop()

This has the same parent/owner configuration as the Main window, and both are top-level windows.  A SubMain, however, is called from within the Main window and has these constraints and features:

   a) It must run in a separate thread and have its own event loop or else events get mixed up between
       it and Main.

   b) It is closed automatically if Main is closed (assuming that Main is programmed to Quit the
       application when it is closed).

   c) Can be covered up by Main unless the StayOnTop attribute is set.

   d) It can perform like an independent application in this manner:
       1) It can be full screen.

       2) It gets a task bar button.

       3) It can have a menu.

       4) It can have its own child windows using this parent/owner configuration:

      Parent = subMain:drawingarea
      Owner  = subMain:drawingarea

       5) Modals can be called which disable a SubMain, if it is specified as the owner of the Modal. 
           These SubMain Modals do not disable Main.

 SubMain windows can be extremely handy. Some examples:

   a) Separate modules in an application, such as an accounting program with General Ledger and
       Accounts Receivable SubMains, each running full screen with its own task bar button, menu, and
       child windows.  Top-Down Library has a template for setting up these windows, and the demo
       application has an example.

   b) Special purpose routines, such as a print preview window, which can run full-screen and give the
        user the largest possible view.  A print preview window which uses this technique can be seen in
        the Top-Down Library demo application.


6) Layered Sibling Window - This window is identical to a Child window, with the same parent/owner configuration and behavior.  What is different is how it is used.  The main difference is that it is called from within an existing Child window, and not from the Main or other top-level window.  In addition to this, it requires a specific way of using threads and event loops. 

The purpose for it is to overcome the inherent limitation on the number of layered windows you can have using just the three primary window types.  It is the key which unlocks the Treasure Room:  Unlimited layers of windows with complete control and predictable behavior.  Using Layered Siblings is the central technique discussed in Part 2 of the series.
 

Part1 - The End
 

1 Windows NT Win32 API Superbible, Richard J. Simon, Waite Group Press
2 "Win32 Window Hierarchy and Styles", Kyle Marsh, MSDN Technology Group
3 Programming Windows, Fifth Edition, Charles Petzold, Microsoft Press
 

Copyright © 2002-2008 Clayton Jones
All rights reserved.


Return to: Articles Page |Top-Down Page | Software And Services | Home