Category Archives: Uncategorized

Happy new year 25/26 – Quick update

It’s been a busy later half of the year, but there are some minor interesting updates to share from this time. This is a short update, especially as we didn’t have time to update binaries right now, but will do that later in the spring.

Testing “better” shell relaunch with RealExitToShell

In the past, doing ExitToShell has just done plain “exit(0)”, causing the emulation to terminate immediately, reflecting the nature of application bundles being handled as private processes within the host system. However, for the next step of development, to make it a more general purpose application runtime environment, having a proper shell application and mechanism for returning from applications to it is required.

As indicated by the name of the trap ExitToShell, it should in this case return control to the shell application by launching it, instead of just doing dummy exit. The tricky part, however, has been the nature of having layer of C-based toolbox intertwined with 68k code, which causes call stacks to mix between 68k and native code. Luckily with System 6-type emulation there’s a very handy, albeit rather “hacky” solution – that is, using setjmp/longjmp for setting up and tearing down the native stack frames.

For experimenting this feature, we added setjmp call just before initial shell launch, and when RealExitToShell configuration flag is active, instead of doing “exit(0)” we do longjmp to rewind native stack to state where it was before shell launch, and continue from there. All the emulated 68k environment is already set up from scratch at that point, so we didn’t have to do much modifications, and the hack seems to work pretty good for this purpose

We did have to fix a couple parts that were not compatible with shell relaunch, most notably clearing application palettes in color mode, and fixing a bug with resource file cleanup when closing old resource maps.

With this current limited hack, we were able to run Apple’s Finder from System 6 under MACE with quite good success. Below is video of how it turned out:

Important note regarding this is that next we have to implement proper disabling/enabling of toolbox traps based on feature levels, as System 6’s Finder has a mysterious quirk that if it detects OSDispatch is implemented, it attempts to do MultiFinder stuff, even though the Finder itself is single-tasking version. For this experiment, we had to manually disable it in the trap table, but there are also other applications which require certain traps to be marked as unimplemented to work properly (most importantly, MS Excel attempts to do System 7 specific stuff if it detects OSDispatch trap, no matter what the reported Gestalt/SysEnvirons System version is. Another case is also Welltris, which does check presence a bunch of Color QuickDraw traps, and attempts to use color-only traps even in classic mode if those are defined). This is something we want to get done for the summer update, to make the generic runtime environment closer to reality.

Another note is that at some point we need to create our own Finder replacement, as even though System 6’s Finder runs quite nicely, we do need to create an alternative shell that would be legally distributable with the generic runtime. Same also goes to certain Desk Accessories, such as Control Panels, which is also Apple’s implementation, and needs to be replaced with original version with close enough functionality.

Also another important note is that this hack only applies to System 6-style single-tasking emulation – for proper System 7-style cooperative multitasking support we need to implement not just the shell launching, but also task switching, with quite different mechanics. We have an idea for this, but it needs kind of major overhaul in the threading system (which we use currently to allow VBL and timer tasks to “interrupt” the active application properly). More on that later!

Other interesting minor updates

File renaming support

As part of experimentation with Finder, we saw need to implement finally renaming of files & folders. The tricky part here was that we need to keep the native file system file paths & names in sync, but using POSIX rename and careful traversal of directory subhierarchy, at least Finder seems to be able to quite well rename the files & folders without major issues. There is known issue that any open FCBs in renamed paths are not updated, but as in System 6-style single-tasking mode it is rare case to rename open files/folders, we’ll fix it later this year.

Text truncation

We also implemented finally truncEnd (and truncMiddle) for TruncText/TruncString, which makes especially file dialogs look much nicer with long, non-fitting filenames getting ellipsis symbol indicating truncated text. This was also visible in the Marathon’s map preview in the load game file selection dialogs.

Proper time formatting using internationalization resources

One quite important feature was also date & time to string conversion routines, which use the itl0 and itl1 resources to also localize the converted dates, and allows also user to configure their own date & time formatting. This is visible in a number of places, including Dalek’s highscore lists, Pipe dream highscore list, ResEdit file “Get Info” dialog, Finder list-style folder views, etc.

Finally fixed the FramePoly glitch

One long-standing (and embarassingly rather simple to fix) issue was the glitches in FramePoly trap. As most of polygon drawing is delegated to region rendering, we accidentally also passed FramePoly to FrameRgn, which in hindsight makes no sense, as FramePoly should logically just draw lines to connect the polygon points. The problem was, that as polygon was converted by FramePoly to region before doing FrameRgn on it, the bounds of the polygon would be off by one pixel, causing quite visible glitches in The Fool’s Errand. Now with this fix, that game also works quite perfectly.

ScreenRow low-mem global buggy behaviour

One really puzzling issue was behaviour of the ScreenRow low memory global…we originally assumed it would be expected to contain rowbytes value of currently active screen resolution & color depth, but what it was actually was supposed to contain was rowbytes of not the active color depth, but imaginary 1-bit screen of the current resolution…so instead of having rowbytes value of 640 in 256-color mode of 640×480 resolution, it was expected to have 80. This issue surfaced when trying to run Titan in color mode, as it depended weirdly on this specific behaviour. It should be noted, that during our testing, we noticed that at least in System 7.1/7.5 also Apple’s own implementation seems to indecisive about this, as Apple’s system starts with this 1-bit rowbytes value, but changing the color depth replaces this low memory value with current depth’s rowbytes…which seems to be quite erratic!

Generic INIT loading mechanism

It’s not yet perfect, but the environment bootstrapping will now iterate system extensions, extensions and control panels to try to load any INIT resources from them. This should allow loading extensions and control panels at boot time by just placing them into the System Folder, instead of the hard-coded the INIT loading that was there previously. This should help and speed up testing various extensions and control panels quite nicely. The ‘sysz’ resource handling seems to work okay’ish, but is not perfect yet (that is, the mechanism that allows INITs to expand system zone at startup time to reserve enough space for their possible needs, without risking of running out of system zone space later when running the emulation).

There’s also a number of other fixes, most being too small to go into great detail, such as:

  • Implemented csCode 23 for native FS driver, which fixes Finder not displaying sensible drive type for emulated file system
  • sfIsFolder & sfIsVolume was not set up properly, causing ResEdit to try to open folders as files (*sigh*)
  • Modify EnvGetNextEventDelayHack to allow specifying delay value with the configuration value
  • Added default label colors to System file
  • Clean up a lot the messy project structure, most importantly by moving toolbox emulation code from getting compiled for each test target to a single library being linked to them. This speeds up the compilation roughly 100x times 😀 (one important step in getting the spaghetti code closer to presentable shape, in hope of opening the source someday in future)

