diff options
author | Luboš Luňák <l.lunak@collabora.com> | 2015-02-26 15:56:24 +0100 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.co.uk> | 2015-03-11 16:21:43 +0100 |
commit | 138d29aa09417eba4d15ade4c9f4dab2620b6326 (patch) | |
tree | 315abb86be92a0f871780912167a611fec7c4d8f | |
parent | e0ad036eed6b151ea81311fcf9ba46f1726b103c (diff) |
support fast MM printing in non-single-file mode only for CUPS
As said in the comment, the non-single-file mode could create way too many print
jobs, so enable this only for the CUPS backend, which has been modified
to send them as a single batch.
Conflicts:
configure.ac
include/vcl/printerinfomanager.hxx
sw/source/uibase/dbui/dbmgr.cxx
vcl/inc/cupsmgr.hxx
vcl/unx/generic/printer/cupsmgr.cxx
vcl/unx/generic/printer/printerinfomanager.cxx
Change-Id: I4c02ca0e8b91323b1d02f004c7b4813433064a11
-rw-r--r-- | config_host/config_cups.h.in | 6 | ||||
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | include/vcl/jobdata.hxx | 6 | ||||
-rw-r--r-- | include/vcl/printerinfomanager.hxx | 10 | ||||
-rw-r--r-- | sw/source/uibase/dbui/dbmgr.cxx | 55 | ||||
-rw-r--r-- | vcl/inc/cupsmgr.hxx | 24 | ||||
-rw-r--r-- | vcl/unx/generic/printer/cupsmgr.cxx | 101 | ||||
-rw-r--r-- | vcl/unx/generic/printer/jobdata.cxx | 18 | ||||
-rw-r--r-- | vcl/unx/generic/printer/printerinfomanager.cxx | 15 |
9 files changed, 212 insertions, 26 deletions
diff --git a/config_host/config_cups.h.in b/config_host/config_cups.h.in new file mode 100644 index 000000000000..6794703664d9 --- /dev/null +++ b/config_host/config_cups.h.in @@ -0,0 +1,6 @@ +#ifndef CONFIG_CUPS_H +#define CONFIG_CUPS_H + +#define ENABLE_CUPS 0 + +#endif diff --git a/configure.ac b/configure.ac index 9131d9b01c45..e8d4fe8ea45d 100644 --- a/configure.ac +++ b/configure.ac @@ -4633,7 +4633,7 @@ if test "$test_cups" = "yes"; then if test "$ac_cv_lib_cups_cupsPrintFiles" != "yes" -o "$ac_cv_header_cups_cups_h" != "yes"; then AC_MSG_ERROR([Could not find CUPS. Install libcups2-dev or cups-devel.]) fi - + AC_DEFINE(ENABLE_CUPS) else AC_MSG_RESULT([no]) fi @@ -12900,6 +12900,7 @@ AC_CONFIG_FILES([config_host.mk AC_CONFIG_HEADERS([config_host/config_buildid.h]) AC_CONFIG_HEADERS([config_host/config_clang.h]) AC_CONFIG_HEADERS([config_host/config_eot.h]) +AC_CONFIG_HEADERS([config_host/config_cups.h]) AC_CONFIG_HEADERS([config_host/config_features.h]) AC_CONFIG_HEADERS([config_host/config_folders.h]) AC_CONFIG_HEADERS([config_host/config_gcc.h]) diff --git a/include/vcl/jobdata.hxx b/include/vcl/jobdata.hxx index 8cffdd1c234c..c173863721c4 100644 --- a/include/vcl/jobdata.hxx +++ b/include/vcl/jobdata.hxx @@ -79,6 +79,12 @@ struct VCL_DLLPUBLIC JobData static bool constructFromStreamBuffer( void* pData, int bytes, JobData& rJobData ); }; +bool operator==(const psp::JobData& rLeft, const psp::JobData& rRight); +inline bool operator!=(const psp::JobData& rLeft, const psp::JobData& rRight) +{ + return !( rLeft == rRight ); +} + } // namespace diff --git a/include/vcl/printerinfomanager.hxx b/include/vcl/printerinfomanager.hxx index 97e68d15e47c..ec5c587838c9 100644 --- a/include/vcl/printerinfomanager.hxx +++ b/include/vcl/printerinfomanager.hxx @@ -196,6 +196,16 @@ public: // check whether a printer's feature string contains a subfeature bool checkFeatureToken( const OUString& rPrinterName, const char* pToken ) const; + // Starts printing in a batch mode, in which all printing will be done together instead of separate jobs. + // If the implementation supports it, calls to endSpool() will only delay the printing until flushBatchPrint() + // is called to print all delayed jobs. + // Returns false if failed or not supported (in which case endSpool() will print normally). + virtual bool startBatchPrint(); + // Actually spools all delayed print jobs, if enabled, and disables batch mode. + virtual bool flushBatchPrint(); + // Returns true batch printing is supported at all. + virtual bool supportsBatchPrint() const; + virtual ~PrinterInfoManager(); }; diff --git a/sw/source/uibase/dbui/dbmgr.cxx b/sw/source/uibase/dbui/dbmgr.cxx index af65b335fa8e..b01e2b29369f 100644 --- a/sw/source/uibase/dbui/dbmgr.cxx +++ b/sw/source/uibase/dbui/dbmgr.cxx @@ -135,6 +135,9 @@ #include <dbfld.hxx> #include <boost/scoped_ptr.hpp> +#include <config_cups.h> +#include <vcl/printerinfomanager.hxx> + using namespace ::osl; using namespace ::svx; @@ -820,6 +823,27 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, bool bNoError = true; const bool bEMail = rMergeDescriptor.nMergeType == DBMGR_MERGE_EMAIL; const bool bMergeShell = rMergeDescriptor.nMergeType == DBMGR_MERGE_SHELL; + bool bCreateSingleFile = rMergeDescriptor.bCreateSingleFile; + + if( rMergeDescriptor.nMergeType == DBMGR_MERGE_PRINTER ) + { + // It is possible to do MM printing in both modes for the same result, but the singlefile mode + // is slower because of all the temporary document copies and merging them together + // into the single file, while the other mode simply updates fields and prints for every record. + // However, this would cause one print job for every record, and e.g. CUPS refuses new jobs + // if it has many jobs enqueued (500 by default), and with the current printing framework + // (which uses a pull model) it's rather complicated to create a single print job + // in steps. + // To handle this, CUPS backend has been changed to cache all the documents to print + // and send them to CUPS only as one job at the very end. Therefore, with CUPS, it's ok + // to use the faster mode. As I have no idea about other platforms, keep them using + // the slower singlefile mode (or feel free to check them, or rewrite the printing code). +#if ENABLE_CUPS + bCreateSingleFile = !psp::PrinterInfoManager::get().supportsBatchPrint(); +#else + bCreateSingleFile = true; +#endif + } ::rtl::Reference< MailDispatcher > xMailDispatcher; OUString sBodyMimeType; @@ -937,7 +961,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, Application::Reschedule(); } - if(rMergeDescriptor.bCreateSingleFile) + if(bCreateSingleFile) { // create a target docshell to put the merged document into xTargetDocShell = new SwDocShell( SFX_CREATE_MODE_STANDARD ); @@ -1036,7 +1060,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, } // create a new temporary file name - only done once in case of bCreateSingleFile - if( createTempFile && ( 1 == nDocNo || !rMergeDescriptor.bCreateSingleFile )) + if( createTempFile && ( 1 == nDocNo || !bCreateSingleFile )) { INetURLObject aEntry(sPath); OUString sLeading; @@ -1086,7 +1110,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, // Create a copy of the source document and work with that one instead of the source. // If we're not in the single file mode (which requires modifying the document for the merging), // it is enough to do this just once. - if( 1 == nDocNo || rMergeDescriptor.bCreateSingleFile ) + if( 1 == nDocNo || bCreateSingleFile ) { assert( !xWorkDocSh.Is()); // copy the source document @@ -1117,7 +1141,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, rWorkShell.SwViewShell::UpdateFlds(); SfxGetpApp()->NotifyEvent(SfxEventHint(SW_EVENT_FIELD_MERGE_FINISHED, SwDocShell::GetEventName(STR_SW_EVENT_FIELD_MERGE_FINISHED), xWorkDocSh)); - if( rMergeDescriptor.bCreateSingleFile ) + if( bCreateSingleFile ) pWorkDoc->RemoveInvisibleContent(); // launch MailMergeEvent if required @@ -1129,7 +1153,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, pEvtSrc->LaunchMailMergeEvent( aEvt ); } - if(rMergeDescriptor.bCreateSingleFile) + if(bCreateSingleFile) { OSL_ENSURE( pTargetShell, "no target shell available!" ); // copy created file into the target document @@ -1162,6 +1186,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, } else if( rMergeDescriptor.nMergeType == DBMGR_MERGE_PRINTER ) { + assert(!bCreateSingleFile); if( 1 == nDocNo ) // set up printing only once at the beginning { // printing should be done synchronously otherwise the document @@ -1191,6 +1216,9 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, SfxPrinter* pDocPrt = pWorkView->GetPrinter(false); JobSetup aJobSetup = pDocPrt ? pDocPrt->GetJobSetup() : pWorkView->GetJobSetup(); Printer::PreparePrintJob( pWorkView->GetPrinterController(), aJobSetup ); +#if ENABLE_CUPS + psp::PrinterInfoManager::get().startBatchPrint(); +#endif } if( !Printer::ExecutePrintJob( pWorkView->GetPrinterController())) bCancel = true; @@ -1324,7 +1352,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, } } } - if( rMergeDescriptor.bCreateSingleFile ) + if( bCreateSingleFile ) { pWorkDoc->SetDBManager( pOldDBManager ); xWorkDocSh->DoClose(); @@ -1337,7 +1365,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, // Freeze the layouts of the target document after the first inserted // sub-document, to get the correct PageDesc. - if(!bFreezedLayouts && (rMergeDescriptor.bCreateSingleFile)) + if(!bFreezedLayouts && bCreateSingleFile) { std::set<SwRootFrm*> aAllLayouts = pTargetShell->GetDoc()->GetAllLayouts(); std::for_each( aAllLayouts.begin(), aAllLayouts.end(), @@ -1347,15 +1375,20 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, } while( !bCancel && (bSynchronizedDoc && (nStartRow != nEndRow)? ExistsNextRecord() : ToNextMergeRecord())); - if( !rMergeDescriptor.bCreateSingleFile ) + if( !bCreateSingleFile ) { if( rMergeDescriptor.nMergeType == DBMGR_MERGE_PRINTER ) + { Printer::FinishPrintJob( pWorkView->GetPrinterController()); +#if ENABLE_CUPS + psp::PrinterInfoManager::get().flushBatchPrint(); +#endif + } pWorkDoc->SetDBManager( pOldDBManager ); xWorkDocSh->DoClose(); } - if (rMergeDescriptor.bCreateSingleFile) + if (bCreateSingleFile) { // sw::DocumentLayoutManager::CopyLayoutFmt() did not generate // unique fly names, do it here once. @@ -1367,7 +1400,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, Application::Reschedule(); // Unfreeze target document layouts and correct all PageDescs. - if(rMergeDescriptor.bCreateSingleFile) + if(bCreateSingleFile) { pTargetShell->CalcLayout(); std::set<SwRootFrm*> aAllLayouts = pTargetShell->GetDoc()->GetAllLayouts(); @@ -1383,7 +1416,7 @@ bool SwDBManager::MergeMailFiles(SwWrtShell* pSourceShell, { rMergeDescriptor.pMailMergeConfigItem->SetTargetView( pTargetView ); } - else if(rMergeDescriptor.bCreateSingleFile) + else if(bCreateSingleFile) { if( rMergeDescriptor.nMergeType != DBMGR_MERGE_PRINTER ) { diff --git a/vcl/inc/cupsmgr.hxx b/vcl/inc/cupsmgr.hxx index c7b948737f05..4db4c1d5e0c7 100644 --- a/vcl/inc/cupsmgr.hxx +++ b/vcl/inc/cupsmgr.hxx @@ -58,6 +58,23 @@ class CUPSManager : public PrinterInfoManager osl::Mutex m_aGetPPDMutex; bool m_bPPDThreadRunning; + struct PendingJob + { + OUString printerName; + OUString jobTitle; + JobData jobData; + bool banner; + OUString faxNumber; + OString file; + PendingJob( const OUString& printerName_, const OUString& jobTitle_, const JobData& jobData_, + bool banner_, const OUString& faxNumber_, const OString& file_ ) + : printerName( printerName_ ), jobTitle( jobTitle_ ), jobData( jobData_ ), banner( banner_ ), faxNumber( faxNumber_ ), file( file_ ) + {} + PendingJob() : banner( false ) {} + }; + std::list< PendingJob > pendingJobs; + bool batchMode; + CUPSManager(); virtual ~CUPSManager(); @@ -66,6 +83,9 @@ class CUPSManager : public PrinterInfoManager void getOptionsFromDocumentSetup( const JobData& rJob, bool bBanner, int& rNumOptions, void** rOptions ) const; void runDests(); OString threadedCupsGetPPD(const char* pPrinter); + + bool processPendingJobs(); + bool printJobs( const PendingJob& job, const std::vector< OString >& files ); public: static void runDestThread(void* pMgr); @@ -80,6 +100,10 @@ public: virtual bool endSpool( const OUString& rPrinterName, const OUString& rJobTitle, FILE* pFile, const JobData& rDocumentJobData, bool bBanner, const OUString& rFaxNumber ) SAL_OVERRIDE; virtual void setupJobContextData( JobData& rData ) SAL_OVERRIDE; + virtual bool startBatchPrint() SAL_OVERRIDE; + virtual bool flushBatchPrint() SAL_OVERRIDE; + virtual bool supportsBatchPrint() const SAL_OVERRIDE; + /// changes the info about a named printer virtual void changePrinterInfo( const OUString& rPrinter, const PrinterInfo& rNewInfo ) SAL_OVERRIDE; diff --git a/vcl/unx/generic/printer/cupsmgr.cxx b/vcl/unx/generic/printer/cupsmgr.cxx index 2dc978ad0e40..3ea62b0d1f53 100644 --- a/vcl/unx/generic/printer/cupsmgr.cxx +++ b/vcl/unx/generic/printer/cupsmgr.cxx @@ -626,8 +626,6 @@ bool CUPSManager::endSpool( const OUString& rPrintername, const OUString& rJobTi rDocumentJobData.m_nCopies ); - int nJobID = 0; - osl::MutexGuard aGuard( m_aCUPSMutex ); std::unordered_map< OUString, int, OUStringHash >::iterator dest_it = @@ -639,32 +637,105 @@ bool CUPSManager::endSpool( const OUString& rPrintername, const OUString& rJobTi } std::unordered_map< FILE*, OString, FPtrHash >::const_iterator it = m_aSpoolFiles.find( pFile ); - if( it != m_aSpoolFiles.end() ) + if( it == m_aSpoolFiles.end() ) + return false; + fclose( pFile ); + PendingJob job( rPrintername, rJobTitle, rDocumentJobData, bBanner, rFaxNumber, it->second ); + m_aSpoolFiles.erase( pFile ); + pendingJobs.push_back( job ); + if( !batchMode ) // process immediately, otherwise will be handled by flushBatchPrint() + return processPendingJobs(); + return true; +} + +bool CUPSManager::startBatchPrint() +{ + batchMode = true; + return true; +} + +bool CUPSManager::supportsBatchPrint() const +{ + return true; +} + +bool CUPSManager::flushBatchPrint() +{ + osl::MutexGuard aGuard( m_aCUPSMutex ); + return processPendingJobs(); +} + +bool CUPSManager::processPendingJobs() +{ + // Print all jobs that have the same data using one CUPS call (i.e. merge all jobs that differ only in files to print). + PendingJob currentJobData; + bool first = true; + std::vector< OString > files; + bool ok = true; + while( !pendingJobs.empty()) + { + if( first ) + { + currentJobData = pendingJobs.front(); + first = false; + } + else if( currentJobData.printerName != pendingJobs.front().printerName + || currentJobData.jobTitle != pendingJobs.front().jobTitle + || currentJobData.jobData != pendingJobs.front().jobData + || currentJobData.banner != pendingJobs.front().banner ) + { + if( !printJobs( currentJobData, files )) + ok = false; + files.clear(); + currentJobData = pendingJobs.front(); + } + files.push_back( pendingJobs.front().file ); + pendingJobs.pop_front(); + } + if( !first ) { - fclose( pFile ); + if( !printJobs( currentJobData, files )) // print the last batch + ok = false; + } + return ok; +} + +bool CUPSManager::printJobs( const PendingJob& job, const std::vector< OString >& files ) +{ + std::unordered_map< OUString, int, OUStringHash >::iterator dest_it = + m_aCUPSDestMap.find( job.printerName ); + rtl_TextEncoding aEnc = osl_getThreadTextEncoding(); // setup cups options int nNumOptions = 0; cups_option_t* pOptions = NULL; - getOptionsFromDocumentSetup( rDocumentJobData, bBanner, nNumOptions, reinterpret_cast<void**>(&pOptions) ); + getOptionsFromDocumentSetup( job.jobData, job.banner, nNumOptions, reinterpret_cast<void**>(&pOptions) ); - OString sJobName(OUStringToOString(rJobTitle, aEnc)); + OString sJobName(OUStringToOString(job.jobTitle, aEnc)); //fax4CUPS, "the job name will be dialled for you" //so override the jobname with the desired number - if (!rFaxNumber.isEmpty()) + if (!job.faxNumber.isEmpty()) { - sJobName = OUStringToOString(rFaxNumber, aEnc); + sJobName = OUStringToOString(job.faxNumber, aEnc); } cups_dest_t* pDest = ((cups_dest_t*)m_pDests) + dest_it->second; - nJobID = cupsPrintFile(pDest->name, - it->second.getStr(), + + std::vector< const char* > fnames; + for( std::vector< OString >::const_iterator it = files.begin(); + it != files.end(); + ++it ) + fnames.push_back( it->getStr()); + + int nJobID = cupsPrintFiles(pDest->name, + fnames.size(), + fnames.data(), sJobName.getStr(), nNumOptions, pOptions); SAL_INFO("vcl.unx.print", "cupsPrintFile( " << pDest->name << ", " - << it->second << ", " << rJobTitle << ", " << nNumOptions + << ( fnames.size() == 1 ? files.front() : OString::number( fnames.size()) ).getStr() << ", " << sJobName << ", " << nNumOptions << ", " << pOptions << " ) returns " << nJobID); for( int n = 0; n < nNumOptions; n++ ) SAL_INFO("vcl.unx.print", @@ -676,11 +747,13 @@ bool CUPSManager::endSpool( const OUString& rPrintername, const OUString& rJobTi system( aCmd.getStr() ); #endif - unlink( it->second.getStr() ); - m_aSpoolFiles.erase( pFile ); + for( std::vector< OString >::const_iterator it = files.begin(); + it != files.end(); + ++it ) + unlink( it->getStr()); + if( pOptions ) cupsFreeOptions( nNumOptions, pOptions ); - } return nJobID != 0; } diff --git a/vcl/unx/generic/printer/jobdata.cxx b/vcl/unx/generic/printer/jobdata.cxx index ae7604098065..dacf2e2c1d7d 100644 --- a/vcl/unx/generic/printer/jobdata.cxx +++ b/vcl/unx/generic/printer/jobdata.cxx @@ -53,6 +53,24 @@ JobData& JobData::operator=(const JobData& rRight) return *this; } +bool psp::operator==(const psp::JobData& rLeft, const psp::JobData& rRight) +{ + return rLeft.m_nCopies == rRight.m_nCopies +// && rLeft.m_bCollate == rRight.m_bCollate + && rLeft.m_nLeftMarginAdjust == rRight.m_nLeftMarginAdjust + && rLeft.m_nRightMarginAdjust == rRight.m_nRightMarginAdjust + && rLeft.m_nTopMarginAdjust == rRight.m_nTopMarginAdjust + && rLeft.m_nBottomMarginAdjust == rRight.m_nBottomMarginAdjust + && rLeft.m_nColorDepth == rRight.m_nColorDepth + && rLeft.m_eOrientation == rRight.m_eOrientation + && rLeft.m_aPrinterName == rRight.m_aPrinterName + && rLeft.m_pParser == rRight.m_pParser +// && rLeft.m_aContext == rRight.m_aContext + && rLeft.m_nPSLevel == rRight.m_nPSLevel + && rLeft.m_nPDFDevice == rRight.m_nPDFDevice + && rLeft.m_nColorDevice == rRight.m_nColorDevice; +} + void JobData::setCollate( bool bCollate ) { if (m_nPDFDevice > 0) diff --git a/vcl/unx/generic/printer/printerinfomanager.cxx b/vcl/unx/generic/printer/printerinfomanager.cxx index 2690c881bd02..0c9ed6369f74 100644 --- a/vcl/unx/generic/printer/printerinfomanager.cxx +++ b/vcl/unx/generic/printer/printerinfomanager.cxx @@ -933,6 +933,21 @@ void PrinterInfoManager::setDefaultPaper( PPDContext& rContext ) const } } +bool PrinterInfoManager::startBatchPrint() +{ + return false; // not implemented +} + +bool PrinterInfoManager::supportsBatchPrint() const +{ + return false; +} + +bool PrinterInfoManager::flushBatchPrint() +{ + return false; +} + SystemQueueInfo::SystemQueueInfo() : m_bChanged( false ) { |