Developer --> Technical Publications

 


Using Non-Session Functions

/*------------------------------------------------------------------------------

    This sample code is the Carbon equivalent of the Classic print loop
    documented in Tech Note 1092 "A Print Loop That Cares ...".  This code
    illustrates the use of the Carbon Printing Manager's non-session APIs.
    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 "Apple 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.

    Copyright © 1998-1999 Apple Computer, Inc., All Rights Reserved
	
    Change History:
        13 Sep 99   pd  Updated for Carbon 1.0 SDK
        11 Apr 99   dk  Original version for Developer Preview 1

------------------------------------------------------------------------------*/

#defineTARGET_API_MAC_CARBON 1

/*------------------------------------------------------------------------------
    Includes
------------------------------------------------------------------------------*/
#include <Quickdraw.h>
#include <Fonts.h>
#include <Resources.h>
#include <PMApplication.h>
#include <NumberFormatting.h>   // for NumToString

/*------------------------------------------------------------------------------
    Globals
------------------------------------------------------------------------------*/
short   gAppResFile = 0;        // application's resource file
Handle  gflatPageFormat = nil;  // used in FlattenAndSavePageFormat

/*------------------------------------------------------------------------------
    Prototypes
------------------------------------------------------------------------------*/
int         main(void);
OSStatus    DoPageSetupDialog(PMPageFormat* pageFormat);
OSStatus    DoPrintDialog(PMPageFormat* pageFormat, PMPrintSettings* printSettings);
void        DoPrintLoop(PMPageFormat* pageFormat, PMPrintSettings* printSettings);
OSStatus    FlattenAndSavePageFormat(PMPageFormat pageFormat);
OSStatus    LoadAndUnflattenPageFormat(PMPageFormat* pageFormat);
UInt32      DetermineNumberOfPagesInDoc(PMRect rect);
void        DrawPage(PMRect pageRect, PMPrintContext printingPort, UInt32 pageNumber);
pascal void pIdleProc(void);
void        PostPrintingErrors(OSStatus status);

/*------------------------------------------------------------------------------
    Function: main
	
    Parameters:
        <none>
	
    Description:
        Contains the PMBegin/PMEnd block, within which all other Printing Manager
        calls are made, and within which the PMPageSetup and PMPrintSettings objects
        are valid.
        Displays a Page Setup dialog, then the Print dialog, then executes a simple
        print loop.
	
------------------------------------------------------------------------------*/
int main(void)
{
    OSStatus        status = noErr;
    GrafPtr         oldPort;
    PMPageFormat    pageFormat = kPMNoPageFormat;
    PMPrintSettings printSettings = kPMNoPrintSettings;
    Handle          gOldPrintRecord = nil;  // placeholder for old print record

    //  Standard Toolbox initialization.
    InitCursor();
	
    //  Save the old QD grafport.
    GetPort(&oldPort);
	
    //  Save the current resource file so that it can be used in pIdleProc.
    gAppResFile = CurResFile();
	
    //  Initialize the printing manager. Now a required call.
    status = PMBegin();
    if (status != noErr) return 0;  // pointless to continue if PMBegin fails
	
    //  If your application has an old print record, it can be converted into new
    //  PMPageFormat and PMPrintSettings objects.  In this sample code, we skip this
    //  step.
    if (gOldPrintRecord != nil)
        status = PMConvertOldPrintRecord(gOldPrintRecord, &printSettings, &pageFormat);

    //  Display the Page Setup dialog.
    if (status == noErr)
        status = DoPageSetupDialog(&pageFormat);

    //  Display the Print dialog.
    if (status == noErr)
        status = DoPrintDialog(&pageFormat, &printSettings);

    //  Execute the print loop.
    if (status == noErr)
        DoPrintLoop(&pageFormat, &printSettings);

    //  Deallocate the PageFormat and PrintSettings objects.
    if (pageFormat != kPMNoPageFormat)
        {
        (void)PMDisposePageFormat(pageFormat);
        pageFormat = kPMNoPageFormat;
        }

    if (printSettings != kPMNoPrintSettings)
        {
        (void)PMDisposePrintSettings(printSettings);
        printSettings = kPMNoPrintSettings;
        }

    //  Close the printing manager. Now a required call.
    (void)PMEnd();

    //  Restore the original QD grafport.
    SetPort(oldPort);

    return 0;

}   // main

/*------------------------------------------------------------------------------
    Function: DoPageSetupDialog
	
    Parameters:
        pageFormat  -   a PageFormat object addr
	
    Description:
        If the caller passes in an empty PageFormat object, create a new one,
        otherwise validate the one provided by the caller.
        Invokes the Page Setup dialog and checks for Cancel.
        Flattens the PageFormat object so it can be saved with the document.
        Note that the PageFormat object is modified by this function.
	
------------------------------------------------------------------------------*/
OSStatus DoPageSetupDialog(PMPageFormat* pageFormat)
{
    OSStatus    status;
    Boolean     accepted;
	
    //  Set up a valid PageFormat object.
    if (*pageFormat == kPMNoPageFormat)
    {
        status = PMNewPageFormat(pageFormat);
		
        if ((status == noErr) && (*pageFormat != kPMNoPageFormat))
            status = PMDefaultPageFormat(*pageFormat);
    }
    else
        status = PMValidatePageFormat(*pageFormat, kPMDontWantBoolean);
	
    //  Display the Page Setup dialog.
    if (status == noErr)
    {
        status = PMPageSetupDialog(*pageFormat, &accepted);
        if (!accepted)
            status = kPMCancel; // user clicked Cancel button
    }
				
    //  If the user did not cancel, flatten and save the PageFormat object
    //  with our document.
    if (status == noErr)
        status = FlattenAndSavePageFormat(*pageFormat);

    return status;
	
}   //  DoPageSetupDialog


