Version 3.00 and above of the printer drivers have been upgraded to allow more than one of them on the iconbar at any one time. This would be an easy change except for a two points:
The chosen concept for multiple printer drivers is: Allow many printer driver icons on the iconbar, but make at most one of them selected. When the user drags a file icon to a particuler printer, that printer will print it. If the user performs a Misc=>Print type menu option (e.g. from !Draw) then it will print to the currently highlighted printer.
This leads to the following solutions to the two problems mentioned above:
A new printer manager module was created (called 'PDriver' and using
the same SWI chunk as the old printer drivers). The old printer driver
modules were slightly upgraded by:
Changing their names to 'PDriverDM', 'PDriverIX' etc.
Removing their standard SWI handling. Instead, the modules
register themselves with the 'PDriver' printer manager module. This module
can then call them when it needs to route a message.
The printer manager module takes over control of the printer driver
SWIs, and introduces two of its own. The first of these new ones is
PDriver_DeclarePrinter:
SWI PDriver_DeclarePrinter
On entry:
R0 => old SWI handling code
R1 = R12 for calls through the branch table
R2 = printer number
On exit:
All preserved
The printer manager notes all printer drivers and their numbers
registered with it, so that any printer may be selected and then used in the
normal way. To select a printer driver the manager provides SWI
PDriver_SelectPrinter:
SWI PDriver_SelectPrinter
On entry:
R0 = printer number
On exit:
R0 = previously selected printer number, -1 for none.
New printer selected, or error if that printer number is not known.
The printer manager routes all PDriver SWIs sent to it to a sensible
printer driver. A 'sensible' printer driver could be the currently selected
printer driver, the printer driver which started a job, or ALL the printer
drivers. The routeing is done by imitating a SWI call - the SWI handling
code is called with R11 being the normal SWI number in the SWI chunk.
This means no change has to be made to the printer driver SWI handling
code. The actual rerouteing of the calls is as follows:
PDriver_Info, PDriver_SetInfo, PDriver_CheckFeatures, PDriver_PageSize, PDriver_SetPageSize, PDriver_ScreenDump, PDriver_SetPrinter. These are all passed to the currently selected printer driver, as it must be the printer module which the caller expects to talk to.
PDriver_SelectJob, PDriver_SelectIllustration. These calls either expect to select a completely new job, in which case they are passed to the selected printer module, or they are used to select an old job, in which case the call must be passed to the printer module which owns that job, or to deselect all jobs, in which case it must be sent to the printer module which owns the current job. Note that to do all this the printer manager must keep track of which modules own which jobs.
PDriver_CurrentJob, PDriver_EnumerateJobs. These calls can all be handled by the printer manager itself, as it knows which module owns which jobs, hence which jobs are active and which is the current job.
PDriver_EndJob, PDriver_AbortJob, PDriver_CancelJob, PDriver_CancelJobWithError. These calls are passed to the owner of the job specified in the call. EndJob and AbortJob also involve deactivating the job in the printer manager's internal structures.
PDriver_Reset. This must call all the printer drivers with PDriver_Reset, and then clear the active job table.
PDriver_FontSWI, PDriver_GiveRectangle, PDriver_DrawPage, PDriver_GetRectangle, PDriver_InsertIllustration. These must be passed to the owner of the current job.
There are actually quite a few more SWIs implemented by the printer
manager module. These are 'ForDriver' SWIs, to enable printer applications
to access their module without doing a SelectDriver, call, SelectDriver to
reselect the previous driver. The ForDriver calls are available for all
those SWIs which use the currently selected pdriver module. The printer
number of the module for the call is passed in R7. So, there are SWIs
PDriver_SetPrinterForDriver, PDriver_SelectJobForDriver,
PDriver_InfoForDriver, and so on.
Currently allocated printer numbers (apply to Acorn):
Number Driver
0 Acorn PostScript printer driver
1 Acorn FX80 type printer driver
2 Acorn HP LaserJet printer driver
3 Acorn Integrex printer driver
4 Computer Concepts Fax modem printer driver
5 Computer Concepts Dumb laser engine printer
6 Computer Concepts Canon LBP4 printer driver
7 Acorn Unified dot matrix printer driver
2) 'Printer:'.
There is no way to stop the current applications from opening
'printer:' to print. This means that the currently highlighted printer must
always have the correct printer driver module and the correct destination
for 'printer:' selected. Since 'printer:' can only be opened once at any one
time their will obviously be a limit of 1 on the number of graphics print
jobs which can be performed at any time. This is not much of a restriction
as the printer driver modules are so slow that you cannot afford the
processor power to attempt more than one print.
Text printing is a completely different matter. All the text
printing is done by the printer driver front-ends themselves. To print to
the serial port the printer driver only needs to open 'serial:', and this
can be open at the same time as another printer driver is printing text to
'netprint#sepia:' or whatever. Indeed, if a printer driver is printing text
to 'serial:' there is nothing to stop an application from opening 'printer:'
and doing a graphics dump!
There is one complication. If the user drags a file out of the save
box of an application to an unhighlighted printer then that printer must
select itself (set up the correct destination for 'printer:', select its
module, send the 'setup' data to its module etc.) before the application
opens 'printer:' to start printing. This leads to a very complicated message
protocol outlined below.
Finally, note that any printing to the parallel port has to go
through 'printer:' - or more precisely 'printer#centronics:'. This means
that if the user is text-printing to a parallel printer, he or she will not
be able to perform a graphics dump to another printer because 'printer:' is
already open. This is unfortunate, but unavoidable.
There are three messages in the protocol:
Message_SelectPermanentPrinter
Block:
data + 20 = task handle of printer to become permanently selected
Use:
This message is broadcast when the user clicks on the 'Select' menu
option by that printer driver, with its own task handle in the data block.
It is also broadcast when a printer driver first starts up, to ensure that
it is selected. Both times the message is sent recorded. If the message
bounces then there is no currently selected printer, so the printer driver
sends itself the corrent Message_SelectPrinterOK message (see below). This
message is also sent when a temporary printer selection completes.
Message_SelectTemporaryPrinter
Block:
data + 20 = task handle of printer to become temporarily selected
Use:
This message is broadcast when the user drags a file onto a
non-highlighted printer driver. The printer driver must force itself to be
selected for a short while so that it can select its printer module, select
the correct destination for 'printer:' etc. ready for an application to open
'printer:' and start printing, when the printer driver can reselect the
permanent printer driver. The message is broadcast recorded delivery, and if
it bounces then the printer driver is free to permanently select itself
using a Message_SelectPrinterOK.
Message_SelectPrinterOK
Block:
data + 20 = task handle of printer which should select itself
data + 24 = 0 for permanent selection
1 for temporary selection
2 for message protocol died
Use:
a)
This message is broadcast in reply to a
Message_SelectPermanentPrinter by the currently highlighted printer. This
printer then deselects itself. This allows a central printer manager task to
keep track of which is the currently highlighted printer.
b)
This message is broadcast in reply to a
Message_SelectTemporaryPrinter by the currently highlighted printer. This
tells the printer which wants to become temporarily selected for the
duration of a save-drag which printer it must permanently select after it
has finished.
c)
This message is broadcast when one of the other messages bounces.
The bounce can only occur if their is no currently selected printer, and so
the task which sent the message can freely send itself a
Message_SelectPrinterOK.
d)
This message is broadcast if a printer tries to become temporarily
selected, the currently highlighted printer responds with this message (as
in b), but the temporary printer fails to claim its requirements for
selection (e.g. opening 'printer:' to see if it can set the printer
destination). This time the message will contain a 'message protocol died'
code.
When a printer driver receives a SelectPrinterOK it must select itself as the current printer. Then it decides if it is a temporary selection, in which case it must record the task handle of the printer driver which sent the message, so it can reply with a Message_SelectPermanentPrinter when the temporary selection is finished with.
Two printer drivers on the iconbar. Drop !Email letter onto currently selected printer driver. This creates a Printer$Scrap file, which is DataLoaded to the printer driver by !Email. The printer driver can then open a file to print to (not printer:, but serial:, printer#centronics:, filename or whatever) and do a multitasking print from that Printer$Scrap file.
[ first driver not printing to printer#centronics: ]
Now drop a !Draw file on the other icon. This printer driver:
Broadcasts a message Message_SelectTemporaryPrinter.
Receives Message_SelectPrinterOK with temporary code.
Opens printer: and closes printer: to find out that no-one is using it.
It then sets up its information.
Finally it replies to !Draw with a message PrintFile.
!Draw picks up the PrintFile message, opens printer: and prints the file. !Draw fails to send back the correct Print_WillPrint message. On the next non-message event the printer driver notices it is temporarily selected, and sends Message_SelectPermanentPrinter to the printer which sent it the previous SelectPrinterOK message.
Note that if the first printer were printing to the parallel port (i.e. printer#centronics:) then the following would happen:
[ first driver is printing to printer#centronics: ]
Drop a !Draw file on the other icon. This printer driver: Opens printer: and closes printer: to find out that the first driver is using it. Issue an error 'Printer: in use'.