MiniVNC is a remote desktop server that has been written from the
ground up for best performance on 68k Macintosh computers.
It was originally an experiment to see whether a Macintosh Plus could
be controlled remotely, but has since been expanded to support color
on all vintage color Macs!
MiniVNC is built on MacTCP and requires System 7, but it will
operate on later Macs using Open Transport. MiniVNC has been
developed and tested using a RaSCSI device operating as an
Ethernet bridge, but should also work using a Mac with a built-in
Ethernet port.
The goal of MiniVNC is to provide better performance and compatibility
with older Macs than ChromiVNC
Development of MiniVNC required months of experimentation and hacking.
The following write-up provides details for developers who have an
interest.
MacTCP Programming is Hard; Doing it Efficiently is Harder
MacTCP is Apple’s first TCP/IP networking stack and is the only
networking API available on the Macintosh Plus. The
MacTCP Programmer’s Guide is a good resource, but lacks code
samples and makes no mention of high-level languages. The
MacTCP Cookbook article by Steve Falkenburg provides more meat
to chew on but actual source code is worth a thousand words. I
finally it on the Apple Developer Group CD Volume VII in the
form of a “finger” protocol example in the directory
Dev.CD Vol. VII:develop:develop 6 code:TCP:finger
This is a good starting point as the “TCPRoutines.c” file
provides an example of using MacTCP parameter blocks from a
high-level language. Steve’s helper routines, while easy-to-use
for simple tasks, are very slow. As I later learned, the most
efficient way to do MacTCP programming is via asynchronous callback
routines.
Since these callback routines execute in interrupt time, writing them
in a high-level language is challenging. I used the technique from the
article “Asynchronous Routines on the Macintosh” in Develop magazine,
March 1993 which involves an assembly language glue routine. Later on,
I used a similar routine for making a Vertical Retrace task for gathering
screen updates.
Today we take for granted threads which make it easy to implement
network applications. The use of callback routines is a huge step
backwards.
For one, it precludes using temporary stack-based storage and instead
all state must be stored in global variables. Doing things like loops
are trivial in a thread but very difficult using callback routines.
The VNC protocol is fairly simple, but the code is far more
complicated than it would have been had I modern techniques at my
disposal.
As an aside, Ari Halberstadt wrote a very promissing thread library
for the Macintosh. Getting it to work with MacTCP might have simplified
the programing model, but at the time it was too much of a heavy lift
for me to get it to work while I was also learning MacTCP. I ended up
using some of his basic OS utilities code in MiniVNC, but not the thread
library itself.
Mouse Control
On the Macintosh, the mouse can be progmattically changed by writing
the new position to the low-memory globals MouseTemp
and
RawMouseLocation
and then copying the value of CrsrCouple
to
CursorNew
to signal the change. This technique is borrowed from
ChromiVNC.
Mouse button control presented a challenge. The technique used by
ChromiVNC is to write the new mouse button state to the low-memory
global MBState
while simultaneously posting a mouseUp
or mouseDown
event to the System event queue. This works on modern Macs, but on the
Macintosh Plus it only works for clicking. Mouse dragging — and
crucially, menu selection — does not work. On that machine the
VIA interrupt in ROM constantly overwrites MBState
with the button
state from the physical mouse, so the trick of writing a value to
MBState
does not work.
I attempted patching the Button
trap and implemented a journaling driver,
but the former was ineffective while the latter was found to be broken and
unusable under System 7’s multi-tasking model.
At last, an analysis of the disassembled code for the VIA interrupt
revealed it deglitched the mouse button by waiting three ticks prior to
updating MBState
. The low-memory variable MBTicks
indicates the start
of the wait period and by periodically setting it to the future &emdash;
in advance of TickCount
— I found I could keep the VIA routine
waiting indefinitely so that I could alter MBState
at will. This
allowed me control of the mouse button on all Macs, including the Macintosh
Plus.
Screen Change Detection via Checksums
On the vintage Macintosh, the