Category Archives: Control Panels

5 year anniversary! And happy new year 2023

It feels crazy to think that today it’s been a whopping 5 years since the project got rebooted to its current iteration! Sorry again for slow progress between late summer and the Christmas holidays, a lot of things going on so we have had to juggle between different things and try to prioritise them. But past couple months have been again quite productive, and we have some nice updates to share:

File system improvements

One important feature that was added to NativeFS has been ability to create directories using DirCreate, something that not only installer applications, but also some apps generally depend on. It’s still not perfect (for example extracting the THINK Pascal installer archives made with SmallerInstaller causes the directories to get a bit haywire), but basic use cases such as creating Desktop & Trash folders seems to work.

Also, some groundwork has been laid to support deletion of files, as the AVL tree routines for node deletion were added – but actual deletion of file system items is still a work-in-progress task, which needs to be done carefully and is not to be rushed considering errors and bugs in this code might cause a bit headache to the end-users.

And also, when doing test runs on some Installer VISE installers, we found out that the NativeFS DRVR’s Control handler had used incorrect csCodes for the logical/physical drive icons (we were using 0x16 and 0x17, while correct ones were 0x15 and 0x16), this tiny mistake caused the whole installer to crash…oops! Another quite important bug fix was adding missing IODone call to the NativeFS DRVR’s Status handler, as that caused basically the entire Device Manager to hang…

List Manager multi-select

Not really a tough feature to implement, but one that has been a TODO for long time, list manager multi-selection has been finally implemented. A very good test case for this has been ResEdit, as it supports multi-selection both in the 2-dimensional icon grid, and in the 1-dimensional list view

List multi-select in action in ResEdit

SeedCFill & CalcCMask

Also as part of filling some missing traps, SeedCFill and CalcCMask were implemented. Like the aforementioned list multi-selection, ResEdit again was a wonderful test case for this, as the color editor PACK 1 in it uses these for the color flood-fill tool:

SeedCFill & CalcCMask in ResEdit’s PACK 1 color pixmap editor

Technically, the SeedCFill and CalcCMask actually call SeedFill and CalcMask, and to do that, they first map the color pixmap passed to the routine to a 1-bit image by using a custom color search proc to a temporary bitmap, which replaces matching colors with 0 and non-matching with 1 (i.e. doing floodfill on certain color gets flooded only to exactly matching pixels, while being bound by any other colors)

Application zone teardown updates & fixes

A bunch of fixes and missing features were added to the InitApplZone & SetApplBase, which makes doing transfer/shell launch to other apps way more reliable:

  • Font caches are flushed in SetApplBase and InitApplZone. Sometimes recently used font might be left cached in the application zone, and doing Launch/Chain to new app might accidentally use the cached (but not obliterated from memory) font, causing random crashes.
  • All color grafports, palettes, and VBL tasks located in application zone are disposed/closed

These are quite important fixes, as the aim is to provide soon the much-promised “generic” MACE runtime, which would contain an application shell (i.e. Finder replacement) to reliably run applications from

Communications Toolbox foundation

Weirdly, the Comm Toolbox has a bunch of very non-related routines included, which some applications seem to depend on. The first one we encountered was some Installer VISE installers using the CountDITL selector to get number of items in dialog item list, which the designers of the toolbox interestingly put as part of the Communications Toolbox. Also, the dispatcher mechanism they use is a very non-standard one (they basically pass parameter block pointer in A0 register, which contains the actual arguments of the routine – which might vary in size and number depending on the API call – and expecting result in D0 register). Although there’s just this one call implemented, the foundation for Comm Toolbox was done so that other routines can be added as needed later.

SoftFPU support

Even though Pekka is working hard on the 6888x FPU support, we did interesting experiment to see how well the SoftFPU control panel would work on MACE. Basically, that utility hooks as the F-line exception handler, using SANE calls to the actual math, and passing those results as emulated FPU instruction results. So, emulation inside emulation, kind of. Getting this done was actually quite easy, as the SANE emulation already covers so many calls, so we just had to hook up the F-line exceptions, and implement two missing SANE FP68K selectors (FNEXTX and alternate FX2X), and we were able to run a test app written in THINK Pascal with native 68881/68882 code generation with correct results:

SoftFPU running on MACE

In the above test application, the Compile Options dialog shows that 68881/68882 codegen is active, the code contains math for 9 / 2, and the Text window shows the result of 4.5 (in scientific formatting, as the Dec2Str routine still has some unfinished features)

Some updates to get Civilization 2 to work…almost

One cool game we also have been wanting to play for a long time is legendary Civilization 2, and we took a small steps in getting closer to being able to play that game someday soon:

  • Time Manager’s “hidden” microseconds trap (A093). This one was a bit hard to find documentation for, but we were able to produce close-enough results to keep Civilization 2 happy, which uses it for some reason. Basically the call returns 64-bit microseconds counter, with low 32 bits in D0, and high 32 bits in A0 register.
  • Added DriverGestalt (43) status call to NativeFS, and dgDeviceType (‘devt’) to it, which Civilization 2 seems to use to detect the media type of volume it was launched from (to see if it was started from the CD-ROM or Hard Disk)
  • CopyPalette trap handler (only partial implementation, but seems to be enough for Civ2 startup)
  • Added some more fake process manager data to GetProcessInformation results, in this case basically faked the processAppSpec by using HGetVol to get active directory, and CurApName from low mem…really dirty, but luckily enough again for Civ2. When process manager is someday added, this hack will be replaced by a proper implementation

With these done, we did get the game to progress quite far already:

There are still some big issues in the game, such as missing for some reason the entire backdrop images from the start-up menus, fonts looking ugly because truetype is not implemented (bitmap fonts have the pixelation on non-exact sizes), and color picture recording has still missing features causing city screens to crash.

Newer Technology GURU: “GUide to Ram Upgrades”

One other nice application that we were also experimenting is NewerTech’s GURU, which not only at the time was nice tool for checking out what RAM/VRAM upgrade options you had for Macs, but also doubles as nice mini-encyclopdia of various Macs, clones – and even printers – with their specs and nice color icons included.

