1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/core/printmac.cpp
3 // Purpose: wxMacPrinter framework
4 // Author: Julian Smart, Stefan Csomor
8 // Copyright: (c) Julian Smart, Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
15 #if wxUSE_PRINTING_ARCHITECTURE
25 #include "wx/msgdlg.h"
26 #include "wx/dcprint.h"
30 #include "wx/osx/private.h"
32 #include "wx/osx/printmac.h"
33 #include "wx/osx/private/print.h"
35 #include "wx/printdlg.h"
37 #include "wx/osx/printdlg.h"
42 // move to print_osx.cpp
45 IMPLEMENT_DYNAMIC_CLASS(wxOSXPrintData
, wxPrintNativeDataBase
)
47 bool wxOSXPrintData::IsOk() const
49 return (m_macPageFormat
!= kPMNoPageFormat
) && (m_macPrintSettings
!= kPMNoPrintSettings
) && (m_macPrintSession
!= kPMNoReference
);
52 wxOSXPrintData::wxOSXPrintData()
54 m_macPageFormat
= kPMNoPageFormat
;
55 m_macPrintSettings
= kPMNoPrintSettings
;
56 m_macPrintSession
= kPMNoReference
;
57 m_macPaper
= kPMNoData
;
60 wxOSXPrintData::~wxOSXPrintData()
64 void wxOSXPrintData::UpdateFromPMState()
68 void wxOSXPrintData::UpdateToPMState()
72 bool wxOSXPrintData::TransferFrom( const wxPrintData
&data
)
75 PMSessionGetCurrentPrinter(m_macPrintSession
, &printer
);
77 wxSize papersize
= wxDefaultSize
;
78 const wxPaperSize paperId
= data
.GetPaperId();
79 if ( paperId
!= wxPAPER_NONE
&& wxThePrintPaperDatabase
)
81 papersize
= wxThePrintPaperDatabase
->GetSize(paperId
);
82 if ( papersize
!= wxDefaultSize
)
90 papersize
= data
.GetPaperSize();
93 if ( papersize
!= wxDefaultSize
)
95 papersize
.x
= (wxInt32
) (papersize
.x
* mm2pt
);
96 papersize
.y
= (wxInt32
) (papersize
.y
* mm2pt
);
99 PMPaperGetHeight(m_macPaper
, &height
);
100 PMPaperGetWidth(m_macPaper
, &width
);
102 if ( fabs( width
- papersize
.x
) >= 5 ||
103 fabs( height
- papersize
.y
) >= 5 )
105 // we have to change the current paper
106 CFArrayRef paperlist
= 0 ;
107 if ( PMPrinterGetPaperList( printer
, &paperlist
) == noErr
)
109 PMPaper bestPaper
= kPMNoData
;
110 CFIndex top
= CFArrayGetCount(paperlist
);
111 for ( CFIndex i
= 0 ; i
< top
; ++ i
)
113 PMPaper paper
= (PMPaper
) CFArrayGetValueAtIndex( paperlist
, i
);
114 PMPaperGetHeight(paper
, &height
);
115 PMPaperGetWidth(paper
, &width
);
116 if ( fabs( width
- papersize
.x
) < 5 &&
117 fabs( height
- papersize
.y
) < 5 )
119 // TODO test for duplicate hits and use additional
120 // criteria for best match
124 PMPaper paper
= kPMNoData
;
125 if ( bestPaper
== kPMNoData
)
127 const PMPaperMargins margins
= { 0.0, 0.0, 0.0, 0.0 };
128 wxString id
, name(_T("Custom paper"));
129 id
.Printf(_T("wxPaperCustom%dx%d"), papersize
.x
, papersize
.y
);
131 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
132 if ( PMPaperCreateCustom
!= NULL
)
134 PMPaperCreateCustom(printer
, wxCFStringRef( id
, wxFont::GetDefaultEncoding() ), wxCFStringRef( name
, wxFont::GetDefaultEncoding() ),
135 papersize
.x
, papersize
.y
, &margins
, &paper
);
138 #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
139 if ( paper
== kPMNoData
)
141 PMPaperCreate(printer
, wxCFStringRef( id
, wxFont::GetDefaultEncoding() ), wxCFStringRef( name
, wxFont::GetDefaultEncoding() ),
142 papersize
.x
, papersize
.y
, &margins
, &paper
);
146 if ( bestPaper
!= kPMNoData
)
148 PMPageFormat pageFormat
;
149 PMCreatePageFormatWithPMPaper(&pageFormat
, bestPaper
);
150 PMCopyPageFormat( pageFormat
, m_macPageFormat
);
151 PMRelease(pageFormat
);
152 PMGetPageFormatPaper(m_macPageFormat
, &m_macPaper
);
159 CFArrayRef printerList
;
160 CFIndex index
, count
;
163 if (PMServerCreatePrinterList(kPMServerLocal
, &printerList
) == noErr
)
165 count
= CFArrayGetCount(printerList
);
166 for (index
= 0; index
< count
; index
++)
168 printer
= (PMPrinter
)CFArrayGetValueAtIndex(printerList
, index
);
169 if ((data
.GetPrinterName().empty()) && (PMPrinterIsDefault(printer
)))
173 name
= PMPrinterGetName(printer
);
175 if (data
.GetPrinterName() == wxCFStringRef(name
).AsString())
180 PMSessionSetCurrentPMPrinter(m_macPrintSession
, printer
);
181 CFRelease(printerList
);
184 PMSetCopies( m_macPrintSettings
, data
.GetNoCopies() , false ) ;
185 PMSetCollate(m_macPrintSettings
, data
.GetCollate());
186 if ( data
.IsOrientationReversed() )
187 PMSetOrientation( m_macPageFormat
, ( data
.GetOrientation() == wxLANDSCAPE
) ?
188 kPMReverseLandscape
: kPMReversePortrait
, false ) ;
190 PMSetOrientation( m_macPageFormat
, ( data
.GetOrientation() == wxLANDSCAPE
) ?
191 kPMLandscape
: kPMPortrait
, false ) ;
193 PMDuplexMode mode
= 0 ;
194 switch( data
.GetDuplex() )
196 case wxDUPLEX_HORIZONTAL
:
197 mode
= kPMDuplexNoTumble
;
199 case wxDUPLEX_VERTICAL
:
200 mode
= kPMDuplexTumble
;
202 case wxDUPLEX_SIMPLEX
:
204 mode
= kPMDuplexNone
;
207 PMSetDuplex( m_macPrintSettings
, mode
) ;
209 // PMQualityMode not yet accessible via API
212 if ( data
.IsOrientationReversed() )
213 PMSetOrientation( m_macPageFormat
, ( data
.GetOrientation() == wxLANDSCAPE
) ?
214 kPMReverseLandscape
: kPMReversePortrait
, false ) ;
216 PMSetOrientation( m_macPageFormat
, ( data
.GetOrientation() == wxLANDSCAPE
) ?
217 kPMLandscape
: kPMPortrait
, false ) ;
219 // PMQualityMode not accessible via API
220 // TODO: use our quality property to determine optimal resolution
222 PMTag tag
= kPMMaxSquareResolution
;
223 PMPrinterGetPrinterResolution(printer
, tag
, &res
);
224 PMSetResolution( m_macPageFormat
, &res
);
226 // after setting the new resolution the format has to be updated, otherwise the page rect remains
227 // at the 'old' scaling
229 PMSessionValidatePageFormat(m_macPrintSession
,
230 m_macPageFormat
, kPMDontWantBoolean
);
231 PMSessionValidatePrintSettings(m_macPrintSession
,
232 m_macPrintSettings
, kPMDontWantBoolean
);
240 bool wxOSXPrintData::TransferTo( wxPrintData
&data
)
242 OSStatus err
= noErr
;
247 err
= PMGetCopies( m_macPrintSettings
, &copies
) ;
249 data
.SetNoCopies( copies
) ;
251 PMOrientation orientation
;
252 err
= PMGetOrientation( m_macPageFormat
, &orientation
) ;
255 if ( orientation
== kPMPortrait
|| orientation
== kPMReversePortrait
)
257 data
.SetOrientation( wxPORTRAIT
);
258 data
.SetOrientationReversed( orientation
== kPMReversePortrait
);
262 data
.SetOrientation( wxLANDSCAPE
);
263 data
.SetOrientationReversed( orientation
== kPMReverseLandscape
);
268 if (PMGetCollate(m_macPrintSettings
, &collate
) == noErr
)
269 data
.SetCollate(collate
);
273 PMSessionGetCurrentPrinter( m_macPrintSession
, &printer
);
274 if (PMPrinterIsDefault(printer
))
275 data
.SetPrinterName(wxEmptyString
);
278 name
= PMPrinterGetName(printer
);
280 data
.SetPrinterName(wxCFStringRef(name
).AsString());
283 PMDuplexMode mode
= 0 ;
284 PMGetDuplex( m_macPrintSettings
, &mode
) ;
287 case kPMDuplexNoTumble
:
288 data
.SetDuplex(wxDUPLEX_HORIZONTAL
);
290 case kPMDuplexTumble
:
291 data
.SetDuplex(wxDUPLEX_VERTICAL
);
295 data
.SetDuplex(wxDUPLEX_SIMPLEX
);
298 // PMQualityMode not yet accessible via API
300 double height
, width
;
301 PMPaperGetHeight(m_macPaper
, &height
);
302 PMPaperGetWidth(m_macPaper
, &width
);
304 wxSize
sz((int)(width
* pt2mm
+ 0.5 ) ,
305 (int)(height
* pt2mm
+ 0.5 ));
306 data
.SetPaperSize(sz
);
307 wxPaperSize id
= wxThePrintPaperDatabase
->GetSize(wxSize(sz
.x
* 10, sz
.y
* 10));
308 if (id
!= wxPAPER_NONE
)
315 void wxOSXPrintData::TransferFrom( wxPageSetupData
*WXUNUSED(data
) )
317 // should we setup the page rect here ?
318 // since MacOS sometimes has two same paper rects with different
319 // page rects we could make it roundtrip safe perhaps
322 void wxOSXPrintData::TransferTo( wxPageSetupData
* data
)
328 OSStatus err
= PMGetUnadjustedPaperRect(m_macPageFormat
, &rPaper
);
331 wxSize
sz((int)(( rPaper
.right
- rPaper
.left
) * pt2mm
+ 0.5 ) ,
332 (int)(( rPaper
.bottom
- rPaper
.top
) * pt2mm
+ 0.5 ));
333 data
->SetPaperSize(sz
);
336 err
= PMGetUnadjustedPageRect(m_macPageFormat
, &rPage
) ;
339 data
->SetMinMarginTopLeft( wxPoint (
340 (int)(((double) rPage
.left
- rPaper
.left
) * pt2mm
) ,
341 (int)(((double) rPage
.top
- rPaper
.top
) * pt2mm
) ) ) ;
343 data
->SetMinMarginBottomRight( wxPoint (
344 (wxCoord
)(((double) rPaper
.right
- rPage
.right
) * pt2mm
),
345 (wxCoord
)(((double) rPaper
.bottom
- rPage
.bottom
) * pt2mm
)) ) ;
347 if ( data
->GetMarginTopLeft().x
< data
->GetMinMarginTopLeft().x
)
348 data
->SetMarginTopLeft( wxPoint( data
->GetMinMarginTopLeft().x
,
349 data
->GetMarginTopLeft().y
) ) ;
351 if ( data
->GetMarginBottomRight().x
< data
->GetMinMarginBottomRight().x
)
352 data
->SetMarginBottomRight( wxPoint( data
->GetMinMarginBottomRight().x
,
353 data
->GetMarginBottomRight().y
) );
355 if ( data
->GetMarginTopLeft().y
< data
->GetMinMarginTopLeft().y
)
356 data
->SetMarginTopLeft( wxPoint( data
->GetMarginTopLeft().x
, data
->GetMinMarginTopLeft().y
) );
358 if ( data
->GetMarginBottomRight().y
< data
->GetMinMarginBottomRight().y
)
359 data
->SetMarginBottomRight( wxPoint( data
->GetMarginBottomRight().x
,
360 data
->GetMinMarginBottomRight().y
) );
365 void wxOSXPrintData::TransferTo( wxPrintDialogData
* data
)
370 UInt32 minPage
, maxPage
;
371 PMGetPageRange( m_macPrintSettings
, &minPage
, &maxPage
) ;
372 data
->SetMinPage( minPage
) ;
373 data
->SetMaxPage( maxPage
) ;
375 PMGetCopies( m_macPrintSettings
, &copies
) ;
376 data
->SetNoCopies( copies
) ;
378 PMGetFirstPage( m_macPrintSettings
, &from
) ;
379 PMGetLastPage( m_macPrintSettings
, &to
) ;
380 if ( to
>= 0x7FFFFFFF ) // due to an OS Bug we don't get back kPMPrintAllPages
382 data
->SetAllPages( true ) ;
383 // This means all pages, more or less
384 data
->SetFromPage(1);
385 data
->SetToPage(9999);
389 data
->SetFromPage( from
) ;
390 data
->SetToPage( to
) ;
391 data
->SetAllPages( false );
395 void wxOSXPrintData::TransferFrom( wxPrintDialogData
* data
)
397 // Respect the value of m_printAllPages
398 if ( data
->GetAllPages() )
399 PMSetPageRange( m_macPrintSettings
, data
->GetMinPage() , (UInt32
) kPMPrintAllPages
) ;
401 PMSetPageRange( m_macPrintSettings
, data
->GetMinPage() , data
->GetMaxPage() ) ;
402 PMSetCopies( m_macPrintSettings
, data
->GetNoCopies() , false ) ;
403 PMSetFirstPage( m_macPrintSettings
, data
->GetFromPage() , false ) ;
405 if (data
->GetAllPages() || data
->GetFromPage() == 0)
406 PMSetLastPage( m_macPrintSettings
, (UInt32
) kPMPrintAllPages
, true ) ;
408 PMSetLastPage( m_macPrintSettings
, (UInt32
) data
->GetToPage() , false ) ;
414 wxPrintNativeDataBase
* wxOSXCreatePrintData()
417 return new wxOSXCocoaPrintData();
420 return new wxOSXCarbonPrintData();
429 IMPLEMENT_DYNAMIC_CLASS(wxMacPrinter
, wxPrinterBase
)
431 wxMacPrinter::wxMacPrinter(wxPrintDialogData
*data
):
436 wxMacPrinter::~wxMacPrinter(void)
440 bool wxMacPrinter::Print(wxWindow
*parent
, wxPrintout
*printout
, bool prompt
)
443 sm_abortWindow
= NULL
;
448 printout
->SetIsPreview(false);
449 if (m_printDialogData
.GetMinPage() < 1)
450 m_printDialogData
.SetMinPage(1);
451 if (m_printDialogData
.GetMaxPage() < 1)
452 m_printDialogData
.SetMaxPage(9999);
454 // Create a suitable device context
455 wxPrinterDC
*dc
= NULL
;
458 wxMacPrintDialog
dialog(parent
, & m_printDialogData
);
459 if (dialog
.ShowModal() == wxID_OK
)
461 dc
= wxDynamicCast(dialog
.GetPrintDC(), wxPrinterDC
);
463 m_printDialogData
= dialog
.GetPrintDialogData();
468 dc
= new wxPrinterDC( m_printDialogData
.GetPrintData() ) ;
471 // May have pressed cancel.
472 if (!dc
|| !dc
->IsOk())
478 // on the mac we have always pixels as addressing mode with 72 dpi
479 printout
->SetPPIScreen(72, 72);
481 wxOSXPrintData
* nativeData
= (wxOSXPrintData
*)
482 (m_printDialogData
.GetPrintData().GetNativeData());
483 PMGetResolution( (nativeData
->GetPageFormat()), &res
);
484 printout
->SetPPIPrinter(int(res
.hRes
), int(res
.vRes
));
486 // Set printout parameters
491 printout
->SetPageSizePixels((int)w
, (int)h
);
492 printout
->SetPaperRectPixels(dc
->GetPaperRect());
494 dc
->GetSizeMM(&mw
, &mh
);
495 printout
->SetPageSizeMM((int)mw
, (int)mh
);
497 // Create an abort window
500 printout
->OnPreparePrinting();
502 // Get some parameters from the printout, if defined
503 int fromPage
, toPage
;
504 int minPage
, maxPage
;
505 printout
->GetPageInfo(&minPage
, &maxPage
, &fromPage
, &toPage
);
513 // Only set min and max, because from and to have been
515 m_printDialogData
.SetMinPage(minPage
);
516 m_printDialogData
.SetMaxPage(maxPage
);
518 printout
->OnBeginPrinting();
520 bool keepGoing
= true;
522 if (!printout
->OnBeginDocument(m_printDialogData
.GetFromPage(), m_printDialogData
.GetToPage()))
525 wxMessageBox(wxT("Could not start printing."), wxT("Print Error"), wxOK
, parent
);
529 for (pn
= m_printDialogData
.GetFromPage();
530 keepGoing
&& (pn
<= m_printDialogData
.GetToPage()) && printout
->HasPage(pn
);
541 keepGoing
= printout
->OnPrintPage(pn
);
545 printout
->OnEndDocument();
547 printout
->OnEndPrinting();
551 sm_abortWindow
->Show(false);
552 delete sm_abortWindow
;
553 sm_abortWindow
= NULL
;
563 wxDC
* wxMacPrinter::PrintDialog(wxWindow
*parent
)
565 wxDC
* dc
= (wxDC
*) NULL
;
567 wxPrintDialog
dialog(parent
, & m_printDialogData
);
568 int ret
= dialog
.ShowModal();
572 dc
= dialog
.GetPrintDC();
573 m_printDialogData
= dialog
.GetPrintDialogData();
579 bool wxMacPrinter::Setup(wxWindow
*WXUNUSED(parent
))
582 wxPrintDialog
dialog(parent
, & m_printDialogData
);
583 dialog
.GetPrintDialogData().SetSetupDialog(true);
585 int ret
= dialog
.ShowModal();
588 m_printDialogData
= dialog
.GetPrintDialogData();
590 return (ret
== wxID_OK
);
600 IMPLEMENT_CLASS(wxMacPrintPreview
, wxPrintPreviewBase
)
602 wxMacPrintPreview::wxMacPrintPreview(wxPrintout
*printout
,
603 wxPrintout
*printoutForPrinting
,
604 wxPrintDialogData
*data
)
605 : wxPrintPreviewBase(printout
, printoutForPrinting
, data
)
610 wxMacPrintPreview::wxMacPrintPreview(wxPrintout
*printout
, wxPrintout
*printoutForPrinting
, wxPrintData
*data
):
611 wxPrintPreviewBase(printout
, printoutForPrinting
, data
)
616 wxMacPrintPreview::~wxMacPrintPreview(void)
620 bool wxMacPrintPreview::Print(bool interactive
)
622 if (!m_printPrintout
)
625 wxMacPrinter
printer(&m_printDialogData
);
626 return printer
.Print(m_previewFrame
, m_printPrintout
, interactive
);
629 void wxMacPrintPreview::DetermineScaling(void)
631 int screenWidth
, screenHeight
;
632 wxDisplaySize( &screenWidth
, &screenHeight
) ;
634 wxSize
ppiScreen( 72 , 72 ) ;
635 wxSize
ppiPrinter( 72 , 72 ) ;
637 // Note that with Leopard, screen dpi=72 is no longer a given
638 m_previewPrintout
->SetPPIScreen( ppiScreen
.x
, ppiScreen
.y
) ;
644 // Get a device context for the currently selected printer
645 wxPrinterDC
printerDC(m_printDialogData
.GetPrintData());
646 if (printerDC
.IsOk())
648 printerDC
.GetSizeMM(&ww
, &hh
);
649 printerDC
.GetSize( &w
, &h
) ;
650 ppiPrinter
= printerDC
.GetPPI() ;
651 paperRect
= printerDC
.GetPaperRect();
659 ww
= (wxCoord
) (w
* 25.4 / ppiPrinter
.x
) ;
660 hh
= (wxCoord
) (h
* 25.4 / ppiPrinter
.y
) ;
661 paperRect
= wxRect(0, 0, w
, h
);
667 m_previewPrintout
->SetPageSizePixels(w
, h
) ;
668 m_previewPrintout
->SetPageSizeMM(ww
, hh
);
669 m_previewPrintout
->SetPaperRectPixels(paperRect
);
670 m_previewPrintout
->SetPPIPrinter( ppiPrinter
.x
, ppiPrinter
.y
) ;
672 m_previewScaleX
= float(ppiScreen
.x
) / ppiPrinter
.x
;
673 m_previewScaleY
= float(ppiScreen
.y
) / ppiPrinter
.y
;
677 // end of print_osx.cpp
682 IMPLEMENT_DYNAMIC_CLASS(wxOSXCarbonPrintData
, wxOSXPrintData
)
684 wxOSXCarbonPrintData::wxOSXCarbonPrintData()
686 if ( PMCreateSession( &m_macPrintSession
) == noErr
)
688 if ( PMCreatePageFormat(&m_macPageFormat
) == noErr
)
690 PMSessionDefaultPageFormat(m_macPrintSession
,
692 PMGetPageFormatPaper(m_macPageFormat
, &m_macPaper
);
695 if ( PMCreatePrintSettings(&m_macPrintSettings
) == noErr
)
697 PMSessionDefaultPrintSettings(m_macPrintSession
,
703 wxOSXCarbonPrintData::~wxOSXCarbonPrintData()
705 (void)PMRelease(m_macPageFormat
);
706 (void)PMRelease(m_macPrintSettings
);
707 (void)PMRelease(m_macPrintSession
);