Windows.c

/*
    File:       Windows.c
 
    Contains:   Handle application's windows
 
    Written by: Chris White 
 
    Copyright:  Copyright © 1995-1999 by Apple Computer, Inc., All Rights Reserved.
 
                You may incorporate this Apple sample source code into your program(s) without
                restriction. This Apple sample source code has been provided "AS IS" and the
                responsibility for its operation is yours. You are not permitted to redistribute
                this Apple sample source code as "Apple sample source code" after having made
                changes. If you're going to re-distribute the source, we require that you make
                it clear in the source that the code was descended from Apple sample source
                code, but that you've made changes.
 
    Change History (most recent first):
                8/5/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
                
 
*/
#include <Types.h>
#include <Quickdraw.h>
#include <QDOffscreen.h>
#include <Devices.h>
#include <LowMem.h> /* For MemError() */
#include <Script.h>
#include <TextUtils.h>
#include <Dialogs.h>
#include <Folders.h>
#include <stddef.h>
#include <Sound.h>
 
#include <CodeFragments.h>
#include <StandardFile.h>
#include <Folders.h>
 
#include "FragmentTool.h"
#include "FragmentStuff.h"
#include "Dialogs.h"
#include "Streams.h"
#include "Utilities.h"
 
#include "Prototypes.h"
 
 
static OSErr CreateContentList ( WindowRef theWindow, tContentsProcPtr contentsProc, void* refCon );
static void AddContentsToList ( WindowRef theWindow );
static void DoDialogItemHit ( DialogRef theDialog, int16 theItem );
static int8 GetStageFromItem ( int16 theItem );
static int16 GetItemFromStage ( int8 theStage );
 
static OSErr CreateTempAndCopyFragment ( tHeaderHan sourceHeader, FSSpecPtr sourceSpec, int16 sourceIndex,
                                        tHeaderHan targetHeader );
 
 
 
 
void DoNewDocument ( void )
{
    OSErr           theErr;
    int16           theRef;
    int16           theVol;
    int32           theDir;
    FSSpec          theSpec;
    Str255          tmpStr = "\p";
    Str255          theFile = "\pFragmentTool ";
    hdrHand         theHeader;
    Size            headerSize;
    
    
    theErr = FindFolder ( kOnSystemDisk, kTemporaryFolderType, kCreateFolder, &theVol, &theDir );
    OSTypeToPStr ( TickCount ( ), tmpStr );
    ConcatPStr ( theFile, tmpStr, sizeof ( Str255 ) );
    theErr = FSMakeFSSpec ( theVol, theDir, theFile, &theSpec );
    theErr = FSpCreate ( &theSpec, kFourQuestionMarks, kCFragLibraryFileType, smSystemScript );
    
 
    // The file has been created with both forks, but it doesn't have a
    // resource map yet. If we try to open it now, we'll get an eofErr (-39).
    FSpCreateResFile ( &theSpec, kFourQuestionMarks, kCFragLibraryFileType, smSystemScript );
    theRef = FSpOpenResFile ( &theSpec, fsRdWrPerm );
    if ( theRef == -1 )
    {
        theErr = ResError ( );
        AlertUser ( kGenericErrorStr, theErr, nil );
        return;
    }
    
    headerSize = offsetof ( cfrgHeader, arrayStart );
    theHeader = (hdrHand) NewHandleClear ( headerSize );
    (*theHeader)->version = 1;      // Current version number
    AddResource ( (Handle) theHeader, kCFragResourceType, kCFragResourceID, "\p" );
    CloseResFile ( theRef );
    
    GetIndString ( tmpStr, 1000, 4 );               // Default document name
    theErr = OpenDocument ( &theSpec, tmpStr );
    if ( theErr )
    {
        AlertUser ( kGenericErrorStr, theErr, nil );
        return;
    }
    
    return;
    
}
 
 
 
void DoOpenDocument ( void )
{
    OSErr               theErr;
    StandardFileReply   theReply;
    
    
    StandardGetFile ( nil, -1, nil, &theReply );
    if ( theReply.sfGood )
    {
        theErr = OpenDocument ( &theReply.sfFile, nil );
        
        if ( theErr )
            AlertUser ( kGenericErrorStr, theErr, nil );
    }
    
    return;
}
 
 
 
OSErr OpenDocument ( FSSpecPtr fileSpec, StringPtr documentName )
{
    OSErr               theErr;
    int16               theFileRef, saveFile;
    WindowRef           theWindow;
    tWindowInfoPtr      theInfo;
    tAddFragmentsRec    theRec;
    Str255              theTitle;
    
    if ( documentName )
        CopyPStr ( documentName, theTitle, sizeof ( Str255 ) );
    else
        CopyPStr ( fileSpec->name, theTitle, sizeof ( Str255 ) );
    
    saveFile = CurResFile ( );
    SetResLoad ( false );
    theFileRef = FSpOpenResFile ( fileSpec, fsRdPerm );
    SetResLoad ( true );
    UseResFile ( saveFile );
    if ( theFileRef == -1 )
        return ResError ( );
    
    theRec.u.out.theFileRef = theFileRef;
    theErr = CreateDocumentWindow ( &theWindow, theTitle, AddFragments, (void*) &theRec );
    if ( theErr )
        return theErr;
    
    theInfo = (tWindowInfoPtr) GetWRefCon ( theWindow );
    theInfo->bUntitled = (documentName) ? true : false;
    theInfo->dataHandle = theRec.u.in.theDataHandle;
    BlockMoveData ( fileSpec, &theInfo->fileSpec, sizeof ( FSSpec ) );
    
    return theErr;
}
 
 
 
