Printing Windows
Volume Number: 6
Issue Number: 5
Column Tag: C Workshop
Printing Windows and Dialogs 
By Kirk Chase, Anaheim, CA
Note: Source code files accompanying article are located on MacTech CD-ROM orsource code disks.
Not so long ago, I was working on a small, in-house project. I got it running,
debugged it, and then showed it to a co-worker for that ever-refreshing pat on the back
for a job well done. Well, the co-worker looked at it and played around with it for a
moment. Then he looked up to me and said, “I can’t print it out!”
The project did not have the ability to print out its contents. It was small enough
that I thought that nobody would ever be on it long enough to care about a hard copy
print out. In fact, the only reason I had put a “save” and “open” procedure was
because I had a small, single data structure that was easy to write out and read in. I
figured printing was not really needed since the job was small and the window contents
contained some items that were not made for printing (scroll bars, buttons, lists, and
so on).
After talking myself into finding a way to print it out, I went back to the keyboard
to try and find an easy, generic way, to print out the window. My first attempt was
this:
1. Open up a picture.
2. Call the update procedure for my window, thereby recording the drawing
commands.
3. Close the picture.
4. When it came time to print, I would draw the picture in the print port in a
rectangle that was positioned where I wanted it to be.
This had all the elements of being simple. A quick “cut and paste” brought the
print loop in. A few more lines of code, and I was printing out the picture just fine. It
worked great, at least on windows that were not very complex. Another approach was
needed for more complex windows.
Another Approach
Looking at my update procedure, I saw many simple drawing commands, a line
here, a rectangle there, some text, and so on. So I said, why not just skip the picture
and call the drawing routines directly when needed. Cut, cut, paste, paste. And all was
well until I printed it out. Oh, most of it came out. I took a closer look at those items
that did not show up on the printed page. There were no controls, no scrolling list, and
no edit text field. A quick look at the offending structures all yielded a simple
conclusion: they were all tied to the grafport that was my window. It was a battle
between the window and the printer port. When it came time to draw those structures,
they could not be coaxed into changing sides for just a moment. Well, no bucket of sand
and metal was going to tell me what I could and could not print.
It was clear that I needed to put in a flag so that I could branch off to a different
update routine when printing. Then I got to work on the structures: the TextEdit
record, the list, and the controls.
The TextEdit record was fairly simple. I just changed the port temporarily to the
print port. The code looked like this:
/* 1 */
if (theTE != NIL)
if (!forPrinting)
TEUpdate(&tempRect,theTE); /* normal updating */
else {
OldPort = (**theTE).inPort; /* change port in TE */
GetPort(&aPort);
(**theTE).inPort = aPort;
TEUpdate(&tempRect,theTE); /* normal updating */
(**theTE).inPort = OldPort; /* restore port in TE */
}
Simple and sweet.
In Control
The control routines were a touch more difficult. I started out with my own
version of DrawControls(). It looked like this:
/* 2 */
/* Draw or Print Controls */
if (!forPrinting)
DrawControls(MyWindow);
else
PrintControls(((WindowPeek) MyWindow)->controlList);
and the PrintControls() looked like this:
/* 3 */
PrintControls(theControl)
ControlHandle theControl;
{ /* PrintControls() */
ProcPtr controlRoutine;
long dummy;
int varCode;
while (theControl != NULL) { /* control loop */
varCode = GetCVariant(theControl);
HLock((Handle) (**theControl).contrlDefProc);
controlRoutine =(ProcPtr) *((**theControl).contrlDefProc);
dummy = CallPascalL(varCode, theControl, 0, 0L, controlRoutine); /*
Call CDEF to Draw */
HUnlock((Handle) (**theControl).contrlDefProc);
theControl = (**theControl).nextControl;
} /* control loop */
} /* PrintControls() */
What this bit of code does is this. It loops through the control list. It gets the
control’s variant and CDEF proc. It then calls the control proc with the message to
draw the control.
This worked like a dream except for the controls the that were inactive. In there
place was a gray box. The problem was simple. When controls go inactive, for the
most part, they just paint a gray rectangle over their control with the pen mode set to
exclusive-or. This little trick “dims” the control. Unfortunately, the LaserWriter
does not support this mode of drawing. Hence the gray box is the only thing that is seen
(overdrawing the control). The only solution I could think of was to temporarily