To distinguish between Clarion WINDOW and APPLICATION structures, and Windows OS User objects, the following text uses upper-cased WINDOW for Clarion structures and a lower-case italic font for User objects: window.
Every window has 2 logical areas:
- Client area – rectangular part of window surface where window contents (controls) is drawing. The client area can be empty, e.g. for iconized windows.
- Non-client area – part of the window’s surface outside the client area. The non-client area can be empty if the client area is equal in size to the entire window rectangle.
Windows uses the non-client area of a window to draw the border, caption, menubar and scrollbars, if any. Because modern window styles assume usage of additional informational and control elements, for example toolbars or status bars which can be created/destroyed at run time, Clarion uses 2 or more windows to implement WINDOW structures:
- Non-client window (mandatory)
- Client window (mandatory)
- Toolbar (optional)
- Site windows for dockable toolboxes (optional)
- MDI Tab bar (in APPLICATIONs, optional)
The term non-client part indicates the non-client window of a WINDOW/APPLICATION structure, and the term client part to indicate the client window area.
Non-client part of WINDOW
The non-client part of WINDOW can contain:
All elements are optional depending on the actual WINDOW declaration.
The client area of non-client part of WINDOW can contain:
- Status bar
- MDI Tab bar (for frame WINDOWs)
- Docking site spaces
The non-client part is a parent window for the client-part.
The non-client part determines the position and dimensions of WINDOW:
- Coordinates of the upper-left corner of the non-client part are position of WINDOW.
- Width and height of the client part are the dimensions of WINDOW.
The Windows OS (not the RTL) deals with the non-client part to move, size, change position in Z-order, activate, maximize, restore, iconize and hide/unhide WINDOW.
Implementation of WINDOW structures in the RTL
Implementation of WINDOWs in the RTL follows their (user) declared structure. In both the current version (C9) of the RTL, and all previous versions, the RTL considers non-client and client parts as a united object.
Schema of implementation of WINDOWs (APPLICATIONs have additional elements)
The Clarion RTL creates the entire WINDOW including window objects for non-client and client parts, toolbar and other elements in the thread where the program executes the CREATE statement for that WINDOW. Because Clarion does not allow creation of MDI child WINDOWs in the Frame’s thread, the RTL uses the CreateMDIWindow API function to create the non-client part of WINDOW. The CreateMDIWindow function has been listed as one of benefits of 32-bit Windows in comparison with earlier 16-bit Windows 3.x versions because it can create an MDI child window in a different thread other than one running the frame window. But the real life implementation of the MDI API in Windows OS is not thread safe. Therefore simultaneous activity of several MDI child windows running in their own threads will eventually cause an inconsistent state of the Windows OS internal structure containing MDI-related information and, consecutively, incorrect functioning of both the MDI frame and MDI child windows in multiple ways.
Since Clarion 6 was introduced and the problems with MDI were discovered huge efforts have been made to hide them for MDI child WINDOWs in Clarion. Unfortunately, there is no complete solution without changing of the internal structure of WINDOWs. The new Clarion RTL will use a new implementation of WINDOWs. The main change is that the non-client and client parts will be strictly separated.
Changes in the WINDOW structure provide several important benefits:
- The non-client part and the client part of the same WINDOW can be created in different threads. Specifically, the non-client part of an MDI child WINDOWs can be created in the Frame’s thread. This solves all the problems caused by the thread-unsafe implementation of MDI in Windows. All the code added to the RTL to work around these problems becomes unnecessary and can be removed. This makes the RTL far more manageable and extensible.
- The client part of WINDOWs with or without the MDI attribute is absolutely identical and is very close to the toolbar. There are a few minor differences, e.g., the client part of a WINDOW can be scrollable and setting focus to a toolbar’s controls is handled in special way. This allows us to share most of the code for the client part and for the toolbar.
- The separate client part can be “glued” to any rectangular area within the bounds of the client area of the non-client part of any WINDOW, for example, to a TAB control. That means the client part can be used as a compound custom control. It can be created multiple times, and every copy can be “glued” to different places without the necessity to duplicate the code. Implementation of such user-defined control could be coded as a class with a method to declare a client-part-only WINDOW and run it’s ACCEPT loop and methods to set or query values of any USE variables. Dockable toolboxes can be re-implemented in this same way. Probably, a new keyword will be added to the language for declaring client-part-only WINDOWs. The host WINDOW would provide a simple interface to inform the “glued” object about events like resizing. The functionality of REGION controls could be extended for handling that implementation. Alternatively we could introduce another new keyword for areas where client-part-only WINDOWs can be “glued”.
- The common part of a WINDOW object is created upon entry to the scope where a WINDOW is declared is the same for WINDOWs with and without the MDI attribute. This allows the possibility to change the type of non-frame WINDOWs at run time before opening them.