Windows.c

/*------------------------------------------------------------------------------
*
*  Apple Developer Technical Support
*
*  
*
*  Program: AEObject-Edition Sample
*  File:   Windows.c -C Source
*
*  by: C.K. Haun <TR>
*
*  Copyright © 1990-1992 Apple Computer, Inc.
*  All rights reserved.
*
*------------------------------------------------------------------------------
* This file contains some of our window handling routines.   
* It also contains the clipboard handlers
*----------------------------------------------------------------------------*/
 
#define __MYWINDOWS__
 
#include "Sampdefines.h"
 
#pragma segment MyWindows
static void DragPictOrObject(Point *where, windowCHandle tempWC);
 
/* AddNewWindow creates and initializes a new document window. */
/* It returns false in this example if there are already 10 windows open. */
 
WindowPtr AddNewWindow(Boolean showIt)
{
    windowCHandle setControls;
    WindowPtr tempWP;
    Handle tempHand;
    short cnt = 0;
    Str31 wtitle;
    tempWP = GetNewWindow(kDocWindow, 0, (WindowPtr)-1);        /* get a new window */
    ((WindowPeek)tempWP)->windowKind = kDocumentWindow;     /* mark it as a document window */
    tempHand = NewHandleClear(sizeof(windowControl));       /* add our control structure to it */
    ((WindowPeek)tempWP)->refCon = tempHand;                /* and attach the controller to the window */
    setControls = (windowCHandle)((WindowPeek)tempWP)->refCon;      /* and put it where we can use it */
    HLock((Handle)setControls);                             /* lock it down while we fill it*/
    
    /* add pointers to our procedures for drawing, saving, and closing */
    /* This way, all I need is one dispatch point for drawing, closing */
    /* or whatever, I don't have to case off the window kind to go to the  */
    /* correct routine.  Kinda like object-oriented programming, but I won't */
    /* admit that. */
    (*setControls)->drawMe = (ProcPtr)DrawFull;
    (*setControls)->saveMe = (ProcPtr)SaveMe;
    (*setControls)->closeMe = (ProcPtr)CloseMyWindow;
    (*setControls)->clickMe = (ProcPtr)DoDocumentClick;
    (*setControls)->sizeMe = (ProcPtr)NilProc;
    /* now initialize all our required handles */
    (*setControls)->pubs = NewHandle(0);
    (*setControls)->pubRects = NewHandle(0);
    (*setControls)->numPubs = 0;
    (*setControls)->subs = NewHandle(0);
    (*setControls)->subRects = NewHandle(0);
    (*setControls)->subDataHandle = NewHandle(0);
    (*setControls)->numSubs = 0;
    (*setControls)->pictHandle = NewHandle(0);
    (*setControls)->pictRects = NewHandle(0);
    (*setControls)->numPicts = 0;
    /* init shapes */
    (*setControls)->theShapes = nil;
    (*setControls)->numShapes = 0;
    /* initialize our control codes and counts */
    (*setControls)->currentAction = 0;
    (*setControls)->undoAction = 0;
    (*setControls)->hasSelection = false;
    (*setControls)->windowDirty = false;
    /* I am using this window ID to identify the sections (publishers and subscribers) */
    /* that are associated with this window */
    (*setControls)->windowID = gMasterWindowID;
    gMasterWindowID += 10000;                               /* update for next window */
    /* clear the file spec for the file this document will be saved to */
    /* since the handle is nil, I know this window hasn't been saved yet. */
    (*setControls)->fileAliasHandle = (AliasHandle)NewHandle(0);
    (*setControls)->boxHandle = nil;                        /* no textedit field */
    (*setControls)->textSections = nil;
    /* if there already is a window (or more) add a count to this title */
    if (showIt) {
        short docWCount = 0;
        WindowPtr ourWindows = (WindowPtr)LMGetWindowList();                   /* grab the first window from the global WindowList */
        Str32 numOfW;
        GetWTitle(tempWP, wtitle);                          /* get our current title (untitled) */
        while (ourWindows) {                                /* count 'em up */
            if (((WindowPeek)ourWindows)->windowKind == kDocumentWindow)
                docWCount++;                                /* only count doc windows o' course */
            ourWindows = (WindowPtr)((WindowPeek)ourWindows)->nextWindow;
        } /* end ourWindows while */
        /* change the number to text, and append it */
        NumToString((long)docWCount, numOfW);
        AppendString(wtitle, numOfW);
        SetWTitle(tempWP, wtitle);
        ShowWindow(tempWP);                                 /* show it */
    }
    HUnlock((Handle)setControls);
    SetPort(tempWP);
    SetUndo(0, false);                                      /* since it is the current window, set all the actions to default */
    SetCurAction(0);                                        /* initialize the environment for a new window in front */
    SetMyCursor(0);
    SwitchChecks(0);
    SetWMenus(true);
    if (showIt) {
        /* add it's name to our window menu */
        AddToWindowMenu(tempWP, nil);
        ChangePlane(tempWP);
    }
    return(tempWP);
}
 
/* end AddNewWindow */
 
/* CloseMyWindow closes the window and disposes of all the memory 
*   associated with it.  It also calls HandleSections (sic) to UnRegister
* all the editions associated with this window 
*/
 
void CloseMyWindow(WindowPtr theClose)
{
    windowCHandle theWind;
    short alBack;
    register qq;
    OSErr myErr;
    PicHandle *tempPicHandPtr;
    NMRec myNotification;
    Str255 nmWords;
    myNotification.qType =nmType ;
    myNotification.nmMark = nil;
    myNotification.nmIcon = nil;
    myNotification.nmSound = (Handle)-1;
    myNotification.nmStr =&nmWords ;
    myNotification.nmResp =nil ;
 
    theWind = (windowCHandle)GetWRefCon(theClose);
    GetIndString(&nmWords,kGeneralStrings,kBringForward);
    HLock((Handle)theWind);
    /* First see if we need to ask the user if they want to save this window or not */
    if ((*theWind)->windowDirty) {
        ModalFilterUPP upp;
       Str255 windName;
        GetWTitle(theClose, windName);
        ParamText(windName, "", "", "");
        /* No before we can do this, we have to be the frontmost application.  It is */
        /* not proper to put up a ModalDialog if you are not frontmost! */
        /* But we cannot bully ourselves forward, we have got to  */
        /* ask the AppleEvent Manager if we can come forward. */
        /* ¥¥¥¥ YOU MUST ASK TO COME FORWARD!!!!! */
        /*  NEVER force yourself forward.  Bad thing will happen if you do, you will */
        /* be messing up scripting systems if you change layers  */
        /* at will.  So, we do this.... */
            myErr = AEInteractWithUser(kAEDefaultTimeout, &myNotification, gCommonIdleFunctionUPP);
        /* now we've got to check the error.  It is possible that there is NO way that */
        /* we can come forward and bring up a dialog (imagine if this machine were running in another */
        /* room, or late at night, and there was no-one to respond to the dialog) */
        /* So we check like so.... */
        if(myErr == errAENoUserInteraction){
            return; /* we're blowing away the save because we can't talk about it */
        }
        InitCursor();
        upp = NewModalFilterProc(standardAlertFilter);
        alBack = Alert(kDirtyAlert, upp);                   /* Ask 'em */
        DisposeRoutineDescriptor(upp);
        
        if (alBack == ok)                                   /* they said yes, dispatch to the save handler */
            (ProcPtr)(*(theWind))->saveMe(theWind, theClose);
        if (alBack == cancel) {
            /* if they said Cancel, this also tells us that the user does not want to */
            /* quit the application if they were in the midst of shutdown ops.  So, */
            /* reset the stopping flag.  Even if they weren't, this doesn't do any harm */
            gStop = false;
            return;
        }
    }
    /* Save all our subscribers and publishers */
    HandleSectionSave(theWind, false, true, nil);
    /* get rid of all our memory associated with this window */
    DisposeHandle((*theWind)->pubs);
    DisposeHandle((*theWind)->pubRects);
    DisposeHandle((*theWind)->subs);
    DisposeHandle((*theWind)->subRects);
    DisposeHandle((Handle)(*theWind)->fileAliasHandle);
    /* Was there a TextEdit handle??? */
    if ((*theWind)->boxHandle != nil)
        TEDispose((*theWind)->boxHandle);
    /* if there are any pictures, kill them too */
    if ((*theWind)->numPicts) {
        HLock((*theWind)->pictHandle);
        tempPicHandPtr = (PicHandle *)*(*theWind)->pictHandle;
        for (qq = 0; qq < (*theWind)->numPicts; qq++) {     /* rectangles are handled in the HandleSectionSave */
            KillPicture(*tempPicHandPtr);
            tempPicHandPtr += 1;
        }
    }
    DisposeHandle((*theWind)->pictHandle);
    DisposeHandle((*theWind)->pictRects);
    DisposeHandle((Handle)theWind);
    DeleteFromWindowMenu(theClose);
    /* and finally actually close the window */
    CloseWindow(theClose);
    if (FrontWindow()) {
        gShowingSecHandle = nil;
        gShowPub = false;
        gShowSub = false;
        if (((WindowPeek)FrontWindow())->windowKind == kDocumentWindow)
            SetWMenus(true);
    } else {
        SetWMenus(false);
        gShowingSecHandle = nil;
        gShowPub = false;
        gShowSub = false;
    }
    EnableItem(gFileMenuHandle, kOpenItem);
    EnableItem(gFileMenuHandle, kNewItem);
    
} /* end CloseMyWindow */
 