OSErr CreateDocumentWindow ( WindowRef* windowRef, Str255 windowTitle,
                                tContentsProcPtr contentsProc, void* refCon )
{
    OSErr       theErr;
    WindowRef   theWindow;
    
    
    theWindow = GetNewCWindow ( kDisplayWindow, nil, (WindowRef) -1L );
    if ( theWindow == nil )
        return (ResError ( )) ? ResError ( ) : resNotFound;
    
    theErr = CreateWindowInfo ( theWindow, sizeof ( tWindowInfo ) );
    if ( theErr )   goto CleanupAndBail;
    
    theErr = CreateContentList ( theWindow, contentsProc, refCon );
    if ( theErr )   goto CleanupAndBail;
    
    
    // Since the application can function without the Drag Manager, an
    // error here is not considered fatal.
    theErr = InstallDragHandlers ( theWindow );
    
    SetWindowType ( theWindow, kDocumentWindowType );
    SetPortWindowPort ( theWindow );
    TextFont ( kFontIDGeneva );
    TextFace ( normal );
    TextSize ( 9 );
    
    SetWTitle ( theWindow, windowTitle );
    SelectWindow ( theWindow );
    ShowWindow ( theWindow );
    
    *windowRef = theWindow;
    
    return noErr;
    
 
CleanupAndBail:
    
    // Don't forget to free any storage we've used so far
    DestroyDocumentWindow ( theWindow );
    
    return theErr;
}
 
 
 
//
// This will close the document's file, dispose of any storage we've hung
// off the window, remove any drag handlers, and then dispose of the window.
//
WindowRef DestroyDocumentWindow ( WindowRef windowRef )
{
    if ( windowRef )
    {
        tWindowInfoPtr theInfo;
        
        theInfo = (tWindowInfoPtr) GetWRefCon ( windowRef );
        if ( theInfo )
        {
            if ( theInfo->listRef )
                LDispose ( theInfo->listRef );
            
            if ( theInfo->dataHandle )
                DisposeHandle ( theInfo->dataHandle );
 
            DisposePtr ( (Ptr) theInfo );
        }
        
        RemoveDragHandlers ( windowRef );
        DisposeWindow ( windowRef );
        
    }
    
    // Return nil so it can be assigned to the window
    // reference which was passed in
    return nil;
}
 
 
 
////////////////////////////////////////////////////////////////////////////////////
 
 
 
//
// Draw *only* the grow icon
//
void DrawClippedGrowIcon ( WindowRef theWindow )
{
    Rect        portRect = theWindow->portRect;
    RgnHandle   oldClip = NULL;
    Rect        newClip;
    
    
    SetPort ( theWindow );
    oldClip = NewRgn ( );
    GetClip ( oldClip );
    
    newClip = portRect;
    newClip.top = newClip.bottom - 15;
    newClip.left = newClip.right - 15;
    ClipRect ( &newClip );
    DrawGrowIcon ( theWindow );
    
    SetClip ( oldClip );
    DisposeRgn ( oldClip );
    
    return;
}
 
 
 
 
//
// This is passed into the CreateDocumentWindow routine
// to add the contents to the newly created list.
//
OSErr AddFragments ( ListRef theList, void* refCon )
{
    OSErr               theErr;
    int16               theFileRef, saveFile;
    int                 index, itemCount;
    Handle              resourceScratch;
    tHeaderHan          parsedResource;
    tAddFragmentsRec*   theRec;
    
    
    
    
    theRec = (tAddFragmentsRec*) refCon;
    theFileRef = theRec->u.out.theFileRef;
    
    parsedResource = (tHeaderHan) NewHandleClear ( sizeof ( tHeader ) );
    theErr = MemError ( );
    if ( theErr )
        return theErr;
    
    saveFile = CurResFile ( );
    UseResFile ( theFileRef );
    resourceScratch = Get1Resource ( kCFragResourceType, kCFragResourceID );
    theErr = ResError ( );
    if ( theErr || resourceScratch == nil)
        return (theErr) ? theErr : resNotFound;
    UseResFile ( saveFile );
    
    
    if ( parsedResource )
    {
        ParseResource ( resourceScratch, parsedResource );
        
        itemCount = (*parsedResource)->itemCount;
        for ( index = 0; index < itemCount; index++ )
        {
            tItemPtr    dstItem;
            
            dstItem = &(*parsedResource)->itemList[index];
            AddFragToList ( theList, dstItem );
            
        }
        
        
        theRec->u.in.theDataHandle = (Handle) parsedResource;
    }
    
    ReleaseResource ( resourceScratch );
        
    return noErr;
    
} // AddFragments
 
 
 
