Subscribe.c

/*------------------------------------------------------------------------------
*
*  Apple Developer Technical Support
*
*  Edition subscribing routines
*
*  Program:    AEObject-Edition Sample
*  File:       Subscribe.c -   C Source
*
*  by:         C.K. Haun <TR>
*
*  Copyright © 1990-1992 Apple Computer, Inc.
*  All rights reserved.
*
*------------------------------------------------------------------------------
* This file handles the Subscribe section of the program.  It also handles some of 
* the common use routines, like the section options dialog.
*----------------------------------------------------------------------------*/
 
#define __SUBSCRIBE__
 
#pragma segment Subscribe
 
#include "Sampdefines.h"
 
/* this point tells EM to center our expanded box, if we're using that feature */
Point expPoint = 
{
    -1, -1
};
 
 
 
 
/* DoSubscribe presents the user with the Subscriber dialog, and allows the user to */
/* subscribe to a PICT type edition, anywhere, anytime.  It also stores the */
/* section handle returned in the window data structure for the current window */
/* You can only subscribe to TEXT if you have a text box open in the current window.  */
/* Optionally, of course, you can put in your own conversion of the TEXT to a PICT and */
/* subscribe to that as such, same as you would with clipboard types. */
 
void DoSubscribe(void)
{
    OSErr myErr;
    SectionHandle secHandle;
    windowCHandle shortName;
    NewSubscriberReply GetSub;
    shortName = (windowCHandle)GetWRefCon(FrontWindow());       /* get our struct */
    GetSub.formatsMask = kPICTformatMask;                   /* tell the dialog we only want PICT type editions */
    if ((*shortName)->boxHandle != nil)                     /* is there a text box already? */
        GetSub.formatsMask += kTEXTformatMask;
    /* GetLastEditionContainerUsed gives you either the last edition container used  */
    /* (either pub or sub, since they are the same to the Edition Manager) or if there */
    /* was not a previous container, it fills it with a default container. */
    GetLastEditionContainerUsed(&GetSub.container);
    /* Now ask the user to select an edition to subscribe to */
    if (!gExpanded)
        myErr = NewSubscriberDialog(&GetSub);
    else
    {
        ExpDlgHookUPP dhUPP = NewExpDlgHookProc(ExpOptHook);
        ExpModalFilterUPP mfUPP = NewExpModalFilterProc(ExpOptFilter);
        myErr = NewSubscriberExpDialog(&GetSub, expPoint, kExpandedDITL, dhUPP, mfUPP, nil);
        DisposeRoutineDescriptor(mfUPP);
        DisposeRoutineDescriptor(dhUPP);
    }
    
    if (myErr != noErr) {                                   /* bail on fail */
        ShowMe("\pNewSubscriberDialog", myErr, __LINE__);
        return;
    }
    if (GetSub.canceled)                                    /* did they cancel the dialog? */
        return;
    HLock((Handle)shortName);
    /* Now create a new section record for the container the user picked.  In other words, the */
    /* Edition manager keeps track of things by the container, and will give you a section */
    /* record that refers to it for you to keep track with.  */
    /* ¥¥¥ NOTE: Whenever the Edition Manager gives you memory (like the section handle) */
    /* it came out of your heap, and YOU are responsible for disposing of it when you are */
    /* completely done (and have UnRegistered) the section.  If you're not careful about this */
    /* then you'll get creeping memory loss.  */
    /* Now see if the window has ever been saved.  If so, we can store a reference to */
    /* the file in the section */
    if (GetHandleSize((Handle)(*shortName)->fileAliasHandle) == 0) {
        myErr = NewSection(&GetSub.container, nil, stSubscriber, (*shortName)->windowID + gSectionID, sumAutomatic, &secHandle);
    } else {
        /* if the file has been saved once, then we can store a reference to the 'parent' file */
        /* in the edition */
        FSSpec tempSpec;
        Boolean myWasChanged;
        myErr = ResolveAlias(nil, ((*shortName)->fileAliasHandle), &tempSpec, &myWasChanged);
        myErr = NewSection(&GetSub.container, &tempSpec, stSubscriber, (*shortName)->windowID + gSectionID, sumAutomatic,
                           &secHandle);
    }
    if (myErr != noErr) {
        ShowMe("\pNewSection", myErr, __LINE__);
        return;
    }
    /* section successfully gotten.  Add it to the current window section list please */
    /* Handle this in whatever way is appropriate for your application, of course.  */
    /* The main point to remember is that you _must_ keep track of the section handles, */
    /* they are your method (only method) for comunication between your application */
    /* and the Edition Manager, you will be passing sections to the EM, and it will be */
    /* passing them back to you. */
    gSectionID++;                                           /* increment our unique ID */
    StoreSubscriber(shortName, secHandle, nil, nil);
    HUnlock((Handle)shortName);
}
 
/* end DoSubscribe */
/* DoOptions handles the SectionOptions menu selection.  The handle passed */
/* (inSection) is a subscriber OR publisher section, the Edition Manager will figure */
/* out what dialog to display by looking at the section record */
/* ¥¥¥ BE CAREFUL with the section  handle you pass to the options dialog (or anywhere, for that matter) */
/* A section that has not been registered, or a section containing a bad alias handle, will */
/* cause the options dialog to blow up in unusual and fun ways */
/* This call also includes the expanded section options dialog box with one */
/* extra item, to show how it's used. */
void DoOptions(SectionHandle inSection)
{
    OSErr myErr;
    SectionOptionsReply oreply;
    Boolean subExpansion;
    
    oreply.sectionH = inSection;                            /* put the section passed in the reply record */
    if ((*inSection)->kind == stSubscriber)
        subExpansion = true;
    else
        subExpansion = false;
    myErr = IsRegisteredSection(inSection);
    if (myErr != noErr) {
        ShowMe("\p Bad Section ", myErr, __LINE__);
        return;
    }
    if (subExpansion) {
        ExpDlgHookUPP dhUPP = NewExpDlgHookProc(SubExpOptHook);
        ExpModalFilterUPP mfUPP = NewExpModalFilterProc(SubExpOptFilter);
        myErr = SectionOptionsExpDialog(&oreply, expPoint, kExpandedSubDITL, dhUPP, mfUPP, nil);
        DisposeRoutineDescriptor(dhUPP);
        DisposeRoutineDescriptor(mfUPP);
    } else {
        if (!gExpanded)
            myErr = SectionOptionsDialog(&oreply);          /* run the dialog */
        else
        {
            ExpDlgHookUPP dhUPP = NewExpDlgHookProc(ExpOptHook);
            ExpModalFilterUPP mfUPP = NewExpModalFilterProc(ExpOptFilter);
            myErr = SectionOptionsExpDialog(&oreply, expPoint, kExpandedDITL, dhUPP, mfUPP, nil);
            DisposeRoutineDescriptor(dhUPP);
            DisposeRoutineDescriptor(mfUPP);
        }
    }
    if (myErr != noErr) {
        ShowMe("\pSection Options", myErr, __LINE__);
        return;
    }
    if (oreply.canceled)                                    /* if user canceled */
        return;
    if (oreply.action == sectionReadMsgID) {
        /* if the user clicked 'Get Edition Now' you'll call your section read routine, the same */
        /* one that gets called on a sect read AppleEvent */
        MyReadSection(inSection);
    } else {
        if (oreply.action == sectionWriteMsgID) {
            /* if the user clicked 'Send Edition Now' you'll call your section write routine, the same */
            /* one that gets called on a sect writ AppleEvent */
            MyUpdateEdition(inSection);
        } else {
            if (oreply.action == 'goto') {  /* why isn't there a constant fo this? */
                /* this is the sect scrl (section scroll) event from the dialog */
                /* the dialog has already taken the action for you, that's it's job */
            } else {
                if (oreply.action == emCancelSectionDialogRefCon) {
                    /* This is for canceling a section, either pub or sub, you have to make the */
                    /* choice based on what the section is */
                    SectionType tempST;
                    HLock((Handle)inSection);
                    tempST = (*inSection)->kind;            /* what kinda thing is this? */
                    HUnlock((Handle)inSection);
                    
                    MyCancelSection(inSection, FindSection(inSection));
                }
            }
        }
    }
}
 