/* DrawFull draws the contents of our document windows */
 
void DrawFull(windowCHandle theWind, WindowPtr theWindPtr)
{
    register qq;
    Rect scratchRect;
    RgnHandle tempRgn;
    RGBColor black = {0,0,0};
    Rect grabRect;
    ShapesHandle theShape;
    /* Are there any shapes in this window? */
    if ((*theWind)->numShapes) {
        theShape = (*theWind)->theShapes;
        /* walk through all the shapes */
        do {
            HLock((Handle)theShape);
            switch ((*theShape)->type) {
                /* Draw whatever type of shape this is */
                case kLineShape:
                    if(gHasColor)
                        RGBForeColor(&(*theShape)->theColor);                       
                    MoveTo((*theShape)->theRect.left, (*theShape)->theRect.top);
                    LineTo((*theShape)->theRect.right, (*theShape)->theRect.bottom);
                    break;
                case kRectShape:
                    if(gHasColor)
                        RGBForeColor(&(*theShape)->theColor);                       
                    FrameRect(&(*theShape)->theRect);
                    break;
                case kOvalShape:
                    if(gHasColor)
                        RGBForeColor(&(*theShape)->theColor);                       
                    FrameOval(&(*theShape)->theRect);
                    break;
            }
            HUnlock((Handle)theShape);
            theShape = (*theShape)->nextShape;
        }while (theShape); /* end of shape list */
    }
if(gHasColor)
    RGBForeColor(&black);                       
    
    /* Is there a TextEdit field in this window? */
    if ((*theWind)->boxHandle != nil) {
        /* If there is a textedit field, there may also be bordered text sections, */
        /* so check for them also */
        Rect framer;
        mySectionDataHandle tempTS = (*theWind)->textSections;
        TEUpdate(&(*theWind)->textBox, (*theWind)->boxHandle);
        framer = (*theWind)->textBox;
        InsetRect(&framer, -3, -2);
        FrameRect(&framer);
        /* step through any possible sections, and border them as needful */
        while (tempTS) {
            if ((*tempTS)->bordered)
                BorderTextSection(tempTS);
            tempTS = (*tempTS)->nextSection;
        } /* end of text section list check */
    }
    
    if ((*theWind)->numSubs) {                              /* are we subscribed to anything? */
        PicHandle *tempHand;
        Handle *tempRHand;
        Rect *tempRect;
        HLock((*theWind)->subDataHandle);                   /* lock down and get the rectangles and */
        HLock((*theWind)->subRects);                        /* current picture data for the subscribers this */
        tempHand = (PicHandle *)*(*theWind)->subDataHandle;     /* window has */
        tempRHand = (Handle *)*(*theWind)->subRects;
        /* cast them into a handy form, and step through the list, drawing each */
        for (qq = 0; qq < (*theWind)->numSubs; qq++) {
            PicHandle tempPic;
            tempPic = *tempHand;
            /* ¥¥¥¥This following check is important!¥¥¥¥ */
            /* No matter what data type you are subscribing to, the data MAY NOT */
            /* be in your application at the time you get an update.  */
            /* Updates have a higher event priority than AppleEvents, and you usually */
            /* will get an update event after you show the 'Subscribe' dialog box and the */
            /* user has subscribed to something.  */
            /* What that means is that you may not have yet gotten the first Section Read */
            /* event for this subscription, you have no data to display. */
            if (GetHandleSize((Handle)tempPic) != nil) {
                HLock(*tempRHand);
                tempRect = (Rect *)*(*tempRHand);
                DrawPicture(tempPic, tempRect);
                HUnlock(*tempRHand);
            }
            tempHand += 1;
            tempRHand += 1;
        }
        HUnlock((*theWind)->subDataHandle);
        HUnlock((*theWind)->subRects);
    }
    if ((*theWind)->numPicts) {
        /* see if we have any pictures.  Pictures will be residual if the user */
        /* used to have a subscriber, and canceled it.  We get rid of the subscription */
        /* but keep the data */
        Handle *tempPicPtr;
        Handle *tempPicRect;
        HLock((*theWind)->pictHandle);
        HLock((*theWind)->pictRects);
        tempPicPtr = (Handle *)*((*theWind)->pictHandle);
        tempPicRect = (Handle *)*((*theWind)->pictRects);
        for (qq = 0; qq < (*theWind)->numPicts; qq++) {
            HLock(*tempPicRect);
            DrawPicture((PicHandle)*tempPicPtr, (Rect *)(*(*tempPicRect)));
            tempPicPtr += 1;
            tempPicRect += 1;
        }
    }
    /* Show publisher in this window if it's been clicked on lately */
    if (theWindPtr == FrontWindow()) {
        if (gShowPub) {
            PenPat(&qd.gray);                                /* 50% gray for publishers */
            PenSize(3, 3);
            FrameRect(&gShowPubRect);
            PenPat(&qd.black);
            PenSize(1, 1);
            grabRect = gShowPubRect;
            grabRect.top = grabRect.bottom - 7;
            grabRect.left = grabRect.right - 7;
            PaintRect(&grabRect);
            /* ¥¥¥¥ NOTE:  I've taken the invert out of these areas because it got confusing for what */
            /* I was publishing and subscribing.  Since we're dealing basically with bitmaps NOT */
            /* with object-style graphiocs, the invert can be confusing.  */
            /*   InsetRect(&gShowPubRect, 4, 4); */
            /* invert the selection */
            /*InvertRect(&gShowPubRect);*/
            /*InsetRect(&gShowPubRect, -4, -4); */
        }
        if (gShowSub) {
            PenPat(&qd.dkGray);                              /* 75% gray for subscriptions */
            PenSize(3, 3);
            InsetRect(&gShowSubRect, -4, -4);
            FrameRect(&gShowSubRect);
            
            PenPat(&qd.black);
            PenSize(1, 1);
            /* same as NOTE above */
            /*InsetRect(&gShowSubRect, 4, 4); */
            /*InvertRect(&gShowSubRect); */
            /*InsetRect(&gShowSubRect, -4, -4); */
            /* add a resizing grabber */
            if (gResizeSub) {
                /* If they can resize subscriptions, draw the grab box. */
                /* see the extra check box I added to the Subscriber Options dialog */
                grabRect = gShowSubRect;
                grabRect.top = grabRect.bottom - 7;
                grabRect.left = grabRect.right - 7;
                
                PenPat(&qd.black);
                /* if this is not the front window, just outline the grabber */
                /* if it is frontmost, draw it in solid black */
                if (theWindPtr != FrontWindow()) {
                    EraseRect(&grabRect);
                    FrameRect(&grabRect);
                } else {
                    EraseRect(&grabRect);
                    PaintRect(&grabRect);
                }
            }
            InsetRect(&gShowSubRect, 4, 4);
        }
        /* see if border showing is happening */
        /* They optionally may have the 'Show All Borders' menu item checked, if so show */
        /* the location of all the sections in this window */
        if (gShowingAll) {
            Rect borderRect;
            /* show all pubs */
            if ((*theWind)->numPubs) {
                Rect *tempRectPtr;
                HLock((*theWind)->pubRects);
                tempRectPtr = (Rect *)*(*theWind)->pubRects;
                PenPat(&qd.gray);                            /* 50% gray for publishers */
                PenSize(3, 3);
                for (qq = 0; qq < (*theWind)->numPubs; qq++) {
                    borderRect = *tempRectPtr;
                    FrameRect(&borderRect);
                    tempRectPtr += 1;
                }
                HUnlock((*theWind)->pubRects);
            }
            
            /* show all subs */
            if ((*theWind)->numSubs) {
                
                Handle *theRectsHandle;
                
                HLock((*theWind)->subRects);                /* lock down the rect handle */
                /* cast it as a pointer to handles for reading ease */
                theRectsHandle = (Handle *)*(*theWind)->subRects;
                
                PenPat(&qd.dkGray);                          /* 75% gray for subscriptions */
                PenSize(3, 3);
                for (qq = 0; qq < (*theWind)->numSubs; qq++) {
                    
                    HLock(*theRectsHandle);
                    
                    borderRect = *((Rect *)*(*theRectsHandle));
                    InsetRect(&borderRect, -4, -4);
                    FrameRect(&borderRect);
                    HUnlock(*theRectsHandle);
                    theRectsHandle += 1;
                    
                }
                HUnlock((*theWind)->subRects);
                
            }
            /* and show all text sections */
            if ((*theWind)->textSections) {
                mySectionDataHandle tempTS = (*theWind)->textSections;
                do {
                    BorderTextSection(tempTS);
                    tempTS = (*tempTS)->nextSection;
                }while (tempTS);
                
            }
            PenSize(1, 1);
            PenPat(&qd.black);
        }
    }
    /* and the grow box */
    scratchRect = theWindPtr->portRect;
    scratchRect.top = scratchRect.bottom - 15;
    scratchRect.left = scratchRect.right - 15;
    tempRgn = NewRgn();
    GetClip(tempRgn);
    ClipRect(&scratchRect);
    DrawGrowIcon(theWindPtr);
    SetClip(tempRgn);
    DisposeRgn(tempRgn);
    
}
 