//
// This returns the Nth document window, ignoring the front-most
//
WindowRef GetIndexedDocumentWindow ( int theIndex )
{
    Boolean     bFirst = true;
    int         thisIndex = 0;      // Must be zero-based, like the List Manager
    WindowRef   currWindow;
    
    
    currWindow = FrontWindow ( );
    while ( currWindow )
    {
        if ( GetWindowType ( currWindow ) == kDocumentWindowType )
        {
            // Skip the front-most document since that's the source document
            if ( bFirst )
                bFirst = false;
            else
            {
                if ( thisIndex == theIndex )
                    return currWindow;
                
                thisIndex++;
            }
        }
        
        currWindow = GetNextWindow ( currWindow );
    }
    
    return nil;
}
 
 
 
//
// Creates the storage for the data to hang off a window or dialog
//
OSErr CreateWindowInfo ( WindowRef windowRef, Size infoSize )
{
    OSErr   theErr;
    Ptr     theInfo = nil;
    
    
    theInfo = NewPtrClear ( infoSize );
    theErr = MemError ( );
    if ( theErr )
        return theErr;
    
    SetWRefCon ( windowRef, (long) theInfo );
    
    return noErr;
}
 
 
 
//
// Closes all the open documents. Called just before a quit, or as
// the result of an option click in a windows go away box.
//
Boolean DoCloseAllDocuments ( void )
{
    Boolean     bCancelled = false;
    WindowRef   aWindow;
    
    aWindow = FrontWindow ( );
    while ( aWindow && !bCancelled )
    {
        bCancelled = DoCloseDocument ( aWindow );
        aWindow = GetNextWindow ( aWindow );
    }
    
    return bCancelled;
}
 
 
 
Boolean DoCloseDocument ( WindowRef theWindow )
{
    int16   windowType;
    
    if ( theWindow )
    {
        windowType = GetWindowType ( theWindow );
        if ( windowType == kDAWindowType )
            CloseDeskAcc ( GetWindowKind ( theWindow ) );
        else if ( windowType == kDocumentWindowType )
        {
            int             i;
            tWindowInfoPtr  theInfo;
            tHeaderHan      theHeader;
            tItemPtr        anItem;
            
            
            // Check for any fragments that have temp files
            theInfo = (tWindowInfoPtr) GetWRefCon ( theWindow );
            if ( theInfo->bDirty )
                if ( DoSaveBeforeClosing ( theWindow ) ) // Did the user cancel?
                    return kCancelled;
                    
            theHeader = (tHeaderHan) theInfo->dataHandle;
            HLock ( (Handle) theHeader );
            for ( i = 0; i < GetItemCount ( theHeader ); i++ )
            {
                anItem = GetNthItem ( theHeader, i );
                if ( anItem == nil )
                    break;
                
                DecrementTempUsageCount ( anItem );
            }
            HUnlock ( (Handle) theHeader );
 
            DestroyDocumentWindow ( theWindow );
        }   
        else if ( windowType == kListWindowType )
            DestroyDialog ( theWindow );
            
        AdjustMenus ( );
    }
    
    return kNotCancelled;
    
} // CloseDocument
 
 
 
Boolean DoSaveBeforeClosing ( WindowRef theWindow )
{
    int16       theItem;
    DialogRef   theDialog;
    WindowRef   dialogWindow;
    Str255      theTitle, theReason;
    
    
    theDialog = GetNewDialog ( kSaveDontsaveDialog, nil, (WindowRef) -1 );
    dialogWindow = GetDialogWindow ( theDialog );
    SetPortWindowPort ( dialogWindow );
    
    GetWTitle ( theWindow, theTitle );
    if ( gQuit )
        GetIndString ( theReason, 1000, 6 );
    else
        GetIndString ( theReason, 1000, 7 );
    ParamText ( theTitle, theReason, nil, nil );
    ShowWindow ( dialogWindow );
    SelectWindow ( dialogWindow );
    
    SetDialogDefaultItem ( theDialog, kStdOkItemIndex );
    SetDialogCancelItem ( theDialog, kStdCancelItemIndex );
    
    
    // As long as the only enabled items are the dimissers, 
    // there is no need to call ModalDialog within a loop.
    ModalDialog ( nil, &theItem );
    DisposeDialog ( theDialog );
    
    if ( theItem == kStdOkItemIndex )
        return DoSave ( theWindow );
    
    return theItem == kStdCancelItemIndex;
}       
 
 
 