/* end DoOptions */
 
/* AEReadSectionHandler is the handler I installed in the AppleEvent manager list for */
/* AppleEvents of the type 'sect' 'read'.  What this means is that whenever I get a */
/* high level event of the type 'sect' 'read' this routine will be dispatched to when I */
/* call AEProcessAppleEvent (in AppleEventM.c).   This is where the actual section data */
/* gets read in, when the Edition Manager tells you the edition is ready to read */
pascal OSErr AEReadSectionHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
{
#pragma unused (reply,refIn)
    SectionHandle theSection;
    OSErr myErr;
    
    myErr = GetSectionHandleFromEvent(messagein, &theSection);      /* in AppleEventM.c */
    if (myErr) {
        ShowMe("\pGetSectionHandleFromEvent", myErr, __LINE__);
        return(myErr);
    }
    /* This next step is very important.  Unexpected things can happen to you, */
    /* a section could disappear between the time an event gets posted and when it */
    /* finally gets to your application (particularly since AppleEvents are the lowest in */
    /* the event hierarchy), the section may have been canceled, deleted, disk off-line, or */
    /* whatever.  You must make a current check with the EM to see if the section that */
    /* you are supposed to read. */
    myErr = IsRegisteredSection((SectionHandle)theSection);
    if (myErr) {
        ShowMe("\pRead IsRegisteredSection", myErr, __LINE__);
        return(myErr);
    }
    /* It is a valid section.  Jump to my routine that opens and reads it */
    MyReadSection(theSection);
}
 
/* end AEReadSectionHandler */
 