/* end DrawFull */
 
/* DoDocumentClick handles clicking in the content region of our */
/* document windows. */
void DoDocumentClick(WindowPtr twindow)
{
    
    /* if the window already was frontmost, take the right */
    /* action for this window */
    /* ¥¥¥ NOTE: Normally, this is also the place where you would */
    /* update the modification date (mdDate)  of publishers */
    /* If the user takes an action across a published area, you */
    /* should update the modification time to flag yourself that this */
    /* edition needs to be sent.  This date/time will also show up in the */
    /* Options dialog for that publisher. But for the sake of clarity in this */
    /* sample, I am only changing the mod date on edition write (in files.c) */
    Point endPoint;
    Point oldendPoint;
    Rect startRect;
    Boolean wasInTB;
    windowCHandle shortname;
    short tempAct;
    Rect testRect;
    shortname = (windowCHandle)GetWRefCon(twindow);
    /* This handle is already locked on entry, from the dispatcher that got us here */
    
    tempAct = (*shortname)->currentAction;                  /* what are they doing? */
    SetPort(twindow);                                       /* make sure the port is good, I'm paranoid */
    GlobalToLocal(&gERecord.where);                         /* everything will be in local coordinate to this window */
    /* I don't want users to draw objects across my text box, so see if this click is in that thang */
    testRect.left = testRect.right = gERecord.where.h;
    testRect.right++;
    testRect.top = testRect.bottom = gERecord.where.v;
    testRect.bottom++;
    wasInTB = InTextBox(shortname, &testRect);
    if (!wasInTB || tempAct == kTextBox || tempAct == kNoAction) {
        switch (tempAct) {                                  /* switch off the action code */
            myLine tempLine;
            case kNoAction:
                /* no menu items checked.  See if they clicked in a */
                /* publisher or subcriber */
                /* border a publisher or subscriber if they clicked in one */
                if (!SearchPubs(gERecord.where) && !SearchSubs(gERecord.where)) {
                    /* if they didn't click in one, then erase the current selection */
                    /* Check to see if they're clicking in the TERecord.  This takes precidence over */
                    /* any other click */
                    /* You'll want to change this depending on your app */
                    if (wasInTB) {
                        /* treat this like a random click to de-border any PICT subscriptions that */
                        /* may be selected */
                        KillSelection(shortname);
                        DeBorderSelection();
                        /* check publisher stuff here */
                        
                        TEClick(gERecord.where, gERecord.modifiers & shiftKey, (*shortname)->boxHandle);
                        if (!gShowingAll) {
                            mySectionDataHandle tempTS = (*shortname)->textSections;
                            Boolean anyOn = false;          /* for our invalidate check */
                            /* step through text sections and turn off flags */
                            //while (tempTS) {
                            ///* also check here to see if anything was bordered.  If it was, invalidate */
                            ///* the TE rectangle so the old borders will be erased.  If there */
                            ///* were NOT any, don't invalidate, so we don't strobe the user to */
                            ///* blindness */
                            //anyOn = anyOn | (*tempTS)->bordered;
                            //(*tempTS)->bordered = false;
                            //tempTS = (*tempTS)->nextSection;
                            //}
                            //if (anyOn)
                            //InvalRect(&(*(*shortname)->boxHandle)->viewRect);
                        }                                   /* see if the click was inside a subscriber */
                        CheckSectionHit();
                        
                    } else {
                        /* if it was a random click, dehilite the text selection if there is one */
                        if ((*shortname)->boxHandle != nil) {
                            TESetSelect((*(*shortname)->boxHandle)->selStart, (*(*shortname)->boxHandle)->selStart,
                                        (*shortname)->boxHandle);
                            /* Also, check to see if any borders are on in the TE box.  If so, turn them off.  */
                            /* That is, unless gSHowingAll is on.... */
                            /* and it's easiest just to invlaidate the terect */
                            InvalRect(&(*(*shortname)->boxHandle)->viewRect);
                            if (!gShowingAll) {
                                mySectionDataHandle tempTS = (*shortname)->textSections;
                                /* step through text sections and turn off flags */
                                while (tempTS) {
                                    (*tempTS)->bordered = false;
                                    tempTS = (*tempTS)->nextSection;
                                } /* tempTS while end */
                            }
                        }
                        KillSelection(shortname);
                        DeBorderSelection();
                        /* and drag around a picture or an object if they want */
                        DragPictOrObject(&gERecord.where, shortname);
                    }
                    break;
                    case kDrawLine:
                        /* they want to draw a line in this window */
                        /* start and end points of the line set to the same val */
                        oldendPoint = endPoint = gERecord.where;
                        PenMode(srcXor);                    /* Xor so we can rubberband the line */
                        while (StillDown()) {               /* Keep doing this as long as the */
                            /* user keeps the mouse down */
                            GetMouse(&endPoint);            /* Current mouse position in local */
                            MakeRect(&gERecord.where, &endPoint, &testRect);
                            if (!InTextBox(shortname, &testRect)) {
                                /* coordinates */
                                if (endPoint != oldendPoint) {      /* only do this if the mouse moved so the line doesn't flicker */
                                    /* erase the old line (redraw in Xor mode ) */
                                    MoveTo(gERecord.where.h, gERecord.where.v);
                                    LineTo(oldendPoint.h, oldendPoint.v);
                                    /* draw the new line */
                                    MoveTo(gERecord.where.h, gERecord.where.v);
                                    LineTo(endPoint.h, endPoint.v);
                                    oldendPoint = endPoint;
                                }
                            } else {
                            endPoint = oldendPoint;
                            }
                        }  /* StillDown while end */
                        PenMode(srcCopy);
                        /* They released the mouse.  Add the line they drew */
                        /* to our record */
                        tempLine.start = gERecord.where;
                        tempLine.end = endPoint;
                        /* see this function later in this file */
                        AddLine((windowCHandle)((WindowPeek)twindow)->refCon, &tempLine);
                        /* changes the Undo menu item text */
                        SetUndo(kDrawLine, false);
                        break;                              /* end line case */
                        
                        /* they want to draw a rectangle in this window */
                    case kDrawRect:
                        /* start and end of rectangle set to the same val */
                        PullRect(shortname, &startRect, false, false, true);
                        /* Add it to our window */
                        AddRect((windowCHandle)((WindowPeek)twindow)->refCon, &startRect);
                        SetUndo(kDrawRect, false);          /* Set undo menu item text to */
                        /* Undo Rectangle */
                        break;                              /* end rectangle case */
                        
                    case kDrawOval:
                        /* start and end of oval set to the same val */
                        PullRect(shortname, &startRect, true, false, true);
                        /* Add the oval to our window struct */
                        AddOval((windowCHandle)((WindowPeek)twindow)->refCon, &startRect);
                        /* Set undo menu item text to Undo Oval */
                        SetUndo(kDrawOval, false);
                        break;
                    case kTextBox:
                        /* start and end of rectangle set to the same val */
                        PullRect(shortname, &startRect, false, false, true);
                        /* Add it to our window */
                        AddTextBox((windowCHandle)((WindowPeek)twindow)->refCon, &startRect);
                        SetUndo(kCantUndo, false);          /* can't undo a text box */
                        SwitchChecks(kTextBox);
                        InitCursor();
                        /* Undo Rectangle */
                        break;
                    case kSelectStuff:
                        /* pretty much like drawrect, but */
                        /* the resulting rect can be published */
                        /* get rid of the old one */
                        if ((*shortname)->hasSelection)     
                            KillSelection((windowCHandle)GetWRefCon(twindow));
                        PullRect(shortname, &startRect, false, false, true);
                        PenPat(&qd.gray);
                        FrameRect(&startRect);
                        PenPat(&qd.black);
                        PenSize(1, 1);
                        AddSelection((windowCHandle)((WindowPeek)twindow)->refCon, &startRect);
                        /* they can only select one rectangle, so clear the check */
                        /* and change the cursor back to an arrow */
                        SwitchChecks(kSelectStuff);
                        InitCursor();
                        (*shortname)->hasSelection = true;
                        SetUndo(kSelectItem - 1, false);        /* since the item on the menu is one more than our use, because of the divider */
                        /* before the MenuSelect call above to see how it's used */
                        break;
                        break;
                } else {
                    unsigned long timeNow;
                    /* they did click in one, see if it is/was a double click please */
                    /* A double-click in a section should be treated the same */
                    /* as if the user had selected Pub/Sub options for that section */
                    KillSelection(shortname);
                    if ((gShowingSecHandle == gLastSection) && (gShowingSecHandle != nil)) {
                        timeNow = TickCount();
                        if ((timeNow - gLastSecClickTick) < GetDblTime()) {
                            /* it is a double click.  treat the same way as the menu selection for */
                            /* Options UNLESS they had the option key down, then do a gotopublisher*/
                            if (gERecord.modifiers & optionKey)
                                MyGoToPublisher(gLastSection);
                            else
                                DoOptions(gShowingSecHandle);       /* in Subscribe.c. */
                            
                        } else {
                            /* not a double click.  Set up for the next pass */
                            /* de-border the old one please */
                            gLastSecClickTick = timeNow;
                            gLastSection = gShowingSecHandle;
                        }
                    } else {
                        gLastSecClickTick = timeNow;
                        gLastSection = gShowingSecHandle;
                    }
                }
        }
    } else {
    /* no matter which tool is selected, you can select in the TB */
    TEClick(gERecord.where, gERecord.modifiers & shiftKey, (*shortname)->boxHandle);
    }
}
 
