← Back to Technotes

#35: Printer Driver Specifications

Author: Dan Hitchens, Matt Deatherage & Suki Lee
Year: 1988

... describes the routines and internal structures needed to design a printer driver for the Apple IIgs system.

View raw text file

Apple II
Technical Notes
_____________________________________________________________________________
                                                  Developer Technical Support

Apple IIgs
#35:    Printer Driver Specifications

Revised by:    Matt Deatherage                                 September 1990
Written by:    Dan Hitchens, Matt Deatherage & Suki Lee              May 1988

This Technical Note describes the routines and internal structures needed to 
design a printer driver for the Apple IIgs system, and you should use this 
Note with the Apple IIgs Toolbox Reference manuals.  An overview and 
associated parameters for each of the printer driver routines are in the Print 
Manager chapter, and you should refer to these for a complete picture.
Changed since March 1990:  Added corrections and further descriptions.
_____________________________________________________________________________


Printing Modes

There are two printing modes:  immediate and deferred.

o  In immediate mode, pages are printed as they are drawn into the 
   printing grafPort.  As the application makes QuickDraw II calls, 
   the printer driver immediately generates commands, transferring 
   ink to page when the page is closed.  This is the fastest form of 
   printing, but only produces high-quality images on printers that 
   can translate QuickDraw II commands to other graphic commands.  
   For example, the LaserWriter driver translates the QuickDraw II 
   calls into PostScript(R) calls which can produce high-quality 
   images.

o  In deferred mode (sometimes referred to as spool mode), pages are 
   captured to memory or disk and printed after all pages have been 
   defined.  Most printer drivers use deferred mode to create high-
   quality images.  Since most drivers cannot obtain enough memory to 
   image an entire page at once, they redraw page in several pieces, 
   or bands.  The printer driver creates a grafPort whose boundsRect, 
   portRect, clipRgn, and visRgn correspond to the band and plays the 
   picture back, thus causing the saved commands to draw only the 
   images which fall within the band.  Once the pixel image for the 
   band is created, the printer driver converts the image to printer 
   codes and sends the codes to the printer through the port driver.


File Structure

The user can install new printer drivers into the system by copying a printer 
driver file into a subdirectory called DRIVERS within the SYSTEM subdirectory.  
The printer driver file must be of type $BB and have an auxiliary type of 
$0001.



Print Driver Calls

A printer driver must support the following calls:

    PrDefault             $0913    Sets print record to default
    PrValidate            $0A13    Validates print record
    PrStlDialog           $0B13    Performs a style dialog
    PrJobDialog           $0C13    Performs a job dialog
    PrPixelMap            $0D13    Prints a pixel map
    PrOpenDoc             $0E13    Opens the document
    PrCloseDoc            $0F13    Closes the document
    PrOpenPage            $1013    Opens a page
    PrClosePage           $1113    Closes a page
    PrPicFile             $1213    Prints a picture file
    --RESERVED--          $1313
    PrError               $1413    Gets the error value
    PrSetError            $1513    Sets the error value
    GetDeviceName         $1713    Gets device's name
    PrDriverVer           $2313    Gets installed driver version

Printer drivers may support the following calls if they use the new driver 
structure outlined below:

    PrGetPrinterSpecs     $1813    Returns printer type and characteristics
    PrGetPgOrientation    $3813    Returns page orientation


Print Driver Entry

o  For older drivers, entry is at the first byte (no offset).  For newer 
   (Print Manager 3.0 and later) drivers, the first word is $0000, indicating 
   a new style driver.  The next word is a count of how many calls this driver 
   supports.  All drivers must support the minimum call set.  Additional calls 
   must be supported in the sequence listed (for example, if a driver supports 
   PrGetPgOrientation, it must also support PrGetPrinterSpecs).
o  The Print Manager places an index to the correct routine in the X register 
   (see the example and note the specific ordering of the routines) .
o  There are two long return addresses (six bytes) that have been pushed onto 
   the stack.  (You must take these addresses into account to access the 
   parameters and to return correctly.)