/* MyReadSection opens and reads the edition data into my window data structure. */
OSErr MyReadSection(SectionHandle theSection)
{
    OSErr myErr;
    EditionRefNum sRefNum=0;
    Size dataSize;
    Boolean existed = false;                                /* for setting the display rect */
    /* open the edition and get a ref number */
    SpinCursor();
    myErr = OpenEdition(theSection, &sRefNum);
    if (myErr) {
        if(sRefNum)CloseEdition(sRefNum,true);
        ShowMe("\pOpenEdition", myErr, __LINE__);
        return(myErr);
        
    }
    /* Here we are double-checking the edition.  I'm first checking for PICT data, */
    /* and as a handy side effect, it gives us the size of the data (returned in my */
    /* variable dataSize) for us to use when we read it later */
    
    
    if (noErr == (myErr = EditionHasFormat(sRefNum, kGenericPICTWord, &dataSize))) {
        /* It does have a pict, read it in */
        register  jj;                                    /* loop vars for window search */
        long subIDtofind;
        
        /*  There is already a handle allocated for this picture in the window structure. 
        *   Find it, resize it (since the edition size could have changed) and fill it.
        *       Keep in mind that the section read may happen for a window which is not 
        *       frontmost, so we need to search all the windows to find the ID */
        WindowPtr tempPort;
        Boolean secFound = false;
        SectionHandle *tempPtr;
        SectionRecord *tempRecord;
        Handle tempHandle;
        WindowPtr tempNextWindow;
        Rect *tempRect;
        Rect holdRect;
        SpinCursor();
        HLock((Handle)theSection);
        subIDtofind = (*theSection)->sectionID;             /* what ID are we reading?  */
        /* check to see if this is the clipboard's section.  If so, let the clipboard */
        /* handle it */
        if ((subIDtofind == (*gClipSection)->sectionID) && (gClipSection != nil)){
            return(ReadClipSection(dataSize, sRefNum));
            }
        GetPort(&tempPort);                                 /* save the current port */
        /* search window list now */
        tempNextWindow = (WindowPtr)LMGetWindowList();                         /* start at the beginning of the chain */
        while (tempNextWindow) {
            SpinCursor();
            if (((WindowPeek)tempNextWindow)->windowKind == kDocumentWindow) {
                windowCHandle tempWC;
                /* do housekeeping to get to the section handle list */
                tempWC = (windowCHandle)GetWRefCon(tempNextWindow);
                HLock((Handle)tempWC);
                tempHandle = (*tempWC)->subs;               /* handle containing SectionHandles */
                HLock(tempHandle);
                tempPtr = (SectionHandle *)*tempHandle;
                /* Loop through all our sections until we find this edition */
                for (jj = 0; jj < (*tempWC)->numSubs; jj++) {
                    Handle *newTemp;
                    SpinCursor();
                    HLock((Handle)*tempPtr);
                    tempRecord = *(*tempPtr);
                    if (tempRecord->sectionID == subIDtofind) {
                        /* found the section belonging to this read. */
                        /* can't break, since it is conceiveable that the user has more that one subscription in this document */
                        SetPort(tempNextWindow);            /* set the port to the window we found the section in */
                        HLock((*tempWC)->subDataHandle);
                        newTemp = (Handle *)*((*tempWC)->subDataHandle);
                        newTemp += jj;
                        /* if the dataSize returned was -1 then the size was unknown when opened.  */
                        /* in this case, this should only happen with our special opener.  */
                        /* So, if it is -1, then we'll have to handle the read */
                        /* in a series of steps to get the right amount of data */
                        /* For now, I'll leave that out until I put in a custom */
                        /* opener. Watch this space */
                        if (dataSize != -1) {
                            HUnlock(*newTemp);
                            MySetHandleSize(*newTemp, dataSize);
                            HLock(*newTemp);
                        }
                        SpinCursor();
                        /* read the pict in */
                        myErr = MyReadEditionData(**newTemp, kGenericPICTWord, sRefNum, &dataSize);
                        /* ¥¥¥¥¥ NOTE: After much discussion with our Human Interface folks and the */
                        /* Edition Manager engineer, we've decided that the interface guidelines */
                        /* for editions will say that reading a subscription does _not_ dirty */
                        /* a document.  A lot of soul-searching went on to make this decision, and */
                        /* we decided this way primarily to keep the user from getting confused.  */
                        /* Editions should be as transparent and automatic as possible, and reminding */
                        /* the user that an edition is a 'special' thing that they have to do */
                        /* unusual things with to make work right will remove some of that */
                        /* automation.  Of course, the 'cached' version of the subscription that */
                        /* you save with the document should be updated when the subscription changes */
                        /* So, the following line was commented out. */
                        /* (*tempWC)->windowDirty = true;  */
                        /* mark window dirty on every read */
                        holdRect = (*(PicHandle)(*newTemp))->picFrame;
                        HUnlock(*newTemp);
                        /* put the picture in the corner, if it didn't exist.  If it did, adjust the rect as
                        *   required */
                        HLock((*tempWC)->subRects);
                        newTemp = (Handle *)*((*tempWC)->subRects);
                        newTemp += jj;
                        /* if the handle is the size of a rect, I've seen this edition before */
                        if (GetHandleSize(*newTemp) == sizeof(Rect)) {
                            existed = true;                 /* it's already been made */
                        } else {
                            HUnlock(*newTemp);
                            MySetHandleSize(*newTemp, sizeof(Rect));        /* new subscription */
                        }
                        HLock(*newTemp);
                        tempRect = (Rect *)*(*newTemp);
                        if (!existed) {
                            tempRect->top = tempRect->left = 0;
                            tempRect->bottom = holdRect.bottom - holdRect.top;
                            tempRect->right = holdRect.right - holdRect.left;
                        } else {
                            InvalRect(tempRect);            /* refresh the old image if the thing was resized */
                            /*          tempRect->bottom = tempRect->top + (holdRect.bottom - holdRect.top);
                            tempRect->right = tempRect->left + (holdRect.right - holdRect.left);
                            */
                        }
                        InvalRect(tempRect);
                        HUnlock(*newTemp);
                        HUnlock((Handle)*tempPtr);
                        
                    } else {
                        HUnlock((Handle)*tempPtr);
                        tempPtr += 1;
                    }
                }                                           /* section handle loop jj */
 
                HUnlock(tempHandle);
                HUnlock((Handle)tempWC);
                /* ¥¥¥ NOTE: You'll notice that there is no break or exit from this section searching loop */
                /* Why?  Because there may be many subscribers to the same edition.  The user may */
                /* have multiple subscribtions in the same window, or in any of his or her windows. */
                /* Don't assume that there is only one subscriber (unless you require it, which may be */
                /* reasonable for a single document but _not_ for a multi-document application), run */
                /* your whole list each time to be certain everything gets refreshed */
            }                                               /* if document */
            SpinCursor();
            tempNextWindow = (WindowPtr)((WindowPeek)tempNextWindow)->nextWindow;
        }                                                   /* window loop qq */
        SetPort(tempPort);                                  /* reset the port to what it was when we entered */
    } else {
        if (noErr == (myErr = EditionHasFormat(sRefNum, kGenericTEXTWord, &dataSize))) {
            WindowPtr theWindow;
            windowCHandle tempWC;
            TEHandle tempTEH;
            mySectionDataHandle theTES;
            long tempStart, tempEnd;
            SpinCursor();
            /* it's a text subscription.  That means we search in the text path, and also need */
            /* to update the TEHandle for the window this goes with */
            theWindow = FindSection(theSection);
            theTES = TextSectionFromSecHandle(theSection);
            HLock((Handle)theTES);
            tempWC = (windowCHandle)GetWRefCon(theWindow);
            tempTEH = (*tempWC)->boxHandle;
            /* save the current TE selection range so that the user is returned to the */
            /* place he or she was before we did the reading, so the text doesn't jump */
            /* around all loony on them */
            tempStart = (*tempTEH)->selStart;
            tempEnd = (*tempTEH)->selEnd;
            
            /* first thing we need to do is remove whatever the current sub data in our */
            /* TE Record is.  if there is any, o'course */
            if ((*theTES)->startChar != (*theTES)->endChar) {
                TESetSelect((*theTES)->startChar, (*theTES)->endChar, (TEHandle)tempTEH);
                TEDelete(tempTEH);
            }
            SetHandleSize((*theTES)->additionalData, dataSize);
            HLock((*theTES)->additionalData);
            MyReadEditionData(*(*theTES)->additionalData, kGenericTEXTWord, sRefNum, &dataSize);
            SpinCursor();
            /* that gives us the text.  Now we need to adjust our endpoint */
            (*theTES)->endChar = ((*theTES)->startChar) + dataSize;
            /* set insertion point to where we want to be */
            TESetSelect((*theTES)->startChar, (*theTES)->startChar, tempTEH);
            TEInsert(*(*theTES)->additionalData, dataSize, tempTEH);
            HUnlock((*theTES)->additionalData);
            HUnlock((Handle)theTES);
            /* reset insertion point to what it once was */
            TESetSelect(tempStart, tempEnd, tempTEH);
        }
    }
}
 
/* end MyReadSection */
 
OSErr MyReadEditionData(Ptr readinPtr, DescType typeToGet, EditionRefNum readRef, Size *howMuch)
{
    OSErr myErr;
    if (myErr = ReadEdition(readRef, typeToGet, readinPtr, howMuch))
        CloseEdition(readRef, false);
    else
        CloseEdition(readRef, true);
        if(myErr)ShowMe("\p reading error",myErr,0);
    return(myErr);
}
 
