Important: The information in this document is obsolete and should not be used for new development.
Getting Data From the Scrap
Your application should read data from the scrap (or from its own private scrap) whenever the user chooses the Paste command. In addition, if your application uses a private scrap, upon receiving a resume event your application should determine whether the contents of the scrap have changed since the previous resume event, and if so, it should take the appropriate actions. The next sections explain how to perform these tasks.Handling the Paste Command
When the user chooses the Paste command, your application should paste the data last cut or copied by the user. You should insert the new data at the current insertion point or, if a selection exists, replace the selection with the new data. You get the data to paste by reading the data from the scrap or from your application's private scrap.When you read data from the scrap, your application should request the data in its preferred scrap format type. If that type of format doesn't exist in the scrap, then request the data in another format. For example, SurfWriter's preferred format type is
'surf'
, so it requests data from the scrap in this format. If this format isn't in the scrap, SurfWriter requests its next preferred type,'TEXT'
. Finally, if the'TEXT'
format isn't in the scrap, SurfWriter requests the data in the'PICT'
format.If your application doesn't have a preferred scrap format type, then read from the scrap each format type your application supports. Along with a pointer to the data of the requested format type, the
GetScrap
function returns an offset, a value that indicates the relative offset of the start of that format of data in the scrap. (Note that the returned value for the offset is valid only if the Translation Manager isn't available; if the Translation Manager is available, then your application should not rely on the offset value.) The format type with the lowest offset is the preferred format type of the application that put the data in the scrap; thus a format with a lower offset is more likely to contain more information than formats in the scrap with higher offsets. So when the Translation Manager isn't available, use the format with the lowest offset when your application doesn't have a particular scrap format that it prefers.If you request a scrap format type that isn't in the scrap and the Translation Manager is available, the Scrap Manager uses the Translation Manager to convert any one of the scrap format types currently in the scrap into the scrap format type requested by your application. The Translation Manager looks for a translator that can perform one of these translations. If such a translator is available (for example, a translator that can translate the
'SDBS'
scrap format type into the'SURF'
scrap format type), the Translation Manager uses the translator to translate the data in the scrap into the requested scrap format type. If the translation is successful, the Scrap Manager returns to your application the data from the scrap in the requested scrap format type.Listing 2-4 shows SurfWriter's routine for handling the Paste command. The SurfWriter application doesn't use a private scrap; whenever the user performs a paste operation, SurfWriter reads the data that is to be pasted from the scrap.
For document windows, the SurfWriter application first determines whether the data in the scrap exists in its own private scrap format (
'SURF'
) by using theGetScrap
function. If you specify aNIL
handle as the location to return the data,GetScrap
does not return the data but does return as its function result the number of bytes (if any) of data of the specified format that exists in the scrap. If data of this format does exist, SurfWriter reads the data in this format. SurfWriter allocates the handle to hold any returned data but does not need to size the handle;GetScrap
automatically resizes the handle passed to it to the required size to hold the retrieved data. Once the data is retrieved in'SURF'
format, SurfWriter pastes the data into the current document.If the scrap does not contain data in
'SURF'
format (and the available translators can't convert any of the scrap format types in the scrap to the'SURF'
format), SurfWriter determines whether any data in'TEXT'
format exists in the scrap. If so, SurfWriter usesGetScrap
to retrieve the data. Once the data is retrieved in'TEXT'
format, SurfWriter pastes the data into the current document.If the scrap does not contain data in
'TEXT'
format, SurfWriter determines whether any data in'PICT'
format exists in the scrap. If so, SurfWriter usesGetScrap
to retrieve the data. Once the data is retrieved in'PICT'
format, SurfWriter determines the destination rectangle, that is, the rectangle where the picture should be displayed, then uses the QuickDrawDrawPicture
procedure to draw the picture in the window. SurfWriter stores a handle to this picture and sets other application-defined variables as needed.Listing 2-4 Handling the Paste command using the scrap
PROCEDURE DoPasteCommand; VAR window: windowPtr; windowType: LongInt; offset: LongInt; sizeOfSurfData: LongInt; sizeOfPictData: LongInt; sizeOfTextData: LongInt; hDest: Handle; myData: MyDocRecHnd; teHand: TEHandle; destRect: Rect; myErr: OSErr; BEGIN window := FrontWindow; windowType := MyGetWindowType(window); IF windowType = kMyDocWindow THEN BEGIN {handle Paste command in document window. Check } { whether the scrap contains any data. This app } { checks for its preferred format type, 'SURF', first} sizeOfSurfData := GetScrap(NIL, 'SURF', offset); IF sizeOfSurfData > 0 THEN BEGIN {allocate handle to hold data from scrap--GetScrap } hDest := NewHandle(0); { automatically resizes it} HLock(hDest); {put data into memory referenced thru hDest handle} sizeOfSurfData := GetScrap(hDest, 'SURF', offset); {paste the data into the current document} MyPasteSurfData(hDest); HUnlock(hDest); DisposeHandle(hDest); END ELSE BEGIN {if no 'SURF' data in scrap, check for 'TEXT'} sizeOfTextData := GetScrap(NIL, 'TEXT', offset); IF sizeOfTextData > 0 THEN BEGIN {allocate handle to hold data from scrap--GetScrap } hDest := NewHandle(0); { automatically resizes it} HLock(hDest); {put data into memory referenced thru hDest handle} sizeOfTextData := GetScrap(hDest, 'TEXT', offset); {paste the text into the current document} MyPasteText(hDest); HUnlock(hDest); DisposeHandle(hDest); END ELSE {if no 'TEXT' data in scrap, check for 'PICT'} BEGIN sizeOfPictData := GetScrap(NIL, 'PICT', offset); IF sizeOfPictData > 0 THEN BEGIN {allocate handle to hold scrap data--GetScrap } hDest := NewHandle(0); { automatically resizes it} HLock(hDest); {put data into memory referenced thru hDest handle} sizeOfPictData := GetScrap(hDest, 'PICT', offset); {calculate destination rectangle for plotting the } { picture} MyGetDestRect(hDest, destRect); DrawPicture(PicHandle(hDest), destRect); {save information about the picture} myData := MyDocRecHnd(GetWRefCon(window)); myData^^.pictNum := myData^^.pictNum +1; myData^^.pictDestRect[myData^^.pictNum] := destRect; IF myData^^.windowPicHndl[myData^^.pictNum] = NIL THEN myData^^.windowPicHndl[myData^^.pictNum] := PicHandle(NewHandle(Size(sizeOfPictData))); myData^^.windowPicHndl[myData^^.pictNum] := PicHandle(hDest); myErr := HandToHand(Handle (myData^^.windowPicHndl[myData^^.pictNum])); HUnlock(hDest); DisposeHandle(hDest); END; {of sizeOfPictData > 0} END; {of "if no 'TEXT' data, check for 'PICT'"} END; {of "if no 'surf' data, check for 'TEXT'"} END {of "if windowType = kMyDocWindow"} ELSE {window is not a document window} BEGIN IF windowType <> kNil THEN BEGIN {handle Paste command in dialog box, } { DialogPaste checks whether the dialog box has any } { editText items and if so, uses TEPaste to paste } { any text from the scrap to the currently selected } { editText item, if any} DialogPaste(window); END; END; END;If your application uses TextEdit in its document windows, then use the TextEdit routineTEPaste
instead ofGetScrap
to read the data to paste. See Listing 2-9 on page 2-30 for an application-defined routine that uses TextEdit to help handle the application's Paste command.If your application uses a private scrap, then read the data from your private scrap rather than from the scrap (unless the scrap contains the more recent data). Listing 2-5 shows SurfPaint's application-defined routine that handles the Paste command by reading the desired data from its private scrap.
Listing 2-5 Handling the Paste command using a private scrap
PROCEDURE DoPasteCmd; VAR window: WindowPtr; windowType: Integer; dataToPaste: Ptr; BEGIN window := FrontWindow; windowType := MyGetWindowType(window); IF windowType = kMyDocWindow THEN BEGIN IF gNewScrap THEN {if new data in scrap, } BEGIN { copy to private scrap} MyConvertScrap(kClipboardToPrivate); gNewScrap := FALSE; END; {get the data to paste from app's private scrap} dataToPaste := NewPtr(kDefaultSize); MyReadDataFromPrivateScrap(dataToPaste); MyPasteData(dataToPaste); DisposePtr(dataToPaste); END ELSE IF windowType <> kNil THEN BEGIN {window is a dialog box} DialogPaste(window); END; END;The SurfPaint application uses a private scrap, and when it receives a resume event, it determines whether the contents of the scrap have changed. If so, SurfPaint sets an application-defined global variable,gScrapNewData
, but does not immediately read in the contents of the scrap. Instead, whenever the user chooses the Paste command, SurfPaint checks the value of this global variable. IfgScrapNewData
isTRUE
SurfPaint reads the new data from the scrap to its private scrap, resets thegScrapNewData
global variable toFALSE
, and then performs the paste operation. SurfPaint also resets the value of thegScrapNewData
global variable toFALSE
whenever the user chooses the Cut or Copy command. By using this method, SurfPaint reads in new data from the scrap only when necessary and avoids reading in data that the user might not use. This method also decreases the time it takes for the application to return to the foreground, as the application avoids or delays any lengthy translation of data from the scrap.Handling Resume Events
As previously described, when your application receives a resume event (and your application uses a private scrap), your application should determine whether the contents of the scrap have changed since the previous suspend event. If the contents of the scrap have changed, your application must be sure to use the new data in the scrap for the user's next Paste command (unless the user chooses Cut or Copy before choosing Paste).In addition, if your application supports the Show Clipboard command and the Clipboard window was showing at the time of the previous suspend event, your application should update its Clipboard window to show the new contents of the scrap.
Listing 2-6 shows SurfPaint's procedure for handling resume events (and suspend events).
Listing 2-6 Handling resume events
PROCEDURE DoSuspendResumeEvent (event: EventRecord); VAR currentFrontWindow: WindowPtr; BEGIN currentFrontWindow := FrontWindow; IF (BAnd(event.message, resumeFlag) <> 0) THEN BEGIN {it's a resume event} IF (BAnd(event.message, convertClipboardFlag) <> 0) THEN BEGIN {set flag to indicate there's new data in the scrap} gNewScrap := TRUE; END; gInBackground := FALSE; {app no longer in background} {activate front window} DoActivate(currentFrontWindow, NOT gInBackground, event); {show Clipboard window if it was showing at last suspend } { event and update its contents to match scrap} MyShowClipboardWindow(gNewScrap); MyShowFloatingWindows; {show any floating windows} END ELSE BEGIN {it's a suspend event, } { handle as shown in Listing 2-3} END; END;Listing 2-6 shows a procedure that responds to suspend and resume events. TheDoSuspendResumeEvent
procedure first gets a pointer to the front window using the Window Manager functionFrontWindow
. It then examines bit 0 of themessage
field of the event record to determine whether the event is a suspend or resume event. If the event is a resume event, the code examines bit 1 of themessage
field of the event record to determine whether it needs to read in the contents of the scrap. If so, the code sets an application-defined global variable,gNewScrap
, to indicate that new data exists in the scrap. When the user next chooses the Paste command, SurfPaint checks the value of thegNewScrap
global variable and, if it'sTRUE
, reads the data from the scrap to its private scrap and then performs the paste operation. If the user chooses the Cut or Copy command before choosing Paste, then SurfPaint resets thegNewScrap
global variable toFALSE
to indicate that its private scrap contains the most recent data for the Paste command. This technique allows SurfPaint to delay or avoid any lengthy translation of data from the scrap to its private scrap and decreases the time it takes for SurfPaint to return to the foreground.The
DoSuspendResumeEvent
procedure then sets a private global flag,gInBackground
, toFALSE
, to indicate that the application is not in the background. It then calls another application-defined routine,DoActivate
, to activate the application's front window. It also calls the application-defined routineMyShowClipboardWindow
to show the Clipboard window and update its contents if it was showing at the time of the previous suspend event.