Focus Transfer
Part activation is the process of making a part and frame ready for editing. As noted previously, activation typically occurs when the user clicks the mouse button when the pointer is within a frame that is not currently active, but it also happens when a window opens, when a window is activated, and as a result of drag-and-drop operations.In the OpenDoc model of part activation, part editors use the concept of focus to activate and deactivate themselves (rather than being activated and deactivated by OpenDoc) and to arbitrate the transfer of several types of shared resources among themselves.
Focus Types
A part makes itself the recipient of a certain type of user event or other action by obtaining the focus for it. A focus is a designation of ownership of a given shared resource, feature, or event type; for example, the frame that owns the keystroke focus receives all keystroke events until it passes ownership of the keystroke focus to another frame.Focus types are defined as ISO strings. Table 5-4 lists the standard set defined by OpenDoc.
To obtain event foci, part editors request them by name from the arbitrator. (You obtain access to the arbitrator by calling the
GetArbitrator
method of the session object.)You need to convert focus names into tokens before using them in any method calls. You call the
Tokenize
method of the session object to convert ISO strings to tokens.Foci may be manipulated singly or in groups called focus sets. A focus set is an OpenDoc object (of class
ODFocusSet
) listing a group of foci that a part editor wants to obtain or release as a group.Foci are owned by frames. In general, mouse events anywhere within the content area of an OpenDoc window always go to the most deeply embedded frame that encloses the click point. However, Shift-click and Command-click events, regardless of their location, are sent to the frame with the selection focus to allow for extending selections.
OpenDoc does not require that the same frame own the selection focus, keystroke focus, and menu focus, although this is most often the case. Also, OpenDoc does not require that the selection focus be in an active window, although this is usually the case, at least on the Mac OS platform.
In most cases, when a frame is activated the part editor for that frame requests the selection focus, keystroke focus, and menu focus. A frame with scroll bars might also request the scrolling focus. Your part editor might create a focus set ahead of time, perhaps during part initialization, that includes the tokenized names of the foci that your part expects to request when it becomes active. You use the arbitrator's
CreateFocusSet
method to create the focus set.A simple part, such as a small text-entry field in a dialog box, might request only the selection focus and keystroke focus on receiving a mouse-up event within its frame area. An even simpler part, such as a button, might not even request the selection focus. It might simply track the mouse until the button is released, and then run a script, never having changed the menu bar, put up palettes or rulers, or become active.
Your part editor can define additional focus types as needed. You can define other kinds of focus, perhaps to handle other kinds of user events (such as input from new kinds of devices). To create a new kind of focus, you need to create a new kind of focus module, the OpenDoc object that the arbitrator uses to determine focus ownership. Chapter 10, "Extending OpenDoc," describes how to use focus modules to extend OpenDoc's focus management.
Foci may be exclusive or nonexclusive. All of the standard foci defined by OpenDoc are exclusive, meaning that only one frame at a time can own a focus. But if you create a new kind of focus, you can make it nonexclusive, meaning that several frames could share ownership of it.
Arbitrating Focus Transfers
This section discusses how to request or relinquish foci to activate or deactivate your frames.Requesting Foci
A part can request, for one of its frames, ownership of a single focus or a set of foci. You request a focus by calling the arbitrator'sRequestFocus
method; you request a focus set by calling the arbitrator'sRequestFocusSet
method. If the request succeeds, your part's frame obtains the focus or focus set.The arbitrator's
RequestFocus
andRequestFocusSet
methods perform a two-stage transaction in transferring a focus or focus set:
- The arbitrator first asks the current owning frame of each focus if it is willing to relinquish the focus, by calling the
BeginRelinquishFocus
method of the frame's part.- If any owner of the focus is unwilling to relinquish it, the arbitrator cancels the request by calling each part's
AbortRelinquishFocus
method. In this case,RequestFocus
orRequestFocusSet
returns false.- If all focus owners are willing to relinquish, the arbitrator calls each part's
CommitRelinquishFocus
method. In this case,RequestFocus
orRequestFocusSet
returns true.
Relinquishing Foci
A part can relinquish foci either on request or when a change to its state (such as the closure of its frame or a completion of a method) warrants it. An active part might unilaterally relinquish certain foci (such as the clipboard focus) as soon as it is finished handling an event, but it might not relinquish other foci (such as the selection focus) until another part asks for them. Nevertheless, most parts willingly relinquish the common foci when asked.Relinquishing foci on request is a two-step process, because multiple foci requested as a focus set must all be provided to the requestor simultaneously; if one is not available, none need be relinquished. Your part editor participates in the process through calls to its
BeginRelinquishFocus
,CommitRelinquishFocus
, andAbortRelinquishFocus
methods.
Your part does not relinquish its focus on request only. For example, in your part's
- In your
BeginRelinquishFocus
method, you need do nothing other than returnkODTrue
orkODFalse
, basing your decision on the type of focus and the identities of the frames (current and proposed focus owners) passed to you. In most cases you can simply returnkODTrue
, unless your part is displaying a dialog box and another part is requesting the modal focus. In that case, because you do not want to yield the modal focus until your dialog box window closes, you returnkODFalse
. See "Acquiring and Relinquishing the Modal Focus" for more information.- Your part's
CommitRelinquishFocus
method verifies that you have actually relinquished the focus type you responded to inBeginRelinquishFocus
. The method should take appropriate action, such as removing menus or palettes, disabling menu items, removing highlighting, and performing whatever other tasks are part of losing that type of focus. Remember that the focus may possibly be moving from one frame to another of your part, so the exact actions can vary.- If, after your part responds with
kODTrue
toBeginRelinquishFocus
, the focus is actually not transferred from your frame, OpenDoc calls your part'sAbortRelinquishFocus
method. If your part has done anything more than return the Boolean result inBeginRelinquishFocus
, it can undo those effects in theAbortRelinquishFocus
method.- If your part is one of several focus owners called to relinquish the foci of a focus set, and if you return
kODFalse
toBeginRelinquishFocus
, yourCommitRelinquishFocus
method is not called (because you chose not to give up the focus). However, yourAbortRelinquishFocus
method is still called (because all owners of a focus set are notified if any one refuses to relinquish the focus).
DisplayFrameClosed
andDisplayFrameRemoved
methods, you should include a call to the arbitrator'sRelinquishFocus
orRelinquishFocusSet
method to unilaterally relinquish any foci owned by the frame that you are closing. When your part closes, itsReleaseAll
method should likewise relinquish all of its foci. When your part finishes displaying a modal dialog box, it should relinquish or transfer the modal focus; when your part finishes accessing the clipboard, it should relinquish the clipboard focus.Transferring Focus Without Negotiation
There are some situations in which the normal process of requesting and relinquishing foci is not used. Another piece of software interrupts your part's execution, and your part loses a focus without being given a chance to relinquish it, or gains focus without having asked for it. To handle those situations, your part editor must implement versions of the methodsFocusAcquired
andFocusLost
. The arbitrator calls these methods when your part has just acquired, or just lost, a specified focus without having negotiated the transaction.For example, a containing part, to support keyboard navigation, might call
FocusAcquired
in turn on each of its embedded parts as the user makes successive keystrokes. Or, if a custom input device with its own focus type were in use and then became detached, the part using the device might receive a call to itsFocusLost
method.These are the interfaces to
FocusAcquired
andFocusLost
:
void FocusAcquired(in ODTypeToken focus, in ODFrame ownerFrame); void FocusLost(in ODTypeToken focus, in ODFrame ownerFrame);YourFocusAcquired
andFocusLost
methods should perform any actions that your part editor deems appropriate in response to having just acquired or lost a focus.The arbitrator's methods
TransferFocus
andTransferFocusSet
allow you to initiate a transfer of focus ownership without negotiation. A part can use these calls to transfer focus among parts and frames that it controls directly. For example, in a modal dialog box consisting of several parts, these methods can be used to transfer a focus from the outer part (the dialog box) directly to an inner part (such as a text field) and back.When focus is transferred with
TransferFocus
orTransferFocusSet
, the arbitrator generally calls theFocusAcquired
method of the new frame's part and theFocusLost
method of the previous frame's part. However, when the frame performing the transfer (the frame representing the part that callsTransferFocus
) is the frame receiving or losing the focus, itsFocusAcquired
orFocusLost
method is not called.
- Calling your own
FocusAcquired
andFocusLost
- It might seem natural to call your own
FocusAcquired
method when your request for foci succeeds, or to call your ownFocusLost
method from your ownCommitRelinquishFocus
method. A better practice, however, is to have related methods call a shared private method, so that you maintain a clear separation between public and private interfaces.![]()
Recording Focus Transfers
Different frames may need different sets of foci when activated. Selection focus, keystroke focus, and menu focus are commonly needed together. However, a frame with scroll bars might also need the scrolling focus, and a frame for a modeless dialog box might not want the selection focus.OpenDoc does not save or restore focus assignments. Therefore, during deactivation of windows and frames, and during closing of windows, you can record the state of focus ownership so that you can restore it at a later activation or reopening. Your display frame's part info is an appropriate place to keep that information. Your part's initialization method might create a focus set with those foci, to use whenever your display frames become active.
On Frame Activation
When a previously inactive frame in a window becomes active, the part editors involved should--besides negotiating the focus transfer--record the gain or loss of selection focus for the respective frames. If you maintain that information, your activation and deactivation routines can check the state and exit quickly if no change in the active state is needed.
- If you are activating your part's frame, you might record, in a Boolean flag with a name such as
fHasRequiredFoci
in the frame's part info data, the fact that the frame has the selection focus. You can perform this action in yourFocusAcquired
method, after its call to the arbitrator'sRequestFocusSet
method succeeds.- If you are deactivating your part's frame, you might set the
fHasRequiredFoci
flag in the frame's part info data to false. You can perform this action in yourFocusLost
method and/or yourCommitRelinquishFocus
method.
On Window Activation
As mentioned in "Activate Events", all parts displayed in a window receive an activate event when the window becomes active, and a deactivate event when the window becomes inactive.When an active facet of a frame of your part becomes inactive through window deactivation, your part's
HandleEvent
method can--upon receiving the deactivate event--store a flag in the facet's part info field to note that the facet was active before window deactivation. Your part then can also maintain, as a background selection, any selection it had been displaying.Conversely, when a facet of a frame of your part receives an activate event because of window activation, your part's
HandleEvent
method can examine the state of the flag in the part info field to determine whether it was the active part when the window became inactive. If so, it should request the selection focus, reset the flag, and convert any background selection it may have maintained into a foreground selection.On Closing and Reopening Documents
Normally, the root part of a newly opened window should activate itself as a matter of course. However, if an embedded part had the selection focus when the window closed, the root part can--if it chooses to--allow the embedded part to recapture that focus when the window reopens.When the state of a window is saved in a document and the document is subsequently reopened, the root part recreates the window. If you want to restore the selection-focus state of your part (plus perhaps the selection itself), you can save the selection and the state of the selection-focus flag in your frame's part info data when the window is closed, and restore them when the window is opened (when your part's
DisplayFrameConnected
method is called).If your part is the root part in this situation, you can either grant the embedded part's request for the selection focus at this time, or you can acquire the selection focus yourself, when your own
DisplayFrameConnected
method is called. (The root part is called last.)
Main | Page One | What's New | Apple Computer, Inc. | Find It | Contact Us | Help