/*  HandleSectionSave handles saving and closing of subscribers for */
/*       a document.  The Boolean flags tell this function wheither to write */
/*       ouut the data [on save or save/close] and weither to UnRegister */
/*       the sections [on close]. */
/*       The resource fork is open on entry. */
/* theWind is locked on entry */
void HandleSectionSave(windowCHandle theWind, Boolean writeEm, Boolean dereg, FSSpec *theSpec)
{
    SectionHandle *theSections;
    Handle *newTemp;
    SectionRecord secRec;
    Handle tempHandle;
    Rect *tempRectPtr;
    register qq;
    OSErr myErr;
    if ((*theWind)->numSubs) {
        Handle *tempPictPtr;
        HLock((*theWind)->subs);
        theSections = (SectionHandle *)*(*theWind)->subs;
        /* and display rectangles */
        HLock((*theWind)->subRects);
        HLock((*theWind)->subDataHandle);
        newTemp = (Handle *)*((*theWind)->subRects);
        tempPictPtr = (Handle *)*((*theWind)->subDataHandle);
        /* loop through the sections */
        for (qq = 0; qq < (*theWind)->numSubs; qq++) {
            SpinCursor();
            /* first update (or create, if needed, the Ed Manger will know) the alias */
            myErr = AssociateSection(*theSections, theSpec);
            if (myErr)
                ShowMe("\p Assocate", myErr, __LINE__);
            
            
            
            /* write the section handle out... */
            if (writeEm) {
                tempHandle = (Handle)*theSections;
                HandToHand(&tempHandle);
                HLock((Handle)*theSections);                /* lock down the original section so we can work with it */
                secRec = *(*(*theSections));                /* just for easier display below */
                AddResource(tempHandle, rSectionType, secRec.sectionID, "");
                /* now do the same with the alias record please */
                tempHandle = (Handle)secRec.alias;
                HandToHand(&tempHandle);
                AddResource(tempHandle, rAliasType, secRec.sectionID, "");
                HUnlock((Handle)*theSections);
                /* save off the display rect for this sub */
                tempHandle = *newTemp;
                HandToHand(&tempHandle);
                AddResource(tempHandle, kRECTType, secRec.sectionID, "");
                /* and save out the picture data, so we don't need to immediatly do a */
                /* section read when the file is opened */
                tempHandle = *tempPictPtr;
                HandToHand(&tempHandle);
                AddResource(tempHandle, kGenericPICTWord, secRec.sectionID, "");
            }                                               /* writeEm if */
            
            if (dereg) {
                UnRegisterSection(*theSections);
                /* and dispose of the alias handle */
                DisposeHandle((Handle)*(*(*theSections))->alias);
                /* and the section handle */
                DisposeHandle((Handle)*theSections);
                /* and the rectangle handle */
                DisposeHandle((Handle)*newTemp);
                /* picture handle disposed in closewindow */
            }
            theSections += 1;                               /* go to next section handle please */
            newTemp += 1;                                   /* and next rectangle */
        }
        HUnlock((*theWind)->subRects);
        HUnlock((*theWind)->subs);
    }                                                       /* end subscriber save section */
    /* now do the same thing for our publishers please */
    /* Of course, here you'll also write the data if pumAutomatic is set */
    
    if ((*theWind)->numPubs) {
        SpinCursor();
        HLock((*theWind)->pubs);
        theSections = (SectionHandle *)*(*theWind)->pubs;
        /* and display rectangles */
        HLock((*theWind)->pubRects);
        tempRectPtr = (Rect *)*((*theWind)->pubRects);
        
        /* loop through the sections */
        for (qq = 0; qq < (*theWind)->numPubs; qq++) {
            SpinCursor();
            /* first update (or create, if needed, the Ed Manger will know) the alias */
            AssociateSection(*theSections, theSpec);
            /* write the section handle out... */
            if (writeEm) {
                tempHandle = (Handle)*theSections;
                HandToHand(&tempHandle);
                HLock((Handle)*theSections);                /* lock down the original section so we can work with it */
                secRec = *(*(*theSections));                /* just for easier display below */
                AddResource(tempHandle, rSectionType, secRec.sectionID, "");
                SpinCursor();
                /* now do the same with the alias record please */
                tempHandle = (Handle)secRec.alias;
                HandToHand(&tempHandle);
                
                AddResource(tempHandle, rAliasType, secRec.sectionID, "");
                SpinCursor();               
                HUnlock((Handle)*theSections);
                /* save off the display rect for this pub */
                
                tempHandle = NewHandle(sizeof(Rect));
                PtrToHand((Ptr)tempRectPtr, &tempHandle, sizeof(Rect));
                HandToHand(&tempHandle);
                AddResource(tempHandle, kRECTType, secRec.sectionID, "");
                SpinCursor();               
                if (secRec.mode == pumOnSave) {
                    MyUpdateEdition(*theSections);
                    /* and indicate that this was saved with a document */
                    (*(*theSections))->refCon |= kSavedOnce;        /* OR in our saved flag with type */
                }
            }                                               /* writeEm if for pubs */
            
            if (dereg) {
                UnRegisterSection(*theSections);
                /* first see if this publisher has ever been saved with a document.  If it hasn't */
                /* then we'll delete it.  */
                if (((*(*theSections))->refCon & 0xf0) == kNeverSaved) {
                    OSErr myErr;
                    FSSpec deleteSpec;
                    Boolean myWasChanged;
                    ResolveAlias(nil, ((*(*theSections))->alias), &deleteSpec, &myWasChanged);
                    SpinCursor();                   
                    if (myErr = DeleteEditionContainerFile(&deleteSpec)) {
                        ShowMe("\pDelete Editon", myErr, __LINE__);
                    }
                }
                
                /* and dispose of the alias handle */
                DisposeHandle((Handle)*(*(*theSections))->alias);
                /* and the section handle */
                DisposeHandle((Handle)*theSections);
                
            }
            theSections += 1;                               /* go to next section handle please */
            tempRectPtr += 1;                               /* and next rectangle */
        }
        HUnlock((*theWind)->pubRects);
        HUnlock((*theWind)->pubs);
    }
    /* now save off any text sections in this document */
    if ((*theWind)->textSections) {
        mySectionDataHandle tempTS = (*theWind)->textSections;
        do {
            SpinCursor();
            tempHandle = (Handle)(*tempTS)->theSection;
            /* make sure the text is the latest */
            RePackText(tempTS, (*theWind)->boxHandle);
            AssociateSection((SectionHandle)tempHandle, theSpec);
            
            if (writeEm) {
                HandToHand(&tempHandle);
                myErr = MemError();
                if (myErr)
                    ShowMe("\p memerr", myErr, __LINE__);
                HLock(tempHandle);                          /* lock down the original section so we can work with it */
                secRec = *(*(SectionHandle)tempHandle);     /* just for easier display below */
                AddResource(tempHandle, rSectionType, secRec.sectionID, "");
                SpinCursor();
                /* save the alias */
                tempHandle = (Handle)secRec.alias;
                HandToHand(&tempHandle);
                AddResource(tempHandle, rAliasType, secRec.sectionID, "");
                SpinCursor();
                /* now save a copy of my whole text record */
                
                tempHandle = (Handle)tempTS;
                HandToHand(&tempHandle);
                /* use the same ID number as the section, make things easy */
                /* zap any forward link in this, so StoreSection doesn't get */
                /* confused when the section is read back in */
                (*(mySectionDataHandle)tempHandle)->nextSection = nil;
                (*(mySectionDataHandle)tempHandle)->additionalData = nil;
                (*(mySectionDataHandle)tempHandle)->theSection = nil;
                AddResource(tempHandle, rMyTextRecordType, secRec.sectionID, "");
                
                /* and finally, the associated text */
                tempHandle = (*tempTS)->additionalData;
                HandToHand(&tempHandle);
                AddResource(tempHandle, rMyTextBlock, secRec.sectionID, "");
                SpinCursor();
                if (secRec.kind == stPublisher && secRec.mode == pumOnSave) {
                    MyUpdateEdition((*tempTS)->theSection);
                    /* and indicate that this was saved with a document */
                    (*(*tempTS)->theSection)->refCon |= kSavedOnce;     /* OR in our saved flag with type */
                }
            }                                               /* text writeem if */
            
            if (dereg) {
                UnRegisterSection((SectionHandle)tempHandle);
                /* first see if this publisher has ever been saved with a document.  If it hasn't */
                /* then we'll delete it.  */
                if (((*(*theSections))->refCon & 0xf0) == kNeverSaved && (*(*theSections))->kind == stPublisher) {
                    OSErr myErr;
                    FSSpec deleteSpec;
                    Boolean myWasChanged;
                    ResolveAlias(nil, (*(SectionHandle)tempHandle)->alias, &deleteSpec, &myWasChanged);
                    if (myErr = DeleteEditionContainerFile(&deleteSpec)) {
                        ShowMe("\pSection Save Delete Editon", myErr, __LINE__);
                    }
                }
                
                /* and dispose of the alias handle */
                DisposeHandle((Handle)(*(SectionHandle)tempHandle)->alias);
                /* and the section handle */
                DisposeHandle((Handle)tempHandle);
                
            }
            tempTS = (*tempTS)->nextSection;
        }
                while (tempTS);
        
    }
}
 