/* end DoDocumentClick */
 
/* DragPictOrObject drags a shape or picture.  Stores last position in */
/* window structure for Undo */
void DragPictOrObject(Point *where, windowCHandle tempWC)
{
    Handle *tempPicRect;
    ShapesHandle theShapes;
    register qq;
    Rect origRect;
    Boolean hadIt = false;
    Point thePoint;
    /* See if the hit was in a Pict, search all picts  */
    
    if ((*tempWC)->numPicts) {
        HLock((*tempWC)->pictRects);
        
        tempPicRect = (Handle *)*((*tempWC)->pictRects);
        /* run through all of them */
        for (qq = 0; qq < (*tempWC)->numPicts; qq++) {
            /* Did we hit this one? */
            if (PtInRect(*where, (Rect *)(*(*tempPicRect)))) {
            /* Yes, drag it around */           
                Rect dragger = *((Rect *)(*(*tempPicRect)));
                thePoint = *where;
                origRect = dragger;
                hadIt = true;
                PullRect(tempWC, &dragger, false, true, false);
                if(!EqualRect(&origRect,&dragger)){
                    /* if it really moved, update the dirty flag  <ckh 1.0.2>*/                 
                    (*tempWC)->windowDirty = kMyTrue;
                    }
                *((Rect *)(*(*tempPicRect)))=dragger;
                InvalRect(&dragger);
                InvalRect(&origRect);                
                if ((*tempWC)->hasSelection)        
                    InvalRect(&(*tempWC)->selectionRect);
                (*tempWC)->hasSelection = true;
                (*tempWC)->selectionRect = dragger;
                /* make this one pixel bigger, so if the user wants to publish a Pict */
                /* they get the whole thing */
                InsetRect(&(*tempWC)->selectionRect,-1,-1);
                break;
                
                
            }
            tempPicRect += 1;
        }
        HUnlock((*tempWC)->pictRects);
        
    }
    if (!hadIt) {
        /* check all my shapes */
        if ((*tempWC)->numShapes) {
            Boolean offsetIt = false;
            theShapes = (*tempWC)->theShapes;
            do {
                Rect dragger;
                HLock((Handle)theShapes);
                dragger = (*theShapes)->theRect;
                if ((*theShapes)->type == kLineShape) {
                    short temp;
                    
                    if (dragger.top > dragger.bottom) {
                        offsetIt = true;
                        temp = dragger.top;
                        dragger.top = dragger.bottom;
                        dragger.bottom = temp;
                    }
                    if (dragger.left > dragger.right) {
                        offsetIt = true;
                        temp = dragger.left;
                        dragger.left = dragger.right;
                        dragger.right = temp;
                        
                    }
                }
                if (PtInRect(*where, &dragger)) {                    
                    thePoint = *where;                    
                    /* have to see if this was a line, since that rect may be reversed */                    
                    origRect = dragger;
                    InsetRect(&dragger, -1, -1);
                    hadIt = true;
                    PullRect(tempWC, &dragger, false, true, false);
                    InsetRect(&dragger, 1, 1);
                    if(!EqualRect(&origRect,&dragger))(*tempWC)->windowDirty = kMyTrue;
                    if (offsetIt) {
                        OffsetRect(&(*theShapes)->theRect, dragger.left - origRect.left, dragger.top - origRect.top);
                    } else {
                        (*theShapes)->theRect = dragger;
                    }
                    InvalRect(&dragger);
                    InvalRect(&origRect);
                    
                    (*tempWC)->hasSelection = true;
                    if ((*tempWC)->hasSelection)
                        InvalRect(&(*tempWC)->selectionRect);
                    (*tempWC)->hasSelection = true;
                    (*tempWC)->selectionRect = dragger;                    
                    /* make this one pixel bigger, so if the user wants to publish an object */
                    /* they get the whole thing */
                    InsetRect(&(*tempWC)->selectionRect,-1,-1);
                    break;
                    
                    
                    
                }
                
                HUnlock((Handle)theShapes);
                theShapes = (*theShapes)->nextShape;
            }while (theShapes); /* end of shapes */
            
        }
    }
} /* end DragPictOrObject */
 
/* KillSelection removes any selection from the current window */
void KillSelection(windowCHandle tempWC)
{
    Rect nulRect =  {
        0, 0, 0, 0
    };
    
    InvalRect(&(*tempWC)->selectionRect);
    (*tempWC)->selectionRect = nulRect;
    (*tempWC)->hasSelection = false;
    
} /* end KillSelection */
 
