1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_vcl.hxx" 26 27 /** 28 this file implements the sal printer interface ( SalPrinter, SalInfoPrinter 29 and some printer relevant methods of SalInstance and SalGraphicsData ) 30 31 as aunderlying library the printer features of psprint are used. 32 33 The query methods of a SalInfoPrinter are implemented by querying psprint 34 35 The job methods of a SalPrinter are implemented by calling psprint 36 printer job functions. 37 */ 38 39 #include <unistd.h> 40 #include <sys/wait.h> 41 #include <sys/stat.h> 42 43 #include "rtl/ustring.hxx" 44 45 #include "osl/module.h" 46 47 #include "vcl/svapp.hxx" 48 #include "vcl/print.hxx" 49 #include "vcl/pdfwriter.hxx" 50 #include "vcl/printerinfomanager.hxx" 51 52 #include <unx/salunx.h> 53 #include "unx/saldisp.hxx" 54 #include "unx/salinst.h" 55 #include "unx/salprn.h" 56 #include "unx/salframe.h" 57 #include "unx/pspgraphics.h" 58 #include "unx/saldata.hxx" 59 60 #include "jobset.h" 61 #include "print.h" 62 #include "salptype.hxx" 63 64 using namespace psp; 65 using namespace rtl; 66 using namespace com::sun::star; 67 68 /* 69 * static helpers 70 */ 71 72 static oslModule driverLib = NULL; 73 extern "C" 74 { 75 typedef int(*setupFunction)(PrinterInfo&); 76 static setupFunction pSetupFunction = NULL; 77 typedef int(*faxFunction)(String&); 78 static faxFunction pFaxNrFunction = NULL; 79 } 80 81 static String getPdfDir( const PrinterInfo& rInfo ) 82 { 83 String aDir; 84 sal_Int32 nIndex = 0; 85 while( nIndex != -1 ) 86 { 87 OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) ); 88 if( ! aToken.compareToAscii( "pdf=", 4 ) ) 89 { 90 sal_Int32 nPos = 0; 91 aDir = aToken.getToken( 1, '=', nPos ); 92 if( ! aDir.Len() ) 93 aDir = String( ByteString( getenv( "HOME" ) ), osl_getThreadTextEncoding() ); 94 break; 95 } 96 } 97 return aDir; 98 } 99 100 static void getPaLib() 101 { 102 if( ! driverLib ) 103 { 104 OUString aLibName( RTL_CONSTASCII_USTRINGPARAM( _XSALSET_LIBNAME ) ); 105 driverLib = osl_loadModuleRelative( (oslGenericFunction)getPaLib, aLibName.pData, SAL_LOADMODULE_DEFAULT ); 106 if ( !driverLib ) 107 { 108 return; 109 } 110 111 pSetupFunction = (setupFunction)osl_getAsciiFunctionSymbol( driverLib, "Sal_SetupPrinterDriver" ); 112 if ( !pSetupFunction ) 113 fprintf( stderr, "could not resolve Sal_SetupPrinterDriver\n" ); 114 115 pFaxNrFunction = (faxFunction)osl_getAsciiFunctionSymbol( driverLib, "Sal_queryFaxNumber" ); 116 if ( !pFaxNrFunction ) 117 fprintf( stderr, "could not resolve Sal_queryFaxNumber\n" ); 118 } 119 } 120 121 inline int PtTo10Mu( int nPoints ) { return (int)((((double)nPoints)*35.27777778)+0.5); } 122 123 inline int TenMuToPt( int nUnits ) { return (int)((((double)nUnits)/35.27777778)+0.5); } 124 125 static void copyJobDataToJobSetup( ImplJobSetup* pJobSetup, JobData& rData ) 126 { 127 pJobSetup->meOrientation = (Orientation)(rData.m_eOrientation == orientation::Landscape ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT); 128 129 // copy page size 130 String aPaper; 131 int width, height; 132 133 rData.m_aContext.getPageSize( aPaper, width, height ); 134 pJobSetup->mePaperFormat = PaperInfo::fromPSName(OUStringToOString( aPaper, RTL_TEXTENCODING_ISO_8859_1 )); 135 136 pJobSetup->mnPaperWidth = 0; 137 pJobSetup->mnPaperHeight = 0; 138 if( pJobSetup->mePaperFormat == PAPER_USER ) 139 { 140 // transform to 100dth mm 141 width = PtTo10Mu( width ); 142 height = PtTo10Mu( height ); 143 144 if( rData.m_eOrientation == psp::orientation::Portrait ) 145 { 146 pJobSetup->mnPaperWidth = width; 147 pJobSetup->mnPaperHeight= height; 148 } 149 else 150 { 151 pJobSetup->mnPaperWidth = height; 152 pJobSetup->mnPaperHeight= width; 153 } 154 } 155 156 // copy input slot 157 const PPDKey* pKey = NULL; 158 const PPDValue* pValue = NULL; 159 160 pJobSetup->mnPaperBin = 0; 161 if( rData.m_pParser ) 162 pKey = rData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ); 163 if( pKey ) 164 pValue = rData.m_aContext.getValue( pKey ); 165 if( pKey && pValue ) 166 { 167 for( pJobSetup->mnPaperBin = 0; 168 pValue != pKey->getValue( pJobSetup->mnPaperBin ) && 169 pJobSetup->mnPaperBin < pKey->countValues(); 170 pJobSetup->mnPaperBin++ ) 171 ; 172 if( pJobSetup->mnPaperBin >= pKey->countValues() ) 173 pJobSetup->mnPaperBin = 0; 174 } 175 176 // copy duplex 177 pKey = NULL; 178 pValue = NULL; 179 180 pJobSetup->meDuplexMode = DUPLEX_UNKNOWN; 181 if( rData.m_pParser ) 182 pKey = rData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) ); 183 if( pKey ) 184 pValue = rData.m_aContext.getValue( pKey ); 185 if( pKey && pValue ) 186 { 187 if( pValue->m_aOption.EqualsIgnoreCaseAscii( "None" ) || 188 pValue->m_aOption.EqualsIgnoreCaseAscii( "Simplex", 0, 7 ) 189 ) 190 { 191 pJobSetup->meDuplexMode = DUPLEX_OFF; 192 } 193 else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexNoTumble" ) ) 194 { 195 pJobSetup->meDuplexMode = DUPLEX_LONGEDGE; 196 } 197 else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexTumble" ) ) 198 { 199 pJobSetup->meDuplexMode = DUPLEX_SHORTEDGE; 200 } 201 } 202 203 // copy the whole context 204 if( pJobSetup->mpDriverData ) 205 rtl_freeMemory( pJobSetup->mpDriverData ); 206 207 int nBytes; 208 void* pBuffer = NULL; 209 if( rData.getStreamBuffer( pBuffer, nBytes ) ) 210 { 211 pJobSetup->mnDriverDataLen = nBytes; 212 pJobSetup->mpDriverData = (sal_uInt8*)pBuffer; 213 } 214 else 215 { 216 pJobSetup->mnDriverDataLen = 0; 217 pJobSetup->mpDriverData = NULL; 218 } 219 } 220 221 static bool passFileToCommandLine( const String& rFilename, const String& rCommandLine, bool bRemoveFile = true ) 222 { 223 bool bSuccess = false; 224 225 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); 226 ByteString aCmdLine( rCommandLine, aEncoding ); 227 ByteString aFilename( rFilename, aEncoding ); 228 229 bool bPipe = aCmdLine.Search( "(TMP)" ) != STRING_NOTFOUND ? false : true; 230 231 // setup command line for exec 232 if( ! bPipe ) 233 while( aCmdLine.SearchAndReplace( "(TMP)", aFilename ) != STRING_NOTFOUND ) 234 ; 235 236 #if OSL_DEBUG_LEVEL > 1 237 fprintf( stderr, "%s commandline: \"%s\"\n", 238 bPipe ? "piping to" : "executing", 239 aCmdLine.GetBuffer() ); 240 struct stat aStat; 241 if( stat( aFilename.GetBuffer(), &aStat ) ) 242 fprintf( stderr, "stat( %s ) failed\n", aFilename.GetBuffer() ); 243 fprintf( stderr, "Tmp file %s has modes: 0%03lo\n", aFilename.GetBuffer(), (long)aStat.st_mode ); 244 #endif 245 const char* argv[4]; 246 if( ! ( argv[ 0 ] = getenv( "SHELL" ) ) ) 247 argv[ 0 ] = "/bin/sh"; 248 argv[ 1 ] = "-c"; 249 argv[ 2 ] = aCmdLine.GetBuffer(); 250 argv[ 3 ] = 0; 251 252 bool bHavePipes = false; 253 int pid, fd[2]; 254 255 if( bPipe ) 256 bHavePipes = pipe( fd ) ? false : true; 257 if( ( pid = fork() ) > 0 ) 258 { 259 if( bPipe && bHavePipes ) 260 { 261 close( fd[0] ); 262 char aBuffer[ 2048 ]; 263 FILE* fp = fopen( aFilename.GetBuffer(), "r" ); 264 while( fp && ! feof( fp ) ) 265 { 266 int nBytes = fread( aBuffer, 1, sizeof( aBuffer ), fp ); 267 if( nBytes ) 268 write( fd[ 1 ], aBuffer, nBytes ); 269 } 270 fclose( fp ); 271 close( fd[ 1 ] ); 272 } 273 int status = 0; 274 waitpid( pid, &status, 0 ); 275 if( ! status ) 276 bSuccess = true; 277 } 278 else if( ! pid ) 279 { 280 if( bPipe && bHavePipes ) 281 { 282 close( fd[1] ); 283 if( fd[0] != STDIN_FILENO ) // not probable, but who knows :) 284 dup2( fd[0], STDIN_FILENO ); 285 } 286 execv( argv[0], const_cast<char**>(argv) ); 287 fprintf( stderr, "failed to execute \"%s\"\n", aCmdLine.GetBuffer() ); 288 _exit( 1 ); 289 } 290 else 291 fprintf( stderr, "failed to fork\n" ); 292 293 // clean up the mess 294 if( bRemoveFile ) 295 unlink( aFilename.GetBuffer() ); 296 297 return bSuccess; 298 } 299 300 static bool sendAFax( const String& rFaxNumber, const String& rFileName, const String& rCommand ) 301 { 302 std::list< OUString > aFaxNumbers; 303 304 if( ! rFaxNumber.Len() ) 305 { 306 getPaLib(); 307 if( pFaxNrFunction ) 308 { 309 String aNewNr; 310 if( pFaxNrFunction( aNewNr ) ) 311 aFaxNumbers.push_back( OUString( aNewNr ) ); 312 } 313 } 314 else 315 { 316 sal_Int32 nIndex = 0; 317 OUString aFaxes( rFaxNumber ); 318 OUString aBeginToken( RTL_CONSTASCII_USTRINGPARAM("<Fax#>") ); 319 OUString aEndToken( RTL_CONSTASCII_USTRINGPARAM("</Fax#>") ); 320 while( nIndex != -1 ) 321 { 322 nIndex = aFaxes.indexOf( aBeginToken, nIndex ); 323 if( nIndex != -1 ) 324 { 325 sal_Int32 nBegin = nIndex + aBeginToken.getLength(); 326 nIndex = aFaxes.indexOf( aEndToken, nIndex ); 327 if( nIndex != -1 ) 328 { 329 aFaxNumbers.push_back( aFaxes.copy( nBegin, nIndex-nBegin ) ); 330 nIndex += aEndToken.getLength(); 331 } 332 } 333 } 334 } 335 336 bool bSuccess = true; 337 if( aFaxNumbers.begin() != aFaxNumbers.end() ) 338 { 339 while( aFaxNumbers.begin() != aFaxNumbers.end() && bSuccess ) 340 { 341 String aCmdLine( rCommand ); 342 String aFaxNumber( aFaxNumbers.front() ); 343 aFaxNumbers.pop_front(); 344 while( aCmdLine.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(PHONE)" ) ), aFaxNumber ) != STRING_NOTFOUND ) 345 ; 346 #if OSL_DEBUG_LEVEL > 1 347 fprintf( stderr, "sending fax to \"%s\"\n", OUStringToOString( aFaxNumber, osl_getThreadTextEncoding() ).getStr() ); 348 #endif 349 bSuccess = passFileToCommandLine( rFileName, aCmdLine, false ); 350 } 351 } 352 else 353 bSuccess = false; 354 355 // clean up temp file 356 unlink( ByteString( rFileName, osl_getThreadTextEncoding() ).GetBuffer() ); 357 358 return bSuccess; 359 } 360 361 static bool createPdf( const String& rToFile, const String& rFromFile, const String& rCommandLine ) 362 { 363 String aCommandLine( rCommandLine ); 364 while( aCommandLine.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(OUTFILE)" ) ), rToFile ) != STRING_NOTFOUND ) 365 ; 366 return passFileToCommandLine( rFromFile, aCommandLine ); 367 } 368 369 /* 370 * SalInstance 371 */ 372 373 // ----------------------------------------------------------------------- 374 375 SalInfoPrinter* X11SalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo, 376 ImplJobSetup* pJobSetup ) 377 { 378 mbPrinterInit = true; 379 // create and initialize SalInfoPrinter 380 PspSalInfoPrinter* pPrinter = new PspSalInfoPrinter; 381 382 if( pJobSetup ) 383 { 384 PrinterInfoManager& rManager( PrinterInfoManager::get() ); 385 PrinterInfo aInfo( rManager.getPrinterInfo( pQueueInfo->maPrinterName ) ); 386 pPrinter->m_aJobData = aInfo; 387 pPrinter->m_aPrinterGfx.Init( pPrinter->m_aJobData ); 388 389 if( pJobSetup->mpDriverData ) 390 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo ); 391 392 pJobSetup->mnSystem = JOBSETUP_SYSTEM_UNIX; 393 pJobSetup->maPrinterName = pQueueInfo->maPrinterName; 394 pJobSetup->maDriver = aInfo.m_aDriverName; 395 copyJobDataToJobSetup( pJobSetup, aInfo ); 396 397 // set/clear backwards compatibility flag 398 bool bStrictSO52Compatibility = false; 399 std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it = 400 pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) ); 401 402 if( compat_it != pJobSetup->maValueMap.end() ) 403 { 404 if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) ) 405 bStrictSO52Compatibility = true; 406 } 407 pPrinter->m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility ); 408 } 409 410 411 return pPrinter; 412 } 413 414 // ----------------------------------------------------------------------- 415 416 void X11SalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter ) 417 { 418 delete pPrinter; 419 } 420 421 // ----------------------------------------------------------------------- 422 423 SalPrinter* X11SalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter ) 424 { 425 mbPrinterInit = true; 426 // create and initialize SalPrinter 427 PspSalPrinter* pPrinter = new PspSalPrinter( pInfoPrinter ); 428 pPrinter->m_aJobData = static_cast<PspSalInfoPrinter*>(pInfoPrinter)->m_aJobData; 429 430 return pPrinter; 431 } 432 433 // ----------------------------------------------------------------------- 434 435 void X11SalInstance::DestroyPrinter( SalPrinter* pPrinter ) 436 { 437 delete pPrinter; 438 } 439 440 // ----------------------------------------------------------------------- 441 442 void X11SalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList ) 443 { 444 mbPrinterInit = true; 445 PrinterInfoManager& rManager( PrinterInfoManager::get() ); 446 static const char* pNoSyncDetection = getenv( "SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION" ); 447 if( ! pNoSyncDetection || ! *pNoSyncDetection ) 448 { 449 // #i62663# synchronize possible asynchronouse printer detection now 450 rManager.checkPrintersChanged( true ); 451 } 452 ::std::list< OUString > aPrinters; 453 rManager.listPrinters( aPrinters ); 454 455 for( ::std::list< OUString >::iterator it = aPrinters.begin(); it != aPrinters.end(); ++it ) 456 { 457 const PrinterInfo& rInfo( rManager.getPrinterInfo( *it ) ); 458 // Neuen Eintrag anlegen 459 SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo; 460 pInfo->maPrinterName = *it; 461 pInfo->maDriver = rInfo.m_aDriverName; 462 pInfo->maLocation = rInfo.m_aLocation; 463 pInfo->maComment = rInfo.m_aComment; 464 pInfo->mpSysData = NULL; 465 466 sal_Int32 nIndex = 0; 467 while( nIndex != -1 ) 468 { 469 String aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) ); 470 if( aToken.CompareToAscii( "pdf=", 4 ) == COMPARE_EQUAL ) 471 { 472 pInfo->maLocation = getPdfDir( rInfo ); 473 break; 474 } 475 } 476 477 pList->Add( pInfo ); 478 } 479 } 480 481 // ----------------------------------------------------------------------- 482 483 void X11SalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo ) 484 { 485 delete pInfo; 486 } 487 488 // ----------------------------------------------------------------------- 489 490 void X11SalInstance::GetPrinterQueueState( SalPrinterQueueInfo* ) 491 { 492 mbPrinterInit = true; 493 } 494 495 // ----------------------------------------------------------------------- 496 497 String X11SalInstance::GetDefaultPrinter() 498 { 499 mbPrinterInit = true; 500 PrinterInfoManager& rManager( PrinterInfoManager::get() ); 501 return rManager.getDefaultPrinter(); 502 } 503 504 // ======================================================================= 505 506 PspSalInfoPrinter::PspSalInfoPrinter() 507 { 508 m_pGraphics = NULL; 509 m_bPapersInit = false; 510 } 511 512 // ----------------------------------------------------------------------- 513 514 PspSalInfoPrinter::~PspSalInfoPrinter() 515 { 516 if( m_pGraphics ) 517 { 518 delete m_pGraphics; 519 m_pGraphics = NULL; 520 } 521 } 522 523 // ----------------------------------------------------------------------- 524 525 void PspSalInfoPrinter::InitPaperFormats( const ImplJobSetup* ) 526 { 527 m_aPaperFormats.clear(); 528 m_bPapersInit = true; 529 530 if( m_aJobData.m_pParser ) 531 { 532 const PPDKey* pKey = m_aJobData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) ); 533 if( pKey ) 534 { 535 int nValues = pKey->countValues(); 536 for( int i = 0; i < nValues; i++ ) 537 { 538 const PPDValue* pValue = pKey->getValue( i ); 539 int nWidth = 0, nHeight = 0; 540 m_aJobData.m_pParser->getPaperDimension( pValue->m_aOption, nWidth, nHeight ); 541 PaperInfo aInfo(PtTo10Mu( nWidth ), PtTo10Mu( nHeight )); 542 m_aPaperFormats.push_back( aInfo ); 543 } 544 } 545 } 546 } 547 548 // ----------------------------------------------------------------------- 549 550 int PspSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* ) 551 { 552 return 900; 553 } 554 555 // ----------------------------------------------------------------------- 556 557 SalGraphics* PspSalInfoPrinter::GetGraphics() 558 { 559 // return a valid pointer only once 560 // the reasoning behind this is that we could have different 561 // SalGraphics that can run in multiple threads 562 // (future plans) 563 SalGraphics* pRet = NULL; 564 if( ! m_pGraphics ) 565 { 566 m_pGraphics = new PspGraphics( &m_aJobData, &m_aPrinterGfx, NULL, false, this ); 567 m_pGraphics->SetLayout( 0 ); 568 pRet = m_pGraphics; 569 } 570 return pRet; 571 } 572 573 // ----------------------------------------------------------------------- 574 575 void PspSalInfoPrinter::ReleaseGraphics( SalGraphics* pGraphics ) 576 { 577 if( pGraphics == m_pGraphics ) 578 { 579 delete pGraphics; 580 m_pGraphics = NULL; 581 } 582 return; 583 } 584 585 // ----------------------------------------------------------------------- 586 587 sal_Bool PspSalInfoPrinter::Setup( SalFrame* pFrame, ImplJobSetup* pJobSetup ) 588 { 589 if( ! pFrame || ! pJobSetup ) 590 return sal_False; 591 592 getPaLib(); 593 594 if( ! pSetupFunction ) 595 return sal_False; 596 597 PrinterInfoManager& rManager = PrinterInfoManager::get(); 598 599 PrinterInfo aInfo( rManager.getPrinterInfo( pJobSetup->maPrinterName ) ); 600 if ( pJobSetup->mpDriverData ) 601 { 602 SetData( ~0, pJobSetup ); 603 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo ); 604 } 605 606 if( pSetupFunction( aInfo ) ) 607 { 608 rtl_freeMemory( pJobSetup->mpDriverData ); 609 pJobSetup->mpDriverData = NULL; 610 611 int nBytes; 612 void* pBuffer = NULL; 613 aInfo.getStreamBuffer( pBuffer, nBytes ); 614 pJobSetup->mnDriverDataLen = nBytes; 615 pJobSetup->mpDriverData = (sal_uInt8*)pBuffer; 616 617 // copy everything to job setup 618 copyJobDataToJobSetup( pJobSetup, aInfo ); 619 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData ); 620 return sal_True; 621 } 622 return sal_False; 623 } 624 625 // ----------------------------------------------------------------------- 626 627 // This function gets the driver data and puts it into pJobSetup 628 // If pJobSetup->mpDriverData is NOT NULL, then the independend 629 // data should be merged into the driver data 630 // If pJobSetup->mpDriverData IS NULL, then the driver defaults 631 // should be merged into the independent data 632 sal_Bool PspSalInfoPrinter::SetPrinterData( ImplJobSetup* pJobSetup ) 633 { 634 // set/clear backwards compatibility flag 635 bool bStrictSO52Compatibility = false; 636 std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it = 637 pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) ); 638 639 if( compat_it != pJobSetup->maValueMap.end() ) 640 { 641 if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) ) 642 bStrictSO52Compatibility = true; 643 } 644 m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility ); 645 646 if( pJobSetup->mpDriverData ) 647 return SetData( ~0, pJobSetup ); 648 649 copyJobDataToJobSetup( pJobSetup, m_aJobData ); 650 651 return sal_True; 652 } 653 654 // ----------------------------------------------------------------------- 655 656 // This function merges the independ driver data 657 // and sets the new independ data in pJobSetup 658 // Only the data must be changed, where the bit 659 // in nGetDataFlags is set 660 sal_Bool PspSalInfoPrinter::SetData( 661 sal_uLong nSetDataFlags, 662 ImplJobSetup* pJobSetup ) 663 { 664 JobData aData; 665 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); 666 667 if( aData.m_pParser ) 668 { 669 const PPDKey* pKey; 670 const PPDValue* pValue; 671 672 // merge papersize if necessary 673 if( nSetDataFlags & SAL_JOBSET_PAPERSIZE ) 674 { 675 int nWidth, nHeight; 676 if( pJobSetup->meOrientation == ORIENTATION_PORTRAIT ) 677 { 678 nWidth = pJobSetup->mnPaperWidth; 679 nHeight = pJobSetup->mnPaperHeight; 680 } 681 else 682 { 683 nWidth = pJobSetup->mnPaperHeight; 684 nHeight = pJobSetup->mnPaperWidth; 685 } 686 String aPaper; 687 688 if( pJobSetup->mePaperFormat == PAPER_USER ) 689 aPaper = aData.m_pParser->matchPaper( 690 TenMuToPt( pJobSetup->mnPaperWidth ), 691 TenMuToPt( pJobSetup->mnPaperHeight ) ); 692 else 693 aPaper = rtl::OStringToOUString(PaperInfo::toPSName(pJobSetup->mePaperFormat), RTL_TEXTENCODING_ISO_8859_1); 694 695 pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) ); 696 pValue = pKey ? pKey->getValueCaseInsensitive( aPaper ) : NULL; 697 698 // some PPD files do not specify the standard paper names (e.g. C5 instead of EnvC5) 699 // try to find the correct paper anyway using the size 700 if( pKey && ! pValue && pJobSetup->mePaperFormat != PAPER_USER ) 701 { 702 PaperInfo aInfo( pJobSetup->mePaperFormat ); 703 aPaper = aData.m_pParser->matchPaper( 704 TenMuToPt( aInfo.getWidth() ), 705 TenMuToPt( aInfo.getHeight() ) ); 706 pValue = pKey->getValueCaseInsensitive( aPaper ); 707 } 708 709 if( ! ( pKey && pValue && aData.m_aContext.setValue( pKey, pValue, false ) == pValue ) ) 710 return sal_False; 711 } 712 713 // merge paperbin if necessary 714 if( nSetDataFlags & SAL_JOBSET_PAPERBIN ) 715 { 716 pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ); 717 if( pKey ) 718 { 719 int nPaperBin = pJobSetup->mnPaperBin; 720 if( nPaperBin >= pKey->countValues() ) 721 pValue = pKey->getDefaultValue(); 722 else 723 pValue = pKey->getValue( pJobSetup->mnPaperBin ); 724 725 // may fail due to constraints; 726 // real paper bin is copied back to jobsetup in that case 727 aData.m_aContext.setValue( pKey, pValue ); 728 } 729 // if printer has no InputSlot key simply ignore this setting 730 // (e.g. SGENPRT has no InputSlot) 731 } 732 733 // merge orientation if necessary 734 if( nSetDataFlags & SAL_JOBSET_ORIENTATION ) 735 aData.m_eOrientation = pJobSetup->meOrientation == ORIENTATION_LANDSCAPE ? orientation::Landscape : orientation::Portrait; 736 737 // merge duplex if necessary 738 if( nSetDataFlags & SAL_JOBSET_DUPLEXMODE ) 739 { 740 pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) ); 741 if( pKey ) 742 { 743 pValue = NULL; 744 switch( pJobSetup->meDuplexMode ) 745 { 746 case DUPLEX_OFF: 747 pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "None" ) ) ); 748 if( pValue == NULL ) 749 pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "SimplexNoTumble" ) ) ); 750 break; 751 case DUPLEX_SHORTEDGE: 752 pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "DuplexTumble" ) ) ); 753 break; 754 case DUPLEX_LONGEDGE: 755 pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "DuplexNoTumble" ) ) ); 756 break; 757 case DUPLEX_UNKNOWN: 758 default: 759 pValue = 0; 760 break; 761 } 762 if( ! pValue ) 763 pValue = pKey->getDefaultValue(); 764 aData.m_aContext.setValue( pKey, pValue ); 765 } 766 } 767 768 m_aJobData = aData; 769 copyJobDataToJobSetup( pJobSetup, aData ); 770 return sal_True; 771 } 772 773 return sal_False; 774 } 775 776 // ----------------------------------------------------------------------- 777 778 void PspSalInfoPrinter::GetPageInfo( 779 const ImplJobSetup* pJobSetup, 780 long& rOutWidth, long& rOutHeight, 781 long& rPageOffX, long& rPageOffY, 782 long& rPageWidth, long& rPageHeight ) 783 { 784 if( ! pJobSetup ) 785 return; 786 787 JobData aData; 788 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); 789 790 // get the selected page size 791 if( aData.m_pParser ) 792 { 793 794 String aPaper; 795 int width, height; 796 int left = 0, top = 0, right = 0, bottom = 0; 797 int nDPI = aData.m_aContext.getRenderResolution(); 798 799 800 if( aData.m_eOrientation == psp::orientation::Portrait ) 801 { 802 aData.m_aContext.getPageSize( aPaper, width, height ); 803 aData.m_pParser->getMargins( aPaper, left, right, top, bottom ); 804 } 805 else 806 { 807 aData.m_aContext.getPageSize( aPaper, height, width ); 808 aData.m_pParser->getMargins( aPaper, top, bottom, right, left ); 809 } 810 811 rPageWidth = width * nDPI / 72; 812 rPageHeight = height * nDPI / 72; 813 rPageOffX = left * nDPI / 72; 814 rPageOffY = top * nDPI / 72; 815 rOutWidth = ( width - left - right ) * nDPI / 72; 816 rOutHeight = ( height - top - bottom ) * nDPI / 72; 817 } 818 } 819 820 // ----------------------------------------------------------------------- 821 822 sal_uLong PspSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pJobSetup ) 823 { 824 if( ! pJobSetup ) 825 return 0; 826 827 JobData aData; 828 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); 829 830 const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ): NULL; 831 return pKey ? pKey->countValues() : 0; 832 } 833 834 // ----------------------------------------------------------------------- 835 836 String PspSalInfoPrinter::GetPaperBinName( const ImplJobSetup* pJobSetup, sal_uLong nPaperBin ) 837 { 838 JobData aData; 839 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); 840 841 String aRet; 842 if( aData.m_pParser ) 843 { 844 const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ): NULL; 845 if( ! pKey || nPaperBin >= (sal_uLong)pKey->countValues() ) 846 aRet = aData.m_pParser->getDefaultInputSlot(); 847 else 848 { 849 const PPDValue* pValue = pKey->getValue( nPaperBin ); 850 if( pValue ) 851 aRet = aData.m_pParser->translateOption( pKey->getKey(), pValue->m_aOption ); 852 } 853 } 854 855 return aRet; 856 } 857 858 // ----------------------------------------------------------------------- 859 860 sal_uLong PspSalInfoPrinter::GetCapabilities( const ImplJobSetup* pJobSetup, sal_uInt16 nType ) 861 { 862 switch( nType ) 863 { 864 case PRINTER_CAPABILITIES_SUPPORTDIALOG: 865 return 1; 866 case PRINTER_CAPABILITIES_COPIES: 867 return 0xffff; 868 case PRINTER_CAPABILITIES_COLLATECOPIES: 869 { 870 // see if the PPD contains a value to set Collate to True 871 JobData aData; 872 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); 873 874 const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ) ) : NULL; 875 const PPDValue* pVal = pKey ? pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "True" ) ) ) : NULL; 876 877 // PPDs don't mention the number of possible collated copies. 878 // so let's guess as many as we want ? 879 return pVal ? 0xffff : 0; 880 } 881 case PRINTER_CAPABILITIES_SETORIENTATION: 882 return 1; 883 case PRINTER_CAPABILITIES_SETDUPLEX: 884 return 1; 885 case PRINTER_CAPABILITIES_SETPAPERBIN: 886 return 1; 887 case PRINTER_CAPABILITIES_SETPAPERSIZE: 888 return 1; 889 case PRINTER_CAPABILITIES_SETPAPER: 890 return 0; 891 case PRINTER_CAPABILITIES_FAX: 892 return PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "fax" ) ? 1 : 0; 893 case PRINTER_CAPABILITIES_PDF: 894 if( PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "pdf" ) ) 895 return 1; 896 else 897 { 898 // see if the PPD contains a value to set Collate to True 899 JobData aData = PrinterInfoManager::get().getPrinterInfo( pJobSetup->maPrinterName ); 900 if( pJobSetup->mpDriverData ) 901 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); 902 return aData.m_nPDFDevice > 0 ? 1 : 0; 903 } 904 case PRINTER_CAPABILITIES_EXTERNALDIALOG: 905 return PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "external_dialog" ) ? 1 : 0; 906 case PRINTER_CAPABILITIES_USEPULLMODEL: 907 { 908 // see if the PPD contains a value to set Collate to True 909 JobData aData = PrinterInfoManager::get().getPrinterInfo( pJobSetup->maPrinterName ); 910 if( pJobSetup->mpDriverData ) 911 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); 912 return aData.m_nPDFDevice > 0 ? 1 : 0; 913 } 914 default: break; 915 }; 916 return 0; 917 } 918 919 // ======================================================================= 920 921 /* 922 * SalPrinter 923 */ 924 925 PspSalPrinter::PspSalPrinter( SalInfoPrinter* pInfoPrinter ) 926 : m_bFax( false ), 927 m_bPdf( false ), 928 m_bSwallowFaxNo( false ), 929 m_bIsPDFWriterJob( false ), 930 m_pGraphics( NULL ), 931 m_nCopies( 1 ), 932 m_bCollate( false ), 933 m_pInfoPrinter( pInfoPrinter ) 934 { 935 } 936 937 // ----------------------------------------------------------------------- 938 939 PspSalPrinter::~PspSalPrinter() 940 { 941 } 942 943 // ----------------------------------------------------------------------- 944 945 static String getTmpName() 946 { 947 rtl::OUString aTmp, aSys; 948 osl_createTempFile( NULL, NULL, &aTmp.pData ); 949 osl_getSystemPathFromFileURL( aTmp.pData, &aSys.pData ); 950 951 return aSys; 952 } 953 954 sal_Bool PspSalPrinter::StartJob( 955 const XubString* pFileName, 956 const XubString& rJobName, 957 const XubString& rAppName, 958 sal_uLong nCopies, 959 bool bCollate, 960 bool bDirect, 961 ImplJobSetup* pJobSetup ) 962 { 963 vcl_sal::PrinterUpdate::jobStarted(); 964 965 m_bFax = false; 966 m_bPdf = false; 967 m_aFileName = pFileName ? *pFileName : String(); 968 m_aTmpFile = String(); 969 m_nCopies = nCopies; 970 m_bCollate = bCollate; 971 972 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData ); 973 if( m_nCopies > 1 ) 974 { 975 // in case user did not do anything (m_nCopies=1) 976 // take the default from jobsetup 977 m_aJobData.m_nCopies = m_nCopies; 978 m_aJobData.setCollate( bCollate ); 979 } 980 981 // check wether this printer is configured as fax 982 int nMode = 0; 983 const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) ); 984 sal_Int32 nIndex = 0; 985 while( nIndex != -1 ) 986 { 987 OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) ); 988 if( ! aToken.compareToAscii( "fax", 3 ) ) 989 { 990 m_bFax = true; 991 m_aTmpFile = getTmpName(); 992 nMode = S_IRUSR | S_IWUSR; 993 994 ::std::hash_map< ::rtl::OUString, ::rtl::OUString, ::rtl::OUStringHash >::const_iterator it; 995 it = pJobSetup->maValueMap.find( ::rtl::OUString::createFromAscii( "FAX#" ) ); 996 if( it != pJobSetup->maValueMap.end() ) 997 m_aFaxNr = it->second; 998 999 sal_Int32 nPos = 0; 1000 m_bSwallowFaxNo = ! aToken.getToken( 1, '=', nPos ).compareToAscii( "swallow", 7 ) ? true : false; 1001 1002 break; 1003 } 1004 if( ! aToken.compareToAscii( "pdf=", 4 ) ) 1005 { 1006 m_bPdf = true; 1007 m_aTmpFile = getTmpName(); 1008 nMode = S_IRUSR | S_IWUSR; 1009 1010 if( ! m_aFileName.Len() ) 1011 { 1012 m_aFileName = getPdfDir( rInfo ); 1013 m_aFileName.Append( '/' ); 1014 m_aFileName.Append( rJobName ); 1015 m_aFileName.AppendAscii( ".pdf" ); 1016 } 1017 break; 1018 } 1019 } 1020 m_aPrinterGfx.Init( m_aJobData ); 1021 1022 // set/clear backwards compatibility flag 1023 bool bStrictSO52Compatibility = false; 1024 std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it = 1025 pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) ); 1026 1027 if( compat_it != pJobSetup->maValueMap.end() ) 1028 { 1029 if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) ) 1030 bStrictSO52Compatibility = true; 1031 } 1032 m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility ); 1033 1034 return m_aPrintJob.StartJob( m_aTmpFile.Len() ? m_aTmpFile : m_aFileName, nMode, rJobName, rAppName, m_aJobData, &m_aPrinterGfx, bDirect ) ? sal_True : sal_False; 1035 } 1036 1037 // ----------------------------------------------------------------------- 1038 1039 sal_Bool PspSalPrinter::EndJob() 1040 { 1041 sal_Bool bSuccess = sal_False; 1042 if( m_bIsPDFWriterJob ) 1043 bSuccess = sal_True; 1044 else 1045 { 1046 bSuccess = m_aPrintJob.EndJob(); 1047 1048 if( bSuccess ) 1049 { 1050 // check for fax 1051 if( m_bFax ) 1052 { 1053 1054 const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) ); 1055 // sendAFax removes the file after use 1056 bSuccess = sendAFax( m_aFaxNr, m_aTmpFile, rInfo.m_aCommand ); 1057 } 1058 else if( m_bPdf ) 1059 { 1060 const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) ); 1061 bSuccess = createPdf( m_aFileName, m_aTmpFile, rInfo.m_aCommand ); 1062 } 1063 } 1064 } 1065 vcl_sal::PrinterUpdate::jobEnded(); 1066 return bSuccess; 1067 } 1068 1069 // ----------------------------------------------------------------------- 1070 1071 sal_Bool PspSalPrinter::AbortJob() 1072 { 1073 sal_Bool bAbort = m_aPrintJob.AbortJob() ? sal_True : sal_False; 1074 vcl_sal::PrinterUpdate::jobEnded(); 1075 return bAbort; 1076 } 1077 1078 // ----------------------------------------------------------------------- 1079 1080 SalGraphics* PspSalPrinter::StartPage( ImplJobSetup* pJobSetup, sal_Bool ) 1081 { 1082 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData ); 1083 m_pGraphics = new PspGraphics( &m_aJobData, &m_aPrinterGfx, m_bFax ? &m_aFaxNr : NULL, m_bSwallowFaxNo, m_pInfoPrinter ); 1084 m_pGraphics->SetLayout( 0 ); 1085 if( m_nCopies > 1 ) 1086 { 1087 // in case user did not do anything (m_nCopies=1) 1088 // take the default from jobsetup 1089 m_aJobData.m_nCopies = m_nCopies; 1090 m_aJobData.setCollate( m_nCopies > 1 && m_bCollate ); 1091 } 1092 1093 m_aPrintJob.StartPage( m_aJobData ); 1094 m_aPrinterGfx.Init( m_aPrintJob ); 1095 1096 return m_pGraphics; 1097 } 1098 1099 // ----------------------------------------------------------------------- 1100 1101 sal_Bool PspSalPrinter::EndPage() 1102 { 1103 sal_Bool bResult = m_aPrintJob.EndPage(); 1104 m_aPrinterGfx.Clear(); 1105 return bResult ? sal_True : sal_False; 1106 } 1107 1108 // ----------------------------------------------------------------------- 1109 1110 sal_uLong PspSalPrinter::GetErrorCode() 1111 { 1112 return 0; 1113 } 1114 1115 // ----------------------------------------------------------------------- 1116 1117 struct PDFNewJobParameters 1118 { 1119 Size maPageSize; 1120 sal_uInt16 mnPaperBin; 1121 1122 PDFNewJobParameters( const Size& i_rSize = Size(), 1123 sal_uInt16 i_nPaperBin = 0xffff ) 1124 : maPageSize( i_rSize ), mnPaperBin( i_nPaperBin ) {} 1125 1126 bool operator!=(const PDFNewJobParameters& rComp ) const 1127 { 1128 Size aCompLSSize( rComp.maPageSize.Height(), rComp.maPageSize.Width() ); 1129 return 1130 (maPageSize != rComp.maPageSize && maPageSize != aCompLSSize) 1131 || mnPaperBin != rComp.mnPaperBin 1132 ; 1133 } 1134 1135 bool operator==(const PDFNewJobParameters& rComp) const 1136 { 1137 return ! this->operator!=(rComp); 1138 } 1139 }; 1140 1141 struct PDFPrintFile 1142 { 1143 rtl::OUString maTmpURL; 1144 PDFNewJobParameters maParameters; 1145 1146 PDFPrintFile( const rtl::OUString& i_rURL, const PDFNewJobParameters& i_rNewParameters ) 1147 : maTmpURL( i_rURL ) 1148 , maParameters( i_rNewParameters ) {} 1149 }; 1150 1151 sal_Bool PspSalPrinter::StartJob( const String* i_pFileName, const String& i_rJobName, const String& i_rAppName, 1152 ImplJobSetup* i_pSetupData, vcl::PrinterController& i_rController ) 1153 { 1154 OSL_TRACE( "StartJob with controller: pFilename = %s", i_pFileName ? rtl::OUStringToOString( *i_pFileName, RTL_TEXTENCODING_UTF8 ).getStr() : "<nil>" ); 1155 // mark for endjob 1156 m_bIsPDFWriterJob = true; 1157 // reset IsLastPage 1158 i_rController.setLastPage( sal_False ); 1159 1160 // update job data 1161 if( i_pSetupData ) 1162 JobData::constructFromStreamBuffer( i_pSetupData->mpDriverData, i_pSetupData->mnDriverDataLen, m_aJobData ); 1163 1164 OSL_ASSERT( m_aJobData.m_nPDFDevice > 0 ); 1165 m_aJobData.m_nPDFDevice = 1; 1166 1167 // possibly create one job for collated output 1168 sal_Bool bSinglePrintJobs = sal_False; 1169 beans::PropertyValue* pSingleValue = i_rController.getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintCollateAsSingleJobs" ) ) ); 1170 if( pSingleValue ) 1171 { 1172 pSingleValue->Value >>= bSinglePrintJobs; 1173 } 1174 1175 int nCopies = i_rController.getPrinter()->GetCopyCount(); 1176 bool bCollate = i_rController.getPrinter()->IsCollateCopy(); 1177 1178 // notify start of real print job 1179 i_rController.jobStarted(); 1180 1181 // setup PDFWriter context 1182 vcl::PDFWriter::PDFWriterContext aContext; 1183 aContext.Version = vcl::PDFWriter::PDF_1_4; 1184 aContext.Tagged = false; 1185 aContext.EmbedStandardFonts = true; 1186 aContext.DocumentLocale = Application::GetSettings().GetLocale(); 1187 aContext.ColorMode = i_rController.getPrinter()->GetPrinterOptions().IsConvertToGreyscales() 1188 ? vcl::PDFWriter::DrawGreyscale : vcl::PDFWriter::DrawColor; 1189 1190 // prepare doc info 1191 aContext.DocumentInfo.Title = i_rJobName; 1192 aContext.DocumentInfo.Creator = i_rAppName; 1193 aContext.DocumentInfo.Producer = i_rAppName; 1194 1195 // define how we handle metafiles in PDFWriter 1196 vcl::PDFWriter::PlayMetafileContext aMtfContext; 1197 aMtfContext.m_bOnlyLosslessCompression = true; 1198 1199 boost::shared_ptr<vcl::PDFWriter> pWriter; 1200 std::vector< PDFPrintFile > aPDFFiles; 1201 boost::shared_ptr<Printer> pPrinter( i_rController.getPrinter() ); 1202 int nAllPages = i_rController.getFilteredPageCount(); 1203 i_rController.createProgressDialog(); 1204 bool bAborted = false; 1205 PDFNewJobParameters aLastParm; 1206 1207 aContext.DPIx = pPrinter->ImplGetDPIX(); 1208 aContext.DPIy = pPrinter->ImplGetDPIY(); 1209 for( int nPage = 0; nPage < nAllPages && ! bAborted; nPage++ ) 1210 { 1211 if( nPage == nAllPages-1 ) 1212 i_rController.setLastPage( sal_True ); 1213 1214 // get the page's metafile 1215 GDIMetaFile aPageFile; 1216 vcl::PrinterController::PageSize aPageSize = i_rController.getFilteredPageFile( nPage, aPageFile ); 1217 if( i_rController.isProgressCanceled() ) 1218 { 1219 bAborted = true; 1220 if( nPage != nAllPages-1 ) 1221 { 1222 i_rController.createProgressDialog(); 1223 i_rController.setLastPage( sal_True ); 1224 i_rController.getFilteredPageFile( nPage, aPageFile ); 1225 } 1226 } 1227 else 1228 { 1229 pPrinter->SetMapMode( MapMode( MAP_100TH_MM ) ); 1230 pPrinter->SetPaperSizeUser( aPageSize.aSize, true ); 1231 PDFNewJobParameters aNewParm( pPrinter->GetPaperSize(), pPrinter->GetPaperBin() ); 1232 1233 // create PDF writer on demand 1234 // either on first page 1235 // or on paper format change - cups does not support multiple paper formats per job (yet?) 1236 // so we need to start a new job to get a new paper format from the printer 1237 // orientation switches (that is switch of height and width) is handled transparently by CUPS 1238 if( ! pWriter || 1239 (aNewParm != aLastParm && ! i_pFileName ) ) 1240 { 1241 if( pWriter ) 1242 { 1243 pWriter->Emit(); 1244 } 1245 // produce PDF file 1246 OUString aPDFUrl; 1247 if( i_pFileName ) 1248 aPDFUrl = *i_pFileName; 1249 else 1250 osl_createTempFile( NULL, NULL, &aPDFUrl.pData ); 1251 // normalize to file URL 1252 if( aPDFUrl.compareToAscii( "file:", 5 ) != 0 ) 1253 { 1254 // this is not a file URL, but it should 1255 // form it into a osl friendly file URL 1256 rtl::OUString aTmp; 1257 osl_getFileURLFromSystemPath( aPDFUrl.pData, &aTmp.pData ); 1258 aPDFUrl = aTmp; 1259 } 1260 // save current file and paper format 1261 aLastParm = aNewParm; 1262 aPDFFiles.push_back( PDFPrintFile( aPDFUrl, aNewParm ) ); 1263 // update context 1264 aContext.URL = aPDFUrl; 1265 1266 // create and initialize PDFWriter 1267 #if defined __SUNPRO_CC 1268 #pragma disable_warn 1269 #endif 1270 pWriter.reset( new vcl::PDFWriter( aContext, uno::Reference< beans::XMaterialHolder >() ) ); 1271 #if defined __SUNPRO_CC 1272 #pragma enable_warn 1273 #endif 1274 } 1275 1276 pWriter->NewPage( TenMuToPt( aNewParm.maPageSize.Width() ), 1277 TenMuToPt( aNewParm.maPageSize.Height() ), 1278 vcl::PDFWriter::Portrait ); 1279 1280 pWriter->PlayMetafile( aPageFile, aMtfContext, NULL ); 1281 } 1282 } 1283 1284 // emit the last file 1285 if( pWriter ) 1286 pWriter->Emit(); 1287 1288 // handle collate, copy count and multiple jobs correctly 1289 int nOuterJobs = 1; 1290 if( bSinglePrintJobs ) 1291 { 1292 nOuterJobs = nCopies; 1293 m_aJobData.m_nCopies = 1; 1294 } 1295 else 1296 { 1297 if( bCollate ) 1298 { 1299 if( aPDFFiles.size() == 1 && pPrinter->HasSupport( SUPPORT_COLLATECOPY ) ) 1300 { 1301 m_aJobData.setCollate( true ); 1302 m_aJobData.m_nCopies = nCopies; 1303 } 1304 else 1305 { 1306 nOuterJobs = nCopies; 1307 m_aJobData.m_nCopies = 1; 1308 } 1309 } 1310 else 1311 { 1312 m_aJobData.setCollate( false ); 1313 m_aJobData.m_nCopies = nCopies; 1314 } 1315 } 1316 1317 // spool files 1318 if( ! i_pFileName && ! bAborted ) 1319 { 1320 bool bFirstJob = true; 1321 for( int nCurJob = 0; nCurJob < nOuterJobs; nCurJob++ ) 1322 { 1323 for( size_t i = 0; i < aPDFFiles.size(); i++ ) 1324 { 1325 oslFileHandle pFile = NULL; 1326 osl_openFile( aPDFFiles[i].maTmpURL.pData, &pFile, osl_File_OpenFlag_Read ); 1327 if( pFile ) 1328 { 1329 osl_setFilePos( pFile, osl_Pos_Absolut, 0 ); 1330 std::vector< char > buffer( 0x10000, 0 ); 1331 // update job data with current page size 1332 Size aPageSize( aPDFFiles[i].maParameters.maPageSize ); 1333 m_aJobData.setPaper( TenMuToPt( aPageSize.Width() ), TenMuToPt( aPageSize.Height() ) ); 1334 // update job data with current paperbin 1335 m_aJobData.setPaperBin( aPDFFiles[i].maParameters.mnPaperBin ); 1336 1337 // spool current file 1338 FILE* fp = PrinterInfoManager::get().startSpool( pPrinter->GetName(), i_rController.isDirectPrint() ); 1339 if( fp ) 1340 { 1341 sal_uInt64 nBytesRead = 0; 1342 do 1343 { 1344 osl_readFile( pFile, &buffer[0], buffer.size(), &nBytesRead ); 1345 if( nBytesRead > 0 ) 1346 fwrite( &buffer[0], 1, nBytesRead, fp ); 1347 } while( nBytesRead == buffer.size() ); 1348 rtl::OUStringBuffer aBuf( i_rJobName.Len() + 8 ); 1349 aBuf.append( i_rJobName ); 1350 if( i > 0 || nCurJob > 0 ) 1351 { 1352 aBuf.append( sal_Unicode(' ') ); 1353 aBuf.append( sal_Int32( i + nCurJob * aPDFFiles.size() ) ); 1354 } 1355 PrinterInfoManager::get().endSpool( pPrinter->GetName(), aBuf.makeStringAndClear(), fp, m_aJobData, bFirstJob ); 1356 bFirstJob = false; 1357 } 1358 } 1359 osl_closeFile( pFile ); 1360 } 1361 } 1362 } 1363 1364 // job has been spooled 1365 i_rController.setJobState( bAborted ? view::PrintableState_JOB_ABORTED : view::PrintableState_JOB_SPOOLED ); 1366 1367 // clean up the temporary PDF files 1368 if( ! i_pFileName || bAborted ) 1369 { 1370 for( size_t i = 0; i < aPDFFiles.size(); i++ ) 1371 { 1372 osl_removeFile( aPDFFiles[i].maTmpURL.pData ); 1373 OSL_TRACE( "removed print PDF file %s\n", rtl::OUStringToOString( aPDFFiles[i].maTmpURL, RTL_TEXTENCODING_UTF8 ).getStr() ); 1374 } 1375 } 1376 1377 return sal_True; 1378 } 1379 1380 1381 1382 /* 1383 * vcl::PrinterUpdate 1384 */ 1385 1386 Timer* vcl_sal::PrinterUpdate::pPrinterUpdateTimer = NULL; 1387 int vcl_sal::PrinterUpdate::nActiveJobs = 0; 1388 1389 void vcl_sal::PrinterUpdate::doUpdate() 1390 { 1391 ::psp::PrinterInfoManager& rManager( ::psp::PrinterInfoManager::get() ); 1392 if( rManager.checkPrintersChanged( false ) ) 1393 { 1394 SalDisplay* pDisp = GetX11SalData()->GetDisplay(); 1395 const std::list< SalFrame* >& rList = pDisp->getFrames(); 1396 for( std::list< SalFrame* >::const_iterator it = rList.begin(); 1397 it != rList.end(); ++it ) 1398 pDisp->SendInternalEvent( *it, NULL, SALEVENT_PRINTERCHANGED ); 1399 } 1400 } 1401 1402 // ----------------------------------------------------------------------- 1403 1404 IMPL_STATIC_LINK_NOINSTANCE( vcl_sal::PrinterUpdate, UpdateTimerHdl, void*, EMPTYARG ) 1405 { 1406 if( nActiveJobs < 1 ) 1407 { 1408 doUpdate(); 1409 delete pPrinterUpdateTimer; 1410 pPrinterUpdateTimer = NULL; 1411 } 1412 else 1413 pPrinterUpdateTimer->Start(); 1414 1415 return 0; 1416 } 1417 1418 // ----------------------------------------------------------------------- 1419 1420 void vcl_sal::PrinterUpdate::update() 1421 { 1422 if( Application::GetSettings().GetMiscSettings().GetDisablePrinting() ) 1423 return; 1424 1425 if( ! static_cast< X11SalInstance* >(GetSalData()->m_pInstance)->isPrinterInit() ) 1426 { 1427 // #i45389# start background printer detection 1428 psp::PrinterInfoManager::get(); 1429 return; 1430 } 1431 1432 if( nActiveJobs < 1 ) 1433 doUpdate(); 1434 else if( ! pPrinterUpdateTimer ) 1435 { 1436 pPrinterUpdateTimer = new Timer(); 1437 pPrinterUpdateTimer->SetTimeout( 500 ); 1438 pPrinterUpdateTimer->SetTimeoutHdl( STATIC_LINK( NULL, vcl_sal::PrinterUpdate, UpdateTimerHdl ) ); 1439 pPrinterUpdateTimer->Start(); 1440 } 1441 } 1442 1443 // ----------------------------------------------------------------------- 1444 1445 void vcl_sal::PrinterUpdate::jobEnded() 1446 { 1447 nActiveJobs--; 1448 if( nActiveJobs < 1 ) 1449 { 1450 if( pPrinterUpdateTimer ) 1451 { 1452 pPrinterUpdateTimer->Stop(); 1453 delete pPrinterUpdateTimer; 1454 pPrinterUpdateTimer = NULL; 1455 doUpdate(); 1456 } 1457 } 1458 } 1459