Programming Guide: Windows

# Programming Guide

## Windows

Windows are platform-specific data structures through which documents display themselves. This section discusses how to use OpenDoc window objects (which are basically wrappers for those structures) regardless of which platform you are developing for.

### Creating and Using Windows

The OpenDoc class ODWindow is a wrapper for a pointer to a platform-specific window structure. For some operations, your part editor must retrieve the window pointer from the ODWindow object and use the platform's facilities. In most cases, however, the interface to ODWindow provides the capability you need for interacting with your windows.

#### Window State Object

There is a single instantiated window state object (class ODWindowState) for each OpenDoc session. The window state consists of a list of the currently existing window objects. You can access all open windows in a session through the window state.

The document shell and dispatcher use the window state to pass events to parts so that they can activate themselves, handle user input, and adjust their menus as necessary. A part may be displayed in any number of frames, in any window of a document. The dispatcher uses the window state to make sure that it passes events to the correct part, no matter what window encloses the active frame and how many other frames the part has.

Normally, your part editor calls the window state only when it creates new windows, when it needs access to a particular window, and when it needs access to the base menu bar object.

If for some reason your part needs access to all windows, you can create an ODWindowIterator object, which gives you access to all windows referenced by the window state.

#### Creating and Registering a Window

In order to receive events in a window, you generally must create an OpenDoc window object for it. (You may not be able to create an OpenDoc window for a modal dialog box, but you can pass an event filter routine to it and therefore receive events.) Windows in OpenDoc are created and maintained through the window-state object, which you access through the session object.

You first create a window with platform-specific calls; you then call the window state object to create an OpenDoc window object describing the platform-specific window. You call either of two methods:

- You call the RegisterWindow method of ODWindowState when you create a window that is not a root window or has never yet been written to storage.

- You call the RegisterWindowForFrame method of ODWindowState when you create a root window from a previously stored root frame. (RegisterWindowForFrame takes fewer parameters than RegisterWindow because the frame passed in with the method already contains some of the needed information).

A window has an is-root property. If the property is true, the window is a root window, which is the same as a document window. The root part of a root window is the root part of its document, and the document cannot close as long as the root window is open. If a window's is-root property is false, the window may be either a part window that has been opened from a source frame within a root window, or it may be a dialog box, palette, or other utility window. OpenDoc permits multiple document windows for a single document, as long as the root part provides a user interface to support this feature. The document shell closes a document when the document's last document window (root window) is closed.

Windows also have a should-save property that, if true, specifies that the state of the window is saved persistently after the window closes. Usually, only document windows should be marked as should-save.

The creator of a window can specify the view type and presentation of the root frame, the frame that displays the root part. The view type specifies whether the root part should draw itself as an icon, and the presentation specifies what kind of appearance the part content should have if not drawn as an icon. View type and presentation are suggestions to the part editor that draws within that frame. View type and presentation are described in more detail in "Defining General Display Characteristics".

On the OpenDoc platform, the root frame in the window has the same shape as the window's content region.

Your part should create windows as invisible and then make them visible as described in "Opening a Window".

#### Opening a Window

After creating a window, your part editor typically makes calls to these three methods, in this order:

1. The window's Open method, which creates the root facet
2. The window's Show method, which makes the window visible
3. The window's Select method, which brings the window to the front

#### Window IDs

Your part editor should not maintain references to ODWindow objects for accessing OpenDoc windows, because the document shell or the window state object can close a window and invalidate the reference. Instead, the window state assigns window IDs that are valid for the length of a session. Use the window's GetID method to get the ID of a window when you create it, and then pass that ID to the window state's AcquireWindow method for subsequent access to the window.

#### Closing a Window

If your part editor needs to close a window programmatically, it calls the window's CloseAndRemove method. That method closes the window, releases the window object and disposes of the platform-specific window structure, deletes the root facet and canvas, and removes the root frame from the document. It also makes any necessary platform-specific calls to dispose of the window itself.

#### Storing and Retrieving Window Characteristics

Whenever a document is saved, OpenDoc writes certain information into a storage unit of the window's root frame. The window's bounding rectangle, title, and other characteristics are saved in a property of type kODPropWindowProperties in the frame's storage unit.

When you create a root window, you retrieve that information from the stored frame, and use it to specify the platform-specific window's characteristics. You can use functions of the WinUtils utility library (provided with OpenDoc) to extract that information, or you can access the frame's storage unit directly. The kODPropWindowProperties property contains a persistent reference to another storage unit, which contains the following properties:

- kODPropShouldShowlinks
- kODPropSourceFrame
- kODPropWindowIsFloating
- kODPropWindowIsResizable
- kODPropWindowIsRootWindow
- kODPropWindowIsVisible
- kODPropWindowRect
- kODPropWindowTitle

##### Making sure a window is on screen

If your part is a root part that recreates a previously stored document window, you must make sure that the window is visible onscreen. Your document may have been moved from one system to another with a different monitor configuration or size. You may need to move or resize the window to fit its new environment.

