Clipboard.c

/*
    File:       Clipboard.c
 
    Contains:   Clipboard support for simple text application.
 
    Version:    SimpleText 1.4 or later
 
** Copyright 1993-1996 Apple Computer. All rights reserved.
**
**  You may incorporate this sample code into your applications without
**  restriction, though the sample code has been provided "AS IS" and the
**  responsibility for its operation is 100% yours.  However, what you are
**  not permitted to do is to redistribute the source as "DSC Sample Code"
**  after having made changes. If you're going to re-distribute the source,
**  we require that you make it clear in the source that the code was
**  descended from Apple Sample Code, but that you've made changes.
 
*/
 
#include "MacIncludes.h"
 
#include "Clipboard.h"
 
 
// --------------------------------------------------------------------------------------------------------------
// GLOBALS FOR THIS FILE ONLY
// --------------------------------------------------------------------------------------------------------------
static Handle           gScrapHandle;
static long             gCurrentOffset;
static QDProcsPtr       gSavedProcs;
static QDProcs          gMyProcs;
static CQDProcs         gMyColorProcs;
 
// --------------------------------------------------------------------------------------------------------------
// INTERNAL ROUTINES
// --------------------------------------------------------------------------------------------------------------
static pascal void GetPICTData(Ptr dataPtr, short byteCount)
/*
    replacement for the QuickDraw bottleneck routine
*/
{ 
    long    longCount = byteCount;
    
    BlockMoveData((*gScrapHandle)+gCurrentOffset, dataPtr, longCount);
    gCurrentOffset += longCount;
    
} // GetPICTData
 
#if GENERATINGCFM
    static RoutineDescriptor gGetPICTDataRD = BUILD_ROUTINE_DESCRIPTOR(uppQDGetPicProcInfo, GetPICTData);
    static QDGetPicUPP gGetPICTData = &gGetPICTDataRD;
#else
    static QDGetPicUPP gGetPICTData = NewQDGetPicProc(GetPICTData);
#endif
 
// --------------------------------------------------------------------------------------------------------------
 
static OSErr DrawPictureFromHandleAndOffset(
    Rect    * pWhereToDraw,         // draw picture at this location
    Handle  sourceHandle,           // handle containing data
    long    sourceOffset)           // offset within handle to start at
{
    OSErr       anErr;
    Rect        whereToDraw = *pWhereToDraw;
    PicHandle   tempPict = (PicHandle) NewHandle(sizeof(Picture));
    
    anErr = MemError();
    nrequire(anErr, FailedNewHandle);
        
    // calculate the rectangle in which to draw, save the picture header into
    // our handle
    {   
    PicPtr  pPicture;
    
    pPicture = (PicPtr)((*sourceHandle) + sourceOffset);
    whereToDraw.right = whereToDraw.left + pPicture->picFrame.right - pPicture->picFrame.left;
    whereToDraw.bottom = whereToDraw.top + pPicture->picFrame.bottom - pPicture->picFrame.top;
    BlockMoveData((Ptr)pPicture, (Ptr)*tempPict, sizeof(Picture));
    }
 
    // store into globals for our GetPicProc in preparation for the draw
    gScrapHandle = sourceHandle;
    gCurrentOffset = sourceOffset + sizeof(Picture);
 
    // install our GetPic proc
    if (gMachineInfo.theEnvirons.hasColorQD)
        SetStdCProcs(&gMyColorProcs);
    else
        SetStdProcs(&gMyProcs);
    gMyProcs.getPicProc = gGetPICTData;
    gMyColorProcs.getPicProc = gGetPICTData;
    gSavedProcs = (*qd.thePort).grafProcs;
    if (gMachineInfo.theEnvirons.hasColorQD)
        (*qd.thePort).grafProcs = (QDProcsPtr)&gMyColorProcs;
    else
        (*qd.thePort).grafProcs = &gMyProcs;
    
    // Draw the picture
    DrawPicture(tempPict, &whereToDraw);
    
    // remove our GetPic proc
    (*qd.thePort).grafProcs = gSavedProcs;
 
    DisposeHandle((Handle)tempPict);
    
// FALL THROUGH EXCEPTION HANDLING
FailedNewHandle:
    return anErr;
    
} // DrawPictureFromHandleAndOffset
 
