Programming Guide: User Event Handling

# Programming Guide

## User Event Handling

Your OpenDoc part editor is required to respond to a specific set of actions or messages from OpenDoc that constitute the majority of user interactions with your parts. In OpenDoc, these messages are called user events.

User events in OpenDoc include mouse clicks and keystrokes, menu commands, activation and deactivation of windows, and other events available only on some platforms. This section defines the different types of events and discusses how your part editor's HandleEvent method handles them.

Certain user events are handled by the dispatcher. The dispatcher accepts the user events from the underlying operating system through the document shell and dispatches them to the part editors. (See "Run-Time Environment" for a discussion on the document shell.) The dispatching system is modular and can be extended to handle new classes of events by adding a dispatch module. Each dispatch module is responsible for deciding which frame or part should be asked to handle each event that the module deals with.

When the OpenDoc dispatcher receives an event intended for your part, it locates a dispatch module for the event. The dispatch module in turn calls your part's HandleEvent method. (Your part's Draw method can be called indirectly because of an event, through the Update method of a window or facet).

Your part becomes the target for a specific type of user event (other than geometry-based events) by obtaining the focus for that event. The OpenDoc arbitrator keeps track of which part owns focuses by consulting a focus module. A focus module tracks, for example, which part is currently active and should receive keyboard events. Focuses and focus modules are described further in "Focus Types".

Geometry-based events, such as mouse clicks, are generally dispatched to the parts within which they occur. This permits inside-out activation to occur.

Your part receives some of the information about its events in the ODEventData structure. This structure is described in OpenDoc Programming Reference.

Other information about the event is passed to your part in an OpenDoc-defined event-info structure:

For any geometry-based event (mouse event) that is passed to your part, the coordinates of the event are passed in the where field of the structure. For events in embedded frames that are passed to your part, the frame and facet within which the event occurred are passed in the embeddedFrame and embeddedFacet fields.

### Types of User Events

Your parts must, in general, handle the following types of user events:

- Mouse events
- Mouse events in embedded frames
- Keyboard events
- Menu events
- Window events
- Activate events
- Update events
- Null events
- Other events

The following sections describe how you handle each of these kinds of events.

#### Mouse Events

When the user presses or releases the mouse button while the mouse pointer is in the content area of an OpenDoc window, the dispatcher finds the correct part to handle the mouse event by traversing the hierarchy of facets in the window.

The dispatcher searches depth-first (the most deeply embedded facets first) and front-to-back (the front-most of sibling facets first). The dispatcher sends the event to the editor of the first and front-most frame it finds whose active shape contains the pointer position. In this way, the smallest enclosing frame surrounding the pointer location receives the mouse event, preserving the OpenDoc inside-out activation model. None of the part editors of any containing parts in that frame's embedding hierarchy are involved in handling the event.

When the user presses a mouse button while the pointer is within a facet of your part, the dispatcher calls your part's HandleEvent method, passing it an event containing the mouse message.

When the user releases the mouse button while the pointer is within your facet, the dispatcher again calls your part's HandleEvent method, passing the mouse message.

The event-dispatching code does not itself activate and deactivate the relevant parts; it is up to the editor of the part receiving the mouse event to decide whether to activate itself or not. See "Mouse Events, Activation, and Dragging" for information on how your part should handle mouse-down and mouse-up events within its facets for the purposes of part activation, window activation, and drag-and-drop.

The dispatcher also tracks pointer position at all times when the mouse button is not pressed.

- When the pointer enters a facet of your part, moves within your facet or leaves your facet, the dispatcher calls your part's HandleEvent method, passing WM_MOUSEMOVE events on the AIX platform.

You can use these events to, for example, change the cursor appearance. See "Handling Mouse Events".

In some situations, OpenDoc redirects or changes mouse events:

- If the user holds down the Shift key, Alt key or Ctrl key while pressing or releasing the mouse button, the dispatcher instead sends the event to the frame with the selection focus. This allows users to extend selections by Shift-clicking, Ctrl-clicking or Alt-Clicking.

- If the mouse event is in the title bar or re-size box of a window, the dispatcher converts it to a window event.

- If the mouse event is in the menu bar, the dispatcher converts it to a menu event.

- If a frame has the modal focus (see "Acquiring and Relinquishing the Modal Focus"), mouse events that occur outside of its border are sent to it. However, mouse events that occur within frames embedded within the frame with the modal focus are sent to the embedded frames, as expected.

- If a frame has the mouse focus (see "Mouse-Up Feedback while Drawing"), it receives all mouse-within events that occur, regardless of their location.

Mouse clicks within controls associated with your part can be handled in a number of ways, as discussed in "Controls".

#### Mouse Events in Embedded Frames

If your part contains embedded frames, the dispatcher can also send you special mouse events that occur within and on the borders of the embedded frames's facets.

The following events occur when your part's frame is the active frame and the embedded frame is selected, bundled, or in icon view type, or if the user Shift-clicks or Ctrl-clicks or Alt-clicks in the embedded frame to extend a selection:

- When the user presses a mouse button while the pointer is within a facet of the embedded frame, the dispatcher calls your part's HandleEvent method, passing it an event type of kODEvtMouseDownEmbedded.