/* MyCancelSection cancels this section.  It removes  */
/*  the section info from our window structure, and also de-registers the */
/* section with (from) the Edition Manager.  If it's a publisher, it also  */
/* deletes the edition file  */
 
void MyCancelSection(SectionHandle inSection, WindowPtr theWindow)
{
    OSErr myErr;
    windowCHandle shortName;
    SectionHandle *tempPtr;
    Rect *tempRectPtr;
    register qq;
    FSSpec deleteSpec;
    Boolean myWasChanged;
    shortName = (windowCHandle)GetWRefCon(theWindow);
    HLock((Handle)shortName);
    
    /* first thing to do is deregister the thing */
    UnRegisterSection(inSection);
    if ((*inSection)->kind == stPublisher) {                /* only delete publishers */
        ResolveAlias(nil, ((*inSection)->alias), &deleteSpec, &myWasChanged);
        if (myErr = DeleteEditionContainerFile(&deleteSpec)) {
            ShowMe("\pCancel Delete Editon", myErr, __LINE__);
        }
    }
    /* get rid of the alias handle for it */
    DisposeHandle((Handle)(*inSection)->alias);
    if ((*inSection)->kind == stPublisher) {
        HLock((*shortName)->pubs);                          /* lock down my list of section handles */
        tempPtr = (SectionHandle *)*(*shortName)->pubs;
        for (qq = 0; qq < (*shortName)->numPubs; qq++) {
            HLock((Handle)*tempPtr);
            if ((*inSection)->sectionID == (*(*tempPtr))->sectionID) {
                DisposeHandle((Handle)inSection);
                DisposeHandle((Handle)(*(*tempPtr))->alias);
                DisposeHandle((Handle)*tempPtr);
                HLock((*shortName)->pubRects);
                tempRectPtr = (Rect *)*((*shortName)->pubRects);
                tempRectPtr += qq;
                if (qq != (*shortName)->numPubs) {
                    register ii;                            /* need to move information down */
                    for (ii = qq; ii < ((*shortName)->numPubs) - 1; ii++) {
                        *tempPtr = *(tempPtr + 1);
                        *tempRectPtr = *(tempRectPtr + 1);
                        tempPtr += 1;
                        tempRectPtr += 1;
                    }
                }
                (*shortName)->numPubs--;
                HUnlock((*shortName)->pubs);
                MySetHandleSize((*shortName)->pubs, GetHandleSize((*shortName)->pubs) - sizeof(Handle));
                HUnlock((*shortName)->pubRects);
                MySetHandleSize((*shortName)->pubRects, (GetHandleSize((*shortName)->pubRects) - sizeof(Rect)));
                
            }
        }
    } else {                                                /* it's a subscriber */
        
        HLock((*shortName)->subs);                          /* lock down my list of section handles */
        tempPtr = (SectionHandle *)*(*shortName)->subs;
        for (qq = 0; qq < (*shortName)->numSubs; qq++) {
            
            HLock((Handle)*tempPtr);
            if ((*inSection)->sectionID == (*(*tempPtr))->sectionID) {
                SectionHandle removeSection;
                Handle *tempRectHand;
                Handle *tempPicHand;
                Handle *tempPicHand2;
                removeSection = (*tempPtr);
                HLock((Handle)removeSection);
                /* When the user cancels a subscription, you do NOT want to delete the */
                /* current subscription data (the picture) at this time.  Since the data should be */
                /* selectable in the document they are working on (text in a text doc, pic in a */
                /* pic doc, etc) they keep the last subscription data, and delete it */
                /* seperatly if they'd like */
                HLock((*shortName)->subRects);
                HLock((*shortName)->subDataHandle);
                tempRectHand = (Handle *)*((*shortName)->subRects);
                tempPicHand = (Handle *)*((*shortName)->subDataHandle);
                tempRectHand += qq;
                tempPicHand += qq;
                
                /* move the picture over, increase the handle by 1 */
                (*shortName)->numPicts++;
                HUnlock((*shortName)->pictHandle);
                MySetHandleSize((*shortName)->pictHandle, (GetHandleSize((*shortName)->pictHandle) + sizeof(Handle)));
                HLock((*shortName)->pictHandle);
                tempPicHand2 = (Handle *)*(*shortName)->pictHandle;
                tempPicHand2 += ((*shortName)->numPicts) - 1;
                *tempPicHand2 = *tempPicHand;
                /* move the rect over also */
                HUnlock((*shortName)->pictRects);
                MySetHandleSize((*shortName)->pictRects, (GetHandleSize((*shortName)->pictRects) + sizeof(Handle)));
                HLock((*shortName)->pictRects);
                tempPicHand2 = (Handle *)*(*shortName)->pictRects;
                tempPicHand2 += ((*shortName)->numPicts) - 1;
                *tempPicHand2 = *tempRectHand;
                HUnlock((*shortName)->pictRects);
                HUnlock((*shortName)->pictHandle);
                if ((qq + 1) != (*shortName)->numSubs) {
                    register ii;                            /* need to move information down */
                    for (ii = qq; ii < ((*shortName)->numSubs) - 1; ii++) {
                        *tempPtr = *(tempPtr + 1);
                        *tempRectHand = *(tempRectHand + 1);
                        *tempPicHand = *(tempPicHand + 1);
                        tempPtr += 1;
                        tempRectHand += 1;
                        tempPicHand += 1;
                    }
                }
                (*shortName)->numSubs--;
                HUnlock((*shortName)->subs);
                MySetHandleSize((*shortName)->subs, GetHandleSize((*shortName)->subs) - sizeof(SectionHandle));
                HUnlock((*shortName)->subRects);
                MySetHandleSize((*shortName)->subRects, (GetHandleSize((*shortName)->subRects) - sizeof(Handle)));
                
            }
        }
    }
    HUnlock((Handle)shortName);
    /* and clear the highlight */
    if (gShowPub || gShowSub) {
        extern Rect gShowPubRect;
        extern Rect gShowSubRect;
        extern SectionHandle gShowingSecHandle;
        gShowPub = gShowSub = false;
        gShowingSecHandle = nil;
        InvalRect(&gShowPubRect);
        InvalRect(&gShowSubRect);
    }
}
 
