1///////////////////////////////////////////////////////////////////////////// 2// Name: src/mac/carbon/printwin.cpp 3// Purpose: wxMacPrinter framework 4// Author: Julian Smart 5// Modified by: Stefan Csomor 6// Created: 04/01/98 7// RCS-ID: $Id: printmac.cpp 58882 2009-02-13 16:05:12Z SC $ 8// Copyright: (c) Julian Smart, Stefan Csomor 9// Licence: wxWindows licence 10///////////////////////////////////////////////////////////////////////////// 11 12// For compilers that support precompilation, includes "wx.h". 13#include "wx/wxprec.h" 14 15#if wxUSE_PRINTING_ARCHITECTURE 16 17#ifdef __BORLANDC__ 18 #pragma hdrstop 19#endif 20 21#ifndef WX_PRECOMP 22 #include "wx/utils.h" 23 #include "wx/dc.h" 24 #include "wx/app.h" 25 #include "wx/msgdlg.h" 26 #include "wx/dcprint.h" 27 #include "wx/math.h" 28#endif 29 30#include "wx/mac/uma.h" 31 32#include "wx/mac/printmac.h" 33#include "wx/mac/private/print.h" 34 35#include "wx/printdlg.h" 36#include "wx/paper.h" 37#include "wx/mac/printdlg.h" 38 39#include <stdlib.h> 40 41IMPLEMENT_DYNAMIC_CLASS(wxMacCarbonPrintData, wxPrintNativeDataBase) 42IMPLEMENT_DYNAMIC_CLASS(wxMacPrinter, wxPrinterBase) 43IMPLEMENT_CLASS(wxMacPrintPreview, wxPrintPreviewBase) 44 45bool wxMacCarbonPrintData::IsOk() const 46{ 47 return (m_macPageFormat != kPMNoPageFormat) && (m_macPrintSettings != kPMNoPrintSettings) && (m_macPrintSession != kPMNoReference); 48} 49wxMacCarbonPrintData::wxMacCarbonPrintData() 50{ 51 m_macPageFormat = kPMNoPageFormat; 52 m_macPrintSettings = kPMNoPrintSettings; 53 m_macPrintSession = kPMNoReference ; 54 m_macPaper = kPMNoData; 55 56 if ( PMCreateSession( &m_macPrintSession ) == noErr ) 57 { 58 if ( PMCreatePageFormat(&m_macPageFormat) == noErr ) 59 { 60 PMSessionDefaultPageFormat(m_macPrintSession, 61 m_macPageFormat); 62 PMGetPageFormatPaper(m_macPageFormat, &m_macPaper); 63 } 64 65 if ( PMCreatePrintSettings(&m_macPrintSettings) == noErr ) 66 { 67 PMSessionDefaultPrintSettings(m_macPrintSession, 68 m_macPrintSettings); 69 } 70 } 71} 72 73wxMacCarbonPrintData::~wxMacCarbonPrintData() 74{ 75 (void)PMRelease(m_macPageFormat); 76 (void)PMRelease(m_macPrintSettings); 77 (void)PMRelease(m_macPrintSession); 78} 79 80bool wxMacCarbonPrintData::TransferFrom( const wxPrintData &data ) 81{ 82 PMPrinter printer; 83 PMSessionGetCurrentPrinter(m_macPrintSession, &printer); 84 85 wxSize papersize = wxDefaultSize; 86 const wxPaperSize paperId = data.GetPaperId(); 87 if ( paperId != wxPAPER_NONE && wxThePrintPaperDatabase ) 88 { 89 papersize = wxThePrintPaperDatabase->GetSize(paperId); 90 if ( papersize != wxDefaultSize ) 91 { 92 papersize.x /= 10; 93 papersize.y /= 10; 94 } 95 } 96 else 97 { 98 papersize = data.GetPaperSize(); 99 } 100 101 if ( papersize != wxDefaultSize ) 102 { 103 papersize.x *= mm2pt; 104 papersize.y *= mm2pt; 105 106 double height, width; 107 PMPaperGetHeight(m_macPaper, &height); 108 PMPaperGetWidth(m_macPaper, &width); 109 110 if ( fabs( width - papersize.x ) >= 5 || 111 fabs( height - papersize.y ) >= 5 ) 112 { 113 // we have to change the current paper 114 CFArrayRef paperlist = 0 ; 115 if ( PMPrinterGetPaperList( printer, &paperlist ) == noErr ) 116 { 117 PMPaper bestPaper = kPMNoData ; 118 CFIndex top = CFArrayGetCount(paperlist); 119 for ( CFIndex i = 0 ; i < top ; ++ i ) 120 { 121 PMPaper paper = (PMPaper) CFArrayGetValueAtIndex( paperlist, i ); 122 PMPaperGetHeight(paper, &height); 123 PMPaperGetWidth(paper, &width); 124 if ( fabs( width - papersize.x ) < 5 && 125 fabs( height - papersize.y ) < 5 ) 126 { 127 // TODO test for duplicate hits and use additional 128 // criteria for best match 129 bestPaper = paper; 130 } 131 } 132 if ( bestPaper != kPMNoData ) 133 { 134 PMPageFormat pageFormat; 135 PMCreatePageFormatWithPMPaper(&pageFormat, bestPaper); 136 PMCopyPageFormat( pageFormat, m_macPageFormat ); 137 PMRelease(pageFormat); 138 PMGetPageFormatPaper(m_macPageFormat, &m_macPaper); 139 } 140 } 141 } 142 } 143 144 PMSetCopies( m_macPrintSettings , data.GetNoCopies() , false ) ; 145 PMSetCollate(m_macPrintSettings, data.GetCollate()); 146 if ( data.IsOrientationReversed() ) 147 PMSetOrientation( m_macPageFormat , ( data.GetOrientation() == wxLANDSCAPE ) ? 148 kPMReverseLandscape : kPMReversePortrait , false ) ; 149 else 150 PMSetOrientation( m_macPageFormat , ( data.GetOrientation() == wxLANDSCAPE ) ? 151 kPMLandscape : kPMPortrait , false ) ; 152 // collate cannot be set 153#if 0 // not yet tested 154 if ( !m_printerName.empty() ) 155 PMSessionSetCurrentPrinter( m_macPrintSession , wxMacCFStringHolder( m_printerName , wxFont::GetDefaultEncoding() ) ) ; 156#endif 157 158#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 159 if ( &PMSetDuplex!=NULL ) 160 { 161 PMDuplexMode mode = 0 ; 162 switch( data.GetDuplex() ) 163 { 164 case wxDUPLEX_HORIZONTAL : 165 mode = kPMDuplexNoTumble ; 166 break ; 167 case wxDUPLEX_VERTICAL : 168 mode = kPMDuplexTumble ; 169 break ; 170 case wxDUPLEX_SIMPLEX : 171 default : 172 mode = kPMDuplexNone ; 173 break ; 174 } 175 PMSetDuplex( m_macPrintSettings, mode ) ; 176 } 177#endif 178 // PMQualityMode not accessible via API 179 // TODO: use our quality property to determine optimal resolution 180 PMResolution res; 181 PMTag tag = kPMMaxSquareResolution; 182 PMPrinterGetPrinterResolution(printer, tag, &res); 183 PMSetResolution(m_macPageFormat, &res); 184 185 // after setting the new resolution the format has to be updated, otherwise the page rect remains 186 // at the 'old' scaling 187 PMSessionValidatePageFormat(m_macPrintSession, 188 m_macPageFormat, kPMDontWantBoolean); 189 PMSessionValidatePrintSettings(m_macPrintSession, 190 m_macPrintSettings, kPMDontWantBoolean); 191 192 return true ; 193} 194 195bool wxMacCarbonPrintData::TransferTo( wxPrintData &data ) 196{ 197 OSStatus err = noErr ; 198 199 UInt32 copies ; 200 err = PMGetCopies( m_macPrintSettings , &copies ) ; 201 if ( err == noErr ) 202 data.SetNoCopies( copies ) ; 203 204 PMOrientation orientation ; 205 err = PMGetOrientation( m_macPageFormat , &orientation ) ; 206 if ( err == noErr ) 207 { 208 if ( orientation == kPMPortrait || orientation == kPMReversePortrait ) 209 { 210 data.SetOrientation( wxPORTRAIT ); 211 data.SetOrientationReversed( orientation == kPMReversePortrait ); 212 } 213 else 214 { 215 data.SetOrientation( wxLANDSCAPE ); 216 data.SetOrientationReversed( orientation == kPMReverseLandscape ); 217 } 218 } 219 220 Boolean collate; 221 if (PMGetCollate(m_macPrintSettings, &collate) == noErr) 222 data.SetCollate(collate); 223#if 0 224 { 225 wxMacCFStringHolder name ; 226 PMPrinter printer ; 227 PMSessionGetCurrentPrinter( m_macPrintSession , 228 &printer ) ; 229 m_printerName = name.AsString() ; 230 } 231#endif 232 233#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 234 if ( &PMGetDuplex!=NULL ) 235 { 236 PMDuplexMode mode = 0 ; 237 PMGetDuplex( m_macPrintSettings, &mode ) ; 238 switch( mode ) 239 { 240 case kPMDuplexNoTumble : 241 data.SetDuplex(wxDUPLEX_HORIZONTAL); 242 break ; 243 case kPMDuplexTumble : 244 data.SetDuplex(wxDUPLEX_VERTICAL); 245 break ; 246 case kPMDuplexNone : 247 default : 248 data.SetDuplex(wxDUPLEX_SIMPLEX); 249 break ; 250 } 251 } 252#endif 253 // PMQualityMode not yet accessible via API 254 255 double height, width; 256 PMPaperGetHeight(m_macPaper, &height); 257 PMPaperGetWidth(m_macPaper, &width); 258 259 wxSize sz((int)(width * pt2mm + 0.5 ) , 260 (int)(height * pt2mm + 0.5 )); 261 data.SetPaperSize(sz); 262 wxPaperSize id = wxThePrintPaperDatabase->GetSize(wxSize(sz.x* 10, sz.y * 10)); 263 if (id != wxPAPER_NONE) 264 { 265 data.SetPaperId(id); 266 } 267 return true ; 268} 269 270void wxMacCarbonPrintData::TransferFrom( wxPageSetupData *data ) 271{ 272 // should we setup the page rect here ? 273 // since MacOS sometimes has two same paper rects with different 274 // page rects we could make it roundtrip safe perhaps 275} 276 277void wxMacCarbonPrintData::TransferTo( wxPageSetupData* data ) 278{ 279 PMRect rPaper; 280 OSStatus err = PMGetUnadjustedPaperRect(m_macPageFormat, &rPaper); 281 if ( err == noErr ) 282 { 283 wxSize sz((int)(( rPaper.right - rPaper.left ) * pt2mm + 0.5 ) , 284 (int)(( rPaper.bottom - rPaper.top ) * pt2mm + 0.5 )); 285 data->SetPaperSize(sz); 286 287 PMRect rPage ; 288 err = PMGetUnadjustedPageRect(m_macPageFormat , &rPage ) ; 289 if ( err == noErr ) 290 { 291 data->SetMinMarginTopLeft( wxPoint ( 292 (int)(((double) rPage.left - rPaper.left ) * pt2mm) , 293 (int)(((double) rPage.top - rPaper.top ) * pt2mm) ) ) ; 294 295 data->SetMinMarginBottomRight( wxPoint ( 296 (wxCoord)(((double) rPaper.right - rPage.right ) * pt2mm), 297 (wxCoord)(((double) rPaper.bottom - rPage.bottom ) * pt2mm)) ) ; 298 299 if ( data->GetMarginTopLeft().x < data->GetMinMarginTopLeft().x ) 300 data->SetMarginTopLeft( wxPoint( data->GetMinMarginTopLeft().x , 301 data->GetMarginTopLeft().y ) ) ; 302 303 if ( data->GetMarginBottomRight().x < data->GetMinMarginBottomRight().x ) 304 data->SetMarginBottomRight( wxPoint( data->GetMinMarginBottomRight().x , 305 data->GetMarginBottomRight().y ) ); 306 307 if ( data->GetMarginTopLeft().y < data->GetMinMarginTopLeft().y ) 308 data->SetMarginTopLeft( wxPoint( data->GetMarginTopLeft().x , data->GetMinMarginTopLeft().y ) ); 309 310 if ( data->GetMarginBottomRight().y < data->GetMinMarginBottomRight().y ) 311 data->SetMarginBottomRight( wxPoint( data->GetMarginBottomRight().x , 312 data->GetMinMarginBottomRight().y) ); 313 } 314 } 315} 316 317void wxMacCarbonPrintData::TransferTo( wxPrintDialogData* data ) 318{ 319 UInt32 minPage , maxPage ; 320 PMGetPageRange( m_macPrintSettings , &minPage , &maxPage ) ; 321 data->SetMinPage( minPage ) ; 322 data->SetMaxPage( maxPage ) ; 323 UInt32 copies ; 324 PMGetCopies( m_macPrintSettings , &copies ) ; 325 data->SetNoCopies( copies ) ; 326 UInt32 from , to ; 327 PMGetFirstPage( m_macPrintSettings , &from ) ; 328 PMGetLastPage( m_macPrintSettings , &to ) ; 329 if ( to >= 0x7FFFFFFF ) // due to an OS Bug we don't get back kPMPrintAllPages 330 { 331 data->SetAllPages( true ) ; 332 // This means all pages, more or less 333 data->SetFromPage(1); 334 data->SetToPage(9999); 335 } 336 else 337 { 338 data->SetFromPage( from ) ; 339 data->SetToPage( to ) ; 340 data->SetAllPages( false ); 341 } 342} 343 344void wxMacCarbonPrintData::TransferFrom( wxPrintDialogData* data ) 345{ 346 PMSetPageRange( m_macPrintSettings , data->GetMinPage() , data->GetMaxPage() ) ; 347 PMSetCopies( m_macPrintSettings , data->GetNoCopies() , false ) ; 348 PMSetFirstPage( m_macPrintSettings , data->GetFromPage() , false ) ; 349 350 if (data->GetAllPages() || data->GetFromPage() == 0) 351 PMSetLastPage( m_macPrintSettings , (UInt32) kPMPrintAllPages, true ) ; 352 else 353 PMSetLastPage( m_macPrintSettings , (UInt32) data->GetToPage() , false ) ; 354} 355 356/* 357* Printer 358*/ 359 360wxMacPrinter::wxMacPrinter(wxPrintDialogData *data): 361wxPrinterBase(data) 362{ 363} 364 365wxMacPrinter::~wxMacPrinter(void) 366{ 367} 368 369bool wxMacPrinter::Print(wxWindow *parent, wxPrintout *printout, bool prompt) 370{ 371 sm_abortIt = false; 372 sm_abortWindow = NULL; 373 374 if (!printout) 375 return false; 376 377 printout->SetIsPreview(false); 378 if (m_printDialogData.GetMinPage() < 1) 379 m_printDialogData.SetMinPage(1); 380 if (m_printDialogData.GetMaxPage() < 1) 381 m_printDialogData.SetMaxPage(9999); 382 383 // Create a suitable device context 384 wxPrinterDC *dc = NULL; 385 if (prompt) 386 { 387 wxMacPrintDialog dialog(parent, & m_printDialogData); 388 if (dialog.ShowModal() == wxID_OK) 389 { 390 dc = wxDynamicCast(dialog.GetPrintDC(), wxPrinterDC); 391 wxASSERT(dc); 392 m_printDialogData = dialog.GetPrintDialogData(); 393 } 394 } 395 else 396 { 397 dc = new wxPrinterDC( m_printDialogData.GetPrintData() ) ; 398 } 399 400 // May have pressed cancel. 401 if (!dc || !dc->Ok()) 402 { 403 if (dc) 404 delete dc; 405 return false; 406 } 407 408 // on the mac we have always pixels as addressing mode with 72 dpi 409 printout->SetPPIScreen(72, 72); 410 PMResolution res; 411 wxMacCarbonPrintData* nativeData = (wxMacCarbonPrintData*) 412 (m_printDialogData.GetPrintData().GetNativeData()); 413 PMGetResolution((nativeData->m_macPageFormat), &res); 414 printout->SetPPIPrinter(int(res.hRes), int(res.vRes)); 415 416 // Set printout parameters 417 printout->SetDC(dc); 418 419 int w, h; 420 dc->GetSize(&w, &h); 421 printout->SetPageSizePixels((int)w, (int)h); 422 printout->SetPaperRectPixels(dc->GetPaperRect()); 423 wxCoord mw, mh; 424 dc->GetSizeMM(&mw, &mh); 425 printout->SetPageSizeMM((int)mw, (int)mh); 426 427 // Create an abort window 428 wxBeginBusyCursor(); 429 430 printout->OnPreparePrinting(); 431 432 // Get some parameters from the printout, if defined 433 int fromPage, toPage; 434 int minPage, maxPage; 435 printout->GetPageInfo(&minPage, &maxPage, &fromPage, &toPage); 436 437 if (maxPage == 0) 438 { 439 wxEndBusyCursor(); 440 return false; 441 } 442 443 // Only set min and max, because from and to have been 444 // set by the user 445 m_printDialogData.SetMinPage(minPage); 446 m_printDialogData.SetMaxPage(maxPage); 447 448 wxWindow *win = CreateAbortWindow(parent, printout); 449 wxSafeYield(win,true); 450 451 if (!win) 452 { 453 wxEndBusyCursor(); 454 wxMessageBox(wxT("Sorry, could not create an abort dialog."), wxT("Print Error"), wxOK, parent); 455 delete dc; 456 457 return false; 458 } 459 460 sm_abortWindow = win; 461 sm_abortWindow->Show(true); 462 wxSafeYield(win,true); 463 464 printout->OnBeginPrinting(); 465 466 bool keepGoing = true; 467 468 int copyCount; 469 for (copyCount = 1; copyCount <= m_printDialogData.GetNoCopies(); copyCount ++) 470 { 471 if (!printout->OnBeginDocument(m_printDialogData.GetFromPage(), m_printDialogData.GetToPage())) 472 { 473 wxEndBusyCursor(); 474 wxMessageBox(wxT("Could not start printing."), wxT("Print Error"), wxOK, parent); 475 break; 476 } 477 if (sm_abortIt) 478 break; 479 480 int pn; 481 for (pn = m_printDialogData.GetFromPage(); 482 keepGoing && (pn <= m_printDialogData.GetToPage()) && printout->HasPage(pn); 483 pn++) 484 { 485 if (sm_abortIt) 486 { 487 keepGoing = false; 488 break; 489 } 490 else 491 { 492#if TARGET_CARBON 493 if ( UMAGetSystemVersion() >= 0x1000 ) 494#endif 495 { 496#if !wxMAC_USE_CORE_GRAPHICS 497 GrafPtr thePort ; 498 GetPort( &thePort ) ; 499#endif 500 wxSafeYield(win,true); 501#if !wxMAC_USE_CORE_GRAPHICS 502 SetPort( thePort ) ; 503#endif 504 } 505 dc->StartPage(); 506 keepGoing = printout->OnPrintPage(pn); 507 dc->EndPage(); 508 } 509 } 510 printout->OnEndDocument(); 511 } 512 513 printout->OnEndPrinting(); 514 515 if (sm_abortWindow) 516 { 517 sm_abortWindow->Show(false); 518 delete sm_abortWindow; 519 sm_abortWindow = NULL; 520 } 521 522 wxEndBusyCursor(); 523 524 delete dc; 525 526 return true; 527} 528 529wxDC* wxMacPrinter::PrintDialog(wxWindow *parent) 530{ 531 wxDC* dc = (wxDC*) NULL; 532 533 wxPrintDialog dialog(parent, & m_printDialogData); 534 int ret = dialog.ShowModal(); 535 536 if (ret == wxID_OK) 537 { 538 dc = dialog.GetPrintDC(); 539 m_printDialogData = dialog.GetPrintDialogData(); 540 } 541 542 return dc; 543} 544 545bool wxMacPrinter::Setup(wxWindow *parent) 546{ 547#if 0 548 wxPrintDialog dialog(parent, & m_printDialogData); 549 dialog.GetPrintDialogData().SetSetupDialog(true); 550 551 int ret = dialog.ShowModal(); 552 553 if (ret == wxID_OK) 554 m_printDialogData = dialog.GetPrintDialogData(); 555 556 return (ret == wxID_OK); 557#endif 558 559 return wxID_CANCEL; 560} 561 562/* 563* Print preview 564*/ 565 566wxMacPrintPreview::wxMacPrintPreview(wxPrintout *printout, 567 wxPrintout *printoutForPrinting, 568 wxPrintDialogData *data) 569 : wxPrintPreviewBase(printout, printoutForPrinting, data) 570{ 571 DetermineScaling(); 572} 573 574wxMacPrintPreview::wxMacPrintPreview(wxPrintout *printout, wxPrintout *printoutForPrinting, wxPrintData *data): 575wxPrintPreviewBase(printout, printoutForPrinting, data) 576{ 577 DetermineScaling(); 578} 579 580wxMacPrintPreview::~wxMacPrintPreview(void) 581{ 582} 583 584bool wxMacPrintPreview::Print(bool interactive) 585{ 586 if (!m_printPrintout) 587 return false; 588 589 wxMacPrinter printer(&m_printDialogData); 590 return printer.Print(m_previewFrame, m_printPrintout, interactive); 591} 592 593void wxMacPrintPreview::DetermineScaling(void) 594{ 595 int screenWidth , screenHeight ; 596 wxDisplaySize( &screenWidth , &screenHeight ) ; 597 598 wxSize ppiScreen( 72 , 72 ) ; 599 wxSize ppiPrinter( 72 , 72 ) ; 600 601 // Note that with Leopard, screen dpi=72 is no longer a given 602 m_previewPrintout->SetPPIScreen( ppiScreen.x , ppiScreen.y ) ; 603 604 wxCoord w , h ; 605 wxCoord ww, hh; 606 wxRect paperRect; 607 608 // Get a device context for the currently selected printer 609 wxPrinterDC printerDC(m_printDialogData.GetPrintData()); 610 if (printerDC.Ok()) 611 { 612 printerDC.GetSizeMM(&ww, &hh); 613 printerDC.GetSize( &w , &h ) ; 614 ppiPrinter = printerDC.GetPPI() ; 615 paperRect = printerDC.GetPaperRect(); 616 m_isOk = true ; 617 } 618 else 619 { 620 // use some defaults 621 w = 8 * 72 ; 622 h = 11 * 72 ; 623 ww = (wxCoord) (w * 25.4 / ppiPrinter.x) ; 624 hh = (wxCoord) (h * 25.4 / ppiPrinter.y) ; 625 paperRect = wxRect(0, 0, w, h); 626 m_isOk = false ; 627 } 628 m_pageWidth = w; 629 m_pageHeight = h; 630 631 m_previewPrintout->SetPageSizePixels(w , h) ; 632 m_previewPrintout->SetPageSizeMM(ww, hh); 633 m_previewPrintout->SetPaperRectPixels(paperRect); 634 m_previewPrintout->SetPPIPrinter( ppiPrinter.x , ppiPrinter.y ) ; 635 636 m_previewScaleX = float(ppiScreen.x) / ppiPrinter.x; 637 m_previewScaleY = float(ppiScreen.y) / ppiPrinter.y; 638} 639 640#endif 641