Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
Source/MyCarbonPrinting.c
/* |
File: MyCarbonPrinting.c |
Contains: Routines needed to perform printing. This example uses sheets and provides for |
save as PDF. |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. |
("Apple") in consideration of your agreement to the following terms, and your |
use, installation, modification or redistribution of this Apple software |
constitutes acceptance of these terms. If you do not agree with these terms, |
please do not use, install, modify or redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and subject |
to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs |
copyrights in this original Apple software (the "Apple Software"), to use, |
reproduce, modify and redistribute the Apple Software, with or without |
modifications, in source and/or binary forms; provided that if you redistribute |
the Apple Software in its entirety and without modifications, you must retain |
this notice and the following text and disclaimers in all such redistributions of |
the Apple Software. Neither the name, trademarks, service marks or logos of |
Apple Computer, Inc. may be used to endorse or promote products derived from the |
Apple Software without specific prior written permission from Apple. Except as |
expressly stated in this notice, no other rights or licenses, express or implied, |
are granted by Apple herein, including but not limited to any patent rights that |
may be infringed by your derivative works or by other works in which the Apple |
Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO |
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED |
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN |
COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR |
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION |
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT |
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN |
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Copyright © 1999-2001 Apple Computer, Inc., All Rights Reserved |
*/ |
#include "MyCarbonPrinting.h" |
#include "AppDrawing.h" |
#include "UIHandling.h" |
// this setting determines whether there will be a printing status dialog when |
// saving to PDF |
#define NO_SAVE_STATUS_DIALOG 1 |
// the following typedefs are defined so that our PrintingProcs structure |
// definition can be defined and used. |
typedef CALLBACK_API(OSStatus, PMSessionBeginDocumentProcPtr) |
(PMPrintSession printSession, |
PMPrintSettings printSettings, |
PMPageFormat pageFormat); |
typedef CALLBACK_API(OSStatus, PMSessionBeginPageProcPtr) |
(PMPrintSession printSession, |
PMPageFormat pageFormat, |
const PMRect *pageFrame); |
typedef CALLBACK_API(OSStatus, PMSessionEndPageProcPtr)(PMPrintSession printSession); |
typedef CALLBACK_API(OSStatus, PMSessionEndDocumentProcPtr)(PMPrintSession printSession); |
typedef struct PrintingProcs{ |
PMSessionBeginDocumentProcPtr BeginDocumentProc; |
PMSessionBeginPageProcPtr BeginPageProc; |
PMSessionEndPageProcPtr EndPageProc; |
PMSessionEndDocumentProcPtr EndDocumentProc; |
}PrintingProcs; |
/* |
The routines PMSessionBeginDocumentNoDialog, PMSessionEndDocumentNoDialog, |
PMSessionBeginPageNoDialog, PMSessionEndPageNoDialog are incorrectly |
missing from the public header file PMCore.h and consequently also |
from ApplicationServices.h. These routines have |
the following availability: |
Availability: |
Mac OS X: in version 10.0 and later in ApplicationServices.framework |
CarbonLib: not available |
Non-Carbon CFM: not available |
These routines are public and will appear in the PMCore.h header file in |
a future release of Mac OS X. |
The functional difference between these routines and the matching routines |
without the 'NoDialog' suffix is that there is not window or status narration |
performed when these routines are used. This makes them suitable for our |
save to PDF situation where we may want either no status narration or |
an application might want to perform its own status narration. |
*/ |
EXTERN_API( OSStatus ) |
PMSessionBeginDocumentNoDialog (PMPrintSession printSession, |
PMPrintSettings printSettings, |
PMPageFormat pageFormat); |
EXTERN_API( OSStatus ) |
PMSessionEndDocumentNoDialog (PMPrintSession printSession); |
EXTERN_API( OSStatus ) |
PMSessionBeginPageNoDialog (PMPrintSession printSession, |
PMPageFormat pageFormat, |
const PMRect * pageFrame); |
EXTERN_API( OSStatus ) |
PMSessionEndPageNoDialog (PMPrintSession printSession); |
static PMSheetDoneUPP gMyPageSetupDoneProc; |
static PMSheetDoneUPP gMyPrintDialogDoneProc; |
static pascal void MyPageSetupDoneProc(PMPrintSession printSession, WindowRef documentWindow, Boolean accepted); |
static pascal void MyPrintDialogDoneProc(PMPrintSession printSession, WindowRef documentWindow, Boolean accepted); |
static OSStatus MySetupPageFormatForPrinting(PMPrintSession printSession, |
void *docDataP, PMPageFormat *pageFormatP); |
static OSStatus MyDoPrintLoop(PMPrintSession printSession, PMPageFormat pageFormat, |
PMPrintSettings printSettings, const void *docDataP, |
const PrintingProcs *printingProcsP); |
/**** Global Data ****/ |
static PrintingProcs gMyPrintingProcsNoStatusDialog = {PMSessionBeginDocumentNoDialog, |
PMSessionBeginPageNoDialog, |
PMSessionEndPageNoDialog, |
PMSessionEndDocumentNoDialog |
}; |
static PrintingProcs gMyPrintingProcsWithStatusDialog = {PMSessionBeginDocument, |
PMSessionBeginPage, |
PMSessionEndPage, |
PMSessionEndDocument |
}; |
// -------------------------------------------------------------------------------------------------------------- |
OSStatus CreateSheetDoneProcs(void) |
{ |
OSStatus err = noErr; |
gMyPageSetupDoneProc = NewPMSheetDoneUPP(MyPageSetupDoneProc); |
if(!gMyPageSetupDoneProc) |
err = memFullErr; |
if(!err){ |
gMyPrintDialogDoneProc = NewPMSheetDoneUPP(MyPrintDialogDoneProc); |
if(!gMyPrintDialogDoneProc) |
err = memFullErr; |
} |
return err; |
} |
// -------------------------------------------------------------------------------------------------------------- |
static OSStatus MySetupPageFormatForPrinting(PMPrintSession printSession, void *docDataP, PMPageFormat *pageFormatP) |
{ |
OSStatus err = noErr; |
PMPageFormat pageFormat = GetPageFormatFromPrivateData(docDataP); |
if (pageFormat == NULL) |
{ |
err = PMCreatePageFormat(&pageFormat); |
if(err == noErr) |
{ |
err = PMSessionDefaultPageFormat(printSession, pageFormat); |
if (err == noErr) |
SetPageFormatOnPrivateData(docDataP, pageFormat); |
else{ |
(void)PMRelease(pageFormat); |
pageFormat = NULL; |
} |
} |
}else{ |
// we already have a page format so we'll validate it |
err = PMSessionValidatePageFormat(printSession, pageFormat, |
kPMDontWantBoolean); |
if(err){ // if validate failed! |
SetPageFormatOnPrivateData(docDataP, NULL); |
(void)PMRelease(pageFormat); |
pageFormat = NULL; |
} |
} |
*pageFormatP = pageFormat; |
return err; |
} |
// -------------------------------------------------------------------------------------------------------------- |
OSStatus DoPageSetup(WindowRef window, void *docDataP) |
{ |
OSStatus err = noErr; |
if(docDataP){ |
PMPrintSession printSession; |
PMPageFormat pageFormat = NULL; |
err = PMCreateSession(&printSession); |
if(!err){ |
Boolean accepted; |
err = MySetupPageFormatForPrinting(printSession, docDataP, &pageFormat); |
if(!err){ |
Boolean sheetsAreAvailable = true; |
err = PMSessionUseSheets(printSession, window, gMyPageSetupDoneProc); |
if(err == kPMNotImplemented){ |
// sheets are not available (aka, Mac OS 8/9) |
err = noErr; |
sheetsAreAvailable = false; |
} |
if(!err){ |
err = PMSessionPageSetupDialog(printSession, pageFormat, &accepted); |
/* when using sheets, the value of 'accepted' returned here is irrelevant |
since it is our sheet done proc that is called when the dialog is dismissed. |
Our dialog done proc will be called when the sheet is dismissed. |
If sheets are NOT implemented then WE call our DialogDone proc here |
to complete the dialog. |
*/ |
if(err == noErr && !sheetsAreAvailable) |
MyPageSetupDoneProc(printSession, window, accepted); |
} |
} |
if(err){ // only if there is an error do we release the session |
// otherwise we'll do that in our sheet done proc |
(void)PMRelease(printSession); |
} |
} |
} |
DoErrorAlert(err, kMyPrintErrorFormatStrKey); |
return err; |
} // DoPageSetup |
// -------------------------------------------------------------------------------------------------------------- |
static pascal void MyPageSetupDoneProc(PMPrintSession printSession, |
WindowRef documentWindow, |
Boolean accepted) |
{ |
#pragma unused(documentWindow, accepted) |
// this sample doesn't do anything with the page format after page setup is done |
// now we release the session we created to do the page setup dialog |
OSStatus err = PMRelease(printSession); |
if(err) |
DoErrorAlert(err, kMyPrintErrorFormatStrKey); |
return; |
} |
// -------------------------------------------------------------------------------------------------------------- |
OSStatus DoPrint(WindowRef parentWindow, void *documentDataP, Boolean printOne) |
{ |
OSStatus err = noErr; |
PMPrintSettings printSettings = NULL; |
PMPageFormat pageFormat = NULL; |
UInt32 minPage = 1, maxPage; |
PMPrintSession printSession; |
err = PMCreateSession(&printSession); |
if(err == noErr){ |
err = MySetupPageFormatForPrinting(printSession, documentDataP, &pageFormat); |
if (err == noErr) |
{ |
err = PMCreatePrintSettings(&printSettings); |
if(err == noErr) |
{ |
err = PMSessionDefaultPrintSettings(printSession, printSettings); |
if(err == noErr){ |
CFStringRef windowTitleRef; |
err = CopyWindowTitleAsCFString(parentWindow, &windowTitleRef); |
if(err == noErr) |
{ |
// set the job name before displaying the print dialog |
err = PMSetJobNameCFString (printSettings, windowTitleRef); |
CFRelease(windowTitleRef); |
} |
} |
} |
if (err == noErr) |
{ |
maxPage = MyGetDocumentNumPagesInDoc(documentDataP); |
err = PMSetPageRange(printSettings, minPage, maxPage); |
} |
if (err == noErr) |
{ |
Boolean accepted; |
Boolean sheetsAreAvailable = true; |
SetPrintSettingsOnPrivateData(documentDataP, printSettings); |
err = PMSessionUseSheets(printSession, parentWindow, gMyPrintDialogDoneProc); |
if(err == kPMNotImplemented){ |
// we get here if sheets are not available, i.e. Mac OS 8/9 |
err = noErr; |
sheetsAreAvailable = false; |
} |
if(err == noErr && !printOne){ |
err = PMSessionPrintDialog(printSession, printSettings, |
pageFormat, |
&accepted); |
/* when using sheets, the value of 'accepted' returned here is irrelevant |
since it is our sheet done proc that is called when the dialog is dismissed. |
Our dialog done proc will be called when the sheet is dismissed. |
If sheets are NOT implemented then WE call our DialogDone proc here |
to complete the dialog. |
*/ |
if(err == noErr && !sheetsAreAvailable) |
MyPrintDialogDoneProc(printSession, parentWindow, accepted); |
}else{ |
// if we are doing print one we have no dialog, therefore |
// we have to call our dialog done proc since there is no |
// dialog to do so for us |
if(err == noErr) |
MyPrintDialogDoneProc(printSession, parentWindow, true); |
} |
} |
} |
if(err != noErr){ |
// if we got an error our dialog done proc will not be called so we need to clean up |
if(printSettings){ |
SetPrintSettingsOnPrivateData(documentDataP, NULL); |
(void)PMRelease(printSettings); // ignoring error since we already have one |
} |
(void)PMRelease(printSession); // ignoring error since we already have one |
} |
} |
DoErrorAlert(err, kMyPrintErrorFormatStrKey); |
return err; |
} |
// -------------------------------------------------------------------------------------------------------------- |
static pascal void MyPrintDialogDoneProc(PMPrintSession printSession, |
WindowRef documentWindow, Boolean accepted) |
{ |
OSStatus err = noErr, tempErr; |
void *ourDataP = GetOurWindowProperty(documentWindow); |
if(ourDataP) |
{ |
PMPrintSettings printSettings = GetPrintSettingsFromPrivateData(ourDataP); |
// only run the print loop if the user accepted the print dialog. |
if(accepted){ |
err = MyDoPrintLoop(printSession, |
GetPageFormatFromPrivateData(ourDataP), |
printSettings, ourDataP, &gMyPrintingProcsWithStatusDialog); |
} |
SetPrintSettingsOnPrivateData(ourDataP, NULL); |
tempErr = PMRelease(printSettings); |
if(err == noErr) |
err = tempErr; |
}// else Assert(...); |
// now we release the session we created to do the Print dialog |
tempErr = PMRelease(printSession); |
if(err == noErr) |
err = tempErr; |
DoErrorAlert(err, kMyPrintErrorFormatStrKey); |
} |
// -------------------------------------------------------------------------------------------------------------- |
static OSStatus MyDoPrintLoop(PMPrintSession printSession, PMPageFormat pageFormat, |
PMPrintSettings printSettings, const void *ourDataP, |
const PrintingProcs *printingProcsP) |
{ |
OSStatus err = noErr; |
OSStatus tempErr = noErr; |
UInt32 firstPage, lastPage, totalDocPages = MyGetDocumentNumPagesInDoc(ourDataP); |
if(!err) |
err = PMGetFirstPage(printSettings, &firstPage); |
if (!err) |
err = PMGetLastPage(printSettings, &lastPage); |
if(!err && lastPage > totalDocPages){ |
// don't draw more than the number of pages in our document |
lastPage = totalDocPages; |
} |
if (!err) // tell the printing system the number of pages we are going to print |
err = PMSetLastPage(printSettings, lastPage, false); |
if (!err) |
{ |
PageDrawProc *drawProc = GetMyDrawPageProc(ourDataP); |
err = printingProcsP->BeginDocumentProc(printSession, printSettings, pageFormat); |
if (!err){ |
UInt32 pageNumber = firstPage; |
// need to check errors from our print loop and errors from the session for each |
// time around our print loop before calling our BeginPageProc |
while(pageNumber <= lastPage && err == noErr && PMSessionError(printSession) == noErr) |
{ |
err = printingProcsP->BeginPageProc(printSession, pageFormat, NULL); |
if (!err){ |
GrafPtr oldPort = NULL; |
void *printingContext = NULL; |
GetPort(&oldPort); // preserve the existing port |
err = PMSessionGetGraphicsContext(printSession, kPMGraphicsContextQuickdraw, |
(void **)&printingContext); |
if(!err){ |
Rect pageRect; |
SetPort((CGrafPtr)printingContext); |
GetPortBounds(printingContext, &pageRect); |
err = drawProc(ourDataP, &pageRect, pageNumber); // image the correct page |
SetPort(oldPort); // restore the prior port |
} |
// we must call EndPage if BeginPage returned noErr |
tempErr = printingProcsP->EndPageProc(printSession); |
if(!err)err = tempErr; |
} |
pageNumber++; |
} // end while loop |
// we must call EndDocument if BeginDocument returned noErr |
tempErr = printingProcsP->EndDocumentProc(printSession); |
if(!err)err = tempErr; |
if(!err) |
err = PMSessionError(printSession); |
} |
} |
return err; |
} |
OSStatus MakePDFDocument(WindowRef parentWindow, void *documentDataP, CFURLRef saveURL) |
{ |
OSStatus err = noErr, tempErr; |
PMPrintSettings printSettings = NULL; |
PMPageFormat pageFormat = NULL; |
PMPrintSession printSession; |
err = PMCreateSession(&printSession); |
if(err == noErr){ |
err = MySetupPageFormatForPrinting(printSession, documentDataP, &pageFormat); |
if (err == noErr) |
{ |
err = PMCreatePrintSettings(&printSettings); |
if(err == noErr) |
{ |
err = PMSessionDefaultPrintSettings(printSession, printSettings); |
if(err == noErr){ |
CFStringRef windowTitleRef; |
err = CopyWindowTitleAsCFString(parentWindow, &windowTitleRef); |
if(err == noErr) |
{ |
// set the job name |
err = PMSetJobNameCFString (printSettings, windowTitleRef); |
CFRelease(windowTitleRef); |
} |
} |
if (err == noErr) |
err = PMSetPageRange(printSettings, 1, MyGetDocumentNumPagesInDoc(documentDataP)); |
// set our destination to be our target URL and the format to be PDF |
if(err == noErr){ |
// this API exists ONLY in Mac OS X 10.1 and later only |
err = PMSessionSetDestination(printSession, printSettings, |
kPMDestinationFile, kPMDocumentFormatPDF, |
saveURL); |
} |
#if !NO_SAVE_STATUS_DIALOG |
if(err == noErr){ |
err = PMSessionUseSheets(printSession, parentWindow, NULL); |
} |
#endif |
} |
if (err == noErr) |
{ |
err = MyDoPrintLoop(printSession, |
pageFormat, |
printSettings, |
documentDataP, |
#if NO_SAVE_STATUS_DIALOG |
&gMyPrintingProcsNoStatusDialog |
#else |
&gMyPrintingProcsWithStatusDialog |
#endif |
); |
} |
} |
if(printSettings){ |
tempErr = PMRelease(printSettings); |
if(err == noErr) |
err = tempErr; |
} |
tempErr = PMRelease(printSession); |
if(err == noErr) |
err = tempErr; |
} |
DoErrorAlert(err, kMySaveAsPDFErrorFormatStrKey); |
return err; |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14