source/OldApp.c

/*
    copyright © 1992-1994 Apple Computer Inc.  All rights reserved.
    
    OldApp.c
    This file implements old application message overrides for the specific driver.
    
    Included in this file is the old PrintRecord emulation.  Note that the ImageWriter
    PrintRecord is a wonder of misdirection and special cases.  You'll have fun
    figuring out the code - so unless you really want to exactly emulate the ImageWriter
    pages, you shouldn't spend too much time looking at this code.
    
    Modification history
    7/23/92         TED             New file today
    12/20/93        dmh             Sync'd with the shipping 1.0b3 GX driver.
     8/26/94        dmh             Sync'd with the shipping 1.0.1 GX driver.
 
*/
 
// Include the standard Mac header files 
#include <Errors.h>
#include <ToolUtils.h>
#include <StdIO.h>
#include <StdLib.h>
#include <String.h>
#include <Strings.h>
#include <Resources.h>
#include <ToolUtils.h>
#include <OSUtils.h>
#include <Files.h>
#include <Types.h>
#include <Packages.h>
#include <Memory.h>
#include <Serial.h>
#include <Devices.h>
#include <Fonts.h>
#include <Printing.h>
#include <Script.h>
#include <Events.h>
#include <Dialogs.h>
#include <FixMath.h>
#include <Lists.h>
#include <AppleTalk.h>
#include <Menus.h>
#include <Events.h>
#include <Balloons.h>
#include <Folders.h>
#include <SCSI.h>
 
// Include the new QuickDraw GX graphics header files 
#include <GXGraphics.h>
#include <GXMath.h>
#include <QDLibrary.h>
#include <FontLibrary.h>
#include <GXLayout.h>
#include <GraphicsLibraries.h>
 
// Include the required Printing Manager header files 
#include <GXPrinting.h>
#include <GXPrinterDrivers.h>
#include <CollectionLibrary.h>
#include <JobFormatModeLibrary.h>
#include <PaperTypeLibrary.h>
#include <PicturesAndPICTLibrary.h>
#include <Collections.h>
#include <GXMessages.h>
 
#include "CommonDefines.h"          // things common to .r and .h files
#include "DriverProtos.h"
 
#if defined(__MWERKS__)
    asm void __Startup__(void);
    asm void __Startup__(void)
    {
        dc.l    0                   // Reserved for owner count.
 
        jmp     SD_ConvertPrintRecordTo
        jmp     SD_ConvertPrintRecordFrom
        jmp     SD_PrintRecordToJob
        jmp     SD_PrValidate
        jmp     SD_PrJobInit
 
        RTS                         // this is needed so __Startup__ symbol works
    }
#endif
 
 
/* ---------------------------------------------------------------------------- */
/* INTERNAL TYPEDEFS AND STRUCTURES                                             */
/* ---------------------------------------------------------------------------- */
// ImageWriter wDev values
#define kBest           0x01
#define kPortrait       0x02
#define kTallAdjusted   0x04
#define k50Percent      0x08
#define kNoGaps         0x10
#define kSetResCalled   0x20
 
// some ImageWriter constants
#define kGapSize        60      // gap at top of page in 120ths of an inch
#define kSmallPlaten    16      // platen width in half inches for small IW
#define kBigPlaten      27      // platen width in half inches for the 15" IW
 