Boolean DoSave ( WindowRef theWindow )
{
    int16           saveFile, theFileRef;
    int             i;
    OSErr           theErr;
    Handle          resourceScratch;
    tWindowInfoPtr  theInfo;
    tHeaderHan      theHeader;
    tItemPtr        anItem;
    
    theInfo = (tWindowInfoPtr) GetWRefCon ( theWindow );
    #if DEBUGGING
    if ( theInfo == nil ) DebugStr ( "\p theInfo == nil" );
    #endif
    
    if ( theInfo->bUntitled )
        return DoSaveAs ( theWindow );
    
    // Check for any fragments that have been deleted...
    theHeader = (tHeaderHan) theInfo->dataHandle;
    HLock ( (Handle) theHeader );
    for ( i = 0; i < GetItemCount ( theHeader ); i++ )
    {
        anItem = GetNthItem ( theHeader, i );
        if ( anItem->bDeleted )
        {
            if ( anItem->bExistsInDocument )
            {
                theErr = DeleteFragment ( theHeader, &theInfo->fileSpec, i );
                if ( theErr )
                {
                    AlertUser ( kGenericErrorStr, theErr, nil );
                    return kNotCancelled;
                }
                anItem->bExistsInDocument = false;
            }
            
            DecrementTempUsageCount ( anItem );
        }
    }
    
    // ...and for any new fragments
    for ( i = 0; i < GetItemCount ( theHeader ); i++ )
    {
        anItem = GetNthItem ( theHeader, i );
        
        if ( anItem->bDeleted || anItem->bExistsInDocument )
            continue;
            
        anItem->codeOffset = 0L;
        theErr = AppendFileData ( GetTempSpecPtr ( anItem ), &theInfo->fileSpec, &anItem->codeOffset, &anItem->codeLength );
        if ( theErr )
        {
            AlertUser ( kGenericErrorStr, theErr, nil );
            return kNotCancelled;
        }
        
        anItem->bExistsInDocument = true;
    }
    
    HUnlock ( (Handle) theHeader );
    
    
    saveFile = CurResFile ( );
    theFileRef = FSpOpenResFile ( &theInfo->fileSpec, fsRdWrPerm );
    theErr = ResError ( );
    if ( theErr )
    {
        int16   theIndex;
        
        theIndex = (theErr == opWrErr || theErr == permErr) ? kFileOpenStr : kGenericErrorStr;
        AlertUser ( theIndex, (theErr == noErr) ? resNotFound : theErr, nil );
        return kNotCancelled;
    }
    UseResFile ( theFileRef );
    
    resourceScratch = Get1Resource ( kCFragResourceType, kCFragResourceID );
    theErr = ResError ( );
    if ( theErr || resourceScratch == nil )
    {
        AlertUser ( kGenericErrorStr, (theErr == noErr) ? resNotFound : theErr, nil );
        return kNotCancelled;
    }
    
    theErr = BuildResource ( (tHeaderHan) theInfo->dataHandle, resourceScratch );
    if ( theErr )
    {
        AlertUser ( kGenericErrorStr, theErr, nil );
        return kNotCancelled;
    }
    
    ChangedResource ( resourceScratch );
    UpdateResFile ( theFileRef );
    ReleaseResource ( resourceScratch );
    CloseResFile ( theFileRef );
    UseResFile ( saveFile );
    
    SetDocumentDirty ( theWindow, false );
    
    return kNotCancelled;
}
 
 
 
Boolean DoSaveAs ( WindowRef theWindow )
{
    tWindowInfoPtr      theInfo;
    StandardFileReply   theReply;
    Str255              defaultName;
    
    
    theInfo = (tWindowInfoPtr) GetWRefCon ( theWindow );
    #if DEBUGGING
    if ( theInfo == nil ) DebugStr ( "\p theInfo == nil" );
    #endif
    
    GetWTitle ( theWindow, defaultName );
    StandardPutFile ( "\p", defaultName, &theReply );
    if ( theReply.sfGood )
    {
        OSErr   theErr;
        
        if ( theInfo->bUntitled )
        {
            theInfo->bUntitled = false;
            DoSave ( theWindow );
            
            theErr = FSpCreate ( &theReply.sfFile, kFourQuestionMarks, kCFragLibraryFileType, theReply.sfScript );
            theErr = FSpExchangeFiles ( &theInfo->fileSpec, &theReply.sfFile );
            FSpDelete ( &theInfo->fileSpec );
            
            BlockMoveData ( &theReply.sfFile, &theInfo->fileSpec, sizeof ( FSSpec ) );
            
            SetWTitle ( theWindow, theReply.sfFile.name );
        }
        else        // User selected ÒSave AsÉÓ
        {
            int16       theRef, saveFile;
            int         i;
            FSSpec      oldSpec;
            tItemPtr    anItem;
            hdrHand     theResource = nil;
            tHeaderHan  theHeader;
            
            
            BlockMoveData ( &theInfo->fileSpec, &oldSpec, sizeof ( FSSpec ) );
            BlockMoveData ( &theReply.sfFile, &theInfo->fileSpec, sizeof ( FSSpec ) );
            theErr = FSpCreate ( &theInfo->fileSpec, kFourQuestionMarks, kCFragLibraryFileType, theReply.sfScript );
            
            theHeader = (tHeaderHan) theInfo->dataHandle;
            HLock ( (Handle) theHeader );
            // copy each fragment's data fork
            for ( i = 0; i < GetItemCount ( theHeader ); i++ )
            {
                FSSpecPtr   theSpecPtr;
 
                anItem = GetNthItem ( theHeader, i );
                if ( anItem->bDeleted )
                    continue;
                
                if ( anItem->bExistsInDocument )
                    theSpecPtr = &oldSpec;
                else
                {
                    theSpecPtr = GetTempSpecPtr ( anItem );
                    anItem->codeOffset = 0L;
                }
                    
                theErr = AppendFileData ( theSpecPtr, &theInfo->fileSpec, &anItem->codeOffset, &anItem->codeLength );
                if ( theErr )
                {
                    AlertUser ( kGenericErrorStr, theErr, nil );
                    return kNotCancelled;
                }
                
                anItem->bExistsInDocument = true;
            }
            HUnlock ( (Handle) theHeader );
            
            
            FSpCreateResFile ( &theInfo->fileSpec, kFourQuestionMarks, kCFragLibraryFileType, smSystemScript );
            theRef = FSpOpenResFile ( &theInfo->fileSpec, fsRdWrPerm );
            
            theResource = (hdrHand) NewHandleClear ( offsetof ( cfrgHeader, arrayStart ) );
            (*theResource)->version = 1;        // Current version number
            
            theErr = BuildResource ( (tHeaderHan) theInfo->dataHandle, (Handle) theResource );
            
            saveFile = CurResFile ( );
            theRef = FSpOpenResFile ( &theInfo->fileSpec, fsRdWrPerm );
            // If the file is already open, it may not be the current resource file
            UseResFile ( theRef );
            AddResource ( (Handle) theResource, kCFragResourceType, kCFragResourceID, "\p" );
            UpdateResFile ( theRef );
            ReleaseResource ( (Handle) theResource );
            CloseResFile ( theRef );
            UseResFile ( saveFile );
            
            
            SetWTitle ( theWindow, theReply.sfFile.name );
            
            SetDocumentDirty ( theWindow, false );
        }
        
        return kNotCancelled;
    }
    
    return kCancelled;
}
 
 
 