/*------------------------------------------------------------------------------
    Function: DoPrintDialog
		
    Parameters:
        pageFormat      -   a PageFormat object addr
        printSettings   -   a PrintSettings object addr
			
    Description:
        If the caller passes an empty PrintSettings object, create a new one,
        otherwise validate the one provided by the caller.
        Invokes the Print dialog and checks for Cancel.
        Note that the PrintSettings object is modified by this function.
		
------------------------------------------------------------------------------*/
OSStatus DoPrintDialog(PMPageFormat* pageFormat, PMPrintSettings* printSettings)
{
    OSStatus    status;
    Boolean     accepted;
	
    //  In this sample code the caller provides a valid PageFormat reference but in
    //  your application you may want to load and unflatten the PageFormat object
    //  that was saved at PageSetup time.  See LoadAndUnflattenPageFormat below.
	
    //  Set up a valid PrintSettings object.
    if (*printSettings == kPMNoPrintSettings)
    {
        status = PMNewPrintSettings(printSettings);
		
        if ((status == noErr) && (*printSettings != kPMNoPrintSettings))
            status = PMDefaultPrintSettings(*printSettings);
    }
    else
        status = PMValidatePrintSettings(*printSettings, kPMDontWantBoolean);
	
    //  Display the Print dialog.
    if (status == noErr)
    {
        status = PMPrintDialog(*printSettings, *pageFormat, &accepted);
        if (!accepted)
            status = kPMCancel; // user clicked Cancel button
    }
		
    return status;
	
}   //  DoPrintDialog


/*------------------------------------------------------------------------------
    Function: DoPrintLoop
	
    Parameters:
        pageFormat      -   a PageFormat object addr
        printSettings   -   a PrintSettings object addr
	
    Description:
        Depends on the caller providing validated PageFormat and PrintSettings
        objects. Calculates a valid page range and prints each page by calling DrawPage.
	
------------------------------------------------------------------------------*/
void DoPrintLoop(PMPageFormat* pageFormat, PMPrintSettings* printSettings)
{
    OSStatus        status,
                    printError;
    PMRect          pageRect;
    PMPrintContext  thePrintingPort = kPMNoReference;
    UInt32          realNumberOfPagesinDoc,
                    pageNumber,
                    firstPage,
                    lastPage;
	
    //  PMGetAdjustedPaperRect returns the paper size taking into account rotation,
    //  resolution and scaling settings.  This is one example of the many accessor
    //  functions provided by the Carbon Printing Manager.
    status = PMGetAdjustedPaperRect(*pageFormat, &pageRect);

    //  PMGetAdjustedPageRect returns the page size taking into account rotation,
    //  resolution and scaling settings.  DetermineNumberOfPagesInDoc returns the
    //  number of pages required to print the document.
    if (status == noErr)
    {
        status = PMGetAdjustedPageRect(*pageFormat, &pageRect);
        if (status == noErr)
            realNumberOfPagesinDoc = DetermineNumberOfPagesInDoc(pageRect);
    }

    //  Get the user's selection for first and last pages
    if (status == noErr)
    {
        status = PMGetFirstPage(*printSettings, &firstPage);
        if (status == noErr)
            status = PMGetLastPage(*printSettings, &lastPage);
    }

    //  Check that the selected page range does not go beyond the actual
    //  number of pages in the document.
    if (status == noErr)
    {
        if (realNumberOfPagesinDoc < lastPage)
            lastPage = realNumberOfPagesinDoc;
    }
			
    //  Tell the Printing Manager to call our idle proc.
    if (status == noErr)
        status = PMSetIdleProc(NewPMIdleProc(pIdleProc));
				
    //  NOTE:  We don't have to worry about the number of copies.  The Printing
    //  Manager handles this.  So we just iterate through the document from the
    //  first page to be printed, to the last.
    if (status == noErr)
    {
        //  Establish a printing port for drawing.
        status = PMBeginDocument(*printSettings, *pageFormat, &thePrintingPort);
        if ((status == noErr) && (thePrintingPort != kPMNoReference))
        {
            //  Print the selected range of pages in the document.
            pageNumber = firstPage;
            while ((pageNumber <= lastPage) && (PMError() == noErr))
            {
                //  NOTE:  We don't have to deal with the old Printing Manager's
                //  128-page boundary limit anymore.
				
                //  Establish a printing page.
                status = PMBeginPage(thePrintingPort, nil);
                if (status != noErr)
                    break;
					
                //  Draw the page.
                DrawPage(pageRect, thePrintingPort, pageNumber);
				
                //  Close the page.
                status = PMEndPage(thePrintingPort);
                if (status != noErr)
                    break;
					
                //  And loop.
                pageNumber++;
            }
			
            // Close the printing port
            (void)PMEndDocument(thePrintingPort);
        }
    }

    //  Only report a printing error once we have completed the print loop. This
    //  ensures that every PMBegin... call is followed by a matching PMEnd...
    //  call, so the Printing Manager can release all temporary memory and close
    //  properly.
    printError = PMError();
    if (printError != noErr)
        PostPrintingErrors(printError);
		
}   //  DoPrintLoop