Example

StartOfNewDriver    START

                    dc i2'0'                           ; new style driver
                    dc i2'(ListEnd-PrDriverList)/4'    ; count

                    jmp (PrDriverList,x)


PrDriverList        dc a4'PrDefault'
                    dc a4'PrValidate'
                    dc a4'PrStlDialog'
                    dc a4'PrJobDialog'
                    dc a4'PrDriverVer'
                    dc a4'PrOpenDoc'
                    dc a4'PrCloseDoc'
                    dc a4'PrOpenPage'
                    dc a4'PrClosePage'
                    dc a4'PrPicFile'
                    dc a4'InvalidRoutine'
                    dc a4'PrError'
                    dc a4'PrSetError'
                    dc a4'GetDeviceName'
                    dc a4'PrPixelMap'
                    dc a4'PrGetPrinterSpecs'
                    dc a4'PrGetPgOrientation'
ListEnd             anop

In previous versions of this Note, the PrPixelMap and PrDriverVer entries were 
reversed.

Note that when using the above technique, you're using a 16-bit jump into a 
table of 24-bit addresses.  If all your entry points are in the same segment, 
this is not a problem.

If your routines' entry points are not all in the same segment, you need a 
dispatching routine like the following:

StartOfNewDriver    START

                    dc i2 '0'                           ; new style driver
                    dc i2 '(ListEnd-PrDriverList)/4'    ; count

                    lda PrDriverList+2,x
                    sep #$20
                    pha                                 ; push high byte of 
;                                                         address
                    rep #$20
                    lda PrDriverList,x
                    dec a                               ; decrement low 2 
;                                                         bytes only
                    pha                                 ; push modified low 
;                                                         word of address
                    rtl                                 ; transfer to the 
;                                                         routine

See Apple IIgs Technical Note #90, 65816 Tips and Pitfalls, for a discussion 
of dispatching with RTL.


Print Driver Exit

When one of your routines is ready to exit, it needs to remove the input 
parameters from the stack, leaving the result space (if any) and the two RTL 
addresses.  Set the accumulator and the carry flag to reflect any error you 
are returning, then perform an RTL.


Example

If there are N bytes of input parameters to remove, use something like the 
following.  This code assumes that the error code is in the accumulator.

                    tay                                 ; keep error code in Y 
;                                                         temporarily
                    lda 5,s
                    sta N+5,s
                    lda 3,s
                    sta N+3,s
                    lda 1,s
                    sta N+1,s
                    tsc
                    clc
                    adc #N
                    tcs
                    tya                                 ; get error code
                    cmp #1                              ; set carry if error 
;                                                         is not zero
                    rtl

Figure 1 diagrams the stack just before exiting the print driver:

    |
    | Previous Contents
    |___________________
    |
    | Results (if any)
    |___________________
    |
    | RTL2 (3 bytes)
    |___________________
    |
    | RTL1 (3 bytes)
    |___________________

                        <-- Stack Pointer

    Figure 1-Stack Prior to Exiting the Print Driver