GURU running on MACE

To get GURU running, there were a couple things needed:

  • We had again to temporarily tweak the GetProcessInformation’s processSignature (which sadly also WarCraft 2 uses, so both this app and that game need a proper implementation for this
  • Interestingly, the tiny and very harmless-looking popup menu triangles (seen in the screenshot on right-hand side) were actually 16-bit RLE-compressed pixmap images, so we had to implement both the 16-bit pixel translator, and the RLE decompressor in the Color QD Picture bits opcode handler
  • Also, the About Box in GURU used TESetText for styled textfield, which was previously a TODO, so that had to be implemented (it basically just replaces existing styles with a single style run)

MacWrite (finally) works now!

We also took some time to dig into other long-time known issues, one of which the MacWrite crashing on newline issue. Interestingly, two separate bugs did surface:

  • The biggest issue was that doing post/pre-increment of registers in middle of execution was not handled properly, in MacWrite’s case the offending instruction was ADDA.W (A0)+,A0, where value from memory pointed was read, A0 was supposed to be incremented by the word size (2 bytes), and the result added to A0 register. The bug caused the increment to get missed before adding the value to A0, causing it to be 2 bytes too low. This caused a bunch of havok in MacWrite, as the app used its own data structures to keep style data for rows, and this made – among memory corruption – the font size to go to a whopping 255 pixels when adding a new line on keyboard
  • The “justify” text alignment was one of rare cases where spExtra of GrafPorts was used to do sub-pixel (fixed-point) spacing of text, so we didn’t notice before Font Manager was missing a byteswap in handling of spExtra, which caused the cached spExtra to get totally crazy values
  • A rare case of resource map not being initialized properly surfaced on document saving, which was fixed
  • And also, document saving in MacWrite seems to depend on IUSetIntl trap (to apparently write localization data to the document), that trap had to be implemented

With these fixes, MacWrite finally works:

MacWrite works now!

Strategic Conquest

Although most of the features we had tested in Strategic Conquest were working, the map drawing had glitches: polygon lines were missing. We did some investigation about this, and found out that MapPoly trap only mapped the polygon points, but totally forgot to do the mapping for polyBBox. This in turn caused the polygon drawing to assume points were out of range, and fail to render anything in most of cases. With this fixed, the map seems to work fine now (at least in the B&W version):

Strategic Conquest MapPoly works now!

Arkanoid has sound!!!

One issue that was also mysterious for long time was why Arkanoid had no audio, while (almost) every single other black & white game/application had sound. After some researching, we found out that being super smart (and bizarre), instead of the standard VLB queue item (like 99.9% of games), or the not-so-common Lvl1DTVIACA1 interrupt handler (which Fokker Triplane does), Arkanoid actually hooks directly to the AutoInt1 vector on the 68K exception vector list, which normally would be handled by the Mac OS to invoke the VBL interrupts. After adding a level of indirection to the AutoInt1 vector (and adding possibility to later add other interrupt handlers to this level), Arkanoid sounds works perfectly! Sadly we did not have time to get a nice video capture of this for this update 😦

THINK Pascal zone check fixed

Another long-time issue that had been bothering us was that THINK Pascal kept saying in debug mode all the time that all zones were damaged, so we finally took time to dig into the THINK Pascal code and look for their zone check code and see what it was doing. Luckily, the only part that was failing was the trailer check, which checked that the bkLim block was supposed to be always 12 bytes in 24-bit mode, was getting triggered because when GrowZone was adjusting the zone trailer, it accidentally wrote 0 (zero) as trailer size, instead of the expected 12 (ironically InitZone did set it up properly). Although this bug had no functional effects to anything else but the zone check, the THINK Pascal was way more happier now, and looks like the LightsBug debugger is working perfectly, zone browser now included!

LightsBug working nicely after zone checks pass

Other bug fixes

There were a couple bugs/missing features that were fixed, with varying effects:

  • Fixed mask overflow in 32-bit pixel data stretching blitter, and implemented TODOs for some 32-bit pixel data colorization variables – These caused black buttons in some F/A Hornet 2.0 dialogs
  • ScrollRect passed wrong offsetPt to ShieldCursor – this caused some cursor artifacts (this bug did not manifest itself until after the actual software cursor code was added recently)
  • The WDEF 0 (standard window defproc) did not offset the grow box drawing correctly when a window grafport was offset to a non-zero origin (like in PhotoShop) – this caused the bottom-right growbox to get drawn in wrong position on the desktop)
  • 1-bit cursor data saving was missing from SetCCursor – This caused the cursor update to not get triggered if doing InitCursor or SetCursor after doing SetCCursor
  • Fixed issue in RestoreBits, where the menu bar was invalidated in RestoreBits even though it was restored, which in turn caused recursive call to DrawMenuBar when had a menu highlighted (the kMBDFMessageHilite message in MBDF code called RestoreBits which in turn did InvalMenuBar call, which caused the DrawMenuBar to get triggered from the second HiliteMenu call inside the DrawMenuBar) – Fixes the issue of MenuBarPattern code getting stuck in infinite recursion in Civilization, as it tried to double-patch itself from the recursed DrawMenuBar call
  • Added missing call to SystemEvent in GetNextEvent, which caused some events, such as key press events, to not get passed properly to Desk Accessories – Fixes the issue of Key Caps DA not receiving text input
  • Allow BlockMove to receive negative lengths. After researching how the List Manager in some 68k Mac OS versions handle the case of having zero rows but non-zero columns, it seems that they do pass negative lengths (maybe on purpose) to BlockMove with no side effects, and BlockMove ignores those – Fixes the unncessary negative length assertion in ResEdit with empty resource files
  • vRefNum case was missing for GetWDInfo calls in NativeFS, which caused ResEdit to not be able to open files from root directory of a volume
  • Do proper setup of stack pointer on application launch to BufPtr, because this was missing (and SP was left in boot-time default), it cut amount of available memory to apps down to 75% of total RAM! This also surfaced another bug that the startup-time boot grafport (used to draw any stuff during INIT loading etc) was not closed, so any code assuming that all PortList entries were valid were randomly crashing
  • Added style support for TEDelete, so using backspace key in SimpleText works now