/*------------------------------------------------------------------------------
    Function: FlattenAndSavePageFormat
	
    Parameters:
        pageFormat  -   a PageFormat object
	
    Description:
        Flattens a PageFormat object so it can be saved with the document.
        Assumes caller passes a validated PageFormat object.
		
------------------------------------------------------------------------------*/
OSStatus FlattenAndSavePageFormat(PMPageFormat pageFormat)
{
    OSStatus    status;
    Handle      flatFormatHandle = nil;
	
    //  Flatten the PageFormat object to memory.
    status = PMFlattenPageFormat(pageFormat, &flatFormatHandle);
	
    //  Write the PageFormat data to file.
    //  In this sample code we simply copy it to a global.
    gflatPageFormat = flatFormatHandle;

    return status;
}   //  FlattenAndSavePageFormat



/*------------------------------------------------------------------------------
    Function: LoadAndUnflattenPageFormat
	
    Parameters:
        pageFormat  -   PageFormat object read from document file
	
    Description:
        Gets flattened PageFormat data from the document and returns a PageFormat
        object. The function is not called in this sample code but your application
        will need to retrieve PageFormat data saved with documents.
		
------------------------------------------------------------------------------*/

OSStatus LoadAndUnflattenPageFormat(PMPageFormat* pageFormat)
{
    OSStatus    status;
    Handle      flatFormatHandle = nil;

    //  Read the PageFormat flattened data from file.
    //  In this sample code we simply copy it from a global.
    flatFormatHandle = gflatPageFormat;

    //  Convert the PageFormat flattened data into a PageFormat object.
    status = PMUnflattenPageFormat(flatFormatHandle, pageFormat);
	
    return status;
}   //  LoadAndUnflattenPageFormat


/*------------------------------------------------------------------------------
    Function: DetermineNumberOfPagesInDoc
	
    Parameters:
        pageRect    -   size of the document, from PMGetAdjustedPageRect
	
    Description:
        Compares the size of the document with the number of pages in the
        PageFormat object to calculate the number of pages required to print
        the document.
		
------------------------------------------------------------------------------*/
UInt32DetermineNumberOfPagesInDoc(PMRect pageRect) 
{
#pragma unused (pageRect)
    //  In this sample code we simply return a hard coded number.
    return 1;
}   //  DetermineNumberOfPagesinDoc


/*------------------------------------------------------------------------------
    Function: DrawPage
	
    Parameters:
        pagerect    -   size of the page we're drawing
        printingPort-   the page's grafport
        pageNumber  -   the logical page number in the document
	
    Description:
        Draws the contents of a single page.
		
------------------------------------------------------------------------------*/
void DrawPage(PMRect pageRect, PMPrintContext printingPort, UInt32 pageNumber)
{
#pragma unused (printingPort)
    Str255      pageString;

    //  In this sample code we simply write the word "Page" followed by the
    //  page number onto each page.
	
    MoveTo((short)(pageRect.left + (pageRect.right - pageRect.left) / 2),
        (short)(pageRect.bottom - (pageRect.bottom - pageRect.top) / 2));
    DrawString("\pPage ");
    NumToString((long)pageNumber, pageString);
    DrawString(pageString);

}   //  DrawPage


/*------------------------------------------------------------------------------
    Function: pIdleProc
	
    Parameters:
        <none>
	
    Description:
        This routine is called by the Printing Manager while the print job is
        being spooled (background printing) or printed (foreground printing).
        Since most print drivers display their own progress dialog boxes, there is
        little need for applications to use the idle proc for progress reporting.
		
------------------------------------------------------------------------------*/
pascal void pIdleProc(void)
{
    //  Save the current resource file.
    short   curRes = CurResFile();

    //  Set the application's resource file.
    UseResFile(gAppResFile);
	
    //  Do something useful.
	
    //  Restore the resource file.
    UseResFile(curRes);
	
}   //  pIdleProc



/*------------------------------------------------------------------------------
    Function: PostPrintingErrors
	
    Parameters:
        status  -   error code
	
    Description:
        This is where we could post an alert to report any problem encountereds
        by the Printing Manager.
		
------------------------------------------------------------------------------*/
void PostPrintingErrors(OSStatus status)
{
#pragma unused (status)
}   //  PostPrintingErrors

© 2000 Apple Computer, Inc. (Last Updated 03 July 2000)