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