Hopefully by summer we’ll have more news for you.

Full list of changes since last post

2025-12-24 22:59:54 +0200 • Add TCP control call codes to MacTCP driver header
2025-12-24 22:58:06 +0200 • Add Welltris test app config
2025-11-08 22:41:08 +0200 • Fix resource file cleanup referencing freed memory
2025-11-08 18:40:44 +0200 • Also throttle OSEvents w/ EnvGetNextEventDelayHack
2025-11-08 00:44:10 +0200 • Set correctly sfIsFolder & sfIsVolume in StdFile
2025-11-08 00:01:34 +0200 • Use label colors for icons in StdFile dialog lists
2025-11-08 00:00:55 +0200 • Add label colors to System file
2025-11-07 23:04:32 +0200 • Implement PBRename/HRename for NativeFS & ADF
2025-11-07 03:07:14 +0200 • Fix dirBkDat byte-swap size bug in Get/SetCatInfo
2025-11-05 23:05:17 +0200 • Write adfRealName to ADF Header, fix root name bug
2025-11-05 23:02:47 +0200 • Throttle Railroad Tycoon to make it more playable
2025-10-30 02:02:27 +0200 • Add EnvRealExitToShell to test with setjmp/longjmp
2025-10-30 01:58:43 +0200 • More old test code cleanup (from startup routines)
2025-10-30 00:43:26 +0200 • Add dummy ShutDwnPower and ShutDwnStart (for exit)
2025-10-29 00:25:52 +0200 • Clean up extra mess from repository
2025-10-28 01:21:59 +0200 • Make ScreenRow low mem global more compatible
2025-10-27 12:05:41 +0200 • Configs for Titan Color, Warlords, Warlords Demo
2025-10-26 23:31:25 +0200 • Config for Titan, Carmen, Mouse Stampede & MacBugs
2025-10-26 06:55:24 +0200 • Add Sargon 3 and Wizard's Fire test app configs
2025-10-26 06:54:50 +0200 • Make reset opcode exit emulator properly in PT-109
2025-10-26 06:54:16 +0200 • Remove old RunEmulation test code from 6 years ago
2025-10-25 19:16:36 +0300 • Cleanup mess - refactor MaceEmuSDL to SDLPlatform
2025-10-25 13:35:02 +0300 • Make GetNextEventDelayHack delay adjustable
2025-10-13 01:30:55 +0300 • Implement truncMiddle TruncText/TruncString case
2025-10-11 23:42:01 +0300 • Implement NativeFS csCode 23 (drive info)
2025-10-11 23:41:37 +0300 • Tweak MIDI driver port names
2025-10-10 23:50:24 +0300 • Update Geneva font to System 6 compatible version
2025-09-29 10:48:29 +0300 • Fix 'qdrw' gestalt response for classic mode
2025-09-29 01:54:41 +0300 • Use TruncString for long menu names in MDEF ID=0
2025-09-29 01:53:47 +0300 • Implement truncEnd case of TruncText & TruncString
2025-09-08 00:45:36 +0300 • Fix bug in reading abbrevation tables from 'itl1's
2025-09-08 00:11:42 +0300 • Fix typo
2025-09-08 00:09:50 +0300 • Proper IUTimeString/IUtimePString implementation
2025-09-08 00:09:02 +0300 • Fix longDate/abbrevDate mixup
2025-09-07 00:08:07 +0300 • Also implement long form (ext&abbrev) IUDateString
2025-09-06 14:04:28 +0300 • Implement short form IUDateString
2025-09-03 11:29:23 +0300 • Implement SndChannelStatus (no disk playback yet)
2025-08-26 23:28:31 +0300 • Make CDResolveCodeResource errors more verbose
2025-08-26 23:27:39 +0300 • NotificationManager globals init (for Afterk Dark)
2025-08-26 23:25:10 +0300 • Byteswap ADF fileinfo flags properly
2025-08-26 23:24:28 +0300 • Icons for Carmen, MacBugs, Mouse Stampede & Titan
2025-08-15 01:47:30 +0300 • Fix the FramePoly glitching
2025-08-10 20:41:30 +0300 • Fix fullscreen glitches (added SDL_RenderClear)
2025-07-30 13:10:12 +0300 • Hack to SDL code to prevent mouse warping bug
2025-07-25 14:29:37 +0300 • Fix settings failure w/ USESIGNING off in CMake
2025-07-25 14:28:18 +0300 • Add more DAs for testing
2025-07-25 14:11:48 +0300 • Handle error if loading settings file fails
2025-07-21 15:49:01 +0300 • Implement ArithAddMin rect blitter (for AfterDark)
2025-07-21 02:02:47 +0300 • Fix typo in AngleFromSlope fix
2025-07-20 23:37:55 +0300 • Start separating toolbox emulation to a sublibrary
2025-07-20 20:58:26 +0300 • Fix another 32-bit block tag ptr bug in MMPurge32
2025-07-20 14:19:50 +0300 • Fix MMMakeSpaceForPtr32 bug using wrong tag byte
2025-07-20 14:08:34 +0300 • Fix low AngleFromSlope slope breaking on release
2025-07-20 03:19:58 +0300 • Fixes to INIT file iteration
2025-07-20 03:18:39 +0300 • Add dummy PtInIconID selector for IconUtils
2025-07-20 02:08:10 +0300 • Support for kD0DispatchedPascalStackBased patches
2025-07-19 16:48:14 +0300 • Proto of generic (ie not hard-coded) INIT loading

Summer ’25 Update

This last year has been extremely busy with real-life things, so there’s been very little time to work on the emulator. During the winter and summer breaks we did have bit of time to work on some things, and there’s a couple important changes that might be of interest for you – so here’s a brief breakdown of the most important things that’ve been updated:

File deletion support

This has been one of the long-time tasks that’s been on the backlog, and has been causing issues with at least a number of test applications, which expect file deletion to work and would fail in random ways when this still was not implemented (this includes games such as Might & Magic 3, Dungeon of Doom, and others). This feature was delayed for a long time as it not only involves deleting the pair of AppleDouble header/data file pairs, but also maintaining the in-memory AVL tree presentation of the file system in stable state – which have now been implemented, at least in basic form, and the aforementioned applications now work much better

Dynamic configuration