#### Open Method of Your Part Editor

Opening your part means creating a window for it and displaying it in the window.

Your part itself initiates the opening of a window when the user selects the Open as window command from the View menu (see "View Menu"), and when it creates its own dialog boxes. Otherwise, your part opens a window only when your part's Open method is called. This is the interface to the Open method:

    ODID Open(in ODFrame frame);

The Open method is called in these circumstances.

- When your part is initially created, when it has no previously stored frame or window information, OpenDoc calls your part's Open method and passes a null value kODNULL for the frame parameter.

- When your part is an embedded part whose frame is selected, and you select Open selection from the Edit menu, your containing part calls your part's Open method and passes a reference to the selected frame in the frame parameter.

- When your part is the root part of a document being opened, OpenDoc calls your part's Open method and passes a reference to the root frame in the frame parameter.

In your implementation of Open, you can take steps similar to the following, depending on the circumstances under which it was called.

1. If you are creating an initial window (frame = null), skip this step and go to step 2.

   - If you are opening a frame into a part window (frame = an embedded frame), check to see if the window already exists. If you have created the part window previously and saved its window ID, pass that ID to the AcquireWindow method of the window state object. If the method returns a valid window, bring the window to the front and exit. If the window does not yet exist, go to step 2.

   - If you are opening a stored document into a window (frame = a root frame), read in the saved window data from the storage unit of the frame passed to the method (see "Storing and Retrieving Window Characteristics").

2. Create a platform-specific window and register it with the window state object, as described in "Creating and Registering a Window".

   - If you are opening a stored document into a window, apply the stored characteristics to the platform-specific window. Call the window state object's RegisterWindowForFrame method.

   - If you are opening a frame into a window or creating an initial window, apply your default characteristics to the platform-specific window. Call the window state object's RegisterWindow method.

3. Get the window's window ID and save it for future reference.

4. Open and bring the window to the front, as described in "Opening a Window". If you are opening a stored document into a window, skip this step because there may be more than one window to open and OpenDoc determines which window is to be in front.

Note:

> You are not absolutely required to open a window when your Open method is called. Your part does whatever is appropriate, given its nature and the conditions under which the method is called. For example, if your part is a very simple sound player, it might simply play its sound and never create a window.

### Handling Window Events

To receive events in its windows that it creates, your part must create an ODWindow object for each platform-specific window it uses, including dialog boxes (except for modal dialog boxes; see "Modal Dialog Boxes").

The document shell handles most window events outside of the content region, for example, events in the title bar or resize box.

If your part handles a window event, its HandleEvent method must return true. If it does not handle an event, its HandleEvent method must return false so that the document shell can handle the event.

#### Resizing

The document shell usually resizes windows. When a window is resized, the active part does not change, but the part editor for the root frame is informed of the resizing through calls by OpenDoc to its FrameShapeChanged and GeometryChanged methods. The root part can then do any necessary invalidation and subsequent redrawing, including creation of new facets if embedded parts have become visible due to the resizing.

#### Closing

The document shell handles a mouse click in the Close icon of a window or user action of Close or its keyboard equivalent. The document shell closes the window, after which the window cannot be reopened.

If the window is a document window and is the only one open for that document, the document shell closes the document.

If your part editor needs to close a window programmatically, it can call the window's CloseAndRemove method. The window is closed and the window object is released.

#### Dragging

The document shell handles some platform-specific window-moving actions, such as dragging of a window by its title bar. No event-handling is required of the window's root part.

Parts in other windows may need to be updated because of the window's move; they receive update events as appropriate.

### Modal Dialog Boxes

When your part editor displays a modal dialog box, it does not need to create an ODWindow object, as with a regular window. However, it should still request the modal focus (using its own display frame as the modal-focus owner), and it can still receive events by providing an event filter

Your part can create and register its own dialog window, request the modal focus for the window's root frame, and handle the dialog box.

#### Acquiring and Relinquishing the Modal Focus

A frame displaying a modal dialog box should own the modal focus, a focus type that exists to constrain certain events.

For example, a mouse click outside the frame that has the modal focus still goes to that frame. If your part's frame has the modal focus and you click outside the frame, your part's HandleEvent method is called and passed a facet of kODNULL. The method should check for a null facet in this situation and either alert the user with a beep or dismiss the dialog box, as appropriate.

A click in a frame embedded within the frame that has the modal focus goes to the embedded frame. This behavior facilitates the construction of dialog boxes and other controls from multiple parts.

Your part obtains and relinquishes the modal focus as it does any focus, as described in "Requesting Focuses" and "Relinquishing Focuses".

In general, your part should not be willing to relinquish the modal focus on request. If your part is displaying a modal dialog, you probably do not want any other modal dialog to be displayed at the same time. To make sure that your part holds on to the modal focus, your part editor's BeginRelinquishFocus method should return kODFalse if the requested focus is kODModalFocus and the proposed new owner of the focus is not one of your own display frames.