/* UndoLast undoes the last drawing action that happened in the current 
* window.  Each window has it's own record of the last action, so 
* Undo is always valid for the current window, and will not act on a 
* window the user doesn't expect. */
void UndoLast(void)
{
    windowCHandle temp;
    WindowPtr tempPort;
    ShapesHandle tempSH, beforeLast;
    GetPort(&tempPort);                                     /* not really necessary, but I'm paranoid */
    SetPort(FrontWindow());
    temp = (windowCHandle)GetWRefCon(FrontWindow());
    HLock((Handle)temp);                                    /* memory may move when handles are resized */
    switch ((*temp)->undoAction) {                          /* last action that happened in this window */
        /* For the graphic objects, we need to erase the last thing draw and update
        * the window record's handles and counts */
        case kDrawLine:
        case kDrawRect:
        case kDrawOval:
            /* unlink and dispose of the last shape handle please */
            /* find the last shape */
            beforeLast = (*temp)->theShapes;
            tempSH = (*temp)->theShapes;
            if ((*temp)->numShapes == 1) {
                (*temp)->numShapes = 0;
                DisposeHandle((Handle)(*temp)->theShapes);
                (*temp)->theShapes = nil;
            } else {
                register qq;
                for (qq = 0; qq < (*temp)->numShapes - 2; qq++) {
                    tempSH = (*tempSH)->nextShape;
                }
                DisposeHandle((Handle)(*tempSH)->nextShape);
                (*tempSH)->nextShape = nil;
                (*temp)->numShapes--;
                
            }
            break;
        case kTextBox:
            TEDispose((*temp)->boxHandle);
            (*temp)->boxHandle = nil;
            InsetRect(&(*temp)->textBox, -3, -2);           /* just don't ask */
            InvalRect(&(*temp)->textBox);
            break;
        case kSelectStuff:
            KillSelection(temp);
            break;
        case kMoveObject:
            
            break;
    }
    HUnlock((Handle)temp);
    /* now make sure things get refreshed */
    InvalRect(&(FrontWindow()->portRect));
    EraseRect(&(FrontWindow()->portRect));
    SetUndo(0, false);
    SetPort(tempPort);
} /* end UndoLast */
 
/* AddLine adds a line to our window data structure */
/* nowHandle is the window data structure handle */
/* inLine is the line to add */
void AddLine(windowCHandle nowHandle, myLine *inline)
{Rect tempRect;
  short temp;
ShapesHandle newShape = NewShape(nowHandle);
 
(*newShape)->type=kLineShape;
(*newShape)->aeType = cGraphicLine;
(*newShape)->theRect.top =  inline->start.v;
(*newShape)->theRect.left = inline->start.h;
(*newShape)->theRect.bottom = inline->end.v;
(*newShape)->theRect.right = inline->end.h;
 
tempRect = (*newShape)->theRect;
if (tempRect.top > tempRect.bottom) {
 
temp = tempRect.top;
tempRect.top = tempRect.bottom;
tempRect.bottom = temp;
}
if (tempRect.left > tempRect.right) {
 
temp = tempRect.left;
tempRect.left = tempRect.right;
tempRect.right = temp;
 
}
 
InvalRect(&tempRect);
}
 
/* end AddLine */
 
/* AddRect adds a rectangle  to our window data structure */
/* nowHandle is the window data structure handle */
/* inRect is the rect to add */
void AddRect(windowCHandle nowHandle, Rect *inrect)
{ShapesHandle tempShape = NewShape(nowHandle);
(*tempShape)->type=kRectShape;
(*tempShape)->aeType = cRectangle;
(*tempShape)->theRect=*inrect;
InvalRect(inrect);
}
 
/* end AddRect */
 
/* AddTextBox adds a text editing box to our window data structure */
/* nowHandle is the window data structure handle */
/* inRect is the position to put the box in to add */
 
void AddTextBox(windowCHandle nowHandle, Rect *inrect)
{
    Rect framer;
    HLock((Handle)nowHandle);
    
    (*nowHandle)->textBox = *inrect;
    (*nowHandle)->windowDirty = kMyTrue;
    /* Create a TERecord to go here */
    InsetRect(&(*nowHandle)->textBox, -3, -3);
    (*nowHandle)->boxHandle = TENew(inrect, &(*nowHandle)->textBox);
    TEActivate((*nowHandle)->boxHandle);
    framer = (*nowHandle)->textBox;
    InsetRect(&framer, -3, -2);
    InvalRect(&framer);
    HUnlock((Handle)nowHandle);
}
 
/* end AddTextBox */
 
/* AddOval adds a oval  to our window data structure */
/* nowHandle is the window data structure handle */
/* inOval is the oval to add */
void AddOval(windowCHandle nowHandle, Rect *inoval)
{ShapesHandle tempShape = NewShape(nowHandle);
(*tempShape)->type=kOvalShape;
(*tempShape)->aeType = cOval;
(*tempShape)->theRect=*inoval;
InvalRect(inoval);
} /* end AddOval */
 
/* AddSelection adds a selection rectangle  to our window data structure */
/* nowHandle is the window data structure handle */
/* inRect is the rect to add */
void AddSelection(windowCHandle nowHandle, Rect *inrect)
{
    HLock((Handle)nowHandle);
    (*nowHandle)->selectionRect = *inrect;
    (*nowHandle)->hasSelection = true;
    HUnlock((Handle)nowHandle);
} /* end AddSelection */
 
 
/* NewShape adds a new shape to our window structure */
 
ShapesHandle NewShape(windowCHandle theWindow)
{
ShapesHandle newShape = (ShapesHandle)NewHandle(sizeof(Shapes));
ShapesHandle tempShapes=(*theWindow)->theShapes;
(*newShape)->theColor = gColorArray[gCurrentColor];
if(tempShapes){ /* if there is already a shape defined */
/* find the end and store this handle there */
while((*tempShapes)->nextShape){
tempShapes=(*tempShapes)->nextShape;
}
(*tempShapes)->nextShape=newShape;
} else {
/* first shape */
(*theWindow)->theShapes=newShape;
}
/* increase our count of shapes */
(*theWindow)->numShapes++;
(*theWindow)->windowDirty = kMyTrue;
(*newShape)->nextShape=nil;
return(newShape);
}
/* end NewShape */
 
 
 
 
/* ChangePlane does the housekeeping we need to do when a window comes to */
/* the front, swapping menu checks, setting the cursor, and so on */
/* And by the way, this routine has caused me more problems than any other, I will */
/* be completely rewriting it in the next release, it is _not_ optimal. */
void ChangePlane(WindowPtr twindow)
{
    short temp;
    Rect scratchRect;
    WindowPtr oldWindow = FrontWindow();
    windowCHandle shortname;
    /* Before the swap kill any current borders */
    DeBorderSelection();
     
    /* deactivate the textedit record of the old window, if there is one */
    if (oldWindow != nil && oldWindow != twindow && IsMyWindow(oldWindow)) {
        windowCHandle tempCH = (windowCHandle)GetWRefCon(oldWindow);
        if ((*tempCH)->boxHandle != nil)
            TEDeactivate((*tempCH)->boxHandle);
            SetPort(oldWindow);
            scratchRect = twindow->portRect;
    scratchRect.top = scratchRect.bottom - 15;
    scratchRect.left = scratchRect.right - 15;
    InvalRect(&scratchRect);
 
    }
    /* if the window coming forward isn't a doc window, dim the tools menu */
 
    if (((WindowPeek)twindow)->windowKind != kDocumentWindow) {
        SetWMenus(false);
    } else {
        SetWMenus(true);
    }
 
    SetUndo(0, true);                                       /* tell SetUndo to pull the undo item value out of the current record */
    shortname = (windowCHandle)GetWRefCon(twindow);         /* was oldwindow */
    HLock((Handle)shortname);
    temp = (*shortname)->currentAction;                     /* pull the last action the */
    HUnlock((Handle)shortname);                             /* user was performing out of the */
    SetCurAction(temp);                                     /* window record */
    SetMyCursor(actsToIDs[temp]);                           /* set the right cursor */
    SwitchChecks(actsToIDs[temp]);                          /* check the right menu item */
    gShowPub = gShowSub = false;                            /* selections go away when windows */
    gShowingSecHandle = nil;
    if ((*shortname)->boxHandle != nil)
        TEActivate((*shortname)->boxHandle);
    SelectWindow(twindow);                                  /* select the window */
    SetPort(twindow);
    scratchRect = twindow->portRect;
    scratchRect.top = scratchRect.bottom - 15;
    scratchRect.left = scratchRect.right - 15;
    InvalRect(&scratchRect);
    /* and re-do our window indexes */
    /* ¥¥¥¥ NOTE:  I am not including the AEStatus window in this  */   
    /* window index or check!  The AEStatus window is a special diagnostic
    /* only type window that is _not_ anything a 'real' application would have */
    /*  It can change planes in  the middle of an AppleEvent if there is information */
    /* to display, and if I included it in my real window list that */
    /* would violate 'state freezing' for the space of an event, which  */
    /* is A Bad Thing */
    /* So I'm looking at everything but the AES window */
    temp = 1;
    oldWindow = FrontWindow();
    while(oldWindow){
    shortname = (windowCHandle)GetWRefCon(oldWindow);
    if((((WindowPeek)oldWindow)->visible) && (((WindowPeek)oldWindow)->windowKind != kAEStatusWindow && IsMyWindow(oldWindow)))
    {(*shortname)->windowIndex = temp;
        temp++;}
    oldWindow = (WindowPtr)((WindowPeek)oldWindow)->nextWindow;
    }
    /* now any invisible windows, since their index will be after the visible ones */
    oldWindow = (WindowPtr)LMGetWindowList();
    while(oldWindow){
    shortname = (windowCHandle)GetWRefCon(oldWindow);
    if((!((WindowPeek)oldWindow)->visible) && (((WindowPeek)oldWindow)->windowKind != kAEStatusWindow) && IsMyWindow(oldWindow))
    {(*shortname)->windowIndex = temp;
    temp++;}
        oldWindow = (WindowPtr)((WindowPeek)oldWindow)->nextWindow;
    }
AdjustCursor(gERecord.where, mousergn);
}
 