/* ---------------------------------------------------------------------------- */
/* FORWARD DECLARES                                                             */
/* ---------------------------------------------------------------------------- */
OSErr SD_ConvertPrintRecordTo(THPrint hoPrint);
OSErr SD_ConvertPrintRecordFrom(gxUniversalPrintRecordHdl huPrint);
 
 
/* ---------------------------------------------------------------------------- */
/* INTERNAL ROUTINES                                                            */
/* ---------------------------------------------------------------------------- */
OSErr   UpdatePrintRecord(THPrint hPrint)
{
    OSErr                       anErr;
    gxUniversalPrintRecordHdl   huPrint = (gxUniversalPrintRecordHdl)hPrint;
    gxUniversalPrintRecordPtr   puPrint;
    short                       devVRes, devHRes, appVRes, appHRes;
    short                       cPlaten;
    
    // convert to universal format
    anErr = SD_ConvertPrintRecordTo(hPrint);
    if (anErr == noErr)
        {
        // determine application & device resolutions, based upon quality mode, tall adjusted
        // setting, and if the app called SetRsl:
        //  draft - 80(h)*72(v)
        //  faster - 80(h)*72(v)
        //  best - 160(h)*144(v)
        //
        //  draft (tall adjusted) - 72*72
        //  faster (tall adjusted) - 72*72
        //  best (tall adjusted) - 144*144
        
        puPrint = *huPrint;
        if (puPrint->options & gxPreciseBitmap)
            switch(puPrint->qualityMode)
                {
                case gxDraftQuality:
                case gxFasterQuality:
                    devVRes = devHRes = 72;
                    appVRes = appHRes = 72;
                    break;
                    
                case gxBestQuality:
                    devVRes = devHRes = 144;
                    appVRes = appHRes = 72;
                    break;
                }
        else
            switch(puPrint->qualityMode)
                {
                case gxDraftQuality:
                case gxFasterQuality:
                    appVRes = devVRes = 72;
                    appHRes = devHRes = 80;
                    break;
                    
                case gxBestQuality:
                    devVRes = 144;
                    devHRes = 160;
                    appVRes = 72;
                    appHRes = 80;
                    break;
                }
            
        // SetRsl was called?  Use the resolution specified by the application
        if (puPrint->appVRes != 72)
            {
            appVRes = devVRes = puPrint->appVRes;
            appHRes = devHRes = puPrint->appHRes;
            }
            
        // finally, store the app & device resolutions
        puPrint->devVRes = devVRes;
        puPrint->devHRes = devHRes;
        puPrint->appVRes = appVRes;
        puPrint->appHRes = appHRes;
        
        // here we do page size calculations
        // Please note that this code is confusing - it's purpose is to emulate
        // the existing ImageWriter driver's page size.  Most drivers would not
        // do this - the existing in the system probably is good enough.
        {
        long        pageGap;                // gap at top of page
        long        dvPaper, dhPaper;       // paper size at device res
        long        dvPage, dhPage;         // page size at device res
        long        scanLines, scanBits;    // # of scan lines or bits on page
        long        maxH;                   // maximum width
        long        hOff, vOff;             // margins (horiz & vert) to get paper rect from page rect
        
        // gap at the top of the page in pixels
        pageGap = (kGapSize * appVRes) / 120;
        if (puPrint->options & gxBiggerPages)
            pageGap = 0;
            
        // figure out paper size in application space pixels
        dvPaper = (puPrint->pageV * appVRes) / 120;
        dhPaper = (puPrint->pageH * appHRes) / 120;
                
        // vertically, align to the head height of 8 pixels
        scanLines = ((dvPaper - pageGap) >> 3) << 3;
        
        // horizontally, allow the biggest width we can handle
        cPlaten = kSmallPlaten;
        if (puPrint->pageH > (9*120) )
            cPlaten = kBigPlaten;
            
        maxH = (cPlaten * appHRes) >> 1;
        if (maxH > dhPaper)
            maxH = dhPaper;
        scanBits = (maxH >> 4) << 4;
        
        if (puPrint->orientation == gxPortraitOrientation)
            {
            // portrait
            
            dhPage = scanBits;
            dvPage = scanLines;
            
            hOff = (dhPage - dhPaper) >> 1;
            vOff = -pageGap;
            }
        else
            {
            // landscape
            
            dhPage = scanLines;
            dvPage = scanBits;
            
            // reverse the paper definition as well
            {
            long iTemp = dhPaper;
            dhPaper = dvPaper;
            dvPaper = iTemp;
            }
            
            hOff = -pageGap;
            vOff = (dvPage - dvPaper) >> 1;
            }
            
        // 50% reduction?  scale everything by 2X
        if (puPrint->options & gxUserFlag0)
            {
            dhPage <<= 1;
            dvPage <<= 1;
            dhPaper <<= 1;
            dvPaper <<= 1;
            hOff <<= 1;
            vOff <<= 1;
            }
            
        // set the page and paper in app space
        puPrint->appPage.left       = puPrint->appPage.top = 0;
        puPrint->appPage.right      = dhPage;
        puPrint->appPage.bottom     = dvPage;
        
        puPrint->appPaper.left      = hOff;
        puPrint->appPaper.top       = vOff;
        puPrint->appPaper.right     = dhPaper + hOff;
        puPrint->appPaper.bottom    = dvPaper + vOff;
                
        // from page, scale up to device space (in case some weenie decides to look at that)
        puPrint->devPage.left       = puPrint->devPage.top = 0;
        puPrint->devPage.right      = dhPage * devHRes / appHRes;
        puPrint->devPage.bottom     = dvPage * devVRes / appVRes;
        }
        
        // convert back to non-universal format
        anErr = SD_ConvertPrintRecordFrom((gxUniversalPrintRecordHdl) hPrint);
        }
        
    return(anErr);
    
} // UpdatePrintRecord
 