/* end MyCancelSection */
 
void StoreSubscriber(windowCHandle shortName, SectionHandle secHandle, Handle inRect, Handle pictIn)
{
    OSErr myErr;
    SectionHandle *tempPtr;
    Handle *tempPicHand;
    Size dataSize;
    EditionRefNum sRefNum;
    /* first we need to determine if this is a PICT or TEXT subscription, since I'm handling */
    /* them differently for drill. */
    myErr = OpenEdition(secHandle, &sRefNum);
    if (myErr = EditionHasFormat(sRefNum, kGenericPICTWord, &dataSize))
        (*secHandle)->refCon |= kTextType;
    else
        (*secHandle)->refCon |= kPictType;
    /* Now that little mechanism could screw up, if the formats of the section have been */
    /* changed since the subscription was originally created.  But it'll work here */
    CloseEdition(sRefNum, true);
    
    /* increase our section handle holding handle by the size of a handle */
    if (((*secHandle)->refCon & 0xf) == kPictType) {
        HUnlock((*shortName)->subs);
        MySetHandleSize((*shortName)->subs, GetHandleSize((*shortName)->subs) + sizeof(SectionHandle));
        HLock((*shortName)->subs);
        /* dereference the handle to our section handles in our window structure */
        /* and cast it to a pointer to section handles, since that's what it contains */
        tempPtr = (SectionHandle *)((*(*shortName)->subs) + (sizeof(SectionHandle) * ((*shortName)->numSubs)));
        /* and store our subscriber section */
        *tempPtr = (SectionHandle)secHandle;
        HUnlock((*shortName)->subs);                        /* let it float again */
        /* Here I'm setting up a handle for the picture data contained in the edition we just */
        /* subscribed to, in an array of handles held in the handle subDataHandle  */
        HUnlock((*shortName)->subDataHandle);
        MySetHandleSize((*shortName)->subDataHandle, GetHandleSize((*shortName)->subDataHandle) + sizeof(Handle));  /* allocate */
        HLock((*shortName)->subDataHandle);
        /* deref it */
        tempPicHand = (Handle *)*((*shortName)->subDataHandle);
        tempPicHand += ((*shortName)->numSubs);
        
        if (pictIn == nil)
            *tempPicHand = NewHandle(0);                    /* set up a nil handleo */
        else
            *tempPicHand = pictIn;
        /* ¥¥¥ NOTE:  You do _NOT_ read the data contained in this section yet! */
        /* All you have done is subscribed to it, the Edition Manager has not told you */
        /* that you can read it!  Wait for the section read event (see below) to get the */
        /* data.  SO I store an empty handle here as a placeholder */
        MoveHHi(*tempPicHand);
        HUnlock((*shortName)->subRects);
        MySetHandleSize((*shortName)->subRects, (GetHandleSize((*shortName)->subRects) + sizeof(Handle)));  /* allocate a new re*/
        myErr = MemError();
        if (myErr)
            ShowMe("\pMemory error ", myErr, __LINE__);
        HLock((*shortName)->subRects);
        /* generate an empty display rectangle handle also */
        tempPicHand = (Handle *)*((*shortName)->subRects);
        tempPicHand += ((*shortName)->numSubs);
        
        if (inRect == nil)
            *tempPicHand = NewHandle(0);                    /* set up a nil handleo */
        else
            *tempPicHand = inRect;
        MoveHHi(*tempPicHand);
        (*shortName)->numSubs++;                            /* increment our count of subscribers */
        HUnlock((*shortName)->subRects);
        HUnlock((*shortName)->subDataHandle);
    } else {
        if (((*secHandle)->refCon & 0xf) == kTextType) {        /* double checking here */
            mySectionDataHandle newSection;
            /* get a new text section record */
            if (inRect == nil) {
                /* this means that it is being created fresh, so we have to get a */
                /* text section record from my routine */
                newSection = GetTextSection(shortName, stSubscriber);
                /* fill it with stuff relating to the section we just created */
                (*newSection)->publishing = false;
                (*newSection)->theID = (*secHandle)->sectionID;
                (*newSection)->theSection = secHandle;
            } else {
                newSection = (mySectionDataHandle)inRect;
            }
            /* store it in our window structure */
            if ((*shortName)->textSections) {
                mySectionDataHandle tempSection = (*shortName)->textSections;
                if ((*shortName)->textSections) {
                    while ((*tempSection)->nextSection)
                        tempSection = (*tempSection)->nextSection;
                }
                (*tempSection)->nextSection = newSection;
                
            } else {
                /* first one */
                (*shortName)->textSections = newSection;
            }
        }
    }
}
 
pascal short SubExpOptHook(short itemOffset, short itemHit, DialogPtr theDialog, Ptr yourDataPtr)
{
#pragma unused (yourDataPtr)
    short myHit;
    short itemType;
    ControlHandle theButton;
    Rect theRect;
    /* first make sure that a sub-dialog is not frontmost */
    /* so we don't filter keys or hits to a sub-dialog */
    if (GetWRefCon((WindowPtr)theDialog) == sfMainDialogRefCon || GetWRefCon((WindowPtr)theDialog) == emOptionsDialogRefCon) {
        /* first see if it's the 'first call' item (see the Standard File chapter).  If it is, then */
        /* we preset our check box */
        if (itemHit == -1) {
            /* this gets the handle to our check box, since we know it's one past the last standard item */
            GetDialogItem(theDialog, itemOffset + 1, &itemType, (Handle *)&theButton, &theRect);
            SetControlValue(theButton, gResizeSub);             /* and set our current value */
        } else {
            /* only have one item in this expansion, but we'll check the range anyway to be safe */
            myHit = itemHit - itemOffset;                   /* since our item numbers are relative to the total number */
            /* of items in the dialog, and the system may change.  Always do your item numbering based */
            /* on the offset, this will prevent incompatability when the system dialog grows or shrinks */
            if (myHit == 1) {                               /* I only added one item, so this be the one */
                /* Pass itemHit here, not myHit, since the dialog manager has no idea that this is an */
                /* additive dialog.  It is counting from the actual start of the DITL, not the start of */
                /* your custom items */
                GetDialogItem(theDialog, itemHit, &itemType, (Handle *)&theButton, &theRect);
                if (GetControlValue(theButton))
                    gResizeSub = false;
                else
                    gResizeSub = true;
                SetControlValue(theButton, gResizeSub);
            }
        }
    }
    return(itemHit);                                        /* the return value must be absolute */
}
 