static OSErr CreateContentList ( WindowRef theWindow, tContentsProcPtr contentsProc, void* refCon )
{
    OSErr       theErr;
    ListHandle  theList;
    Point       cellSize = {0, 32767};
    Cell        firstCell = {0, 0};
    Rect        dataRect = {0, 0, 0, 1};
    Rect        viewRect;
    
    
    // The width of a cell needs to be 32767 so any hiliting
    // doesn't stop short of the window width after it's been resized.
    
    viewRect = theWindow->portRect;
    viewRect.bottom -= 15; viewRect.right -= 15;
    theList = LNew ( &viewRect, &dataRect, cellSize, 0, theWindow, 
                        false, false, true, true );
    if ( theList )
    {
        (*theList)->selFlags = lOnlyOne;
        (*theList)->lClickLoop = gClickLoopUPP;
        SetWListRef ( theWindow, theList );
        
        // Since the calling routine is always in the same architecture type as
        // the callback routine, we don't need to worry about any Mixed Mode
        // complications. We just treat it as a straight forward routine pointer.
        if ( contentsProc )
        {
            theErr = (*contentsProc) ( theList, refCon );
            if ( theErr )
                return theErr;
        }
        
        LSetSelect ( true, firstCell, theList );
        
        // Now the list has been fully prepared, turn the drawing mode on
        LSetDrawingMode ( true, theList );
    }
    
    return noErr;
    
} // CreateContentList
 
 
 
Boolean IsDocumentDirty ( WindowRef theWindow )
{
    if ( GetWindowType ( theWindow ) == kDocumentWindowType )
    {
        tWindowInfoPtr  theInfo;
        
        theInfo = (tWindowInfoPtr) GetWRefCon ( theWindow );
        if ( theInfo )
            return ( theInfo->bDirty );
    }
    
    return false;
}
 
 
 
void SetDocumentDirty ( WindowRef theWindow, Boolean bIsDirty )
{
    if ( GetWindowType ( theWindow ) == kDocumentWindowType )
    {
        tWindowInfoPtr  theInfo;
        
        theInfo = (tWindowInfoPtr) GetWRefCon ( theWindow );
        if ( theInfo )
            theInfo->bDirty = bIsDirty;
            
        AdjustMenus ( );
    }
    
    return;
}
 
 
 
void SetWListRef ( WindowRef theWindow, ListHandle theList )
{
    ((tWindowInfoPtr) GetWRefCon ( theWindow ))->listRef = theList;
    
    return;
}
 
 
 
ListHandle GetWListRef ( WindowRef theWindow )
{
    return ((tWindowInfoPtr) GetWRefCon ( theWindow ))->listRef;
}
 
 
 
void SetWFileSpec ( WindowRef theWindow, FSSpecPtr theSpec )
{
    BlockMoveData ( theSpec, &((tWindowInfoPtr) GetWRefCon ( theWindow ))->fileSpec, sizeof ( FSSpec ) );
    
    return;
}
 
 
 
/*----------------------- Handle window update events ----------------------*/
 
