Index: vcl/unx/source/gdi/makefile.mk =================================================================== RCS file: /cvs/gsl/vcl/unx/source/gdi/makefile.mk,v retrieving revision 1.9 diff -u -p -u -r1.9 makefile.mk --- vcl/unx/source/gdi/makefile.mk 27 Aug 2002 14:52:35 -0000 1.9 +++ vcl/unx/source/gdi/makefile.mk 29 May 2003 15:44:36 -0000 @@ -103,7 +103,8 @@ SLOFILES= \ CFLAGS+=-D_USE_PRINT_EXTENSION_=1 SLOFILES+=$(SLO)$/xprintext.obj .ELSE -SLOFILES+=$(SLO)$/salprnpsp.obj +CFLAGS+= `pkg-config --cflags libgnomecups-1.0` +SLOFILES+=$(SLO)$/salprncups.obj .ENDIF .IF "$(OS)"=="SOLARIS" Index: vcl/unx/inc/salprn.h =================================================================== RCS file: /cvs/gsl/vcl/unx/inc/salprn.h,v retrieving revision 1.9 diff -u -p -u -r1.9 salprn.h --- vcl/unx/inc/salprn.h 13 Nov 2002 20:24:03 -0000 1.9 +++ vcl/unx/inc/salprn.h 2 Jun 2003 11:56:15 -0000 @@ -85,8 +85,10 @@ struct SalInfoPrinterData struct SalPrinterData { + ULONG m_nError; String m_aFileName; String m_aTmpFile; + String m_aJobName; String m_aFaxNr; bool m_bFax:1; bool m_bPdf:1; @@ -95,7 +97,8 @@ struct SalPrinterData ::psp::PrinterJob m_aPrintJob; ::psp::JobData m_aJobData; ::psp::PrinterGfx m_aPrinterGfx; - ULONG m_nCopies; + ULONG m_nCopies; + bool isPrintToFile() { return m_aFileName.Len() > 0; } }; class Timer; --- /dev/null 2003-01-30 10:24:37.000000000 +0000 +++ vcl/unx/source/gdi/salprncups.cxx 2003-05-29 16:48:01.000000000 +0100 @@ -0,0 +1,1396 @@ +/************************************************************************* + * + * $RCSfile$ + * + * $Revision$ + * + * last change: $Author$ $Date$ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +/** + this file implements the sal printer interface ( SalPrinter, SalInfoPrinter + and some printer relevant methods of SalInstance and SalGraphicsData ) + + as aunderlying library the printer features of psprint are used. + + The query methods of a SalInfoPrinter are implemented by querying psprint + + The job methods of a SalPrinter are implemented by calling psprint + printer job functions. + */ + +#include +#include +#include + +#ifndef _SV_JOBSET_H +#include +#endif +#ifndef _SV_SALINST_HXX +#include +#endif +#ifndef _SV_SALPRN_HXX +#include +#endif +#ifndef _SV_SALGDI_HXX +#include +#endif +#ifndef _SV_PRINT_H +#include +#endif +#ifndef _SV_SALPTYPE_HXX +#include +#endif +#ifndef _SV_SALFRAME_HXX +#include +#endif +#ifndef _SV_SALDATA_HXX +#include +#endif + +#include +#include +#include +#include + +#include + +#include + +#ifndef _PSPRINT_JOBDATA_HXX_ +#include +#endif + +#include +#include + +static bool cups_debug = false; + +namespace cups { }; + +using namespace cups; +using namespace psp; +using namespace rtl; +using namespace osl; + +namespace cups { + + class PrinterInfoManagerCups : ::psp::PrinterInfoManager + { + PrinterInfoManagerCups(); + void initialize (); + + ::psp::JobData m_aGlobalDefaults; + ::rtl::OUString m_aDefaultPrinter; + GList *m_aPrinterList; + ::std::hash_map< ::rtl::OUString, ::psp::JobData, ::rtl::OUStringHash > m_aJobDataCache; + + private: + void mergeToJobData ( ::psp::JobData &rJobInfo, const PPDParser *pParser ); + void mergeCupsSettings ( ::psp::JobData &rJobInfo ); + public: + String m_aGlobalDriverName; + static PrinterInfoManagerCups& getCups(); + + bool isBuiltinGeneric() { return m_aPrinterList == NULL; }; + + void listPrinters ( ::std::list< ::rtl::OUString >& rList ) const; + ::psp::JobData getJobInfo ( const ::rtl::OUString& rPrinter ); + SalPrinterQueueInfo *getSalPrinterQueueInfo ( const ::rtl::OUString& rPrinter ); + bool checkPrintersChanged (); + GnomeCupsPrinter *getGnomePrinter ( const ::rtl::OUString& rPrinter ); + GnomeCupsPrinter *getGnomePrinter ( SalPrinterQueueInfo *aQueueInfo ) + { return getGnomePrinter ( aQueueInfo->maPrinterName ); } + const ::rtl::OUString& getDefaultPrinter () const + { return m_aDefaultPrinter; } + virtual const PPDParser *getParserForPrinter( ::rtl::OUString rPrinter ); + virtual ::std::hash_map< fontID, fontID > *getFontSubstitutesForPrinter( ::rtl::OUString rPrinter ); + virtual FILE *getPipeToPrinter( ::rtl::OUString rPrinter ); + }; + + PrinterInfoManagerCups& PrinterInfoManagerCups::getCups() + { + static PrinterInfoManagerCups aManager; + set( &aManager ); + return aManager; + } + + extern "C" { + static gboolean + gcups_password_cb (const char *prompt, + char **username, + char **password, + GnomeCupsAuthContext *ctxt) + { + fprintf( stderr, "No authentication yet\n" ); + return FALSE; + } + } + + PrinterInfoManagerCups::PrinterInfoManagerCups() + { + static bool cups_initialized = false; + if (!cups_initialized) { + cups_initialized = true; + gnome_cups_init( gcups_password_cb ); + if (g_getenv ("CUPS_DEBUG") && + atoi (g_getenv ("CUPS_DEBUG"))) + cups_debug = true; + } + initialize (); + } + + const ::psp::PPDParser * + PrinterInfoManagerCups::getParserForPrinter( ::rtl::OUString rPrinter ) + { + return getJobInfo( rPrinter ).m_pParser; + } + + ::std::hash_map< fontID, fontID > * + PrinterInfoManagerCups::getFontSubstitutesForPrinter( ::rtl::OUString rPrinter ) + { // font mapping tables are a terrible idea. + return NULL; + } + + FILE * + PrinterInfoManagerCups::getPipeToPrinter( ::rtl::OUString rPrinter ) + { // we always print to a file + return NULL; + } + + bool PrinterInfoManagerCups::checkPrintersChanged() + { + bool different = false; + GList *printers; + + /* gnome-cups does timeout polling */ + printers = gnome_cups_get_printers (); + if (g_list_length (printers) != g_list_length (m_aPrinterList)) + different = true; + else { + GList *l1, *l2; + for (l2 = m_aPrinterList, l1 = printers; + l1 && l2; l1 = l1->next, l2 = l2->next) { + if (strcmp ((char *) l1->data, (char *) l2->data)) { + different = true; + break; + } + } + } + + if (different) + initialize (); + + return different; + } + + void PrinterInfoManagerCups::initialize() + { + rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); + OUString aPrinterPath( getPrinterPath() ); + m_aJobDataCache.clear(); + + // first initialize the global defaults + m_aGlobalDefaults = JobData(); + m_aGlobalDriverName = String( RTL_CONSTASCII_USTRINGPARAM( "CUPS" ) ); + + // g_warning ("We need to parse SGEN43.PS ... - how can we ship that ?"); + // need a parser for the PPDContext. generic printer should do. + m_aGlobalDefaults.m_pParser = PPDParser::getParser + ( String( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) ); + m_aGlobalDefaults.m_aContext.setParser( m_aGlobalDefaults.m_pParser ); + + if( ! m_aGlobalDefaults.m_pParser ) + { + fprintf( stderr, "Error: no SGENPRT available, shutting down psprint...\n" ); + // return; + } + + char *prnt; + if (!(prnt = gnome_cups_get_default())) + prnt = g_strdup("GenericPostscript"); + m_aDefaultPrinter = OUString( prnt, strlen( prnt ), RTL_TEXTENCODING_UTF8 ); + g_free( prnt ); + + gnome_cups_printer_list_free( m_aPrinterList ); + m_aPrinterList = gnome_cups_get_printers(); + } + + void + PrinterInfoManagerCups::listPrinters( ::std::list< OUString >& rList ) const + { + GList *l; + + rList.clear(); + if (m_aPrinterList) + { + for (l = m_aPrinterList; l; l = l->next) + rList.push_back( OUString( (char *)l->data, + strlen( (char *) l->data ), + RTL_TEXTENCODING_UTF8 ) ); + } + else + { + rList.push_back( ::rtl::OUString::createFromAscii( "GenericPostscript" ) ); + } + } + + GnomeCupsPrinter * + PrinterInfoManagerCups::getGnomePrinter ( const ::rtl::OUString& rPrinter ) + { + if (isBuiltinGeneric()) + return NULL; + else + { + OString name = OUStringToOString( rPrinter, RTL_TEXTENCODING_UTF8 ); + return gnome_cups_printer_get (name.getStr()); + } + } + + SalPrinterQueueInfo* + PrinterInfoManagerCups::getSalPrinterQueueInfo ( const ::rtl::OUString& rPrinter ) + { + GnomeCupsPrinter *printer = getGnomePrinter( rPrinter ); + + OString name = OUStringToOString( rPrinter, RTL_TEXTENCODING_UTF8 ); + // fprintf (stderr, "Add printer '%s'\n", name.getStr()); + + SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo; + pInfo->maPrinterName = OUString (rPrinter); + pInfo->maDriver = m_aGlobalDriverName; + pInfo->maLocation = String + ( printer ? gnome_cups_printer_get_location( printer ) : "", RTL_TEXTENCODING_UTF8); + pInfo->maComment = String + ( printer ? gnome_cups_printer_get_description (printer) : "", RTL_TEXTENCODING_UTF8); + pInfo->mpSysData = NULL; + pInfo->mnJobs = printer ? gnome_cups_printer_get_job_count (printer) : 0; + + gnome_cups_printer_unref( printer ); + + return pInfo; + } + + + void + PrinterInfoManagerCups::mergeToJobData ( ::psp::JobData &rJobInfo, + const PPDParser *pParser ) + { + rJobInfo.m_pParser = pParser; + rJobInfo.m_aContext.setParser( pParser ); + + // merge the ppd context keys if the printer has the same keys and values + // this is a bit tricky, since it involves mixing two PPDs + // without constraints which might end up badly + // this feature should be use with caution + // it is mainly to select default paper sizes for new printers + for( int nPPDValueModified = 0; nPPDValueModified < m_aGlobalDefaults.m_aContext.countValuesModified(); nPPDValueModified++ ) + { + const PPDKey* pDefKey = m_aGlobalDefaults.m_aContext.getModifiedKey( nPPDValueModified ); + const PPDValue* pDefValue = m_aGlobalDefaults.m_aContext.getValue( pDefKey ); + const PPDKey* pPrinterKey = pDefKey ? rJobInfo.m_pParser->getKey( pDefKey->getKey() ) : NULL; + if( pDefKey && pPrinterKey ) + // at least the options exist in both PPDs + { + if( pDefValue ) + { + const PPDValue* pPrinterValue = pPrinterKey->getValue( pDefValue->m_aOption ); + if( pPrinterValue ) + // the printer has a corresponding option for the key + rJobInfo.m_aContext.setValue( pPrinterKey, pPrinterValue ); + } + else + rJobInfo.m_aContext.setValue( pPrinterKey, NULL ); + } + } + } + + void + PrinterInfoManagerCups::mergeCupsSettings( ::psp::JobData &rJobInfo ) + { + GnomeCupsPrinter *printer; + + printer = getGnomePrinter( rJobInfo.m_aPrinterName ); + + if( cups_debug ) { + gnome_cups_printer_force_refresh( printer, GNOME_CUPS_PRINTER_REFRESH_OPTIONS ); + g_warning ("Forced printer option refresh"); + } + + // Set the local cups options + if (printer) + { + if (cups_debug) + g_warning ("Refreshing user options ..."); + + GList *user_options = gnome_cups_printer_get_options (printer); + + for (GList *l = user_options; l; l = l->next) + { + GnomeCupsPrinterOptionChoice *opt = (GnomeCupsPrinterOptionChoice *) l->data; + + char *value = gnome_cups_printer_get_option_value (printer, opt->value); + + if (cups_debug) + g_warning (" '%s' -> '%s'", opt->value, value); + + if (!opt->text || !value) + continue; + + const PPDKey* pKey; + + pKey = rJobInfo.m_pParser->getKey( String::CreateFromAscii( opt->value ) ); + if (pKey) { + const PPDValue* pValue; + + pValue = pKey->getValue( String( value, RTL_TEXTENCODING_UTF8 ) ); + + if (pValue) + rJobInfo.m_aContext.setValue( pKey, pValue ); + + else if (cups_debug) + g_warning ("No value '%s'", value); + + } else if (cups_debug) + g_warning ("No key '%s'", opt->value); + } + gnome_cups_printer_option_list_free (user_options); + + gnome_cups_printer_unref( printer ); + } + else if (cups_debug) + g_warning ("No printer"); + } + + ::psp::JobData + PrinterInfoManagerCups::getJobInfo( const ::rtl::OUString& rPrinter ) + { + ::std::hash_map< OUString, ::psp::JobData, OUStringHash >::const_iterator it = m_aJobDataCache.find( rPrinter ); + + if (it != m_aJobDataCache.end()) { + ::psp::JobData aJobInfo = it->second; + mergeCupsSettings( aJobInfo ); + + return aJobInfo; + } + + ::psp::JobData aJobInfo = m_aGlobalDefaults; + + OString name = OUStringToOString( rPrinter, RTL_TEXTENCODING_UTF8 ); + + aJobInfo.m_aPrinterName = OUString (rPrinter); + + const char *v; + if( cups_debug && (v = g_getenv( "PPD_DO" )) && atoi( v ) ) + g_warning ("--- ppd parsing disabled ---"); + else + { + GnomeCupsPrinter *printer = NULL; + GnomeCupsPPDFile *ppd_file = NULL; + char *ppd_fname = NULL; + const PPDParser *pParser = NULL; + + if ( ( printer = getGnomePrinter( rPrinter ) ) && + ( ppd_file = gnome_cups_printer_get_ppd_file( printer ) ) && + ( ppd_fname = gnome_cups_ppd_file_get_name( ppd_file ) ) && + ( pParser = PPDParser::getParser ( String( ppd_fname, RTL_TEXTENCODING_UTF8 ) ) ) && + pParser ) + { + if (cups_debug) + g_warning ("---- parse ppd ...----"); + mergeToJobData (aJobInfo, pParser); + } + else if (cups_debug) + g_warning ("---- failed to parse ppd '%s' ----", ppd_fname); + + g_free( ppd_fname ); + gnome_cups_ppd_file_release( ppd_file ); + gnome_cups_printer_unref( printer ); + } + + mergeCupsSettings( aJobInfo ); + + + m_aJobDataCache[ rPrinter ] = aJobInfo; + + return aJobInfo; + } + +} /* namespace cups */ + +inline int PtTo10Mu( int nPoints ) { return (int)(((double)nPoints)*35.27777778)+0.5; } + +inline int TenMuToPt( int nUnits ) { return (int)(((double)nUnits)/35.27777778)+0.5; } + +static struct +{ + int width; + int height; + const char* name; + int namelength; + Paper paper; +} aPaperTab[] = +{ + { 29700, 42000, "A3", 2, PAPER_A3 }, + { 21000, 29700, "A4", 2, PAPER_A4 }, + { 14800, 21000, "A5", 2, PAPER_A5 }, + { 25000, 35300, "B4", 2, PAPER_B4 }, + { 17600, 25000, "B5", 2, PAPER_B5 }, + { 21600, 27900, "Letter", 6, PAPER_LETTER }, + { 21600, 35600, "Legal", 5, PAPER_LEGAL }, + { 27900, 43100, "Tabloid", 7, PAPER_TABLOID }, + { 0, 0, "USER", 4, PAPER_USER } +}; + +static Paper getPaperType( const String& rPaperName ) +{ + ByteString aPaper( rPaperName, RTL_TEXTENCODING_ISO_8859_1 ); + for( int i = 0; i < sizeof( aPaperTab )/sizeof( aPaperTab[0] ); i++ ) + { + if( ! strcmp( aPaper.GetBuffer(), aPaperTab[i].name ) ) + return aPaperTab[i].paper; + } + return PAPER_USER; +} + +static void copyJobDataToJobSetup( ImplJobSetup* pJobSetup, JobData& rData ) +{ + + pJobSetup->meOrientation = (Orientation)(rData.m_eOrientation == orientation::Landscape ? + ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT); + + // copy page size + String aPaper; + int width, height; + + rData.m_aContext.getPageSize( aPaper, width, height ); + pJobSetup->mePaperFormat = getPaperType( aPaper ); + pJobSetup->mnPaperWidth = 0; + pJobSetup->mnPaperHeight = 0; + if( pJobSetup->mePaperFormat == PAPER_USER ) + { + // transform to 100dth mm + width = PtTo10Mu( width ); + height = PtTo10Mu( height ); + + if( rData.m_eOrientation == psp::orientation::Portrait ) + { + pJobSetup->mnPaperWidth = width; + pJobSetup->mnPaperHeight = height; + } + else + { + pJobSetup->mnPaperWidth = height; + pJobSetup->mnPaperHeight = width; + } + } + + // copy input slot + const PPDKey* pKey; + const PPDValue* pValue; + ::std::list< const PPDValue* > aValues; + ::std::list< const PPDValue* >::iterator it; + + pKey = rData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ); + pValue = rData.m_aContext.getValue( pKey ); + rData.m_aContext.getUnconstrainedValues( pKey, aValues ); + pJobSetup->mnPaperBin = 0xffff; + if ( pKey && pValue ) + { + for( pJobSetup->mnPaperBin = 0; + pValue != pKey->getValue( pJobSetup->mnPaperBin ) && + pJobSetup->mnPaperBin < pKey->countValues(); + pJobSetup->mnPaperBin++ ) + ; + if( pJobSetup->mnPaperBin >= pKey->countValues() || pValue == pKey->getDefaultValue() ) + pJobSetup->mnPaperBin = 0xffff; + } + for( it = aValues.begin(); it != aValues.end(); ++it, pJobSetup->mnPaperBin++ ) + if( *it == pValue ) + break; + if( it == aValues.end() ) + pJobSetup->mnPaperBin = 0xffff; + + // copy the whole context + if( pJobSetup->mpDriverData ) + rtl_freeMemory( pJobSetup->mpDriverData ); + + int nBytes; + void* pBuffer = NULL; + if( rData.getStreamBuffer( pBuffer, nBytes ) ) + { + pJobSetup->mnDriverDataLen = nBytes; + pJobSetup->mpDriverData = (BYTE*)pBuffer; + } + else + { + pJobSetup->mnDriverDataLen = 0; + pJobSetup->mpDriverData = NULL; + } +} + +/* + * SalInstance + */ + +// ----------------------------------------------------------------------- + +SalInfoPrinter* SalInstance::CreateInfoPrinter( + SalPrinterQueueInfo *pQueueInfo, + ImplJobSetup *pJobSetup ) +{ + maInstData.mbPrinterInit = true; + + SalInfoPrinter* pPrinter = new SalInfoPrinter; + PrinterInfoManagerCups& rManager( PrinterInfoManagerCups::getCups() ); + ::psp::JobData aJobInfo = rManager.getJobInfo( pQueueInfo->maPrinterName ); + + pPrinter->maPrinterData.m_aJobData = aJobInfo; + pPrinter->maPrinterData.m_aPrinterGfx.Init( pPrinter->maPrinterData.m_aJobData ); + + if( pJobSetup ) + { + if( pJobSetup->mpDriverData ) + JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, + pJobSetup->mnDriverDataLen, + aJobInfo ); + + pJobSetup->mnSystem = JOBSETUP_SYSTEM_UNIX; + pJobSetup->maPrinterName = pQueueInfo->maPrinterName; + pJobSetup->maDriver = rManager.m_aGlobalDriverName; + copyJobDataToJobSetup( pJobSetup, aJobInfo ); + } + + return pPrinter; +} + +// ----------------------------------------------------------------------- + +void SalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter ) +{ + delete pPrinter; +} + +// ----------------------------------------------------------------------- + +SalPrinter* SalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter ) +{ + maInstData.mbPrinterInit = true; + // create and initialize SalPrinter + SalPrinter* pPrinter = new SalPrinter; + pPrinter->maPrinterData.m_aJobData = pInfoPrinter->maPrinterData.m_aJobData; + + return pPrinter; +} + +// ----------------------------------------------------------------------- + +void SalInstance::DestroyPrinter( SalPrinter* pPrinter ) +{ + delete pPrinter; +} + +// ----------------------------------------------------------------------- + +void SalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList ) +{ + maInstData.mbPrinterInit = true; + PrinterInfoManagerCups& rManager( PrinterInfoManagerCups::getCups() ); + ::std::list< OUString > aPrinters; + rManager.listPrinters( aPrinters ); + + for( ::std::list< OUString >::iterator it = aPrinters.begin(); it != aPrinters.end(); ++it ) { + SalPrinterQueueInfo *pInfo = rManager.getSalPrinterQueueInfo( *it ); + GetPrinterQueueState( pInfo ); + pList->Add( pInfo ); + } +} + +// ----------------------------------------------------------------------- + +void SalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo ) +{ + delete pInfo; +} + +// ----------------------------------------------------------------------- + +void SalInstance::GetPrinterQueueState( SalPrinterQueueInfo* pInfo ) +{ + if (!pInfo) + return; + + GnomeCupsPrinter *printer; + printer = PrinterInfoManagerCups::getCups().getGnomePrinter( pInfo ); + if (!printer) + { + pInfo->mnStatus = QUEUE_STATUS_READY; + return; + } + + switch (gnome_cups_printer_get_state (printer)) { + case IPP_PRINTER_IDLE: + pInfo->mnStatus = QUEUE_STATUS_READY; + break; + case IPP_PRINTER_PROCESSING: + pInfo->mnStatus = QUEUE_STATUS_PROCESSING; + break; + case IPP_PRINTER_STOPPED: + default: + pInfo->mnStatus = QUEUE_STATUS_ERROR; + + GList *l, *reasons = gnome_cups_printer_get_state_reasons (printer); + if (!reasons || !reasons->data) + break; + + pInfo->mnStatus = 0; + for (l = reasons; l; l = l->next) { + GnomeCupsPrinterReason *reason = (GnomeCupsPrinterReason *) reasons->data; + +#define MAP_STATUS(str,en) \ + if (!strcmp (reason->keyword, (str))) \ + pInfo->mnStatus |= QUEUE_STATUS_##en; + + /* cf. RFC 2911.txt 4.4.12 */ + MAP_STATUS ("stopping", PENDING_DELETION); + MAP_STATUS ("timed-out", ERROR); + MAP_STATUS ("media-empty", PAPER_PROBLEM); + MAP_STATUS ("connecting-to-device", IO_ACTIVE); + MAP_STATUS ("output-tray-area-full", OUTPUT_BIN_FULL); + MAP_STATUS ("marker-supply-low", TONER_LOW); + MAP_STATUS ("marker-supply-empty", NO_TONER); + MAP_STATUS ("developer-low", TONER_LOW); + MAP_STATUS ("developer-empty", NO_TONER); + MAP_STATUS ("marker-waste-full", USER_INTERVENTION); + MAP_STATUS ("door-open", DOOR_OPEN); + MAP_STATUS ("cover-open", DOOR_OPEN); + MAP_STATUS ("interlock-open", DOOR_OPEN); + MAP_STATUS ("input-tray-missing", DOOR_OPEN); + MAP_STATUS ("output-tray-missing", DOOR_OPEN); + MAP_STATUS ("none", ERROR); // ? + MAP_STATUS ("other", ERROR); + MAP_STATUS ("paused", PAUSED); + MAP_STATUS ("moving-to-paused", PAUSED); + MAP_STATUS ("shutdown", OFFLINE); + MAP_STATUS ("media-jam", PAPER_JAM); + MAP_STATUS ("media-needed", PAPER_OUT); + MAP_STATUS ("media-low", READY); // PAPER_PROBLEM + MAP_STATUS ("output-tray-area-almost-full", READY); // OUTPUT_BIN_FULL + MAP_STATUS ("marker-waste-almost-full", READY); // USER_INTERVENTION +#undef MAP_STATUS + } + + if ( !pInfo->mnStatus ) + pInfo->mnStatus = QUEUE_STATUS_ERROR; + + gnome_cups_printer_free_reasons( reasons ); + break; + } + gnome_cups_printer_unref( printer ); +} + +// ----------------------------------------------------------------------- + +String SalInstance::GetDefaultPrinter() +{ + maInstData.mbPrinterInit = true; + PrinterInfoManagerCups& rManager( PrinterInfoManagerCups::getCups() ); + return rManager.getDefaultPrinter(); +} + +// ======================================================================= + +SalInfoPrinter::SalInfoPrinter() +{ + maPrinterData.m_pGraphics = NULL; + m_bPapersInit = false; +} + +// ----------------------------------------------------------------------- + +SalInfoPrinter::~SalInfoPrinter() +{ + if( maPrinterData.m_pGraphics ) + { + delete maPrinterData.m_pGraphics; + maPrinterData.m_pGraphics = NULL; + } +} + +// ----------------------------------------------------------------------- + + +void SalInfoPrinter::InitPaperFormats( const ImplJobSetup* pSetupData ) +{ + m_aPaperFormats.clear(); + m_bPapersInit = true; + + if( maPrinterData.m_aJobData.m_pParser ) + { + const PPDKey* pKey = maPrinterData.m_aJobData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) ); + if( pKey ) + { + int nValues = pKey->countValues(); + for( int i = 0; i < nValues; i++ ) + { + const PPDValue* pValue = pKey->getValue( i ); + vcl::PaperInfo aInfo; + aInfo.m_aPaperName = pValue->m_aOptionTranslation; + if( ! aInfo.m_aPaperName.Len() ) + aInfo.m_aPaperName = pValue->m_aOption; + int nWidth = 0, nHeight = 0; + maPrinterData.m_aJobData.m_pParser->getPaperDimension( pValue->m_aOption, nWidth, nHeight ); + aInfo.m_nPaperWidth = (unsigned long)((PtTo10Mu( nWidth )+50)/100); + aInfo.m_nPaperHeight = (unsigned long)((PtTo10Mu( nHeight )+50)/100); + m_aPaperFormats.push_back( aInfo ); + } + } + } +} + +// ----------------------------------------------------------------------- + +int SalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* pSetupData ) +{ + return 900; +} + +// ----------------------------------------------------------------------- + +SalGraphics* SalInfoPrinter::GetGraphics() +{ + // return a valid pointer only once + // the reasoning behind this is that we could have different + // SalGraphics that can run in multiple threads + // (future plans) + SalGraphics* pRet = NULL; + if( ! maPrinterData.m_pGraphics ) + { + maPrinterData.m_pGraphics = new SalGraphics; + maPrinterData.m_pGraphics->maGraphicsData.m_pJobData = &maPrinterData.m_aJobData; + maPrinterData.m_pGraphics->maGraphicsData.m_pPrinterGfx = &maPrinterData.m_aPrinterGfx; + maPrinterData.m_pGraphics->maGraphicsData.bPrinter_ = TRUE; + pRet = maPrinterData.m_pGraphics; + } + return pRet; +} + +// ----------------------------------------------------------------------- + +void SalInfoPrinter::ReleaseGraphics( SalGraphics* pGraphics ) +{ + if( pGraphics == maPrinterData.m_pGraphics ) + { + delete pGraphics; + maPrinterData.m_pGraphics = NULL; + } +} + +// ----------------------------------------------------------------------- + +#include + +BOOL SalInfoPrinter::Setup( SalFrame* pFrame, ImplJobSetup* pJobSetup ) +{ + if( ! pFrame || ! pJobSetup ) + return FALSE; + + OString str = OUStringToOString (maPrinterData.m_aJobData.m_aPrinterName, RTL_TEXTENCODING_UTF8); + const char *argv[] = { "gnome-cups-manager", "--properties", NULL, NULL }; + argv [2] = str.getStr (); + BOOL success; + + if (cups_debug) + fprintf (stderr, "Setup ... [ properties on '%s' ]\n", str.getStr ()); + + success = g_spawn_async (NULL, (gchar **)argv, + NULL, G_SPAWN_SEARCH_PATH, + NULL, NULL, NULL, NULL); + + return success; +} + +// ----------------------------------------------------------------------- + +// This function gets the driver data and puts it into pJobSetup +// If pJobSetup->mpDriverData is NOT NULL, then the independend +// data should be merged into the driver data +// If pJobSetup->mpDriverData IS NULL, then the driver defaults +// should be merged into the independent data +BOOL SalInfoPrinter::SetPrinterData( ImplJobSetup* pJobSetup ) +{ + if (cups_debug) + fprintf (stderr, "--- re-fetch data from cupsd ---\n"); + if( pJobSetup->mpDriverData ) + return SetData( ~0, pJobSetup ); + + copyJobDataToJobSetup( pJobSetup, maPrinterData.m_aJobData ); + return TRUE; +} + +// ----------------------------------------------------------------------- + +// This function merges the independ driver data +// and sets the new independ data in pJobSetup +// Only the data must be changed, where the bit +// in nGetDataFlags is set +BOOL SalInfoPrinter::SetData( + ULONG nSetDataFlags, + ImplJobSetup* pJobSetup ) +{ + JobData aData; + JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); + + if( aData.m_pParser ) + { + const PPDKey* pKey; + const PPDValue* pValue; + + // merge papersize if necessary + if( nSetDataFlags & SAL_JOBSET_PAPERSIZE ) + { + int nWidth, nHeight; + if( pJobSetup->meOrientation == ORIENTATION_PORTRAIT ) + { + nWidth = pJobSetup->mnPaperWidth; + nHeight = pJobSetup->mnPaperHeight; + } + else + { + nWidth = pJobSetup->mnPaperHeight; + nHeight = pJobSetup->mnPaperWidth; + } + String aPaper; + if( pJobSetup->mePaperFormat == PAPER_USER ) + aPaper = aData.m_pParser->matchPaper( + TenMuToPt( pJobSetup->mnPaperWidth ), + TenMuToPt( pJobSetup->mnPaperHeight ) ); + else + aPaper = String( ByteString( aPaperTab[ pJobSetup->mePaperFormat ].name ), RTL_TEXTENCODING_ISO_8859_1 ); + pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) ); + pValue = pKey ? pKey->getValue( aPaper ) : NULL; + if( ! ( pKey && pValue && aData.m_aContext.setValue( pKey, pValue, false ) == pValue ) ) + return FALSE; + } + + // merge paperbin if necessary + if( nSetDataFlags & SAL_JOBSET_PAPERBIN ) + { + pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ); + if( pKey ) + { + int nPaperBin = pJobSetup->mnPaperBin; + if( nPaperBin == 0xffff ) + pValue = pKey->getDefaultValue(); + else + pValue = pKey->getValue( pJobSetup->mnPaperBin ); + + // may fail due to constraints; + // real paper bin is copied back to jobsetup in that case + aData.m_aContext.setValue( pKey, pValue ); + } + // if printer has no InputSlot key simply ignore this setting + // (e.g. SGENPRT has no InputSlot) + } + + // merge orientation if necessary + if( nSetDataFlags & SAL_JOBSET_ORIENTATION ) + aData.m_eOrientation = pJobSetup->meOrientation == ORIENTATION_LANDSCAPE ? orientation::Landscape : orientation::Portrait; + + maPrinterData.m_aJobData = aData; + copyJobDataToJobSetup( pJobSetup, aData ); + return TRUE; + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +void SalInfoPrinter::GetPageInfo( + const ImplJobSetup* pJobSetup, + long& rOutWidth, long& rOutHeight, + long& rPageOffX, long& rPageOffY, + long& rPageWidth, long& rPageHeight ) +{ + if( ! pJobSetup ) + return; + + JobData aData; + JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); + + // get the selected page size + if( aData.m_pParser ) + { + String aPaper; + int width, height; + int left = 0, top = 0, right = 0, bottom = 0; + int nDPI = aData.m_aContext.getRenderResolution(); + + + if( aData.m_eOrientation == psp::orientation::Portrait ) + { + aData.m_aContext.getPageSize( aPaper, width, height ); + aData.m_pParser->getMargins( aPaper, left, right, top, bottom ); + } + else + { + aData.m_aContext.getPageSize( aPaper, height, width ); + aData.m_pParser->getMargins( aPaper, bottom, top, left, right ); + } + rPageWidth = width * nDPI / 72; + rPageHeight = height * nDPI / 72; + rPageOffX = left * nDPI / 72; + rPageOffY = top * nDPI / 72; + rOutWidth = ( width - left - right ) * nDPI / 72; + rOutHeight = ( height - top - bottom ) * nDPI / 72; + + if( cups_debug ) + g_warning ("SalInfoPrinter:: GetPageInfo ... margins: %ld %ld %ld %ld", + rPageOffX, rPageOffY, rPageWidth - rOutWidth, rPageHeight - rOutHeight); + } +} + +// ----------------------------------------------------------------------- + +ULONG SalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pJobSetup ) +{ + if( ! pJobSetup ) + return 0; + + JobData aData; + JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); + + const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ): NULL; + + return pKey ? pKey->countValues() : 0; +} + +// ----------------------------------------------------------------------- + +String SalInfoPrinter::GetPaperBinName( const ImplJobSetup* pJobSetup, ULONG nPaperBin ) +{ + JobData aData; + JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); + + String aRet; + if( aData.m_pParser ) + { + const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ): NULL; + if( nPaperBin == 0xffff || !pKey ) + aRet = aData.m_pParser->getDefaultInputSlot(); + else + { + const PPDValue* pValue = pKey->getValue( nPaperBin ); + if( pValue ) + aRet = pValue->m_aOptionTranslation.Len() ? pValue->m_aOptionTranslation : pValue->m_aOption; + } + } + + return aRet; +} + +// ----------------------------------------------------------------------- + +ULONG SalInfoPrinter::GetCapabilities( const ImplJobSetup* pJobSetup, USHORT nType ) +{ + /* FIXME: surely we can do better here */ + switch( nType ) + { + case PRINTER_CAPABILITIES_SUPPORTDIALOG: + return 1; + case PRINTER_CAPABILITIES_COPIES: + return 0xffff; + case PRINTER_CAPABILITIES_COLLATECOPIES: + return 0; + case PRINTER_CAPABILITIES_SETORIENTATION: + return 1; + case PRINTER_CAPABILITIES_SETPAPERBIN: + return 1; + case PRINTER_CAPABILITIES_SETPAPERSIZE: + return 1; + case PRINTER_CAPABILITIES_SETPAPER: + return 0; + case PRINTER_CAPABILITIES_FAX: + return 0; + default: break; + }; + return 0; +} + +// ======================================================================= + +/* + * SalPrinter + */ + +SalPrinter::SalPrinter() +{ +} + +// ----------------------------------------------------------------------- + +SalPrinter::~SalPrinter() +{ +} + +// ----------------------------------------------------------------------- + +static inline String getTmpName() +{ + int fd; + String ret; + char *tmp_name; + + tmp_name = g_strdup_printf( "%s/ooo-ps-XXXXXX", + g_get_tmp_dir() ); + + if ((fd = g_mkstemp (tmp_name))) + close (fd); + else + { + g_warning ("Failed to create tmpfile '%s'", tmp_name); + return ret; + } + + ret = String( ByteString( tmp_name ), RTL_TEXTENCODING_UTF8 ); + + g_free (tmp_name); + + return ret; +} + +BOOL SalPrinter::StartJob( + const XubString* pFileName, + const XubString& rJobName, + const XubString& rAppName, + ULONG nCopies, BOOL bCollate, + ImplJobSetup* pJobSetup ) +{ + int nMode = 0; + vcl_sal::PrinterUpdate::jobStarted(); + + maPrinterData.m_bFax = false; + maPrinterData.m_bPdf = false; + maPrinterData.m_aFileName = pFileName ? *pFileName : String(); + maPrinterData.m_aJobName = rJobName; + maPrinterData.m_aTmpFile = String(); + maPrinterData.m_nCopies = nCopies; + + JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, + maPrinterData.m_aJobData ); + if( maPrinterData.m_nCopies > 1 ) + // in case user did not do anything (m_nCopies=1) + // take the default from jobsetup + maPrinterData.m_aJobData.m_nCopies = maPrinterData.m_nCopies; + + maPrinterData.m_aTmpFile = getTmpName(); + if (!maPrinterData.m_aTmpFile.Len()) + return FALSE; + + String printTo; + if (maPrinterData.isPrintToFile ()) + { + ::std::hash_map< ::rtl::OUString, ::rtl::OUString, ::rtl::OUStringHash >::const_iterator it; + it = pJobSetup->maValueMap.find( ::rtl::OUString::createFromAscii( "Filter#" ) ); + nMode = S_IRUSR | S_IWUSR; + if( it != pJobSetup->maValueMap.end() ) + { + OUString aFilter = it->second; + maPrinterData.m_bPdf = !aFilter.compareToAscii( "PDF" ); + } + + if (maPrinterData.m_bPdf) + printTo = maPrinterData.m_aTmpFile; + else + printTo = maPrinterData.m_aFileName; + } + else + printTo = maPrinterData.m_aTmpFile; + + maPrinterData.m_aPrinterGfx.Init( maPrinterData.m_aJobData ); + + // FIXME: race + if (PrinterInfoManagerCups::getCups().isBuiltinGeneric() && + !maPrinterData.m_aFileName.Len()) + { +#ifdef SAL_PRINTER_ERROR_NO_PRINTER + maPrinterData.m_nError = SAL_PRINTER_ERROR_NO_PRINTER; + return FALSE; +#else + g_warning ("Can't print with generic printer"); +#endif + } + + return maPrinterData.m_aPrintJob.StartJob + ( printTo, nMode, rJobName, rAppName, maPrinterData.m_aJobData, + &maPrinterData.m_aPrinterGfx ) ? TRUE : FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL SalPrinter::EndJob() +{ + BOOL bSuccess = maPrinterData.m_aPrintJob.EndJob(); + BOOL bUnlink = FALSE; + OString aTmpName = OUStringToOString + ( maPrinterData.m_aTmpFile, RTL_TEXTENCODING_UTF8 ); + + if( bSuccess ) + { + if (maPrinterData.isPrintToFile ()) + { + if (maPrinterData.m_bPdf) + { + if (cups_debug) + g_warning ("Print to PDF..."); + String aCommandLine = String( RTL_CONSTASCII_USTRINGPARAM( + "/usr/bin/gs -q -dNOPAUSE -sDEVICE=pdfwrite -sOutputFile=\"(OUTFILE)\" (INFILE)" ) ); + + if (g_getenv ("SAL_PDF_CONVERT_CMD")) + aCommandLine.AssignAscii (g_getenv ("SAL_PDF_CONVERT_CMD")); + +#define REPLACE(a,b) \ + while( aCommandLine.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( a ) ), b ) != STRING_NOTFOUND ); + + REPLACE ("(OUTFILE)", maPrinterData.m_aFileName); + REPLACE ("(INFILE)", maPrinterData.m_aTmpFile); + + OString aSystemCmd = OUStringToOString ( aCommandLine, RTL_TEXTENCODING_UTF8 ); + gint exit_status = 0; + if (!g_spawn_command_line_sync (aSystemCmd.getStr (), NULL, NULL, &exit_status, NULL)) + bSuccess = FALSE; + else + bSuccess = !exit_status; + } + else if (cups_debug) + g_warning ("Print to PS file..."); + } + else + { + OString aJobTitle = OUStringToOString + ( maPrinterData.m_aJobName, RTL_TEXTENCODING_UTF8 ); + + if (cups_debug) + g_warning( "Printing file '%s' name '%s' to '%s'", + (const sal_Char *)aTmpName, + (const sal_Char *)OUStringToOString + ( maPrinterData.m_aJobName, RTL_TEXTENCODING_UTF8 ), + (const sal_Char *)OUStringToOString + ( maPrinterData.m_aJobData.m_aPrinterName, RTL_TEXTENCODING_UTF8 ) ); + + GError *error = NULL; + GList *print_options = NULL; + GnomeCupsPrinter *printer; + + printer = PrinterInfoManagerCups::getCups().getGnomePrinter + ( maPrinterData.m_aJobData.m_aPrinterName ); + +#ifdef USE_CUPS_OPTIONS + gnome_cups_printer_force_refresh + ( printer, GNOME_CUPS_PRINTER_REFRESH_OPTIONS ); + print_options = gnome_cups_printer_get_options( printer ); +#endif + bSuccess = gnome_cups_printer_print_file + ( printer, (const sal_Char *) aTmpName, + (const sal_Char *) aJobTitle, print_options, &error) != 0; + + if (!bSuccess) { + if (cups_debug) + g_warning ("Error printing '%s' ... (0x%x)", + aTmpName.getStr(), error ? error->code : -1); + // We can map the IPP status type in error->code but + // since we can only map it to 2 errors, why bother + maPrinterData.m_nError = PRINTER_GENERALERROR; + } + +#ifdef USE_CUPS_OPTIONS + gnome_cups_printer_option_list_free( print_options ); +#endif + + gnome_cups_printer_unref( printer ); + } + } + else if (cups_debug) + g_warning ("Internal printing was not a success"); + + if (maPrinterData.m_aTmpFile.Len()) + { + if (cups_debug) + g_warning ("Unlinking tmpfile"); + unlink( (const sal_Char *) aTmpName ); + } + + vcl_sal::PrinterUpdate::jobEnded(); + + if (cups_debug) + g_warning ("::EndJob returns %d", bSuccess); + return bSuccess; +} + +// ----------------------------------------------------------------------- + +BOOL SalPrinter::AbortJob() +{ + BOOL bAbort = maPrinterData.m_aPrintJob.AbortJob() ? TRUE : FALSE; + vcl_sal::PrinterUpdate::jobEnded(); + return bAbort; +} + +// ----------------------------------------------------------------------- + +SalGraphics* SalPrinter::StartPage( ImplJobSetup* pJobSetup, BOOL bNewJobData ) +{ + JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, maPrinterData.m_aJobData ); + maPrinterData.m_pGraphics = new SalGraphics(); + maPrinterData.m_pGraphics->maGraphicsData.m_pJobData = &maPrinterData.m_aJobData; + maPrinterData.m_pGraphics->maGraphicsData.m_pPrinterGfx = &maPrinterData.m_aPrinterGfx; + maPrinterData.m_pGraphics->maGraphicsData.bPrinter_ = true; + maPrinterData.m_pGraphics->maGraphicsData.m_pPhoneNr = maPrinterData.m_bFax ? &maPrinterData.m_aFaxNr : NULL; + maPrinterData.m_pGraphics->maGraphicsData.m_bSwallowFaxNo = maPrinterData.m_bSwallowFaxNo; + if( maPrinterData.m_nCopies > 1 ) + // in case user did not do anything (m_nCopies=1) + // take the default from jobsetup + maPrinterData.m_aJobData.m_nCopies = maPrinterData.m_nCopies; + + maPrinterData.m_aPrintJob.StartPage( maPrinterData.m_aJobData, bNewJobData ? sal_True : sal_False ); + maPrinterData.m_aPrinterGfx.Init( maPrinterData.m_aPrintJob ); + + return maPrinterData.m_pGraphics; +} + +// ----------------------------------------------------------------------- + +BOOL SalPrinter::EndPage() +{ + sal_Bool bResult = maPrinterData.m_aPrintJob.EndPage(); + maPrinterData.m_aPrinterGfx.Clear(); + return bResult ? TRUE : FALSE; +} + +// ----------------------------------------------------------------------- + +ULONG SalPrinter::GetErrorCode() +{ + return maPrinterData.m_nError; +} + +/* + * vcl::PrinterUpdate + */ + +Timer* vcl_sal::PrinterUpdate::pPrinterUpdateTimer = NULL; +int vcl_sal::PrinterUpdate::nActiveJobs = 0; + +void vcl_sal::PrinterUpdate::doUpdate() +{ + ::cups::PrinterInfoManagerCups& rManager( ::cups::PrinterInfoManagerCups::getCups() ); + if( rManager.checkPrintersChanged() ) + { + SalFrame* pFrame = GetSalData()->pFirstFrame_; + while( pFrame ) + { + pFrame->maFrameData.Call( SALEVENT_PRINTERCHANGED, NULL ); + pFrame = pFrame->maFrameData.GetNextFrame(); + } + } +} + +// ----------------------------------------------------------------------- + +IMPL_STATIC_LINK( vcl_sal::PrinterUpdate, UpdateTimerHdl, void*, pDummy ) +{ + if( nActiveJobs < 1 ) + { + doUpdate(); + delete pPrinterUpdateTimer; + pPrinterUpdateTimer = NULL; + } + else + pPrinterUpdateTimer->Start(); + + return 0; +} + +// ----------------------------------------------------------------------- + +void vcl_sal::PrinterUpdate::update() +{ + if( nActiveJobs < 1 ) + doUpdate(); + else if( ! pPrinterUpdateTimer ) + { + pPrinterUpdateTimer = new Timer(); + pPrinterUpdateTimer->SetTimeout( 500 ); + pPrinterUpdateTimer->SetTimeoutHdl( STATIC_LINK( NULL, vcl_sal::PrinterUpdate, UpdateTimerHdl ) ); + pPrinterUpdateTimer->Start(); + } +} + +// ----------------------------------------------------------------------- + +void vcl_sal::PrinterUpdate::jobEnded() +{ + nActiveJobs--; + if( nActiveJobs < 1 ) + { + if( pPrinterUpdateTimer ) + { + pPrinterUpdateTimer->Stop(); + delete pPrinterUpdateTimer; + pPrinterUpdateTimer = NULL; + doUpdate(); + } + } +} Index: vcl/util/makefile.mk =================================================================== RCS file: /cvs/gsl/vcl/util/makefile.mk,v retrieving revision 1.46.2.3 diff -u -p -u -r1.46.2.3 makefile.mk --- vcl/util/makefile.mk 31 Jul 2003 15:28:43 -0000 1.46.2.3 +++ vcl/util/makefile.mk 29 Aug 2003 14:34:04 -0000 @@ -275,6 +275,8 @@ SHL1STDLIBS += -framework Cocoa .IF "$(GUIBASE)"=="unx" +SHL1STDLIBS += `pkg-config --libs libgnomecups-1.0` + .IF "$(WITH_LIBSN)"=="YES" SHL1STDLIBS+=$(LIBSN_LIBS) .ENDIF