/* end ChangePlane */
 
/* may be a shape ,PICT, or a selection range */
/* so if it's a shape, I cut the shape definition, pict, same thing.  */
/* if it's  a selection range, I dunno what I'm gonna do. */
/* no, actually I'll just cut all the components of the range */
void CutGraphic(windowCHandle tempWC)
{Rect localSelection = (*tempWC)->selectionRect;
 
 
}
 
void CopyGraphic(windowCHandle tempWC)
{
#pragma unused (tempWC)
}
void ClearGraphic(windowCHandle tempWC)
{
#pragma unused (tempWC)
}
 
 
/* This sets window properties, it's passed one of our property tokens */
OSErr SetWindowProperty(PropertyTHdl propertyBack, AEDesc *theData)
{
    OSErr myErr = noErr;
    AEDesc convertedDesc;
    Size dataSize;
    switch ((*propertyBack)->theProperty) {
        case pName:
            /* setting name.  Let's see if the data is typeChar */
            if (theData->descriptorType != typeChar) {
                /* problem.  See if it'll coerce */
                myErr = AECoerceDesc(theData, typeChar, &convertedDesc);
                if (!myErr) {
                    /* it converted.  swap descs (kinda) */
                    myErr = AEDisposeDesc(theData);
                    myErr = AEDuplicateDesc(&convertedDesc, theData);
                    myErr = AEDisposeDesc(&convertedDesc);
                }
            }
            if (!myErr) {
                Str63 newName,oldName;
                
                /* the data in the handle is text.  Make it into a string for us */
                dataSize = GetHandleSize(theData->dataHandle);
                if (dataSize > 63)
                    dataSize = 63;                          /* Truncating the name because I want to */
                HLock(theData->dataHandle);
                BlockMove((Ptr)*(theData->dataHandle), (Ptr)&newName[1], dataSize);
                HUnlock(theData->dataHandle);
                newName[0] = dataSize;
                /* set the title.  We have the window pointer in the property token */
                GetWTitle((*propertyBack)->token.window,&oldName);
                SetWTitle((*propertyBack)->token.window, &newName);
            /* v 1.0.1 revise old name in window menu please */
                AddToWindowMenu((*propertyBack)->token.window,&oldName);
                /* all done! */
            }
            break;
        case pBounds:
            /* we have been passed a new rectangle, in global coords */
            /* so pull the rectangle out */
            /* again, make sure the data is in a rect type */
            if (theData->descriptorType != typeQDRectangle) {
                /* problem.  See if it'll coerce */
                myErr = AECoerceDesc(theData, typeQDRectangle, &convertedDesc);
                if (!myErr) {
                    /* it converted.  swap descs (kinda) */
                    myErr = AEDisposeDesc(theData);
                    myErr = AEDuplicateDesc(&convertedDesc, theData);
                    myErr = AEDisposeDesc(&convertedDesc);
                }
            }
            if (!myErr) {
                Rect newRect;
                /* OK, the data handle contains a rect.  I'll move it so it's easier to read */
                newRect = *((Rect *)*(theData->dataHandle));
                /* Move the window.  Pass a false as BringToFront since we don't want window shuffling */
                /* check the rect for validity */
                if( newRect.top < newRect.bottom && newRect.left < newRect.right){
                MoveWindow((*propertyBack)->token.window, newRect.left, newRect.top, false);
                /* set the new dimensions.  And generate an update as needed */
                SizeWindow((*propertyBack)->token.window, (newRect.right - newRect.left), (newRect.bottom - newRect.top), true);
                /* Done! */
                } else {
                myErr = errAEEventNotHandled;
                AddToReply("\pBad Window Size",kWeirdSizeErr);
                }
            }
            break;
        case pHasTitleBar:
        case pIsModal:
        case pIsModified:
        case pIsResizable:
        case pIsStationeryPad:
        case pIsZoomed:
        /* add new Winter '92 registry error code <ckh 1.0.2>*/
            myErr = errAENotModifiable;                   /* I am not allowing these properties to be modified */
            AddToReply("\p Attempted to modify a read-only parameter",errAENotModifiable);
 
            break;
        case pVisible:
            /* value is true oder false */
 
 
            if(**(theData->dataHandle)){
                ShowWindow((*propertyBack)->token.window);
                AddToWindowMenu((*propertyBack)->token.window,nil);
                }
            else {
                DeleteFromWindowMenu((*propertyBack)->token.window);
                HideWindow((*propertyBack)->token.window);
                }
 
            break;
    }
    return(myErr);
} /* end SetWindowProperty */
 
OSErr SetShapeProperty(PropertyTHdl propertyBack, AEDesc *theData)
{
    OSErr myErr = noErr;
    AEDesc convertedDesc;
    WindowPtr tempWindow;
    ShapesHandle theShape =(*propertyBack)->token.shapeHandle;
    switch ((*propertyBack)->theProperty) {
        case pBounds:
        case pDefinitionRect:
            /* we have been passed a new rectangle */
            /* so pull the rectangle out */
            /* again, make sure the data is in a rect type */
            if (theData->descriptorType != typeQDRectangle) {
                /* problem.  See if it'll coerce */
                myErr = AECoerceDesc(theData, typeQDRectangle, &convertedDesc);
                if (!myErr) {
                    /* it converted.  swap descs (kinda) */
                    myErr = AEDisposeDesc(theData);
                    myErr = AEDuplicateDesc(&convertedDesc, theData);
                    myErr = AEDisposeDesc(&convertedDesc);
                }
            }
            if (!myErr) {
            /* we have a rect.  Set the shape to it */
            HLock((Handle)theShape);
            /* invalidate the old rect so the user sees the change */
            /* ¥ NOTE:  I'm getting current port and setting the one in the  */
            /* token.  Remember, there is NO reason for an event to have to */
            /* occur in the frontmost or current port */
            GetPort(&tempWindow);
            SetPort((*propertyBack)->inWindow);
            InvalRect(&(*theShape)->theRect);
            /* i dont want the rect set to zero, please */
            if(!EmptyRect(((Rect *)*(theData->dataHandle)))){
            
            (*theShape)->theRect = *((Rect *)*(theData->dataHandle));
            InvalRect(&(*theShape)->theRect);}
            SetPort(tempWindow);
            }
            break;
        case pPenColor:
        /* pretty much the same for colors */
           if (theData->descriptorType != typeRGBColor) {
                /* problem.  See if it'll coerce */
                myErr = AECoerceDesc(theData, typeRGBColor, &convertedDesc);
                if (!myErr) {
                    /* it converted.  swap descs (kinda) */
                    myErr = AEDisposeDesc(theData);
                    myErr |= AEDuplicateDesc(&convertedDesc, theData);
                    myErr |= AEDisposeDesc(&convertedDesc);
                }
            }
            if (!myErr) {
            /* we have a rect.  Set the shape to it */
            HLock((Handle)theShape);
            /* invalidate the old rect so the user sees the change */
            /* ¥ NOTE:  I'm getting current port and setting the one in the  */
            /* token.  Remember, there is NO reason for an event to have to */
            /* occur in the frontmost or current port */
            GetPort(&tempWindow);
            SetPort((*propertyBack)->inWindow);
            InvalRect(&(*theShape)->theRect);
            (*theShape)->theColor = *((RGBColor *)*(theData->dataHandle));
            SetPort(tempWindow);
            }
        
        
        break;
        /* I'm not handling any other properties right now, check again later */
        default:
        /* add new Winter '92 registry error code <ckh 1.0.2>*/
            myErr = errAENotModifiable;                   /* I am not allowing these properties to be modified */
            AddToReply("\p Attempted to modify a read-only parameter",errAENotModifiable);
 
        break;
    }
    return(myErr);
}
 
 
 
 
/* Check to see if a window belongs to a desk accessory. */
/* This is _almost_ unnecessary in System 7.  Since DAs have their own layer now, and */
/* it's _almost_ impossible to force a DA into an applications space, this should */
/* rarely be true */
/* HOWEVER, there are INITs out there that will stick windows in your window list. */
/* BallooonWriter does, for example */
Boolean IsDAWindow(WindowPtr window)
{
    if (window == nil)
        return false;
    else                                                    /* DA windows have negative windowKinds */
        return((WindowPeek)window)->windowKind < 0;
}
 
