home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connectio…eloper Series 2005 March / Dev.CD Mar 05.iso / What's New / Technical Notes and Q&As / ADC Reference Library / technotes / tn2002 / downloads / ScriptablePrintLoop.hqx / ScriptablePrintLoop / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-12-04  |  40.3 KB  |  1,071 lines

  1. /*
  2.  IMPORTANT: This Apple software is supplied to you by Apple Computer,
  3.  Inc. ("Apple") in consideration of your agreement to the following terms,
  4.  and your use, installation, modification or redistribution of this Apple
  5.  software constitutes acceptance of these terms.  If you do not agree with
  6.  these terms, please do not use, install, modify or redistribute this Apple
  7.  software.
  8.  
  9.  In consideration of your agreement to abide by the following terms, and
  10.  subject to these terms, Apple grants you a personal, non-exclusive
  11.  license, under Apple‚Äôs copyrights in this original Apple software (the
  12.  "Apple Software"), to use, reproduce, modify and redistribute the Apple
  13.  Software, with or without modifications, in source and/or binary forms;
  14.  provided that if you redistribute the Apple Software in its entirety and
  15.  without modifications, you must retain this notice and the following text
  16.  and disclaimers in all such redistributions of the Apple Software.
  17.  Neither the name, trademarks, service marks or logos of Apple Computer,
  18.  Inc. may be used to endorse or promote products derived from the Apple
  19.  Software without specific prior written permission from Apple. Except as
  20.  expressly stated in this notice, no other rights or licenses, express or
  21.  implied, are granted by Apple herein, including but not limited to any
  22.  patent rights that may be infringed by your derivative works or by other
  23.  works in which the Apple Software may be incorporated.
  24.  
  25.  The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES
  26.  NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE
  27.  IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
  28.  PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION
  29.  ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
  30.  
  31.  IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
  32.  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  33.  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  34.  INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
  35.  MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND
  36.  WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT
  37.  LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY
  38.  OF SUCH DAMAGE.  */
  39.  
  40. /*------------------------------------------------------------------------------
  41.  
  42.     This sample code is the Carbon equivalent of the classic print loop
  43.     documented in Tech Note 1092 "A Print Loop That Cares ...".  This code
  44.     illustrates the use of functions defined in PMCore.h and PMApplication.h
  45.     instead of Printing.h.
  46.     
  47.     The code has been refactored with additional code that demonstrates how
  48.     to implement scriptable printing (handling of the pdoc Apple event) in
  49.     a parallel manner to the original print loop code.
  50.     
  51.     This code is an updated version of the BasicPrintLoop sample that is
  52.     installed with the Mac OS X version 10.3 (Panther) developer tools.
  53.  
  54.     You may incorporate this sample code into your applications without
  55.     restriction, though the sample code has been provided "AS IS" and the
  56.     responsibility for its operation is 100% yours.  However, what you are
  57.     not permitted to do is to redistribute the source as "Apple Sample Code"
  58.     after having made changes. If you're going to re-distribute the source,
  59.     we require that you make it clear in the source that the code was
  60.     descended from Apple Sample Code, but that you've made changes.
  61.     
  62.     Version:    1.1
  63.     
  64.     Technology:    Carbon Printing for Mac OS 8, 9 & X
  65.  
  66.     Copyright ¬© 1998-2003 Apple Computer, Inc  ., All Rights Reserved
  67.     
  68.     Change History:
  69.     
  70.         DH  11/4/03     refactored code and merged in scriptable printing code
  71.         DH  11/7/03     removed PDE code for clarity
  72.  
  73. ------------------------------------------------------------------------------*/
  74.  
  75. /*------------------------------------------------------------------------------
  76.     Includes
  77. ------------------------------------------------------------------------------*/
  78.  
  79. #include <Carbon/Carbon.h>
  80.  
  81. #include <ApplicationServices/ApplicationServices.h>
  82.  
  83.  
  84. #define NUMPAGES    10      // the number of pages in our sample "document" 
  85.  
  86. #define    PRINTSAMPLE    1       //  menu item ID for the Print Sample menu item
  87.  
  88.  
  89. /*------------------------------------------------------------------------------
  90.     Globals and Constants
  91. ------------------------------------------------------------------------------*/
  92. static    Handle    gflatPageFormat = NULL;        // used in FlattenAndSavePageFormat
  93.  
  94. const UInt32 kFileBufferSize = 1024;
  95. enum { kPrintSampleCommandID = 'smpl' };
  96.  
  97. /*------------------------------------------------------------------------------
  98.     Prototypes
  99. ------------------------------------------------------------------------------*/
  100. #pragma mark -----prototypes-----
  101.  
  102. int main ( int argc, char* argv[] );
  103. void Initialize ( void );
  104. void DoEventLoop ( void );
  105. void DoHighLevel ( EventRecord *AERecord );
  106.  
  107.  
  108. OSErr AEOpenHandler ( const AppleEvent *inputEvent, AppleEvent *outputEvent, SInt32 handlerRefCon );
  109. OSErr AEOpenDocHandler ( const AppleEvent *inputEvent, AppleEvent *outputEvent, SInt32 handlerRefCon );
  110. OSErr AEQuitHandler ( const AppleEvent *inputEvent, AppleEvent *outputEvent, SInt32 handlerRefCon );
  111.  
  112. static OSStatus AppHandler ( EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData );
  113.  
  114. OSStatus DoPageSetupDialog ( PMPrintSession printSession, PMPageFormat* pageFormat );
  115. OSStatus DoPrintDialog ( PMPrintSession printSession, PMPageFormat pageFormat, PMPrintSettings* printSettings, Boolean* shouldPrintPtr );
  116. OSStatus FlattenAndSavePageFormat ( PMPageFormat pageFormat );
  117. OSStatus LoadAndUnflattenPageFormat ( PMPageFormat* pageFormat );
  118. OSStatus DetermineNumberOfPagesInDoc ( PMPageFormat pageFormat, UInt32* numPages );
  119. void PostPrintingErrors ( OSStatus status );
  120. void DrawPage ( CGContextRef context, char* documentDataPtr, UInt32 pageNumber );
  121. OSStatus PrintPage ( PMPrintSession session, PMPageFormat format, char* documentDataPtr, UInt32 pageNumber );
  122. OSStatus PrintDocument ( PMPrintSession session, PMPrintSettings settings, PMPageFormat format, CFStringRef documentTitle, char* documentDataPtr );
  123. void DoPrintSample ( void );
  124. WindowRef ShowDocumentWindow ( CFStringRef title, char* data, UInt32 dataLength );
  125. static OSErr AEPrintDocument ( const AppleEvent *inputEvent, AppleEvent *outputEvent, SInt32 handlerRefCon );
  126. OSStatus SetupPDEs ( void );
  127. OSStatus RetrievePDESettings ( PMPageFormat pageFormat, PMPrintSettings printSettings );
  128.  
  129.  
  130.  
  131. #pragma mark -----application code-----
  132.  
  133. int main(int argc, char* argv[])
  134. {
  135.     IBNibRef         nibRef;
  136.     WindowRef         window;
  137.     EventTypeSpec    kEvents[] = {   { kEventClassCommand, kEventCommandProcess } };
  138.     
  139.     OSStatus        err;
  140.  
  141.     // Create a Nib reference passing the name of the nib file (without the .nib extension)
  142.     // CreateNibReference only searches into the application bundle.
  143.     err = CreateNibReference(CFSTR("main"), &nibRef);
  144.     require_noerr( err, CantGetNibRef );
  145.     
  146.     // Once the nib reference is created, set the menu bar. "MainMenu" is the name of the menu bar
  147.     // object. This name is set in InterfaceBuilder when the nib is created.
  148.     err = SetMenuBarFromNib(nibRef, CFSTR("MenuBar"));
  149.     require_noerr( err, CantSetMenuBar );
  150.     
  151.     // Then create a window. "MainWindow" is the name of the window object. This name is set in 
  152.     // InterfaceBuilder when the nib is created.
  153.     err = CreateWindowFromNib(nibRef, CFSTR("MainWindow"), &window);
  154.     require_noerr( err, CantCreateWindow );
  155.  
  156.     // We don't need the nib reference anymore.
  157.     DisposeNibReference(nibRef);
  158.     
  159.     // install AE handlers
  160.     err = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, NewAEEventHandlerUPP(AEPrintDocument), 0, false);
  161.     err = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, NewAEEventHandlerUPP(AEOpenHandler), 0, false);
  162.     err = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, NewAEEventHandlerUPP(AEOpenDocHandler), 0, false);
  163.     err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP(AEQuitHandler), 0, false);
  164.  
  165.     //  Install Carbon Event handler for the application
  166.     InstallApplicationEventHandler( AppHandler, GetEventTypeCount( kEvents ), kEvents, 0, NULL );
  167.     
  168.     // The window was created hidden so show it.
  169.     ShowWindow( window );
  170.     
  171.     // Call the event loop
  172.     RunApplicationEventLoop();
  173.  
  174. CantCreateWindow:
  175. CantSetMenuBar:
  176. CantGetNibRef:
  177.     return err;
  178. }
  179.  
  180.  
  181.  
  182. //-----------------------------------------------------------------------------
  183. //    AppHandler
  184. //-----------------------------------------------------------------------------
  185. //    Deal with commands for the appliation.
  186. //
  187. static OSStatus
  188. AppHandler( EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData )
  189. {
  190.     HICommand        command;
  191.     OSStatus        result = eventNotHandledErr;
  192.     
  193.     GetEventParameter( inEvent, kEventParamDirectObject, typeHICommand, NULL,
  194.             sizeof( HICommand ), NULL, &command );
  195.     
  196.     switch ( command.commandID )
  197.     {
  198.         case kPrintSampleCommandID:
  199.             DoPrintSample();
  200.             result = noErr;
  201.             break;
  202.     }
  203.  
  204.     return result;
  205. }
  206.  
  207.  
  208. #pragma mark -----Apple Event Handlers-----
  209. /*------------------------------------------------------------------------------
  210.  
  211.     Function:    AEOpenHandler
  212.     
  213.     Parameters:
  214.         inputEvent    -    Apple Event to process
  215.         outputEvent    -    returned event
  216.         handlerRefCon - ref con
  217.     Description:
  218.        Does nothing.
  219. ------------------------------------------------------------------------------*/
  220. OSErr AEOpenHandler ( const AppleEvent *inputEvent, AppleEvent *outputEvent, SInt32 handlerRefCon )
  221. {
  222.     #pragma unused (inputEvent,outputEvent,handlerRefCon)
  223.     
  224.     return(noErr);
  225. }   //  AEOpenHandler
  226.  
  227.  
  228. /*------------------------------------------------------------------------------
  229.  
  230.     Function:    AEOpenDocHandler
  231.     
  232.     Parameters:
  233.         inputEvent    -    Apple Event to process
  234.         outputEvent    -    returned event
  235.         handlerRefCon - ref con
  236.     Description:
  237.        Does nothing.
  238.  
  239. ------------------------------------------------------------------------------*/
  240. OSErr AEOpenDocHandler ( const AppleEvent *inputEvent, AppleEvent *outputEvent, SInt32 handlerRefCon )
  241. {
  242.     #pragma unused (inputEvent,outputEvent,handlerRefCon)
  243.     
  244.     return(errAEEventNotHandled); 
  245.     
  246. }   //  AEOpenDocHandler
  247.  
  248.  
  249. /*------------------------------------------------------------------------------
  250.  
  251.     Function:    AEQuitHandler
  252.     
  253.     Parameters:
  254.         inputEvent    -    Apple Event to process
  255.         outputEvent    -    returned event
  256.         handlerRefCon - ref con
  257.     Description:
  258.        Process the high level kAEQuitApplication Apple Event.
  259.        Simply calls QuitApplicationEventHandler() to break out of RunApplicationEventLoop().
  260.  
  261. ------------------------------------------------------------------------------*/
  262. OSErr AEQuitHandler ( const AppleEvent *inputEvent, AppleEvent *outputEvent, SInt32 handlerRefCon )
  263. {
  264.     #pragma unused (inputEvent,outputEvent,handlerRefCon)
  265.     
  266.     QuitApplicationEventLoop();
  267.  
  268.     return(noErr);
  269. }   //  AEQuitHandler
  270.  
  271.  
  272. #pragma mark -----printing functions-----
  273. /*------------------------------------------------------------------------------
  274.  
  275.     Function:    DoPageSetupDialog
  276.     
  277.     Parameters:
  278.         printSession    -    current printing session
  279.         pageFormat      -    a PageFormat object addr
  280.     
  281.     Description:
  282.         If the caller passes in an empty PageFormat object, DoPageSetupDialog
  283.         creates a new one, otherwise it validates the one provided by the caller.
  284.         It then invokes the Page Setup dialog and checks for Cancel. Finally it
  285.         flattens the PageFormat object so it can be saved with the document.
  286.         Note that the PageFormat object is modified by this function.
  287.     
  288. ------------------------------------------------------------------------------*/
  289. OSStatus DoPageSetupDialog ( PMPrintSession printSession, PMPageFormat* pageFormat )
  290. {
  291.     assert( printSession != NULL );
  292.     
  293.     OSStatus    status = noErr;
  294.     Boolean        accepted = true;
  295.     
  296.     //    Set up a valid PageFormat object.
  297.     if ( *pageFormat == kPMNoPageFormat )
  298.     {
  299.         status = PMCreatePageFormat(pageFormat);
  300.     
  301.         //    Note that PMPageFormat is not session-specific, but calling
  302.         //    PMSessionDefaultPageFormat assigns values specific to the printer
  303.         //    associated with the current printing session.
  304.         if ( (status == noErr) && (*pageFormat != kPMNoPageFormat) )
  305.         {
  306.             status = PMSessionDefaultPageFormat( printSession, *pageFormat );
  307.         }
  308.     }
  309.     else
  310.     {
  311.         status = PMSessionValidatePageFormat( printSession, *pageFormat, kPMDontWantBoolean );
  312.     }
  313.  
  314.     //    Display the Page Setup dialog.    
  315.     if ( status == noErr )
  316.     {
  317.         status = PMSessionPageSetupDialog( printSession, *pageFormat, &accepted );
  318.         if ( (status == noErr) && !accepted )
  319.         {
  320.             status = kPMCancel;        // user clicked Cancel button
  321.         }
  322.     }    
  323.                 
  324.     //    If the user did not cancel, flatten and save the PageFormat object
  325.     //    with our document.
  326.     if ( status == noErr )
  327.     {
  328.         status = FlattenAndSavePageFormat( *pageFormat );
  329.     }
  330.  
  331.     return status;
  332. }    //    DoPageSetupDialog
  333.  
  334.  
  335. /*------------------------------------------------------------------------------
  336.     Function:    DoPrintDialog
  337.         
  338.     Parameters:
  339.         printSession    -    current printing session
  340.         pageFormat      -    a PageFormat object addr
  341.         printSettings    -    a PrintSettings object addr
  342.             
  343.     Description:
  344.         If the caller passes an empty PrintSettings object, DoPrintDialog creates
  345.         a new one, otherwise it validates the one provided by the caller.
  346.         It then invokes the Print dialog and checks for Cancel.
  347.         Note that the PrintSettings object is modified by this function.
  348.         *PrintSettings will either be valid (and caller needs to release) or NULL
  349.         
  350. ------------------------------------------------------------------------------*/
  351. OSStatus DoPrintDialog ( PMPrintSession printSession, PMPageFormat pageFormat,
  352.                             PMPrintSettings* printSettings, Boolean* shouldPrintPtr )
  353. {
  354.     assert( printSession != NULL );
  355.     assert( pageFormat != kPMNoPageFormat );
  356.     
  357.     OSStatus    status = noErr;
  358.     UInt32        realNumberOfPagesinDoc;
  359.     
  360.     //    In this sample code the caller provides a valid PageFormat reference but in
  361.     //    your application you may want to load and unflatten the PageFormat object
  362.     //    that was saved at PageSetup time.  See LoadAndUnflattenPageFormat below.
  363.     
  364.     //    Set up a valid PrintSettings object.
  365.     if ( *printSettings == kPMNoPrintSettings )
  366.     {
  367.         status = PMCreatePrintSettings( printSettings );    
  368.  
  369.         //    Note that PMPrintSettings is not session-specific, but calling
  370.         //    PMSessionDefaultPrintSettings assigns values specific to the printer
  371.         //    associated with the current printing session.
  372.         if ( (status == noErr) && (*printSettings != kPMNoPrintSettings) )
  373.         {
  374.             status = PMSessionDefaultPrintSettings( printSession, *printSettings );
  375.         }
  376.     }
  377.     else
  378.     {
  379.         status = PMSessionValidatePrintSettings( printSession, *printSettings, kPMDontWantBoolean );
  380.     }
  381.     
  382.     //    Before displaying the Print dialog, we calculate the number of pages in the
  383.     //    document.  On Mac OS X this is useful because we can prime the Print dialog
  384.     //    with the actual page range of the document and prevent the user from entering
  385.     //    out-of-range numbers.  This is not possible on Mac OS 8 and 9 because the driver,
  386.     //    not the printing manager, controls the page range fields in the Print dialog.
  387.  
  388.     //    Calculate the number of pages required to print the entire document.
  389.     if ( status == noErr )
  390.     {
  391.         status = DetermineNumberOfPagesInDoc( pageFormat, &realNumberOfPagesinDoc );
  392.  
  393.         //    Set a valid page range before displaying the Print dialog
  394.         if ( status == noErr )
  395.         {
  396.             status = PMSetPageRange( *printSettings, 1, realNumberOfPagesinDoc );
  397.         }
  398.     }
  399.  
  400.     //    Display the Print dialog.
  401.     if ( status == noErr )
  402.     {
  403.         status = PMSessionPrintDialog( printSession, *printSettings, pageFormat, shouldPrintPtr );
  404.     }
  405.         
  406.     return status;
  407. }    //    DoPrintDialog
  408.  
  409.  
  410. /*------------------------------------------------------------------------------
  411.     Function:
  412.         FlattenAndSavePageFormat
  413.     
  414.     Parameters:
  415.         pageFormat    -    a PageFormat object
  416.     
  417.     Description:
  418.         Flattens a PageFormat object so it can be saved with the document.
  419.         Assumes caller passes a validated PageFormat object.
  420.         
  421. ------------------------------------------------------------------------------*/
  422. OSStatus FlattenAndSavePageFormat ( PMPageFormat pageFormat )
  423. {
  424.     assert( pageFormat != kPMNoPageFormat );
  425.     
  426.     OSStatus    status;
  427.     Handle      flatFormatHandle = NULL;
  428.     
  429.     //    Flatten the PageFormat object to memory.
  430.     status = PMFlattenPageFormat( pageFormat, &flatFormatHandle );
  431.  
  432.     if ( status == noErr )
  433.     {
  434.         //    Write the PageFormat data to file.
  435.         //    In this sample code we simply copy it to a global.    
  436.         gflatPageFormat = flatFormatHandle;
  437.     }
  438.  
  439.     return status;
  440. }    //    FlattenAndSavePageFormat
  441.  
  442.  
  443.  
  444. /*------------------------------------------------------------------------------
  445.     Function:    LoadAndUnflattenPageFormat
  446.     
  447.     Parameters:
  448.         pageFormat    - PageFormat object read from document file
  449.     
  450.     Description:
  451.         Gets flattened PageFormat data from the document and returns a PageFormat
  452.         object.
  453.         The function is not called in this sample code but your application
  454.         will need to retrieve PageFormat data saved with documents.
  455.         
  456. ------------------------------------------------------------------------------*/
  457. OSStatus LoadAndUnflattenPageFormat ( PMPageFormat* pageFormatPtr )
  458. {
  459.     assert( pageFormatPtr != NULL );
  460.     
  461.     OSStatus    status = noErr;
  462.     Handle      flatFormatHandle = NULL;
  463.  
  464.     //    Read the PageFormat flattened data from file.
  465.     //    In this sample code we simply copy it from a global.
  466.     flatFormatHandle = gflatPageFormat;
  467.     if ( flatFormatHandle )
  468.     {
  469.         //    Convert the PageFormat flattened data into a PageFormat object.
  470.         status = PMUnflattenPageFormat( flatFormatHandle, pageFormatPtr );
  471.     }
  472.     else
  473.     {
  474.         *pageFormatPtr = kPMNoPageFormat;
  475.     }
  476.     
  477.     return status;
  478. }    //    LoadAndUnflattenPageFormat
  479.  
  480.  
  481.  
  482. /*------------------------------------------------------------------------------
  483.     Function:    DetermineNumberOfPagesInDoc
  484.     
  485.     Parameters:
  486.         pageFormat    - a PageFormat object addr
  487.         numPages    - on return, the size of the document in pages
  488.             
  489.     Description:
  490.         Calculates the number of pages needed to print the entire document.
  491.         
  492. ------------------------------------------------------------------------------*/
  493. OSStatus DetermineNumberOfPagesInDoc ( PMPageFormat pageFormat, UInt32* numPages )
  494. {
  495.     assert( pageFormat != kPMNoPageFormat );
  496.     assert( numPages != NULL );
  497.     
  498.     OSStatus    status;
  499.     PMRect      pageRect;
  500.  
  501.     //    PMGetAdjustedPageRect returns the page size taking into account rotation,
  502.     //    resolution and scaling settings.
  503.     status = PMGetAdjustedPageRect( pageFormat, &pageRect );
  504.  
  505.     //    In this sample code we simply return a hard coded number.  In your application,
  506.     //    you will need to figure out how many page rects are needed to image the
  507.     //    current document.
  508.     *numPages = NUMPAGES;
  509.  
  510.     return status;
  511.     
  512. }    //    DetermineNumberOfPagesinDoc
  513.  
  514.  
  515. /*------------------------------------------------------------------------------
  516.     Function:    PostPrintingErrors
  517.     
  518.     Parameters:
  519.         status    -    error code
  520.     
  521.     Description:
  522.         This is where we could post an alert to report any problem reported
  523.         by the Printing Manager.
  524.         
  525. ------------------------------------------------------------------------------*/
  526. void PostPrintingErrors ( OSStatus status )
  527. {
  528.     #pragma unused (status)    
  529. }    //    PostPrintingErrors
  530.  
  531.  
  532.  
  533.  
  534.  
  535. /*------------------------------------------------------------------------------
  536. Function:    DrawPage
  537.  
  538. Parameters:
  539. context            -    destination context for the drawing
  540. documentDataPtr    -     sample data (replace with your own document data)
  541. pageNumber        -    which page to draw
  542.  
  543. Description:
  544. This sample drawing function renders a fake page to the destination context.
  545.  
  546. ------------------------------------------------------------------------------*/
  547. void DrawPage ( CGContextRef context, char* documentDataPtr, UInt32 pageNumber )
  548. {
  549.     assert( context != NULL );
  550.     assert( documentDataPtr != NULL );
  551.     assert( strlen( documentDataPtr ) >= 192 ); //  we use the first 192 characters of the data
  552.     
  553.     char buffer[256];
  554.  
  555.     //     set colors, text drawing mode, and font then draw page number using Quartz 2D
  556.     //     draw some of the document contents in different colors
  557.     sprintf( buffer, "Page Number: %u", (unsigned int)pageNumber );
  558.  
  559.     CGContextSetRGBFillColor( context, 0.0, 0.0, 0.0, 1.0 );
  560.     CGContextSetRGBStrokeColor( context, 1.0, 0.0, 0.0, 1.0 );
  561.  
  562.     CGContextSetTextDrawingMode( context, kCGTextFill );
  563.     CGContextSelectFont( context, "Helvetica", 48.0, kCGEncodingMacRoman );
  564.  
  565.     CGContextShowTextAtPoint( context, 100.0, 700.0, buffer, strlen( buffer ) );
  566.  
  567.     CGContextSetRGBFillColor( context, 1.0, 0.0, 0.0, 1.0 );
  568.     CGContextShowTextAtPoint( context, 100.0, 400.0, documentDataPtr, 64 );
  569.  
  570.     CGContextSetRGBFillColor( context, 0.0, 1.0, 0.0, 1.0 );
  571.     CGContextShowTextAtPoint( context, 100.0, 300.0, documentDataPtr + 64, 64 );
  572.  
  573.     CGContextSetRGBFillColor( context, 0.0, 0.0, 1.0, 1.0 );
  574.     CGContextShowTextAtPoint( context, 100.0, 200.0, documentDataPtr + 128, 64 );
  575. }   //  DrawPage
  576.  
  577.  
  578. /*------------------------------------------------------------------------------
  579. Function:    PrintPage
  580.  
  581. Parameters:
  582. session            -    print session for this job
  583. format            -    page format information for this document
  584. documentDataPtr    -     sample data (replace with your own document data)
  585. pageNumber        -    which page to draw
  586.  
  587. Description:
  588. This function prints a page for the session using the provided formatting information
  589.  
  590. ------------------------------------------------------------------------------*/
  591. OSStatus PrintPage ( PMPrintSession session, PMPageFormat format, char* documentDataPtr, UInt32 pageNumber )
  592. {
  593.     assert( session != NULL );
  594.     assert( format != kPMNoPageFormat );
  595.     assert( documentDataPtr != NULL );
  596.     assert( strlen( documentDataPtr ) >= 192 ); //  we use the first 192 characters of the data
  597.     
  598.     CGContextRef printingContext = NULL;
  599.  
  600.     //    Set up a page for printing.  Under the classic Printing Manager, applications
  601.     //    could provide a page rect different from the one in the print record to achieve
  602.     //    scaling. This is no longer recommended and on Mac OS X, the PageRect argument
  603.     //    is ignored.
  604.     OSStatus status = PMSessionBeginPage( session, format, NULL );
  605.  
  606.     //    get cg context for drawing
  607.     if ( status == noErr )
  608.     {
  609.         status = PMSessionGetGraphicsContext( session, kPMGraphicsContextCoreGraphics, (void**) &printingContext );
  610.  
  611.         if ( status == noErr )
  612.         {
  613.             //    Render the page contents to the printing context
  614.             DrawPage( printingContext, documentDataPtr, pageNumber );
  615.         }
  616.  
  617.         //    end page
  618.         status = PMSessionEndPage( session );
  619.     }
  620.  
  621.     return status;
  622. }   //  PrintPage
  623.  
  624.  
  625.  
  626. /*------------------------------------------------------------------------------
  627. Function:    PrintDocument
  628.  
  629. Parameters:
  630. session            -    print session for this job
  631. settings        -    print settings for this job
  632. format            -    page format information for this document
  633. documentDataPtr    -     sample data (replace with your own document data)
  634.                     note that this sample uses the first 192 bytes of the document data
  635.  
  636. Description:
  637. This function prints a document for the session using the provided formatting and settings information
  638.  
  639. ------------------------------------------------------------------------------*/
  640. OSStatus PrintDocument ( PMPrintSession session, PMPrintSettings settings, PMPageFormat format, CFStringRef documentTitle, char* documentDataPtr )
  641. {
  642.     assert( session != NULL );
  643.     assert( settings != kPMNoPrintSettings );
  644.     assert( format != kPMNoPageFormat );
  645.     assert( documentTitle != NULL );
  646.     assert( documentDataPtr != NULL );
  647.     assert( strlen( documentDataPtr ) >= 192 ); //  we use the first 192 characters of the data
  648.     
  649.     UInt32    realNumberOfPagesinDoc, pageNumber, firstPage, lastPage;
  650.     
  651.     //    set an appropriate document title based on the document data - call PMSetJobName( settings, jobName )
  652.     OSStatus status = PMSetJobNameCFString( settings, documentTitle );
  653.     
  654.     //    determine the first and last pages from the print settings
  655.     if ( status == noErr )
  656.     {
  657.         status = PMGetFirstPage( settings, &firstPage );
  658.         if ( status == noErr )
  659.         {
  660.             status = PMGetLastPage( settings, &lastPage );
  661.         }
  662.     }
  663.  
  664.     //    pin against actual number of pages in doc
  665.     if ( status == noErr )
  666.     {
  667.         status = DetermineNumberOfPagesInDoc( format, &realNumberOfPagesinDoc );
  668.         if ( (status == noErr) && (realNumberOfPagesinDoc < lastPage) )
  669.         {
  670.             lastPage = realNumberOfPagesinDoc;
  671.         }
  672.     }
  673.  
  674.     //    Before executing the print loop, tell the Carbon Printing Manager which pages
  675.     //    will be spooled so that the progress dialog can reflect an accurate page count.
  676.     //    This is recommended on Mac OS X.  On Mac OS 8 and 9, we have no control over
  677.     //    what the printer driver displays.
  678.     if ( status == noErr )
  679.     {
  680.         status = PMSetFirstPage( settings, firstPage, false );
  681.  
  682.         if (status == noErr)
  683.         {
  684.             status = PMSetLastPage( settings, lastPage, false );
  685.         }
  686.     }
  687.  
  688.     //    Note, we don't have to worry about the number of copies.  The printing
  689.     //    manager handles this.  So we just iterate through the document from the
  690.     //    first page to be printed, to the last.
  691.     if ( status == noErr )
  692.     {
  693.         //    Let the printing system know that we want to draw using Quartz 2D
  694.         CFStringRef         strings[1];
  695.         CFArrayRef          ourGraphicsContextsArray;
  696.  
  697.         strings[0] = kPMGraphicsContextCoreGraphics; // This is important!
  698.  
  699.         ourGraphicsContextsArray = CFArrayCreate( kCFAllocatorDefault, (const void **)strings, 1, &kCFTypeArrayCallBacks );
  700.  
  701.         if ( ourGraphicsContextsArray != NULL )
  702.         {
  703.             status = PMSessionSetDocumentFormatGeneration( session, kPMDocumentFormatPDF, ourGraphicsContextsArray, NULL );
  704.             CFRelease( ourGraphicsContextsArray );
  705.         }
  706.         else
  707.         {
  708.             status = memFullErr;
  709.         }
  710.         
  711.         if ( status == noErr )
  712.         {
  713.             //    Begin a new print job.
  714.             status = PMSessionBeginDocument( session, settings, format );
  715.             if (status == noErr)
  716.             {
  717.                 //    Print the selected range of pages in the document.
  718.                 pageNumber = firstPage;
  719.     
  720.                 /* Note that we check PMSessionError immediately before beginning a new
  721.                 page. This handles user cancelling appropriately. Also, if we got
  722.                 an error on any previous iteration of the print loop, we break
  723.                 out of the loop.
  724.                 */
  725.                 while ( (pageNumber <= lastPage) && (status == noErr) && (PMSessionError( session ) == noErr) )
  726.                 {
  727.                     //    Note, we don't have to deal with the classic Printing Manager's
  728.                     //    128-page boundary limit.
  729.     
  730.                     //    Print the page
  731.                     status = PrintPage( session, format, documentDataPtr, pageNumber );
  732.     
  733.                     //    And loop.
  734.                     pageNumber++;
  735.                 } // end while loop
  736.     
  737.                 // Close the print job.  This dismisses the progress dialog on Mac OS X.
  738.                 OSStatus tempErr = PMSessionEndDocument( session );
  739.                 if ( status == noErr )
  740.                 {
  741.                     status = tempErr;
  742.                 }
  743.             }
  744.         }
  745.     }
  746.  
  747.     return status;
  748. }   //  PrintDocument
  749.  
  750.  
  751. /*------------------------------------------------------------------------------
  752. Function:    DoPrintSample
  753.  
  754. Parameters:
  755. None
  756. Description:
  757. Sample print loop.
  758. ------------------------------------------------------------------------------*/
  759. void DoPrintSample ( void )
  760. {
  761.     OSStatus        status = noErr;
  762.     PMPageFormat    pageFormat = kPMNoPageFormat;
  763.     PMPrintSettings    printSettings = kPMNoPrintSettings;
  764.     PMPrintSession    printSession = NULL;
  765.     Handle            oldPrintRecord = NULL;    // place holder for old print record
  766.     CFStringRef        docTitle = CFSTR( "Scriptable Printing Job" );
  767.     char            fakeDataPtr[] = "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789";
  768.     Boolean         shouldPrint = true;
  769.  
  770.     //    Initialize the printing manager and create a printing session.
  771.     status = PMCreateSession( &printSession );
  772.     if ( status == noErr )
  773.     {
  774.         //    If your application has an old print record, it can be converted into new
  775.         //    PMPageFormat and PMPrintSettings objects.  In this sample code, we skip this step.
  776.         if ( oldPrintRecord != NULL )
  777.         {
  778.             status = PMSessionConvertOldPrintRecord( printSession, oldPrintRecord, &printSettings, &pageFormat );
  779.         }
  780.     
  781.         //    Display the Page Setup dialog.
  782.         if ( status == noErr )
  783.         {
  784.             //  set up the pageFormat and show the Page Setup dialog
  785.             //  we must free the pageFormat object (will be valid or NULL)
  786.             status = DoPageSetupDialog( printSession, &pageFormat );
  787.     
  788.             //    Display the Print dialog.
  789.             if ( status == noErr )
  790.             {
  791.                 //  set up the printSettings and show the Print dialog
  792.                 //  we must free the printSettings object (will be valid or NULL)
  793.                 status = DoPrintDialog( printSession, pageFormat, &printSettings, &shouldPrint );
  794.                 
  795.                 //    Execute the print loop.
  796.                 if ( status == noErr && shouldPrint )
  797.                 {
  798.                     status = PrintDocument( printSession, printSettings, pageFormat, docTitle, fakeDataPtr );
  799.  
  800.                     if ( status == kPMCancel )
  801.                     {
  802.                         status = noErr;
  803.                     }
  804.                 }
  805.             }
  806.         }
  807.     
  808.         //    Release the printSettings and pageFormat objects.
  809.         //  PMRelease decrements the ref count of the allocated object.
  810.         //    We let the Printing Manager decide when to release the allocated memory.
  811.         PMRelease( printSettings );
  812.         PMRelease( pageFormat );
  813.         
  814.         //    Terminate the current printing session.
  815.         PMRelease( printSession );
  816.     }
  817.     
  818.     if ( status != noErr )
  819.     {
  820.         PostPrintingErrors(status);
  821.     }
  822.     
  823.     return;
  824. }   //  DoPrintSample
  825.  
  826.  
  827. /*------------------------------------------------------------------------------
  828.  
  829. Function:    ShowDocumentWindow
  830.  
  831. Parameters:
  832. title        -    title for the sample document window
  833. data        -    sample data to put in the window
  834. dataLength    -    how much data is there?
  835.  
  836. Description:
  837. This function displays a sample document window.
  838.  
  839. ------------------------------------------------------------------------------*/
  840. WindowRef ShowDocumentWindow ( CFStringRef title, char* data, UInt32 dataLength )
  841. {
  842.     Rect windowRect = { 0, 0, 500, 500 };
  843.     WindowRef windowRef = NULL;
  844.  
  845.     // Create a window to display the file's data.
  846.     OSStatus status = CreateNewWindow( kDocumentWindowClass, kWindowNoAttributes, &windowRect, &windowRef );
  847.  
  848.     if ( status == noErr )
  849.     {
  850.         MacMoveWindow( windowRef, 100, 100, true );
  851.         MacShowWindow( windowRef );
  852.  
  853.         // Use the file's name as the window's title.
  854.         if ( title )
  855.         {
  856.             SetWindowTitleWithCFString( windowRef, title );
  857.         }
  858.  
  859.         if ( data != NULL )
  860.         {
  861.             // Display the contents of the file.
  862.             SetPortWindowPort( windowRef );
  863.             MoveTo( 10, 10 );
  864.             MacDrawText( &data[0], 0, dataLength );
  865.         }
  866.     }
  867.  
  868.     return windowRef;
  869. }   //  ShowDocumentWindow
  870.  
  871.  
  872.  
  873. /*------------------------------------------------------------------------------
  874.  
  875. Function:    ReadFileData
  876.  
  877. Parameters:
  878.     fileRef    -    file to read from
  879.     ioCount    -    (in)number of bytes to read, (out)number of bytes read
  880.     buffer  -   buffer to hold incoming bytes
  881. Description:
  882.     Open the file referenced by fileRef and read [0, ioCount] bytes into buffer.
  883.     Return bytes actually read in ioCount and error status in status
  884.  
  885. ------------------------------------------------------------------------------*/
  886. OSStatus ReadFileData ( FSRef fileRef, long* ioCount, char* buffer )
  887. {
  888.     OSStatus     status = noErr;
  889.     SInt16        fileRefNum = 0;
  890.     
  891.     status = FSOpenFork( &fileRef, 0, NULL, fsRdPerm, &fileRefNum );
  892.     if ( status == noErr )
  893.     {
  894.         // read the data (1024 max)
  895.         FSRead(fileRefNum, ioCount, &buffer[0]);
  896.         
  897.         // Close file.
  898.         FSClose(fileRefNum);
  899.     }
  900.     
  901.     return status;
  902. }   //  ReadFileData
  903.  
  904.  
  905. /*------------------------------------------------------------------------------
  906.  
  907. Function:    AEPrintDocument
  908.  
  909. Parameters:
  910. inputEvent    -    Apple Event to process
  911. outputEvent    -    returned event
  912. handlerRefCon - ref con
  913. Description:
  914. Process the high level kAEPrintDocuments Apple Event. A Print Settings is
  915. extracted from the Apple Event and coerced to a PMPrintSettings and a PMPrinter.
  916. The coerced PMPrintSettings is used to print each document in the document list.
  917. The PMPrinter, if any, represents the desired target printer. We set the sessions
  918. printer to be that printer.
  919.  
  920. This sample is limited to processing only the first 1024 bytes of a text file.
  921.  
  922. ------------------------------------------------------------------------------*/
  923. OSErr AEPrintDocument ( const AppleEvent *inputEvent, AppleEvent *outputEvent, SInt32 handlerRefCon )
  924. {
  925. #pragma unused (outputEvent,handlerRefCon)
  926.  
  927.     assert( inputEvent != NULL );
  928.  
  929.     OSStatus        status = noErr;
  930.     PMPrintSettings    printSettings = kPMNoPrintSettings;
  931.     PMPrinter        printer = NULL;
  932.     Boolean            showPrintDialog = false;
  933.     PMPrintSession     session = NULL;
  934.     PMPageFormat     pageFormat = kPMNoPageFormat;
  935.     Boolean            printIt = true;
  936.  
  937.     #define kDontCare NULL
  938.     
  939.     //  In this next section, grab the parameters from the incoming Apple event
  940.     //  Note that since everything is optional, we're ignoring status
  941.     //  If the data isn't in the event then we just move on.
  942.  
  943.     //    Grab the print settings
  944.     //     They may not have requested any specific print settings.
  945.     //    Later on, we'll use the default print settings in this case.
  946.     status = AEGetParamPtr( inputEvent, keyAEPropData, kPMPrintSettingsAEType, kDontCare, &printSettings, sizeof( void* ), kDontCare );
  947.     
  948.     //     Grab the requested printer, if any
  949.     //     They may not have requested a target printer.
  950.     status = AEGetParamPtr( inputEvent, keyAEPropData, kPMPrinterAEType, kDontCare, &printer, sizeof( void* ), kDontCare );
  951.  
  952.     //     See if we need to show the print dialog.
  953.     //    If the scripter didn't specify, default to not showing the print dialog
  954.     status = AEGetParamPtr( inputEvent, kPMShowPrintDialogAEType, typeBoolean, kDontCare, &showPrintDialog, sizeof( Boolean ), kDontCare );
  955.  
  956.     //    Now that we've retrieved the PMPrintSettings, PMPrinter, and showPrintDialog items from the event, handle each file in the list
  957.  
  958.     // Create the session we'll use to print.
  959.     status = PMCreateSession( &session );
  960.     
  961.     if ( status == noErr )
  962.     {
  963.         // Set the output to the target printer.
  964.         if ( printer != NULL )
  965.         {
  966.             status = PMSessionSetCurrentPMPrinter( session, printer );
  967.         }
  968.     
  969.         //    if the scripter didn't request any specific print settings, load up the default set
  970.         if ( printSettings == kPMNoPrintSettings )
  971.         {
  972.             status = PMCreatePrintSettings( &printSettings );
  973.             if ( status == noErr )
  974.             {
  975.                 status = PMSessionDefaultPrintSettings( session, printSettings );
  976.             }
  977.         }
  978.     
  979.         // Create a default pageformat
  980.         // In a real application, unflatten the page format stored with the document and use that
  981.         status = PMCreatePageFormat(&pageFormat);
  982.         
  983.         if ( (status == noErr) && (pageFormat != kPMNoPageFormat) )
  984.         {
  985.             PMSessionDefaultPageFormat(session, pageFormat);
  986.         }
  987.     
  988.         //    Show the print dialog?
  989.         //    Note: only show the print dialog once for a given pdoc event - use the resulting settings for all files in the event
  990.         if ( showPrintDialog )
  991.         {
  992.             PMSessionPrintDialog( session, printSettings, pageFormat, &printIt );
  993.         }
  994.  
  995.         if ( printIt )
  996.         {
  997.             AEDescList        docList;
  998.             long            index, itemsInList;
  999.             
  1000.             // Get the file list.
  1001.             status = AEGetParamDesc( inputEvent, keyDirectObject, typeAEList, &docList );
  1002.     
  1003.             if ( status == noErr )
  1004.             {
  1005.                 status = AECountItems( &docList, &itemsInList );            // how many files passed in
  1006.     
  1007.                 // Walk the list of files.
  1008.                 for ( index = 1; index <= itemsInList; index++ )
  1009.                 {
  1010.                     AEKeyword        keywd;
  1011.                     DescType        returnedType;
  1012.                     Size            actualSize;
  1013.                     HFSUniStr255    fileName;
  1014.                     CFStringRef        fileNameRef=NULL;
  1015.                     WindowRef        windowRef = NULL;
  1016.                     char            buffer[ kFileBufferSize ];
  1017.                     long            count = sizeof( buffer );
  1018.                     FSRef            fileRef;
  1019.     
  1020.                     // Get the file ref.
  1021.                     status = AEGetNthPtr( &docList, index, typeFSRef, &keywd, &returnedType,
  1022.                                         (Ptr)(&fileRef), sizeof( fileRef ), &actualSize );
  1023.     
  1024.                     // Get the file name to use in the window's title.
  1025.                     if ( status == noErr )
  1026.                     {
  1027.                         status = FSGetCatalogInfo( &fileRef, 0, NULL, &fileName,NULL,NULL);
  1028.                     }
  1029.                     
  1030.                     if ( status == noErr )
  1031.                     {
  1032.                         fileNameRef = CFStringCreateWithCharacters(kCFAllocatorDefault, &fileName.unicode[0], fileName.length);
  1033.                     }
  1034.     
  1035.                     // Open the file for reading.
  1036.                     if ( status == noErr )
  1037.                     {
  1038.                         status = ReadFileData( fileRef, &count, &buffer[0] );
  1039.                         if ( status == noErr )
  1040.                         {
  1041.                             //    Show a sample document window
  1042.                             windowRef = ShowDocumentWindow( fileNameRef, buffer, count );
  1043.     
  1044.                             status = PrintDocument( session, printSettings, pageFormat, fileNameRef, buffer );
  1045.     
  1046.                             //    We're done with the filename string
  1047.                             CFRelease( fileNameRef );
  1048.     
  1049.                             //    We're done with the window
  1050.                             DisposeWindow( windowRef );
  1051.                         }
  1052.                     }
  1053.                 }
  1054.             }
  1055.         }
  1056.         
  1057.         // Clean up.
  1058.         PMRelease( pageFormat );
  1059.         PMRelease( session );
  1060.     }
  1061.  
  1062.     // We're done so get rid of everything.
  1063.     PMRelease( printSettings );
  1064.     PMRelease( printer );
  1065.  
  1066.     return status;
  1067. }   //  AEPrintDocument
  1068.  
  1069.  
  1070.  
  1071.