// --------------------------------------------------------------------------------------------------------------
// OOP INTERFACE ROUTINES
// --------------------------------------------------------------------------------------------------------------
static OSErr    ClipboardUpdateWindow(WindowRef pWindow, WindowDataPtr pData)
{
#pragma unused (pData)
 
    OSErr       anErr;
    FontInfo    theInfo;
    long        scrapResult;
    long        offset;
    ResType     validScrapType = '????';
    Rect        topAreaRect;
    RgnHandle   oldClip = NewRgn();
    
    // clear out any data that was there before
    GetClip(oldClip);
    EraseRect(&GetWindowPort(pWindow)->portRect);
    
    // get that scrap!
    anErr = LoadScrap();
    nrequire(anErr, LoadScrap);
    
    // figure out the scrap type and offset
    {
    short i = 0;
    ResType     scrapTypes[] = {'TEXT', 'PICT', '????'};
 
    while (scrapTypes[i] != '????')
        {
        scrapResult = GetScrap(nil, scrapTypes[i], &offset);
        if (scrapResult > 0)
            {
            validScrapType = scrapTypes[i];
            break;
            }
        ++i;
        }
    }
    
    // setup for the drawing
    TextFont(applFont);
    TextSize(9);
    GetFontInfo(&theInfo);
 
    // caclulate our area at the top to say what type of contents the scrap is
    topAreaRect = GetWindowPort(pWindow)->portRect;
    topAreaRect.bottom = topAreaRect.top + theInfo.ascent + theInfo.descent + theInfo.leading * 2 + 2;
 
    // draw two lines under the area to separate it from the rest of the window
    MoveTo(topAreaRect.left, topAreaRect.bottom - 2);
    Line(topAreaRect.right - topAreaRect.left, 0);
    Move(0, 2);
    Line(-(topAreaRect.right - topAreaRect.left), 0);
 
    // draw a string describing the contents
    {
    Str255  theString;
    
    switch (validScrapType)
        {
        case 'PICT':
            GetIndString(theString, kClipboardStrings, iClipboardPICT);
            break;
            
        case 'TEXT':
            GetIndString(theString, kClipboardStrings, iClipboardText);
            break;
            
        default:
            if (InfoScrap()->scrapCount == 0)
                GetIndString(theString, kClipboardStrings, iClipboardNone);
            else
                GetIndString(theString, kClipboardStrings, iClipboardUnknown);
            break;
        }
        
    MoveTo(topAreaRect.left + 4, topAreaRect.bottom - 4);
    DrawString(theString);
    }
    
    // calculate the part *not* in our top area 
    topAreaRect.top = topAreaRect.bottom+1;
    topAreaRect.bottom = GetWindowPort(pWindow)->portRect.bottom;
 
    // remember the scrap count -- if it changes, we do an update!
    ((ClipboardDataPtr)pData)->scrapCount = InfoScrap()->scrapCount;
 
    // now, draw the contents, if we have a legal type to use
    {
    Rect    clipArea = topAreaRect;
    Handle  scrapHandle = InfoScrap()->scrapHandle;
    
    clipArea.right -= 15;
    clipArea.bottom -= 15;
    ClipRect(&clipArea);
    switch (validScrapType)
        {
        case 'PICT':
            DrawPictureFromHandleAndOffset(&clipArea, 
                    scrapHandle, offset);
            break;
            
        case 'TEXT':
            {
            char    oldState;
                    
            oldState = HGetState(scrapHandle);
            HLock(scrapHandle);
            clipArea.right -= 15;
            clipArea.bottom -= 15;
            TETextBox(*scrapHandle+offset, scrapResult, &clipArea, teJustLeft);
            }
            break;
        }
    }
    
    // finally draw the grow icon, but omit our top area rect from the drawing
    ClipRect(&topAreaRect);
    DrawGrowIcon(pWindow);
    
    SetClip(oldClip);
    DisposeRgn(oldClip);
    
    UnloadScrap();
    
// FALL THROUGH EXCEPTION HANDLING
LoadScrap:
    return anErr;
    
} // ClipboardUpdateWindow
 
 
// --------------------------------------------------------------------------------------------------------------
 