One of most important changes for this year has been adding finally support for dynamic configuration of runtime, which means that emulated machine type and features can be configured using mace.settings file (located in the Resources folder within the app bundle), and a set of predefined machine profiles. Here’s brief breakdown of all configuration settings that are implemented:

Profile selection:

EnvProfile: Select the machine profile. Current predefined profiles are:
- mace_plus_4mb_sys607.profile: The default Mac Plus-like environment, with 4 megabytes of RAM and reports System version as 6.0.7
- mace_plus_4mb_sys700.profile: Same as previous profile, but reports System version as 7.0.0
- mace_se_4mb_sys700.profile: Same as previous, but instead of Mac Plus identifies as Mac SE. This profile should be used with THINK Pascal 4.x, as MACE trap tables always in the format of SE/II and later models (Long story short, Mac Plus had different trap table layout, which THINK Pascal would expect when it identified that model, and it would lead to conflict) 
- mace_68020_8mb_sys700_24bit.profile: 24-bit 68020 Mac II with 8 megabytes of RAM and reports System version as 7.0.0
- mace_68030_32mb_sys755_32bit.profile: 24-bit 68030 Mac II with 32 megabytes of RAM, 32-bit memory manager eanbled, and reports System version as 7.5.5
- mace_68040_32mb_sys755_32bit.profile: Same as previous, but with 68040 CPU emulation level

Application settings:

EnvStartupWorkingDirectory: Choose startup directory within the emulated file system
EnvStartupFile: Choose which file will be LAUNCHed at emulator startup
EnvAppName: Default application display name (for bundled applications)

(Note that any non-ASCII custom characters in the filenames should be escaped using \xNN format, where NN is the MacRoman code for the character)

Additional configuration settings (for mace.settings):

EnvUseRelativeMouse: Set this to 1 to use relative mouse mode instead of absolute (use for games that alter mouse position, such as Apache strike or Wolfenstein 3D, or for games that hide mouse pointer and use it for input, such as Dark Castle). NOTE: There's a weird glitch from combination of the most recent macOS versions, the version of SDL2 we're using, and the software cursor obscuring code, which cause cursor sometimes jumping to screen center when this mode is enabled
EnvDisableDeskAccessories: Disable desk accessories
EnvClassicSoundPhaseShift: Alter the default .Sound DRVR output phase, set this to -1 (minus one) for Dark Castle for audio to work properly
EnvGetNextEventDelayHack: Set this to 1 for old games that run too fast (such as Stunt Copter)
EnvDefaultColorDepth: Set bit depth of the color video device
EnvVideoScreenWidth: Set width of the color video device
EnvVideoScreenHeight: Set height of the color video device

IMPORTANT NOTE: If you set the combined framebuffer size of color video (that is, width times height times bit depth of screen) to larger than 1 megabyte, it will only work if a 32-bit machine profile is used! This is as currently we only support fixed memory modes set at startup time, and on real macs in 24-bit mode the machine would transparently do MMU switching between 32- and 24-bit modes for screen accesses, something we don’t support yet!

The machine profile settings can be overridden from mace.settings, but changing most of the other default profile settings is not recommended as they will likely lead to non-functional environment.

Below are two screenshots highlighting effect of changing active machine profile within the same environment:

New experimental CDN for demo application bundle builds

The old versions of demo applications haven’t been updated for a long time, but this year we wanted to get you a bit more recent version of the emulator to try out. However, there’s some challenges as our Apple Developer program ran out, so we don’t have signed binaries available, and we don’t have at moment a working Windows machine so we also don’t have windows versions available. HOWEVER, we did build ARM64 (unsigned) versions of both the existing demo applications, and we also created bundles for a number of new apps to try out, including a number of color games such as KYE, and demo version of Civilization and Eric’s Ultimate Solitaire Sampler, and a few others. Head over to the “Downloads” section using the link at top of the page to try them out! We also moved the files to a dedicated low-cost CDN, so WordPress should no longer mess up and randomly delete the ZIP files like in the past.

Please note that as they’re unsigned, you’ll have to at first launch choose “Done” instead of “Move to Bin” to not delete the application, and then go to System Settings -> Privacy & Security -> Security and choose “Open Anyway” to force macOS to open the demo apps. This is as we didn’t want to spend this year another $100 on Apple’s Developer Program as we have other expenses we need to cover. We’ll make the signed binaries again available someday in future, once we have chance to get back working on the emulator with more time.

Other minor fixes

There’s also some other minor fixes, such as:

  • Fixes to 16-bit (“thousands of colors”) support for color quickdraw, which had still issues in the direct mode blitting, most notable drawing of mouse cursor. This seems to work now well enough so that Marathon is able to run in this mode. However, as gamma tables are not yet implemented, the gamma fades used by games to do fade-to-black effects do not yet work. This should be however a trivial feature to implement in future. There’s also foundation for 32-bit (“millions of colors”) mode, but most of blitters are still unimplemented so it’s not usable yet.
  • cscSetGray control code support for color video DRVR. This allows setting the screen to monochrome mode for indexed display modes, allowing you to relive the fun memories of having a 16-grayscale monochrome displays 🙂
  • Fix PutScrap to not keep incrementing the LMScrapSize value. This caused ResEdit to quickly run out of memory especially in color mode
  • Fix UpdateGWorld to not reference old GWorld (this bug surfaced when we experimented color depth switching within Marathon)
  • Other minor fixes

Some screenshots of the grayscale mode

Hopefully we’ll have again more to show you guys in the winter. We also have had the AppleDoubler tool ready for a long time, which would speed up a lot converting native files to the ADF format used by the emulator, but sadly haven’t had time to polish and publish it properly. But we’ll definitely get over to doing it around December/Christmas break.

Full list of changes since last post

