Important: The information in this document is obsolete and should not be used for new development.
Putting Data in the Scrap
Your application should write data to the scrap (or to its own private scrap) whenever the user chooses the Cut or Copy command and the document the user is working with contains a selection. In addition, if your application uses a private scrap, your application must copy the contents of its private scrap to the scrap upon receiving a suspend event. The next sections explain how to perform these tasks.Handling the Cut Command
When the user chooses the Cut command and the document the user is working with contains a selection, your application should remove the data from the selection and save the data (either in the scrap or in your application's private scrap).The SurfWriter application doesn't use a private scrap; whenever the user performs a cut operation, SurfWriter writes the current selection to the scrap. The SurfWriter application does define its own private scrap format type and writes this format to the scrap, along with one of the standard scrap formats. Listing 2-1 shows SurfWriter's routine for handling the Cut command (it also uses this routine for the Copy command).
Listing 2-1 Writing data to the scrap
PROCEDURE DoCutOrCopyCmd (cut: Boolean); VAR window: WindowPtr; windowType: Integer; isText: Boolean; ptrToScrapData: Ptr; length, myLongErr: LongInt; BEGIN window := FrontWindow; windowType := MyGetWindowType(window); IF windowType = kMyDocWindow THEN BEGIN ptrToScrapData := NewPtr(kDefaultSize); isText := MyIsSelectionText; IF isText THEN {selection contains text} BEGIN MyGetSelection('SURF', ptrToScrapData, length); myLongErr := ZeroScrap; myLongErr := PutScrap(length, 'SURF', ptrToScrapData); IF myLongErr <> noErr THEN DoError(myLongErr); MyGetSelection('TEXT', ptrToScrapData, length); myLongErr := PutScrap(length, 'TEXT', ptrToScrapData); IF myLongErr <> noErr THEN DoError(myLongErr); END ELSE {selection contains graphics} BEGIN MyGetSelection('PICT', ptrToScrapData, length); myLongErr := ZeroScrap; myLongErr := PutScrap(length, 'PICT', ptrToScrapData); IF myLongErr <> noErr THEN DoError(myLongErr); END; DisposePtr(ptrToScrapData); IF cut THEN MyDeleteSelection; END ELSE IF windowType <> kNIL THEN BEGIN {window is a dialog box} IF cut THEN DialogCut(window) ELSE DialogCopy(window); END; END;TheDoCutOrCopyCmd
procedure first determines the type of window that is frontmost. If the frontmost window is a document window,DoCutOrCopyCmd
uses another application-defined routine,MyIsSelectionText
, to determine whether the current selection contains text or graphics. If the selection contains only text, SurfWriter writes the data to the scrap using two formats: its own private format ('SURF'
) and the standard format'TEXT'
. TheDoCutOrCopyCmd
procedure uses another application-defined routine,MyGetSelection
, to return the current selection in a particular format.DoCutOrCopyCmd
then calls theZeroScrap
function to clear the contents of the scrap. After callingZeroScrap
,DoCutOrCopyCmd
callsPutScrap
, specifying the length of the data, a pointer to the data, and identifying the scrap format type as'SURF'
.DoCutOrCopyCmd
then uses theMyGetSelection
routine again, this time to return the current selection in the'TEXT'
format type.DoCutOrCopyCmd
callsPutScrap
to write the data to the scrap, specifying a pointer to the data and identifying the scrap format type as'TEXT'
.If the selection contains a picture,
DoCutOrCopyCmd
uses theMyGetSelection
routine to return the current selection using the'PICT'
format type. After callingZeroScrap
,DoCutOrCopyCmd
callsPutScrap
to write the data to the scrap, specifying a pointer to the data and identifying the scrap format type as'PICT'
.Finally, if
DoCutOrCopyCmd
was called as a result of the user performing a cut operation,DoCutOrCopyCmd
deletes the selection from the current document.If the frontmost window is a dialog box,
DoCutOrCopyCmd
uses the Dialog Manager'sDialogCut
(orDialogCopy
) procedure to write the selected data to the scrap.Note that you should always call
ZeroScrap
before writing data to the scrap. If you write multiple formats to the scrap, callZeroScrap
once before you write the first format to the scrap.You should always write data to the scrap in your application's preferred order
of formats. For example, SurfWriter's preferred format for text data is its own private format ('SURF'
), so it writes that format first and then writes the standard format'TEXT'
.If your application uses TextEdit in its document windows, then use the TextEdit routine
TECut
(orTECopy
) instead ofZeroScrap
andPutScrap
. See Listing 2-8 on page 2-29 for an application-defined routine that uses TextEdit routines to help handle the Cut and Copy commands.If your application uses a private scrap, then copy the selected data to your private scrap rather than to the scrap. For example, the SurfPaint application uses a private scrap. Listing 2-2 shows SurfPaint's application-defined routine that handles the Cut command by writing the selected data to its private scrap.
Listing 2-2 Writing data to a private scrap
PROCEDURE DoCutOrCopyCmd (cut: Boolean); VAR window: WindowPtr; windowType: Integer; BEGIN window := FrontWindow; windowType := MyGetWindowType(window); IF windowType = kMyDocWindow THEN BEGIN MyWriteDataToPrivateScrap; {reset gScrapNewData to indicate that this app's private } { scrap now contains the most recent data} IF gScrapNewData THEN gScrapNewData := FALSE; IF cut THEN MyDeleteSelection; END ELSE IF windowType <> kNil THEN BEGIN {window is a dialog window} IF cut THEN DialogCut(window) ELSE DialogCopy(window); END; END;The application-definedDoCutOrCopyCmd
procedure shown in Listing 2-2 calls another application-defined procedure,MyWriteDataToPrivateScrap
, to write the data in the current selection to the application's private scrap. SurfPaint uses the application-defined global variablegScrapNewData
to indicate when data should be read from the scrap instead of its own private scrap as a result of the user choosing the Paste command. Upon receiving a resume event, if the contents of the scrap have changed, SurfPaint sets thegScrapNewData
global variable toTRUE
. If the user chooses Paste andgScrapNewData
isTRUE
, SurfPaint reads the scrap to get the data to paste; otherwise SurfPaint reads its own private scrap to get the data to paste.If the user chooses Cut or Copy before the next Paste command, SurfPaint writes the newly selected data to its private scrap, eliminating the need to read the previous contents of the scrap, and thus the
DoCutOrCopyCmd
procedure resets thegScrapNewData
global variable toFALSE
.Handling the Copy Command
When the user chooses the Copy command and the document the user is working with contains a selection, your application should copy the selected data (without deleting it) and save the copied data (either in the scrap or in your application's private scrap). See Listing 2-1 on page 2-16, Listing 2-2 on page 2-18, and Listing 2-8 on page 2-29 for application-defined routines that handle the Copy command.Handling Suspend Events
As previously described, if your application uses a private scrap, your application must copy the contents of its private scrap to the scrap upon receiving a suspend event. In addition, if your application supports the Show Clipboard command, it should hide the Clipboard window if it's currently showing (because the contents of the scrap may change while your application yields time to another application).Listing 2-3 shows SurfPaint's routine that responds to suspend events (and resume events).
Listing 2-3 Copying data from the scrap in response to suspend events
PROCEDURE DoSuspendResumeEvent (event: EventRecord); VAR currentFrontWindow: WindowPtr; BEGIN currentFrontWindow := FrontWindow; IF (BAnd(event.message, resumeFlag) <> 0) THEN BEGIN {it's a resume event; } END { handle as shown in Listing 2-6} ELSE BEGIN {it's a suspend event} {copy private scrap to the scrap} MyConvertScrap(kPrivateToClipboard); gInBackground := TRUE; {deactivate front window} DoActivate(currentFrontWindow, NOT gInBackground, event); MyHideClipboardWindow; {hide Clipboard window if showing} MyHideFloatingWindows; {hide any floating windows} END; END;Listing 2-3 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. See Listing 2-6 on page 2-25 for details on handling resume events.For suspend events, the
DoSuspendResumeEvent
procedure calls the application-definedMyConvertScrap
procedure to copy the contents of its private scrap to the scrap. (See Listing 2-7 on page 2-27 for theMyConvertScrap
procedure.) It then sets the private global flaggInBackground
toTRUE
to indicate that the application is in the background. It calls another application-defined routine to deactivate the application's front window. It also calls the application-defined routineMyHideClipboardWindow
to hide the Clipboard window if it's currently showing.