You should do an RTL with the contents of the flags and registers set 
appropriately.  (See the Return from Call section of the "Using The Apple 
Tools" chapter of the Apple IIgs Toolbox Reference.)


Print Record Structure

Since application programs often need to fiddle with parts of the print record 
(i.e., the values in the style subrecord), we have defined ways for 
applications to interpret the print record, and specifically the style 
subrecord.

iDev, the first word of the printer information subrecord, has two defined 
values for third-party printer drivers.  A value of $8001 indicates a dot-
matrix printer while a value of $8003 indicates a laser printer.

A value of $8001 indicates that fields of the style subrecord should be 
interpreted as they are by the ImageWriter driver, as documented in the Apple 
IIgs Toolbox Reference.  The first seven bits (0-6) of wDev are defined as for 
the ImageWriter driver.  Bits 7-11 are reserved for Apple's use and must be 
set to zero.  Bits 12-15 may be used by third-party printer drivers as 
necessary; these bits are set to zero in Apple's drivers.

A value of $8003 indicates that fields of the style subrecord should be 
interpreted as they are by the LaserWriter driver.  The first four bits (0-3) 
of wDev are defined as for the LaserWriter driver.  Bits 4-11 are reserved for 
Apple's use and must be set to zero.  Bits 12-15 may be used by third-party 
printer drivers as necessary; these bits are set to zero in Apple's drivers.

If an application wishes to take advantages of specific features of a third-
party printer driver, it has to know that it is dealing with that driver.  
Since all drivers look pretty much alike, the Print Manager allows you to ask 
for the name of the currently selected printer driver.  An application may 
make the Print Manager call PMGetPrinterName, which is documented in Volume 3 
of the Toolbox Reference.  The Print Manager returns the name of the currently 
selected printer in a Pascal (length byte) string.  The name returned is the 
name of the file from which the driver was loaded.  If you intend to use this 
method to identify a driver, you must inform users not to rename the Printer 
Driver file on the boot disk.

For alternate driver identification, Developer Technical Support assigns new 
iDev values if you feel it is absolutely necessary for your driver.  Please 
keep in mind, however, that no application knows how to interpret style 
records for non-standard iDev values, and that Apple does not publish such 
interpretations.


Print Driver Calls

Your printer driver handles the following calls:

PrDefault                            ($0913)

Description:
    Fills the fields of the specified print record with default values for the 
    printer.

Passed:
    PrintRecordHandle                LONG    Handle to the print record

Returned:
    None

Performs the following:
o  Validates that PrintRecordHandle is a handle and does nothing if not.
o  Determines the default values for the print record either through tables or 
   calculations.  The default values should take into account such things as 
   paper size and orientation, print mode, printer type, etc.
o  Copies the default values to the print record specified by the 
   PrintRecordHandle parameter.

PrValidate                           ($0A13)

Description:
    Checks the print record to see that it is valid for the currently installed 
    printer driver.

Passed:
    PrintRecordHandle                LONG    Handle to the print record

Returned:
    ChangeFlag                       WORD    Boolean; TRUE if the record is 
                                             adjusted

Performs the following:
o  Checks to see if the print record is from this particular driver.
o  If the print record is not from this driver, it uses the default values for 
   this driver.
o  If the print record is from this driver, it makes any changes that might be 
   needed (i.e., style, paper size, etc.).

PrStlDialog                          ($0B13)

Description:
    Performs a style dialog with the user.

Passed:
    PrintRecordHandle                LONG    Handle to the print record

Returned:
    ConfirmFlag                      WORD    Boolean; TRUE if the dialog is 
                                             confirmed

Performs the following:
o  Conducts a style dialog with the user to determine the page dimensions and 
   other information needed for page setup (the initial settings of the dialog 
   are derived from the print record).
o  If the user confirms the dialog, the information from the dialog is saved 
   in the specified print record, PrValidate is called, and the routine 
   returns TRUE.
o  If the user cancels the dialog, the print record is left unchanged, and the 
   routine returns FALSE.

Note:  The following are items typically found in printer style dialogs:

o  Paper Size (US Letter, US Legal, A4 Letter, B5 Letter, International 
   Fanfold)
o  Printing Orientation (Landscape, Portrait)
o  Vertical Sizing (Normal, Intermediate, Condensed)
o  Special Effects:
        Font Effects (Font Substitution, Smoothing)
        Reduction or Enlargement
        Gaps or No Gaps between pages

Every printer style dialog should have an OK button (default) and a Cancel 
button.

Note:  When calling other routines in your printer driver (like 
       PrValidate), be sure to do so through the Tool Dispatcher ($E10000 
       or $E10004) so any necessary patches have an opportunity to execute.

PrJobDialog                          ($0C13)

Description:
    Performs a job dialog with the user.

Passed:
    PrintRecordHandle                LONG    Handle to the print record

Returned:
    ConfirmFlag                      WORD    Boolean; True if the dialog is 
                                             confirmed

Performs the following:
o  Conducts a job dialog with the user to determine the print quality, range 
   of pages to print, and other specifications.  The initial settings are 
   derived from the previous PrJobDialog call (or initial default values) 
   except the page range which is set to ALL, and the number of copies which 
   is set to ONE.
o  If the user confirms the dialog, PrValidate is called, the print record is 
   updated, and the routine returns TRUE.
o  If the user cancels the dialog, the print record is left unchanged, and the 
   routine returns FALSE.

Note:  The following are items typically found in printer job dialogs:

       o  Print Quality (Best, Faster, Draft, etc.)
       o  Color option
       o  Pages (All, Range)
       o  Copies
       o  Paper Source (paper cassette, manual feed)

Every printer job dialog should have an OK button (default) and a Cancel 
button.

Note:  When calling other routines in your printer driver (like 
       PrValidate), be sure to do so through the Tool Dispatcher ($E10000 
       or $E10004) so any necessary patches have an opportunity to 
       execute.

PrPixelMap                           ($0D13)

Description:
    Prints all or part of the specified pixel map.

Passed:
    srcLocPtr                        LONG    Pointer to the source LocInfo 
                                             which contains the pointer to 
                                             the pixel map.
    srcRectPtr                       LONG    Pointer to the rectangle which
                                             encloses the pixel map to be 
printed.
    colorFlag                        WORD    Boolean; FALSE if black and white,
                                             TRUE if color.

Returned:
    None
Performs the following:
o  Calls DevIsItSafe (port driver call) to verify that the port it functioning 
   and it is safe to proceed.  If it is not functioning, set the internal 
   error code to $1302 (Port Not On) and return with an error status.
o  Saves the current grafPort.
o  Turns on the watch cursor to signal the user that it will take some time.
o  Clears the internal error code (default, if no errors occur).

You can choose to print the pixel map in any convenient fashion; one 
convenient way is to allocate a new print record and call your normal printing 
routines.  This method is outlined below.

o  Gets a new handle for a print record and set it to the defaults by calling 
   PrDefault.
o  If colorFlag is set, change the style subrecord of the print record to 
   reflect color printing.
o  Do any initialization that might be needed by the driver.
o  Determine the intersection of the two rectangles (rectangle pointed to by 
   srcRectPtr and the pixel map's boundary rectangle from srcLocPtr) and if 
   there is no intersection, then nothing is to be printed.
o  Print the pixel image which is within the intersection of the two 
   rectangles.
o  Cause a page eject to occur on the printer.
o  Do any clean up that is needed.
o  Turn off the watch cursor by calling InitCursor (or restore the previous 
   cursor using SetCursor).
o  Restore the grafPort by calling SetPort.

PrOpenDoc                            ($0E13)

Description:
    This routine initializes the things needed to open a document.  In deferred 
    mode, it establishes a grafPort and makes it the current port for printing.

Passed:
    PrintRecordHandle                LONG    Handle to the print record
    PrinterPortPtr                   LONG    Pointer to the grafPort, if 
                                             desired, zero to allocate a new 
                                             grafPort
Returned:
    PrinterPortPtrRet                LONG    Pointer to the grafPort if the
                                             PrinterPortPtr was zero

Performs the following:
o  Calls DevIsItSafe (port driver call) to verify that the port is functioning 
   and it is safe to proceed.
o  Turns on the watch cursor to signal the user that it will take some time.
o  Validates the print record passed by  calling PrValidate.
o  Clears the internal error code (default, if nothing happens).
o  Puts up a dialog indicating that printing is occurring (or preparing to 
   print).
o  If the user needs a grafPort, create one and internally note that one was 
   created (PrCloseDoc needs to know that one was created here).
o  Initializes parameters (i.e., page number, document number, etc.).
o  If deferred mode, create an initial page list (an array of handles to 
   pictures) for recording pages.  You can pick an arbitrary number to start 
   with (like 20).  This assumes spooling to memory; spooling to disk will 
   obviously be different.
o  Do other initialization that might be needed to start a print job.

Possible errors:
    portNotOn                        $1302    Indicates Port Not On

PrCloseDoc                           ($0F13)

Description:
    Closes the grafPort being used for printing.  For immediate mode, this 
    routine ends the printing job.  For deferred mode, this routine ends the 
    recording of the document to be printed.

Passed:
    PrintGrafPortPtr                 LONG    Pointer to the grafPort used for 
                                             printing

Returned:
    None

Performs the following:
o  Checks that the last print driver call did not cause a Port Not On error.  
   If the error occurred, do nothing and return.
o  Call ClosePort to close the printing grafPort.
o  If the driver allocated a grafPort in PrOpenDoc, disposes of it.
o  If in immediate mode, does what is needed to shut things down.
o  Takes down the information dialog box from PrOpenDoc.


Possible errors:
    portNotOn                        $1302    Indicates Port Not On
    prBozo                           $13FF    Someone unloaded the driver in 
                                              the middle of the print loop

PrOpenPage                           ($1013)

Description:
    Begins a new page only if the page falls within the page range specified in 
    the job subrecord.

Passed:
    PrintGrafPortPtr                 LONG    Pointer to the grafPort used for 
                                             printing
    PageFramePtr                     LONG    Pointer to the scaling parameter,
                                             zero for none.
Returned:
    None

Performs the following:
o  Looks at the driver's internal error value, and if an error has occurred, 
   it returns without doing anything.
o  Increments the page number.
o  Calls SetPort to make the specified port the current port.
o  Initializes the port and zeroes the boundary rectangle so no actual drawing 
   occurs.
o  If immediate mode, then do the following:
        If this page is to be printed, install immediate mode procedures by 
        doing the following:
        o  Create a procedure table (get the standard procedures from 
           SetStdProcs).
        o  Put pointers to your procedures into the table and call the 
           QuickDraw II routine SetGrafProcs.  This causes QuickDraw II calls 
           to call your routines instead of drawing to the pixel map 
           associated with the grafPort.
o  If deferred mode, then do the following:
   o  If the current page is out of the page range, then return without 
      doing anything further.
   o  If the user passes his own PageFramePtr , then get it.
   o  Open a picture by calling OpenPicture and adding its handle to the 
      page list array described in PrOpenDoc.
   o  Set the ClipRgn and VisRgn to the sizing framing rectangle specified 
      by PageFramePtr , or if none was specified, to the default of rPage.

Possible errors:
    portNotOn                        $1302    Indicates Port Not On
    prBozo                           $13FF    Someone unloaded the driver in 
                                              the middle of the print loop

PrClosePage                          ($1113)

Description:
    This signals the end of a page.

Passed:
    PrintGrafPortPtr                 LONG    Pointer to the grafPort used for 
                                             printing

Returned:
    None

Performs the following:
o  Looks at the driver's internal error value and if a Port Not On error has 
   occurred, it returns without doing anything.
o  If immediate mode, do the following:
o  If the current page is within the range of pages to be printed, then 
   cause a form feed (unless no gap was specified).
o  If deferred mode, do the following:
o  If there was no picture generated, then do nothing and just return.
o  Restore the grafPort to the port saved in PrOpenPage.
o  Do a ClosePicture to close the picture.

Possible errors:
    portNotOn                        $1302    Indicates Port Not On
    prBozo                           $13FF    Someone unloaded the driver in 
                                              the middle of the print loop

PrPicFile                            ($1213)

Description:
    Prints a picture file generated in deferred mode.

Passed:
    PrintRecordHandle                LONG    Handle to the print record
    PrintGrafPortPtr                 LONG    Pointer to the grafPort used for 
                                             printing
    StatusRecPtr                     LONG    Pointer to the printer status 
                                             record

Returned:
    None

Performs the following:
o  Looks at the driver's internal error value and if a Port Not On error has 
   occurred, it returns without doing anything.
o  If immediate mode, return without doing anything.
o  If deferred mode, then do the following:
   o  If the error code is not zero (errors) then dispose of all the recorded 
      page images.
   o  Put up an information dialog indicating that printing is occurring.
   o  Display a watch cursor (saving the current cursor first if you like).
   o  If PrintGrafPortPtr is NIL, create one and make a note of it.
   o  Call OpenPort to make the grafPort the current port.
   o  If StatusRecPtr is NIL, use an internal one.  This is to simplify your 
      code; if the StatusRecPtr is NIL, you can reasonably choose not to use a 
      status record at all, but this requires an extra code path.
   o  Initialize the status record and the number of copies counter.
   o  If the idle procedure pointer in the print record is NIL, point to an 
      internal one.  Again, as with the StatusRecPtr, you can choose to ignore 
      idle procedures if no pointer is provided, but this requires an extra 
      code path.
   o  Do The Following For Each Copy:
      o  Calculate the number of bands to print one page and initialize the 
         page counter.
      o  Do The Following For Each Page:
         o  Call the idle procedure routine and initialize the band counter.
         o  Get the handle to the picture associated with the current page.
         o  Set the dirty flag in the status record to FALSE.
         o  If manual paper feed, put up a dialog and wait for a response.
         o  Do The Following For Each Band:
            o  Call the idle procedure.
            o  Calculate the band rectangle and update iCurBand with the 
               current band number.
            o  Call the idle procedure again.
            o  Set the imaging flag in the status record to TRUE.
            o  Call InitPort to reinitialize the port.
            o  Adjust fields in the port to cause drawing into the band 
               buffer.
            o  Adjust fields in the location information field of the status 
               record and calculate the sizing rectangle.
            o  Calculate the boundary rectangle for the band and set the port 
               rectangle to it.
            o  Set the ClipRgn and the VisRgn to the sizing rectangle.
            o  Initialize the band by filling it with white space.
            o  Call DrawPicture to draw the picture into the band's 
               rectangle.
            o  Do whatever is needed to print the pixel image in the band's 
               rectangle.
            o  Clear the imaging flag.
            o  Calculate the next band's position.
            o  Increment the band's counter and loop back if not done.
         o  If a vertical gap was specified, cause a form feed.
         o  Increment the page count to the next page and loop back if not 
            done.
      o  Increment the number of copies counter and loop back if not done.
   o  Free any buffers that you own and close the port.
   o  Dispose of the information dialog that you put up.
   o  Dispose of each picture in the picture list by calling KillPicture.
   o  Dispose of the picture list itself.
   o  Restore the cursor.

Possible errors:    
    portNotOn                        $1302    Indicates Port Not On
    prBozo                           $13FF    Someone unloaded the driver in 
                                              the middle of the print loop

PrError                              ($1413)

Description:
    Gets the error code from the last Print Manager call.

Passed:
    None

Returned:
    LastError                        WORD    Result code from last Print 
                                             Manager call

Performs the following:
o  Gets the driver's internal error value (which was determined by the last 
   driver call) and sets the return parameter LastError to it.

Possible Errors:
    noError                          $0000
    PrAbort                          $0080    Indicates print job was aborted
                                     $1301    Indicates missing drivers
                                     $1302    Indicates Port Not On
                                     $1303    Indicates No Print Record
                                     $1306    Indicates PAP Connection Not 
                                              Made
                                     $1307    Indicates Read/Write PAP Error
                                     $1308    Indicates Printer Connection 
                                              Failed
    prBozo                           $13FF    Someone unloaded the driver in 
                                              the middle of the print loop

PrSetError                           ($1513)

Description:
    Sets the error value.

Passed:
    ErrorNumber                      WORD    Error number to be set

Returned:
    None

Performs the following:
o  Sets the driver's internal error value to the value of the passed 
   ErrorNumber parameter.

GetDeviceName                        ($1713)
(also known as PrChanged)

Description:
    Used as a communications tool between the printer driver and port driver.

Passed:
    None

Returned:
    None

Performs the following:
o  Calls the port driver routine PrDevPrChanged with the printer name as 
   input.  This is necessary for drivers that work over AppleTalk.  The name 
   passed as the parameter to PrDevPrChanged should be what AppleTalk uses in 
   an NBPLookup situation; for AppleTalk, such a name should follow Name 
   Binding Protocol conventions.

   This routine will be called by the Print Manager when your driver is first 
   loaded so a network port driver can find devices of your type.  
   Applications should not make this call.  When this routine will be called 
   is not guaranteed; you can't use this as a substitute for a startup call.

PrDriverVer                          ($2313)

Description:
    Returns the version number of the currently installed printer driver.

Passed:
    Wordspace                        WORD    Space for results

Returned:
    versionInfo                      WORD    Printer driver's version number

Performs the following:
o  Gets the internal version number of the printer driver and returns it on 
   the stack at versionInfo.

Note:  The internal version number is stored major byte, minor byte 
       (i.e., $0103 represents version 1.3)

PrGetPrinterSpecs                    ($1813)

Description:
    Returns the type of printer and the printer's characteristics.

Passed:
    Wordspace                        WORD    Space for results
    Wordspace                        WORD    Space for results

Returned:
    PrinterType                      WORD    0 = undefined
                                             1 = ImageWriter or ImageWriter II
                                             2 = ImageWriter LQ
                                             3 = LaserWriter family 
                                                 (except IIsc)
                                             4 = Epson
                                             $8001 = generic dot matrix printer
                                             $8003 = generic laser printer
    PrCharacteristics                WORD    Bits 15-2 = reserved, must be zero
                                             Bits 1-0:  00 = cannot determine
                                                        01 = black and white 
                                                             only
                                                        10 = color capable

Performs the following:
o    Returns characteristics intrinsic for the printer being supported.

The value returned for PrinterType should be the driver's iDev value.

PrGetPgOrientation                   ($3813)

Description:
    Returns the page orientation from a print record.

Passed:
    Wordspace                        WORD    Space for result
    PrintRecordHandle                LONG    Handle to the print record

Returned:
    PgOrientation                    WORD    Current page orientation:
                                             0 = portrait
                                             1 = landscape

Performs the following:
o  Returns the page orientation from the current page setup information in the 
   print record.


Immediate Mode Procedures

To print in the immediate mode, you need to install procedures which cause 
printing when you make QuickDraw II calls (as noted in PrOpenPage).  This 
section describes the structure and parameters for these routines.

The basic idea is that your driver replaces low-level QuickDraw II routines 
with pointers to your own routines.  For example, when someone wants QuickDraw 
II to draw some text (say with DrawString), QuickDraw II calls your low-level 
routine to draw the text.  You can then print the text instead.

To install the immediate mode procedures, first create a procedure table for 
sixteen entries (16*4 bytes) and fill it with the standard procedures by 
calling SetStdProcs.  Once you have the standard procedures, install the 
addresses of your replacement procedures into it and call SetGrafProcs.  
Installing your procedure addresses causes the appropriate QuickDraw II calls 
to call your procedures, which, in turn, perform the actual printing.

The routines that need to be written are known as QuickDraw II "bottleneck 
procedures."  For most dot-matrix printer drivers, the one of most concern 
when writing immediate mode procedures is StdText.  If your target device has 
an alternate page imaging language, you may wish to print entirely in 
immediate mode.  In this case, you want to intercept most of the bottleneck 
procedures.  Apple IIgs Technical Note #34, Low-Level QuickDraw II Routines, 
contains information on how to install these procedures.  The sample code 
which follows shows how to replace StdPixels and StdText.

Example:

;*****************************************************************
;** Example of Immediate Mode Printer Procedures.               **
;*****************************************************************
Immedprocs     Start

SrcRect        equ $DC
SrcLocInfo     equ $CC
DrawVerb       equ $38
TextPtr        equ $da
TextLength     equ $d8
CharToDraw     equ $d6

;------------------------------------------------------------------
;
; StdPixels Procedure (Prints Pixel maps)
;
;------------------------------------------------------------------
Pixel          Entry

               phb                          ;save data bank reg on stack
               phk                          ;get program bank reg.
               plb                          ;use as data bank reg.

               lda iPrErr                   ;get errors
               beq Continue                 ;branch if none
               brl ExitPixel                ;branch if errors

Continue       anop

;This gets the source rectangle and stores it at PixelRect
               ldx #6
MoveSrc        lda SrcRect,x
               sta PixelRect,x
               dex
               dex
               bpl MoveSrc

;This gets the source LocInfo and stores it at PixelLoc 
               ldx #16-2
MoveLI         lda SrcLocInfo,x
               sta PixelLoc,x
               dex
               dex
               bpl MoveLI

               pushlong #PixelLoc           ;push pointer to LocInfo
               pushlong #PixelRect          ;push pointer to rectangle


;++++++++++++++++++++++
; Insert code here to print a pixel map
;    INPUT:    PixelLoc   LONG, Pointer to pixel LocInfo
;              PixelRect  LONG, Pointer to pixels BoundsRect
;    SP->
;++++++++++++++++++++++

Exitpixel      lda #0                       ;return with no errors
               clc
               plb                          ;restore data bank
               rtl                          ;return with long

PixelLoc       ds 16                        ;pixel LocInfo
PixelRect      ds 8                         ;pixel rectangle

;------------------------------------------------------------------
;
; StdText Procedure (Prints Standard Text)
;
;------------------------------------------------------------------
StdText        Entry

               phb                          ;save data bank reg on stack
               phk                          ;get program bank reg. 
               plb                          ;use as data bank reg.

               pushlong #PenPos
               _GetPen                      ;current pen pos. -> PenPos

;++++++++++++++++++++++
; Insert Code Here to move the printers head to the corresponding
; PenPos position (if needed).
;++++++++++++++++++++++

               pushword #0                  ;space for textwidth
                                            ;(for call to _TextWidth)

               lda DrawVerb                 ;get DrawVerb
               beq DoCar                    ;if DrawVerb=0 then DoCar

               cmp #1
               beq Dotext2                  ;if DrawVerb=1 then Dotext2
;
;We get here if it's a "C" string (DrawVerb=2)
;
DoCstring      anop
               sep #$20
               longa off
;Search down through string looking for terminator to calc. length
               ldy #0
KeepLooking    lda [TextPtr],y
               beq TheEnd
               iny
               bra KeepLooking
TheEnd         rep #$20
               longa on
               lda TextPtr+2
               pha                          ;push the pointer to string
               lda Textptr
               pha
               phy                          ;push the length of sting
               bra Common

;
;We get here if it's just one character (DrawVerb=0)
;
DoCar          anop
               pushword #0
               tdc
               clc
               adc #CharToDraw              ;calculate addr. of char.
               pha                          ;push addr. of character
               pushword #1                  ;push length of one char.
               bra Common

;
;We get here if it's a string of text (DrawVerb=1)
;
DoText2        anop
               lda TextPtr+2
               pha                          ;push pointer to the string
               lda Textptr
               pha
               lda TextLength
               pha                          ;push the strings length
Common         lda 5,s                      ;Dup the last 3 words of
               pha                          ;the stack (for _TextWidth)
               lda 5,s
               pha
               lda 5,s
               pha
;++++++++++++++++++++++
; Insert code here to print the text
;
;    INPUT:    TextPointer    LONG, Pointer to text to print
;              TextLength     WORD, No. of bytes to print
;    SP->
;++++++++++++++++++++++
               _TextWidth                   ;get the texts width (DH)
               pushword #0                  ;set (DV)=0
               _Move                        ;move current pen location

ExitText       lda #0                       ;return with no errors
               clc
               plb                          ;restore data bank
               rtl                          ;returnith long

PenPos         ds 4                         ;pen position
               end


Further Reference
_____________________________________________________________________________
  o  Apple IIgs Toolbox Reference, Volumes 1-3
  o  Apple IIgs Technical Note #36, Port Driver Specifications
  o  Apple IIgs Technical Note #90, 65816 Tips and Pitfalls

PostScript is a registered trademark of Adobe Systems Incorporated.