//<FF>
/* ---------------------------------------------------------------------------- */
/* MESSAGE OVERRIDES                                                            */
/* ---------------------------------------------------------------------------- */
OSErr SD_ConvertPrintRecordTo(THPrint hoPrint)
/*
    This call takes a print record in old style (driver specific) format, and
    converts it to the format of "gxUniversalPrintRecordHdl"
*/
{
    TPPrint                     poPrint;            // pointer to old style print record
    gxUniversalPrintRecordHdl   huPrint = (gxUniversalPrintRecordHdl)hoPrint;   // handle to universal print record
    gxUniversalPrintRecordPtr   puPrint;            // pointer to universal print record
    short                       qualityMode;        // cached quality mode
    short                       wDev;               // cached wDev
    
    // cache pointers for size and speed
    puPrint = *huPrint;
    poPrint = *hoPrint;
    wDev = poPrint->prStl.wDev;
    
    // determine quality mode
    if (poPrint->prJob.bJDocLoop == 0)
        qualityMode = gxDraftQuality;
    else
        {
        if (wDev & kBest)
            qualityMode = gxBestQuality;
        else
            qualityMode = gxFasterQuality;
        }
        
    // universal feed is the inverse of our feed
    puPrint->feed           =   1-(poPrint->prStl.feed);
    
    // wDev 0x02 means portrait, else landscape
    if (wDev & kPortrait) 
        puPrint->orientation    =   gxPortraitOrientation;
    else
        {
        puPrint->orientation    =   gxLandscapeOrientation;
        
        // landscape disabled draft, forces tall adjusted
        if (qualityMode == gxDraftQuality)
            qualityMode = gxFasterQuality;
        wDev |= kTallAdjusted;
        }
        
    // copies are in iCopies field (wow.)
    puPrint->actualCopies       =   poPrint->prJob.iCopies;
    
    // store our flags
    puPrint->options = 0;
    
    // tall adjusted
    if (wDev & kTallAdjusted) 
        puPrint->options |= gxPreciseBitmap;
        
    // 50% reduction
    if (wDev & k50Percent) 
        {
        puPrint->options |= gxUserFlag0;
        puPrint->reduction = 50;
        
        // for 50% reduction, we always return faster to the application
        qualityMode = gxFasterQuality;
        }
    else
        puPrint->reduction = 100;
        
    // no gaps
    if (wDev & kNoGaps) 
        puPrint->options |= gxBiggerPages;
    
    // finally, store quality mode  
    puPrint->qualityMode = qualityMode;
    
    // and we can't have any errors - because this code is too godlike.
    return(noErr);
    
} // SD_ConvertPrintRecordTo
 