What next?

It’s always hard to estimate what will be done and when, but there are still some key goals we’re aiming in the near future:

  • To get the public binaries finally updated after we have time to figure out not only a nice, cheap and practical CDN or other way update the files
  • When electricity prices go down (which got crazy during winter, so had to turn off most of extra computer equipment), work on automating the builds for different platforms, instead of manually building everything (even though CMake does a lot of the hard lifting)
  • Get Sound Manager 3.x to work, so we can start putting out the color version too
  • Try to make sure ReserveMem & NewHandle combos work as expected, right now this is causing THINK Pascal to run out of memory – this is something we want to make sure works, before we move to:
  • 32-bit memory manager. Something that’s needed not just to get more than 8 megabytes of accessible memory, but also to get some picky games (such as Doom) to run, AND to allow:
  • Direct memory access support, for avoiding the overhead of virtual memory interface, potentially speeding up emulation quite a lot. This requires 32-bit memory model to work efficiently.
  • Update build system to include creation of the System file from resource scripts – it’s still being handled as binary file that’s edited using native resource tools, which is not only cumbersome, but also makes it difficult to have variants of the System file for different system types – when we at some point do add process manager support, the way for example desk accessories and fonts are handled needs adjustment, as in process manager-aware (System 7 and later) those are external files instead of ones in System like in System 6 and earlier
  • Work on the so-many missing features (which do also cause known bad behaviour or crashes)
  • Debug and research the problems and crashes which we know about, but haven’t yet figured out what is causing them (such as F/A Hornet and F117A drawing issues, ball missing bug in Loony Labyrinth, timing issues in Monkey Island and Prince of Persia 2…)
  • Prepare a Discord server for public access
  • Many, many, ….many other things

We will as always update our progress on this blog, hopefully a bit more frequently. Your support and encouragement has been very inspiring, and we’re trying as soon as possible to share more and more of the stuff we’ve been making with you.

Full list of changes since last post

2023-02-15 14:56:38 +0200 • Fix 24-bit zone trailer & add bkLim validation
2023-02-15 03:45:35 +0200 • Add dummy ADBOp trap (for SoftWindows)
2023-02-14 21:47:21 +0200 • Expose & use low-level AutoInt1 vector for VBLs
2023-02-13 23:34:21 +0200 • Add LMKbdType and use it for Gestalt & SysEnvirons
2023-02-13 00:27:16 +0200 • Also adjust polyBBox in MapPoly
2023-02-12 17:40:45 +0200 • Style support for TEDelete
2023-02-12 17:39:11 +0200 • Disable font width table logging in debug mode
2023-02-08 23:48:12 +0200 • Merge branch 'master' of
2023-02-08 23:47:43 +0200 • Remember to close the startup-time GrafPort
2023-02-08 06:12:54 +0200 • Merge branch 'master' of
2023-02-08 06:12:50 +0200 • Handle TEMeasure start in middle of style run
2023-02-08 06:12:02 +0200 • Don't return random value if FindFolder fails
2023-02-08 06:11:09 +0200 • Some cleanup in HighLevelFSDispatch
2023-02-08 06:10:30 +0200 • Don't ignore opIFore and opIBack
2023-02-06 02:47:11 +0200 • Reset stack pointer A7 in non-multitasking Launch
2023-02-06 00:48:02 +0200 • Handle vRefNum case in GetWDInfo
2023-02-05 23:15:40 +0200 • Implement IUSetIntl selector for IntlUtils Pack6
2023-02-05 22:29:59 +0200 • Fix rare case of res map handle not initialized
2023-02-05 22:26:45 +0200 • Fix ADDA.W/L postincrement same as destination bug
2023-01-30 12:28:55 +0200 • Fix byteswap bug on spExtra handling in FMSwapFont
2023-01-29 01:26:40 +0200 • Add dummy stub for HMRemoveBalloon (for Excel 3.0)
2023-01-28 08:35:17 +0200 • Implement TESetText styled textfield case
2023-01-28 00:35:35 +0200 • Some process manager placeholder hacks for GURU2.6
2023-01-28 00:34:03 +0200 • Use 16-bit RLE decoder for PICT packtype 3
2023-01-28 00:33:37 +0200 • Add 16-bit RLE decompressor for QD Pictures
2023-01-28 00:32:33 +0200 • Add 16bit direct to indexed color pixel translator
2023-01-26 21:06:19 +0200 • Merge branch 'master' of
2023-01-26 21:06:17 +0200 • Fix 68k Bxx opcode with 32-bit extension
2023-01-26 01:07:16 +0200 • Fix return value of Microseconds trap
2023-01-25 14:45:34 +0200 • Hack face processAppSpec in GetProcessInformation
2023-01-25 13:52:55 +0200 • Partial CopyPalette (0xAAA1) trap implementation
2023-01-25 03:32:02 +0200 • Add dummy Lower/Strip/Upper/StripUpperText handler
2023-01-25 03:01:56 +0200 • Handle 'devt' driver gestalt in NativeFS
2023-01-25 03:00:19 +0200 • Return controlErr on non-support NFS Control codes
2023-01-25 02:41:18 +0200 • Add DriverGestaltParam & dummy handler in NativeFS
2023-01-25 02:39:21 +0200 • Fix broken return from NativeFS Status handler
2023-01-25 02:38:02 +0200 • Implement Microseconds trap (A093) for Time Mgr
2023-01-23 03:10:20 +0200 • Expose some rsc manager stuff for SetResourceSize
2023-01-23 03:09:21 +0200 • Merge branch 'master' of
2023-01-23 03:08:20 +0200 • Log also 68k program counter in trap debug msgs
2023-01-23 03:07:21 +0200 • Update TimeManager.c
2023-01-23 03:06:42 +0200 • Work on SetResourceSize
2023-01-17 22:25:49 +0200 • F-line handler for M68kHelper glue module
2023-01-17 22:04:05 +0200 • Implement FNEXTX and alternative FX2X selector $10
2023-01-17 22:01:38 +0200 • Fix f-line dispatcher installation in 68k cpu code
2023-01-17 00:27:06 +0200 • Add CountDITL, and a VERY bizarre A08B dispatcher
2023-01-16 14:06:31 +0200 • Fix invalid icon csCode in NFS + add assert checks
2023-01-16 13:54:23 +0200 • Fix byteswap bug
2023-01-16 13:41:18 +0200 • Remove VBL tasks in app zone in InitApplZone
2023-01-16 13:34:27 +0200 • Dispose palettes in app zone in InitApplZone
2023-01-16 13:22:09 +0200 • Close all open grafports in InitApplZone
2023-01-16 13:21:38 +0200 • Flush font caches in InitApplZone
2023-01-16 13:02:15 +0200 • Flush font caches in SetApplBase
2023-01-16 13:01:45 +0200 • Add SLCheckApplZoneAddress, for app zone cleanup
2023-01-16 13:01:04 +0200 • Detect use of ResErrProc in resource manager
2023-01-16 13:00:29 +0200 • Add (partial) font cache flushing in Font Dispatch
2023-01-16 12:59:34 +0200 • Implement FCMPL selector in SANE FP68K trap
2023-01-09 23:32:54 +0200 • Implement QDExtensions's GDeviceChanged selector
2023-01-09 23:22:39 +0200 • Implement QDExtensions's OffscreenVersion selector
2023-01-08 23:17:28 +0200 • Added AVL Tree node deletion routines
2023-01-08 13:49:24 +0200 • Implement SeedCFill + CalcCMask QD traps
2023-01-06 16:57:46 +0200 • Fix handling of zero & negative BlockMove lengths
2023-01-06 11:24:27 +0200 • Check VCB flags in SetFileInfo/SetCatInfo
2023-01-01 17:46:21 +0200 • List Mgr's LClick multiselect (shift+cmd) support
2022-12-29 11:06:57 +0200 • Implement RsrcMapEntry trap handler
2022-12-20 00:02:35 +0200 • Don't return mouseMovedMessage unless app4 bit set
2022-12-18 14:05:14 +0200 • Implement SysEdit trap handler
2022-12-18 14:04:49 +0200 • Fix issue of GetNextEvent not calling SystemEvent
2022-12-17 00:25:55 +0200 • Fix unneeded invalidate of menu bar in restorebits
2022-12-14 21:29:16 +0200 • Save 1-bit cursor data in SetCCursor
2022-12-14 16:21:12 +0200 • Fix wDrawGIcon incorrect offset in nonzero origin
2022-12-13 21:49:42 +0200 • Proper fix for horizontal stretch pixel masking
2022-08-24 02:02:08 +0300 • Fix ShieldCursor offset in ScrollRect
2022-08-22 23:21:44 +0300 • Improve relative mouse mode host cursor behaviour
2022-08-22 22:11:12 +0300 • Merge branch 'master' of
2022-08-22 22:11:02 +0300 • Add dummy MIDI driver module (for MIDI Manager)
2022-08-22 22:09:16 +0300 • Fixes to 32-bit direct-to-8bit color QD blitter
2022-08-22 22:08:03 +0300 • Fix mask overflow in 32-bit horizontal CQD stretch
2022-08-21 13:30:13 +0300 • Fix sound manager header
2022-08-05 03:58:52 +0300 • Add empty dummy MIDIGetClients selector
2022-08-05 02:58:50 +0300 • Refactor filesystem AVL tree code & add validation
2022-08-05 02:57:45 +0300 • Cleanup SoundDispatch & add SndDispVersion handler
2022-08-01 17:28:51 +0300 • Merge branch 'master' of
2022-08-01 17:28:46 +0300 • Implement DirCreate file manager trap
2022-07-31 23:09:20 +0300 • Re-export traps & selectors for status update

