Bump version to 4.1-6
[LibreOffice.git] / vcl / generic / print / genprnpsp.cxx
blob9ffb69cdcaa3c7dc50249369f5bb840c263cf90c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 /**
22 this file implements the sal printer interface ( SalPrinter, SalInfoPrinter
23 and some printer relevant methods of SalInstance and SalGraphicsData )
25 as aunderlying library the printer features of psprint are used.
27 The query methods of a SalInfoPrinter are implemented by querying psprint
29 The job methods of a SalPrinter are implemented by calling psprint
30 printer job functions.
33 // For spawning PDF and FAX generation
34 #if defined( UNX )
35 # include <unistd.h>
36 # include <sys/wait.h>
37 # include <sys/stat.h>
38 #endif
40 #include "rtl/ustring.hxx"
42 #include "osl/module.h"
44 #include "vcl/svapp.hxx"
45 #include "vcl/print.hxx"
46 #include "vcl/pdfwriter.hxx"
47 #include "vcl/printerinfomanager.hxx"
49 #include "saldatabasic.hxx"
50 #include "generic/genprn.h"
51 #include "generic/geninst.h"
52 #include "generic/genpspgraphics.h"
54 #include "jobset.h"
55 #include "print.h"
56 #include "salptype.hxx"
58 #include <com/sun/star/beans/PropertyValue.hpp>
60 using namespace psp;
61 using namespace com::sun::star;
65 * static helpers
68 #if defined( UNX ) && !( defined( MACOSX ) || defined( IOS ) || defined( ANDROID ) )
69 static oslModule driverLib = NULL;
70 #endif
71 extern "C"
73 typedef int(*setupFunction)(PrinterInfo&);
74 static setupFunction pSetupFunction = NULL;
75 typedef int(*faxFunction)(OUString&);
76 static faxFunction pFaxNrFunction = NULL;
79 static OUString getPdfDir( const PrinterInfo& rInfo )
81 OUString aDir;
82 sal_Int32 nIndex = 0;
83 while( nIndex != -1 )
85 OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
86 if( aToken.startsWith( "pdf=" ) )
88 sal_Int32 nPos = 0;
89 aDir = aToken.getToken( 1, '=', nPos );
90 if( aDir.isEmpty() && getenv( "HOME" ) )
91 aDir = OUString( getenv( "HOME" ), strlen( getenv( "HOME" ) ), osl_getThreadTextEncoding() );
92 break;
95 return aDir;
98 static void getPaLib()
100 #if defined( UNX ) && !( defined( MACOSX ) || defined( IOS ) || defined( ANDROID ) )
101 if( ! driverLib )
103 driverLib = osl_loadModuleRelativeAscii( (oslGenericFunction)getPaLib,
104 _XSALSET_LIBNAME,
105 SAL_LOADMODULE_DEFAULT );
106 if ( !driverLib )
107 return;
109 pSetupFunction = (setupFunction)osl_getAsciiFunctionSymbol( driverLib, "Sal_SetupPrinterDriver" );
110 if ( !pSetupFunction )
111 fprintf( stderr, "could not resolve Sal_SetupPrinterDriver\n" );
113 pFaxNrFunction = (faxFunction)osl_getAsciiFunctionSymbol( driverLib, "Sal_queryFaxNumber" );
114 if ( !pFaxNrFunction )
115 fprintf( stderr, "could not resolve Sal_queryFaxNumber\n" );
117 #endif
120 inline int PtTo10Mu( int nPoints ) { return (int)((((double)nPoints)*35.27777778)+0.5); }
122 inline int TenMuToPt( int nUnits ) { return (int)((((double)nUnits)/35.27777778)+0.5); }
124 static void copyJobDataToJobSetup( ImplJobSetup* pJobSetup, JobData& rData )
126 pJobSetup->meOrientation = (Orientation)(rData.m_eOrientation == orientation::Landscape ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT);
128 // copy page size
129 OUString aPaper;
130 int width, height;
132 rData.m_aContext.getPageSize( aPaper, width, height );
133 pJobSetup->mePaperFormat = PaperInfo::fromPSName(OUStringToOString( aPaper, RTL_TEXTENCODING_ISO_8859_1 ));
135 pJobSetup->mnPaperWidth = 0;
136 pJobSetup->mnPaperHeight = 0;
137 if( pJobSetup->mePaperFormat == PAPER_USER )
139 // transform to 100dth mm
140 width = PtTo10Mu( width );
141 height = PtTo10Mu( height );
143 if( rData.m_eOrientation == psp::orientation::Portrait )
145 pJobSetup->mnPaperWidth = width;
146 pJobSetup->mnPaperHeight= height;
148 else
150 pJobSetup->mnPaperWidth = height;
151 pJobSetup->mnPaperHeight= width;
155 // copy input slot
156 const PPDKey* pKey = NULL;
157 const PPDValue* pValue = NULL;
159 pJobSetup->mnPaperBin = 0;
160 if( rData.m_pParser )
161 pKey = rData.m_pParser->getKey( OUString("InputSlot") );
162 if( pKey )
163 pValue = rData.m_aContext.getValue( pKey );
164 if( pKey && pValue )
166 for( pJobSetup->mnPaperBin = 0;
167 pValue != pKey->getValue( pJobSetup->mnPaperBin ) &&
168 pJobSetup->mnPaperBin < pKey->countValues();
169 pJobSetup->mnPaperBin++ )
171 if( pJobSetup->mnPaperBin >= pKey->countValues() )
172 pJobSetup->mnPaperBin = 0;
175 // copy duplex
176 pKey = NULL;
177 pValue = NULL;
179 pJobSetup->meDuplexMode = DUPLEX_UNKNOWN;
180 if( rData.m_pParser )
181 pKey = rData.m_pParser->getKey( OUString("Duplex") );
182 if( pKey )
183 pValue = rData.m_aContext.getValue( pKey );
184 if( pKey && pValue )
186 if( pValue->m_aOption.EqualsIgnoreCaseAscii( "None" ) ||
187 pValue->m_aOption.EqualsIgnoreCaseAscii( "Simplex", 0, 7 )
190 pJobSetup->meDuplexMode = DUPLEX_OFF;
192 else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexNoTumble" ) )
194 pJobSetup->meDuplexMode = DUPLEX_LONGEDGE;
196 else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexTumble" ) )
198 pJobSetup->meDuplexMode = DUPLEX_SHORTEDGE;
202 // copy the whole context
203 if( pJobSetup->mpDriverData )
204 rtl_freeMemory( pJobSetup->mpDriverData );
206 int nBytes;
207 void* pBuffer = NULL;
208 if( rData.getStreamBuffer( pBuffer, nBytes ) )
210 pJobSetup->mnDriverDataLen = nBytes;
211 pJobSetup->mpDriverData = (sal_uInt8*)pBuffer;
213 else
215 pJobSetup->mnDriverDataLen = 0;
216 pJobSetup->mpDriverData = NULL;
220 // Needs a cleaner abstraction ...
221 #if defined( UNX )
222 static bool passFileToCommandLine( const OUString& rFilename, const OUString& rCommandLine, bool bRemoveFile = true )
224 bool bSuccess = false;
226 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
227 OString aCmdLine(OUStringToOString(rCommandLine, aEncoding));
228 OString aFilename(OUStringToOString(rFilename, aEncoding));
230 bool bPipe = aCmdLine.indexOf( "(TMP)" ) != -1 ? false : true;
232 // setup command line for exec
233 if( ! bPipe )
234 aCmdLine = aCmdLine.replaceAll(OString("(TMP)"), aFilename);
236 #if OSL_DEBUG_LEVEL > 1
237 fprintf( stderr, "%s commandline: \"%s\"\n",
238 bPipe ? "piping to" : "executing",
239 aCmdLine.getStr() );
240 struct stat aStat;
241 if( stat( aFilename.getStr(), &aStat ) )
242 fprintf( stderr, "stat( %s ) failed\n", aFilename.getStr() );
243 fprintf( stderr, "Tmp file %s has modes: 0%03lo\n", aFilename.getStr(), (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.getStr();
250 argv[ 3 ] = 0;
252 bool bHavePipes = false;
253 int pid, fd[2];
255 if( bPipe )
256 bHavePipes = pipe( fd ) ? false : true;
257 if( ( pid = fork() ) > 0 )
259 if( bPipe && bHavePipes )
261 close( fd[0] );
262 char aBuffer[ 2048 ];
263 FILE* fp = fopen( aFilename.getStr(), "r" );
264 while (fp && !feof(fp))
266 size_t nBytesRead = fread(aBuffer, 1, sizeof( aBuffer ), fp);
267 if (nBytesRead )
269 size_t nBytesWritten = write(fd[1], aBuffer, nBytesRead);
270 OSL_ENSURE(nBytesWritten == nBytesRead, "short write");
271 if (nBytesWritten != nBytesRead)
272 break;
275 fclose( fp );
276 close( fd[ 1 ] );
278 int status = 0;
279 waitpid( pid, &status, 0 );
280 if( ! status )
281 bSuccess = true;
283 else if( ! pid )
285 if( bPipe && bHavePipes )
287 close( fd[1] );
288 if( fd[0] != STDIN_FILENO ) // not probable, but who knows :)
289 dup2( fd[0], STDIN_FILENO );
291 execv( argv[0], const_cast<char**>(argv) );
292 fprintf( stderr, "failed to execute \"%s\"\n", aCmdLine.getStr() );
293 _exit( 1 );
295 else
296 fprintf( stderr, "failed to fork\n" );
298 // clean up the mess
299 if( bRemoveFile )
300 unlink( aFilename.getStr() );
302 return bSuccess;
304 #endif
306 static bool sendAFax( const OUString& rFaxNumber, const OUString& rFileName, const OUString& rCommand )
308 #if defined( UNX )
309 std::list< OUString > aFaxNumbers;
311 if( rFaxNumber.isEmpty() )
313 getPaLib();
314 if( pFaxNrFunction )
316 OUString aNewNr;
317 if( pFaxNrFunction( aNewNr ) )
318 aFaxNumbers.push_back( aNewNr );
321 else
323 sal_Int32 nIndex = 0;
324 OUString aFaxes( rFaxNumber );
325 OUString aBeginToken( "<Fax#>" );
326 OUString aEndToken( "</Fax#>" );
327 while( nIndex != -1 )
329 nIndex = aFaxes.indexOf( aBeginToken, nIndex );
330 if( nIndex != -1 )
332 sal_Int32 nBegin = nIndex + aBeginToken.getLength();
333 nIndex = aFaxes.indexOf( aEndToken, nIndex );
334 if( nIndex != -1 )
336 aFaxNumbers.push_back( aFaxes.copy( nBegin, nIndex-nBegin ) );
337 nIndex += aEndToken.getLength();
343 bool bSuccess = true;
344 if( aFaxNumbers.begin() != aFaxNumbers.end() )
346 while( aFaxNumbers.begin() != aFaxNumbers.end() && bSuccess )
348 OUString aFaxNumber( aFaxNumbers.front() );
349 aFaxNumbers.pop_front();
350 OUString aCmdLine(
351 rCommand.replaceAll("(PHONE)", aFaxNumber));
352 #if OSL_DEBUG_LEVEL > 1
353 fprintf( stderr, "sending fax to \"%s\"\n", OUStringToOString( aFaxNumber, osl_getThreadTextEncoding() ).getStr() );
354 #endif
355 bSuccess = passFileToCommandLine( rFileName, aCmdLine, false );
358 else
359 bSuccess = false;
361 // clean up temp file
362 unlink(OUStringToOString(rFileName, osl_getThreadTextEncoding()).getStr());
364 return bSuccess;
365 #else
366 (void)rFaxNumber; (void)rFileName; (void)rCommand;
367 return false;
368 #endif
371 static bool createPdf( const OUString& rToFile, const OUString& rFromFile, const OUString& rCommandLine )
373 #if defined( UNX )
374 OUString aCommandLine(
375 rCommandLine.replaceAll("(OUTFILE)", rToFile));
377 return passFileToCommandLine( rFromFile, aCommandLine );
378 #else
379 (void)rToFile; (void)rFromFile; (void)rCommandLine;
380 return false;
381 #endif
385 * SalInstance
388 void SalGenericInstance::configurePspInfoPrinter(PspSalInfoPrinter *pPrinter,
389 SalPrinterQueueInfo* pQueueInfo, ImplJobSetup* pJobSetup)
391 if( pJobSetup )
393 PrinterInfoManager& rManager( PrinterInfoManager::get() );
394 PrinterInfo aInfo( rManager.getPrinterInfo( pQueueInfo->maPrinterName ) );
395 pPrinter->m_aJobData = aInfo;
396 pPrinter->m_aPrinterGfx.Init( pPrinter->m_aJobData );
398 if( pJobSetup->mpDriverData )
399 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo );
401 pJobSetup->mnSystem = JOBSETUP_SYSTEM_UNIX;
402 pJobSetup->maPrinterName = pQueueInfo->maPrinterName;
403 pJobSetup->maDriver = aInfo.m_aDriverName;
404 copyJobDataToJobSetup( pJobSetup, aInfo );
408 SalInfoPrinter* SalGenericInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
409 ImplJobSetup* pJobSetup )
411 mbPrinterInit = true;
412 // create and initialize SalInfoPrinter
413 PspSalInfoPrinter* pPrinter = new PspSalInfoPrinter();
414 configurePspInfoPrinter(pPrinter, pQueueInfo, pJobSetup);
415 return pPrinter;
418 void SalGenericInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
420 delete pPrinter;
423 SalPrinter* SalGenericInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
425 mbPrinterInit = true;
426 // create and initialize SalPrinter
427 PspSalPrinter* pPrinter = new PspSalPrinter( pInfoPrinter );
428 pPrinter->m_aJobData = static_cast<PspSalInfoPrinter*>(pInfoPrinter)->m_aJobData;
430 return pPrinter;
433 void SalGenericInstance::DestroyPrinter( SalPrinter* pPrinter )
435 delete pPrinter;
438 void SalGenericInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
440 mbPrinterInit = true;
441 PrinterInfoManager& rManager( PrinterInfoManager::get() );
442 static const char* pNoSyncDetection = getenv( "SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION" );
443 if( ! pNoSyncDetection || ! *pNoSyncDetection )
445 // #i62663# synchronize possible asynchronouse printer detection now
446 rManager.checkPrintersChanged( true );
448 ::std::list< OUString > aPrinters;
449 rManager.listPrinters( aPrinters );
451 for( ::std::list< OUString >::iterator it = aPrinters.begin(); it != aPrinters.end(); ++it )
453 const PrinterInfo& rInfo( rManager.getPrinterInfo( *it ) );
454 // Neuen Eintrag anlegen
455 SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
456 pInfo->maPrinterName = *it;
457 pInfo->maDriver = rInfo.m_aDriverName;
458 pInfo->maLocation = rInfo.m_aLocation;
459 pInfo->maComment = rInfo.m_aComment;
460 pInfo->mpSysData = NULL;
462 sal_Int32 nIndex = 0;
463 while( nIndex != -1 )
465 OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
466 if( aToken.match( "pdf=" ) )
468 pInfo->maLocation = getPdfDir( rInfo );
469 break;
473 pList->Add( pInfo );
477 void SalGenericInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo )
479 delete pInfo;
482 void SalGenericInstance::GetPrinterQueueState( SalPrinterQueueInfo* )
484 mbPrinterInit = true;
487 OUString SalGenericInstance::GetDefaultPrinter()
489 mbPrinterInit = true;
490 PrinterInfoManager& rManager( PrinterInfoManager::get() );
491 return rManager.getDefaultPrinter();
494 PspSalInfoPrinter::PspSalInfoPrinter()
495 : m_pGraphics( NULL )
499 PspSalInfoPrinter::~PspSalInfoPrinter()
501 if( m_pGraphics )
503 delete m_pGraphics;
504 m_pGraphics = NULL;
508 void PspSalInfoPrinter::InitPaperFormats( const ImplJobSetup* )
510 m_aPaperFormats.clear();
511 m_bPapersInit = true;
513 if( m_aJobData.m_pParser )
515 const PPDKey* pKey = m_aJobData.m_pParser->getKey( OUString("PageSize") );
516 if( pKey )
518 int nValues = pKey->countValues();
519 for( int i = 0; i < nValues; i++ )
521 const PPDValue* pValue = pKey->getValue( i );
522 int nWidth = 0, nHeight = 0;
523 m_aJobData.m_pParser->getPaperDimension( pValue->m_aOption, nWidth, nHeight );
524 PaperInfo aInfo(PtTo10Mu( nWidth ), PtTo10Mu( nHeight ));
525 m_aPaperFormats.push_back( aInfo );
531 int PspSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* )
533 return 900;
536 SalGraphics* PspSalInfoPrinter::GetGraphics()
538 // return a valid pointer only once
539 // the reasoning behind this is that we could have different
540 // SalGraphics that can run in multiple threads
541 // (future plans)
542 SalGraphics* pRet = NULL;
543 if( ! m_pGraphics )
545 m_pGraphics = GetGenericInstance()->CreatePrintGraphics();
546 m_pGraphics->Init( &m_aJobData, &m_aPrinterGfx, NULL, false, this );
547 pRet = m_pGraphics;
549 return pRet;
552 void PspSalInfoPrinter::ReleaseGraphics( SalGraphics* pGraphics )
554 if( pGraphics == m_pGraphics )
556 delete pGraphics;
557 m_pGraphics = NULL;
559 return;
562 sal_Bool PspSalInfoPrinter::Setup( SalFrame* pFrame, ImplJobSetup* pJobSetup )
564 if( ! pFrame || ! pJobSetup )
565 return sal_False;
567 getPaLib();
569 if( ! pSetupFunction )
570 return sal_False;
572 PrinterInfoManager& rManager = PrinterInfoManager::get();
574 PrinterInfo aInfo( rManager.getPrinterInfo( pJobSetup->maPrinterName ) );
575 if ( pJobSetup->mpDriverData )
577 SetData( ~0, pJobSetup );
578 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo );
581 if( pSetupFunction( aInfo ) )
583 aInfo.resolveDefaultBackend();
584 rtl_freeMemory( pJobSetup->mpDriverData );
585 pJobSetup->mpDriverData = NULL;
587 int nBytes;
588 void* pBuffer = NULL;
589 aInfo.getStreamBuffer( pBuffer, nBytes );
590 pJobSetup->mnDriverDataLen = nBytes;
591 pJobSetup->mpDriverData = (sal_uInt8*)pBuffer;
593 // copy everything to job setup
594 copyJobDataToJobSetup( pJobSetup, aInfo );
595 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
596 return sal_True;
598 return sal_False;
601 // This function gets the driver data and puts it into pJobSetup
602 // If pJobSetup->mpDriverData is NOT NULL, then the independend
603 // data should be merged into the driver data
604 // If pJobSetup->mpDriverData IS NULL, then the driver defaults
605 // should be merged into the independent data
606 sal_Bool PspSalInfoPrinter::SetPrinterData( ImplJobSetup* pJobSetup )
608 if( pJobSetup->mpDriverData )
609 return SetData( ~0, pJobSetup );
611 copyJobDataToJobSetup( pJobSetup, m_aJobData );
613 return sal_True;
616 // This function merges the independ driver data
617 // and sets the new independ data in pJobSetup
618 // Only the data must be changed, where the bit
619 // in nGetDataFlags is set
620 sal_Bool PspSalInfoPrinter::SetData(
621 sal_uLong nSetDataFlags,
622 ImplJobSetup* pJobSetup )
624 JobData aData;
625 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
627 if( aData.m_pParser )
629 const PPDKey* pKey;
630 const PPDValue* pValue;
632 // merge papersize if necessary
633 if( nSetDataFlags & SAL_JOBSET_PAPERSIZE )
635 OUString aPaper;
637 if( pJobSetup->mePaperFormat == PAPER_USER )
638 aPaper = aData.m_pParser->matchPaper(
639 TenMuToPt( pJobSetup->mnPaperWidth ),
640 TenMuToPt( pJobSetup->mnPaperHeight ) );
641 else
642 aPaper = OStringToOUString(PaperInfo::toPSName(pJobSetup->mePaperFormat), RTL_TEXTENCODING_ISO_8859_1);
644 pKey = aData.m_pParser->getKey( OUString("PageSize") );
645 pValue = pKey ? pKey->getValueCaseInsensitive( aPaper ) : NULL;
647 // some PPD files do not specify the standard paper names (e.g. C5 instead of EnvC5)
648 // try to find the correct paper anyway using the size
649 if( pKey && ! pValue && pJobSetup->mePaperFormat != PAPER_USER )
651 PaperInfo aInfo( pJobSetup->mePaperFormat );
652 aPaper = aData.m_pParser->matchPaper(
653 TenMuToPt( aInfo.getWidth() ),
654 TenMuToPt( aInfo.getHeight() ) );
655 pValue = pKey->getValueCaseInsensitive( aPaper );
658 if( ! ( pKey && pValue && aData.m_aContext.setValue( pKey, pValue, false ) == pValue ) )
659 return sal_False;
662 // merge paperbin if necessary
663 if( nSetDataFlags & SAL_JOBSET_PAPERBIN )
665 pKey = aData.m_pParser->getKey( OUString("InputSlot") );
666 if( pKey )
668 int nPaperBin = pJobSetup->mnPaperBin;
669 if( nPaperBin >= pKey->countValues() )
670 pValue = pKey->getDefaultValue();
671 else
672 pValue = pKey->getValue( pJobSetup->mnPaperBin );
674 // may fail due to constraints;
675 // real paper bin is copied back to jobsetup in that case
676 aData.m_aContext.setValue( pKey, pValue );
678 // if printer has no InputSlot key simply ignore this setting
679 // (e.g. SGENPRT has no InputSlot)
682 // merge orientation if necessary
683 if( nSetDataFlags & SAL_JOBSET_ORIENTATION )
684 aData.m_eOrientation = pJobSetup->meOrientation == ORIENTATION_LANDSCAPE ? orientation::Landscape : orientation::Portrait;
686 // merge duplex if necessary
687 if( nSetDataFlags & SAL_JOBSET_DUPLEXMODE )
689 pKey = aData.m_pParser->getKey( OUString("Duplex") );
690 if( pKey )
692 pValue = NULL;
693 switch( pJobSetup->meDuplexMode )
695 case DUPLEX_OFF:
696 pValue = pKey->getValue( OUString("None") );
697 if( pValue == NULL )
698 pValue = pKey->getValue( OUString("SimplexNoTumble") );
699 break;
700 case DUPLEX_SHORTEDGE:
701 pValue = pKey->getValue( OUString("DuplexTumble") );
702 break;
703 case DUPLEX_LONGEDGE:
704 pValue = pKey->getValue( OUString("DuplexNoTumble") );
705 break;
706 case DUPLEX_UNKNOWN:
707 default:
708 pValue = 0;
709 break;
711 if( ! pValue )
712 pValue = pKey->getDefaultValue();
713 aData.m_aContext.setValue( pKey, pValue );
717 m_aJobData = aData;
718 copyJobDataToJobSetup( pJobSetup, aData );
719 return sal_True;
722 return sal_False;
725 void PspSalInfoPrinter::GetPageInfo(
726 const ImplJobSetup* pJobSetup,
727 long& rOutWidth, long& rOutHeight,
728 long& rPageOffX, long& rPageOffY,
729 long& rPageWidth, long& rPageHeight )
731 if( ! pJobSetup )
732 return;
734 JobData aData;
735 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
737 // get the selected page size
738 if( aData.m_pParser )
741 OUString aPaper;
742 int width, height;
743 int left = 0, top = 0, right = 0, bottom = 0;
744 int nDPI = aData.m_aContext.getRenderResolution();
747 if( aData.m_eOrientation == psp::orientation::Portrait )
749 aData.m_aContext.getPageSize( aPaper, width, height );
750 aData.m_pParser->getMargins( aPaper, left, right, top, bottom );
752 else
754 aData.m_aContext.getPageSize( aPaper, height, width );
755 aData.m_pParser->getMargins( aPaper, top, bottom, right, left );
758 rPageWidth = width * nDPI / 72;
759 rPageHeight = height * nDPI / 72;
760 rPageOffX = left * nDPI / 72;
761 rPageOffY = top * nDPI / 72;
762 rOutWidth = ( width - left - right ) * nDPI / 72;
763 rOutHeight = ( height - top - bottom ) * nDPI / 72;
767 sal_uLong PspSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pJobSetup )
769 if( ! pJobSetup )
770 return 0;
772 JobData aData;
773 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
775 const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( OUString("InputSlot") ): NULL;
776 return pKey ? pKey->countValues() : 0;
779 OUString PspSalInfoPrinter::GetPaperBinName( const ImplJobSetup* pJobSetup, sal_uLong nPaperBin )
781 JobData aData;
782 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
784 OUString aRet;
785 if( aData.m_pParser )
787 const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( OUString("InputSlot") ): NULL;
788 if( ! pKey || nPaperBin >= (sal_uLong)pKey->countValues() )
789 aRet = aData.m_pParser->getDefaultInputSlot();
790 else
792 const PPDValue* pValue = pKey->getValue( nPaperBin );
793 if( pValue )
794 aRet = aData.m_pParser->translateOption( pKey->getKey(), pValue->m_aOption );
798 return aRet;
801 sal_uLong PspSalInfoPrinter::GetCapabilities( const ImplJobSetup* pJobSetup, sal_uInt16 nType )
803 switch( nType )
805 case PRINTER_CAPABILITIES_SUPPORTDIALOG:
806 return 1;
807 case PRINTER_CAPABILITIES_COPIES:
808 return 0xffff;
809 case PRINTER_CAPABILITIES_COLLATECOPIES:
811 // see if the PPD contains a value to set Collate to True
812 JobData aData;
813 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
815 const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( OUString("Collate") ) : NULL;
816 const PPDValue* pVal = pKey ? pKey->getValue(OUString("True")) : NULL;
818 // PPDs don't mention the number of possible collated copies.
819 // so let's guess as many as we want ?
820 return pVal ? 0xffff : 0;
822 case PRINTER_CAPABILITIES_SETORIENTATION:
823 return 1;
824 case PRINTER_CAPABILITIES_SETDUPLEX:
825 return 1;
826 case PRINTER_CAPABILITIES_SETPAPERBIN:
827 return 1;
828 case PRINTER_CAPABILITIES_SETPAPERSIZE:
829 return 1;
830 case PRINTER_CAPABILITIES_SETPAPER:
831 return 0;
832 case PRINTER_CAPABILITIES_FAX:
833 return PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "fax" ) ? 1 : 0;
834 case PRINTER_CAPABILITIES_PDF:
835 if( PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "pdf" ) )
836 return 1;
837 else
839 // see if the PPD contains a value to set Collate to True
840 JobData aData = PrinterInfoManager::get().getPrinterInfo( pJobSetup->maPrinterName );
841 if( pJobSetup->mpDriverData )
842 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
843 return aData.m_nPDFDevice > 0 ? 1 : 0;
845 case PRINTER_CAPABILITIES_EXTERNALDIALOG:
846 return PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "external_dialog" ) ? 1 : 0;
847 case PRINTER_CAPABILITIES_USEPULLMODEL:
849 // see if the PPD contains a value to set Collate to True
850 JobData aData = PrinterInfoManager::get().getPrinterInfo( pJobSetup->maPrinterName );
851 if( pJobSetup->mpDriverData )
852 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
853 return aData.m_nPDFDevice > 0 ? 1 : 0;
855 default: break;
857 return 0;
861 * SalPrinter
863 PspSalPrinter::PspSalPrinter( SalInfoPrinter* pInfoPrinter )
864 : m_bFax( false ),
865 m_bPdf( false ),
866 m_bSwallowFaxNo( false ),
867 m_bIsPDFWriterJob( false ),
868 m_pGraphics( NULL ),
869 m_nCopies( 1 ),
870 m_bCollate( false ),
871 m_pInfoPrinter( pInfoPrinter )
875 PspSalPrinter::~PspSalPrinter()
879 static OUString getTmpName()
881 OUString aTmp, aSys;
882 osl_createTempFile( NULL, NULL, &aTmp.pData );
883 osl_getSystemPathFromFileURL( aTmp.pData, &aSys.pData );
885 return aSys;
888 sal_Bool PspSalPrinter::StartJob(
889 const OUString* pFileName,
890 const OUString& rJobName,
891 const OUString& rAppName,
892 sal_uLong nCopies,
893 bool bCollate,
894 bool bDirect,
895 ImplJobSetup* pJobSetup )
897 OSL_TRACE("PspSalPrinter::StartJob");
898 GetSalData()->m_pInstance->jobStartedPrinterUpdate();
900 m_bFax = false;
901 m_bPdf = false;
902 m_aFileName = pFileName ? *pFileName : OUString();
903 m_aTmpFile = OUString();
904 m_nCopies = nCopies;
905 m_bCollate = bCollate;
907 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
908 if( m_nCopies > 1 )
910 // in case user did not do anything (m_nCopies=1)
911 // take the default from jobsetup
912 m_aJobData.m_nCopies = m_nCopies;
913 m_aJobData.setCollate( bCollate );
916 int nMode = 0;
917 #if defined( UNX )
918 // check whether this printer is configured as fax
919 sal_Int32 nIndex = 0;
920 const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
921 while( nIndex != -1 )
923 OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
924 if( aToken.startsWith( "fax" ) )
926 m_bFax = true;
927 m_aTmpFile = getTmpName();
928 nMode = S_IRUSR | S_IWUSR;
930 ::boost::unordered_map< OUString, OUString, OUStringHash >::const_iterator it;
931 it = pJobSetup->maValueMap.find( OUString("FAX#") );
932 if( it != pJobSetup->maValueMap.end() )
933 m_aFaxNr = it->second;
935 sal_Int32 nPos = 0;
936 m_bSwallowFaxNo = aToken.getToken( 1, '=', nPos ).startsWith( "swallow" ) ? true : false;
938 break;
940 if( aToken.startsWith( "pdf=" ) )
942 m_bPdf = true;
943 m_aTmpFile = getTmpName();
944 nMode = S_IRUSR | S_IWUSR;
946 if( m_aFileName.isEmpty() )
948 OUStringBuffer aFileName( getPdfDir( rInfo ) );
949 aFileName.append( '/' );
950 aFileName.append( rJobName );
951 aFileName.appendAscii( ".pdf" );
952 m_aFileName = aFileName.makeStringAndClear();
954 break;
957 #endif
958 m_aPrinterGfx.Init( m_aJobData );
960 return m_aPrintJob.StartJob( ! m_aTmpFile.isEmpty() ? m_aTmpFile : m_aFileName, nMode, rJobName, rAppName, m_aJobData, &m_aPrinterGfx, bDirect ) ? sal_True : sal_False;
963 sal_Bool PspSalPrinter::EndJob()
965 sal_Bool bSuccess = sal_False;
966 if( m_bIsPDFWriterJob )
967 bSuccess = sal_True;
968 else
970 bSuccess = m_aPrintJob.EndJob();
971 OSL_TRACE("PspSalPrinter::EndJob %d", bSuccess);
973 if( bSuccess )
975 // check for fax
976 if( m_bFax )
978 const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
979 // sendAFax removes the file after use
980 bSuccess = sendAFax( m_aFaxNr, m_aTmpFile, rInfo.m_aCommand );
982 else if( m_bPdf )
984 const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
985 bSuccess = createPdf( m_aFileName, m_aTmpFile, rInfo.m_aCommand );
989 GetSalData()->m_pInstance->jobEndedPrinterUpdate();
990 return bSuccess;
993 sal_Bool PspSalPrinter::AbortJob()
995 sal_Bool bAbort = m_aPrintJob.AbortJob() ? sal_True : sal_False;
996 GetSalData()->m_pInstance->jobEndedPrinterUpdate();
997 return bAbort;
1000 SalGraphics* PspSalPrinter::StartPage( ImplJobSetup* pJobSetup, sal_Bool )
1002 OSL_TRACE("PspSalPrinter::StartPage");
1004 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
1005 m_pGraphics = GetGenericInstance()->CreatePrintGraphics();
1006 m_pGraphics->Init( &m_aJobData, &m_aPrinterGfx, m_bFax ? &m_aFaxNr : NULL,
1007 m_bSwallowFaxNo, m_pInfoPrinter );
1008 if( m_nCopies > 1 )
1010 // in case user did not do anything (m_nCopies=1)
1011 // take the default from jobsetup
1012 m_aJobData.m_nCopies = m_nCopies;
1013 m_aJobData.setCollate( m_nCopies > 1 && m_bCollate );
1016 m_aPrintJob.StartPage( m_aJobData );
1017 m_aPrinterGfx.Init( m_aPrintJob );
1019 return m_pGraphics;
1022 sal_Bool PspSalPrinter::EndPage()
1024 sal_Bool bResult = m_aPrintJob.EndPage();
1025 m_aPrinterGfx.Clear();
1026 OSL_TRACE("PspSalPrinter::EndPage");
1027 return bResult ? sal_True : sal_False;
1030 sal_uLong PspSalPrinter::GetErrorCode()
1032 return 0;
1035 struct PDFNewJobParameters
1037 Size maPageSize;
1038 sal_uInt16 mnPaperBin;
1040 PDFNewJobParameters( const Size& i_rSize = Size(),
1041 sal_uInt16 i_nPaperBin = 0xffff )
1042 : maPageSize( i_rSize ), mnPaperBin( i_nPaperBin ) {}
1044 bool operator!=(const PDFNewJobParameters& rComp ) const
1046 Size aCompLSSize( rComp.maPageSize.Height(), rComp.maPageSize.Width() );
1047 return
1048 (maPageSize != rComp.maPageSize && maPageSize != aCompLSSize)
1049 || mnPaperBin != rComp.mnPaperBin
1053 bool operator==(const PDFNewJobParameters& rComp) const
1055 return ! this->operator!=(rComp);
1059 struct PDFPrintFile
1061 OUString maTmpURL;
1062 PDFNewJobParameters maParameters;
1064 PDFPrintFile( const OUString& i_rURL, const PDFNewJobParameters& i_rNewParameters )
1065 : maTmpURL( i_rURL )
1066 , maParameters( i_rNewParameters ) {}
1069 sal_Bool PspSalPrinter::StartJob( const OUString* i_pFileName, const OUString& i_rJobName, const OUString& i_rAppName,
1070 ImplJobSetup* i_pSetupData, vcl::PrinterController& i_rController )
1072 OSL_TRACE( "StartJob with controller: pFilename = %s", i_pFileName ? OUStringToOString( *i_pFileName, RTL_TEXTENCODING_UTF8 ).getStr() : "<nil>" );
1073 // mark for endjob
1074 m_bIsPDFWriterJob = true;
1075 // reset IsLastPage
1076 i_rController.setLastPage( sal_False );
1078 // update job data
1079 if( i_pSetupData )
1080 JobData::constructFromStreamBuffer( i_pSetupData->mpDriverData, i_pSetupData->mnDriverDataLen, m_aJobData );
1082 OSL_ASSERT( m_aJobData.m_nPDFDevice > 0 );
1083 m_aJobData.m_nPDFDevice = 1;
1085 // possibly create one job for collated output
1086 sal_Bool bSinglePrintJobs = sal_False;
1087 beans::PropertyValue* pSingleValue = i_rController.getValue( OUString( "PrintCollateAsSingleJobs" ) );
1088 if( pSingleValue )
1090 pSingleValue->Value >>= bSinglePrintJobs;
1093 int nCopies = i_rController.getPrinter()->GetCopyCount();
1094 bool bCollate = i_rController.getPrinter()->IsCollateCopy();
1096 // notify start of real print job
1097 i_rController.jobStarted();
1099 // setup PDFWriter context
1100 vcl::PDFWriter::PDFWriterContext aContext;
1101 aContext.Version = vcl::PDFWriter::PDF_1_4;
1102 aContext.Tagged = false;
1103 aContext.EmbedStandardFonts = true;
1104 aContext.DocumentLocale = Application::GetSettings().GetLanguageTag().getLocale();
1105 aContext.ColorMode = i_rController.getPrinter()->GetPrinterOptions().IsConvertToGreyscales()
1106 ? vcl::PDFWriter::DrawGreyscale : vcl::PDFWriter::DrawColor;
1108 // prepare doc info
1109 aContext.DocumentInfo.Title = i_rJobName;
1110 aContext.DocumentInfo.Creator = i_rAppName;
1111 aContext.DocumentInfo.Producer = i_rAppName;
1113 // define how we handle metafiles in PDFWriter
1114 vcl::PDFWriter::PlayMetafileContext aMtfContext;
1115 aMtfContext.m_bOnlyLosslessCompression = true;
1117 boost::shared_ptr<vcl::PDFWriter> pWriter;
1118 std::vector< PDFPrintFile > aPDFFiles;
1119 boost::shared_ptr<Printer> pPrinter( i_rController.getPrinter() );
1120 int nAllPages = i_rController.getFilteredPageCount();
1121 i_rController.createProgressDialog();
1122 bool bAborted = false;
1123 PDFNewJobParameters aLastParm;
1125 aContext.DPIx = pPrinter->ImplGetDPIX();
1126 aContext.DPIy = pPrinter->ImplGetDPIY();
1127 for( int nPage = 0; nPage < nAllPages && ! bAborted; nPage++ )
1129 if( nPage == nAllPages-1 )
1130 i_rController.setLastPage( sal_True );
1132 // get the page's metafile
1133 GDIMetaFile aPageFile;
1134 vcl::PrinterController::PageSize aPageSize = i_rController.getFilteredPageFile( nPage, aPageFile );
1135 if( i_rController.isProgressCanceled() )
1137 bAborted = true;
1138 if( nPage != nAllPages-1 )
1140 i_rController.createProgressDialog();
1141 i_rController.setLastPage( sal_True );
1142 i_rController.getFilteredPageFile( nPage, aPageFile );
1145 else
1147 pPrinter->SetMapMode( MapMode( MAP_100TH_MM ) );
1148 pPrinter->SetPaperSizeUser( aPageSize.aSize, true );
1149 PDFNewJobParameters aNewParm( pPrinter->GetPaperSize(), pPrinter->GetPaperBin() );
1151 // create PDF writer on demand
1152 // either on first page
1153 // or on paper format change - cups does not support multiple paper formats per job (yet?)
1154 // so we need to start a new job to get a new paper format from the printer
1155 // orientation switches (that is switch of height and width) is handled transparently by CUPS
1156 if( ! pWriter ||
1157 (aNewParm != aLastParm && ! i_pFileName ) )
1159 if( pWriter )
1161 pWriter->Emit();
1163 // produce PDF file
1164 OUString aPDFUrl;
1165 if( i_pFileName )
1166 aPDFUrl = *i_pFileName;
1167 else
1168 osl_createTempFile( NULL, NULL, &aPDFUrl.pData );
1169 // normalize to file URL
1170 if( !aPDFUrl.startsWith( "file:" ) )
1172 // this is not a file URL, but it should
1173 // form it into a osl friendly file URL
1174 OUString aTmp;
1175 osl_getFileURLFromSystemPath( aPDFUrl.pData, &aTmp.pData );
1176 aPDFUrl = aTmp;
1178 // save current file and paper format
1179 aLastParm = aNewParm;
1180 aPDFFiles.push_back( PDFPrintFile( aPDFUrl, aNewParm ) );
1181 // update context
1182 aContext.URL = aPDFUrl;
1184 // create and initialize PDFWriter
1185 #if defined __SUNPRO_CC
1186 #pragma disable_warn
1187 #endif
1188 pWriter.reset( new vcl::PDFWriter( aContext, uno::Reference< beans::XMaterialHolder >() ) );
1189 #if defined __SUNPRO_CC
1190 #pragma enable_warn
1191 #endif
1194 pWriter->NewPage( TenMuToPt( aNewParm.maPageSize.Width() ),
1195 TenMuToPt( aNewParm.maPageSize.Height() ),
1196 vcl::PDFWriter::Portrait );
1198 pWriter->PlayMetafile( aPageFile, aMtfContext, NULL );
1202 // emit the last file
1203 if( pWriter )
1204 pWriter->Emit();
1206 // handle collate, copy count and multiple jobs correctly
1207 int nOuterJobs = 1;
1208 if( bSinglePrintJobs )
1210 nOuterJobs = nCopies;
1211 m_aJobData.m_nCopies = 1;
1213 else
1215 if( bCollate )
1217 if( aPDFFiles.size() == 1 && pPrinter->HasSupport( SUPPORT_COLLATECOPY ) )
1219 m_aJobData.setCollate( true );
1220 m_aJobData.m_nCopies = nCopies;
1222 else
1224 nOuterJobs = nCopies;
1225 m_aJobData.m_nCopies = 1;
1228 else
1230 m_aJobData.setCollate( false );
1231 m_aJobData.m_nCopies = nCopies;
1235 // spool files
1236 if( ! i_pFileName && ! bAborted )
1238 bool bFirstJob = true;
1239 for( int nCurJob = 0; nCurJob < nOuterJobs; nCurJob++ )
1241 for( size_t i = 0; i < aPDFFiles.size(); i++ )
1243 oslFileHandle pFile = NULL;
1244 osl_openFile( aPDFFiles[i].maTmpURL.pData, &pFile, osl_File_OpenFlag_Read );
1245 if (pFile && (osl_setFilePos(pFile, osl_Pos_Absolut, 0) == osl_File_E_None))
1247 std::vector< char > buffer( 0x10000, 0 );
1248 // update job data with current page size
1249 Size aPageSize( aPDFFiles[i].maParameters.maPageSize );
1250 m_aJobData.setPaper( TenMuToPt( aPageSize.Width() ), TenMuToPt( aPageSize.Height() ) );
1251 // update job data with current paperbin
1252 m_aJobData.setPaperBin( aPDFFiles[i].maParameters.mnPaperBin );
1254 // spool current file
1255 FILE* fp = PrinterInfoManager::get().startSpool( pPrinter->GetName(), i_rController.isDirectPrint() );
1256 if( fp )
1258 sal_uInt64 nBytesRead = 0;
1261 osl_readFile( pFile, &buffer[0], buffer.size(), &nBytesRead );
1262 if( nBytesRead > 0 )
1264 size_t nBytesWritten = fwrite(&buffer[0], 1, nBytesRead, fp);
1265 OSL_ENSURE(nBytesRead == nBytesWritten, "short write");
1266 if (nBytesRead != nBytesWritten)
1267 break;
1269 } while( nBytesRead == buffer.size() );
1270 OUStringBuffer aBuf( i_rJobName.getLength() + 8 );
1271 aBuf.append( i_rJobName );
1272 if( i > 0 || nCurJob > 0 )
1274 aBuf.append( sal_Unicode(' ') );
1275 aBuf.append( sal_Int32( i + nCurJob * aPDFFiles.size() ) );
1277 PrinterInfoManager::get().endSpool( pPrinter->GetName(), aBuf.makeStringAndClear(), fp, m_aJobData, bFirstJob );
1278 bFirstJob = false;
1281 osl_closeFile( pFile );
1286 // job has been spooled
1287 i_rController.setJobState( bAborted ? view::PrintableState_JOB_ABORTED : view::PrintableState_JOB_SPOOLED );
1289 // clean up the temporary PDF files
1290 if( ! i_pFileName || bAborted )
1292 for( size_t i = 0; i < aPDFFiles.size(); i++ )
1294 osl_removeFile( aPDFFiles[i].maTmpURL.pData );
1295 OSL_TRACE( "removed print PDF file %s", OUStringToOString( aPDFFiles[i].maTmpURL, RTL_TEXTENCODING_UTF8 ).getStr() );
1299 return sal_True;
1303 class PrinterUpdate
1305 static Timer* pPrinterUpdateTimer;
1306 static int nActiveJobs;
1308 static void doUpdate();
1309 DECL_STATIC_LINK( PrinterUpdate, UpdateTimerHdl, void* );
1310 public:
1311 static void update(SalGenericInstance &rInstance);
1312 static void jobStarted() { nActiveJobs++; }
1313 static void jobEnded();
1316 Timer* PrinterUpdate::pPrinterUpdateTimer = NULL;
1317 int PrinterUpdate::nActiveJobs = 0;
1319 void PrinterUpdate::doUpdate()
1321 ::psp::PrinterInfoManager& rManager( ::psp::PrinterInfoManager::get() );
1322 SalGenericInstance *pInst = static_cast<SalGenericInstance *>( GetSalData()->m_pInstance );
1323 if( pInst && rManager.checkPrintersChanged( false ) )
1324 pInst->PostPrintersChanged();
1327 // -----------------------------------------------------------------------
1329 IMPL_STATIC_LINK_NOINSTANCE( PrinterUpdate, UpdateTimerHdl, void*, EMPTYARG )
1331 if( nActiveJobs < 1 )
1333 doUpdate();
1334 delete pPrinterUpdateTimer;
1335 pPrinterUpdateTimer = NULL;
1337 else
1338 pPrinterUpdateTimer->Start();
1340 return 0;
1343 void PrinterUpdate::update(SalGenericInstance &rInstance)
1345 if( Application::GetSettings().GetMiscSettings().GetDisablePrinting() )
1346 return;
1348 if( ! rInstance.isPrinterInit() )
1350 // #i45389# start background printer detection
1351 psp::PrinterInfoManager::get();
1352 return;
1355 if( nActiveJobs < 1 )
1356 doUpdate();
1357 else if( ! pPrinterUpdateTimer )
1359 pPrinterUpdateTimer = new Timer();
1360 pPrinterUpdateTimer->SetTimeout( 500 );
1361 pPrinterUpdateTimer->SetTimeoutHdl( STATIC_LINK( NULL, PrinterUpdate, UpdateTimerHdl ) );
1362 pPrinterUpdateTimer->Start();
1366 void SalGenericInstance::updatePrinterUpdate()
1368 PrinterUpdate::update(*this);
1371 void SalGenericInstance::jobStartedPrinterUpdate()
1373 PrinterUpdate::jobStarted();
1376 void PrinterUpdate::jobEnded()
1378 nActiveJobs--;
1379 if( nActiveJobs < 1 )
1381 if( pPrinterUpdateTimer )
1383 pPrinterUpdateTimer->Stop();
1384 delete pPrinterUpdateTimer;
1385 pPrinterUpdateTimer = NULL;
1386 doUpdate();
1391 void SalGenericInstance::jobEndedPrinterUpdate()
1393 PrinterUpdate::jobEnded();
1396 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */