merge the formfield patch from ooo-build
[ooovba.git] / vcl / unx / source / gdi / salprnpsp.cxx
bloba9e2695436525a06bd49d63b1c922467611ab01b
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: salprnpsp.cxx,v $
10 * $Revision: 1.53 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
34 /**
35 this file implements the sal printer interface ( SalPrinter, SalInfoPrinter
36 and some printer relevant methods of SalInstance and SalGraphicsData )
38 as aunderlying library the printer features of psprint are used.
40 The query methods of a SalInfoPrinter are implemented by querying psprint
42 The job methods of a SalPrinter are implemented by calling psprint
43 printer job functions.
46 #include <salunx.h>
47 #include <unistd.h>
48 #include <sys/wait.h>
49 #include <sys/stat.h>
51 #include "saldisp.hxx"
52 #include "salinst.h"
53 #include "salprn.h"
54 #include "salframe.h"
55 #include "pspgraphics.h"
56 #include "saldata.hxx"
57 #include "vcl/svapp.hxx"
58 #include "vcl/jobset.h"
59 #include "vcl/print.h"
60 #include "vcl/salptype.hxx"
61 #include "vcl/printerinfomanager.hxx"
63 #include "rtl/ustring.hxx"
65 #include "osl/module.h"
67 using namespace psp;
68 using namespace rtl;
71 * static helpers
74 #include "rtsname.hxx"
76 static oslModule driverLib = NULL;
77 extern "C"
79 typedef int(*setupFunction)(PrinterInfo&);
80 static setupFunction pSetupFunction = NULL;
81 typedef int(*faxFunction)(String&);
82 static faxFunction pFaxNrFunction = NULL;
85 static String getPdfDir( const PrinterInfo& rInfo )
87 String aDir;
88 sal_Int32 nIndex = 0;
89 while( nIndex != -1 )
91 OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
92 if( ! aToken.compareToAscii( "pdf=", 4 ) )
94 sal_Int32 nPos = 0;
95 aDir = aToken.getToken( 1, '=', nPos );
96 if( ! aDir.Len() )
97 aDir = String( ByteString( getenv( "HOME" ) ), osl_getThreadTextEncoding() );
98 break;
101 return aDir;
104 static void getPaLib()
106 if( ! driverLib )
108 OUString aLibName( RTL_CONSTASCII_USTRINGPARAM( _XSALSET_LIBNAME ) );
109 driverLib = osl_loadModuleRelative( (oslGenericFunction)getPaLib, aLibName.pData, SAL_LOADMODULE_DEFAULT );
110 if ( !driverLib )
112 return;
115 pSetupFunction = (setupFunction)osl_getAsciiFunctionSymbol( driverLib, "Sal_SetupPrinterDriver" );
116 if ( !pSetupFunction )
117 fprintf( stderr, "could not resolve Sal_SetupPrinterDriver\n" );
119 pFaxNrFunction = (faxFunction)osl_getAsciiFunctionSymbol( driverLib, "Sal_queryFaxNumber" );
120 if ( !pFaxNrFunction )
121 fprintf( stderr, "could not resolve Sal_queryFaxNumber\n" );
125 inline int PtTo10Mu( int nPoints ) { return (int)((((double)nPoints)*35.27777778)+0.5); }
127 inline int TenMuToPt( int nUnits ) { return (int)((((double)nUnits)/35.27777778)+0.5); }
129 static void copyJobDataToJobSetup( ImplJobSetup* pJobSetup, JobData& rData )
131 pJobSetup->meOrientation = (Orientation)(rData.m_eOrientation == orientation::Landscape ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT);
133 // copy page size
134 String aPaper;
135 int width, height;
137 rData.m_aContext.getPageSize( aPaper, width, height );
138 pJobSetup->mePaperFormat = PaperInfo::fromPSName(OUStringToOString( aPaper, RTL_TEXTENCODING_ISO_8859_1 ));
140 pJobSetup->mnPaperWidth = 0;
141 pJobSetup->mnPaperHeight = 0;
142 if( pJobSetup->mePaperFormat == PAPER_USER )
144 // transform to 100dth mm
145 width = PtTo10Mu( width );
146 height = PtTo10Mu( height );
148 if( rData.m_eOrientation == psp::orientation::Portrait )
150 pJobSetup->mnPaperWidth = width;
151 pJobSetup->mnPaperHeight= height;
153 else
155 pJobSetup->mnPaperWidth = height;
156 pJobSetup->mnPaperHeight= width;
160 // copy input slot
161 const PPDKey* pKey = NULL;
162 const PPDValue* pValue = NULL;
164 pJobSetup->mnPaperBin = 0;
165 if( rData.m_pParser )
166 pKey = rData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) );
167 if( pKey )
168 pValue = rData.m_aContext.getValue( pKey );
169 if( pKey && pValue )
171 for( pJobSetup->mnPaperBin = 0;
172 pValue != pKey->getValue( pJobSetup->mnPaperBin ) &&
173 pJobSetup->mnPaperBin < pKey->countValues();
174 pJobSetup->mnPaperBin++ )
176 if( pJobSetup->mnPaperBin >= pKey->countValues() )
177 pJobSetup->mnPaperBin = 0;
181 // copy the whole context
182 if( pJobSetup->mpDriverData )
183 rtl_freeMemory( pJobSetup->mpDriverData );
185 int nBytes;
186 void* pBuffer = NULL;
187 if( rData.getStreamBuffer( pBuffer, nBytes ) )
189 pJobSetup->mnDriverDataLen = nBytes;
190 pJobSetup->mpDriverData = (BYTE*)pBuffer;
192 else
194 pJobSetup->mnDriverDataLen = 0;
195 pJobSetup->mpDriverData = NULL;
199 static bool passFileToCommandLine( const String& rFilename, const String& rCommandLine, bool bRemoveFile = true )
201 bool bSuccess = false;
203 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
204 ByteString aCmdLine( rCommandLine, aEncoding );
205 ByteString aFilename( rFilename, aEncoding );
207 bool bPipe = aCmdLine.Search( "(TMP)" ) != STRING_NOTFOUND ? false : true;
209 // setup command line for exec
210 if( ! bPipe )
211 while( aCmdLine.SearchAndReplace( "(TMP)", aFilename ) != STRING_NOTFOUND )
214 #if OSL_DEBUG_LEVEL > 1
215 fprintf( stderr, "%s commandline: \"%s\"\n",
216 bPipe ? "piping to" : "executing",
217 aCmdLine.GetBuffer() );
218 struct stat aStat;
219 if( stat( aFilename.GetBuffer(), &aStat ) )
220 fprintf( stderr, "stat( %s ) failed\n", aFilename.GetBuffer() );
221 fprintf( stderr, "Tmp file %s has modes: 0%03lo\n", aFilename.GetBuffer(), (long)aStat.st_mode );
222 #endif
223 const char* argv[4];
224 if( ! ( argv[ 0 ] = getenv( "SHELL" ) ) )
225 argv[ 0 ] = "/bin/sh";
226 argv[ 1 ] = "-c";
227 argv[ 2 ] = aCmdLine.GetBuffer();
228 argv[ 3 ] = 0;
230 bool bHavePipes = false;
231 int pid, fd[2];
233 if( bPipe )
234 bHavePipes = pipe( fd ) ? false : true;
235 if( ( pid = fork() ) > 0 )
237 if( bPipe && bHavePipes )
239 close( fd[0] );
240 char aBuffer[ 2048 ];
241 FILE* fp = fopen( aFilename.GetBuffer(), "r" );
242 while( fp && ! feof( fp ) )
244 int nBytes = fread( aBuffer, 1, sizeof( aBuffer ), fp );
245 if( nBytes )
246 write( fd[ 1 ], aBuffer, nBytes );
248 fclose( fp );
249 close( fd[ 1 ] );
251 int status = 0;
252 waitpid( pid, &status, 0 );
253 if( ! status )
254 bSuccess = true;
256 else if( ! pid )
258 if( bPipe && bHavePipes )
260 close( fd[1] );
261 if( fd[0] != STDIN_FILENO ) // not probable, but who knows :)
262 dup2( fd[0], STDIN_FILENO );
264 execv( argv[0], const_cast<char**>(argv) );
265 fprintf( stderr, "failed to execute \"%s\"\n", aCmdLine.GetBuffer() );
266 _exit( 1 );
268 else
269 fprintf( stderr, "failed to fork\n" );
271 // clean up the mess
272 if( bRemoveFile )
273 unlink( aFilename.GetBuffer() );
275 return bSuccess;
278 static bool sendAFax( const String& rFaxNumber, const String& rFileName, const String& rCommand )
280 std::list< OUString > aFaxNumbers;
282 if( ! rFaxNumber.Len() )
284 getPaLib();
285 if( pFaxNrFunction )
287 String aNewNr;
288 if( pFaxNrFunction( aNewNr ) )
289 aFaxNumbers.push_back( OUString( aNewNr ) );
292 else
294 sal_Int32 nIndex = 0;
295 OUString aFaxes( rFaxNumber );
296 OUString aBeginToken( RTL_CONSTASCII_USTRINGPARAM("<Fax#>") );
297 OUString aEndToken( RTL_CONSTASCII_USTRINGPARAM("</Fax#>") );
298 while( nIndex != -1 )
300 nIndex = aFaxes.indexOf( aBeginToken, nIndex );
301 if( nIndex != -1 )
303 sal_Int32 nBegin = nIndex + aBeginToken.getLength();
304 nIndex = aFaxes.indexOf( aEndToken, nIndex );
305 if( nIndex != -1 )
307 aFaxNumbers.push_back( aFaxes.copy( nBegin, nIndex-nBegin ) );
308 nIndex += aEndToken.getLength();
314 bool bSuccess = true;
315 if( aFaxNumbers.begin() != aFaxNumbers.end() )
317 while( aFaxNumbers.begin() != aFaxNumbers.end() && bSuccess )
319 String aCmdLine( rCommand );
320 String aFaxNumber( aFaxNumbers.front() );
321 aFaxNumbers.pop_front();
322 while( aCmdLine.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(PHONE)" ) ), aFaxNumber ) != STRING_NOTFOUND )
324 #if OSL_DEBUG_LEVEL > 1
325 fprintf( stderr, "sending fax to \"%s\"\n", OUStringToOString( aFaxNumber, osl_getThreadTextEncoding() ).getStr() );
326 #endif
327 bSuccess = passFileToCommandLine( rFileName, aCmdLine, false );
330 else
331 bSuccess = false;
333 // clean up temp file
334 unlink( ByteString( rFileName, osl_getThreadTextEncoding() ).GetBuffer() );
336 return bSuccess;
339 static bool createPdf( const String& rToFile, const String& rFromFile, const String& rCommandLine )
341 String aCommandLine( rCommandLine );
342 while( aCommandLine.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(OUTFILE)" ) ), rToFile ) != STRING_NOTFOUND )
344 return passFileToCommandLine( rFromFile, aCommandLine );
348 * SalInstance
351 // -----------------------------------------------------------------------
353 SalInfoPrinter* X11SalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
354 ImplJobSetup* pJobSetup )
356 mbPrinterInit = true;
357 // create and initialize SalInfoPrinter
358 PspSalInfoPrinter* pPrinter = new PspSalInfoPrinter;
360 if( pJobSetup )
362 PrinterInfoManager& rManager( PrinterInfoManager::get() );
363 PrinterInfo aInfo( rManager.getPrinterInfo( pQueueInfo->maPrinterName ) );
364 pPrinter->m_aJobData = aInfo;
365 pPrinter->m_aPrinterGfx.Init( pPrinter->m_aJobData );
367 if( pJobSetup->mpDriverData )
368 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo );
370 pJobSetup->mnSystem = JOBSETUP_SYSTEM_UNIX;
371 pJobSetup->maPrinterName = pQueueInfo->maPrinterName;
372 pJobSetup->maDriver = aInfo.m_aDriverName;
373 copyJobDataToJobSetup( pJobSetup, aInfo );
375 // set/clear backwards compatibility flag
376 bool bStrictSO52Compatibility = false;
377 std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it =
378 pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) );
380 if( compat_it != pJobSetup->maValueMap.end() )
382 if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) )
383 bStrictSO52Compatibility = true;
385 pPrinter->m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility );
389 return pPrinter;
392 // -----------------------------------------------------------------------
394 void X11SalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
396 delete pPrinter;
399 // -----------------------------------------------------------------------
401 SalPrinter* X11SalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
403 mbPrinterInit = true;
404 // create and initialize SalPrinter
405 PspSalPrinter* pPrinter = new PspSalPrinter( pInfoPrinter );
406 pPrinter->m_aJobData = static_cast<PspSalInfoPrinter*>(pInfoPrinter)->m_aJobData;
408 return pPrinter;
411 // -----------------------------------------------------------------------
413 void X11SalInstance::DestroyPrinter( SalPrinter* pPrinter )
415 delete pPrinter;
418 // -----------------------------------------------------------------------
420 void X11SalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
422 mbPrinterInit = true;
423 PrinterInfoManager& rManager( PrinterInfoManager::get() );
424 static const char* pNoSyncDetection = getenv( "SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION" );
425 if( ! pNoSyncDetection || ! *pNoSyncDetection )
427 // #i62663# synchronize possible asynchronouse printer detection now
428 rManager.checkPrintersChanged( true );
430 ::std::list< OUString > aPrinters;
431 rManager.listPrinters( aPrinters );
433 for( ::std::list< OUString >::iterator it = aPrinters.begin(); it != aPrinters.end(); ++it )
435 const PrinterInfo& rInfo( rManager.getPrinterInfo( *it ) );
436 // Neuen Eintrag anlegen
437 SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
438 pInfo->maPrinterName = *it;
439 pInfo->maDriver = rInfo.m_aDriverName;
440 pInfo->maLocation = rInfo.m_aLocation;
441 pInfo->maComment = rInfo.m_aComment;
442 pInfo->mpSysData = NULL;
444 sal_Int32 nIndex = 0;
445 while( nIndex != -1 )
447 String aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
448 if( aToken.CompareToAscii( "pdf=", 4 ) == COMPARE_EQUAL )
450 pInfo->maLocation = getPdfDir( rInfo );
451 break;
455 pList->Add( pInfo );
459 // -----------------------------------------------------------------------
461 void X11SalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo )
463 delete pInfo;
466 // -----------------------------------------------------------------------
468 void X11SalInstance::GetPrinterQueueState( SalPrinterQueueInfo* )
470 mbPrinterInit = true;
473 // -----------------------------------------------------------------------
475 String X11SalInstance::GetDefaultPrinter()
477 mbPrinterInit = true;
478 PrinterInfoManager& rManager( PrinterInfoManager::get() );
479 return rManager.getDefaultPrinter();
482 // =======================================================================
484 PspSalInfoPrinter::PspSalInfoPrinter()
486 m_pGraphics = NULL;
487 m_bPapersInit = false;
490 // -----------------------------------------------------------------------
492 PspSalInfoPrinter::~PspSalInfoPrinter()
494 if( m_pGraphics )
496 delete m_pGraphics;
497 m_pGraphics = NULL;
501 // -----------------------------------------------------------------------
503 void PspSalInfoPrinter::InitPaperFormats( const ImplJobSetup* )
505 m_aPaperFormats.clear();
506 m_bPapersInit = true;
508 if( m_aJobData.m_pParser )
510 const PPDKey* pKey = m_aJobData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
511 if( pKey )
513 int nValues = pKey->countValues();
514 for( int i = 0; i < nValues; i++ )
516 const PPDValue* pValue = pKey->getValue( i );
517 int nWidth = 0, nHeight = 0;
518 m_aJobData.m_pParser->getPaperDimension( pValue->m_aOption, nWidth, nHeight );
519 PaperInfo aInfo(PtTo10Mu( nWidth ), PtTo10Mu( nHeight ));
520 m_aPaperFormats.push_back( aInfo );
526 // -----------------------------------------------------------------------
528 DuplexMode PspSalInfoPrinter::GetDuplexMode( const ImplJobSetup* pJobSetup )
530 DuplexMode aRet = DUPLEX_UNKNOWN;
531 PrinterInfo aInfo( PrinterInfoManager::get().getPrinterInfo( pJobSetup->maPrinterName ) );
532 if ( pJobSetup->mpDriverData )
533 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo );
534 if( aInfo.m_pParser )
536 const PPDKey * pKey = aInfo.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) );
537 if( pKey )
539 const PPDValue* pVal = aInfo.m_aContext.getValue( pKey );
540 if( pVal && (
541 pVal->m_aOption.EqualsIgnoreCaseAscii( "None" ) ||
542 pVal->m_aOption.EqualsIgnoreCaseAscii( "Simplex", 0, 7 )
545 aRet = DUPLEX_OFF;
547 else
548 aRet = DUPLEX_ON;
551 return aRet;
554 // -----------------------------------------------------------------------
556 int PspSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* )
558 return 900;
561 // -----------------------------------------------------------------------
563 SalGraphics* PspSalInfoPrinter::GetGraphics()
565 // return a valid pointer only once
566 // the reasoning behind this is that we could have different
567 // SalGraphics that can run in multiple threads
568 // (future plans)
569 SalGraphics* pRet = NULL;
570 if( ! m_pGraphics )
572 m_pGraphics = new PspGraphics( &m_aJobData, &m_aPrinterGfx, NULL, false, this );
573 m_pGraphics->SetLayout( 0 );
574 pRet = m_pGraphics;
576 return pRet;
579 // -----------------------------------------------------------------------
581 void PspSalInfoPrinter::ReleaseGraphics( SalGraphics* pGraphics )
583 if( pGraphics == m_pGraphics )
585 delete pGraphics;
586 m_pGraphics = NULL;
588 return;
591 // -----------------------------------------------------------------------
593 BOOL PspSalInfoPrinter::Setup( SalFrame* pFrame, ImplJobSetup* pJobSetup )
595 if( ! pFrame || ! pJobSetup )
596 return FALSE;
598 getPaLib();
600 if( ! pSetupFunction )
601 return FALSE;
603 PrinterInfoManager& rManager = PrinterInfoManager::get();
605 PrinterInfo aInfo( rManager.getPrinterInfo( pJobSetup->maPrinterName ) );
606 if ( pJobSetup->mpDriverData )
608 SetData( ~0, pJobSetup );
609 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo );
612 if( pSetupFunction( aInfo ) )
614 rtl_freeMemory( pJobSetup->mpDriverData );
615 pJobSetup->mpDriverData = NULL;
617 int nBytes;
618 void* pBuffer = NULL;
619 aInfo.getStreamBuffer( pBuffer, nBytes );
620 pJobSetup->mnDriverDataLen = nBytes;
621 pJobSetup->mpDriverData = (BYTE*)pBuffer;
623 // copy everything to job setup
624 copyJobDataToJobSetup( pJobSetup, aInfo );
625 return TRUE;
627 return FALSE;
630 // -----------------------------------------------------------------------
632 // This function gets the driver data and puts it into pJobSetup
633 // If pJobSetup->mpDriverData is NOT NULL, then the independend
634 // data should be merged into the driver data
635 // If pJobSetup->mpDriverData IS NULL, then the driver defaults
636 // should be merged into the independent data
637 BOOL PspSalInfoPrinter::SetPrinterData( ImplJobSetup* pJobSetup )
639 // set/clear backwards compatibility flag
640 bool bStrictSO52Compatibility = false;
641 std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it =
642 pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) );
644 if( compat_it != pJobSetup->maValueMap.end() )
646 if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) )
647 bStrictSO52Compatibility = true;
649 m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility );
651 if( pJobSetup->mpDriverData )
652 return SetData( ~0, pJobSetup );
654 copyJobDataToJobSetup( pJobSetup, m_aJobData );
656 return TRUE;
659 // -----------------------------------------------------------------------
661 // This function merges the independ driver data
662 // and sets the new independ data in pJobSetup
663 // Only the data must be changed, where the bit
664 // in nGetDataFlags is set
665 BOOL PspSalInfoPrinter::SetData(
666 ULONG nSetDataFlags,
667 ImplJobSetup* pJobSetup )
669 JobData aData;
670 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
672 if( aData.m_pParser )
674 const PPDKey* pKey;
675 const PPDValue* pValue;
677 // merge papersize if necessary
678 if( nSetDataFlags & SAL_JOBSET_PAPERSIZE )
680 int nWidth, nHeight;
681 if( pJobSetup->meOrientation == ORIENTATION_PORTRAIT )
683 nWidth = pJobSetup->mnPaperWidth;
684 nHeight = pJobSetup->mnPaperHeight;
686 else
688 nWidth = pJobSetup->mnPaperHeight;
689 nHeight = pJobSetup->mnPaperWidth;
691 String aPaper;
693 if( pJobSetup->mePaperFormat == PAPER_USER )
694 aPaper = aData.m_pParser->matchPaper(
695 TenMuToPt( pJobSetup->mnPaperWidth ),
696 TenMuToPt( pJobSetup->mnPaperHeight ) );
697 else
698 aPaper = rtl::OStringToOUString(PaperInfo::toPSName(pJobSetup->mePaperFormat), RTL_TEXTENCODING_ISO_8859_1);
700 pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
701 pValue = pKey ? pKey->getValueCaseInsensitive( aPaper ) : NULL;
702 if( ! ( pKey && pValue && aData.m_aContext.setValue( pKey, pValue, false ) == pValue ) )
703 return FALSE;
706 // merge paperbin if necessary
707 if( nSetDataFlags & SAL_JOBSET_PAPERBIN )
709 pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) );
710 if( pKey )
712 int nPaperBin = pJobSetup->mnPaperBin;
713 if( nPaperBin >= pKey->countValues() )
714 pValue = pKey->getDefaultValue();
715 else
716 pValue = pKey->getValue( pJobSetup->mnPaperBin );
718 // may fail due to constraints;
719 // real paper bin is copied back to jobsetup in that case
720 aData.m_aContext.setValue( pKey, pValue );
722 // if printer has no InputSlot key simply ignore this setting
723 // (e.g. SGENPRT has no InputSlot)
726 // merge orientation if necessary
727 if( nSetDataFlags & SAL_JOBSET_ORIENTATION )
728 aData.m_eOrientation = pJobSetup->meOrientation == ORIENTATION_LANDSCAPE ? orientation::Landscape : orientation::Portrait;
730 m_aJobData = aData;
731 copyJobDataToJobSetup( pJobSetup, aData );
732 return TRUE;
735 return FALSE;
738 // -----------------------------------------------------------------------
740 void PspSalInfoPrinter::GetPageInfo(
741 const ImplJobSetup* pJobSetup,
742 long& rOutWidth, long& rOutHeight,
743 long& rPageOffX, long& rPageOffY,
744 long& rPageWidth, long& rPageHeight )
746 if( ! pJobSetup )
747 return;
749 JobData aData;
750 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
752 // get the selected page size
753 if( aData.m_pParser )
756 String aPaper;
757 int width, height;
758 int left = 0, top = 0, right = 0, bottom = 0;
759 int nDPI = aData.m_aContext.getRenderResolution();
762 if( aData.m_eOrientation == psp::orientation::Portrait )
764 aData.m_aContext.getPageSize( aPaper, width, height );
765 aData.m_pParser->getMargins( aPaper, left, right, top, bottom );
767 else
769 aData.m_aContext.getPageSize( aPaper, height, width );
770 aData.m_pParser->getMargins( aPaper, top, bottom, right, left );
773 rPageWidth = width * nDPI / 72;
774 rPageHeight = height * nDPI / 72;
775 rPageOffX = left * nDPI / 72;
776 rPageOffY = top * nDPI / 72;
777 rOutWidth = ( width - left - right ) * nDPI / 72;
778 rOutHeight = ( height - top - bottom ) * nDPI / 72;
782 // -----------------------------------------------------------------------
784 ULONG PspSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pJobSetup )
786 if( ! pJobSetup )
787 return 0;
789 JobData aData;
790 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
792 const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ): NULL;
793 return pKey ? pKey->countValues() : 0;
796 // -----------------------------------------------------------------------
798 String PspSalInfoPrinter::GetPaperBinName( const ImplJobSetup* pJobSetup, ULONG nPaperBin )
800 JobData aData;
801 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
803 String aRet;
804 if( aData.m_pParser )
806 const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ): NULL;
807 if( ! pKey || nPaperBin >= (ULONG)pKey->countValues() )
808 aRet = aData.m_pParser->getDefaultInputSlot();
809 else
811 const PPDValue* pValue = pKey->getValue( nPaperBin );
812 if( pValue )
813 aRet = pValue->m_aOptionTranslation.Len() ? pValue->m_aOptionTranslation : pValue->m_aOption;
817 return aRet;
820 // -----------------------------------------------------------------------
822 ULONG PspSalInfoPrinter::GetCapabilities( const ImplJobSetup* pJobSetup, USHORT nType )
824 switch( nType )
826 case PRINTER_CAPABILITIES_SUPPORTDIALOG:
827 return 1;
828 case PRINTER_CAPABILITIES_COPIES:
829 return 0xffff;
830 case PRINTER_CAPABILITIES_COLLATECOPIES:
831 return 0;
832 case PRINTER_CAPABILITIES_SETORIENTATION:
833 return 1;
834 case PRINTER_CAPABILITIES_SETPAPERBIN:
835 return 1;
836 case PRINTER_CAPABILITIES_SETPAPERSIZE:
837 return 1;
838 case PRINTER_CAPABILITIES_SETPAPER:
839 return 0;
840 case PRINTER_CAPABILITIES_FAX:
841 return PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "fax" ) ? 1 : 0;
842 case PRINTER_CAPABILITIES_PDF:
843 return PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "pdf" ) ? 1 : 0;
844 case PRINTER_CAPABILITIES_EXTERNALDIALOG:
845 return PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "external_dialog" ) ? 1 : 0;
846 default: break;
848 return 0;
851 // =======================================================================
854 * SalPrinter
857 PspSalPrinter::PspSalPrinter( SalInfoPrinter* pInfoPrinter )
858 : m_bFax( false ),
859 m_bPdf( false ),
860 m_bSwallowFaxNo( false ),
861 m_pGraphics( NULL ),
862 m_nCopies( 1 ),
863 m_pInfoPrinter( pInfoPrinter )
867 // -----------------------------------------------------------------------
869 PspSalPrinter::~PspSalPrinter()
873 // -----------------------------------------------------------------------
875 static String getTmpName()
877 rtl::OUString aTmp, aSys;
878 osl_createTempFile( NULL, NULL, &aTmp.pData );
879 osl_getSystemPathFromFileURL( aTmp.pData, &aSys.pData );
881 return aSys;
884 BOOL PspSalPrinter::StartJob(
885 const XubString* pFileName,
886 const XubString& rJobName,
887 const XubString& rAppName,
888 ULONG nCopies, BOOL /*bCollate*/,
889 ImplJobSetup* pJobSetup )
891 vcl_sal::PrinterUpdate::jobStarted();
893 m_bFax = false;
894 m_bPdf = false;
895 m_aFileName = pFileName ? *pFileName : String();
896 m_aTmpFile = String();
897 m_nCopies = nCopies;
899 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
900 if( m_nCopies > 1 )
901 // in case user did not do anything (m_nCopies=1)
902 // take the default from jobsetup
903 m_aJobData.m_nCopies = m_nCopies;
905 // check wether this printer is configured as fax
906 int nMode = 0;
907 const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
908 sal_Int32 nIndex = 0;
909 while( nIndex != -1 )
911 OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
912 if( ! aToken.compareToAscii( "fax", 3 ) )
914 m_bFax = true;
915 m_aTmpFile = getTmpName();
916 nMode = S_IRUSR | S_IWUSR;
918 ::std::hash_map< ::rtl::OUString, ::rtl::OUString, ::rtl::OUStringHash >::const_iterator it;
919 it = pJobSetup->maValueMap.find( ::rtl::OUString::createFromAscii( "FAX#" ) );
920 if( it != pJobSetup->maValueMap.end() )
921 m_aFaxNr = it->second;
923 sal_Int32 nPos = 0;
924 m_bSwallowFaxNo = ! aToken.getToken( 1, '=', nPos ).compareToAscii( "swallow", 7 ) ? true : false;
926 break;
928 if( ! aToken.compareToAscii( "pdf=", 4 ) )
930 m_bPdf = true;
931 m_aTmpFile = getTmpName();
932 nMode = S_IRUSR | S_IWUSR;
934 if( ! m_aFileName.Len() )
936 m_aFileName = getPdfDir( rInfo );
937 m_aFileName.Append( '/' );
938 m_aFileName.Append( rJobName );
939 m_aFileName.AppendAscii( ".pdf" );
941 break;
944 m_aPrinterGfx.Init( m_aJobData );
946 bool bIsQuickJob = false;
947 std::hash_map< rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator quick_it =
948 pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsQuickJob" ) ) );
949 if( quick_it != pJobSetup->maValueMap.end() )
951 if( quick_it->second.equalsIgnoreAsciiCaseAscii( "true" ) )
952 bIsQuickJob = true;
955 // set/clear backwards compatibility flag
956 bool bStrictSO52Compatibility = false;
957 std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it =
958 pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) );
960 if( compat_it != pJobSetup->maValueMap.end() )
962 if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) )
963 bStrictSO52Compatibility = true;
965 m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility );
967 return m_aPrintJob.StartJob( m_aTmpFile.Len() ? m_aTmpFile : m_aFileName, nMode, rJobName, rAppName, m_aJobData, &m_aPrinterGfx, bIsQuickJob ) ? TRUE : FALSE;
970 // -----------------------------------------------------------------------
972 BOOL PspSalPrinter::EndJob()
974 BOOL bSuccess = m_aPrintJob.EndJob();
976 if( bSuccess )
978 // check for fax
979 if( m_bFax )
982 const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
983 // sendAFax removes the file after use
984 bSuccess = sendAFax( m_aFaxNr, m_aTmpFile, rInfo.m_aCommand );
986 else if( m_bPdf )
988 const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
989 bSuccess = createPdf( m_aFileName, m_aTmpFile, rInfo.m_aCommand );
992 vcl_sal::PrinterUpdate::jobEnded();
993 return bSuccess;
996 // -----------------------------------------------------------------------
998 BOOL PspSalPrinter::AbortJob()
1000 BOOL bAbort = m_aPrintJob.AbortJob() ? TRUE : FALSE;
1001 vcl_sal::PrinterUpdate::jobEnded();
1002 return bAbort;
1005 // -----------------------------------------------------------------------
1007 SalGraphics* PspSalPrinter::StartPage( ImplJobSetup* pJobSetup, BOOL )
1009 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
1010 m_pGraphics = new PspGraphics( &m_aJobData, &m_aPrinterGfx, m_bFax ? &m_aFaxNr : NULL, m_bSwallowFaxNo, m_pInfoPrinter );
1011 m_pGraphics->SetLayout( 0 );
1012 if( m_nCopies > 1 )
1013 // in case user did not do anything (m_nCopies=1)
1014 // take the default from jobsetup
1015 m_aJobData.m_nCopies = m_nCopies;
1017 m_aPrintJob.StartPage( m_aJobData );
1018 m_aPrinterGfx.Init( m_aPrintJob );
1020 return m_pGraphics;
1023 // -----------------------------------------------------------------------
1025 BOOL PspSalPrinter::EndPage()
1027 sal_Bool bResult = m_aPrintJob.EndPage();
1028 m_aPrinterGfx.Clear();
1029 return bResult ? TRUE : FALSE;
1032 // -----------------------------------------------------------------------
1034 ULONG PspSalPrinter::GetErrorCode()
1036 return 0;
1040 * vcl::PrinterUpdate
1043 Timer* vcl_sal::PrinterUpdate::pPrinterUpdateTimer = NULL;
1044 int vcl_sal::PrinterUpdate::nActiveJobs = 0;
1046 void vcl_sal::PrinterUpdate::doUpdate()
1048 ::psp::PrinterInfoManager& rManager( ::psp::PrinterInfoManager::get() );
1049 if( rManager.checkPrintersChanged( false ) )
1051 SalDisplay* pDisp = GetX11SalData()->GetDisplay();
1052 const std::list< SalFrame* >& rList = pDisp->getFrames();
1053 for( std::list< SalFrame* >::const_iterator it = rList.begin();
1054 it != rList.end(); ++it )
1055 pDisp->SendInternalEvent( *it, NULL, SALEVENT_PRINTERCHANGED );
1059 // -----------------------------------------------------------------------
1061 IMPL_STATIC_LINK_NOINSTANCE( vcl_sal::PrinterUpdate, UpdateTimerHdl, void*, EMPTYARG )
1063 if( nActiveJobs < 1 )
1065 doUpdate();
1066 delete pPrinterUpdateTimer;
1067 pPrinterUpdateTimer = NULL;
1069 else
1070 pPrinterUpdateTimer->Start();
1072 return 0;
1075 // -----------------------------------------------------------------------
1077 void vcl_sal::PrinterUpdate::update()
1079 if( Application::GetSettings().GetMiscSettings().GetDisablePrinting() )
1080 return;
1082 if( ! static_cast< X11SalInstance* >(GetSalData()->m_pInstance)->isPrinterInit() )
1084 // #i45389# start background printer detection
1085 psp::PrinterInfoManager::get();
1086 return;
1089 if( nActiveJobs < 1 )
1090 doUpdate();
1091 else if( ! pPrinterUpdateTimer )
1093 pPrinterUpdateTimer = new Timer();
1094 pPrinterUpdateTimer->SetTimeout( 500 );
1095 pPrinterUpdateTimer->SetTimeoutHdl( STATIC_LINK( NULL, vcl_sal::PrinterUpdate, UpdateTimerHdl ) );
1096 pPrinterUpdateTimer->Start();
1100 // -----------------------------------------------------------------------
1102 void vcl_sal::PrinterUpdate::jobEnded()
1104 nActiveJobs--;
1105 if( nActiveJobs < 1 )
1107 if( pPrinterUpdateTimer )
1109 pPrinterUpdateTimer->Stop();
1110 delete pPrinterUpdateTimer;
1111 pPrinterUpdateTimer = NULL;
1112 doUpdate();