Summer ’22 update

In attempt to increase frequency of status updates on the project after slow progress during the past year, here’s some information about what we’ve been working hard during the summer vacation.

Styled TextEdit updates

One of the most overlooked – but still very important – features has been the Styled TextEdit support. We already had started working on the foundations almost two years ago, and had last year got the drawing to work pretty well (mostly focusing on Marathon’s “computer terminal” screens) – but actual editing features of the styled text have been largely missing. Luckily SimpleText, with its fully-featured styled text editing features, provides a bunch of test cases for a number of them. Below is screenshot of some text styling at work:

Basic styled text editing in SimpleText

Right now, styled text can be finally entered (using various style parameters such as face, font, size), and SimpleText can also open various text documents with styling information. Below is one example, the READ ME file of Prince of Destruction:

Opening a styled text document in SimpleText

But a lot of work needs to be still done, as major features are still unfinished (such as hit-testing of styled text records, which is needed for both mouse click, arrow key and selection support).

“AppleDoubler” tool

Motivation to work on the “AppleDoubler” tool got boost by a question asked in the June on emaculation about our file system choices. We had planned for a long time to make tool for converting native Mac files to the ADF format, but hadn’t taken time to work on that until now. It didn’t actually take more than a couple hours to write (plus some random time to do some tweaks later), but as nice effect we are able now to convert applications for testing blazingly quickly (compared to the manual conversion process earlier). This has led to discovery of a number of bugs which were fixed, and missing special cases of existing features that have been tweaked.

The AppleDoubler tool will be available as soon as we sort out our binary distributions to work a bit better (until now, files have been hosted here on the WP blog, but due to a bunch of issues with executables, and the time-consuming progress of updating downloads page, we will look into more automated alternate solutions, to allow more frequent updates, and also more downloads to be available.)

Software cursor