static Boolean  ClipboardFilterEvent(WindowRef pWindow, WindowDataPtr pData, EventRecord *pEvent)
{   
 
    // Force an update on scrap changes during activate/deactivate.
 
    switch (pEvent->what)
        {
        case nullEvent:
        case activateEvt:
            if (LoadScrap() == noErr)
                {
                PScrapStuff pScrap = InfoScrap();
                
                if (pScrap->scrapCount != ((ClipboardDataPtr)pData)->scrapCount)
                    {
                    GrafPtr pPort = (GrafPtr)GetWindowPort(pWindow);
                    
                    SetPort(pPort);
                    InvalRect(&pPort->portRect);
                    }
                }
            break;
        
        // Follow the HI guidelines and hide the clipboard when we are suspended.
    
        case osEvt:
            if (((pEvent->message >> 24) & 0x0FF) == suspendResumeMessage)
                {
                if((pEvent->message & resumeFlag)==0)   // suspending
                    {
                    HideWindow(pWindow);
                    pWindow = FrontWindow();
                    if (pWindow)
                        HiliteWindow(pWindow, false);
                    }
                else                                    // resuming
                    ShowWindow(pWindow);
                }
            break;
            
        } // switch(what)
    
    return false;
    
} // ClipboardFilterEvent
 
 
// --------------------------------------------------------------------------------------------------------------
 
static OSErr    ClipboardKeyEvent(WindowRef pWindow, WindowDataPtr pData, EventRecord *pEvent, Boolean isMotionKey)
{   
    #pragma unused(pWindow, pData, pEvent, isMotionKey)
 
    return noErr;
 
} // ClipboardKeyEvent
 
 
// --------------------------------------------------------------------------------------------------------------
 
static OSErr    ClipboardGetBalloon(WindowRef pWindow, WindowDataPtr pData, 
        Point *localMouse, short * returnedBalloonIndex, Rect *returnedRectangle)
{
#pragma unused (pWindow, pData, localMouse, returnedRectangle)
 
    *returnedBalloonIndex = iNoBalloon;
    
    return noErr;
 
} // ClipboardGetBalloon
 
// --------------------------------------------------------------------------------------------------------------
 
static OSErr    ClipboardGetDocumentRect(WindowRef pWindow, WindowDataPtr pData, 
            LongRect * documentRectangle, Boolean forGrow)
{
#pragma unused (pWindow, pData, forGrow)
    
    Rect    maxSize = (**GetGrayRgn()).rgnBBox;
    
    RectToLongRect(&maxSize, documentRectangle);
    
    return noErr;
    
} // ClipboardGetDocumentRect
 
 
// --------------------------------------------------------------------------------------------------------------
 
static OSErr    ClipboardCloseWindow(WindowRef pWindow, void* refCon)
{   
#pragma unused(pWindow,refCon)
 
    ChangeCommandName(cShowClipboard, kClipboardStrings, iClipboardShow);
    UnloadScrap();
    
    return noErr;
 
} // ClipboardCloseWindow
 
 
// --------------------------------------------------------------------------------------------------------------
 
static OSErr    ClipboardMakeWindow(WindowRef pWindow, WindowDataPtr pData)
{
#pragma unused (pWindow)
 
    pData->hasGrow              = true;
    pData->pFilterEvent         = (FilterEventProc)     ClipboardFilterEvent;
    pData->pKeyEvent            = (KeyEventProc)        ClipboardKeyEvent;
    pData->pGetBalloon          = (GetBalloonProc)      ClipboardGetBalloon;
    pData->pUpdateWindow        = (UpdateWindowProc)    ClipboardUpdateWindow;
    pData->pGetDocumentRect     = (GetDocumentRectProc) ClipboardGetDocumentRect;
    pData->pCloseWindow         = (CloseWindowProc)     ClipboardCloseWindow;
    
    pData->contentRect.right = pData->contentRect.left + 
                    qd.screenBits.bounds.right - qd.screenBits.bounds.left - 96;
    pData->contentRect.bottom = pData->contentRect.top + 150;
    MoveWindow(pWindow, 
            qd.screenBits.bounds.left + 4, 
            qd.screenBits.bounds.bottom - 154, false);
    
    ChangeCommandName(cShowClipboard, kClipboardStrings, iClipboardHide);
 
    return noErr;
    
} // ClipboardMakeWindow
 
 
// --------------------------------------------------------------------------------------------------------------
 
OSErr   ClipboardPreflightWindow(PreflightPtr pPreflightData)
{   
    pPreflightData->resourceID          = kClipboardWindowID;
    pPreflightData->continueWithOpen    = true;
    pPreflightData->makeProcPtr         = ClipboardMakeWindow;
    pPreflightData->storageSize         = sizeof(ClipboardDataRecord);
    
    return noErr;
    
} // ClipboardPreflightWindow
 
// --------------------------------------------------------------------------------------------------------------
 
void ClipboardGetFileTypes(OSType * pFileTypes, OSType * pDocumentTypes, short * numTypes)
{
#pragma unused (pFileTypes, pDocumentTypes, numTypes)
 
} // ClipboardGetFileTypes