- When the user releases a mouse button while the pointer is within the embedded facet, the dispatcher again calls your part's HandleEvent method, this time passing it an event type of kODEvtMouseUpEmbedded.

  There is one exception to this. If the embedded frame is selected (rather than bundled or in icon view type), and if the mouse-up is not part of a Shift-click, Ctrl-click or Alt-click, your part does not receive the mouse-up event. In such a case, if the user initiates a drag the mouse-up event is converted to a drop; if the user does not initiate a drag, the mouse-up event is sent to the embedded frame so that the embedded part can activate itself. See "Mouse Events, Activation, and Dragging" for more information, including how to handle events in a background process.

The following event occurs when the frame embedded within your part is the active frame:

- When the user presses the mouse button while the pointer is within the active border of a facet of the embedded frame, the dispatcher calls your part's HandleEvent method, passing it an event type of kODEvtMouseDownBorder.

These events allow your part to activate itself and select or drag the embedded part.

#### Keystroke Events

When the user presses a key on the keyboard and your part has the keyboard focus, the dispatcher calls your part's HandleEvent method, passing it an event type of kODEvtKeyDown. When the user releases the key, the dispatcher again calls your part's HandleEvent method, this time passing it an event type of kODEvtKeyUp.

Exceptions to this convention include keystrokes that are keyboard equivalents to menu commands when the menu has the focus, which go to your part as menu events, and keystroke events involving the Page Up, Page Down, Home and End keys, which go to the frame that has the scrolling focus.

#### Menu Events

If the user presses the mouse button when the mouse pointer is within the menu bar, or if the user enters a keyboard equivalent to that action, the OpenDoc converts the mouse-down or keystroke event into a menu event of type kODEvtMenu and calls the HandleEvent method of the part with the menu focus.

On the OS/2 and Windows platforms, the message field of the event structure passed to HandleEvent contains WM_COMMAND. Processing of the WM_COMMAND message for menu events is handled the same as for a Windows or PM application window procedure.

On the AIX platform, the event structure passed to HandleEvent is a MenuEventData structure, defined in IDL file ODTypesM.idl The message field of this structure is set to kODEvtMenu; the menu field contains the ID of the selected menu; and the item field contains the ID of the selected item.

For a description of the HandleEvent method, see the OpenDoc Programming Reference. Handling individual menu commands is discussed in "Menus".

#### Window Events

If the user presses the mouse button while the pointer is within a non-content position of the window (such as the close icon in the window), or if the user enters a keyboard equivalent to that action, OpenDoc converts the mouse-down or keystroke event into an event of type kODEvtWindow and the document shell handles the event.

How to handle window events when your part is the root part is described in "Handling Window Events".

#### Activate Events

On platforms that support activation and deactivation of windows, OpenDoc sends activate events and deactivate events, of type kODEvtActivate, to each facet in the window when the window changes state.

If the user clicks in the title bar of an inactive window, OpenDoc activates the window and brings it to the front. If the user clicks in the content area of an inactive window, the part at the click location brings the window to the front. Either way, when an active window becomes inactive because another window has become active, each facet of each part displayed in the window being deactivated receives a deactivate event, and each facet of each part displayed in the window being activated receives an activate event.

Your part's HandleEvent method can use these events to store and retrieve information with which it can decide whether or not to activate itself when its window becomes active; see "Handling Activate Events" for an explanation.

#### Update Events

To support redrawing of previously invalidated areas of a window, frame, or facet, OpenDoc handles update events and calls the Draw methods of the appropriate parts.

Update events are themselves triggered by the existence of invalid areas, created through changes to the content of parts, the activation of windows, or the removal of obscuring objects such as floating windows.

OpenDoc does not pass update events to your HandleEvent method. When an update event occurs that involves a facet of your part, the dispatcher calls the Update method of the window, which results in a call to your Draw method. For more information, see "Invalidating and Updating".

### Propagating Events

A containing part can set a flag in an embedded frame that allows the containing part to receive events not handled by the embedded frame. If your part contains embedded frames with that flag set, your HandleEvent method receives the events originally sent to them. OpenDoc sets the propagated field in the EventInfo structure to true when it passes a propagated event to your part.

Whenever you add a facet to a frame, you can check the state of the flag by calling the frame's DoesPropagateEvents method. You can then set or clear the flag by calling the frame's SetPropagateEvents method.

This is a specialized feature of OpenDoc, not likely to be used by most part editors. You might use it to manipulate embedded selections; for example, you could use tab-key events to allow the user to tab between embedded parts that do not themselves support tabbing or otherwise handle tab-key events.

If you do not set the event-propagating flag for any of your embedded frames, your HandleEvent method receives only those embedded-frame events described in "Mouse Events in Embedded Frames".

### HandleEvent Method of Your Part Editor

The dispatcher calls your part's HandleEvent method to pass it a user event meant for your part. This is the interface to the method:

    ODBoolean HandleEvent(inout ODEventData event,
                          in ODFrame frame,
                          in ODFacet facet),
                          inout ODEventInfo eventInfo);

Your implementation of HandleEvent might be similar to this:

1. Initialize the result flag to kODFalse.

2. Obtain the part info data from the frame or facet to which the event was directed, if you have stored relevant information there.

3. Execute a switch statement with one case for each event type. Pass execution to the appropriate handler for each event type. Set the result flag to kODTrue if an individual handler handles the event.

4. Return the result flag as the method result.

Your individual event handlers should function as described in other sections of this chapter. Each should return kODTrue to HandleEvent if it handles an event, and kODFalse if it does not.

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