Using 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 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:
17 Oct 99 pd Updated for Carbon 1.1 SDK to use session APIs
13 Sep 99 pd Updated for Carbon 1.0 SDK
11 Apr 99 dk Original version for Developer Preview 1
------------------------------------------------------------------------------*/
#define TARGET_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(PMPrintSession printSession, PMPageFormat* pageFormat);
OSStatus DoPrintDialog(PMPrintSession printSession, PMPageFormat pageFormat,
PMPrintSettings* printSettings);
void DoPrintLoop(PMPrintSession printSession, PMPageFormat pageFormat,
PMPrintSettings printSettings);
OSStatus FlattenAndSavePageFormat(PMPageFormat pageFormat);
OSStatus LoadAndUnflattenPageFormat(PMPageFormat* pageFormat);
UInt32 DetermineNumberOfPagesInDoc(PMRect rect);
void DrawPage(PMRect pageRect, UInt32 pageNumber);
pascal void pIdleProc(void);
void PostPrintingErrors(OSStatus status);
/*------------------------------------------------------------------------------
Function: main
Parameters:
<none>
Description:
Uses PMCreateSession/PMRelease instead of PMBegin/PMEnd. Note that the two
printing objects, PMPageSetup and PMPrintSettings are valid outside the
printing session. This is not the case with PMBegin/PMEnd. Note also
that no nesting of printing sessions is allowed for Carbon applications
running under MacOS 8 or 9.
In this sample code, we show where an old print record could be read in and
converted. This is followed by displaying the Page Setup dialog, then the
Print dialog, and finally we print the page(s) of the document.
------------------------------------------------------------------------------*/
int main(void)
{
OSStatus status = noErr;
GrafPtr oldPort;
PMPageFormat pageFormat = kPMNoPageFormat;
PMPrintSettings printSettings = kPMNoPrintSettings;
PMPrintSession printSession;
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 and create a printing session.
status = PMCreateSession(&printSession);
if (status != noErr) return 0; // pointless to continue if PMCreateSession 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 = PMSessionConvertOldPrintRecord(printSession, gOldPrintRecord,
&printSettings, &pageFormat);
// Display the Page Setup dialog.
if (status == noErr)
status = DoPageSetupDialog(printSession, &pageFormat);
// Display the Print dialog.
if (status == noErr)
status = DoPrintDialog(printSession, pageFormat, &printSettings);
// Execute the print loop.
if (status == noErr)
DoPrintLoop(printSession, pageFormat, printSettings);
// Release the PageFormat and PrintSettings objects. PMRelease decrements the
// ref count of the allocated objects. We let the Printing Manager decide when
// to release the allocated memory.
if (pageFormat != kPMNoPageFormat)
(void)PMRelease(&pageFormat);
if (printSettings != kPMNoPrintSettings)
(void)PMRelease(&printSettings);
// Terminate the current printing session.
(void)PMRelease(&printSession);
// Restore the original QD grafport.
SetPort(oldPort);
return 0;
} // main
/*------------------------------------------------------------------------------
Function: DoPageSetupDialog
Parameters:
printSession - current printing session
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(PMPrintSession printSession, PMPageFormat* pageFormat)
{
OSStatus status;
Boolean accepted;
// Set up a valid PageFormat object.
if (*pageFormat == kPMNoPageFormat)
{
status = PMCreatePageFormat(pageFormat);
// Note that PMPageFormat is not session-specific, but calling
// PMSessionDefaultPageFormat assigns values specific to the printer
// associated with the current printing session.
if ((status == noErr) && (*pageFormat != kPMNoPageFormat))
status = PMSessionDefaultPageFormat(printSession, *pageFormat);
}
else
status = PMSessionValidatePageFormat(printSession, *pageFormat,
kPMDontWantBoolean);
// Display the Page Setup dialog.
if (status == noErr)
{
status = PMSessionPageSetupDialog(printSession, *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:
printSession - current printing session
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(PMPrintSession printSession, PMPageFormat pageFormat,
PMPrintSettings* printSettings)
{
OSStatus status;
Boolean accepted;
UInt32 minPage = 1,
maxPage = 9999;
// 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 = PMCreatePrintSettings(printSettings);
// Note that PMPrintSettings is not session-specific, but calling
// PMSessionDefaultPrintSettings assigns values specific to the printer
// associated with the current printing session.
if ((status == noErr) && (*printSettings != kPMNoPrintSettings))
status = PMSessionDefaultPrintSettings(printSession, *printSettings);
}
else
status = PMSessionValidatePrintSettings(printSession, *printSettings,
kPMDontWantBoolean);
// Set a valid page range before displaying the Print dialog
if (status == noErr)
status = PMSetPageRange(*printSettings, minPage, maxPage);
// Display the Print dialog.
if (status == noErr)
{
status = PMSessionPrintDialog(printSession, *printSettings, pageFormat,
&accepted);
if (!accepted)
status = kPMCancel; // user clicked Cancel button
}
return status;
} // DoPrintDialog
/*------------------------------------------------------------------------------
Function: DoPrintLoop
Parameters:
printSession - current printing session
pageFormat - a PageFormat object addr
printSettings - a PrintSettings object addr
Description:
Assumes the caller provides validated PageFormat and PrintSettings
objects.
Calculates a valid page range and prints each page by calling DrawPage.
------------------------------------------------------------------------------*/
void DoPrintLoop(PMPrintSession printSession, PMPageFormat pageFormat,
PMPrintSettings printSettings)
{
OSStatus status,
printError;
PMRect pageRect;
UInt32 realNumberOfPagesinDoc,
pageNumber,
firstPage,
lastPage;
// PMGetAdjustedPaperRect returns the paper size taking into account rotation,
// resolution, and scaling settings. Note this is the paper size selected
// the Page Setup dialog. It is not guaranteed to be the same as the paper
// size selected in the Print dialog on Mac OS X.
status = PMGetAdjustedPaperRect(pageFormat, &pageRect);
// PMGetAdjustedPageRect returns the page size taking into account rotation,
// resolution, and scaling settings. Note this is the imageable area of the
// paper selected in the Page Setup dialog.
// 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 = PMSessionSetIdleProc(printSession, 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 graphics context for drawing the document's pages.
// Although it's not used in this sample code, PMGetGrafPtr can be called
// get the QD grafport.
status = PMSessionBeginDocument(printSession, printSettings, pageFormat);
if (status == noErr)
{
// Print all the pages in the document. Note that we spool all pages
// and rely upon the Printing Manager to print the correct page range.
// In this sample code we assume the total number of pages in the
// document is equal to "lastPage".
pageNumber = 1;
while ((pageNumber <= lastPage) && (PMSessionError() == noErr))
{
// NOTE: We don't have to deal with the old Printing Manager's
// 128-page boundary limit anymore.
// Set up a page for printing.
status = PMSessionBeginPage(printSession, pageFormat, &pageRect);
if (status != noErr)
break;
// Draw the page.
DrawPage(pageRect, pageNumber);
// Close the page.
status = PMSessionEndPage(printSession);
if (status != noErr)
break;
// And loop.
pageNumber++;
}
// Close the printing port
(void)PMSessionEndDocument(printSession);
}
}
// Only report a printing error once we have completed the print loop. This
// ensures that every PMSessionBegin... call is followed by a matching
// PMSessionEnd... call, so the Printing Manager can release all temporary
// memory and close properly.
printError = PMSessionError();
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)
{
OSStatusstatus;
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 - a PageFormat object read from a 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.
------------------------------------------------------------------------------*/
UInt32 DetermineNumberOfPagesInDoc(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
pageNumber - the logical page number in the document
Description:
Draws the contents of a single page.
------------------------------------------------------------------------------*/
void DrawPage(PMRect pageRect, UInt32 pageNumber)
{
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 encountered
by the Printing Manager.
------------------------------------------------------------------------------*/
void PostPrintingErrors(OSStatus status)
{
#pragma unused (status)
} // PostPrintingErrors
© 2000 Apple Computer, Inc. (Last Updated 03 July 2000)