One longtime “to-do” task has been proper software cursor implementation, which has been delayed mostly because SDL’s cursor API has handled the monochrome cursors quite well for most of the use cases. However, there have been three downsides of this approach:

  1. The “inverted” cursors (such as the I-beam, and Lemming’s cursors) don’t show up properly, as most modern host systems don’t support inversions in cursor graphics. Especially in lemmings this has been tricky in the monochrome mode, as the cursor would appear black on black background, making the game really hard to play
  2. The native cursors don’t show up when doing screenshots of windows, or when capturing in OBS using window capture. This has been mostly prominent on Twitch streams where mouse has been invisible
  3. Color cursor support has been unimplemented, as for proper ‘crsr’ display the mapping of cursor color table needs to be done

The final push for software cursor implementation came when we tried running Super Studio Session editor, which replaces a number of default cursor vectors with its own implementation (which it uses to align the “note” cursor on music sheet at certain spots). We saw that the cursor that application implemented all by itself worked mostly really well, but because of some ShieldCursor bugs, it was leaving trails at certain places. Below are screenshots of Super Studio Session (ignore the “THINK Pascal” window title, we don’t yet have proper general-purpose shell/desktop application yet, so we used the very practical “Transfer” feature of THINK Pascal to launch any application from the file system through Standard File dialog, without needing to do any extra work 😀 )

It took a couple days of work to get the software cursor to work (the work was sped up a lot by a number abstractions we had done earlier, related to VBL task execution etc), and adding color cursor support was not that tough as ‘crsr’ and ‘ppat’ resources share a common heritage, and thus their color table and depth expansion code could be shared. Below are some screenshots of Civilization, showing the color mouse cursor in action:


As a curiosity, in progress of trying out various applications, we noticed that SoftWindows 1.x (the last 68k-compatible version of that application) seems to work pretty well. As it does have quite high memory requirements (considering the currently implemented 24-bit memory manager by default has only 8 megabytes of RAM), we did have to make a temporary hack to boost the RAM limit in the test configuration to 12 megabytes (leaving space for only 3 slots in the emulated slot address space – while the default configuration allows up to 7). This allowed us to actually boot into Windows 3.1 and run a number of games/apps on it (biggest limiting factor for what worked was that this version SoftWindows only emulates a 286, thus allowing only Standard mode in Windows 3, instead of the Enhanced mode required by a lot of applications). Below are some screenshots of what we tried out:

MIDI Manager research

As we knew that certain Sierra games do advertise MT-32 compatibility, we did some quick snooping around, and learned that at least Space Quest 1 does use Apple’s little-known MIDI Manager to handle the hardware MIDI playback (unlike Thexder, which appears to have its own serial driver for MIDI, choosing to use the serial port directly). This led to some curiosity about the MIDI Manager implementation, for which there is sadly very little documentation – an article about programming it on the always valuable MacTech archive and the universal headers. A couple articles from mid 90’s point to ARPA as source to buy the MIDI documentation and SDK from, which sadly is no longer available.

The work on MIDI Manager support is still ongoing, but we feel it might be relatively easy to write a layer that emulates MIDI Manager’s patching features, and wrap the MIDI driver as a abstract device that could pass the MIDI packets to host OS’ native MIDI interface (in Mac OS X case, the CoreMIDI). All MIDI Manager calls go anyway through the same SoundDispatch trap like a number of Sound Manager calls, so tapping to that interface is really easy. (Another question, though, is how well timing will work, and whether default MIDI synthesizer (or the SC-55 midi hardware) will handle Space Quest’s MIDI output that expects an MT-32…)

Various other updates

As mentioned before, there have been a ton of fixes and updates, but here is mention of a couple ones that might be of interest:

Popup Control CDEF (and TextEdit) fixes: There were a number of bugs in both the Popup Control drawing (and TextEdit setup) code, which manifested quite visually in the HyperCard script editor. Below are screenshots of “before” and “after” to show what kind of effects the fixes had:

Menu Bar Pattern Control Panel: As another curiosity, we tried this one old Control Panel from early 90s, to see what would happen – and seems that whatever magic it uses to draw patterns behind menu bar, it seems to be 100% compatible:

Menu Bar Pattern Control Panel

FracSin/FracCos: The After Dark module called “Spotlight” (not to be confused with the OS X search tool) was the first case that needed FracSin/FracCos implementation to work, so we used it as a test case for those traps and got it working pretty well:

After Dark “Spotlight”

Palette fixes: There were a number of bugs & missing features in Palette Manager code (for example, SetEntries had bug that made it fail incorrectly with cProtectErr, which caused a number of issues around the place). Here is Lode Runner: The Legend Returns editor, which had weird color issues before the fix (ignore the palette debugger in bottom right):

Lode Runner: The Legend Returns level editor

BitmapToRegion: This trap was already before used by Escape Velocity, but as that game needs a couple other improvements to reach playable state, Snood worked out pretty well as a use case for this (as it uses it for practically all of its sprites to convert their masks to regions for drawing). After a couple hours, the game seems to be quite happy with the routine (Snood 1.x pictured):

Snood using sprites with masks defined by BitmapToRegion

Default MDEF ‘cicn’ support: While trying out Snood, we noticed that Snood 2 was the first use case of color icons (‘cicn’s) in menu items. As the MDEF already had almost-working handling for this case, we added some temporary code to the Icon Utilities module and got nice color icons in menus now:

Color icons in Snood 2.x Players menu

More blitter fixes/improvements: There were numerous fixes to basic blitters too, which affected test cases such as 3 in Three, “Spotlight” (when brightness was other than 0%), Shanghai II mahjong, etc). Here’s some screenshots of what we got working with the improvements:

Next step

We will continue working on the missing features as always, trying to reach the goal of a generic runtime release as soon as possible. We also will try to find solution for the binary file distribution in near future, so anybody interested trying the new features out could do that as soon as possible (especially considering the last released binaries are already getting quite old). We will keep you updated on this blog on our progress as always.

Full list of changes since last post