//<FF>
/* ---------------------------------------------------------------------------- */
OSErr SD_ConvertPrintRecordFrom(gxUniversalPrintRecordHdl huPrint)
/*
    This call takes a print record in universal format and converts it
    to old style (driver specific) format.
    
    Note: for the ImageWriter, I'm filling in way more things than theoretically
    I need to.  However, since the ImageWriter is one of the oldest print drivers,
    there is much more of a chance that someone assumes something about one or
    more of the fields.
*/
{
    gxUniversalPrintRecordPtr   puPrint;            // pointer to universal print record
    THPrint                     hoPrint = (THPrint)huPrint; // handle to old style print record
    TPPrint                     poPrint;            // pointer to old style print record
    short                       options;            // cached universal options
    short                       qualityMode;        // cached universal quality mode
    short                       actualCopies;       // cached universal copies
    
    // cache pointers for size and speed
    puPrint = *huPrint;
    poPrint = *hoPrint;
 
    // save away fields within the universal record that we'll be stomping over
    // as we convert
    options         = puPrint->options;
    qualityMode     = puPrint->qualityMode;
    actualCopies    = puPrint->actualCopies;
    
    poPrint->iPrVersion         = 4;        // used to be 3, but this is
                                            // a new driver.  We support versions
                                            // 3 and 4
    poPrint->prInfo.iDev        = 0;        // always zero for the ImageWriter
    
    // skip remaining fields in prInfo because they are unchanged
    
    // determine the wDev
    {
    short   wDev;
    
    // this is the wDev value for the ImageWriter
    wDev = 0x0100;
    
    if (puPrint->orientation == gxPortraitOrientation)
        wDev |= kPortrait;
    else
        {
        // for landscape, disable draft and force tall adjusted
        if (qualityMode == gxDraftQuality)
            qualityMode = gxFasterQuality;
            
        options |= gxPreciseBitmap;
        }
    
    // user options
    if (options & gxPreciseBitmap)
        wDev |= kTallAdjusted;
    if (options & gxUserFlag0)
        {
        wDev |= k50Percent;
        qualityMode = gxFasterQuality;
        }
 
    if (options & gxBiggerPages)
        wDev |= kNoGaps;
        
    // if the application's resolution isn't 72 - then clearly SetRsl must have been called
    // to change it.
    if (poPrint->prInfo.iVRes != 72)
        {
        wDev |= kSetResCalled;
        qualityMode = gxBestQuality;
        }
        
    if (qualityMode == gxBestQuality)
        wDev |= kBest;
        
        
    // and finally, save away that short value we worked so hard to determine
    poPrint->prStl.wDev = wDev;
    }
 
    // other fields in prStl remain the same
    
    poPrint->prStl.bPort    = 0;
    poPrint->prStl.feed     = 1 - (puPrint->feed);
    poPrint->prInfoPT.iDev  = (qualityMode == gxBestQuality) ? -768 : 0;
 
    // other fields in prInfoPT remain the same
    {
    Rect    rPage = poPrint->prInfoPT.rPage;
    
    // calculate some fields we don't use - in case someone really wants to look at
    // them for some reason
    poPrint->prXInfo.iRowBytes  = rPage.right >> 3;
    poPrint->prXInfo.iBandV     = 32;
    poPrint->prXInfo.iBandH     = poPrint->prXInfo.iRowBytes << 3;
    poPrint->prXInfo.iDevBytes  = poPrint->prXInfo.iRowBytes * 
                                    poPrint->prXInfo.iBandV + 
                                    poPrint->prXInfo.iBandH;
    poPrint->prXInfo.iBands     = (rPage.bottom+(poPrint->prXInfo.iBandV-1)) / poPrint->prXInfo.iBandV;
    poPrint->prXInfo.bPatScale  = (qualityMode == gxBestQuality) ? -2 : 0;
    poPrint->prXInfo.bUlThick   = 1;
    poPrint->prXInfo.bUlOffset  = 1;
    poPrint->prXInfo.bUlShadow  = 1;
    poPrint->prXInfo.scan       = (poPrint->prStl.wDev & kPortrait) ? 0 : 2;
    poPrint->prXInfo.bXInfoX    = 0;
    }
    
    // other fields in prJob remain the same
    poPrint->prJob.iCopies      = actualCopies;
    poPrint->prJob.bJDocLoop    = (qualityMode == gxDraftQuality) ? 0 : 1;
    
    // this routine is so studly, there can be no errors
    return(noErr);  
    
} // SD_ConvertPrintRecordFrom
 
 
//<FF>
/* ---------------------------------------------------------------------------- */
OSErr SD_PrintRecordToJob(THPrint hPrint, gxJob theJob)
/*
    We convert the "tall adjusted" setting into the correct rendering option for
    the job collection.
*/
{
    OSErr   anErr;
    Handle  jobQualitySettingsHdl;  
    
    anErr = Forward_GXPrintRecordToJob(hPrint, theJob);
    if (anErr == noErr)
        {
        long imagewriterOptions = kSuperRes;
        
        if ((**hPrint).prStl.wDev & kSetResCalled)
            {
            Collection          jobCollection = GXGetJobCollection(GXGetJob());
            gxQualityInfo       *qualitySettings;
    
 
            // get old info and replace it with final quality
 
 
            jobQualitySettingsHdl = NewHandle(0);
            anErr = MemError();
            nrequire(anErr, FailedNewHandle);
 
            anErr = GetCollectionItemHdl (  jobCollection,
                                            gxQualityTag,
                                            gxPrintingTagID,
                                            jobQualitySettingsHdl );
 
            if (anErr == collectionItemNotFoundErr) 
                {
                Str255          bestString, roughString;
                Size            count1, count2;
                Ptr             p;
                short           curResFile = CurResFile();
                
                UseResFile(GXGetMessageHandlerResFile());
                GetIndString( bestString, kOldQualityID, kBestString);
                GetIndString( roughString, kOldQualityID, kRoughString);
                UseResFile(curResFile);
 
                SetHandleSize(jobQualitySettingsHdl,(sizeof(gxQualityInfo) + bestString[0] + roughString[0] + 2 ));
                anErr = MemError();
                nrequire( anErr, FailedSetHandleSize );
                        
                qualitySettings = *((gxQualityInfo **) jobQualitySettingsHdl);
                
                qualitySettings->disableQuality = false;
                qualitySettings->defaultQuality = 1;
                qualitySettings->currentQuality = 1;
                qualitySettings->qualityCount = 2;
        
                count1 = bestString[0]+1;
                p = qualitySettings->qualityNames;
                BlockMove( bestString, p, count1 );
        
                count2 = roughString[0]+1;
                p += count1;
                BlockMove( roughString, p, count2 );
        
                }
            else
                qualitySettings = *((gxQualityInfo **) jobQualitySettingsHdl);
 
            (qualitySettings->currentQuality = qualitySettings->qualityCount-1);
 
            anErr = AddCollectionItemHdl (  jobCollection,
                                            gxQualityTag,
                                            gxPrintingTagID,
                                            jobQualitySettingsHdl );
                                                 
            if (anErr == noErr)
                (void) SetCollectionItemInfo(jobCollection, gxQualityTag, gxPrintingTagID, 0x0000FFFF, gxVolatileOutputDriverCategory);
                
            DisposHandle(jobQualitySettingsHdl);
            }
 
        if ((**hPrint).prStl.wDev & kTallAdjusted)
            imagewriterOptions = 0;
            
        if (anErr == noErr)
            anErr = AddCollectionItem(GXGetJobCollection(theJob), 
                        DriverCreator,
                        0,
                        sizeof(imagewriterOptions),
                        &imagewriterOptions);
        }
 
FailedNewHandle:        
    return(anErr);
 
FailedSetHandleSize:
    DisposHandle(jobQualitySettingsHdl);
    return(anErr);
    
} // SD_PrintRecordToJob
 
