home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / scnote / scrnfkey.022 / ScreenFKEY.p < prev    next >
Text File  |  1989-10-04  |  9KB  |  282 lines

  1. { pasmat -q -k -t 2 -: aFKEY6.p FKEY6.p -r -u }
  2.  
  3. {*#############################################################################################
  4. #                                                                   
  5. #    Apple Macintosh Developer Technical Support                        
  6. #                                                                   
  7. #    FKEY6 : Saves the contents of the main Macintosh screen to a PICT file.    
  8. #
  9. #    ScreenFKEY.p                                                           
  10. #                                                                   
  11. #    Copyright ⌐ 1989 Apple Computer, Inc.                            
  12. #    All rights reserved.                                            
  13. #                                                                    
  14. #    Versions:                                                            
  15. #            1.00                     10/89                            
  16. #                                                                   
  17. #    Components:                                                        
  18. #            ScreenFKEY.p            October 1, 1989                     
  19. #            ScreenFKEY.a              October 1, 1989                     
  20. #            ScreenFKEY.make          October 1, 1989                    
  21. #                                                                   
  22. #    ScreenFKEY is a basic example on how to spool a PICT file to disk by replacing the 
  23. #    bottleneck PutPICProc, it saves the contents of the screen to a file. The FKEY creates 
  24. #    ten files Screen 0 through Screen 9; it is necessary to erase or rename old files when 
  25. #    the limit is reached. 
  26. #    
  27. #    This FKEY works in any Macintosh computer and saves the screen regardless of the 
  28. #    setting of the screen; to use, it has to be added to the System file using ResEdit.
  29. #
  30. ############################################################################################*}
  31.  
  32.  
  33.  
  34. { The basic strategy is as follows:
  35.   1.- Make sure we can create the file.
  36.   2.- If Color QuickDraw is available then use a color port
  37.       else use a regular B/W port
  38.   3.- Replace the bottleneck procedure for our own putPict procedure
  39.   4.- Open a picture, 3 above guarantees that data will go to disk
  40.   5.- CopyBits the whole screen into itself causing the stuff to go
  41.       to the picture.
  42.   6.- Close the picture
  43.   7.- Finish the PICT file.
  44.   8.- Leave things (QDProcs, port) the way they were.       }
  45.  
  46. { Another point of interest is the technique used to provide pseudo
  47.   globals needed for the process to work by tagging the fields to the
  48.   end of the grafport record.           }
  49.  
  50. UNIT FKEY;
  51.  
  52. INTERFACE
  53.  
  54.     USES Memtypes, Quickdraw, OSIntf, ToolIntf, PackIntf;
  55.  
  56. TYPE
  57.      BitMapPtr = ^BitMap; { Type casting stuff }
  58.  
  59. { structure used to mantain some globals that can not be accessed
  60.   in the standard way when QD calls the bottleneck procedure   }
  61.  
  62.     GDataRec = RECORD
  63.         pHand: PicHandle; { picture being created }
  64.         gRef: INTEGER; { file reference number }
  65.         fileOK: BOOLEAN; { problems flag }
  66.     END;
  67.     
  68.     { now lets put together a port + our data structure      }
  69.     GportPlus = RECORD
  70.         TRUEPort: CGrafPort;
  71.         GDStuff: GDataRec;
  72.     END;
  73.     
  74.     GPPtr = ^GportPlus;
  75.  
  76. { main procedure for the FKEY }
  77. PROCEDURE PICTOut;
  78.  
  79. { PutPICTData replaces the standard bottleneck proc }
  80. PROCEDURE PutPICTData(dataPtr: Ptr;  byteCount: INTEGER);
  81.  
  82.  
  83.  
  84. IMPLEMENTATION
  85.  
  86. PROCEDURE PutPICTData{(dataPtr: Ptr; byteCount: INTEGER)};
  87.  
  88. VAR
  89.     longCount: LONGINT; { byte count }
  90.     myPortPlus: GPPtr; { global data pointer }
  91.  
  92. BEGIN
  93.  
  94.     GetPort(grafPtr(myPortPlus)); { to access the global data }
  95.     
  96.     longCount := byteCount;
  97.     
  98.     IF myPortPlus^.GDStuff.fileOK THEN BEGIN { do this only if file is still OK }
  99.         
  100.         IF FSWrite(myPortPlus^.GDStuff.gRef, longCount, dataPtr) <> noErr THEN
  101.             { something bad occurred, must delete file }
  102.             myPortPlus^.GDStuff.fileOK := FALSE;
  103.         
  104.         IF myPortPlus^.GDStuff.pHand <> NIL THEN { if the picture is already open }
  105.             { keep size up to date so QD }
  106.             { can adjust for oddness        }
  107.             myPortPlus^.GDStuff.pHand^^.picSize := myPortPlus^.GDStuff.pHand^^.picSize + longCount;
  108.     END
  109.  
  110. END;
  111.  
  112. { The main procedure of the FKEY.
  113.   This code installs the bottle neck procedure, opens the picture and does all
  114.   the house keeping.
  115. }
  116.  
  117. PROCEDURE PICTOut;
  118.  
  119. VAR
  120.     err: OSErr;
  121.     i: INTEGER;
  122.     longCount, longZero: LONGINT;
  123.     myProcs: CQDProcs;
  124.     myOldProcs: QDProcs;
  125.     
  126.     savePictSizeFrame: Picture;
  127.     
  128.     nameStr: Str255;
  129.     vrefnum: INTEGER;
  130.     bytesAvail: LONGINT;
  131.     
  132.     oldPort: grafPtr;
  133.     wPortPlus: GportPlus;
  134.     wPortPlusPtr: GPPtr;
  135.     myDev, aDev: GDHandle;
  136.     pictHand: PicHandle;
  137.     globalRef: INTEGER;
  138.     
  139.     theWorld: SysEnvRec;
  140.     
  141.     bitPtr: BitMapPtr;
  142.  
  143.     { We use this procedure to kill the file if something fails.
  144.     We don't want to leave files laying around, do we? }
  145.     PROCEDURE DeathKiss;
  146.     BEGIN
  147.         IF globalRef <> 0 THEN 
  148.             err := FSClose(globalRef);
  149.         
  150.         { close the file if it is open }
  151.         err := FSDelete(nameStr, vrefnum); { to make sure Delete works }
  152.         SysBeep(1); { Let the world know }
  153.         Exit(PICTOut); { and get out of here! }
  154.     END; {DeathKiss} 
  155.  
  156. BEGIN {PICTOut}
  157.  
  158.     err := SysEnvirons(1, theWorld); { Lets check if we have what we need }
  159.     
  160.     { initializing the pointer to port + global stuff}
  161.     wPortPlusPtr := @wPortPlus;
  162.     
  163.     { Init this variable to help exit procedure clean our stuff when we have to run away. }
  164.     globalRef := 0; { if not zero then a file is open }
  165.     
  166.     { first we see if it is possible to open file }
  167.     
  168.     IF GetVInfo(0, @nameStr, vrefnum, bytesAvail) <> noErr THEN
  169.         { get info on default volume }
  170.         DeathKiss; { error, get out of here! }
  171.  
  172.     { At this point we could check to see if there is room in the volume for the PICT file,
  173.     I chose not to because using a value for the maximun length could probably abort the
  174.     process when there is room for the actual length. I decided that it is better to fail
  175.     when trying to write than kill the saving without reason. }
  176.  
  177.     { We try to create a file 'Screen x' beginning with 0 up to 9, if ten
  178.     files exist we exit and abort the saving              }
  179.     nameStr := 'Screen 0'; { initial name }
  180.     REPEAT BEGIN
  181.         err := Create(nameStr, vrefnum, 'GAO.', 'PICT');
  182.         IF err <> noErr THEN BEGIN
  183.             IF err = dupFNErr THEN BEGIN { if file already there bump the name }
  184.                 nameStr[8] := Chr(Ord(nameStr[8]) + 1);
  185.                 IF nameStr[8] = ':' THEN { ten files should be enough }
  186.                     DeathKiss; { can't make more files, get out of here! }
  187.             END
  188.             ELSE
  189.                 DeathKiss; { error, get out of here! }
  190.         END
  191.     END UNTIL (err = noErr);
  192.     
  193.     IF FSOpen(nameStr, vrefnum, globalRef) <> 0 THEN { if error delete }
  194.         DeathKiss; { error, get out of here! }
  195.  
  196.     { file should be open at this point, so we try to write out the header for the pict file }
  197.     longZero := 0;
  198.     longCount := 4;
  199.     FOR i := 1 TO (532  DIV 4 ) DO BEGIN { init PICT header and then some }
  200.         err := FSWrite(globalRef, longCount, @longZero);
  201.         IF err <> noErr THEN
  202.         DeathKiss {error while file open, get out and kill file }
  203.     END;
  204.         
  205.     IF SetFPos(globalRef, fsFromStart, 522) <> noErr THEN
  206.         DeathKiss; {error while positioning file, exit }
  207.  
  208.     GetPort(oldPort); { save current port }
  209.     
  210.     { init global vars }
  211.     wPortPlus.GDStuff.gRef := globalRef; { for file accesses }
  212.     wPortPlus.GDStuff.pHand := NIL; { no picture when begining }
  213.     wPortPlus.GDStuff.fileOK := TRUE; { we hope }
  214.  
  215.     IF theWorld.hasColorQD THEN BEGIN
  216.         OpenCport(CGrafPtr(wPortPlusPtr)); { Lets get a color port }
  217.         SetStdCProcs(myProcs); { set its bottleneck procs }
  218.         grafPtr(wPortPlusPtr)^.grafProcs := @myProcs;
  219.         myProcs.putPicProc := @PutPICTData;
  220.         myDev := GetMainDevice; { to get to screen }
  221.         bitPtr := BitMapPtr(myDev^^.gdPMap^)
  222.     END ELSE BEGIN
  223.         Openport(grafPtr(wPortPlusPtr)); { Lets get an old style port }
  224.         SetStdProcs(myOldProcs); { set procs }
  225.         grafPtr(wPortPlusPtr)^.grafProcs := @myOldProcs;
  226.         myOldProcs.putPicProc := @PutPICTData;
  227.         bitPtr := BitMapPtr(@wPortPlusPtr^.TRUEPort.portPixMap)
  228.     END;
  229.  
  230.     ClipRect(bitPtr^.bounds); { Just in case, make sure clip region is OK. }
  231.     
  232.     pictHand := OpenPicture(bitPtr^.bounds);
  233.     
  234.     { On a Macintosh II + color port OpenPicture fails if the heap 
  235.     doesn't have at least 1000 bytes free, so we better check 
  236.     if we have a valid handle         }
  237.  
  238.     IF pictHand <> NIL THEN BEGIN
  239.         wPortPlus.GDStuff.pHand := pictHand; { now we have a handle }
  240.     
  241.         { CopyBits will call our procedure }
  242.         CopyBits(bitPtr^, bitPtr^, bitPtr^.bounds, bitPtr^.bounds, srcCopy, NIL);
  243.     
  244.         ClosePicture;
  245.     
  246.     { We need this later to complete file }
  247.         savePictSizeFrame := pictHand^^; 
  248.     
  249.         KillPicture(pictHand) { release all memory }
  250.         
  251.     END ELSE { no picture saved so we have to kill the file }
  252.         wPortPlus.GDStuff.fileOK := FALSE;
  253.  
  254.     { Now we proceed to clean up and to restore the port }
  255.     grafPtr(wPortPlusPtr)^.grafProcs := NIL;
  256.     SetPort(oldPort);
  257.     IF theWorld.hasColorQD THEN
  258.         { Lets get rid of the color port }
  259.         CloseCport(CGrafPtr(wPortPlusPtr))
  260.     ELSE
  261.         ClosePort(grafPtr(wPortPlusPtr)); {or get rid of the normal port}
  262.  
  263.     { after everything is back in good shape we can check if the copybits data
  264.     went to disk a O.K. and if there is a picture at all }
  265.     
  266.     IF NOT (wPortPlus.GDStuff.fileOK) THEN
  267.         DeathKiss; {error while saving file, exit }
  268.     
  269.     IF SetFPos(globalRef, fsFromStart, 512) <> noErr THEN
  270.         DeathKiss; {error while positioning file, exit }
  271.     
  272.     longCount := SizeOf(Picture);
  273.     IF FSWrite(globalRef, longCount, @savePictSizeFrame) <> noErr THEN
  274.         DeathKiss; {error while writing picture size and rect to file, exit }
  275.     
  276.     IF FSClose(globalRef) <> noErr THEN { now close the file }
  277.         DeathKiss; {error while closing file, exit }
  278.  
  279. END; {PICTOut}
  280.  
  281. END. { Unit FKEY }
  282.