/* end IsDAWindow*/
 
/* DrawClip draws the current contents of the clipboard */
void DrawClip(windowCHandle theWind, WindowPtr windowIn)
{
#pragma unused(theWind)
    RgnHandle tempRgn;
    Rect theRect;
    Str63 clipString;
    UpdateScrap(false);                                     /* no neverending updateas */
    MoveTo(10, 10);
    /* Get the basic clipboard text */
    GetIndString(clipString, kClipBoardStrings, 1);
    DrawString(clipString);
    /* get the string that says what type of thing is on the clipboard */
    GetIndString(clipString, kClipBoardStrings, gClipHasContents);
    DrawString(clipString);
    MoveTo(0, 13);
    /* underline those words */
    LineTo(FindClipWindow()->portRect.right, 13);
    HLock(gScrapData);
    /* I make all my clipboard data into a picture, so we can use DrawPicture to display it */
    if ((GetHandleSize(gScrapData) != 0) && gScrapData) {
        Rect picRect;
        picRect = ((*(PicHandle)gScrapData))->picFrame;
        OffsetRect(&picRect, 0, 15);
        DrawPicture((PicHandle)gScrapData, &picRect);
    }
    HUnlock(gScrapData);
    /* Add our grow box, clip out the rect so we don't get the */
    /* spurious scroll area lines */
    theRect = windowIn->portRect;
    theRect.top = theRect.bottom - 15;
    theRect.left = theRect.right - 15;
    tempRgn = NewRgn();
    GetClip(tempRgn);
    ClipRect(&theRect);
    DrawGrowIcon(windowIn);
    SetClip(tempRgn);
    DisposeRgn(tempRgn);
    
} /* end DrawClip */
 
 
 
void ClipClick(WindowPtr twindow)
{                                                           /* nothing happens on a clipboard click, it's in here for whenever I put scroll bars in */
#pragma unused (twindow)
} /* end ClipClick */
 
/* Closes the clipboard window and takes it off the window menu */
/* Remember, however, it isn't dead.  If there is a section on the  */
/* clipboard it can still get updated */
void CloseClip(WindowPtr inWind)
{
#pragma unused (inWind)
    WindowPtr clipWind = FindClipWindow();
    Str63 menuText;
    if (((WindowPeek)clipWind)->visible) {
            HideWindow(clipWind);
        
        DeleteFromWindowMenu(clipWind);
        if (FrontWindow() != nil)
            ChangePlane(FrontWindow());
        /* change the menu string to read 'Show Clipboard' */
        GetIndString(menuText, kGeneralStrings, kShowClipString);
        SetMenuItemText(gEditMenuHandle, kClapNum, menuText);
    }
} /* end CloseClip */
 
void SizeClip(WindowPtr windowIn)
{
#pragma unused (windowIn)
} /* end SizeClip */
 
/* UpdateScrap reads in the current scrap, and makes a picture from it */
/* It will also cause the clipboard window to redraw if it's visible */
void UpdateScrap(Boolean refreshIt)
{
    /* The 'refreshIt' variable is there to indicate if the window should be */
    /* invalidated or not.  I added this so this routine can safely */
    /* be called from the drawing procedure without fear of nverending updates */
    Handle textData;
    long myOffset;
    long length;
    textData = NewHandle(0);
    if (gClipHasContents == kClipHasSub) {
    } else {
        /* show standard scrap types, prefering pictures */
        length = GetScrap(gScrapData, 'PICT', &myOffset);
        if (length < 0) {
            if (length == noTypeErr) {
                length = GetScrap(textData, kGenericTEXTWord, &myOffset);
                /* if it's text, I'm going to make it into a picture for my clipboard display, makes things */
                /* easier in my draw proc */
                if (length > 0) {
                    DisposeHandle(gScrapData);               /* kill the old one */
                    gScrapData = (Handle)OpenPicture(&FindClipWindow()->portRect);
                    HLock(textData);
                    TETextBox(*textData, length, &(FindClipWindow())->portRect, teJustLeft);
                    HUnlock(textData);
                    ClosePicture();
                    gClipHasContents = kClipHasText;
                }
            } else {                                        /* another type of error, like nothing available at all */
                MySetHandleSize(gScrapData, 0);
                gClipHasContents = kClipEmpty;
            }
        } else {
            /* set the pict rect so it's in the upper left of our clipboard */
            gClipHasContents = kClipHasPict;
            OffsetRect(&((*(PicHandle)gScrapData))->picFrame, (((*(PicHandle)gScrapData))->picFrame.left * -1),
                       (((*(PicHandle)gScrapData))->picFrame.top * -1) + 11);
        }
    }
    DisposeHandle(textData);
    if (refreshIt && ((WindowPeek)FindClipWindow())->visible) {
        /* if we want it refreshed, force an update */
        WindowPtr temp;
        GetPort(&temp);
        SetPort(FindClipWindow());
        InvalRect(&(FindClipWindow())->portRect);
        SetPort(temp);
    }
}
 
/* end updatescrap */
 
/* SpitClip spits our private subscription out to the general clipboard as a PICT type scrap */
/* when we go in the background.  Does nothing if it's not a subscription, since it'll already */
/* be right. */
 
void SpitClip(void)
{
    if (gClipHasContents == kClipHasSub) {
        ZeroScrap();
        HLock(gScrapData);
        PutScrap(GetHandleSize(gScrapData), 'PICT', *gScrapData);
        
    }
} /* end spitclip */
 
/* Handy little routine to find and return a pointer to the clipboard, visible or not */
WindowPtr FindClipWindow(void)
{
    WindowPtr twindow = (WindowPtr)LMGetWindowList();
    while (twindow) {
        if (((WindowPeek)twindow)->windowKind == kClipboardWindow)
            return(twindow);
        twindow = (WindowPtr)((WindowPeek)twindow)->nextWindow;
    } /* end of windows while */
    return(nil);                                            /* should never reach here */
} /* end FindClipWindow */
 
/* AppleEvent Status Window routines */
/* Changes the visiblility state of the AEStatus window */
void ToggleAEWindow(void)
{
    WindowPtr oldFront = FrontWindow();
    Str63 menuText;
    short tempShort;
    if(!IsModalFront()){
    WindowPtr AEWind = FindAEWindow();                      /* find it */
    if (((WindowPeek)AEWind)->visible) {                    /* if it's visiblem hide it */
        HideWindow(AEWind);
        DeleteFromWindowMenu(AEWind);                       /* and remive it from the menu */
        tempShort = kShowAEString;
    } else {
        ShowWindow(AEWind);                                 /* show the thing */
        AddToWindowMenu(AEWind, nil);                       /* add it's name to the window menu */
        if(oldFront)ChangePlane(AEWind);                                /* bring it forward */
        tempShort = kHideAEString;
        
    }
    /* get the correct text for the 'Show/Hide AEWindow' menu item */
    GetIndString(menuText, kGeneralStrings, tempShort);
    SetMenuItemText(gAppleEventMenuHandle, kShowAEWind, menuText);
}
} /* end ToggleAEWindow */
 
/* Handy little routine for finding the AEStatus window, visible or not */
WindowPtr FindAEWindow(void)
{
    WindowPtr twindow = (WindowPtr)LMGetWindowList();
    while (twindow) {
        if (((WindowPeek)twindow)->windowKind == kAEStatusWindow)
            return(twindow);
        twindow = (WindowPtr)((WindowPeek)twindow)->nextWindow;
    }
    return(nil);                                            /* should never reach here */
    
} /* end FindAEWindow */
 
/* Draws the AEStatus window */
void DrawAES(windowCHandle theWind, WindowPtr windowIn)
{
    Rect theRect;
    RgnHandle tempRgn;
    theRect = windowIn->portRect;
    TEUpdate(&theRect, (*theWind)->boxHandle);
    theRect.top = theRect.bottom - 15;
    theRect.left = theRect.right - 15;
    tempRgn = NewRgn();
    GetClip(tempRgn);
    ClipRect(&theRect);
    DrawGrowIcon(windowIn);
    SetClip(tempRgn);
    DisposeRgn(tempRgn);
    
} /* end DrawAES */
 
 
 
/* Handles a click in the AEStatus window,  by  doing a TEClick */
void ClickAES(WindowPtr twindow)
{
    windowCHandle tempWCH = (windowCHandle)GetWRefCon(twindow);
    Rect theRect = twindow->portRect;
    SetPort(twindow);
    GlobalToLocal(&gERecord.where);
    
    TEClick(gERecord.where, gERecord.modifiers & shiftKey, (*tempWCH)->boxHandle);
    
} /* end ClickAES */
 
/* CloseAES doesn't close the window, just makes it invisible */
void CloseAES(WindowPtr inWind)
{
#pragma unused (inWind)
WindowPtr aeWind = FindAEWindow();
    Str32 menuText;
    if (((WindowPeek)aeWind)->visible) {               
        HideWindow(aeWind);
        DeleteFromWindowMenu(aeWind);
        if (FrontWindow() != nil)
            ChangePlane(FrontWindow());
        /* and change the menu text */
        GetIndString(menuText, kGeneralStrings, kShowAEString);
        SetMenuItemText(gAppleEventMenuHandle, kShowAEWind, menuText);
    }
} /* end CloseAES */
 
void AESKey(char theKey, windowCHandle tempWC)
{
    TEKey(theKey, (*tempWC)->boxHandle);
} /* end AESKey */
 
/* Resize the AES window */
/* When resizing TextEdit records, I always destroy and recreate them in */
/* their new size, instead of mucking around with the rects.  Simpler and safer */
void SizeAES(WindowPtr windowIn)
{
    Handle theText;
    Rect newRect;
    
    short selStart, selEnd;
    windowCHandle tempWCH = (windowCHandle)GetWRefCon(windowIn);
    /* recalculate the TE rectangle */
    newRect = windowIn->portRect;
    newRect.right -= 16;
    /* Get the old text */
    theText = (Handle)TEGetText((*tempWCH)->boxHandle);
    /* get the old selection range */
    selStart = (*(*tempWCH)->boxHandle)->selStart;
    selEnd = (*(*tempWCH)->boxHandle)->selEnd;
    /* copy the old text */
    HandToHand(&theText);
    /* kill the TERecord */
    TEDeactivate((*tempWCH)->boxHandle);
    TEDispose((*tempWCH)->boxHandle);
    /* recreate it in it's new size */
    (*tempWCH)->boxHandle = TENew(&newRect, &newRect);
    /* and do all the housekeeping associated with a new TERecord */
    TEAutoView(true, (*tempWCH)->boxHandle);
    HLock((Handle)theText);
    TESetText((Ptr)*theText, GetHandleSize((Handle)theText), (*tempWCH)->boxHandle);
    TECalText((*tempWCH)->boxHandle);
    DisposeHandle((Handle)theText);
    TEActivate((*tempWCH)->boxHandle);
    TESetSelect(selStart, selEnd, (*tempWCH)->boxHandle);
    TEUpdate(&newRect, (*tempWCH)->boxHandle);
} /* end SizeAES */
 
/* The next few routines add text to the AEStatus window, in various ways */
void AddToAEWindow(Ptr text, long count)
{
    WindowPtr tempW = FindAEWindow();
    WindowPtr temp;
    windowCHandle tempWCH = (windowCHandle)GetWRefCon(tempW);
    GetPort(&temp);
    /* No matter what, if we're adding text we want the window to be visible, even if  */
    /* it's not frontmost */
    if (!((WindowPeek)tempW)->visible) {
        ToggleAEWindow();
    
    }
    /* if it's your preference to see the window any time something happens, it comes forward here */
    if (gPreferences.bringAEUp && FrontWindow() != tempW && !IsModalFront())
        ChangePlane(tempW);                                 /* bring it forward if you want */
    SetPort(tempW);
    /* move to the end of the record */
    TESetSelect(32000, 32000, (*tempWCH)->boxHandle);
    /* add the text */
    TEInsert(text, count, (*tempWCH)->boxHandle);
    SetPort(temp);
} /* end AddToAEWindow */
 
/* routine to add a number easily */
void AddAENum(long theNum)
{
    Str31 theString;
    NumToString(theNum, theString);
    AddToAEWindow(&theString[1], theString[0]);
    
} /* end AddAENum */
 
/* routine to add a PString easily */
void AddAEText(ConstStr255Param theText)
{
    AddToAEWindow(&theText[1], theText[0]);
    
} /* end AddAEText */
 
/* This routine is called when the user selects a window from the Windows menu */
/* it gets the item text, then finds the window that matches it and */
/* makes it frontmost */
void WindowToFront(short which,Str63 name)
{
    Str63 tempTitle;
    Str63 otherName;
    WindowPtr frontW = FrontWindow();
    if (!frontW)
        return;
    if(name == nil){name = &otherName;
        GetMenuItemText(gWindowMenuHandle, which, name);
        }
    do {
        GetWTitle(frontW, tempTitle);
        if (EqualString(name, tempTitle, false, false)) {
            break;
        } else {
            frontW = (WindowPtr)((WindowPeek)frontW)->nextWindow;
        }
    }
            while (frontW);
 
    if (frontW)
        ChangePlane(frontW);
    
} /* end WindowToFront */
 
/* Adds the input window title to the window list.  If it was there  */
/* in an old incarnation, it replaces the old text with the new name */
/* (like when a user saves the file, or does a 'save as' */
void AddToWindowMenu(WindowPtr theWindow, const Str255 oldName)
{
    
    short count = CountMItems(gWindowMenuHandle);
    Str255 wTitle;
    Str255 theItem;
    short iCount = 0;
    GetWTitle(theWindow, wTitle);
    /* if the window already existed, change an existing menu item */
    if (oldName) {
        do {
            iCount++;
            GetMenuItemText(gWindowMenuHandle, iCount, theItem);
            if (EqualString(theItem, oldName, false, false))
                break;
            
        }
                while (true);
        SetMenuItemText(gWindowMenuHandle, iCount, wTitle);
    } else {
        count++;
        InsertMenuItem(gWindowMenuHandle, wTitle, count);
    }
} /* end AddToWindowMenu */
 
/* take this window off the window menu, for whatever reason */
void DeleteFromWindowMenu(WindowPtr theWindow)
{
    register qq;
    Str63 item, name;
    short count = CountMItems(gWindowMenuHandle);
    GetWTitle(theWindow, name);
    for (qq = 1; qq < count + 1; qq++) {
        GetMenuItemText(gWindowMenuHandle, qq, &item);
        if (EqualString(item, name, false, false)) {
            DeleteMenuItem(gWindowMenuHandle, qq);
        }
    }
} /* end DeleteFromWindowMenu */
 
/* CheckExisting is called from our file opener to see if this file */
/* is already open */
Boolean CheckExisting(FSSpecPtr newSpec)
{
    Boolean openNow = false;
    /* check against all the open windows */
    WindowPtr tempWindow = FrontWindow();
    FSSpec tempSpec;
    Boolean wasCh;
    windowCHandle tempWC;
    while(tempWindow){
        if(((WindowPeek)tempWindow)->windowKind == kDocumentWindow){
            tempWC = (windowCHandle)GetWRefCon(tempWindow);
            if(GetHandleSize((Handle)(*tempWC)->fileAliasHandle)){
                ResolveAlias(nil,(*tempWC)->fileAliasHandle,&tempSpec,&wasCh);
                openNow = CompareFSSpecs(&tempSpec,newSpec);
                if(openNow)break;
            }
        
        }
        tempWindow = (WindowPtr)((WindowPeek)tempWindow)->nextWindow;
    }
    
    return(openNow);
} /* end CheckExisting */
 
#undef __MYWINDOWS__