C for Yourself - part 46

Steve Mumford continues his overview of the printing process

Following on from last month's instalment, here's a closer look at the message passing protocol that must take place when printing from within the WIMP. This 'red tape' is necessary to avoid conflicts between applications as they try to share resources, as well as providing a method of extending the WIMP's functionality without changing the user interface.

The printing protocol

In order to check whether Acorn's Printers application has been loaded, the program must send a message to all the active tasks running in the WIMP and hope that the printer manager responds to your call. This is done by using Wimp_SendMessage to broadcast a Message_PrintSave using a format similar to the one shown below:

#define Message_PrintFile 0x80140
#define Message_PrintSave 0x80142
#define Message_PrintTypeOdd 0x80145
#define Message_PrintTypeKnown 0x80146

unsigned char msgblock[256];
_kernel_swi_regs in, out;

au_wordtobyte(256, msg_block, 0); /* size of message block */
au_wordtobyte(0, msg_block, 4);
au_wordtobyte(0, msg_block, 8);
au_wordtobyte(0, msg_block, 12); /* this is an original message */
au_wordtobyte(Message_PrintSave, msg block, 16);
au_wordtobyte(0xff4, msg_block, 40); /* filetype */
in.r[0] = 18; /* User Message Recorded */
in.r[1] = (int) msg_block;
in.r[2] = 0;
_kernel_swi(Wimp_SendMessage, &in, &out);

Setting R2 to zero indicates to the WIMP that this message is to be distributed to all currently active tasks, and storing 18 in RO gives it the type User_Message_Recorded - in this case, if no other tasks reply to the message, the process that sent it is informed and given a copy back with a Wimp_Poll event code of 19. Assuming that the printer driver is present and all is well, your task will receive a Message_PrintFile in reply.

Although RISC OS 2 handled this stage slightly differently, with RISC OS 3 we just ignore that announcement and wait for Message_PrintTypeOdd to be sent to our application. This message is sent out whenever Printers is given a file to print that it doesn't recognise, so we have to check that our program was actually trying to print something before replying to it with Message_PrintTypeKnown. At this stage, the protocol is complete and we can now concentrate on preparing the output.

Printer options and page sizes

Once you've determined that the Printers application has been loaded, the active printer driver can be queried to reveal its current capabilities, from the available x and y resolutions to the dimensions of the printable area of the paper. These details are commonly used to customise dialogue boxes and display absolute printing boundaries on screen, enabling the user to predict fairly accurately what will and won't appear on the page.

The two SWI calls which provide these details are PDriver_Info and PDriver_PageSize. Both are called with an empty set of registers; no parameters are necessary. On return, the registers contain all the information relevant to the currently selected printer driver - PDriver_PageSize is the simpler of the two and returns the full x and y dimensions of the page in millipoints in registers 1 and 2. These are followed in registers 3 to 6 by the distances to the left, bottom, right and top edges of the printable region of the paper as measured from the bottom left corner.

PDriver_Info is a little more complicated but it supplies the programmer with a large amount of information. RO is split and holds the printer driver's version number (multiplied by 100 to convert it to an integer) in bits 0 to 15, storing another integer in bits 16-31 to indicate the type of the printer. For instance, the number 0 indicates a PostScript printer, 2 means you're talking to an HP LaserJet or compatible, and the number 4 represents a fax modem. R1 and R2 hold the x and y resolutions of the printer in question, R5 and R6 store halftone resolutions if used, and R4 points to a string giving the printer's name (a maximum of 20 characters in length including the null termination byte).

R3 holds a series of bits that indicate the printer's capabilities quite precisely - looking at the value of these bits would allow you to determine how many colours were available, whether it can handle colour overwriting and so on. These values are useful in allowing the programmer to change the plotting method to make best use of the printer's facilities - for instance, attempting to plot a sprite on a pen plotter isn't going to get you very far. We'll make use of these next time.

Source: Acorn User - 190 - January 1998
Publication: Acorn User
Contributor: Steve Mumford