void DoUpdate ( EventRecord* theEvent )
{
    WindowRef   theWindow;
    SInt16      theType;
    GrafPtr     savePort;
    
    
    
    theWindow = (WindowRef) theEvent->message;
            
    
    theType = GetWindowType ( theWindow );
    GetPort ( &savePort );
    SetPortWindowPort ( theWindow );
    BeginUpdate ( theWindow );                  // visRgn temporarily = updateRgn
    EraseRect ( &theWindow->portRect );
 
    switch ( theType )
    {
        case kDocumentWindowType:
        {
            ListHandle  theList = nil;
            
            theList = GetWListRef ( theWindow );
            if ( theList )
                LUpdate ( (*theList)->port->visRgn, theList );
            DrawClippedGrowIcon ( theWindow );
        }
        break;
        
        case kListWindowType:
        {
            ListHandle      theList = nil;
            tDialogInfoPtr  theInfo;
            
            UpdateDialog ( theWindow, theWindow->visRgn );
            theInfo = (tDialogInfoPtr) GetWRefCon ( theWindow );
            theList = theInfo->listRef;
            if ( theList )
                LUpdate ( (*theList)->port->visRgn, theList );
        }
        break;
 
        case kGetInfoWindowType:
        {
            TEHandle        textH;
            
            UpdateDialog ( theWindow, theWindow->visRgn );
            textH = ((DialogPeek) theWindow)->textH;
            if ( textH )
                TEUpdate ( &(*textH)->viewRect, textH );
        }
        break;
    }
    
    EndUpdate ( theWindow );                    // restore normal visRgn of grafport
    SetPort ( savePort );
    
    return;
    
} // DoUpdate
 
 
 
void DoActivate ( EventRecord* theEvent )
{
    SInt16      itemHit;
    SInt16      theType;
    ListHandle  theList = nil;
    WindowRef   theWindow = (WindowRef) theEvent->message;
    Boolean     bActiveFlag = theEvent->modifiers & 1;
    
    
    
    theType = GetWindowType ( theWindow );
    switch ( theType )
    {
        case kDocumentWindowType:
        {
            LActivate ( bActiveFlag, GetWListRef ( theWindow ) );
            DrawClippedGrowIcon ( theWindow );
        }
        break;
        
        case kListWindowType:
        {
            tDialogInfoPtr theInfo = (tDialogInfoPtr) GetWRefCon ( theWindow );
            theList = theInfo->listRef;
            if ( theList )
                LActivate ( bActiveFlag, theList );
            DialogSelect ( theEvent, &theWindow, &itemHit );
        }
        break;
        
        case kGetInfoWindowType:
        {
            TEHandle        textH;
            
            textH = ((DialogPeek) theWindow)->textH;
            if ( textH )
            {
                if ( bActiveFlag )
                    TEActivate ( textH );
                else
                    TEDeactivate ( textH );
            }
            DialogSelect ( theEvent, &theWindow, &itemHit );
        }
        break;
    }
    
    
    AdjustMenus ( );
    
} // DoActivate
 
 
 
void DoContentClick ( WindowRef theWindow, EventRecord* theEvent )
{
    WindowRef   frontWindow;
    
    // If a movable modal is active, ignore click in an inactive 
    // window, otherwise select it or handle the content click.
    
    frontWindow = FrontWindow ( );
    if ( theWindow != frontWindow )
    {
        if ( IsMovableModal ( frontWindow ) )
            SysBeep ( 30 );
        else
            SelectWindow ( theWindow );
    }
    else
    {
        if ( IsMovableModal ( theWindow ) )
            DoDialogContentClick ( theWindow, theEvent );
        else
        {
            Boolean bWasHandled;
            bWasHandled = HandleListClick ( theWindow, theEvent );
            
            AdjustMenus ( );
        }
    }
    
    return;
    
} // DoContentClick
 
 
 
 
 
void DoGrowWindow ( WindowRef theWindow, EventRecord* theEvent )
{
    const short kMinDocSize = 64;
    const short kMaxDocSize = 32767;
    
    long    newSize;
    Rect    limitRect;
    
    
    // set up the limiting rectangle
    SetRect ( &limitRect, kMinDocSize, kMinDocSize, kMaxDocSize, kMaxDocSize );
    // call Window Manager to let the user drag size box
    newSize = GrowWindow ( theWindow, theEvent->where, &limitRect );
    if ( newSize )                  // if the user changed its size
    {
        short h, v;
        
        h = newSize & 0x0000FFFF;
        v = newSize >> 16;
        SizeWindow ( theWindow, h, v, true );
        h -= 15; v -= 15;
        LSize ( h, v, GetWListRef ( theWindow ) );
        SetPort ( theWindow );
        InvalRect ( &theWindow->portRect );
    }
    
    return;
    
} // DoGrowWindow
 
 
 
 
void DoDragWindow ( WindowRef theWindow, EventRecord* theEvent )
{
    WindowRef   frontWindow;
    
    
    // If a movable modal is active, ignore click in an inactive 
    // title bar, otherwise let the Window Manager handle it.
    
    frontWindow = FrontWindow ( );
    if ( theWindow != frontWindow && IsMovableModal ( frontWindow ) )
        SysBeep ( 30 );
    else                                
    {
        RgnHandle   theRgn;
        Rect        dragRect;
        
        theRgn = GetGrayRgn ( );
        dragRect = (*theRgn)->rgnBBox;
        DragWindow ( theWindow, theEvent->where, &dragRect );
    }
    
    return;
}
 
 
 
Boolean IsMovableModal ( WindowRef theWindow )
{
    return (GetWVariant ( theWindow ) == movableDBoxProc);
}
 
 
 
