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)