summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2015-02-26 15:56:24 +0100
committerMiklos Vajna <vmiklos@collabora.co.uk>2015-03-11 16:21:43 +0100
commit138d29aa09417eba4d15ade4c9f4dab2620b6326 (patch)
tree315abb86be92a0f871780912167a611fec7c4d8f
parente0ad036eed6b151ea81311fcf9ba46f1726b103c (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.in6
-rw-r--r--configure.ac3
-rw-r--r--include/vcl/jobdata.hxx6
-rw-r--r--include/vcl/printerinfomanager.hxx10
-rw-r--r--sw/source/uibase/dbui/dbmgr.cxx55
-rw-r--r--vcl/inc/cupsmgr.hxx24
-rw-r--r--vcl/unx/generic/printer/cupsmgr.cxx101
-rw-r--r--vcl/unx/generic/printer/jobdata.cxx18
-rw-r--r--vcl/unx/generic/printer/printerinfomanager.cxx15
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 )
{