int16 GetWindowType ( WindowRef theWindow )
{
    int16 theType = 0;
    
    if ( theWindow )
    {
        theType = GetWindowKind ( theWindow );
        if ( theType < 0 )
            theType = kDAWindowType;
        else if ( theType == kApplicationWindowKind )
            theType = kDocumentWindowType;
        else
        {
            tDialogInfoPtr theInfo = (tDialogInfoPtr) GetWRefCon ( theWindow );
            if ( theInfo )
                theType = theInfo->windowType;
        }
    }
    
    return theType;
}
 
 
 
void SetWindowType ( WindowRef theWindow, int16 theType )
{
    int16 theKind;
 
    if ( theWindow )
    {
        theKind = GetWindowKind ( theWindow );
        if ( theKind != kApplicationWindowKind )
        {
            tDialogInfoPtr theInfo = (tDialogInfoPtr) GetWRefCon ( theWindow );
            if ( theInfo )
                theInfo->windowType = theType;
        }
    }
    
    return;
}
 
 
 
int16 GetWindowSubType ( WindowRef theWindow )
{
    int16 theKind;
    int16 theType = 0;
    
    if ( theWindow )
    {
        theKind = GetWindowKind ( theWindow );
        if ( theKind != kApplicationWindowKind )
        {
            tDialogInfoPtr theInfo = (tDialogInfoPtr) GetWRefCon ( theWindow );
            if ( theInfo )
                theType = theInfo->windowSubType;
        }
    }
    
    return theType;
}
 
 
 
void SetWindowSubType ( WindowRef theWindow, int16 theType )
{
    int16 theKind;
 
    if ( theWindow )
    {
        theKind = GetWindowKind ( theWindow );
        if ( theKind != kApplicationWindowKind )
        {
            tDialogInfoPtr theInfo = (tDialogInfoPtr) GetWRefCon ( theWindow );
            if ( theInfo )
                theInfo->windowSubType = theType;
        }
    }
    
    return;
}
 
 
 
void DoZoomWindow ( WindowRef theWindow, EventRecord* theEvent, int16 windowPart )
{
    Point               globalPt = theEvent->where;
    
    SetPort ( theWindow );
    if ( TrackBox ( theWindow, globalPt, windowPart ) )
    {
        /*
            TO DO:
                This doesn't handle multiple screens
        */
        
        ZoomWindow ( theWindow, windowPart, true );
        InvalRect ( &theWindow->portRect );
    }
    
    return;
}
 
 
 
OSErr CopyWindowFragment ( WindowRef source, int16 sourceIndex, WindowRef target )
{
    int16           itemIndex;
    OSErr           theErr;
    tWindowInfoPtr  sourceInfo = nil;
    tWindowInfoPtr  targetInfo = nil;
    
    
    
    itemIndex = GetIndexFromNthWindowItem ( source, sourceIndex );
    
    sourceInfo = (tWindowInfoPtr) GetWRefCon ( source );
    targetInfo = (tWindowInfoPtr) GetWRefCon ( target );
    
    theErr = CreateTempAndCopyFragment ( (tHeaderHan) sourceInfo->dataHandle, &sourceInfo->fileSpec,
                                            itemIndex, (tHeaderHan) targetInfo->dataHandle );
    if ( theErr == noErr )
    {
        SignedByte  theState;
        tItemPtr    theItem;
        
        theState = HGetState ( sourceInfo->dataHandle );
        HLock ( sourceInfo->dataHandle );
        theItem = GetNthItem ( (tHeaderHan) sourceInfo->dataHandle, itemIndex );
        AddFragToList ( GetWListRef ( target ), theItem );
        HSetState ( sourceInfo->dataHandle, theState );
        
        SetDocumentDirty ( target, true );
    }
    
    return theErr;
}
 
 
 
OSErr MoveWindowFragment ( WindowRef source, int16 sourceIndex, WindowRef target )
{
    OSErr   theErr = noErr;
    
    theErr = CopyWindowFragment ( source, sourceIndex, target );
    if ( !theErr )
        theErr = DeleteWindowFragment ( source, sourceIndex );
    
    return theErr;
}
 
 
 
OSErr DeleteWindowFragment ( WindowRef theWindow, int16 theIndex )
{
    int16           itemIndex;
    OSErr           theErr;
    tWindowInfoPtr  theInfo;
    
    
    // Since we don't support undo just yet, there's no need
    // to copy it to a temporary file.
    
    itemIndex = GetIndexFromNthWindowItem ( theWindow, theIndex );
    
    theInfo = (tWindowInfoPtr) GetWRefCon ( theWindow );
    theErr = DeleteFragment ( (tHeaderHan) theInfo->dataHandle, nil, itemIndex );
    
    if ( theErr == noErr )
    {
        DeleteFromList ( GetWListRef ( theWindow ), theIndex );
        SetDocumentDirty ( theWindow, true );
    }
    
    return theErr;
}
 
 
 