//<FF>
/* ---------------------------------------------------------------------------- */
OSErr SD_PrValidate(    THPrint hPrint,                 // old style print record
                        Boolean *wasChanged)            // was the print record changed?
/*
    This call validates the current print record.  It's fairly simplistic (as were
    all of the old drivers) - the wDev or versions don't match the current, we call
    PrintDefault.  Otherwise, we call UpdatePrintRecord - to allow the driver to sanity
    check any internal fields.
    
*/
{
    unsigned short  wDev;                       // note: if this were signed, the shift below would fail                    
    Boolean         recordIsInvalid = true;         
    OSErr           anErr = noErr;
    
    // check the wDev.  The upper byte must be equal to our idea of the wDev
        
    wDev =  (**hPrint).prStl.wDev;  
    wDev >>= 8;                             // get just the device ID
 
    // If the device id is equal, then check the version number of the print record.
    //  Only if that is also equal to the current version, will we return false (valid).
        
    if (    (wDev == 1) 
        &&
            (
            ( ((**hPrint).iPrVersion) == 3 ) ||
            ( ((**hPrint).iPrVersion) == 4 ) 
            )
        )
        recordIsInvalid = false;
            
 
    // If the the print record is not valid, then return the default print record.
    // Otherwise, update the print record, based on the application's calls
    // to PrGeneral.
        
    if (recordIsInvalid)
        PrintDefault(hPrint);
    else
        anErr = UpdatePrintRecord(hPrint);
        
    *wasChanged = recordIsInvalid;
    
    return (anErr);
    
} // SD_PrValidate
 
//<FF>
/* ---------------------------------------------------------------------------- */
OSErr SD_PrJobInit(THPrint hPrint, TPPrDlg * pDlg)
/*
    This routine is called to initialize the job dialog.  We take the default
    behavior - and then disable some of the items based on settings the user
    has made:
        - 50% disables all items
        - apps that call SetRsl disable all items
        - landscape disables draft mode
*/
{
    OSErr   anErr;
    
    anErr = Forward_GXPrJobInit(hPrint, pDlg);
    if (anErr == noErr)
        {
        Boolean disableDraft    = false;
        Boolean disableAll      = false;
        short   wDev            = (**hPrint).prStl.wDev;
        short   idx;
        Rect    box;
        Handle  item;
        short   type;
        
        if (wDev & k50Percent)
            disableAll = true;
            
        if (wDev & kSetResCalled)
            disableAll = true;
            
        if (!(wDev & kPortrait))
            disableDraft = true;
        
        // disable any controls we need to
        for (idx = 6; idx <= 8; ++idx)
            {
            GetDItem((DialogPtr) *pDlg, idx, &type, &item, &box);
            
            if ( (disableAll) || ((disableDraft) && (idx == 8) ) )
                HiliteControl((ControlHandle) item, 255);
            
            }
        }
 
    return(anErr);
    
} // SD_PrJobInit