When you have finished displaying a modal dialog box, you can directly transfer it to its previous owner by calling the arbitrator's TransferFocus method, as noted in "Handling a Simple Modal Dialog Box".

#### Event Filters

With modal dialog boxes, your part editor's dialog-box event filter controls which events you receive while a dialog box or alert box is being displayed. To pass received null events, update events, and activate events on to OpenDoc or other windows for handling, your event filter can send them to the OpenDoc dispatcher by calling its Dispatch method.

Your event filter should not pass other events, such as mouse events, to the dispatcher.

#### Handling a Simple Modal Dialog Box

To display a simple modal dialog box or Alert box, you can take these steps:

1. Get a reference to the frame that currently owns the modal focus by calling the arbitrator's GetFocusOwner method. Request the modal focus from the arbitrator, using its RequestFocus method. If you obtain the focus, proceed.

2. Install your dialog event filter function.

3. Create the dialog box, using a Dialog Manager function such as GetNewDialog or a utility function such as ODGetNewDialog (from the DlogUtil utility library provided with OpenDoc). One advantage of using ODGetNewDialog is that it positions the dialog box in relation to your part's document window, rather than to any part windows that may be open.

4. Handle the dialog box with a Dialog Manager call such as ModalDialog. Act on the results and, when finished, dispose of the dialog box with a Dialog Manager call such as DisposeDialog.

5. Remove your dialog event filter function.

6. Restore the modal focus to its previous owner by calling the arbitrator's TransferFocus method.

By always saving and restoring the owner of the modal focus, your part can use this approach for nested modal dialog boxes, such as a dialog box that is built from several embedded parts.

#### Handling a Movable Modal Dialog Box

In OpenDoc, to implement a full-featured movable modal dialog box, one that allows process switching, you must create a window object (ODWindow) to contain it. To display a movable modal dialog box, you can take these steps:

1. Use the appropriate methods to create the structures for the dialog box.

2. Create a window object, using the window state's RegisterWindow method. Give it properties appropriate for your modal dialog, such as floating, nonpersistent and floating.

3. Request the modal focus for the root frame of the dialog window.

4. Adjust menus, as necessary, for the presence of the dialog box.

5. Call the Open, Show, and Select methods of the modal dialog window.

6. Handle events in the dialog box through your normal event-handling mechanism.

To make sure you dismiss the modal dialog box at the right time, you can take actions such as these when you receive a mouse-down event in the dialog box:

1. Determine whether the event applies to your dialog and, if so, what item you selected.

2. If you chose to close the dialog box, relinquish the modal focus and call the window's CloseAndRemove method to delete the window and its root frame.

3. Re-enable any menus or menu items that you disabled for display during the existence of the dialog box.

Note:

> It is also possible to create a modal dialog box that is movable, but does not support process switching. To do so, use a filter function and other functions in a utility library (DlogUtil) provided with OpenDoc.

### Modeless Dialog Boxes

Modeless dialog boxes are more like regular windows than modal dialogs are. They can be activated and deactivated, and they need not be dismissed for your part to become active and editable.

#### Showing the Dialog Box

To display a modeless dialog box in OpenDoc, you must create a window object (ODWindow) to contain it. To display the dialog box, you can take steps such as these:

1. In case the dialog window already exists, try to get a reference to it by passing its ID (previously stored in your part) to the window state's AcquireWindow method. If it does not yet exist, create the platform-specific structures for the dialog box, and create a window object with the window state's RegisterWindow method. Call the window's Open method.

2. Call the window's Show and Select methods to make it visible and active.

3. If you do not already have the window ID of the dialog window, get it by calling the window's GetID method. Save it for use in step 1 the next time you choose the action that brings up the modeless dialog box.

#### Closing the Dialog Box

When you click in the close box of a modeless dialog, you can hide the dialog window, rather than close it, so that it is not destroyed. This is an optimization that allows you to quickly display the dialog box again.

In your part's HandleEvent method, you can respond in this general way to a mouse click within a window's close box:

1. From the frame or facet passed to HandleEvent, obtain information that can identify the window. For example, get a reference to the window object in which the event occurred (by calling the facet's GetWindow method), or examine the frame's presentation or part info data for identifying characteristics.

2. Compare that information to stored information that defines your modeless dialog box. For example, get a reference to your modal dialog's window object (by passing its ID to the window state's AcquireWindow method), for example, or check a stored value that defines your modeless dialog's presentation.

3. If the two are the same, hide the window instead of closing it.

#### Hiding a Dialog Box when Deactivating a Frame

When your part is deactivated, it should hide any of its modeless dialog boxes.

When your part relinquishes the selection focus, it can get a reference to the dialog window (by passing its ID to the window state's AcquireWindow method), call the window's IsShown method to see if it is currently being shown, and then save that shown state and hide the window.

When your part reacquires the selection focus, it can retrieve a reference to the dialog window by passing its ID to the window state's AcquireWindow method. Then, if the dialog window had been visible at deactivation, your part can once again show it.

[ Top | Previous | Next | Contents | Index | Documentation Homepage ]