pascal Boolean SubExpOptFilter(DialogPtr theDialog, EventRecord *theEvent, short itemOffset, short *itemHit, Ptr yourDataPtr)
{
#pragma unused (itemHit,yourDataPtr) 
    short itemType;
    ControlHandle theButton;
    Rect theRect;
    /* first make sure that a sub-dialog is not frontmost */
    /* so we don't filter keys or hits to a sub-dialog */
    if (GetWRefCon((WindowPtr)theDialog) == sfMainDialogRefCon || GetWRefCon((WindowPtr)theDialog) == emOptionsDialogRefCon) {
        /* standard filter proc kinda stuff here */
        if ((theEvent->what) == keyDown) {
            char tempChar;
            tempChar = theEvent->message & charCodeMask;
            
            if (((tempChar == 'A') || (tempChar == 'a')) && (theEvent->modifiers & cmdKey)) {
                /* they pressed an A with the command key down, we get to handle it. */
                GetDialogItem(theDialog, itemOffset + 1, &itemType, (Handle *)&theButton, &theRect);
                if (GetControlValue(theButton))
                    gResizeSub = false;
                else
                    gResizeSub = true;
                SetControlValue(theButton, gResizeSub);
                return(true);                               /* tell folks we handled it */
            }
        }
    }
    return(false);                                          /* was not a keystroke we wanted */
    
}
 
/* DeleteSubscriber is called by a menu command 'Clear' */
 
void DeleteSubscriber(void)
{
    ModalFilterUPP upp = NewModalFilterProc(standardAlertFilter);
    if (StopAlert(kCanxSub, upp) == 2) {
        MyCancelSection(gShowingSecHandle, FindSection(gShowingSecHandle));
        
    }
    DisposeRoutineDescriptor(upp);
}
 
/* end DeleteSubscriber */
 
/* PasteSubscription pastes the section (a subscriber) from the clipboard into the */
/* frontmost window (as you would expect) */
void PasteSubscription(void)
{
    
    windowCHandle tempWC;
    SectionHandle tempHandle;
    AliasHandle tempHandle2;
    FSSpec newFileSpec;
    Boolean myWasChanged;
    Rect tempPRect =  {
        0, 0, 40, 40
    };
    long myOffset;
    long fred;
    Handle tempRectHand = NewHandle(sizeof(Rect));
    /* first see if there is a section handle on the clipboard */
    /* kill the current section on the clipboard, if there is one */
    /* ¥¥¥¥ NEW, we're looking for section handles and aliases on the clipboard.  */
    
    /* set up a dummy picture for this incoming section.... */
    if (!gScrapData)
        gScrapData = NewHandle(0);
    fred = GetScrap(gScrapData, rSectionType, &myOffset);
    if (fred > 0) {                                         /* if there is a section on the clipboard */
        myOffset = 0;
        /* read in the rect also */
        
        fred = GetScrap(tempRectHand, kRECTType, &myOffset);
        
        if (fred > 0) {
            short offH, offV;
            /* move the rect to the upper left */
            offH = (*(Rect *)*tempRectHand).right - (*(Rect *)*tempRectHand).left;
            offV = (*(Rect *)*tempRectHand).bottom - (*(Rect *)*tempRectHand).top;
            (*(Rect *)*tempRectHand).left = 0;
            (*(Rect *)*tempRectHand).top = 0;
            (*(Rect *)*tempRectHand).right = offH;
            (*(Rect *)*tempRectHand).bottom = offV;
            /* and read in the pict */
            myOffset = 0;
            GetScrap((Handle)gClipPict, kGenericPICTWord, &myOffset);
        } else {
            *(Rect *)*tempRectHand = tempPRect;             /* default it */
        }
    }
    HLock(tempRectHand);
    tempWC = (windowCHandle)GetWRefCon(FrontWindow());
    HLock((Handle)tempWC);
    if (gClipPict && GetHandleSize((Handle)gClipPict)) {
        InvalRect((Rect *)*tempRectHand);
        
    } else {
        *(Rect *)(*tempRectHand) = tempPRect;
    }
    /* update the ID of the section to include the master ID of the window yer pasting into */
    (*gClipSection)->sectionID += (*tempWC)->windowID;
    StoreSubscriber(tempWC, gClipSection, tempRectHand, (Handle)gClipPict);
    HUnlock((Handle)tempWC);
    /* Now, after you paste the subscription, you have to change the subscription on the clipboard. */
    /* You need to duplicate it, and assign a new ID number, since if the thing is pasted again */
    /* you could have two subscriptions with the same ID, which would not be nice.  So we do this... */
    tempHandle = gClipSection;
    tempHandle2 = (*gClipSection)->alias;
    HandToHand((Handle *)&tempHandle);
    HandToHand((Handle *)&tempHandle2);
    (*tempHandle)->sectionID = gSectionID;
    (*tempHandle)->alias = tempHandle2;
    gSectionID++;
    /* now register the section so the edition manager knows to send you updates */
    ResolveAlias(nil, tempHandle2, &newFileSpec, &myWasChanged);
    if ((RegisterSection(&newFileSpec, tempHandle, &myWasChanged))==noErr)
        gClipSection = tempHandle;
    gClipHasContents = kClipHasSub;
    MyReadSection(tempHandle);
    
}
/* CutSubscription and CopySubscription move the current selection in the active window to the */
/* ClipBoard.  The main difference here from standard scrap handling is that the scrap you now */
/* have is dynamic.  The contents of the clipboard can change if the publisher of this subscription */
/* changes, so you must treat this section as you would any other subscriber */
/* frontmost window (as you would expect) */
void CutSubscription(void)
{
    CopySubscription();
    DeleteSubscriber();                                     /* even though they said cut, I want to make sure that they really mean it */
}
/* CopySubscriber moves the current display subscriber to the clipboard, making a new */
/* subscription in the process, since we don't want to have two copies of the same thing */
void CopySubscription(void)
{
    SectionHandle tempHandle;
    AliasHandle tempHandle2;
    FSSpec newFileSpec;
    Boolean myWasChanged;
    /* First check to see if there is already a section to remove */
    if (gClipHasContents == kClipHasSub) {
        KillClipSub();
    }
    tempHandle = gShowingSecHandle;
    /* copy the alias also */
    tempHandle2 = (*gShowingSecHandle)->alias;
    HandToHand((Handle *)&tempHandle);
    HandToHand((Handle *)&tempHandle2);
    /* create a unique ID for this section.  I'll just use the next section ID */
    (*tempHandle)->sectionID = gSectionID;
    (*tempHandle)->alias = tempHandle2;
    gSectionID++;
    /* now register the section so the edition manager knows to send you updates */
    ResolveAlias(nil, tempHandle2, &newFileSpec, &myWasChanged);
    if ((RegisterSection(&newFileSpec, tempHandle, &myWasChanged))==noErr)
        gClipSection = tempHandle;
    gClipPict = (PicHandle)NewHandle(0);                    /* allocate an empty handle for this picture data */
    gClipHasContents = kClipHasSub;
    /* write the section handle out to the cipboard */
    ZeroScrap();
    PutScrap(sizeof(Handle), rSectionType, (Ptr)&tempHandle);
    PutScrap(sizeof(Rect), kRECTType, (Ptr)&gShowSubRect);
    
    MyReadSection(tempHandle);
    
    InitCursor();                                           /* set to watch by MyReadSection, would normally be reset next pass */
    /* through the event loop, but NOT if it's being called by Cut, */
    /* so I'll reset it just to be safe */
}
 