2022-07-31 00:45:08 +0300 • Implement colorizing srcOr rectangle blitter
2022-07-30 23:49:00 +0300 • Implement colorizing srcBic rectangle blitter
2022-07-30 13:34:42 +0300 • Fix missing handle derefence bug
2022-07-30 13:47:58 +0300 • Implement SaveEntries trap for Palette Manager
2022-07-30 04:09:17 +0300 • Disable potentially invalid check in Entry2Index
2022-07-30 03:08:06 +0300 • Stretching subPin blitter + improve call interface
2022-07-30 03:07:01 +0300 • Reinforce zone checks for handle operations
2022-07-30 01:27:53 +0300 • Fix AppendMenu/InsertMenuitem legnth > 127 cases
2022-07-30 01:14:39 +0300 • Implement a rudimentary PlotCIconHandle (for MDEF)
2022-07-30 00:39:04 +0300 • Merge branch 'master' of
2022-07-30 00:38:58 +0300 • Proper implementation for BitmapToRegion QD trap
2022-07-26 23:16:20 +0300 • Add dummy MIDIManager (+ MIDISignIn & MIDIAddPort)
2022-07-26 20:35:26 +0300 • Merge branch 'master' of
2022-07-26 20:35:16 +0300 • Implement PaletteDispatch ResizePalette selector
2022-07-26 18:28:13 +0300 • Fix timer thread race condition issue
2022-07-26 15:53:28 +0300 • Implement color QD opDefHilite PICT opcode
2022-07-26 15:52:42 +0300 • Implement opPnLocHFrac PICT opcode
2022-07-26 15:52:06 +0300 • Fix edge case of shielding cursor in classic mode
2022-07-26 14:51:53 +0300 • Fix GetNew(C)Window autopositioning code
2022-07-26 14:07:53 +0300 • Fix TESetStyleScrap (StyleDataPtr -> TextStylePtr)
2022-07-26 05:35:47 +0300 • Version 9 compressed resource support (+fixes)
2022-07-26 03:05:37 +0300 • Add dummy ReplaceText selector stub for ScriptUtil
2022-07-26 00:46:57 +0300 • Add TESetStyleScrap (needs still some work)
2022-07-25 03:33:36 +0300 • Update line start for redraw when setting heights
2022-07-24 14:12:29 +0300 • Implement styled TESetSelect
2022-07-24 14:11:48 +0300 • Partial implementation of styled TEInsert
2022-07-24 06:08:06 +0300 • Merge branch 'master' of
2022-07-24 06:05:17 +0300 • Work on styled text (TEContinuousStyle selector)
2022-07-24 06:03:22 +0300 • Implement AdMin blend mode in color region blitter
2022-07-23 22:33:53 +0300 • Call vector #4 for unimplemented instructions
2022-07-23 02:07:22 +0300 • AppleDoubler: cleanup tool console output logging
2022-07-23 01:40:40 +0300 • AppleDoubler: add timestamps,buildscript & cleanup
2022-07-21 16:26:26 +0300 • Fix incorrect cProtectErr check in SetEntries
2022-07-21 15:32:55 +0300 • Implement FracSin and FracCos traps
2022-07-19 15:40:00 +0300 • Only mark arc dirty, if drawn on the screen port
2022-07-19 15:02:32 +0300 • Fix some compiler warnings (missing QD includes)
2022-07-19 15:00:12 +0300 • Use bullet (0xA5) as mark in popupUseWFont CDEF 63
2022-07-19 14:58:54 +0300 • Fix one-off error in MBDF hittest (crashed popups)
2022-07-19 06:45:32 +0300 • Fix saving of port state in TextEdit calls
2022-07-19 06:44:33 +0300 • Fix warnings in cursor module
2022-07-19 06:13:22 +0300 • Merge branch 'master' of
2022-07-19 06:12:48 +0300 • Add color QD hilite & fix font state in CDEF 63
2022-07-18 21:14:00 +0300 • Merge branch 'master' of
2022-07-18 21:13:52 +0300 • Cleanup: Refactor cursor code out of Mouse module
2022-07-18 04:12:22 +0300 • Support also function key (F1-F15) key codes
2022-07-17 07:38:02 +0300 • Fix incorrect ShieldCursor offsetPt in CopyBits
2022-07-17 07:27:27 +0300 • Implement DefaultSetCCursor (for 'crsr' support)
2022-07-17 07:26:49 +0300 • Fix MCallSetCCursor (called wrong vector)
2022-07-17 07:26:03 +0300 • Fix handle resizing bug in GetCCursor
2022-07-17 06:15:09 +0300 • Fix cursor left-side clipping
2022-07-17 02:36:52 +0300 • Color QD monochrome software cursor implemented
2022-07-11 23:12:03 +0300 • Use DoVBLTask do update cursor in color QD mode
2022-07-11 23:09:54 +0300 • Implement AddIconToSuite selector in IconDispatch
2022-07-11 21:56:20 +0300 • Implement NewIconSuite selector for IconDispatch
2022-07-11 19:40:19 +0300 • Implement AttackVBL trap
2022-07-11 14:27:11 +0300 • More color vs b&w QD cursor code specialization
2022-07-11 02:43:18 +0300 • Cleanup Cursor module code
2022-07-11 02:42:49 +0300 • Specialize Color QD case in ShieldCursor
2022-07-11 02:35:42 +0300 • Init cursor at startup
2022-07-10 14:29:23 +0300 • Redraw software cursor in SetCursor, if changed
2022-07-10 13:13:16 +0300 • Fix clamping of mouse in DefaultCrsrTask
2022-07-10 04:07:45 +0300 • Merge branch 'master' of
2022-07-10 04:07:02 +0300 • Implement software cursor for "classic" QD mode
2022-07-10 04:05:22 +0300 • Fix DefaultShieldCursor (it did not erase cursor)
2022-07-10 03:58:34 +0300 • Fix CrsrObscure handling in the DefaultCrsrTask
2022-07-10 03:57:44 +0300 • Only setup AllocCursor and SetCCursor in color QD
2022-07-10 03:56:18 +0300 • Increase screen buffer refresh rate temporarily
2022-07-10 03:55:34 +0300 • Fix mouse native window clamping (-1 from bounds)
2022-07-08 02:35:07 +0300 • Merge branch 'master' of
2022-07-08 02:35:00 +0300 • Vectorize SetCCursor (& fix some setup bugs)
2022-07-08 02:17:30 +0300 • Merge branch 'master' of
2022-07-07 20:25:22 +0300 • Fix ShieldCursor bugs
2022-07-05 23:44:59 +0300 • Fix Serial.h
2022-07-05 02:56:01 +0300 • Merge branch 'master' of
2022-07-05 02:55:56 +0300 • AppleDoubler: Fix OSX's weird swap of ':' and '/'
2022-07-04 16:50:27 +0300 • Fix LoadSeg 32K+ offset wraparound (use unsigned)
2022-07-04 16:29:48 +0300 • Merge branch 'master' of
2022-07-04 16:29:41 +0300 • Add dummy serial driver stub (AIn/AOut/Bin/BOut)
2022-07-04 15:04:51 +0300 • Fix UPP call signature of JShieldCursor
2022-07-04 04:28:09 +0300 • Merge branch 'master' of
2022-07-04 04:27:59 +0300 • AppleDoubler: Also encode folder names
2022-07-04 02:16:46 +0300 • Fix byteswap bug in font size check
2022-07-04 02:00:14 +0300 • Fix FOND style lookup: start at 1st match,not last
2022-07-04 01:56:59 +0300 • Add Oregon Trail (1.x) to test app configs
2022-07-03 14:05:54 +0300 • Implement QDDone selector for QDExtensions
2022-07-03 13:56:22 +0300 • Merge branch 'master' of
2022-07-03 13:56:16 +0300 • Add (no-op) LockRange & UnlockRange in FSDispatch
2022-07-03 04:29:30 +0300 • Add first version of AppleDoubler converter tool
2022-07-02 06:13:32 +0300 • Handle NFSGetDirInfo errors in NFSCreateFileHook
2022-07-02 06:12:36 +0300 • Implement DateToSeconds
2022-07-02 04:06:13 +0300 • Add SoftWindows test app to JSON configs
2022-07-02 04:05:42 +0300 • Implement GetGWorldDevice selector in QDExtensions
2022-06-18 02:05:16 +0300 • Add ZPC to test app config JSONs
2022-04-28 04:01:02 +0300 • Fix crash in TECallCharByte utility routine
2022-04-28 04:00:57 +0300 • Add missing header file from previous commit
2022-04-28 03:57:54 +0300 • Tweak naming of some private TE data structures
2022-04-28 01:18:54 +0300 • Fix GetCTable crash of locked 'clut' in 24bit mode
2022-04-23 22:04:03 +0300 • Implement styled TESetStyle
2022-04-23 21:42:07 +0300 • Work a bit on InitScripts (load smRoman 'itlb' 0)
2022-04-23 13:55:03 +0300 • Add Font2Script & implement FontScript+IntlScript
2022-04-18 11:28:33 +0300 • Temporary fail-safe in _Enqueue
2022-04-18 02:06:31 +0300 • Finish faster non-MeasureText path in NPixel2Char
2022-04-17 22:52:23 +0300 • Use NPixel2Char in TextEdit (FindLine etc)
2022-04-17 22:50:50 +0300 • First version of working NPixel2Char in Script Mgr
2022-04-16 21:08:10 +0300 • Implement SndControl (classic SM2)
2022-04-15 05:03:02 +0300 • Prep TEHitTestHook calls to work with NPixel2Char
2022-04-15 04:59:57 +0300 • Handle 0x2C (font) and 0x2E (glyph state) in PICTs
2022-04-13 16:20:10 +0300 • Fix Munger ptr2=nil & len2=0 case (search)
2022-04-13 02:41:36 +0300 • Allow bypass of ampCmd and timbreCmd in snth 4101