OSErr CreateTempAndCopyFragment ( tHeaderHan sourceHeader, FSSpecPtr sourceSpec, int16 sourceIndex,
                                        tHeaderHan targetHeader )
{
    SignedByte  sourceState, targetState;
    OSErr       theErr;
    tItemPtr    sourceItem, targetItem;
    FSSpec      tempSpec;
    
    
    sourceState = HGetState ( (Handle) sourceHeader );
    HLock ( (Handle) sourceHeader );
    targetState = HGetState ( (Handle) targetHeader );
    HLock ( (Handle) targetHeader );
    
    sourceItem = GetNthItem ( sourceHeader, sourceIndex );
    // Do we already have a temporary file that contains this fragment
    if ( GetTempUsageCount ( sourceItem ) )
    {
        theErr = CopyFragment ( sourceHeader, nil, sourceIndex, targetHeader, nil );
        
        targetItem = GetLastItem ( targetHeader );
        targetItem->bExistsInDocument = false;
        IncrementTempUsageCount ( targetItem );
    }
    else
    {
        theErr = CreateTemporaryFile ( &tempSpec );
        
        theErr = CopyFragment ( sourceHeader, sourceSpec, sourceIndex, targetHeader, &tempSpec );
        if ( theErr )
            // We'll let the system handle the temp file. It may
            // be useful for debugging, if nothing else.
            return theErr;
        
        sourceItem = GetNthItem ( sourceHeader, sourceIndex );
        IncrementTempUsageCount ( sourceItem );
        BlockMoveData ( &tempSpec, GetTempSpecPtr ( sourceItem ), sizeof ( FSSpec ) );
        
        targetItem = GetLastItem ( targetHeader );
        targetItem->bExistsInDocument = false;
        targetItem->tempFilePtr = sourceItem->tempFilePtr;
        IncrementTempUsageCount ( targetItem );
    }
    
    HSetState ( (Handle) sourceHeader, sourceState );
    HSetState ( (Handle) sourceHeader, targetState );
    
    return theErr;
}
 
 
 
tItemPtr GetNthWindowItem ( WindowRef theWindow, int16 theIndex )
{
    tWindowInfoPtr  theInfo = nil;
    
    
    theIndex = GetIndexFromNthWindowItem ( theWindow, theIndex );
    
    theInfo = (tWindowInfoPtr) GetWRefCon ( theWindow );
    return GetNthItem ( (tHeaderHan) theInfo->dataHandle, theIndex );
}
 
 
 
int16 GetIndexFromNthWindowItem ( WindowRef theWindow, int16 theIndex )
{
    int16           theSize;
    int             i;
    Cell            theCell = { 0, 0 };
    tWindowInfoPtr  theInfo = nil;
    tHeaderHan      theHeader;
    Str255          theText;
    
    
    theInfo = (tWindowInfoPtr) GetWRefCon ( theWindow );
    
    // First, get the text we're looking for. Two fragments with the same name
    // but different architectures are quite likely. We need to include the type.
    
    theSize = sizeof ( Str255 );
    theCell.v = theIndex;
    LGetCell ( &theText[1], &theSize, theCell, theInfo->listRef );
    theText[0] = theSize;
    
    theHeader = (tHeaderHan) theInfo->dataHandle;
    // Now, scan our items looking for a match
    for ( i = 0; i < GetItemCount ( theHeader ); i++ )
    {
        tItemPtr        theItem;
        unsigned char   archTypeStr[5];
        Str255          itemText;
        
        theItem = GetNthItem ( theHeader, i );
        // Since we're looking for an item in the window, ignore deleted items
        if ( theItem->bDeleted )
            continue;
        
        CopyPStr ( theItem->name, itemText, sizeof ( Str255 ) );
        ConcatPStr ( itemText, "\p\t", sizeof ( Str255 ) );
        OSTypeToPStr ( theItem->archType, archTypeStr );
        ConcatPStr ( itemText, archTypeStr, sizeof ( Str255 ) );
        if ( EqualString ( theText, itemText, true, true ) )
            return i;
    }
    
    
    #if DEBUGGING
    DebugStr ( "\p GetIndexFromNthWindowItem returning 0" );
    #endif
 
    return 0;
}
 
 
 
void AddFragToList ( ListRef theList, tItemPtr theItem )
{
    unsigned char   archTypeStr[5];
    Str255          theText;
    
    
    CopyPStr ( theItem->name, theText, sizeof ( Str255 ) );
    ConcatPStr ( theText, "\p\t", sizeof ( Str255 ) );
    OSTypeToPStr ( theItem->archType, archTypeStr );
    ConcatPStr ( theText, archTypeStr, sizeof ( Str255 ) );
    AddToList ( theList, theText );
    
    return;
}
 
 
 
void UpdateFragInList ( WindowRef theWindow, int16 theIndex, StringPtr newName )
{
    unsigned char   archTypeStr[5];
    tItemPtr        theItem;
    ListRef         theList;
    Str255          theText;
    
    
    theItem = GetNthWindowItem ( theWindow, theIndex );
    theList = GetWListRef ( theWindow );
    CopyPStr ( newName, theText, sizeof ( Str255 ) );
    ConcatPStr ( theText, "\p\t", sizeof ( Str255 ) );
    OSTypeToPStr ( theItem->archType, archTypeStr );
    ConcatPStr ( theText, archTypeStr, sizeof ( Str255 ) );
    UpdateList ( theList, theIndex, theText );
    
    return;
}