OSErr ReadClipSection(Size readIn, EditionRefNum sRefNum)
{OSErr myErr = noErr;
    extern Handle gScrapData;
    MySetHandleSize((Handle)gClipPict, readIn);
    HLock((Handle)gClipPict);
    /* read the pict in */
    myErr = MyReadEditionData((Ptr)*gClipPict, kGenericPICTWord, sRefNum, &readIn);
    HUnlock((Handle)gClipPict);
    gScrapData = (Handle)gClipPict;
    if (((WindowPeek)FindClipWindow())->visible) {
        WindowPtr temp;
        GetPort(&temp);
        SetPort(FindClipWindow());
        InvalRect(&FindClipWindow()->portRect);
        SetPort(temp);
    }   
return(myErr);
}
/* This kills the current section on the clipboard, since it's being replaced */
/* and you don't want to receive events for it anymore */
void KillClipSub(void)
{
    UnRegisterSection(gClipSection);
    DisposeHandle((Handle)(*gClipSection)->alias);
    DisposeHandle((Handle)gClipSection);
    gClipSection = nil;
    gClipHasContents = kClipEmpty;
    if (GetHandleSize((Handle)gClipPict) != nil)
        KillPicture(gClipPict);
}
 
/* MyGoToPublisher is used if the user was holding down the Option key during a */
/* double click, to send them to the publisher without seeing the dialog box */
OSErr MyGoToPublisher(SectionHandle theSection)
{
    EditionInfoRecord theEdInfo;
    
    GetEditionInfo(theSection, &theEdInfo);
    return(GoToPublisherSection(&theEdInfo.container));
}
 
/* Searches the subcriber list, hilites the selection, and drags it */
/* This is very similar to the publisher check, but has added functionality */
/* for dragging the subscriber around the window */
Boolean SearchSubs(Point thePoint)
{
    register qq;
    Str63 pubString;
    Handle *theRectsHandle;
    Boolean subGotIt = false;
    windowCHandle shortname = (windowCHandle)GetWRefCon(FrontWindow());
    HLock((Handle)shortname);
    if ((*shortname)->numSubs) {                            /* does it have any subscribers? */
        HLock((*shortname)->subRects);                      /* lock down the rect handle */
        /* cast it as a pointer to handles for reading ease */
        theRectsHandle = (Handle *)*(*shortname)->subRects;
        for (qq = 0; qq < (*shortname)->numSubs; qq++) {        /* step through the subscribers */
            SectionHandle *tempPtr;
            Rect *checkRect;
            Rect cornerRect;
            HLock(*theRectsHandle);
            checkRect = (Rect *)**theRectsHandle;
            /* did they click in this rect? */
            InsetRect(checkRect, kNegFour, kNegFour);                   /* include the possible borders */
            if (PtInRect(thePoint, checkRect)) {            /* yes */
                /* erase the old display rectangles, if there are any */
                if (gShowSub){
                    InsetRect(&gShowSubRect, kNegFour, kNegFour);
                    InvalRect(&gShowSubRect);
                    InsetRect(&gShowSubRect, kFour, kFour);
 
                    }
                gShowSub = true;
                if (gShowPub) {
                    InvalRect(&gShowPubRect);
                    gShowPub = false;
                }
                /* get the section handle for this section */
                HLock((*shortname)->subs);
                tempPtr = (SectionHandle *)*(*shortname)->subs;
                tempPtr += qq;
                gShowingSecHandle = *tempPtr;
                HUnlock((*shortname)->subs);
                /* change the menu item name now */
                GetIndString(pubString, kGeneralStrings, kSubOptString);
                
                SetMenuItemText(gEditMenuHandle, kSoptionsItem,pubString);
                
                InvalRect(checkRect);                       /* make sure it gets redrawn */
                /* now I want the actual rect values so I can drag it around */
                /* in response to the user */
                gShowSubRect = *checkRect;
                PenPat(&qd.dkGray);
                PenSize(3, 3);
                FrameRect(&gShowSubRect);
                PenSize(1, 1);
                /* Here you drag the thing around to where the user wants it, updating the 
                *   window record as you do it. */
                GetMouse(&thePoint);
                InvalRect(&gShowSubRect);
                /* two choices here.  They could be dragging the whole thing, or resizing it.  */
                /* The resize box is in the lower right ten pixels, I'll say, so if the original */
                /* click is there I'll go to the resize routine */
                cornerRect = gShowSubRect;
                cornerRect.top = cornerRect.bottom - 7;
                cornerRect.left = cornerRect.right - 7;
                if (PtInRect(thePoint, &cornerRect) && gResizeSub) {
                    
                    PullRect(shortname, &gShowSubRect, false, true,true);
                    
                } else {
                    while (StillDown()) {                   /* keep doing it until they release the mouse */
                        Point tempPoint;
                         PenMode(patXor);
                         FrameRect(&gShowSubRect);           /* nasty way to put up a flashing border for the drag */
                         FrameRect(&gShowSubRect);
                        GetMouse(&tempPoint);
                        /* keep inside the window please, don't let them drag the */
                        /* rectangle outside the window bounds */
                        if (PtInRect(tempPoint, &(FrontWindow()->portRect))) {
                            if (tempPoint != thePoint) {
                                OffsetRect(&gShowSubRect, tempPoint.h - thePoint.h, tempPoint.v - thePoint.v);
                                thePoint = tempPoint;
                            }
                        }
                    }
                    PenMode(normal);
                }
                InvalRect(&gShowSubRect);
                InsetRect(checkRect, kFour, kFour);                 /* remember that ShowingRect is kFour bigger */
                InsetRect(&gShowSubRect, kFour, kFour);                 /* remember that ShowingRect is kFour bigger */
 
                if (gShowSubRect != *checkRect) {           /* don't update if they didn't end up moving it */
 
 
                        *checkRect = gShowSubRect;          /* update our record of things */
                }
 
                
                
                subGotIt = true;
            } else {
            /* shrink it back agin */
            InsetRect(checkRect, kFour, kFour);                 /* remember that ShowingRect is kFour bigger */
 
            }
            HUnlock(*theRectsHandle);
            theRectsHandle += 1;                            /* increase by one Rect to check next */
            if (subGotIt)
                break;
        }
        HUnlock((*shortname)->subRects);
    }
    HUnlock((Handle)shortname);
    return(subGotIt);
}
 
/* end SearchSubs */
 
 
 
 
#undef __SUBSCRIBE__