Marathon fixed & INITs revisited; Fun with Control Panel (cdevs & After Dark)

Marathon color fix

As predicted in the previous post, the culprit for the messed up colors in Marathon was actually just the unfinished implementation of UpdateGWorld. What caused problems in this case was, that the color table in the backbuffer GWorld, which the game uses for off-screen drawing, was created during loading when the intro color table was active, and thus it “inherited” that active color table from the GDevice. However, UpdateGWorld was expected to update new colors from the GDevice when entering the game, and as it was not implemented, that left the old color table intact and messed up the colors. The current implementation of UpdateGWorld handles most of the cases, but does not do the existing pixel data conversion cases, which some applications might required (TODO-assertions were added there though, to signal when we encounter such case).

One handy source (literally!) for debugging Marathon’s backbuffer behaviour was the Marathon source code, which Bungie published quite some time ago at:

Also, we noticed that Marathon has pretty decent support for mouselook, so we enabled the relative mouse mode for test JSON config, and it feels pretty playable with it.

Here are some screenshots of the first level of Marathon running (finally) with proper colors:

Here are also a couple screenshots of one of the demo levels played by the game after staying idle in the main menu:

The first level seems to be completely playable until the end, except that the terminals on the level do not work yet (they require the Styled TextEdit implementation, which still remains on the TODO list – however with quite higher priority now, as so many applications seem to need it already). This is especially tricky as the teleport used at end of the level requires that feature also to pass the level 🙂

INITs revisited

Some time ago, we played around a bit with the INIT loading during startup, and used it to load After Dark screen saver. However, the handling of memory during startup was not optimal; basically BufPtr, which is the top of memory usable for application zone, and 68k stack pointer, were colliding, which caused random crashing.

As the color support is already quite nice for most basic cases (in indexed color modes), we wanted to see how After Dark would work in the color mode, so we did some quick fixing for this. Basically we moved the stack to near middle of the memory range, in a area which was very unlikely to hit the top of system zone, and way below the BufPtr limit, which After Dark wants to lower. This seems to fix that problem for now.

Control Panels

Another important thing we wanted was to allow the After Dark control panel to be usable, so that the screensaver modules could be configured. As we don’t have yet our own control panel to support running cdev resources (the control panels), we temporarily tried out what happens if we run the actual, real Control Panel desk accessory from System 6 – seems that there almost no issues getting this to work, as seen below:

System 6’s “General” Control Panel (cdev) running in the System 6’s Control Panel Desk Accessory (DRVR) running on M.A.C.E.

