Important: The information in this document is obsolete and should not be used for new development.
Implementing Your Cyberdog Display Part Class
This section describes the steps you take to implement a Cyberdog display part class. You take the following steps to create your display part class:
The following sections describe the steps in more detail, using the text-viewer part,
- Define your Cyberdog part class.
- Set up the OpenDoc extension protocol to use your Cyberdog part extension subclass.
- Handle release of the part extension object.
- Initialize objects created in your display part class.
- Use Cyberdog's Document menu.
- Use window-position hints.
- Handle downloading of data.
- Determine the window in which to display the Cyberdog item.
- Handle closing the display part's window.
CybTxtViewer. The text-viewer part is based on the OpenDoc sample program,SamplePart. These sections assume that you are working with anODPartsubclass that has already been defined and whose methods have been overridden for some purpose, such as to display text. The chapter does not show, for example, how to implement drawing. For an example of defining an OpenDoc part subclass from theODPartclass, see the OpenDoc Cookbook. For more general information about programming with OpenDoc, see the OpenDoc Programmer's Guide.Modifying Your ODPart Subclass
You can start with your existing subclass ofODPartand modify it to support the Cyberdog part extension and to handle events that affect Cyberdog-related operations. To modify your part class so that it becomes a Cyberdog display part class, you should modify the class definition to include
Listing 4-6 shows the portion of the part class definition that defines both the new fields and methods and also the methods whose implementation must be modified.
- a pointer to the Cyberdog part extension object
- methods that initialize the Cyberdog display part object and its part extension object
- methods that set up the Cyberdog part extension
- methods that handle releasing the extension when the part is closed
Listing 4-6 The
CybTxtViewerclass definition
class CybTxtViewer { public: CybTxtViewer(); virtual ~CybTxtViewer(); ... // Modified to implement the Cyberdog part extension ODBoolean HasExtension(Environment* ev, ODType name); ODExtension* AcquireExtension(Environment* ev, ODType name); void ReleaseExtension(Environment* ev, ODExtension* extension); // Modified or added to release the part extension void ReleaseAll(Environment* ev); void ReleaseCyberPartExtension(Environment* ev); // Modified to handle closing windows ODBooleanHandleEvent (Environment* ev, ODEventData* event, ODFrame* frame, ODFacet* facet, ODEventInfo* eventInfo); ODBooleanHandleMenuEvent(Environment* ev, ODEventData* event, ODFrame* frame); // Modified to download a Cyberdog item's data void OpenCyberItem (Environment *ev, CyberItem* item, ODPart* openerPart, ParameterSet* openParams); void PollStream(Environment* ev); // Modified to reuse a Cyberdog item's window ODWindow* GetCyberItemWindow(Environment *ev, CyberItem* item); // Modified or added to support window-position hints ODID Open(Environment* ev, ODFrame* frame); ODWindow* CreateWindow (Environment* ev, ODFrame* frame, ODType frameType, WindowProperties* windowProperties, WindowPtr behindThisWindow = (WindowPtr) -1); WindowPtr GetBehindWindow(Environment* ev); WindowProperties* GetDefaultWindowProperties(Environment* ev, ODFrame* frame, Rect* windowRect, CDWindowPositionHint* windowPositionHint = nil); // Modified to support Cyberdog's document menu void CreateMenus(Environment* ev); void CheckMenus(Environment *ev, ODFrame* frame); protected: // Added to initialize Cyberdog and a part extension void Initialize(Environment* ev); private: // A reference to the Cyberdog part extension CyberSample_som_CybTxtViewerCyberExt*fCybTxtViewerCyberExt; Handle fDocMenu;// Cyberdog's Document menu CyberStream* fStream;// Cyberdog stream // The following fields are used with downloading: char* fChars; ODULong fCharsLength; ODULong fCharsAllocLength; }Listing 4-6 defines several fields that maintain references to the Cyberdog part extension (CyberSample_som_CybTxtViewerCyberExt), the Cyberdog Document menu (fDocMenu), and the Cyberdog stream (fStream) used to download the data. Other fields are used to manage the downloading operation. The constructor and theInitializemethod handle initialization of these fields, which are discussed in "Creating and Destroying the Display Part Object" (page 127).The HasExtension, AcquireExtension, and ReleaseExtension methods implement the OpenDoc extension protocol. They are discussed in "Implementing the OpenDoc Extension Protocol" (page 124). The ReleaseAll and ReleaseCyberPartExtension methods handle the release of the extension when the part is deleted. These methods are discussed in "Releasing the Part Extension" (page 126).
The
HandleEventmethod handles polling and the closing of the text-viewer part's window. TheHandleMenuEventmethod also handles the closing of the text-viewer part's window. The methodsOpenCyberItemandPollStreaminitiate downloading from the stream and manage the stream, respectively. For information about setting up a Cyberdog stream, see "Creating a Stream for Downloading" (page 135). For information about using a Cyberdog stream, see "Downloading From the Stream" (page 136). For information about closing the display part's window, see "Closing Your Display Part's Window" (page 140).The
OpenandCreateWindowmethods use window-position hints. These hints are manipulated by theGetBehindWindowand GetDefaultWindowProperties methods. For more information about using window-position hints, see "Using Window-Position Hints" (page 130).The
CreateMenusandCheckMenusmethods allow Cyberdog's Document menu to be displayed. For more information about Cyberdog's document menu, see "Supporting Cyberdog's Document Menu" (page 129).Implementing the OpenDoc Extension Protocol
To implement the extension protocol between your Cyberdog display part and your Cyberdog part extension, you override threeODPartmethods in your part class:
These are the same methods that you override to associate an extension with any OpenDoc part. For more information about extending an OpenDoc part, see the OpenDoc Programmer's Guide.
- Override the HasExtension method to return kODTrue if the part has an extension with the name kCyberPartExtension.
- Override the
AcquireExtensionmethod to return a reference to your Cyberdog part extension object.- Override the ReleaseExtension method to delete the Cyberdog part extension.
Listing 4-7 shows the HasExtension method for the text-viewer part. It returns kODTrue if the extension is kCyberPartExtension; otherwise, it returns kODFalse.
Listing 4-7 The text-viewer part's
HasExtensionmethod
ODBoolean CybTxtViewer::HasExtension(Environment* ev, ODType name) { ODBooleanresult = kODFalse; if (strcmp(name, kCyberPartExtension) == 0) result = kODTrue; return result; }Listing 4-8 shows theAcquireExtensionmethod for the text-viewerpart. It sets the fCybTxtViewerCyberExt field and acquires a reference to the extension.Listing 4-8 The text-viewer part's
AcquireExtensionmethod
ODExtension* CybTxtViewer::AcquireExtension(Environment* ev, ODType name) { ODExtension* extension = kODNULL; if (strcmp(name, kCyberPartExtension) == 0) { if (fCybTxtViewerCyberExt) { extension = (ODExtension*) fCybTxtViewerCyberExt; extension->Acquire(ev); } } return extension; }Listing 4-9 shows the ReleaseExtension method for the text-viewerpart. It deletes the reference to the extension, if it exists, and sets the fCybTxtViewerCyberExt field tokODNULL.Listing 4-9 The text-viewer part's
ReleaseExtensionmethod
void CybTxtViewer::ReleaseExtension(Environment* ev, ODExtension* extension) { if (extension == (ODExtension*) fCybTxtViewerCyberExt) { delete fCybTxtViewerCyberExt; fCybTxtViewerCyberExt = kODNULL; } }Releasing the Part Extension
When your display part is closed, OpenDoc calls the part'sReleaseAllmethod to release all resources that continue to be referenced by the part. You must make sure that your part'sReleaseAllmethod releases your Cyberdog part extension object. If your part is the only one that currently references the extension, you can delete the object; otherwise, you should release the part extension and call the extension's BaseRemoved method to notify the extension that the part no longer exists.Listing 4-10 shows only the portion of the text-viewer part's override of the
ReleaseAllmethod that relates to releasing the part extension. TheReleaseAllmethod calls the ReleaseCyberPartExtension method to do the actual work of releasing the part extension. It also deletes the stream if it exists.Listing 4-10 The text-viewer part's
ReleaseAllmethod
void CybTxtViewer::ReleaseAll( Environment* ev ) { ... ReleaseCyberPartExtension(ev); if (fStream) { delete fStream; fStream = kODNULL; } }The ReleaseCyberPartExtension method is defined by the CybTxtViewer class, not by theODPartclass. It exists to separate the work associated with releasing the Cyberdog part extension from the other work being performed (but not shown) in theReleaseAllmethod.Listing 4-11 shows the ReleaseCyberPartExtension method. It calls the part extension's Release method, which decrements the part extension's reference count. If the extension is in use by another part and has not been deleted as a result of calling Release, the
BaseRemovedmethod is called and the fCybTxtViewerCyberExt field is set to kODNULL.Listing 4-11 Releasing the text viewer's Cyberdog part extension
void CybTxtViewer::ReleaseCyberPartExtension(Environment* ev) { if (fCybTxtViewerCyberExt) { fCybTxtViewerCyberExt->Release(ev); // The part extension may not exist at this point. if(fCybTxtViewerCyberExt) { fCybTxtViewerCyberExt->BaseRemoved(ev); fCybTxtViewerCyberExt = kODNULL; } } }Creating and Destroying the Display Part Object
When a display part object is created, you must initialize its fields. Then the part must take these actions:
The constructor must set its fields to safe values, as shown in Listing 4-12.
- Call the
InitCyberdogfunction to initialize Cyberdog.- Create an object from your Cyberdog part extension subclass. The part must then take these two actions:
- Call its ICyberPartExtension method to initialize the extension.
- Establish a reference to your display part object in the Cyberdog part extension.
- Replace the OpenDoc Document menu with Cyberdog's Document menu.
Listing 4-12 The
CybTxtViewerconstructor
CybTxtViewer::CybTxtViewer() { ... fCybTxtViewerCyberExt = kODNULL; fStream = kODNULL; fDocMenu = kODNULL; fCharsLength = 0; fCharsAllocLength = 0; fChars = kODNULL; }You perform initialization in yourInitPartandInitPartFromStoragemethods. Listing 4-13 shows the text-viewer part'sInitializemethod, which is called from both theInitPartandInitPartFromStoragemethods (not shown). It initializes Cyberdog, creates and initializes the part extension.Listing 4-13 Initializing the Cyberdog environment
void CybTxtViewer::Initialize( Environment* ev ) { ... // Initialize Cyberdog. ODSession* session = ODGetSession(ev,fSelf); OSErr err = InitCyberdog(ev, session); ... // Create and initialize the Cyberdog part extension. fCybTxtViewerCyberExt = new Apple_som_CybTxtViewerCyberExt; if(fCybTxtViewerCyberExt != kODNULL) { fCybTxtViewerCyberExt->ICyberPartExtension(ev, fSelf); fCybTxtViewerCyberExt->SetBasePart(ev, this); } ... }The destructor must delete any data that has been left in memory and may also need to delete a stream if the display part was terminated while a download operation was in progress. It also must delete the Cyberdog Document menu. Listing 4-14 shows the destructor for the text-viewerpart.Listing 4-14 The
CybTxtViewerdestructor
CybTxtViewer::~CybTxtViewer() { // Delete downloaded data. if (fChars) ODDisposePtr(fChars); // Delete the stream. if (fStream) delete fStream; // Delete the Cyberdog document menu. if (fDocMenu != nil) DisposeHandle(fDocMenu); }Supporting Cyberdog's Document Menu
Your display part must replace OpenDoc's Document menu with Cyberdog's Document menu. You call the Cyberdog session's InstallCyberDocumentMenu method to install Cyberdog's Document menu. The Document menu is replaced only if the display part is in the Cyberdog session document.For example, the text-viewer part calls the InstallCyberDocumentMenu method from its
CreateMenusmethod whenever menus need to be created:
fDocMenu = GetCyberSession(ev)->InstallCyberDocumentMenu (ev, fSelf, fMenuBar);For information about creating menus, see "Displaying Cyberdog Menus" (page 105).When menus need to be recreated, or when the part is destroyed, you should dispose of the Document menu. The text-viewer part disposes the Document menu's handle from its destructor and before recreating menus in its
CheckMenusmethod:
if (fDocMenu != nil) { DisposeHandle(fDocMenu); fDocMenu = nil; }
- IMPORTANT
- Do not forget to install the Cyberdog Document menu. The OpenDoc Document menu contains items that are not applicable to a Cyberdog session document, such as the Delete menu item, whose use would have undesirable consequences.
![]()
Using Window-Position Hints
A window-position hint provides information to your display part about where to open its window. It specifies the window to be in front of your part's window and the coordinates specifying where to place your part's window.A window-position hint may have been written to the storage unit by an opener part before your display part is opened. For example, the user may start an operation involving your part, such as a download operation, and then activate a different window or open a modal dialog box. When the first operation finishes your part should use the window-position hint instead of opening its window in front of the user's active window.
On opening, your Cyberdog display part should use a window-position hint to place a part's window at the specified position on the screen and behind the specified window. You must read the
CDWindowPositionHintdata structure from storage when opening your display part. You then use the hint when you create the window.Listing 4-15 shows the text-viewer part's
Openmethod, which calls the CDGetWindowPositionHint function to retrieve a window-position hint from the storage unit. TheOpenmethod then calls the GetBehindWindow method to determine which window to open the text-viewer's window behind. It then calls the GetDefaultWindowProperties, which uses the position hint. Finally, it calls theCreateWindowmethod to create the window using the hint.Listing 4-15 The text-viewer part's
Openmethod
ODID CybTxtViewer::Open(Environment* ev, ODFrame* frame) { ODID windowID; TempODWindow window(kODNULL); WindowProperties* windowProperties = kODNULL; ODVolatile(windowProperties); WindowPtr behindThisWindow = (WindowPtr)-1; TRY if ( frame == kODNULL ) { CDWindowPositionHint windowPositionHint; CDWindowPositionHint* windowPositionHintPtr; // Retreive the window-position hint from the storage unit. if (CDGetWindowPositionHint(ev, GetODPart(ev)->GetStorageUnit(ev), &windowPositionHint)) windowPositionHintPtr = &windowPositionHint; // Found else windowPositionHintPtr = nil; // No hint in storage unit // Deterimine the window layer to open in. behindThisWindow = GetBehindWindow (ev, windowPositionHintPtr); // Calculate the bounding rectangle for a new window. Rect windowRect = this->CalcPartWindowSize(ev, kODNULL); // Get the default settings for a document window. windowProperties = this->GetDefaultWindowProperties(ev, kODNULL, &windowRect, windowPositionHintPtr); // Create a window and register it with OpenDoc. window = this->CreateWindow(ev, kODNULL, kODFrameObject, windowProperties, behindThisWindow); } ... // Create the window's root facet. window->Open(ev); // Make the window visible. window->Show(ev); // Activate and select the window if it is in front. if (behindThisWindow == (WindowPtr)-1) window->Select(ev); ... windowID = (window ? window->GetID(ev) : kODNULLID); CATCH_ALL ... RERAISE; ENDTRY return windowID; }Listing 4-16 shows the text-viewer part's CDGetWindowPositionHint method, which reads the window-position hint from the storage unit.Listing 4-16 Reading the window-position hint from storage
ODBoolean CDGetWindowPositionHint(Environment* ev, ODStorageUnit* su, CDWindowPositionHint *windowPositionHint) { if (ODSUExistsThenFocus(ev, su, kCDWindowPositionHintProperty, kCDWindowPositionHintValue)) { StorageUnitGetValue(su, ev, sizeof(CDWindowPositionHint), (ODValue)windowPositionHint); return kODTrue; } else return kODFalse; }The text-viewer part's GetBehindWindow method, shown in Listing 4-17, returns the window to open behind, which is the window specified in the window-position hint, if available. Otherwise, the method ensures that the window appears behind any modal windows.Listing 4-17 Using the window-position layer hint
WindowPtr CybTxtViewer::GetBehindWindow(Environment* ev, CDWindowPositionHint* windowPositionHint) { WindowPtr window = nil; // Get the window indicated in the window-position hint. if (windowPositionHint) { window = windowPositionHint->behindWindow; } else // If no hint, make sure the window goes behind any modal windows. { // Find last modal window in the window list. WindowPtr aWindow = FrontWindow(); while (aWindow && WindowIsModal(aWindow)) { window = aWindow; aWindow = (WindowPtr) GetNextWindow(aWindow); } } if (!window) // No hint or modal dialog box; open in front window = (WindowPtr) -1; return window; }Listing 4-18 shows the text-viewer part's GetDefaultWindowProperties method, which uses the window-position coordinates to position the window.Listing 4-18 Using the window-position coordinate hint
WindowProperties* CybTxtViewer::GetDefaultWindowProperties(Environment* ev, ODFrame* sourceFrame, Rect* windowRect, CDWindowPositionHint* windowPositionHint) { WindowProperties* windowProperties = new WindowProperties; TRY // Position the window if ( sourceFrame ) // Use the source frame if one exists. this->CalcPartWindowPosition(ev, sourceFrame, windowRect); else if ( windowPositionHint ) // Otherwise, use the window-position hint, if one exists. OffsetRect (windowRect, windowPositionHint->windowPosition.h, windowPositionHint->windowPosition.v); else // If none, place the window at the top left of the desktop. OffsetRect(windowRect, kALittleNudge, GetMBarHeight() + kMacWindowTitleBarHeight); ... CATCH_ALL ODDeleteObject(windowProperties); RERAISE; ENDTRY return windowProperties; }The window layer (behindThisWindow) and coordinates (in windowProperties) are used when creating the window, as shown in the following call to theNewCWindowfunction from theCreateWindowmethod (not shown):
platformWindow = NewCWindow((Ptr)ODNewPtr(sizeof(WindowRecord)), &(windowProperties->boundsRect), windowProperties->title, kODFalse, /* visible */ windowProperties->procID, behindThisWindow, windowProperties->hasCloseBox, windowProperties->refCon);Creating a Stream for Downloading
When a Cyberdog item is opened, Cyberdog calls your part extension'sOpenCyberItemmethod. This is the most convenient place for you to specify tasks that need to be performed in conjunction with opening the Cyberdog item.In the case of the text-viewer sample, the part extension's
OpenCyberItemmethod--see Listing 4-4 (page 119)--calls the text viewer part'sOpenCyberItemmethod to do the work of creating a stream and to use it for downloading data. The text-viewer part'sOpenCyberItemmethod also registers the item in the log. Listing 4-19 shows the text-viewer part's method.Listing 4-19 The
OpenCyberItemmethod of the text-viewer part
void CybTxtViewer::OpenCyberItem(Environment *ev, CyberItem* item, ODPart* openerPart, ParameterSet* openParams) { // Create a stream for the download operation. fStream = item->CreateCyberStream(ev); // Open the stream, which starts the download operation. fStream->Open(ev); // Get the Cyberdog item's parent for the log. CyberItem* parent = kODNULL; if(openParams) openParams->GetParameter(ev, kCDParentItemKey, &parent); // Add the Cyberdog item to the log. GetCyberSession(ev)->AddCyberItemToLog(ev, parent, item); }The method creates the Cyberdog stream by calling the Cyberdog item's CreateCyberStream method. It then calls the stream'sOpenmethod to initiate downloading. Finally, it calls the session's AddCyberItemToLog method to add the item to the log.Downloading From the Stream
When downloading, you must periodically check whether the stream contains any data and, if so, display the data. You can, for example, check the status of downloading from the stream during idle time. You should try not to do too much work during idle time; otherwise, the system will be perceived as unresponsive. You must balance the work so as to avoid this perception yet obtain enough data from the stream on each poll to complete the download operation in a reasonable time. You take these steps to manipulate the stream:
Listing 4-20 shows the text-viewer part's
- Call the stream's GetStreamStatus method to determine whether new data has arrived.
- When data is present, call the stream's
GetBuffermethod to obtain the data.- Copy the data to your display part's storage.
- Call the stream's
ReleaseBuffermethod to release the buffer after the data has been copied.- Repeat steps 1 through 4 until enough data has been copied or until there is no more data to download.
- Draw the data; for example, by notifying OpenDoc that the data needs to be drawn or by drawing it yourself.
- When the download operation is complete, delete the stream.
HandleEventmethod. It calls thePollStreammethod when a null event is received.Listing 4-20 The text-viewer part's
HandleEventmethod
ODBoolean CybTxtViewer::HandleEvent( Environment*ev, ODEventData*event, ODFrame* frame, ODFacet* facet, ODEventInfo*eventInfo ) { ODBooleaneventHandled = kODFalse; switch ( event->what ) { ... case kODEvtNull: if (fStream) PollStream(ev); break; ... default: break; } return eventHandled; }ThePollStreammethod does the work associated with managing the stream. It checks whether any data is available to download from the stream. If so, thePollStreammethod copies the data into a buffer and invalidates the screen so that OpenDoc displays the data when the screen is redrawn. When downloading ends or an error occurs, the stream is deleted. Listing 4-21 shows these actions.Listing 4-21 Handling downloaded data
void CybTxtViewer::PollStream(Environment* ev) { StreamStatus status; ODBoolean gotData = kODFalse; Size bytesThisPoll = 0; if (fStream == kODNULL) return; while (bytesThisPoll < kBytesPerPoll) { status = fStream->GetStreamStatus(ev); // Exit the loop if no data is available. if (!(status & kCDDataAvailable)) break; // Data is available. Get the buffer; copy it to the data area. char* buffer; Size size; fStream->GetBuffer(ev, &buffer, &size); if (buffer) { Size newLength = fCharsLength + size; if (newLength > fCharsAllocLength) newLength = fCharsAllocLength; if (newLength > fCharsLength) { ODBlockMove(buffer, fChars+fCharsLength, newLength - fCharsLength); fCharsLength = newLength; } gotData = kODTrue; bytesThisPoll += size; fStream->ReleaseBuffer(ev, buffer); } } // Check status. status = fStream->GetStreamStatus(ev); // Downloading is complete or an error occurred. if ((status & kCDDownloadComplete) || (status & kCDErrorOccurred) || (status & kCDAbortComplete)) { delete fStream; fStream = kODNULL; } if (gotData) ForceRedraw(ev); }During each call toPollStream, at most kBytesPerPoll (defined as 8,192 bytes) is copied from the stream into thefcharsdata structure. The text-viewer part defines the kBytesPerPoll constant, not Cyberdog.The ForceRedraw method is simply a method that invalidates the area in which the data in the
fcharsstructure is to be displayed. OpenDoc redraws the invalidated area in the usual way.Locating the Cyberdog Item's Window
Cyberdog calls the part extension's GetCyberItemWindow method to locate a window that currently displays the specified Cyberdog item. If you do not override this method, the default GetCyberItemWindow method returns kODNULL and Cyberdog opens a new window in which to display the Cyberdog item's data. Your override can return a window that already displays the Cyberdog item's data. In this case, the window you return will be opened when the Cyberdog item is opened.In this example, the text-viewer part extension's GetCyberItemWindow method calls the text-viewer part's GetCyberItemWindow method to do the actual work. See "Overriding Cyberdog Part Extension Methods" (page 119) for information about the part extension's GetCyberItemWindow method.
Listing 4-22 shows the text-viewer part's GetCyberItemWindow method. The method returns a reference to a window if the window is already displaying the same Cyberdog item. The Cyberdog part extension's CanShowCyberItem method returns whether or not the Cyberdog item is displayed. If the Cyberdog item to be opened is not currently displayed, the method returns kODNULL. In response, Cyberdog opens a new window for the item.
Listing 4-22 The
GetCyberItemWindowmethod of the text-viewer part
ODWindow* CybTxtViewer::GetCyberItemWindow (Environment *ev, CyberItem* item) { ODWindow* window = kODNULL; // Determine whether the part already displays the specified // Cyberdog item. if ( fCybTxtViewerCyberExt->CanShowCyberItem(ev, item) ) { // Iterate over the list of frames, looking for a root frame. // If a root frame is found, return its window. if(fDisplayFrames) { CListIterator fiter(fDisplayFrames); for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First(); fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() ) { if ( proxy->FrameIsLoaded(ev) ) { ODFrame* odFrame = proxy->GetFrame(ev); if(odFrame->IsRoot(ev)) { TempODWindow window = odFrame->AcquireWindow(ev); return window; } } } } } return kODNULL; }Closing Your Display Part's Window
When a user attempts to close a display part's window, your part must intercept this command and allow Cyberdog to close the window. This action is necessary because OpenDoc normally closes the Cyberdog session document when it closes the last open window and, thus, would require a new Cyberdog session document to be created the next time Cyberdog is used. Allowing Cyberdog to close the window avoids creating unnecessary sessions and session documents.Take these steps to close your part's window:
In the text-viewer part, two methods handle the closing of the part's window. The HandleEvent method closes the window after a click in the window's close box. The HandleMenuEvent method closes the window in response to a Close command. Both methods close the window in the same way.
- Obtain a reference to the Cyberdog session by calling the GetCyberSession function.
- Close the window by calling the Cyberdog session's CloseCyberDraftWindow method. The parameter to the CloseCyberDraftWindow method is a pointer to your part.
- Close the window in the normal way if the CloseCyberDraftWindow method returns kODFalse, indicating that the window was not in the Cyberdog session document.
Listing 4-23 shows the HandleEvent method.
Listing 4-23 The
HandleEventmethod of the text-viewer part
ODBoolean CybTxtViewer::HandleEvent( Environment*ev, ODEventData*event, ODFrame* frame, ODFacet* facet, ODEventInfo*eventInfo ) { ODBooleaneventHandled = kODFalse; switch ( event->what ) { ... case kODEvtWindow: if (event->message == inGoAway) { eventHandled = GetCyberSession(ev)->CloseCyberDraftWindow(ev, fSelf); } break; ... default: break; } return eventHandled; }Listing 4-24 shows the HandleMenuEvent method, which closes the window in response to a menu event.Listing 4-24 The
HandleMenuEventmethod of the text-viewer part
ODBoolean CybTxtViewer::HandleMenuEvent( Environment*ev, ODEventData*event, ODFrame* frame ) { ODULong menuResult = event->message; ODUShort menu = HiWord(menuResult); ODUShort item = LoWord(menuResult); ODBooleanhandled = kODTrue; ODULongcommandID; ... switch (commandID) ) { ... case kODCommandClose: handled = GetCyberSession(ev)->CloseCyberDraftWindow(ev, fSelf); break; ... default: handled = kODFalse; } return handled; }