Index: inc/psprint/printerinfomanager.hxx =================================================================== RCS file: /cvs/gsl/psprint/inc/psprint/printerinfomanager.hxx,v retrieving revision 1.4 diff -u -r1.4 printerinfomanager.hxx --- inc/psprint/printerinfomanager.hxx 10 Jun 2003 14:34:28 -0000 1.4 +++ inc/psprint/printerinfomanager.hxx 5 Oct 2003 03:20:19 -0000 @@ -81,6 +81,35 @@ #include #endif +#ifdef MACOSX +/* MacOS X print system discovery constants: + * + * These values enumerate Apple OS printing systems we could use. + * They are used as indications _as well as_ indexes into the + * aParms structure used below for print commands. + */ +#define kApplePrintingFailure 0 /* For whatever reason, we can't print at all */ +#define kApplePrintingLPR 1 /* Darwin 5.x style LPR printing */ +#define kApplePrintingCUPS 2 /* MacOS X 10.2/Darwin 6 style CUPS (also CUPS installed by users on 10.1) */ +#define kApplePrintingPrintCenter 3 /* MacOS X 10.1 /usr/sbin/Print printing */ + +/* Constants for PostScript vs PDF printing */ +#define kApplePrintingUsePDF 1 /* Default; Run PS through ps2pdf first (requires GhostScript) */ +#define kApplePrintingUsePS 2 /* Optional, print PS directly to printer (less compatible, requires PS printer) */ + +/* Define various printing commands */ +#define kApplePCPrintCommand "/usr/sbin/Print" /* Mac OS X 10.1 Print Center Printing command */ +#define kApplePS2PDFLocation "/usr/local/bin/ps2pdf" /* PS -> PDF conversion command */ +#define kApplePCQueueName "Apple Print Center Default Printer" /* Name that appears in Print... dialog as the default */ + /* printer for 10.1 Print Center printing */ + +/* Prototype for print method discovery function. Returns + * a constant defined in printerinfomanager.hxx + */ +sal_Int32 macxp_GetSystemPrintMethod( void ); +#endif + + namespace psp { Index: inc/psprint/printerjob.hxx =================================================================== RCS file: /cvs/gsl/psprint/inc/psprint/printerjob.hxx,v retrieving revision 1.4 diff -u -r1.4 printerjob.hxx --- inc/psprint/printerjob.hxx 26 Mar 2003 14:24:02 -0000 1.4 +++ inc/psprint/printerjob.hxx 5 Oct 2003 03:20:19 -0000 @@ -87,7 +87,8 @@ rtl::OUString maSpoolDirName; rtl::OUString maFileName; // empty: spool to command, else spool to named file - int mnFileMode; + int mnFileMode; + rtl::OUString maJobName; osl::File* mpJobHeader; osl::File* mpJobTrailer; @@ -95,9 +96,9 @@ std::list< osl::File* > maPageList; std::list< osl::File* > maHeaderList; - JobData m_aDocumentJobData; + JobData m_aDocumentJobData; JobData m_aLastJobData; - PrinterGfx* m_pGraphics; + PrinterGfx* m_pGraphics; sal_uInt32 mnResolution; Index: source/fontmanager/fontmanager.cxx =================================================================== RCS file: /cvs/gsl/psprint/source/fontmanager/fontmanager.cxx,v retrieving revision 1.39 diff -u -r1.39 fontmanager.cxx --- source/fontmanager/fontmanager.cxx 1 Jul 2003 14:52:08 -0000 1.39 +++ source/fontmanager/fontmanager.cxx 5 Oct 2003 03:20:20 -0000 @@ -159,6 +159,16 @@ return nRet; } +inline sal_uInt32 getUInt32BE( const sal_uInt8*& pBuffer ) +{ + sal_uInt32 nRet = (((sal_uInt32)pBuffer[0]) << 24) | + (((sal_uInt32)pBuffer[1]) << 16) | + (((sal_uInt32)pBuffer[2]) << 8) | + (((sal_uInt32)pBuffer[3]) ); + pBuffer += 4; + return nRet; +} + static italic::type parseItalic( const ByteString& rItalic ) { italic::type eItalic = italic::Unknown; @@ -376,6 +386,9 @@ // so currently we get kernpairs by accessing the raw data struct _TrueTypeFont* pImplTTFont = (struct _TrueTypeFont*)pTTFont; + //----------------------------------------------------------------- + // Kerning: KT_MICROSOFT + //----------------------------------------------------------------- if( pImplTTFont->nkern && pImplTTFont->kerntype == KT_MICROSOFT ) { // create a glyph -> character mapping @@ -433,8 +446,8 @@ } } break; - case 2: + case 2: { const sal_uInt8* pSubTable = pTable; sal_uInt16 nRowWidth = getUInt16BE( pTable ); @@ -472,6 +485,131 @@ } } } + + //----------------------------------------------------------------- + // Kerning: KT_APPLE_NEW + //----------------------------------------------------------------- + if( pImplTTFont->nkern && pImplTTFont->kerntype == KT_APPLE_NEW ) + { + // create a glyph -> character mapping + ::std::hash_map< sal_uInt16, sal_Unicode > aGlyphMap; + ::std::hash_map< sal_uInt16, sal_Unicode >::iterator left, right; + for( i = 21; i < 0xfffd; i++ ) + { + sal_uInt16 nGlyph = MapChar( pTTFont, (sal_Unicode)i, 0 ); // kerning for horz only + if( nGlyph != 0 ) + aGlyphMap[ nGlyph ] = (sal_Unicode)i; + } + + // Loop through each of the 'kern' subtables + KernPair aPair; + for( i = 0; i < pImplTTFont->nkern; i++ ) + { + const sal_uInt8* pTable = pImplTTFont->kerntables[i]; + + sal_uInt32 nLength = getUInt32BE( pTable ); + sal_uInt16 nCoverage = getUInt16BE( pTable ); + sal_uInt16 nTupleIndex = getUInt16BE( pTable ); + + // Get kerning type + sal_Bool bKernVertical = nCoverage & 0x8000; + sal_Bool bKernCrossStream = nCoverage & 0x4000; + sal_Bool bKernVariation = nCoverage & 0x2000; + + // Kerning sub-table format, 0 through 3 + sal_uInt8 nSubTableFormat = nCoverage & 0x00FF; + + aPair.kern_x = 0; + aPair.kern_y = 0; + switch( nSubTableFormat ) + { + case 0: + { + // Grab the # of kern pairs but skip over the: + // searchRange + // entrySelector + // rangeShift + sal_uInt16 nPairs = getUInt16BE( pTable ); + pTable += 6; + + for( int n = 0; n < nPairs; n++ ) + { + sal_uInt16 nLeftGlyph = getUInt16BE( pTable ); + sal_uInt16 nRightGlyph = getUInt16BE( pTable ); + sal_Int16 nKern = (sal_Int16)getUInt16BE( pTable ); + + left = aGlyphMap.find( nLeftGlyph ); + right = aGlyphMap.find( nRightGlyph ); + if( left != aGlyphMap.end() && right != aGlyphMap.end() ) + { + aPair.first = left->second; + aPair.second = right->second; + + // Only support horizontal kerning for now + aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm; + aPair.kern_y = 0; + m_pMetrics->m_aXKernPairs.push_back( aPair ); + +/* switch( nCoverage & 1 ) + { + case 1: + aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm; + m_pMetrics->m_aXKernPairs.push_back( aPair ); + break; + case 0: + aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm; + m_pMetrics->m_aYKernPairs.push_back( aPair ); + break; + } +*/ + } + } + } + break; + + case 2: + { + const sal_uInt8* pSubTable = pTable; + sal_uInt16 nRowWidth = getUInt16BE( pTable ); + sal_uInt16 nOfLeft = getUInt16BE( pTable ); + sal_uInt16 nOfRight = getUInt16BE( pTable ); + sal_uInt16 nOfArray = getUInt16BE( pTable ); + const sal_uInt8* pTmp = pSubTable + nOfLeft; + sal_uInt16 nFirstLeft = getUInt16BE( pTmp ); + sal_uInt16 nLastLeft = getUInt16BE( pTmp ) + nFirstLeft - 1; + pTmp = pSubTable + nOfRight; + sal_uInt16 nFirstRight = getUInt16BE( pTmp ); + sal_uInt16 nLastRight = getUInt16BE( pTmp ) + nFirstRight -1; + + int nPairs = (int)(nLastLeft-nFirstLeft+1)*(int)(nLastRight-nFirstRight+1); + for( aPair.first = nFirstLeft; aPair.first < nLastLeft; aPair.first++ ) + { + for( aPair.second = 0; aPair.second < nLastRight; aPair.second++ ) + { + sal_Int16 nKern = (sal_Int16)getUInt16BE( pTmp ); + switch( nCoverage & 1 ) + { + case 1: + aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm; + m_pMetrics->m_aXKernPairs.push_back( aPair ); + break; + case 0: + aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm; + m_pMetrics->m_aYKernPairs.push_back( aPair ); + break; + } + } + } + } + break; + + default: + fprintf( stderr, "Found unsupported Apple-style kern subtable type %d.\n", nSubTableFormat ); + break; + } + } + } + #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "found %d/%d kern pairs for %s\n", m_pMetrics->m_aXKernPairs.size(), @@ -1438,9 +1576,17 @@ aNames.pop_front(); } else - // poor font does not have a family name - // name it to file name minus ".tt{f|c}" - pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( pTTFontFile->m_aFontFile.copy( 0, pTTFontFile->m_aFontFile.getLength()-4 ), aEncoding ), sal_True ); + { + sal_Int32 dotIndex; + + // poor font does not have a family name + // name it to file name minus the extension + dotIndex = pTTFontFile->m_aFontFile.lastIndexOf( '.' ); + if ( dotIndex == -1 ) + dotIndex = pTTFontFile->m_aFontFile.getLength(); + + pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( pTTFontFile->m_aFontFile.copy( 0, dotIndex ), aEncoding ), sal_True ); + } } pFont->m_aAliases.clear(); for( ::std::list< OUString >::iterator it = aNames.begin(); it != aNames.end(); ++it ) Index: source/fontsubset/sft.c =================================================================== RCS file: /cvs/gsl/psprint/source/fontsubset/sft.c,v retrieving revision 1.23 diff -u -r1.23 sft.c --- source/fontsubset/sft.c 22 Jul 2003 10:12:54 -0000 1.23 +++ source/fontsubset/sft.c 5 Oct 2003 03:20:23 -0000 @@ -1344,6 +1344,11 @@ eID = GetUInt16(table, 6 + i * 8, 1); offset = GetUInt32(table, 8 + i * 8, 1); + /* Unicode tables in Apple fonts */ + if (pID == 0) { + ThreeOne = offset; break; + } + if (pID == 3) { switch (eID) { case 0: ThreeZero = offset; break; Index: source/helper/helper.cxx =================================================================== RCS file: /cvs/gsl/psprint/source/helper/helper.cxx,v retrieving revision 1.14 diff -u -r1.14 helper.cxx --- source/helper/helper.cxx 15 Apr 2003 16:14:38 -0000 1.14 +++ source/helper/helper.cxx 5 Oct 2003 03:20:23 -0000 @@ -74,6 +74,8 @@ #include #include "jvmaccess/javainfo.hxx" +#define OSL_DEBUG_LEVEL 2 + using namespace rtl; namespace psp { @@ -143,8 +145,15 @@ { OUString aNetPath = getOfficePath( psp::NetPath ); OUString aUserPath = getOfficePath( psp::UserPath ); + +#ifdef MACOSX + // For CUPS printing, add /etc/cups/ppd to pull in autogenerated printer PPDs + aPath += OUString( RTL_CONSTASCII_USTRINGPARAM("/etc/cups/ppd") ); +#endif if( aNetPath.getLength() ) { + if( aPath.getLength() ) + aPath += OUString( RTL_CONSTASCII_USTRINGPARAM( ":" ) ); aPath += aNetPath; aPath += OUString( RTL_CONSTASCII_USTRINGPARAM( "/share/psprint" ) ); } @@ -177,7 +186,11 @@ if( ! aDir.getLength() ) continue; +#ifdef MACOSX + if( pSubDir && !aDir.equals(OString("/etc/cups/ppd")) ) +#else if( pSubDir ) +#endif { aDir += "/"; aDir += pSubDir; Index: source/helper/makefile.mk =================================================================== RCS file: /cvs/gsl/psprint/source/helper/makefile.mk,v retrieving revision 1.2 diff -u -r1.2 makefile.mk --- source/helper/makefile.mk 20 Aug 2002 15:07:42 -0000 1.2 +++ source/helper/makefile.mk 5 Oct 2003 03:20:23 -0000 @@ -72,10 +72,20 @@ # --- Files -------------------------------------------------------- +.IF "$(GUIBASE)"=="aqua" + +dummy: + @echo "Nothing to build for GUIBASE $(GUIBASE)" + +.ELSE # "$(GUIBASE)"=="aqua" + SLOFILES=\ $(SLO)$/ppdparser.obj \ $(SLO)$/strhelper.obj \ $(SLO)$/helper.obj + + +.ENDIF # GUIBASE = aqua # --- Targets ------------------------------------------------------ Index: source/helper/ppdparser.cxx =================================================================== RCS file: /cvs/gsl/psprint/source/helper/ppdparser.cxx,v retrieving revision 1.8 diff -u -r1.8 ppdparser.cxx --- source/helper/ppdparser.cxx 15 Apr 2003 16:14:50 -0000 1.8 +++ source/helper/ppdparser.cxx 5 Oct 2003 03:20:23 -0000 @@ -267,7 +267,10 @@ aFile = getPPDFile( aFile ); if( ! aFile.Len() ) +{ +fprintf( stderr, "Could not get printer PPD file!\n" ); return NULL; +} for( ::std::list< PPDParser* >::const_iterator it = aAllParsers.begin(); it != aAllParsers.end(); ++it ) if( (*it)->m_aFile == aFile ) @@ -442,6 +445,25 @@ m_nLanguageLevel = pKey->getValue( 0 )->m_aValue.ToInt32(); if( pKey = getKey( String( RTL_CONSTASCII_USTRINGPARAM( "TTRasterizer" ) ) ) ) m_bType42Capable = pKey->getValue( 0 )->m_aValue.EqualsIgnoreCaseAscii( "Type42" ) ? true : false; + +#ifdef MACOSX + // Many Mac OS X PPDs for inkjet printers simply use CUPS to convert the output to a PDF, + // and to take advantage of that we wish to embed fonts for these printers even if its + // minimal CUPS PPD doesn't have TTRasterizer. + // To determine if this printer is supposed to take PDF input, look for the "cupsFilter" key, + // and if it exists, for the string "application/pdf" which specifies the CUPS filter to use for it + // If present, we assume that we can embed TrueType fonts and that the CUPS filter will take care + // of rasterizing them appropriately. + if ( m_bType42Capable == false ) + { + if ( pKey = getKey( String(RTL_CONSTASCII_USTRINGPARAM("cupsFilter")) ) ) + { + ByteString aCupsFilterString( pKey->getValue( 0 )->m_aValue, RTL_TEXTENCODING_ISO_8859_1 ); + if ( strstr(aCupsFilterString.GetBuffer(), "application/pdf") > 0 ) + m_bType42Capable = true; + } + } +#endif } PPDParser::~PPDParser() @@ -566,6 +588,10 @@ // found a colon, there may be an option String aLine = aCurrentLine.Copy( 1, nPos-1 ); aLine = WhitespaceToSpace( aLine ); + #ifdef MACOSX + // Some Epson PPDs use <20> to encodes spaces in UI strings + aLine.SearchAndReplaceAllAscii( "<20>", String(RTL_CONSTASCII_USTRINGPARAM(" ")) ); + #endif int nTransPos = aLine.Search( '/' ); if( nTransPos != STRING_NOTFOUND ) pValue->m_aOptionTranslation = aLine.Copy( nTransPos+1 ); Index: source/printer/makefile.mk =================================================================== RCS file: /cvs/gsl/psprint/source/printer/makefile.mk,v retrieving revision 1.2 diff -u -r1.2 makefile.mk --- source/printer/makefile.mk 20 Aug 2002 15:09:10 -0000 1.2 +++ source/printer/makefile.mk 5 Oct 2003 03:20:23 -0000 @@ -72,10 +72,18 @@ # --- Files -------------------------------------------------------- +.IF "$(GUIBASE)"=="aqua" + +dummy: + @echo "Nothing to build for GUIBASE $(GUIBASE)" + +.ELSE # "$(GUIBASE)"=="aqua" + SLOFILES=\ $(SLO)$/printerinfomanager.obj \ $(SLO)$/jobdata.obj +.ENDIF # GUIBASE = aqua # --- Targets ------------------------------------------------------ Index: source/printer/printerinfomanager.cxx =================================================================== RCS file: /cvs/gsl/psprint/source/printer/printerinfomanager.cxx,v retrieving revision 1.19 diff -u -r1.19 printerinfomanager.cxx --- source/printer/printerinfomanager.cxx 12 Jun 2003 11:08:59 -0000 1.19 +++ source/printer/printerinfomanager.cxx 5 Oct 2003 03:20:23 -0000 @@ -73,11 +73,21 @@ #include #include +#ifdef MACOSX +#include +#endif + // filename of configuration files #define PRINT_FILENAME "psprint.conf" // the group of the global defaults #define GLOBAL_DEFAULTS_GROUP "__Global_Printer_Defaults__" +#ifdef MACOSX +// filename of CUPS config file +#define MACXP_CUPS_CONF_FILENAME "printers.conf" +#define MACXP_CUPS_CONF_DIR "/etc/cups/" +#endif + using namespace psp; using namespace rtl; using namespace osl; @@ -165,7 +175,19 @@ if( ! bChanged ) bChanged = m_pQueueInfo->hasChanged(); if( bChanged ) + { +#ifdef MACOSX + // For Mac OS X 10.2, the user may change print queues via the Print Center + // at any point. Therefore, we need to completely requery the system + // for print queues when our watch file changes. + sal_Int32 applePrintSystem; + + applePrintSystem = macxp_GetSystemPrintMethod(); + if ( applePrintSystem == kApplePrintingCUPS ) + m_aSystemPrintQueues.clear(); +#endif initialize(); + } return bChanged; } @@ -174,11 +196,19 @@ void PrinterInfoManager::initialize() { +#ifdef MACOSX + sal_Int32 applePrintSystem; +#endif rtl_TextEncoding aEncoding = gsl_getSystemTextEncoding(); m_aPrinters.clear(); m_aWatchFiles.clear(); OUString aDefaultPrinter; +#ifdef MACOSX + // Discover the print system to use on Mac OS X/Darwin + applePrintSystem = macxp_GetSystemPrintMethod(); +#endif + // first initialize the global defaults // have to iterate over all possible files // there should be only one global setup section in all @@ -220,7 +250,8 @@ m_aGlobalDefaults.m_eOrientation = aValue.EqualsIgnoreCaseAscii( "Landscape" ) ? orientation::Landscape : orientation::Portrait; aValue = aConfig.ReadKey( "Scale" ); - m_aGlobalDefaults.m_nScale = aValue.ToInt32(); + if ( aValue.Len() ) + m_aGlobalDefaults.m_nScale = aValue.ToInt32(); aValue = aConfig.ReadKey( "MarginAdjust" ); m_aGlobalDefaults.m_nLeftMarginAdjust = aValue.GetToken( 0, ',' ).ToInt32(); @@ -273,6 +304,52 @@ } fillFontSubstitutions( m_aGlobalDefaults ); +#ifdef MACOSX + // For Mac OS X 10.2 with CUPS printing, we also wish to be + // notified of queue/printer updates, but these don't necessarily + // happen when psprint.conf changes. The user can change settings in + // the Print Center which should also make OOo update its queue list. + if ( applePrintSystem == kApplePrintingCUPS ) + { + // /etc/cups/printers.conf gets modified every time the Print Center printer + // list is modified, so we want to watch this file too. + INetURLObject aCUPSDir( String(RTL_CONSTASCII_USTRINGPARAM(MACXP_CUPS_CONF_DIR)), INET_PROT_FILE, INetURLObject::ENCODE_ALL ); + INetURLObject aCUPSConfFile( aCUPSDir ); + aCUPSConfFile.Append( String(RTL_CONSTASCII_USTRINGPARAM(MACXP_CUPS_CONF_FILENAME)) ); + + // check directory validity + OUString aCUPSUniPath; + FileBase::getFileURLFromSystemPath( aCUPSDir.PathToFileName(), aCUPSUniPath ); + Directory aTestDirectory( aCUPSUniPath ); + + // If aTestDirectory.open() returns E_None (0), then we are OK. + // If not, don't add the watch file because we can't get to it. + if( aTestDirectory.open() == FileBase::E_None ) + { + aTestDirectory.close(); + + FileBase::getFileURLFromSystemPath( aCUPSConfFile.PathToFileName(), aCUPSUniPath ); + FileStatus aTestStatus( FileStatusMask_All ); + DirectoryItem aTestItem; + + // setup WatchFile list + WatchFile aCUPSWatchFile; + aCUPSWatchFile.m_aFilePath = aCUPSUniPath; + if( ! DirectoryItem::get( aCUPSUniPath, aTestItem ) && + ! aTestItem.getFileStatus( aTestStatus ) ) + { + aCUPSWatchFile.m_aModified = aTestStatus.getModifyTime(); + } + else + { + aCUPSWatchFile.m_aModified.Seconds = 0; + aCUPSWatchFile.m_aModified.Nanosec = 0; + } + m_aWatchFiles.push_back( aCUPSWatchFile ); + } + } +#endif + // now collect all available printers for( print_dir_it = aDirList.begin(); print_dir_it != aDirList.end(); ++print_dir_it ) { @@ -377,6 +454,16 @@ */ #if defined SOLARIS || defined(IRIX) aValue = "lp"; +#elif defined(MACOSX) + if ( applePrintSystem == kApplePrintingCUPS ) + aValue = "lp"; + else if ( applePrintSystem == kApplePrintingPrintCenter ) + aValue = kApplePCPrintCommand; + else + { + // Fallback case is kApplePrintingLPR + aValue = "lpr"; + } #else aValue = "lpr"; #endif @@ -405,11 +492,9 @@ if( aValue.Len() ) aPrinter.m_aInfo.m_eOrientation = aValue.EqualsIgnoreCaseAscii( "Landscape" ) ? orientation::Landscape : orientation::Portrait; + aValue = aConfig.ReadKey( "Scale" ); if( aValue.Len() ) - { - aValue = aConfig.ReadKey( "Scale" ); aPrinter.m_aInfo.m_nScale = aValue.ToInt32(); - } aValue = aConfig.ReadKey( "MarginAdjust" ); if( aValue.Len() ) @@ -536,6 +621,124 @@ aPrinter.m_bModified = false; aPrinter.m_aGroup = ByteString( aPrinterName, aEncoding ); //provide group name in case user makes this one permanent in padmin +#ifdef MACOSX + // If we are using OS X 10.2 CUPS printing, we want to grab the PPD that this printer + // is associated with from /etc/cups/ppd (it's autocreated by the OS X printing system) and + // use those values instead of the ones generated in the merged defaults. We want to make + // this system printer just like we assigned it a PPD in padmin. + if ( applePrintSystem == kApplePrintingCUPS ) + { + aPrinter.m_aInfo.m_aFontSubstitutes.clear(); + aPrinter.m_aInfo.m_aFontSubstitutions.clear(); + + // Printer's autogenerated PPD will be /etc/cups/ppd/.ppd + aPrinter.m_aInfo.m_aDriverName = String( *it ); + aPrinter.m_aInfo.m_pParser = PPDParser::getParser( aPrinter.m_aInfo.m_aDriverName ); + aPrinter.m_aInfo.m_aContext.setParser( aPrinter.m_aInfo.m_pParser ); + + if( aPrinter.m_aInfo.m_pParser ) + { + // merge the ppd context keys if the printer has the same keys and values + // 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 ); + // If the default PPD has a certain key, attempt to get that same key in the Printer's PPD + const PPDKey* pPrinterKey = pDefKey ? aPrinter.m_aInfo.m_pParser->getKey( pDefKey->getKey() ) : NULL; + + // The key usually merged is PageSize + if( pDefKey && pPrinterKey ) + { + // Key exists in both the Default PPD and the printer's specific PPD. + if( pDefValue ) + { + const PPDValue* pPrinterValue = pPrinterKey->getValue( pDefValue->m_aOption ); + // If the printer has a corresponding option for the key, use printer PPD's option + if( pPrinterValue ) + aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, pPrinterValue ); + } + else + aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, NULL ); + } + } + + // Some CUPS PPDs on Mac OS X (Epson, HP) don't include the requisite + // PageSize information for the value. We have to fudge it from the + // margin information. Others (Canon BJC 8200) have the coordinates + // but not the "setpagedevice" stuff + const PPDKey* pPSizeKey = aPrinter.m_aInfo.m_pParser->getKey( String(RTL_CONSTASCII_USTRINGPARAM("PageSize")) ); + if ( pPSizeKey ) + { + int psIndex = 0; + int nNumValues = pPSizeKey->countValues(); + + for ( psIndex = 0; psIndex < nNumValues; psIndex++ ) + { + const PPDValue* pPSizeValue = pPSizeKey->getValue( psIndex ); + + // Only take care of PPD values that are not formatted correctly. + if ( pPSizeValue && + ( !(pPSizeValue->m_aValue.Len()) || + (pPSizeValue->m_aValue.Len() && (pPSizeValue->m_aValue.SearchAscii("setpagedevice")==STRING_NOTFOUND)) ) + ) + { + // Deal with the two cases: 1) where there is a blank PageSize value and + // 2) where there are simply the dimensions as the PageSize value + if ( !pPSizeValue->m_aValue.Len() ) + { + int paperWidth; + int paperHeight; + char aWidth[ 32 ]; + char aHeight[ 32 ]; + + // Grab dimensions for this paper size from the "PaperDimension" key of the PPD + aPrinter.m_aInfo.m_pParser->getPaperDimension( pPSizeValue->m_aOption, paperWidth, paperHeight ); + snprintf( aWidth, 32, "%d", paperWidth ); + snprintf( aHeight, 32, "%d", paperHeight ); + + // Construct a suitable PageSize key value from the PaperDimension values for this paper size + pPSizeValue->m_aValue.AppendAscii( "<m_aValue.AppendAscii( aWidth ); + pPSizeValue->m_aValue.AppendAscii( " " ); + pPSizeValue->m_aValue.AppendAscii( aHeight ); + pPSizeValue->m_aValue.AppendAscii( "] /ImagingBBox null>> setpagedevice" ); + } + else + { + String aBox( pPSizeValue->m_aValue ); + + // The PageSize value was just the bounding box, add in the correct postscript + pPSizeValue->m_aValue.AssignAscii( "" ); + pPSizeValue->m_aValue.AppendAscii( "<m_aValue.Append( aBox ); + pPSizeValue->m_aValue.AppendAscii( "] /ImagingBBox null>> setpagedevice" ); + } + } + } + } + } + else + { + ByteString aBytePrinterName = ByteString( UniString(aPrinter.m_aInfo.m_aDriverName), RTL_TEXTENCODING_UTF8 ); + fprintf( stderr, "Could not get Printer PPD from /etc/cups/ppd for printer '%s'! Using simple shared printer PPD...\n", aBytePrinterName.GetBuffer() ); + + // Some printers don't have the PPDs in /etc/cups/ppd (like Rendezvous-shared ones) + // so we have to simply use a stripped down shared printer PPD for them + aPrinter.m_aInfo.m_aDriverName = String( RTL_CONSTASCII_USTRINGPARAM("MacShared") ); + aPrinter.m_aInfo.m_pParser = PPDParser::getParser( aPrinter.m_aInfo.m_aDriverName ); + aPrinter.m_aInfo.m_aContext.setParser( aPrinter.m_aInfo.m_pParser ); + if( !(aPrinter.m_aInfo.m_pParser) ) + { + fprintf( stderr, "Warning: still couldn't load the PPD, MacShared.ppd may be missing. Will use generic printer PPD.\n" ); + aPrinter.m_aInfo.m_aDriverName = String( RTL_CONSTASCII_USTRINGPARAM("SGENPRT") ); + aPrinter.m_aInfo.m_pParser = PPDParser::getParser( aPrinter.m_aInfo.m_aDriverName ); + aPrinter.m_aInfo.m_aContext.setParser( aPrinter.m_aInfo.m_pParser ); + } + } + } +#endif + m_aPrinters[ aPrinterName ] = aPrinter; } } @@ -1017,6 +1220,16 @@ { "/usr/sbin/lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0 }, { "lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0 }, { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpstat -s", "lp -d \"(PRINTER)\"", "system for ", ": ", 1 } +#elif defined(MACOSX) + /* These elements correspond to the constants defined for Apple printing in + * printerinfomanager.hxx and are indexed by those constants. ORDER IS IMPORTANT!!! + */ + /* Apple LPR printing (kApplePrintingLPR) */ + { "/usr/bin/lpc status", "lpr -P (PRINTER)", "", ":", 0 }, + /* Apple CUPS printing (kApplePrintingCUPS) */ + { "LANG=C;LC_ALL=C;export LANG LC_ALL;/usr/bin/lpstat -s", "lp -d (PRINTER)", "device for ", ": ", 1 }, + /* Apple Print Center printing (kApplePrintingPrintCenter) */ + { kApplePCQueueName, kApplePCPrintCommand, "", ":", 0 } #else { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpstat -s", "lp -d \"(PRINTER)\"", "system for ", ": ", 1 }, { "/usr/sbin/lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0 }, @@ -1033,9 +1246,16 @@ bool bSuccess = false; std::list< ByteString > aLines; rtl_TextEncoding aEncoding = gsl_getSystemTextEncoding(); - OUString aPrintCommand; +#ifdef MACOSX + sal_Int32 applePrintSysType; + + /* Get our OS specific printing scheme for MacOS X */ + applePrintSysType = macxp_GetSystemPrintMethod(); +#endif + + /* Discover which command we can use to get a list of all printer queues */ for( i = 0; i < sizeof(aParms)/sizeof(aParms[0]) && ! bSuccess; i++ ) { aLines.clear(); @@ -1047,54 +1267,209 @@ #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "trying print queue command \"%s\" ... ", aParms[i].pQueueCommand ); #endif - if( pPipe = popen( aPrtQueueCmd.GetBuffer(), "r" ) ) + #ifdef MACOSX + /* For Mac OS X 10.1 Print Center printing, we only use the default queue. We do not + * need to discover it. So when it comes up in the list of possible queues, + * recognize it and declare success. + */ + if ( applePrintSysType == kApplePrintingPrintCenter ) { - while( fgets( pBuffer, 1024, pPipe ) ) - aLines.push_back( ByteString( pBuffer ) ); - if( ! pclose( pPipe ) ) - bSuccess = true; + if ( strstr(aPrtQueueCmd.GetBuffer(), kApplePCQueueName) != NULL ) + bSuccess = TRUE; + #ifdef DEBUG + else + fprintf( stderr, "Ignoring print queue command \"%s\" because using 10.1 Print Center printing.\n", aParms[i].pQueueCommand ); + #endif + } + else + #endif + { + if( pPipe = popen( aPrtQueueCmd.GetBuffer(), "r" ) ) + { + while( fgets( pBuffer, 1024, pPipe ) ) + aLines.push_back( ByteString( pBuffer ) ); + if( ! pclose( pPipe ) ) + bSuccess = true; + } } #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "%s\n", bSuccess ? "success" : "failed" ); #endif } - if( bSuccess ) +#ifdef MACOSX + /* Since we only print to the default printer for MacOS X 10.1, + * queue discovery serves no purpose. + */ + if ( applePrintSysType == kApplePrintingPrintCenter ) { std::list< OUString > aSysPrintQueues; - while( aLines.begin() != aLines.end() ) + aSysPrintQueues.push_back( OUString::createFromAscii(kApplePCQueueName) ); + #ifdef DEBUG + fprintf( stderr, "printerinfomanager.cxx: using Print Center default print queue.\n" ); + #endif + + MutexGuard aGuard( m_aMutex ); + m_bChanged = true; + m_aQueues = aSysPrintQueues; + m_aCommand = aPrintCommand; + } + else +#endif /* MACOSX */ + { + /* Normal Unix print queue discovery, also used for Darwin 5 LPR printing + * and MacOS X 10.2/Darwin 6 CUPS printing. + */ + if( bSuccess ) { - int nPos = 0, nAftPos; + std::list< OUString > aSysPrintQueues; + + while( aLines.begin() != aLines.end() ) + { + int nPos = 0, nAftPos; - ByteString aOutLine( aLines.front() ); - aLines.pop_front(); + ByteString aOutLine( aLines.front() ); + aLines.pop_front(); - for( int i = 0; i < nForeTokenCount && nPos != STRING_NOTFOUND; i++ ) - { - nPos = aOutLine.Search( aForeToken, nPos ); - if( nPos != STRING_NOTFOUND && aOutLine.Len() >= nPos+aForeToken.Len() ) - nPos += aForeToken.Len(); - } - if( nPos != STRING_NOTFOUND ) - { - nAftPos = aOutLine.Search( aAftToken, nPos ); - if( nAftPos != STRING_NOTFOUND ) + for( int i = 0; i < nForeTokenCount && nPos != STRING_NOTFOUND; i++ ) { - OUString aSysQueue( String( aOutLine.Copy( nPos, nAftPos - nPos ), aEncoding ) ); - // do not insert duplicates (e.g. lpstat tends to produce such lines) - std::list< OUString >::const_iterator it; - for( it = aSysPrintQueues.begin(); it != aSysPrintQueues.end() && *it != aSysQueue; ++it ) - ; - if( it == aSysPrintQueues.end() ) - aSysPrintQueues.push_back( aSysQueue ); + nPos = aOutLine.Search( aForeToken, nPos ); + if( nPos != STRING_NOTFOUND && aOutLine.Len() >= nPos+aForeToken.Len() ) + nPos += aForeToken.Len(); + } + if( nPos != STRING_NOTFOUND ) + { + nAftPos = aOutLine.Search( aAftToken, nPos ); + if( nAftPos != STRING_NOTFOUND ) + { + OUString aSysQueue( String( aOutLine.Copy( nPos, nAftPos - nPos ), aEncoding ) ); + // do not insert duplicates (e.g. lpstat tends to produce such lines) + std::list< OUString >::const_iterator it; + for( it = aSysPrintQueues.begin(); it != aSysPrintQueues.end() && *it != aSysQueue; ++it ) + ; + if( it == aSysPrintQueues.end() ) + aSysPrintQueues.push_back( aSysQueue ); + } } } - } - MutexGuard aGuard( m_aMutex ); - m_bChanged = true; - m_aQueues = aSysPrintQueues; - m_aCommand = aPrintCommand; + MutexGuard aGuard( m_aMutex ); + m_bChanged = true; + m_aQueues = aSysPrintQueues; + m_aCommand = aPrintCommand; + } } } + +#ifdef MACOSX + +/* On Apple systems printing gets more complicated... + * 1) Darwin 5: use straight lpr system, user has to configure lpr correctly + * 2) MacOS X 10.1: use /usr/sbin/Print which prints to default Print Center printer + * 3) MacOS X 10.2: use CUPS duo of lpstat/lp + * 4) Darwin 6: Like MacOS X 10.2, use CUPS + * + * --- FIXME --- We don't support printer choosing on MacOS X 10.1 at this time, + * only printing to default Print Center printer. The user can + * change the default Print Center printer at any point however. + */ + +/* + * macxp_GetSystemPrintMethod() + * + * Find out which printing system/OS we are using. + * + * Darwin 5 is the fallback case. To check for 10.1 printing we try to see if + * /usr/sbin/Print exists. For 10.2/Darwin 6, we attempt to find lpstat. Users + * might also have installed CUPS on Darwin 5 or MacOS X 10.1, but we default to + * Print Center (/usr/sbin/Print) printing on 10.1. + * + */ +sal_Int32 macxp_GetSystemPrintMethod( void ) +{ + int applePrintSysType; + int err; + struct stat status; + + /* Attempt to find out which OS we are on... */ + applePrintSysType = kApplePrintingLPR; + + /* Check for MacOS X 10.1 first. */ + err = stat( "/usr/sbin/Print", &status ); + if ( err == 0 ) + { + applePrintSysType = kApplePrintingPrintCenter; + #ifdef DEBUG + fprintf( stderr, "printerinfomanager.cxx: found MacOS X 10.1-type printing system.\n" ); + #endif + } + else + { + /* Test for MacOS X 10.2/Darwin6 CUPS printing */ + err = stat( "/usr/bin/lpstat", &status ); + if ( err == 0 ) + { + applePrintSysType = kApplePrintingCUPS; + #ifdef DEBUG + fprintf( stderr, "printerinfomanager.cxx: found MacOS X 10.2-type CUPS-based printing system.\n" ); + #endif + } + } + + #ifdef DEBUG + if ( applePrintSysType == kApplePrintingLPR ) + fprintf( stderr, "printerinfomanager.cxx: falling back to Darwin5-type LPR printing system.\n" ); + #endif + + return( applePrintSysType ); +} + +/* + * macxp_GetSystemPrintFormat() + * + * There are two ways to print: using PostScript (PS) and using PDF. + * Because MacOS X 10.2 CUPS printing has PDF converts built in for + * almost every printer, it is very easy to print using PDF. For 10.1, + * extra steps must be taken to print with PDF, but it is still more + * compatible. For Darwin 5 and 6, we default to PS printing. + * + * The user may still wish to print PS to PS compatible printers and + * therefore the environment variable OOO_PRINT_PS_DIRECTLY, if set, + * forces OOo to NOT undergo the PS -> PDF translation by default. + */ +/*sal_Int32 macxp_GetSystemPrintFormat( void ) +{ + int printFormat; + int err; + struct stat status; + sal_Char *pPDFOverride = NULL; + + printFormat = kApplePrintingUsePS; + + /* Check for presence of OSAScript executable, which is + * believed to be MacOS X only (ie not present on Darwin). + * + err = stat( "/usr/bin/osascript", &status ); + if ( err == 0 ) + { + /* Check to see if the user wants to print PS anyway * + pPDFOverride = getenv( "OOO_PRINT_PS_DIRECTLY" ); + if ( pPDFOverride == NULL ) + { + /* Now we have to check for ps2pdf to make sure we can do the conversion * + err = stat( kApplePS2PDFLocation, &status ); + if ( err == 0 ) + { + printFormat = kApplePrintingUsePDF; + #ifdef DEBUG + fprintf( stderr, "printerinfomanager.cxx: Will print in PDF format using PS->PDF coversion filters.\n" ); + #endif + } + } + } + + return( printFormat ); +}*/ +#endif + Index: source/printergfx/makefile.mk =================================================================== RCS file: /cvs/gsl/psprint/source/printergfx/makefile.mk,v retrieving revision 1.2 diff -u -r1.2 makefile.mk --- source/printergfx/makefile.mk 20 Aug 2002 15:10:29 -0000 1.2 +++ source/printergfx/makefile.mk 5 Oct 2003 03:20:23 -0000 @@ -73,6 +73,13 @@ # --- Files -------------------------------------------------------- +.IF "$(GUIBASE)"=="aqua" + +dummy: + @echo "Nothing to build for GUIBASE $(GUIBASE)" + +.ELSE # "$(GUIBASE)"=="aqua" + SLOFILES=\ $(SLO)$/printerjob.obj \ $(SLO)$/text_gfx.obj \ @@ -80,6 +87,8 @@ $(SLO)$/common_gfx.obj \ $(SLO)$/glyphset.obj \ $(SLO)$/bitmap_gfx.obj + +.ENDIF # --- Targets ------------------------------------------------------ Index: source/printergfx/printerjob.cxx =================================================================== RCS file: /cvs/gsl/psprint/source/printergfx/printerjob.cxx,v retrieving revision 1.21 diff -u -r1.21 printerjob.cxx --- source/printergfx/printerjob.cxx 26 Mar 2003 14:24:08 -0000 1.21 +++ source/printergfx/printerjob.cxx 5 Oct 2003 03:20:24 -0000 @@ -107,6 +107,19 @@ using namespace psp ; +#ifdef MACOSX +// Prototype our MacOS X printing help function +void macxp_ProcessAndPrintDocument( sal_Int32 applePrintSysType, + char *spoolFileName, + FILE *pDestFile, + const rtl::OString psprintPrintCmd, + const rtl::OString psprintDriverName, + const JobData pJobData, + const rtl::OUString *aJobName, + sal_uInt32 jobDPI ); +int macxp_ConvertPSFileToPDF( char *psFileName, char *pdfFileName, int pdfFileNameBufferLen, sal_uInt32 jobDPI ); +#endif + // forward declaration #define nBLOCKSIZE 0x2000 @@ -431,6 +444,7 @@ maFileName = rFileName; mnFileMode = nMode; maSpoolDirName = createSpoolDir (); + maJobName = rJobName; rtl::OUString aExt = rtl::OUString::createFromAscii (".ps"); mpJobHeader = CreateSpoolFile (rtl::OUString::createFromAscii("psp_head"), aExt); @@ -496,6 +510,11 @@ sal_Bool PrinterJob::EndJob () { +#ifdef MACOSX + sal_Int32 applePrintSysType; + char *spoolFileName = NULL; +#endif + // write document setup (done here because it // includes the accumulated fonts writeSetup( mpJobHeader, m_aDocumentJobData ); @@ -519,8 +538,12 @@ FILE* pDestFILE = NULL; - /* create a destination either as file or as a pipe */ +#ifdef MACOSX + /* Ascertain the printing system */ + applePrintSysType = macxp_GetSystemPrintMethod(); +#endif + /* create a destination either as file or as a pipe */ sal_Bool bSpoolToFile = maFileName.getLength() > 0 ? sal_True : sal_False; if (bSpoolToFile) { @@ -558,9 +581,48 @@ const rtl::OString aShellCommand = rtl::OUStringToOString (rCommand, RTL_TEXTENCODING_ISO_8859_1); - pDestFILE = popen (aShellCommand.getStr(), "w"); - if (pDestFILE == NULL) - return sal_False; + /* Mac OS X: open a pipe only if we are using (1) Darwin5 LPR printing. + * All other OS X/Darwin cases use spool to file. + * Other UNIX: always open a pipe. + */ + if ( + #ifdef MACOSX + applePrintSysType == kApplePrintingLPR + #else + sal_True + #endif + ) + { + pDestFILE = popen (aShellCommand.getStr(), "w"); + if (pDestFILE == NULL) + return sal_False; + } + #ifdef MACOSX + else + { + /* Spool to file instead so we can convert it. Cases used here: + * 1) kApplePrintingPrintCenter && kApplePrintingUsePDF + * 2) kApplePrintingPrintCenter && kApplePrintingUsePS + * 3) kApplePrintingCUPS && kApplePrintingUsePDF + * 4) kApplePrintingCUPS && kApplePrintingUsePS + */ + + /* Get a temporary file name for the spool file. + * This name must be free()ed later. + */ + spoolFileName = macxp_tempnam( NULL, "ooopj" ); + if ( spoolFileName == NULL ) + return sal_False; + + /* Create temporary spool file */ + pDestFILE = fopen( spoolFileName, "w" ); + if ( pDestFILE == NULL ) + { + free( spoolFileName ); + return sal_False; + } + } + #endif } /* spool the document parts to the destination */ @@ -598,10 +660,324 @@ if (bSpoolToFile) fclose (pDestFILE); else - pclose (pDestFILE); + { + #ifdef MACOSX + sal_uInt32 nXdpi; + sal_uInt32 nYdpi; + + /* For Mac OS X/Darwin, process and spool the file to the printing subsystem + * if required. + */ + const rtl::OUString& rPrinter = m_aLastJobData.m_aPrinterName; + const PrinterInfoManager& rPrinterInfoManager = PrinterInfoManager::get(); + const PrinterInfo& rPrinterInfo = rPrinterInfoManager.getPrinterInfo( rPrinter ); + + // Grab printer's spool command + const rtl::OUString& rCommand = rPrinterInfo.m_aCommand; + const rtl::OString aShellCommand = rtl::OUStringToOString( rCommand, RTL_TEXTENCODING_ISO_8859_1 ); + + // Grab the printer's PPD file name + const rtl::OUString& rDriverName = rPrinterInfo.m_aDriverName; + const rtl::OString aDriverName = rtl::OUStringToOString( rDriverName, RTL_TEXTENCODING_ISO_8859_1 ); + + /* Grab the resolution for the job, for use in PS->PDF conversion */ +/* GetResolution( nXdpi, nYdpi );*/ + + macxp_ProcessAndPrintDocument( applePrintSysType, + spoolFileName, + pDestFILE, + aShellCommand, + aDriverName, + m_aLastJobData, + &maJobName, + mnResolution ); + #else + pclose (pDestFILE); + #endif + } + +#ifdef MACOSX + /* If we created a spool file for our Mac OS X/Darwin job, + * delete it. Also free the variable, since it is malloc()ed in macxp_tempnam() + * and otherwise we'd leak memory. + */ + if ( spoolFileName ) + { + unlink( spoolFileName ); + free( spoolFileName ); + } +#endif return sal_True; } + +#ifdef MACOSX +// Because the printing on MacOS X and Darwin is a bit more complicated, +// its got its own routine. + +#define kSysCommandBufferLen 1024 +#define kPDFFileNameBufferLen 1024 + +void macxp_ProcessAndPrintDocument( sal_Int32 applePrintSysType, + char *spoolFileName, + FILE *pDestFile, + const rtl::OString psprintPrintCmd, + const rtl::OString psprintDriverName, + const JobData pJobData, + const rtl::OUString *aJobName, + sal_uInt32 jobDPI ) +{ + char sysCommandBuffer[ kSysCommandBufferLen ]; + int printCmdErr; + sal_Int32 printFormat; + + if ( applePrintSysType == kApplePrintingLPR ) + { + /* Job is to be printed with Darwin5 lpr. It has already + * been piped to lp/lpr above in EndJob(), so simply + * close the pipe. + */ + pclose( pDestFile ); + } + else + { + /* Handle cases for MacOS X printing that don't pipe directly to lp/lpr */ + + /* Close the intermediate file */ + fclose( pDestFile ); + + /* Determine if we are going to print with PostScript, or with PS->PDF conversion. + * We assume we are to use PS->PDF conversion unless proven otherwise. Most printers + * will have a PPD, except Rendezvous-shared ones. If the PPD _doesn't_ have the + * "cupsFilter" key, or if the "cupsFilter" key _doesn't_ contain "application/pdf", + * then we print directly with PostScript. + */ + printFormat = kApplePrintingUsePDF; + if ( (sal_False == psprintDriverName.equals("SGENPRT")) && (sal_False == psprintDriverName.equals("MacShared")) ) + { + /* The should exist a valid PPD for this printer */ + if ( pJobData.m_pParser ) + { + const PPDKey *pCupsFilterKey; + const PPDValue *pCupsFilterValue; + + pCupsFilterKey = pJobData.m_pParser->getKey( String(RTL_CONSTASCII_USTRINGPARAM("cupsFilter")) ); + pCupsFilterValue = pCupsFilterKey != NULL ? pJobData.m_aContext.getValue( pCupsFilterKey ) : NULL; + if ( pCupsFilterValue ) + { + ByteString aCupsFilterString( pCupsFilterValue->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ); + if ( aCupsFilterString.Search("application/pdf") == 0 ) + { + /* cupsFilter didn't have application/pdf */ + printFormat = kApplePrintingUsePS; + } + } + else + { + /* No "cupsFilter" key */ + printFormat = kApplePrintingUsePS; + } + } + } + + if ( (applePrintSysType==kApplePrintingPrintCenter) && (printFormat==kApplePrintingUsePS) ) + { + /* Now pass the PS file to /usr/sbin/Print for printing. */ + snprintf( sysCommandBuffer, kSysCommandBufferLen-1, "%s -M ps \"%s\"", kApplePCPrintCommand, spoolFileName ); + #ifdef DEBUG + fprintf( stderr, "printerjob.cxx: printing doc with command '%s'\n", sysCommandBuffer ); + #endif + + printCmdErr = system( sysCommandBuffer ); + } + else if ( (applePrintSysType==kApplePrintingPrintCenter) && (printFormat==kApplePrintingUsePDF) ) + { + char pdfFileName[ kPDFFileNameBufferLen ]; + char pdfFileNameMacFormat[ kPDFFileNameBufferLen ]; + char *c; + + /* Convert file to PDF using GhostScript */ + printCmdErr = macxp_ConvertPSFileToPDF( spoolFileName, pdfFileName, kPDFFileNameBufferLen, jobDPI ); + if ( printCmdErr == 0 ) + { + /* AppleScript expects MacOS-style paths, so convert Unix path to Mac OS Style. + * If the Unix path is absolute, get rid of the starting slash + */ + strncpy( pdfFileNameMacFormat, pdfFileName, kPDFFileNameBufferLen-1 ); + if ( *pdfFileNameMacFormat == '/' ) + sprintf( pdfFileNameMacFormat, "%s", (pdfFileNameMacFormat+1) ); + while ( (c=strchr(pdfFileNameMacFormat,'/')) != NULL ) + *c = ':'; + + /* Construct and execute the actual printing command using AppleScript */ + snprintf( sysCommandBuffer, kSysCommandBufferLen-1, "/usr/bin/osascript -e 'tell application \"Finder\"' -e 'print {file \"%s\"}' -e 'end tell'", pdfFileNameMacFormat ); + #ifdef DEBUG + fprintf( stderr, "printerjob.cxx: printing PDF with command '%s'\n", sysCommandBuffer ); + #endif + printCmdErr = system( sysCommandBuffer ); + } + unlink( pdfFileName ); + } + else if ( (applePrintSysType==kApplePrintingCUPS) && ((printFormat==kApplePrintingUsePDF) || (printFormat==kApplePrintingUsePS)) ) + { + char pdfFileName[ kPDFFileNameBufferLen ]; + char numCopiesSwitch[ 5 ]; + sal_uInt32 index; + + /* Convert file to PDF using GhostScript if using PS->PDF conversion */ + if ( printFormat == kApplePrintingUsePDF ) + printCmdErr = macxp_ConvertPSFileToPDF( spoolFileName, pdfFileName, kPDFFileNameBufferLen, jobDPI ); + else + { + strncpy( pdfFileName, spoolFileName, kPDFFileNameBufferLen ); + printCmdErr = 0; + } + + if ( printCmdErr == 0 ) + { + #define kJobOptionsStringSize 500 + char jobOptions[ kJobOptionsStringSize ]; + + jobOptions[ 0 ] = NULL; + /* Based on job options, find out what parameters to pass to the printer. */ + if ( pJobData.m_pParser ) + { + const PPDKey *pSizeKey; + const PPDValue *pSizeValue; + const PPDKey *pSlotKey; + const PPDValue *pSlotValue; + BOOL needComma = FALSE; + + // Only CUPS PS->PDF printers require the page size options + if ( printFormat == kApplePrintingUsePDF ) + { + // Add page size option if necessary + pSizeKey = pJobData.m_pParser->getKey( String(RTL_CONSTASCII_USTRINGPARAM("PageSize")) ); + pSizeValue = pSizeKey != NULL ? pJobData.m_aContext.getValue( pSizeKey ) : NULL; + if ( pSizeValue ) + { + ByteString aSizeString( pSizeValue->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ); + snprintf( jobOptions, kJobOptionsStringSize, "-o \"media=" ); + strncat( jobOptions, aSizeString.GetBuffer(), kJobOptionsStringSize-strlen(jobOptions) ); + needComma = TRUE; + } + } + + // Add paper tray option if necessary + pSlotKey = pJobData.m_pParser->getKey( String(RTL_CONSTASCII_USTRINGPARAM("InputSlot")) ); + pSlotValue = pSlotKey != NULL ? pJobData.m_aContext.getValue( pSlotKey ) : NULL; + if ( pSlotValue ) + { + ByteString aSlotString( pSlotValue->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ); + // If the string wasn't created from PageSize, create it now + if ( strlen(jobOptions) == 0 ) + snprintf( jobOptions, kJobOptionsStringSize, "-o \"media=" ); + if ( TRUE == needComma ) + strncat( jobOptions, ",", kJobOptionsStringSize - strlen(jobOptions) ); + + strncat( jobOptions, aSlotString.GetBuffer(), kJobOptionsStringSize - strlen(jobOptions) ); + } + + // Add on the ending " to the media= part + if ( strlen(jobOptions) > 0 ) + strncat( jobOptions, "\"", kJobOptionsStringSize - strlen(jobOptions) ); + + /* Deal with landscape orientation */ + // Disable for the moment since testers say it has undesired effects + // if ( pJobData.m_eOrientation == orientation::Landscape ) + // strncat( jobOptions, " -o landscape ", kJobOptionsStringSize - strlen(jobOptions) ); + + /* Attach a job title */ + ByteString jobTitle( aJobName->getStr(), RTL_TEXTENCODING_UTF8 ); + snprintf( jobOptions, kJobOptionsStringSize, "%s -t \"%s\"", jobOptions, jobTitle.GetBuffer() ); + } + + /* Construct and execute the printing command */ + snprintf( sysCommandBuffer, kSysCommandBufferLen-1, "cat \"%s\" | %s %s", pdfFileName, psprintPrintCmd.getStr(), jobOptions ); + #ifdef DEBUG + fprintf( stderr, "printerjob.cxx: printing PDF with command '%s'\n", sysCommandBuffer ); + #endif + + /* Stupid lp and lpr on 10.2 don't actually honor their respective # copies arguments. + * So we have to just keep printing the job over and over for multiple copies for PS->PDF + * printers. Direct-to-PostScript printers can handle the # copies _inside_ the PostScript + * document we are sending to them. + */ + int numCopies = (printFormat == kApplePrintingUsePDF ) ? pJobData.m_nCopies : 1; + for( index = 1; index <= numCopies; index++ ) + printCmdErr = system( sysCommandBuffer ); + } + unlink( pdfFileName ); + } + + #ifdef DEBUG + /* A printCmdErr of -1 will usually be an error in PS->PDF conversion, + * otherwise its an error returned by system(). + */ + if ( printCmdErr != 0 ) + fprintf( stderr, "printerjob.cxx: printing error, got %d.\n", printCmdErr ); + else + fprintf( stderr, "printerjob.cxx: printing successful, system() returned 0.\n" ); + #endif + } +} + +#define kSysPrintSetupString "sh -c 'PATH=$PATH:/usr/local/bin" +#define kPDFFileExtension ".pdf" + +// Convert PostScript files to PDF for easy printing, using GhostScript. +// Returns: 0 if no error +// -1 if error +int macxp_ConvertPSFileToPDF( char *psFileName, char *pdfFileName, int pdfFileNameBufferLen, sal_uInt32 jobDPI ) +{ + int returnVal = 0; + int printCmdErr = 0; + + /* Make sure we've got the space to play with file names/paths */ + if ( (strlen(psFileName) + strlen(kPDFFileExtension)) >= pdfFileNameBufferLen-1 ) + { + fprintf( stderr, "printerjob.cxx: Cannot convert print job to PDF because the file's path is too long.\n" ); + returnVal = -1; + } + else + { + char *sysCommandBuffer; + + /* Create the file name for the converted PDF and assemble the conversion command */ + snprintf( pdfFileName, pdfFileNameBufferLen-1, "%s%s", psFileName, kPDFFileExtension ); + + sysCommandBuffer = (char *)malloc( sizeof(char) * ( strlen(kSysPrintSetupString) + + strlen(kApplePS2PDFLocation) + + 10 + /* For " -r" */ + strlen(psFileName) + + strlen(pdfFileName) + + 10) ); /* 10 bytes fudge factor */ + if ( sysCommandBuffer == NULL ) + returnVal = -1; + else + { + sprintf( sysCommandBuffer, "%s;%s -r%d \"%s\" \"%s\"'", kSysPrintSetupString, kApplePS2PDFLocation, jobDPI, psFileName, pdfFileName ); + #ifdef DEBUG + fprintf( stderr, "printerjob.cxx: converting document to PDF with command '%s'\n", sysCommandBuffer ); + #endif + + /* Convert the PS spool file to a PDF */ + printCmdErr = system( sysCommandBuffer ); + free( sysCommandBuffer ); + + #ifdef DEBUG + if ( printCmdErr != 0 ) + fprintf( stderr, "printerjob.cxx: pdf conversion error, system() returned %d.\n", printCmdErr ); + else + fprintf( stderr, "printerjob.cxx: pdf conversion successful, system() returned 0.\n" ); + #endif + returnVal = (printCmdErr != 0) ? -1 : 0; + } + } + + return( returnVal ); +} +#endif /* MACOSX */ sal_Bool PrinterJob::AbortJob () Index: util/makefile.mk =================================================================== RCS file: /cvs/gsl/psprint/util/makefile.mk,v retrieving revision 1.9 diff -u -r1.9 makefile.mk --- util/makefile.mk 15 Apr 2003 14:34:44 -0000 1.9 +++ util/makefile.mk 5 Oct 2003 03:20:24 -0000 @@ -71,6 +71,13 @@ # --- Allgemein ---------------------------------------------------------- +.IF "$(GUIBASE)"=="aqua" + +dummy: + @echo "Nothing to build for GUIBASE $(GUIBASE)" + +.ELSE # "$(GUIBASE)"=="aqua" + .IF "$(OS)"=="WNT" LIB1TARGET= $(SLB)$/a$(TARGET).lib LIB1FILES= $(SLB)$/fontsubset.lib @@ -102,6 +109,8 @@ SHL1DEF= $(MISC)$/$(SHL1TARGET).def .ENDIF # "$(OS)"=="WNT" + +.ENDIF # GUIBASE = aqua # --- Targets ------------------------------------------------------------