2025-07-19 02:01:43 +0300 • Add EnvClassicSoundPhaseShift to dynamic settings 
2025-07-19 00:40:38 +0300 • Update version number                             
2025-07-19 00:39:42 +0300 • Fix setup of csMode from gdFlags in InitGDevice   
2025-07-18 16:26:20 +0300 • Implement cscSetGray for the color video DRVR     
2025-06-30 03:37:05 +0300 • Fix reference to old GWorld in UpdateGWorld exit  
2025-06-30 03:23:59 +0300 • Add 32-bit graphics output blitter to SDL module  
2025-06-30 03:02:56 +0300 • Better divsul overflow fix (takes size into cons..
2025-06-30 02:30:25 +0300 • Fix compilation errors in mdb and mpr             
2025-06-30 02:26:00 +0300 • Update trap list source                           
2025-06-30 02:25:25 +0300 • Fix negative integer overflow in divsul           
2025-06-30 02:24:24 +0300 • Fix nested sourceDevice declaration               
2025-06-29 23:13:34 +0300 • Hack CMakeLists.txt to work with new CMake version
2025-06-29 23:12:57 +0300 • Fix 32-bit ROM resource zone corruption bug       
2025-06-29 23:12:19 +0300 • Make screen size configurable in mace.settings    
2025-06-29 23:11:31 +0300 • Fix incorrect color depth in a number of test apps
2025-03-14 23:06:39 +0200 • Fix inverted cursor drawing glitch in direct mode 
2025-03-14 11:18:47 +0200 • CRT filter for 16-bit mode                        
2025-03-09 02:17:32 +0200 • Fix PutScrap setting invalid LMScrapSize value    
2025-01-15 23:05:10 +0200 • Support GetNextEventDelayHack in dynamic settings 
2025-01-15 14:03:01 +0200 • Minor fixes to Fool's Errand app configuration    
2025-01-13 01:27:56 +0200 • Fix F/A-18 Hornet test app filename in settings   
2025-01-13 00:04:43 +0200 • Fix setup of 32-bit mode memory pages             
2025-01-12 22:32:59 +0200 • Handle escaped hex values in configuration strings
2025-01-12 01:53:17 +0200 • Fix NewAlias stub to return a dummy Alias Handle  
2025-01-12 00:43:20 +0200 • Relocate trap generator to its own sub folder     
2025-01-12 00:42:50 +0200 • First implementation of dynamic settings system   
2025-01-05 03:21:29 +0200 • Remove old backup of trap list source file        
2025-01-04 02:28:52 +0200 • Work on refactoring configs to dynamic settings   
2025-01-02 19:38:26 +0200 • Implement basic file deletion (logical & physical)
2024-11-03 21:30:22 +0200 • Partial RestoreEntries implementation             
2024-10-23 13:32:06 +0300 • Add missing std file dialog 'dctb' color tables   
2024-10-23 13:31:29 +0300 • Add Ares Demo test app config                     
2024-08-14 11:20:20 +0300 • Save regs on CallComponentFunction & debug cleanup

Summer ’24 Update – Component & MIDI Manager news

It’s been a while since previous update, as life has been really busy during the past year. Sadly progress has been slow because of lack of time, but we do have some exciting news to share though for this year. Let’s dig in…

Enchanted Scepters

On Emaculation forums, one member asked us whether Enchanted Scepters was compatible with MACE. As we do have both 24-bit (and recently also 32-bit) addressing support, the original version of the game not being 32-bit clean was not an issue, but we ran into other interesting feature in the World Builder engine…when calling HandToHand to duplicate handle, we did return error code in D0, and resulting handle in A0 as specified by Apple documentation…HOWEVER, the original apple routine also does TST.W D0 before returning, so the zero flag is set to indicate the error state already at that state…Enhanced scepters expected this flag to be set by the time HandToHand returned, and of course we did not do this explicit testing of D0 register, and thus it crashed and burned with SysError 10. After adding a manual TSTW_D0 glue call at end of the trap (and a bunch of other traps returning value in Dn register), Enhanced Scepters seems to be mostly co-operating:

Enchanted Scepters

There’s still a bit weirdness with the custom WDEF it’s using, but we haven’t looked more into that yet.

Larger than 1mb slot space in 32-bit mode

As we did last year add the 32-bit addressing mode support to memory manager, we were finally able to experiment with taking advantage of this increased space, and added support for slot video devices to go beyond the 1MB slot device memory window limitation, which allows us to now use (almost) arbitrarily large display resolutions, that were previously limited to roughly 640×480 at thousands of colors, or 1024×768 at 256 colors. So…what better way to test this, than running SimCity 2000 in Full HD resolution:

SimCity 2000 running in Full HD resolution in full-screen mode

16-bit QuickDraw direct mode improvements

As some people might know, the original Marathon was recently released by Aleph One team for free on Steam, and partially inspired by this, we decided to work a bit on the direct color mode support of MACE, to allow running original Marathon in those higher depth modes. We previously already did have Marathon running in the usual, indexed 256-color mode, but there was a bunch of stuff missing or broken that needed to be implemented:

  • SetDepth needed to also accept color depth in addition to device modes
  • Cursor blitters and color table expansion did not yet work properly in direct modes
  • Device type of GDevices was set up incorrectly
  • Some blitters were unimplemented (i.e. colorizing BitBlt)
  • A bunch of blitters had byteswap bugs, that did not surface earlier, as indexed modes were never using more than 8 bits per pixel
  • 16-bit bitmap to pixmap expansion was missing
  • hilite draw modes were not rendering correctly as they did not expect data to be 16 or more bits per pixel
  • Some pattern drawing modes were not applying background/foreground color properly, as in direct modes black&white are reversed when compared to indexed modes, and this was not taken into account (in indexed modes, black is always last, white first, while in direct modes black is first, as its RGB value is zero, and white is last, as it’s either 7FFF or 00FFFFFF)

Here’s some before & after shots of Marathon main menu taken during this development process:

And here’s pic of the ingame dithering being inverted and font rendering still being broken:

Marathon “quit game” confirm dialog before the 16-bit color support fixes

Here’s also pics of the settings screen, before and after fixing the byteswap bug of 16-bit BitBlt:

Also, some pics of “Get File” dialog before & after fixes (also includes PICT 2 fixes, which will follow up):

PICT 2 recording improvements

As part of Marathon fixes, we also ended up digging into improving the previously broken PICT version 2 recording implementation. As the original PICT recording was specifically implemented with “classic”, non-color QuickDraw in mind that uses 1-byte opcodes, a lot of QD routines did not support saving the opcodes in the 2-byte format used by PICT version 2. Marathon uses this specifically for drawing a preview of the current map location, saving that in the savegame file, and using it to display preview in the Open/Get File dialog. Fixing this involved going through all the recording routines, and modifying it to use PICT version-independent code. This also has nice benefit that it made ResEdit DLOG/WIND previews also work now in color mode:

ResEdit DLOG preview works now in color modes too

AND also, this seems to have fixed the previously crashing Civilization 2 city screen, which uses PICT 2 recording somewhere in it:

Civilization 2 city screen no longer crashes

Sadly all recording are not yet fully supported, as StdBits is still missing some cases, and that causes at least ResEdit trying to display preview of windows that have goaway/zoom boxes, which are PixMaps, to fail to record/play back properly.

MAJOR FEATURE: Component Manager first steps

One other important milestone feature has also been support for Component Manager, which has now been partially implemented enough to allow Internet Config component extension to register, and the Internet Config application to load up and use the registered component mostly okay:

In case there’s somebody reading this, who does not remember what Internet Config was used for, it was the tool used to configure practically any internet-related settings in the old MacOS, offering through Component Manager a unified API for any applications to share & use these settings, co-exist and co-operate together. It consists of two main parts:

  • Internet Config Extension – This is actually not a traditional extension, which would contain ‘INIT’ code, but a component of type ‘thng’. Component Manager loads all these components during system startup, and registers them to be used by any applications which might rely on them
  • Internet Config Application – This is the UI for configuring the Internet Config settings, and it uses Component Manager to discover and connect to the Internet Config ‘ICAp’ component

Internet Config was a great test case for this, as it has very precise set of Component Manager features it uses, and does not depend on too many other features of the system, which we might not yet have implemented. There’s still dependency on file deletion which causes the saving of settings to fail, but we’ll eventually get that implemented and it should not be a major issue.

Originally Component Manager was developed for QuickTime, to support loading various video/audio codecs, but another major use case for it is Sound Manager 3.x – which is actually the major motivation for us to work on supporting components, as we hope to make our Sound Manager 3.x implementation follow the Sound Components design as closely as possible, which in turn relies on having Component Manager available to abstract all the mixers, hardware devices, compressors/decompressors etc in an universal pipeline.

Resource Manager fixes & ResEdit CODE editor

Just as a filler, we also wanted to get the famous ResEdit ‘CODE’ editor to work in MACE, as it allows disassembling any 68k code using the ResEdit itself. Interestingly almost everything needed to do this was implemented fine, but we had to implement SetResPurge trap (and default purge procedure), and also found a bug in reallocation or purged compressed resources by happy accident. Here’s pic of the CODE editor in action:

ResEdit ‘CODE’ Editor

AppleDoubler UTF-8 denormalization

Also on the side, we noticed that at some point the UTF-8 to MacRoman encoding in AppleDoubler tool had broken because of way UTF-8 can be present same file names both in normalized and denormalized formats, and we only supported denormalized UTF-8. As our current macOS host system gave us normalized file names, we added denormalization for all characters that are part of the MacRoman character set, and after that we were happily able to convert exotic names such as Déjà Vu II’s folder name into AppleDouble:

Déjà Vu II folder name denormalized & converted to MacRoman properly

Font/DA Mover

We already have had support for Desk Accessories for quite a while now, but until now we did all testing & adding those to the System file by manually copying the resources of those DAs. When we were working on the MIDI Manager support (news of which will follow up after this), we wanted to also add PatchBay DA to the System file, but decided to try for fun, how well would Apple’s Font/DA Mover work in MACE? Well…

Font/DA Mover

…the answer is: It worked just perfectly out of the box! We were able to manipulate both existing and new DAs from DA suitcases just fine, and the tool was happy to install PatchBay into our completely custom System file without any issues!

MIDI Manager implementation

And now to one of the coolest features we did do for this update: We had already been planning about experimenting with adding support for Apple MIDI Manager interface (which actually works using SoundDispatch with tool number 4), but we didn’t really get into this until this summer. One major breakthrough was finding finally the very elusive set of MIDI Manager documentation, which nowdays appears to be only found in Apple DocViewer format:

Apple DocViewer showing MIDI Manager SDK documentation

(The Palatino font above is a bit weird, as by design bitmap fonts default to half- or double-size versions if exact fit is not found, which in this case was the double-size one. Normally when viewing this font in this size in System 7 you’d get a way smoother look thanks to TrueType rendering, which we don’t support…yet!)

It took a couple weeks of work during the summer, but we finally got enough of MIDI Manager API implemented to allow both PatchBay to happily show our custom MIDI driver, load up MIDI Jukebox, and make connections between the driver and the application:

MIDI Jukebox and PatchBay in MACE

BUT what was even cooler, was the fact that thanks to MIDI packet format being universal, we eventually had very little to do to allow passing all the MIDI packets from MIDI Jukebox, through our custom driver, to the host system using CoreMIDI. And as we were able to hook actual MIDI Hardware, which in our case was M-Audio USB MIDI Adapter, and an original Roland SoundCanvas SC-55MkII, we got this nice recording of playing MIDI files in MIDI Jukebox in MACE through the real, physical hardware synthesizer:

The mouse cursor is a bit laggy in this capture, as we ran this whole non-stop one hour session in debug mode in Xcode, which is really slow even on a Mac Studio. We still need to work on the Time port timers, as randomly they don’t start up properly, instead stalling up the whole port. But once you get the timer running, it seems to work stable for a long time!

The very original motivation was to support native MIDI playback in Space Quest 1 remake, which does take advantage of Apple MIDI Manager:

Space Quest 1 using MIDI Manager, as seen in PatchBay

Sadly Space Quest 1 expects the sound module to be a MT-32, and we couldn’t figure out how to get SC-55mkII into MT-32 emulation mode, so the music in that game does not sound very great, and we didn’t take capture of it. Plus there’s also something missing from other part of emulation, as the game never proceeds from the intro screen, but stays there playing happily the music without allowing player to skip forward.

Also, thanks to PatchBay DA, which also uses the rarely used Desk Accessory feature of having its own menu in applications menu bar, we finally had a test case for SystemMenu trap, which was implemented!

Bonus: Some Havoc screenshots

Here’s also some screenshots of Havoc running on MACE…we wanted to just check if the game would try to use any QuickDraw 3D routines (as it’s supposedly one of the few QD3D compatible games), but apparently it’s happy to do everything in software 3D and actually runs pretty well, so…here’s how it looks like:

That’s all for now…we don’t know when the next update will be, as life’s going to get just more busy…but rest assured, work on MACE will continue. We’ll…be…back!

Full list of changes since last post

2024-08-12 02:03:18 +0300 • Fix MIDI timer drift (hook to time manager global)
2024-08-11 03:49:44 +0300 • Fix disabled MIDI debug message compile warnings
2024-08-11 03:49:04 +0300 • Quick hack to connect host CoreMIDI to MIDI Driver
2024-08-11 03:27:59 +0300 • Readhook implementation and packet dequeueing
2024-08-10 19:51:39 +0300 • Update MIDI time ports from the MIDI timer handler
2024-08-10 19:49:52 +0300 • Start MIDI driver clock
2024-08-10 01:25:43 +0300 • First proto of MIDIWritePacket implementation
2024-08-06 00:25:08 +0300 • Work on MIDIWritePacket (packet alloc & dealloc)
2024-07-29 19:38:05 +0300 • Implement MIDI time conversion for formats 0 to 5
2024-07-29 17:55:46 +0300 • Implement MIDIGetCurTime for MIDI Manager
2024-07-29 16:13:56 +0300 • Fix MIDI driver signature & data port directions
2024-07-29 16:13:22 +0300 • Partial implementation of MIDIConnectData
2024-07-29 14:50:11 +0300 • Implement MIDIGetPortName and MIDISetSync
2024-07-29 14:36:33 +0300 • Add temporary (quick hack) ports to MIDI driver
2024-07-29 14:35:27 +0300 • Implement MIDIGetPortInfo for MIDI Manager
2024-07-29 14:34:41 +0300 • Fix invalid port ID bug in MIDIGetPorts
2024-07-29 14:00:23 +0300 • Fixes to global MIDI port indexing
2024-07-29 13:28:38 +0300 • Partial stub of MIDIConnectTime implementation
2024-07-29 00:25:24 +0300 • Partial stub of MIDISetCurTime implementation
2024-07-28 10:40:26 +0300 • Tweak type of Get/SetSR in M68kHelper
2024-07-28 02:22:48 +0300 • Link CoreMIDI on macOS targets
2024-07-28 02:22:39 +0300 • Implement MIDIStartTimer for MIDI Manager
2024-07-28 02:15:41 +0300 • Part of MIDIAddPort implementation
2024-07-26 15:53:05 +0300 • Test code to dump list of host CoreMIDI devices
2024-07-26 01:43:54 +0300 • Fix MIDI Manager version number
2024-07-25 00:59:39 +0300 • Implement SystemMenu trap (for PatchBay DA)
2024-07-25 00:45:18 +0300 • Implement MIDISignOut (partially) for MIDI Manager
2024-07-24 16:45:48 +0300 • Add dummy DILoad stub for Font/DA Mover to work
2024-07-24 04:35:59 +0300 • Implement MIDIGetClientName for MIDI Manager
2024-07-24 04:26:11 +0300 • Implement MIDIGetPorts for MIDI Manager
2024-07-24 04:07:04 +0300 • Implement MIDIGetClientIcon for MIDI Manager
2024-07-24 04:01:47 +0300 • Implement MIDIGetClients for MIDI Manager
2024-07-24 04:01:32 +0300 • Implement MIDIWorldChanged for MIDI Manager
2024-07-24 03:53:18 +0300 • First MIDISignIn implementation test pass
2024-07-23 18:13:04 +0300 • A bit of work on MIDISignIn (checks for duplicate)
2024-07-23 18:12:09 +0300 • Call MIDI sign-in from the MIDI driver
2024-07-23 18:11:46 +0300 • Add MIDIDriverSignIn alternate MIDISignIn selector
2024-07-20 04:48:30 +0300 • Fix stack mismatch icon transformed SICN rendering
2024-07-17 21:48:21 +0300 • Add Deja Vu 2 test application configuration
2024-07-17 20:59:06 +0300 • Implement utf8 denormalization in AppleDoubler
2024-07-17 07:00:12 +0300 • Fix reallocation of purged compressed resources
2024-07-17 05:40:17 +0300 • Implement SetResPurge
2024-06-08 17:56:50 +0300 • Fix 32-bit memory manager free space debug checker
2024-06-08 17:56:23 +0300 • Add missing AppleEvent header additions
2024-06-08 02:30:42 +0300 • Merge branch 'master' of
2024-06-08 02:30:24 +0300 • Fake sound manager gestalt
2024-06-08 02:22:10 +0300 • Add dummy stub for AEPutKeyPtr AppleEvent selector
2024-06-08 02:18:11 +0300 • Add dummy stub Pack8 AECreateAppleEvent selector
2024-06-07 22:31:04 +0300 • Fix color graying out crashes in popupmenu CDEF 63
2024-06-07 22:13:23 +0300 • Dummy stub for IconSuiteToRgn icon utils selector
2024-06-07 21:52:27 +0300 • Fix calculation of offsets in thing ID validation
2024-06-07 21:51:03 +0300 • Fix incorrect size of component open file table
2024-06-07 13:35:25 +0300 • Implement OpenDefaultComponent
2024-06-07 13:35:03 +0300 • Implement FindNextComponent
2024-06-07 13:34:48 +0300 • Fixes to & cleanup in RegisterComponent
2024-06-07 13:26:14 +0300 • Fix comp head byteswap bug in RegisterComponent
2024-06-07 02:40:10 +0300 • Fix CallComponent Delegate fallback case stack bug
2024-06-07 02:11:51 +0300 • Add dummy stub for FlushCacheRange in HWPriv
2024-06-07 02:04:45 +0300 • Fix stack mismatch in component parameters cleanup
2024-06-07 02:04:14 +0300 • Implement DelegateComponentCall (simple case)
2024-06-07 00:33:58 +0300 • Fix component & instance index/pointer conversion
2024-06-05 23:25:27 +0300 • Minor component bug fixes
2024-06-05 23:20:40 +0300 • Implement Set/GetComponentInstanceStorage
2024-06-05 23:19:28 +0300 • Implement CallComponentFunction
2024-06-05 23:18:59 +0300 • First proto of OpenComponent & open component call
2024-06-05 14:30:23 +0300 • LoadComponent partial implementation (in sys zone)
2024-06-05 14:08:51 +0300 • Implement CloseComponentResFile
2024-06-05 13:55:45 +0300 • Implement OpenComponentResFile
2024-06-05 13:54:56 +0300 • Fix resolving file of registered components
2024-06-05 11:52:17 +0300 • Component validation added, start work on loading
2024-06-05 00:22:56 +0300 • Work on open/close/register/unregister comp calls
2024-06-04 01:08:59 +0300 • Use UPPs in CallComponent instead of a 68k callsub
2024-06-03 16:15:53 +0300 • ComponentDispatch refactor & proto CallComponent
2024-06-03 16:13:44 +0300 • Use opcode enum in ClosePicture, not hard-coded FF
2024-05-27 18:39:38 +0300 • Implement GrafDevice trap
2024-05-18 15:18:11 +0300 • Fix screen dirty area tracker overflow
2024-05-18 14:10:08 +0300 • Fix StdFile dialog visibility failsafe not working
2024-05-18 02:57:42 +0300 • Fix byteswap size in PICT v2 padding
2024-05-18 02:37:27 +0300 • Merge branch 'master' of
2024-05-18 02:37:16 +0300 • Fix padding of PICT v2 data when recording opcodes
2024-05-18 02:30:22 +0300 • Fix srcOr mode for 16-bit region blitters
2024-05-18 02:30:06 +0300 • Fix or & bic modes for 16-bit rectangle blitters
2024-05-17 16:33:49 +0300 • Fix colorization of srcOr & srcBic in direct modes
2024-05-17 02:26:57 +0300 • Merge branch 'master' of
2024-05-17 02:26:54 +0300 • Disable debug zone dump for MoveHHi
2024-05-17 02:05:25 +0300 • Fix zcbFree after MoveHHi to below min size target
2024-05-15 03:25:46 +0300 • Fix cast warnings for reading shifted pattern data
2024-05-15 01:41:36 +0300 • Fix hilite drawing mode to work in 16-bit colors
2024-05-15 00:59:58 +0300 • 1-to-16bit monochrome pixel expansion routine
2024-05-15 00:59:11 +0300 • Major work on version 2 PICT recording support
2024-05-13 16:02:35 +0300 • Fix byteswap bug causing 16bit color mode glitches
2024-05-13 14:51:33 +0300 • Add colorizing block blitter srcCopy mode
2024-05-13 12:26:06 +0300 • Fix wrong gdType in InitGDevice after SetDepth
2024-05-13 11:45:10 +0300 • Support blitting cursor in direct modes properly
2024-05-13 03:02:13 +0300 • Make QDScaleMask16 work with 16-bit cursor data
2024-05-13 01:32:11 +0300 • Tweak GetCTable to pass through 16-bit case
2024-05-13 01:18:21 +0300 • Fix SetDepth to also accept mode as depth argument
2023-12-25 04:31:05 +0200 • Add SimCity Classic and Duke 3D 68k Demo test apps
2023-12-10 23:19:19 +0200 • Enable >1mb slot space for slot devices in 32-bi..
2023-12-10 23:13:30 +0200 • Fix 32-bit heap compaction
2023-11-27 19:31:59 +0200 • Fix MIDIWorldChanged signature
2023-11-24 15:08:05 +0200 • Add dummy MIDIWorldChanged stub for SoundDispatch
2023-11-24 14:57:28 +0200 • Merge branch 'master' of
2023-11-24 14:57:21 +0200 • Work on Component Manager call dispatcher
2023-11-24 04:06:23 +0200 • Add Enchanted Scepters test app JSON config
2023-11-24 04:05:54 +0200 • Reinforce unsigned selStart/selEnd in TextEdit
2023-11-24 04:03:47 +0200 • Do explicit TSTW_D0 to update flags in HandToHand
2023-11-24 04:02:49 +0200 • Do a explicit TSTW_Dn on traps that return Dn
2023-11-13 00:47:13 +0200 • Implement FSpOpenRF for HighLevelFSDispatch
2023-11-13 00:44:25 +0200 • Start work on CopyDeepMask
2023-10-21 14:04:37 +0300 • Fix far-right edge ShieldCursor bug in classic QD
2023-10-21 14:03:05 +0300 • Update OSX icns files
2023-10-21 14:02:29 +0300 • Add Shadowgate to test apps list

TextEdit update: first styled text features added

The progress has been a bit slow in the last month because of us being extra busy at our regular daytime jobs, but we did manage to squeeze some long-awaited changes in. We finally started the work on multistyled textedit support, which is extension added to TextEdit API around System 6.0.4, allowing more than a single style to be applied within text edit records.

As we did not have much time to work on this yet during November, we only have so far roughly these features implemented for style support:

  • Multistyled TE record creation using TEStyleNew
  • Partial setting of appending multistyled text using TEStyleInsert
  • Adjusting existing styles using TESetStyle
  • Drawing multistyled text within the TEDoText’s teDraw selector
  • Measuring multistyled text

And the following style properties can be used within the styles:

  • Style font family
  • Text face (bold, italic, underline, etc…)
  • Font size
  • Text color

From the test applications we have been running, the most important ones requiring styled textedit support have been HyperCard 2.x and Marathon. Below is screenshot of HyperCard 2.0 Home stack, with multistyled text showing right on the welcome screen:

HyperCard 2.0 Home stack with multistyled text

And even more importantly, Marathon terminals can now be opened and operated, which means that we can finally proceed forward in Marathon gameplay to the other levels beyond the first one:

Marathon’s terminal view, with multistyled textedit field used for the text rendering

However, there are still some missing features, of which we need add these most important ones next:

  • Finalize TEStyleInsert to handle given StScrpHandle data properly
  • Implement other multistyle TEDoText selectors, such as teFind and teCaret, to allow actual styled text editing
  • Merge identical adjacent styles after style adjust operations, to avoid excessive style run array growth
  • Add other missing selectors to TEDispatch where needed
  • Also implement any other missing toolbox calls used by textedit where needed

With current speed of progress, the most important ones of the remaining parts textedit API should be usable within a couple of weeks. Unless we get too distracted by playing Marathon 🙂

Full list of changes since last post

2020-11-29 23:52:29 +0200 • Added PortChanged (no-op) selector in QDExtensions
2020-11-29 23:27:24 +0200 • Add JSON cmake config for HyperCard 2.2 test app
2020-11-29 23:26:55 +0200 • Add no-op dummy InitDateCache ScriptUtil selector
2020-11-29 23:22:50 +0200 • Implement partially ScriptUtil's SetEnvirons
2020-11-28 04:47:13 +0200 • Fix clamping of negative offset in TEPinScroll
2020-11-28 04:46:09 +0200 • Fix clamping of below bottom in pt-to-line routine
2020-11-28 03:48:03 +0200 • Implement TEGetPoint selector for TEDispatch
2020-11-27 01:30:49 +0200 • Handle styled text in TEDispose
2020-11-27 00:52:53 +0200 • Refactor TE locals, don't cache dereferenced hTE
2020-11-26 05:38:32 +0200 • Other fixes to make TESetStyle to work & add debug
2020-11-26 05:33:34 +0200 • Get correct style run idx for singlebyte edge case
2020-11-26 05:31:53 +0200 • Fix lineheight calc (wrong index & zero new slots)
2020-11-26 05:28:27 +0200 • Add missing TEApplyStyle byteswap (run->startChar)
2020-11-26 05:27:33 +0200 • Return correct style index @ existing style lookup
2020-11-26 05:26:30 +0200 • Set stCount, stHeight and stAscent for new styles
2020-11-26 05:25:31 +0200 • Add viewRect validation to TEDoText (debug mode)
2020-11-26 05:24:38 +0200 • Set stCount to 1 when inserting a new style
2020-11-26 05:23:52 +0200 • Re-deref TEHandle in TEStyleNew after hText alloc
2020-11-26 05:22:51 +0200 • Increment text pointer in TEFindLine for new style
2020-11-26 05:19:32 +0200 • Fix byteswap in numerator check in StdText
2020-11-25 04:28:32 +0200 • Work on TESetStyle (not yet working, but almost)
2020-11-23 03:24:16 +0200 • Start work on TESetStyle (and TEContinuousStyle)
2020-11-22 05:15:36 +0200 • Add style support to TEGetLineForV
2020-11-22 04:47:30 +0200 • TESetSelect styled text support
2020-11-22 04:45:35 +0200 • More TEStyleInsert work (line heights calculated)
2020-11-22 00:57:54 +0200 • TEStyleInsert progress (TEFindLine style support)
2020-11-21 04:53:05 +0200 • TextEdit BIG refactor & start adding TEStyleInsert
2020-11-21 02:46:25 +0200 • Implement GetCPixel and SetCPixel (ResEdit PACK 1)
2020-11-20 15:59:17 +0200 • Fix colorQD colormap bug, 1&2-bit modes flipped fg
2020-11-20 15:37:02 +0200 • Implement GetEntryUsage trap for palette manager
2020-11-20 15:23:33 +0200 • Implement old-style FONT lookup in RealFont
2020-11-20 14:47:15 +0200 • Fix bugs in styled text rendering, it works now
2020-11-20 13:56:34 +0200 • Don't set/read flags for purged/unallocated handle
2020-11-20 12:44:49 +0200 • Implement TEGetHeight (non-styled) for SimCity 2K
2020-11-20 12:28:04 +0200 • Make SWAP macro single-line safe
2020-11-20 05:48:11 +0200 • Fix for what looks like VERY strange bug in Excel…
2020-11-20 05:45:10 +0200 • Add dummy GetPortNameFromPSN selector @ OSDispatch
2020-11-20 05:44:27 +0200 • Add PPC trap dispatcher w/ dummy PPCInit & PPCOpen
2020-11-20 05:20:57 +0200 • Temporarily increase system heap size
2020-11-20 05:20:15 +0200 • Dummy switcher info data for testing Excel 3.0
2020-11-20 04:36:18 +0200 • Prototype styled TextEdit draw & linewidth measure
2020-11-10 22:48:13 +0200 • Implement TEGetStyleHandle for TEDispatch
2020-11-10 22:28:22 +0200 • Implement dummy IsLayer selector for LayerDispatch
2020-11-10 22:09:35 +0200 • Add TEDispatch, and TECustomHook and TEFeatureFlag
2020-11-10 03:22:20 +0200 • Implement TEStyleNew trap handler for TextEdit
2020-11-10 03:20:44 +0200 • Update Scarab of RA test app config to new version
2020-11-08 13:47:35 +0200 • Optional release version logging/assertions toggle
2020-11-08 13:46:56 +0200 • Minor code cleanups (logging, prep dirtyrects etc)
2020-11-08 13:27:22 +0200 • Fix src/mask address calculation in B&W CopyMask
2020-11-08 00:54:19 +0200 • Reinforce save of auxiliary regs in C->68k calls
2020-11-08 00:42:58 +0200 • Fix clamping of teLength in TextEdit's DoDraw proc
2020-11-04 16:17:43 +0200 • Add GWorld rowbytes calculation method selection
2020-10-31 03:26:53 +0200 • Handle wInGoAway also in SystemClick (Close DA)
2020-10-31 03:25:08 +0200 • Add missing change from the slot manager commit

A new host for the blog

Until this day we’ve been keeping this project blog private, but we were told that there might be other people who might be interested in reading about the news and progression of our little project.

For this purpose, we’ve now moved to this new public domain, and also uploaded the private videos on YouTube for public viewing

If there’s anybody who’s interested following this project, please let us know by following this blog and/or the YouTube channel. This way we will know if we should post news about our progress in the future too.

YouTube channel:

This blog:

Mapping the goals

For a project with a scope as large as this one has, setting goals and planning how to get there is very important. Here’s a rough outline of what we actually want to achieve:

  • Some level of compatibility with all apps ranging from early apps for 128K Mac in 1984 to the last PowerPC apps in early 2000’s
  • Ability to run apps either:
    • Classic-style seamless integration with any host operating system desktop. This would be for any apps/games which use windows and adapt correctly to various desktop sizes.
    • Full-screen exclusive mode. Mostly for full-screen games/apps, and apps designed for fixed-resolution screens such as most of the early games.
  • Sound emulation either through low-level Classic-type sound hardware (often used in early monochrome games), and high-level Sound Manager emulation (for games/apps from the later times).
  • Provide a one-click solution to play any compatible favourite game as a pre-built Mac OS X .app package.

With these goals in mind, this project is divided to various phases, each of which can be considered as kind of a milestone:

  • Phase 1: Motorola 68000 CPU emulation, with “Classic Mac”-type hardware emulation with monochrome-only QuickDraw on 512×342 screen in non-seamless mode, 24-bit Memory Manager, “Sound Driver”-compatible hardware sound emulation and file system emulation, System 6.0.7/7.1 level Toolbox API compatibility.
  • Phase 2: Later 68020/30/40 emulation, with Slot Manager-type video device emulation, 32-bit Color QuickDraw and Sound Manager emulation, better System 7.1/7.5.x API compatibility. Optionally 32-bit Memory Manager support.
  • Phase 3: PowerPC emulation, Mac OS 8-level Toolbox API’s (Appearance, Game Sprockets, Networking).
  • Phase 4: Mac OS 9-level Toolbox API’s, OpenGL compatibility.

The Phase 1 and 2 seem to be most realistic, but if (when!) we actually reach those milestones, we can revisit the plans and see how feasible the rest of the goals look at that point.