Legacy Documentclose button

Important: The information in this document is obsolete and should not be used for new development.

Previous Book Contents Book Index Next

Inside Macintosh: Cyberdog Programmer's Kit / Part 2 - Programming in Cyberdog
Chapter 4 - Creating a Cyberdog Display Part


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, CybTxtViewer. The text-viewer part is based on the OpenDoc sample program, SamplePart. These sections assume that you are working with an ODPart subclass 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 the ODPart class, 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 of ODPart and 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.

Listing 4-6 The CybTxtViewer class 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 the Initialize method 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 HandleEvent method handles polling and the closing of the text-viewer part's window. The HandleMenuEvent method also handles the closing of the text-viewer part's window. The methods OpenCyberItem and PollStream initiate 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 Open and CreateWindow methods use window-position hints. These hints are manipulated by the GetBehindWindow and GetDefaultWindowProperties methods. For more information about using window-position hints, see "Using Window-Position Hints" (page 130).

The CreateMenus and CheckMenus methods 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 three ODPart methods 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.

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 HasExtension method

ODBoolean CybTxtViewer::HasExtension(Environment* ev, ODType name)
{
   ODBooleanresult = kODFalse;
      
   if (strcmp(name, kCyberPartExtension) == 0)
      result = kODTrue;
   return result;
}
Listing 4-8 shows the AcquireExtension method for the text-viewer part. It sets the fCybTxtViewerCyberExt field and acquires a reference to the extension.

Listing 4-8 The text-viewer part's AcquireExtension method

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-viewer part. It deletes the reference to the extension, if it exists, and sets the fCybTxtViewerCyberExt field to kODNULL.

Listing 4-9 The text-viewer part's ReleaseExtension method

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's ReleaseAll method to release all resources that continue to be referenced by the part. You must make sure that your part's ReleaseAll method 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 ReleaseAll method that relates to releasing the part extension. The ReleaseAll method 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 ReleaseAll method

void CybTxtViewer::ReleaseAll( Environment* ev )
{
   ...
   ReleaseCyberPartExtension(ev);
   if (fStream)
   {
      delete fStream;
      fStream = kODNULL;
   }
}
The ReleaseCyberPartExtension method is defined by the CybTxtViewer class, not by the ODPart class. It exists to separate the work associated with releasing the Cyberdog part extension from the other work being performed (but not shown) in the ReleaseAll method.

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 BaseRemoved method 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.

Listing 4-12 The CybTxtViewer constructor

CybTxtViewer::CybTxtViewer()
{
   ...
   fCybTxtViewerCyberExt = kODNULL;
   fStream = kODNULL;
   fDocMenu = kODNULL;
   fCharsLength = 0;
   fCharsAllocLength = 0;
   fChars = kODNULL;
}
You perform initialization in your InitPart and InitPartFromStorage methods. Listing 4-13 shows the text-viewer part's Initialize method, which is called from both the InitPart and InitPartFromStorage methods (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-viewer part.

Listing 4-14 The CybTxtViewer destructor

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 CreateMenus method 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 CheckMenus method:

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 CDWindowPositionHint data 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 Open method, which calls the CDGetWindowPositionHint function to retrieve a window-position hint from the storage unit. The Open method 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 the CreateWindow method to create the window using the hint.

Listing 4-15 The text-viewer part's Open method

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 the NewCWindow function from the CreateWindow method (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's OpenCyberItem method. 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 OpenCyberItem method--see Listing 4-4 (page 119)--calls the text viewer part's OpenCyberItem method to do the work of creating a stream and to use it for downloading data. The text-viewer part's OpenCyberItem method also registers the item in the log. Listing 4-19 shows the text-viewer part's method.

Listing 4-19 The OpenCyberItem method 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's Open method 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:

  1. Call the stream's GetStreamStatus method to determine whether new data has arrived.
  2. When data is present, call the stream's GetBuffer method to obtain the data.
  3. Copy the data to your display part's storage.
  4. Call the stream's ReleaseBuffer method to release the buffer after the data has been copied.
  5. Repeat steps 1 through 4 until enough data has been copied or until there is no more data to download.
  6. Draw the data; for example, by notifying OpenDoc that the data needs to be drawn or by drawing it yourself.
  7. When the download operation is complete, delete the stream.

Listing 4-20 shows the text-viewer part's HandleEvent method. It calls the PollStream method when a null event is received.

Listing 4-20 The text-viewer part's HandleEvent method

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;
}
The PollStream method does the work associated with managing the stream. It checks whether any data is available to download from the stream. If so, the PollStream method 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 to PollStream, at most kBytesPerPoll (defined as 8,192 bytes) is copied from the stream into the fchars data 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 fchars structure 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 GetCyberItemWindow method 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.

Listing 4-23 shows the HandleEvent method.

Listing 4-23 The HandleEvent method 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 HandleMenuEvent method 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;
}

Previous Book Contents Book Index Next

© Apple Computer, Inc.
13 JUL 1996