Surprisingly, bunch of the functionality in “General” control panel was directly working; The desktop pattern editor was almost completely functional, but required implementation of the SetDeskCPat trap, which it uses to apply modified pattern on the desktop. Menu blinking and caret flash controls work directly (as TextEdit and Menu Manager were built to use those low memory globals), and speaker volume control works when run in the “classic” (monochrome Mac Plus style) mode – color version still has the unfinished Sound Manager implementation. The date & time controls show placeholder value as the International Utilities routines are still unfinished, and RAM cache does nothing 🙂

System 6’s “CloseView” Control Panel (cdev) running in the System 6’s Control Panel Desk Accessory (DRVR) running on M.A.C.E.

Even more interestingly, the CloseView control panel (above) also work almost without any fixes; The Key1Trans and Key2Trans low memory procedure pointers were needed to allow shortcut keys to not crash. The zoom controls and zooming work neatly and follow mouse properly, as the cdev does some clever patching of a number of QuickDraw routines, so all the native C drawing is directed to a secondary buffer, which the CloseView cdev draws actually on the screen – when active, it seems to replace WMgrPort and WMgrCPort with the backbuffer, and even modifies ScreenBase to make CopyBits work properly! However, there is still some issue with the algorithm it uses to track “dirty” area, when magnification is off but closeview is active, as it leaves some artifacts on the screen when for example moving windows.

After Dark Control Panel (cdev) running in the System 6’s Control Panel Desk Accessory (DRVR) running on M.A.C.E.

But most importantly, After Dark is now also working. There were a couple fixes needed to make the control panel itself, and some modules, work – such as blend and subpin transfer modes for rectangle blitter, and a number of System 7-type temporary memory handle allocation functions (which for now just directly map to regular handle allocations in the application zone).

But most importantly, the rather complex and deep mix of native C, 68k DRVR, INIT and cdev code with patched traps included, surfaced a rare register trashing condition in the invocation of 68k code from native code – this was only present as a crash when using “Demo” feature of After Dark control panel! The problem was, that as certain 68k procedure calls needed arguments to be passed in registers, they were not saved before the call – and as native C part of the toolbox does not use the 68k registers, and thus does not internally save them, certain 68k -> native -> 68k call combinations resulted with registers being trashed. After adding the fix by implementing proper register save/restore, After Dark is much more stable, and looks great! Here are screenshots of some of the modules which work now (you can click image for larger view):

There are still a number of things to fix though; for example, MultiModule does not work yet (cannot configure modules for some reason), and other modules have unique cases which need to be handled separately (such as “Down the Drain” requiring GetCPixel), and some modules occasionally spitting “Not enough memory” error, but this is good as it provides a lot of test cases for the future!

Also some of the other desk accessories were kind of working and not; some such as “Mouse” control panel won’t have any affect (mouse is right now completely controlled by host operating system), “Monitors” requires proper Slot Manager implementation for handling the graphic devices to not crash, “Color” (probably) needs to have support for modifying the labels in System file, and “Sound” does not do much without Sound Manager. We will in future also try out other cdevs to see what happens 🙂

Full list of changes since last post

2020-10-30 04:38:37 +0200 • Rename SMSlotInterruptGlobals for clarity
2020-10-30 04:36:28 +0200 • Iterate INIT resources in LoadNamedINITFile
2020-10-30 04:33:32 +0200 • Enable relative mouse mode for marathon cmake JSON
2020-10-30 04:33:05 +0200 • Add control panel files to TeachText cmake json
2020-10-29 23:57:28 +0200 • Implement CloseCPort trap
2020-10-29 23:53:50 +0200 • Also add subPin mode to pattern rectangle blitter
2020-10-29 23:26:20 +0200 • Arithmetic blend mode in pattern rectangle blitter
2020-10-29 23:24:53 +0200 • Save & restore ALL 68k register on C->68k calls
2020-10-29 17:40:16 +0200 • Fix byteswap bug in UPP routineCount
2020-10-28 03:55:16 +0200 • First part of Key(1/2)Trans lowmem proc support
2020-10-27 07:09:52 +0200 • Add dummy TempFreeMem/NewHandle/HLock/DisposHandle
2020-10-27 05:52:11 +0200 • Add ShutDown Mgr (+ dummy ShutDwnInstall selector)
2020-10-27 05:30:12 +0200 • Make SystemTask more compatible with DAs
2020-10-27 03:05:01 +0200 • Implement SetDeskCPat trap handler
2020-10-27 02:49:46 +0200 • Implement PixPatChanged selector for QDExtensions
2020-10-27 02:43:19 +0200 • Also fix the hack in boot-time temp memory size
2020-10-27 02:42:05 +0200 • Temporarily move SP out of below BufPtr at startup
2020-10-27 02:41:05 +0200 • Fix a really stupid DRVR call bug (HLock missing)
2020-10-13 01:03:50 +0300 • Set RAMBase during startup
2020-10-06 01:17:40 +0300 • Dummy placeholder for WriteParam trap handler
2020-10-06 01:16:12 +0300 • Fix directory ID for indexed non-HFS GetFileInfo
2020-10-06 01:14:03 +0300 • Implement (kind of) TempTopMem OSDispatch selector
2020-10-03 17:27:12 +0300 • Add SlotManager dispatcher (and SVersion selector)
2020-10-03 03:33:17 +0300 • Fix memory leak in ClosePort
2020-10-03 03:30:57 +0300 • Add rest of UpdateGWorld (except pixmap data copy)
2020-10-03 02:33:45 +0300 • Handle _MapRgn wideOpen case; Fixes Marathon map
2020-10-03 01:34:23 +0300 • Clear MemErr in Lock/UnlockHandle on success
2020-10-02 16:30:08 +0300 • Fix warning in LayerDispatch from missing #include
2020-10-02 05:07:00 +0300 • Pass right pixelDepth to NewGWorld in UpdateGWorld
2020-10-02 04:57:55 +0300 • Some progress on UpdateGWorld implementation