2 year anniversary of MACE! And some color progress & bonus

It is now two years since we started this project, and so far the progress is looking promising. At this point, it is good to take a brief overall look at where we are right now… so far, we have a lot of phase #1 goals accomplished:

  • Good enough 68000 emulation to run majority of games designed to use that CPU.
  • Majority of “classic” QuickDraw traps implemented to allow black & white games which needs them to work. Also hardware-level VIA page-swapping support for double-buffered games such as Dark Castle and Continuum.
  • Complete “.Sound” driver functionality, including ~99% coverage of low-level sound hardware emulation to allow games such as Dark Castle, Tetris and Pirates! to have working sound.
  • External file system emulation with HFS metadata support abstracted to ADF files, with almost all read/write operations tested working (except delete/rename, which have so far been rarely needed)
  • Basically implemented most of toolbox calls needed to, get out of the 87 test applications, 78 to work in at least somewhat usable way, and 43 to function near-perfectly.
  • Ability to run (or try running) the test applications/games as native OSX application bundles (and now with Windows support, also as windows EXE files), with full mouse/keyboard support, fullscreen/windowed and pixel-double support. Sound also mostly works but the SDL buffering needs some tweaking especially on windows…

As the toolbox is quite large, and there is a large number of traps/selectors which are rarely needed, and have not been encountered in the applications we have been testing vigorously. These APIs are still unimplemented, but they will be eventually added to the emulation. However, because these missing phase #1 features have such minor impact on most test applications, we also have started to work on some phase #2 features which are not only beneficial for a lot of current test suite, but which also will allow a huge number of new applications to be added to our tests:

  • 68020/030/040 emulation, which Pukka has already done a lot of progress on.
  • Color QuickDraw support, which was started after Christmas (more about that later in this post – very important for getting color games to work!)
  • Some preliminary progress on System 7.x APIs (FSSpec calls, Folder Manager, Time Manager, Script Manager, etc.).

Because of the fact that as we are implementing new features in a parallel fashion, we don’t have any fixed schedule for milestones. But realistically we expect to get a lot progress on the color support during the spring, which is the biggest bottleneck for getting much larger test application coverage. The downside of this is, however, that a “generic” emulator release will get delayed, because we want it to be as complete as possible, so that you won’t have to suffer from the incomplete features until we get everything polished. You can always follow the test application coverage (and overall progress) on our status page at https://mace.software/status/.

Color QuickDraw progress & first color game (somewhat) playable: KYE!

Since the previous post, majority of work as focused on getting source-mode blitting to work within the color hardware and Color QD API emulation. One of the easiest test cases for that purpose is a fun game called KYE, which was one of personal favorites of Toni on his LC II in early 90’s. The reason why this particular game is nicely suited for this early-stage testing is the fact that it uses mostly just PlotCIcon to draw all of its “sprite” graphics. Thanks to this, we did not have to work on a huge number of different calls at once, but were able to focus on getting that single call working. That way we could get something visible progress on the screen, instead of the invisible “under-the-hood” type of progress which has more impact on the long term.

For curiosity, below is a set of screenshots taken during the PlotCIcon development, which shows how the bugs were squished one by one until the rendering was finally okay:

Here’s a screenshot of latest stage of PlotCIcon functionality in KYE:

Level 3 of KYE

As you can see in the screenshot, icon rendering is working nicely, but text rendering is still completely missing. We also updated the WDEF 0 to have most of color support, so it uses now shading from the default ‘wctb’, leading to authentic System 7-style look and feel. Because of early stage of implementation, the color blitter has right now following limitations:

  • Blitter only works on “indexed” targets (1-8 bit pixmaps), i.e. not on “direct” (16/32-bit) screens
  • Only supports indexed sources too
  • Only simple srcCopy and srcOr modes supported (non-colorized)
  • No stretching support yet (only 1:1 scaling)
  • No arithmetic modes yet
  • Focus at this stage is on accuracy – that is, getting the output results to look exactly same as on the original, “real” Color QD – so performance is far from optimal for now. Leaves a lot of space for blitter optimization in future though…
  • Probably a lot of other use cases which I can’t recall right now…

Below is also a short video of level 2 gameplay:

Test run of level 2 of KYE (in 8-bit color mode)

Anniversary bonus! PT-109 gameplay video

To celebrate the two-year anniversary, we also recorded 90 minutes of PT-109 gameplay to show the current state of that game’s compatibility with M.A.C.E. below:

90 minutes of PT-109 campaign gameplay (16 missions)

This video shows what to expect when we get the “generic” emulator released some day in the future. For now, we can only share the video of this awesome game as it is sadly copyrighted – but we have a bunch of freely available games at our downloads page at https://mace.software/files for both Mac OS X and Windows 64-bit.

If you are interested in keeping up with our progress (now that we start the third year with full speed) you can follow this blog, or one or more of the following:

Full list of changes since last post

2020-02-23 22:32:57 +0200 • Add srcOr transfer mode to generic (=slow) blitter
2020-02-22 21:39:25 +0200 • Fix MOVE SR,-(A7) bug
2020-02-22 19:27:03 +0200 • Fix byteswap bug of ctSeed & tweak 2-&4- bit cluts
2020-02-22 18:51:04 +0200 • PenMode color QD compatibility
2020-02-22 18:50:30 +0200 • Add patXor mode for pixpat color rectangle blitter
2020-02-22 18:03:25 +0200 • Implement color QD versions of Get/SetPenState
2020-02-22 18:02:26 +0200 • Implement PenPixPat
2020-02-22 17:25:03 +0200 • Apply source mask to region scanlines when seeking
2020-02-22 17:24:06 +0200 • Fix align to destination in color srcCopy blitter
2020-02-22 17:21:57 +0200 • Fix b&w pixel data expansion being off by 32 bits
2020-02-22 17:19:46 +0200 • Add extra space after mask buffer for alignment
2020-02-22 17:18:43 +0200 • Keep rgn buffers 1-bit until destination expansion
2020-02-22 05:10:55 +0200 • Fix rowbytes calculation, cicns are now almost ok
2020-02-22 04:45:39 +0200 • Color blitter progress, KYE cicns almost visible
2020-02-22 02:33:59 +0200 • Region scanline to destination scaling functions
2020-02-21 22:50:17 +0200 • First successful pixel depth & clut translation
2020-02-21 22:17:11 +0200 • Get source & mask pixel data to translation buffer
2020-02-21 22:14:54 +0200 • Fix missing DerefHandle in PlotCIcon pixmap setup
2020-02-21 02:59:49 +0200 • More work on color blitter (PlotCIcon case init)
2020-02-18 01:02:13 +0200 • Progress on pixel translation in color src blitter
2020-02-17 17:05:51 +0200 • First colorized WDEF 0 parts (doc variant tested)
2020-02-17 17:03:33 +0200 • Fix missing deref of pixpat handle in color mapper
2020-02-17 16:18:49 +0200 • Fix assignment of WMgrCPort in InitWindows
2020-02-17 16:17:55 +0200 • Fix byteswap bug in PlotCIcon (b&w case detection)
2020-02-17 16:16:12 +0200 • Fix invalid portRect in InitCPort
2020-02-17 02:53:34 +0200 • Add RSAllocArray to allocate arrays in the scratch
2020-02-16 01:58:21 +0200 • Separate color QD CopyMask trap from "classic" one
2020-02-16 01:57:31 +0200 • Add dummy color stretch blitter & map use cases
2020-02-13 02:28:58 +0200 • Fix WindowManager colorQD CalcVis portBits mapping
2020-02-13 02:26:55 +0200 • Fix incorrect source rect passed in PlotCIcon
2020-02-13 02:01:51 +0200 • Half-dummy PlotCIcon, missing still src blitters
2020-02-13 02:00:49 +0200 • Fix window port bitmap size for color QD wCalcRgns
2020-02-12 02:24:35 +0200 • Fix MovePortTo (target rect did not map to pixmap)
2020-02-11 23:09:14 +0200 • Implement GetCIcon
2020-02-11 00:41:10 +0200 • Single-device colorQD DeviceLoop implementation
2020-02-11 00:29:28 +0200 • Improve WDEF 0 color compatibility for NewWindow
2020-02-11 00:20:50 +0200 • Fix default AuxWinHandle result of GetAuxWin trap
2020-02-10 23:46:56 +0200 • ColorQD version of BackPat
2020-02-10 21:25:14 +0200 • Fix wrong pattern given by QDDrawRegion to blitter
2020-02-10 06:25:48 +0200 • MovePortTo and PortSize colorQD compatibility
2020-02-10 05:37:21 +0200 • Fix colorQD multidevice StdArc drawing
2020-02-10 05:03:29 +0200 • Refactor 'MBDF' 0 for more color QD compatibility
2020-02-10 02:36:45 +0200 • Finish implementation of SetMCEntries
2020-02-10 02:16:13 +0200 • First (non-complete) InitPalettes pass
2020-02-10 02:15:26 +0200 • Add RSEnter/RSReturn pair to colorQD PenNormal
2020-02-10 02:14:46 +0200 • Fix RSEnter/RSReturn imbalance in QDDrawRegion
2020-02-10 02:14:11 +0200 • Tweak GestaltQDVersion selector result in color QD
2020-02-10 02:13:24 +0200 • Tweak default placeholder device mode
2020-02-09 23:05:22 +0200 • Tweak fake-ROM clut table seeds to match rsrc IDs
2020-02-09 03:38:12 +0200 • Implement NewPalette in Palette Manager
2020-02-09 02:33:13 +0200 • Implement GetNewPalette trap for Palette Manager
2020-02-08 17:09:07 +0200 • ColorQD compatible SetPortBits (no-op @CGrafPorts)
2020-02-08 17:08:02 +0200 • ColorQD SetOrigin (dereference CGrafPort pixmap)
2020-02-08 13:43:47 +0200 • Fix GrayRgn calculation in colorQD mode
2020-02-08 13:41:36 +0200 • Add ColorQD Region draw operations (non-masked)
2020-02-08 05:29:59 +0200 • Fix window manager clip bug in colorQD InitWindows
2020-02-08 05:27:57 +0200 • Fix detection of color port in ColorStretchBits
2020-02-08 04:54:31 +0200 • ColorQD Line and LineTo + line renderer
2020-02-08 02:42:58 +0200 • Implement ColorQD Move and MoveTo
2020-02-08 02:12:25 +0200 • ColorQD versions of PenNormal and PenPat
2020-02-08 02:02:08 +0200 • Fix CGrafPort/GrafPort target check for patterns
2020-02-08 02:00:44 +0200 • Start work on FillCRoundRect (PixPat expansion)
2020-02-08 00:01:45 +0200 • 8- & 16-bit scanline srcCopy & fix PixPat handling
2020-02-07 17:20:08 +0200 • 1, 2 & 4-bit scanline blitter and region expansion
2020-02-07 01:52:53 +0200 • Unify color QD and classic QD Arc draw traps
2020-02-07 01:44:43 +0200 • Generalize color QD pattern expansion for arcs too
2020-02-06 22:54:14 +0200 • Implement custom grafProcs support for Arc drawing
2020-02-06 22:36:47 +0200 • Refactor scanline blitters into separate module
2020-02-06 04:11:58 +0200 • Tweak base address and rowbytes for arc draw loop
2020-02-06 03:46:00 +0200 • Major region buffer refactor part #1 for color QD
2020-02-06 03:33:18 +0200 • Setup default mctb colors for drawing the menu bar
2020-02-03 22:58:37 +0200 • Implement GetMaskTable
2020-02-01 19:28:29 +0200 • Use OpenCPort instead of OpenPort in color QD init
2020-02-01 19:27:36 +0200 • Add RGBWhite/RGBBlack low-mem globals
2020-02-01 19:26:23 +0200 • GetForeColor/GetBackColor CGrafPort support
2020-02-01 19:14:41 +0200 • Implement GetMCEntry
2020-02-01 18:05:19 +0200 • Implement GetMaxDevice
2020-02-01 01:44:33 +0200 • Fix ShieldCursor/ShowCursor imbalance in QDDrawArc
2020-02-01 01:04:38 +0200 • Fix byteswap bug in rectangle region recording
2020-02-01 01:03:00 +0200 • Disable ROM write check for now, DungeonOfDoom fix

First steps into a more “colorful” emulation

One of the major features of phase #2, as we originally wrote in the milestone and phase plan two years ago, is adding support for Color QuickDraw emulation. Even though a lot of APIs considered part of phase #1 are still incomplete, the application compatibility and overall progress of project appears good enough to justify starting the work on that particular feature at this point. Nevertheless, all missing phase #1 features will be worked on simultaneously as they come up when testing the applications.

Adding color support will eventually allow us to test a huge number of new applications and games, and it will also allow trying out the existing ones in color modes. Especially games from the early 1990s have very good support for multiple color depths, so it should be interesting (for example, Civilization’s support for 1-bit and 256 colors, Railroad Tycoon’s 1-bit and 16 color support, Glider’s 16-color art, etc…)

First steps: The slot-based architecture

Originally Apple’s Mac II lineup had a quite different architecture from the old “classic”-type compact macs, which also reflects on how Color QuickDraw operates. Instead of dividing the memory space into four regions as in “classic” Macs (4mb RAM, 4mb ROM, 4mb I/O and 4mb VIA space), the slot-based models (in original 24-bit model) divide memory into 1mb “slots”, which are more dynamically assigned. For example, IM:Memory 3-6 describes the following model (in 24-bit mode):

  • 0x000000-0x7FFFFF: RAM
  • 0x800000-0x8FFFFF: ROM
  • 0x900000-0xEFFFFF: Nubus slot addresses
  • 0xF00000-0xFFFFFF: I/O

That particular model fits quite well with the currently implemented 24-bit memory manager, so we use that as a starting point for Color QuickDraw machine emulation. It also allows us to partially emulate slow manager APIs (as slot numbers $9 through $E match their address space as on real Macs), and allows possibility for emulating multiple screen using multiple “virtual” slot manager cards, one for each screen. The drawback of this, though, is that only one megabyte is assigned for each video device in 24-bit mode, which limits usable VRAM to that 1 megabyte. What this practically means, is that these are the approximately maximum supported “standard” resolutions for each color depth:

  • 1-bit (black & white): 3840 x 2160 (4K)
  • 2-bit (4-color): 2560 x 1440 (QHD)
  • 4-bit (16-color): 1920 x 1080 (FHD)
  • 8-bit (256-color): 1280 x 720 (HD)
  • 16-bit (32K colors): 832 x 624 (Mac 16″)
  • 32-bit (16.7M colors): 512 x 384 (Mac 12″)

Of course, when we later someday add 32-bit memory manager support, we will have 256 megabytes per video device, and can get rid of this limitation.

The slot driver

One key component between the “virtual” slot-based video device emulation, and the Color QuickDraw, is the device driver for the slot device. In our case, we added the .Display_Video_MACE_FB driver (following Apple’s naming convention for slot drivers), which is used by QuickDraw’s and Color Manager to control video modes, color table, etc.

On real Macs slot manager would be responsible for iterating parsing sRsrc:s and other slot-specific data structures, but we forego those hardware-specific details and address the native video device data (currently SDL) through our platform-abstraction interface.

The DRVR calls are still important to implement properly, as they were quite standard on real Macs, and there might be apps using them directly, even though well-behaving apps should always use GDevice, Color Manager and Color QuickDraw API calls.

Platform abstraction for color video

As we already had prepared for adding color support when starting the project two years ago, most of the support for it existed already in the platform abstraction layer. There were a couple tweaks needed, but most work was just adding the output renderers for each of the new color depths (originally there was only 1-bit blitter, as it was the only color depth supported on classic Macs). This also included adding the color lookup tables in the pipeline, so that we are ready for Palette Manager when we get to the point of implementing it.


As there may exist any number of screens, with any resolution and various color depths, Color QuickDraw added the concept of GDevices. Each GDevice represents one screen/video card attached to the system, with its own screen buffer, color & gamma tables, etc.

Color QuickDraw allows drawing to all of these devices at once using the standard toolbox API, doing all the color conversion and addressing for the user. This is what we need to implement next also in our emulator.

Color Manager

One key component of Color QuickDraw is Color Manager, which is responsible for managing the color tables for each GDevice. What this means, that it creates and manages the inverse color lookup tables (which are used to map RGB colors to indexed colors), and handles those lookups. It also keeps track of seed values for color tables, which are used to determine when color tables have changed, which is important especially if a previously expanded pattern is drawn after a new color table has been activated. For now, we implemented a very basic ITable generation for allowing RGBColors to work on indexed color modes.

Inverse color-lookup table

As meantioned above, one key feature of Color Manager is the generation and management of ITab data structures, which are used to map RGB Colors back into color table indices in indexed video modes (2-, 4- and 8-bit depths). The generator is run in MakeITable trap handler, which takes handle of color table, handle of output inverse table, and desired channel resolution as arguments.

The inverse table is actually a RGB cube, where the cube’s channel size is defined by the number of bits given as the resolution; so for example resolution of 4bits gives 2^4 = 16, and the entire RGB cube would take 16x16x16 bytes which is 4096 bytes, or 4K of memory. As in three-dimensional XYZ space, RGB cube can be thought of in the same way; Each R, G, B coordinate are used to locate index in the cube’s 3-dimensional table.

When Color QuickDraw wants to get for example, index of RGB color #E39EA0, Color Manager would convert first the RGB components into cube’s resolution range (in this case, result would be (14, 9, 10]), and use those values of index the ITab data to get the value.

When the cube is generated by MakeITable, it is initially empty, but is given the seed values from the source color table; each seed value is the color lookup table index, placed at the RGB coordinate which it specifies. After this, the seed values are progressively iterated, so that each value “spreads” into adjacent RGB cube slots in any of the six axis directions (+R/-R, +G/-G, +B/-B). This is repeated as long until there are no longer any unfilled slots left in the RGB cube. This is familiar method from basic pathfinding, and some maze generation algorithms, and ensures that each RGB cube slot contains the index of color lookup table which is the closest available approximation for that particular RGB color.

PixMaps (and PixPats)

As BitMaps only supported 1-bit graphics, Apple added PixMap in Color QuickDraw to allow representing graphics of any bit depth using a standard data structure. Additionally, the GDevices use PixMap to represent the VRAM buffers, and PixPat (multi-color patterns) structure also uses PixMap as storage for the pattern data. And they also are by default implemented as Handles, which means they can be moved in the heap during compaction to prevent memory fragmentation (but require locking in certain cases).

The first step: Using legacy GrafPorts with Color QuickDraw

As Color QuickDraw has a lot of layers to provide backwards-compatibility for older applications, the first step was to start from the most basic one, legacy GrafPort support. As the very first call done to QuickDraw is to gray out the screen at startup, we focused on getting the most basic case for FillRect working at first. With adding support for pattern expansion to any pixel depth, and adding new srcCopy blitters, we got this fist monochrome output result after a couple weeks of coding:

First 1-bit monochrome rectangles using Color QuickDraw in 640×480 mode

When emulating the old-style GrafPorts, of of their interesting features to simulate was support for the 8 old-style QuickDraw colors (which map mostly to the colors used in ImageWriter printers with CMYK ribbon). With proper color mapping, and a couple days of banging the head against desk, we ended up with this result:

Rectangles drawn in old-style 8-color GrafPort using Color QuickDraw

Second step: CGrafPort support

As mentioned earlier, the old-style GrafPorts were limited to only displaying those 8 colors, so to get the full range of RGB colors displayed, we had to add a proper CGrafPort support. This included implementing OpenCPort and InitCPort, and initialization of all related data structures. For example, all patterns in CGrafPorts are PixPat patterns, so we had to do a Pattern-to-PixPat conversion.

Most importantly, the fgColor/bkColor no longer represented the old-style color constants, but instead needed to be mapped to bit-depth specific index (on indexed device modes) or pixel value (on direct device modes). To control these colors, we implemented the RGBForeColor/RGBBackColor traps, which map the RGB values to the mode-specific values.

After a couple of days of more hard work, we now have the RGB colors working in CGrafPorts:

There is still A LOT of things to do before we can get much beyond simple rectangles on the screen, but the tasks should get easier as we go along. A lot of the routines (such as color mapping) can probably be shared as-is with most of other Color QuickDraw APIs. Some of the tasks next up are:

  • Adding region masking variant to the color blitter
  • Adding other pattern modes beyond patCopy
  • Adding source transfer modes (only patCopy done at the time of writing this)
  • Color versions of the special horizontal single-scanline blitters
  • A lot of other stuff

Full list of changes since last post

2020-01-31 18:02:57 +0200 • Basic support for "oldPat" PixPats in CGrafPorts
2020-01-31 16:35:14 +0200 • Implement InvertColor (default gdCompProc only!!!)
2020-01-31 13:47:55 +0200 • Some progress on CGrafPort colormapping & bugfixes
2020-01-30 02:10:42 +0200 • Add ColorQD Fore/BackColor & RGBFore/BackColor
2020-01-30 01:25:49 +0200 • Init default ColorQD PixPat patterns in InitCPort
2020-01-29 20:06:33 +0200 • Implement NewPixMap and NewPixPat
2020-01-29 01:42:41 +0200 • Initialize WMgrCPort (color port) in InitWindows
2020-01-29 01:41:59 +0200 • Implement OpenCPort and (mostly) InitCPort
2020-01-29 00:48:03 +0200 • Implement GetPixPat and GetCCursor colorQD traps
2020-01-28 22:12:56 +0200 • Implement DisposePixPat trap handler in color QD
2020-01-28 01:46:18 +0200 • Fix non-default colored patterns in 1-bit mode
2020-01-28 01:11:02 +0200 • ColorQD compatible GlobalToLocal/LocalToGlobal
2020-01-27 20:22:27 +0200 • Fix palette alignment issue in 8- and 15-bit modes
2020-01-27 20:20:38 +0200 • 15-bit (thousands of colors) SDL rendering support
2020-01-27 20:20:04 +0200 • 2-bit SDL output rendering support
2020-01-27 20:19:27 +0200 • Disable grayscale flag for now, test&fix it later
2020-01-27 20:18:37 +0200 • Fix last palette entry missing (zero-based count)
2020-01-27 13:33:46 +0200 • Add support for direct colors in color mapping
2020-01-27 13:26:34 +0200 • Set GDevice's gdType properly at initialization
2020-01-27 10:38:45 +0200 • GDev CLUT setup & rendering (first colors output!)
2020-01-27 09:44:47 +0200 • ColorQD ForeColor/BackColor in old-style GrafPorts
2020-01-27 09:43:56 +0200 • Fix initialization of QDColors low-mem global
2020-01-27 04:59:25 +0200 • Use Color2Index in color mapping for correct color
2020-01-27 04:56:41 +0200 • Set GDevice's gdResPref in the InitGDevice handler
2020-01-27 04:39:29 +0200 • Color2Index proto (no hidden color handling yet)
2020-01-27 04:36:27 +0200 • Fix the one-entry off "black-most black" index bug
2020-01-27 04:11:57 +0200 • Finish the first proto of MakeITable
2020-01-27 03:19:38 +0200 • Remove unneeded mitq resource from build
2020-01-27 03:18:51 +0200 • "Plant" seeds for the ITab generator from the clut
2020-01-26 00:24:21 +0200 • Start work on MakeITable
2020-01-26 00:23:50 +0200 • Tweak pattern blitters, preparing 8-bit support
2020-01-26 00:22:14 +0200 • Dummy Color2Index stub, prep use in colormapping
2020-01-25 17:05:21 +0200 • Hack 4- and 8-bit (16 & 256-color) output support
2020-01-25 17:01:45 +0200 • Fix old-type pattern to 8-bit conversion
2020-01-25 16:55:25 +0200 • Fix mask calculation for non-1-bit rectangle blits
2020-01-25 02:21:23 +0200 • First simple non-region FillRect case for ColorQD
2020-01-25 02:20:38 +0200 • Block attempting to post events before InitEvents
2020-01-25 02:19:04 +0200 • Fix the "dummy buffer" string RSAlloc overflow
2020-01-24 02:35:50 +0200 • Some progress on color blitter rectangle culling
2020-01-24 02:34:20 +0200 • Add QDErr low-mem global
2020-01-24 00:05:55 +0200 • Do CQD old 1-bit pattern to b&w GrafPort expansion
2020-01-23 00:18:35 +0200 • First CQD color mapping pass for old-type GrafPort
2020-01-22 17:53:29 +0200 • A bit of work on the color QD color mapping
2020-01-21 01:32:09 +0200 • Implement portBits to PixMap conversion to colorQD
2020-01-21 01:30:38 +0200 • Init lot of lowmem globals for default videodevice
2020-01-21 01:27:42 +0200 • Fix byteswap bug on device depth in CVGetVidParams
2020-01-20 15:02:02 +0200 • Refactor QD a bit in preparation of color support
2020-01-20 02:34:13 +0200 • Disable for now dirtyrect optimization in color QD
2020-01-20 02:22:37 +0200 • ColorQD versions of InitPort and OpenPort
2020-01-20 01:33:36 +0200 • Save LastMode/-Fore/-Back/-Depth in FMSwapFont
2020-01-20 01:32:29 +0200 • Fix two indexing bugs in ColorVideoInitOneSlot
2020-01-20 01:30:00 +0200 • Implement most of InitGDevice trap for color QD
2020-01-20 01:28:50 +0200 • Add empty stub for MakeITable trap
2020-01-19 23:29:53 +0200 • Add GetDeviceList trap
2020-01-19 20:37:49 +0200 • Add grayscale flag to video devices
2020-01-19 14:36:11 +0200 • Fill in GDevice's VPBlock from color video driver
2020-01-19 14:35:34 +0200 • Fill in DCE slot info in Open call for slot device
2020-01-19 05:03:02 +0200 • Add one more missing ROM clut resource
2020-01-19 05:02:32 +0200 • Add DisposePixMap, New/InitGDevice, GetNextDevice
2020-01-19 04:59:55 +0200 • Use cmake source_group TREE to clean up projects
2020-01-19 04:59:08 +0200 • Add MacVideo header
2020-01-18 23:54:18 +0200 • A couple more CQD resources (gama, mitq, cluts)
2020-01-18 05:51:16 +0200 • Add unit table debug dump tool to device manager
2020-01-18 05:50:37 +0200 • Add "virtual" slot DRVR installation support
2020-01-18 04:29:39 +0200 • Tweak video driver name & fix default slot amount
2020-01-18 04:26:22 +0200 • Implement DoVBLTask trap (untested)
2020-01-17 17:27:46 +0200 • Add SlotManager module + slot queue initialization
2020-01-17 01:52:09 +0200 • Implement color version of InitGraf
2020-01-17 01:28:37 +0200 • Add GetCTSeed/GetCTable/DisposeCTable to ColorMgr
2020-01-17 01:18:38 +0200 • Add TableSeed and HiliteRGB low-mem globals
2020-01-17 01:17:59 +0200 • Add default 'clut' tables to color ROM resources
2020-01-16 01:50:16 +0200 • Clean up linker errors for missing color QD stubs
2020-01-16 01:43:16 +0200 • Add setup of menubar 'mctb' color table (untested)
2020-01-16 01:35:33 +0200 • Empty stubs for GetCIcon, PlotCIcon & DisposeCIcon
2020-01-16 01:27:38 +0200 • GDevices module & GetMainDevice/GetMaxDevice stubs
2020-01-16 01:20:13 +0200 • Add empty stub for _ActivatePalette
2020-01-16 01:15:39 +0200 • Empty stubs for Delete/SetMCEntries & InitPalettes
2020-01-16 01:06:12 +0200 • Tweak ClassicSound to not fail colorQD compilation
2020-01-16 00:56:30 +0200 • Tweak some CMake configs for color-only apps
2020-01-16 00:55:31 +0200 • Refactor VBL code out of VIA + add slot# to video
2020-01-15 02:52:16 +0200 • Improve compilation of QDExtensions with color QD
2020-01-15 02:41:14 +0200 • Improve Menu Manager color QD compatibility
2020-01-15 02:40:40 +0200 • FMSwapFont color QD tweaks & LastSPExtra type fix
2020-01-15 02:36:37 +0200 • Fix ClassicSound compile error w/o Sound driver
2020-01-15 00:49:29 +0200 • Separate Mono & Color fake roms + add 32-mode flag
2020-01-15 00:47:24 +0200 • Add the DRVR 120 (.Display_Video_MACE) to fake rom
2020-01-15 00:45:59 +0200 • Add color video initialization call to boot code
2020-01-15 00:44:02 +0200 • Add stub for the color video driver
2020-01-15 00:42:54 +0200 • Add symbol name to binary-to-C converter

Windows version (and screen mode control)

As mentioned in the earlier posts, a large amount of this Christmas vacation was spent on the Windows version of M.A.C.E. runtime, and creating something for Windows users to try out. Now all the core work has been done, and we have the first prototype of the Windows port of runtime – with all of the existing test applications now available also as Windows executables. Now, there are a couple important points:

  • The windows executables are currently built only for the 64-bit x64 architecture
  • They have only been tested on Windows 10 (and only on Toni’s brand new 3.06Ghz Xeon W3550, and whatever processor Pukka’s new PC has). We have no idea on what other computers they work (or do not work)
  • You might want to avoid running them under certain virtualization software applications, as at least on Toni’s VirtualBox the performance was… not very stellar, at least compared to a physical PC without virtualization.
  • The PC keys are (for now) mapped permanently as follows:
    • Left alt = Left command
    • Left ctrl = Left option
    • Right alt = Right command
    • Right ctrl = Left control
  • Under windows 10, the “windows square” key (between Ctrl and Alt) cannot be used by the emulator as command or option key, because the Windows OS doesn’t seem to allow it to be fully captured (only partially).
  • AltGr key does NOT work as Right alt, because on Windows AltGr actually simulates Left Ctrl + Left Alt key presses. We need to investigate this more in the future.
  • The filesystem package is cached under Users -> username -> AppData -> Roaming -> MACE, with individual cache folder for each pre-packaged test application. So, if you for example create cool Continuum Galaxy files, this is where you’ll find them. And as AppleDouble files, they are exchangeable between M.A.C.E. on Windows, M.A.C.E. on Mac OS X, and theoretically (but not tested) with the Executor emulator which also uses AppleDouble files.

Below is a screenshot of the currently available test apps running on Windows 10:

If you have Windows, you can right now try them out in the Downloads section on this page.

Screen mode control: Full-screen mode and pixel doubling

Another neat new feature that was added to the new M.A.C.E. runtime version, besides the Windows compatibility, is the ability to switch between windowed/fullscreen modes on the fly, and also toggling the pixel-doubling feature. The shortcuts for these are:

  • Cmd+Shift+1: Toggle pixel doubling mode
  • Cmd+Shift+2: Switch between windowed and full-screen modes

These keyboard shortcuts were chosen (for now) as they should conflict very little with existing Mac applications, as they were used as disk eject FKEYs on real Macs.

This new feature has been both updated into the existing Mac OS X test app bundles, as well as in the new Windows versions.

Full list of changes since last post

2020-01-07 00:39:56 +0200 • Skip unwanted packaged VFS entries
2020-01-06 23:40:32 +0200 • Don't cache OSX 10.6 vs 10.9 target in CMake
2020-01-06 20:32:52 +0200 • Fix typo in scaline range check in _StretchBits
2020-01-06 19:10:24 +0200 • Bump runtime version & tweak version info format
2020-01-06 07:08:39 +0200 • Load package VFS from Win32 resource on Windows
2020-01-06 07:07:18 +0200 • Include dynamically generated .rc in win32 targets
2020-01-06 07:06:34 +0200 • Fix encoding of special symbols in two test apps
2020-01-06 06:05:01 +0200 • Add extracting VFS archive in initialization code
2020-01-05 04:30:25 +0200 • Add file archive reader, and clean up CMake files
2020-01-04 23:20:46 +0200 • Sign-extend <32bit args to prevent ARM optimizat..
2020-01-04 04:18:12 +0200 • Try fix Raspberry hMenu bug, enforce 16-bit menuID
2020-01-03 22:22:10 +0200 • Lock SDL window data during screen mode switch
2020-01-03 21:52:42 +0200 • Refactor display toggles to use DynamicConfig keys
2020-01-03 21:50:30 +0200 • Add first part of DynamicConfig system (UserPrefs)
2020-01-01 17:54:41 +0000 • Disable JSON parser tests from build
2020-01-03 01:20:14 +0200 • Fix DynamicConfiguration JSON dependency + bin dir
2020-01-03 00:39:24 +0200 • Merge branch 'master' of 
2020-01-03 00:39:21 +0200 • Add missing header search path for JSON lib
2020-01-03 00:36:54 +0200 • Fix OSX target, CMP0066 and set SDL2 debug/release
2020-01-02 23:08:12 +0200 • Merge branch 'master' of 
2020-01-02 23:08:06 +0200 • Specialize OSX Cmake config to 10.6 and 10.9 bases
2020-01-02 20:36:10 +0200 • Add JSON parser to the MACE runtime (for configs)
2020-01-02 19:09:33 +0200 • Also fix the Mac icns for previously invalid icons
2020-01-02 18:51:14 +0200 • Add stub for DynamicConfiguration module
2020-01-02 18:50:30 +0200 • Sanitize Windows key mappings to be more usable
2020-01-02 04:13:26 +0200 • Add ICO files to EXEs, & use console only in debug
2020-01-02 04:11:18 +0200 • Use debug/release SDL2 lib depending on app target
2020-01-02 04:09:56 +0200 • Reconvert Windows ICO files
2020-01-02 04:09:39 +0200 • Fix incorrect icon assignments of couple test apps
2020-01-02 04:08:20 +0200 • Make SDL2-static compile on VC release mode
2020-01-02 00:51:30 +0200 • Add processing of Windows ICO files
2020-01-01 23:49:58 +0200 • Fix trap glue generator to use new byteswap macros
2020-01-01 23:48:56 +0200 • Refactor cmake to use offline icon conversion
2020-01-01 20:39:58 +0200 • Add lpng 1.6.37 to ThirdParty external libraries
2020-01-01 17:10:36 +0200 • Force redraw of screen on SDL expose events
2020-01-01 15:38:09 +0000 • Haiku compilation fixes

Happy New Year!

This is just a quick status update to celebrate the new year 2020. As teased in the Christmas update one week ago, there has been some progress on the cross-platform ports of M.A.C.E., and this update is just to give a brief glimpse of the state of Windows and Raspberry ports (with a new year celebration theme):

Platform port status: Raspberry PI

Thanks to the hard to work and big efforts done by Pukka on the Raspberry PI port this year, we finally got it to the stage where Toni was able to integrate the platform into CMake build system, and create working builds for the test applications. Pukka found some performance issues in the SDL rendering, which motivated Toni to also get a Raspberry PI to help debug and identify the problem.

It was figured out, that the SDL2 graphics implementation we had previously used had serious issues, and was rewritten mostly to remove dependency on SDL surfaces, using instead SDL texture for the rendering. With this change, the performance on Raspberry improved to the point of matching the Mac (and Windows) platforms. Additionally, we took this opportunity to improve the fullscreen & pixel-double rendering code to the point that they are also almost ready for public testing.

However, for some reason sound does not yet work on the builds done by Toni on Raspbian 10, although they seem to work on Pukka’s Raspbian 8. This need some more investigation, alongside some other issues on the platform. The basic X11 view driver + software renderer driver combination seems to offer however a good solution for the time being.

Platform port status: Windows

The Windows port, which we teased one week ago in the Christmas update, has advanced quickly and will soon be ready for testing. It took in total one week (the Christmas vacation) for fixing the code for MSVC compiler compatibility (a couple thousands errors), and getting the builds to run. The changes we needed to make include:

  • Fixing problems with zero-size struct arrays
  • Lack of typeof(x) macro leading to need to refactor all byte-swapping and RSAlloc macros (and places where they were used)
  • A couple header changes (such as alloca being defined in different headers on POSIX vs. MSVC)
  • Adding some Windows API code for file system iteration and manipulation alongside of POSIX/Std C code
  • Fixing some bugs that were surfaced by the new port, but were affecting all platforms
  • Other minor changes (clock API, refactoring unistd references, tweaking CMake configs, etc…)

The remaining tasks for first Windows test release are still integration with Windows executable resources, and storage of the NativeFS data on windows builds.

What’s next?

The year 2020 should definitely bring us to the point of releasing a more generic way to run M.A.C.E., including additional platform support, and compatibility with much more applications. At the moment the focus is – beside adding the new platform support – on getting as many of the known issues in the current test applications fixed (which you can follow in our status page). But looking forward to the stage #2 of project, we also hope to start work on Sound Manager and Color QuickDraw implementation in the second half of 2020.

Full list of changes since last post

2020-01-01 02:31:53 +0200 • Fix order of debugger setup in environment headers
2020-01-01 02:18:32 +0200 • Set MemErr to noErr if GetHandleSize succeeds     
2020-01-01 02:17:18 +0200 • Add Finnish Apple Macintosh Basics as test app    
2019-12-31 22:49:19 +0200 • Fix byteswap sign bug in CalcMask/SeedFill        
2019-12-31 04:47:15 +0200 • Only grab input in fullscreen mode                
2019-12-31 04:12:39 +0200 • Merge branch 'master' of  
2019-12-31 04:12:34 +0200 • Fix GCC byteswap macros for raspberry pi          
2019-12-31 03:59:25 +0200 • Use left control as command key on windows        
2019-12-31 01:46:39 +0200 • Refactor SDLPlatform to use Textures, not Surfaces
2019-12-31 00:07:32 +0200 • Merge branch 'master' of  
2019-12-31 00:07:13 +0200 • Update CMake configs and MacTCP for raspberry pi  
2019-12-30 22:25:41 +0200 • Merge branch 'master' of  
2019-12-30 22:24:27 +0200 • Fix buffer overflow in StretchBits dstScanlineBuf 
2019-12-30 21:43:20 +0200 • Fix case-sensitive FS filename issue in CMake file
2019-12-30 02:07:02 +0200 • Fix+optimize pixel-double and fullscreen rendering
2019-12-29 22:41:31 +0200 • Merge branch 'master' of  
2019-12-29 22:41:21 +0200 • Fix Windows build audio issue (SDL buffer format) 
2019-12-29 22:39:38 +0200 • Fix crash: Add missing Open/OpenDeny error checks 
2019-12-29 03:57:01 +0200 • Fix debug strcat in AVLTree.c for Mac version     
2019-12-29 03:33:38 +0200 • Refactor byteswapping (& clean up lot of warnings)
2019-12-29 03:25:58 +0200 • Enable console mode for now in MSVC (for debug)   
2019-12-29 03:25:18 +0200 • Fix signature of argc argument in main method     
2019-12-28 23:36:15 +0200 • Fix bug in path separator conversion in MSVC build
2019-12-28 17:32:02 +0000 • Fix some sign bugs, 1000 miles now starts on Win32
2019-12-28 17:29:58 +0000 • Use MSVC built-in byteswap macros for byteswapping
2019-12-28 17:28:21 +0000 • Fix SDL main & set executable as a Windows GUI app
2019-12-28 15:25:55 +0200 • Fix malloc.h/alloca.h header includes for MacOS   
2019-12-28 15:02:36 +0200 • Merge branch 'master' of  
2019-12-28 15:02:31 +0200 • Clean up misc debug macros etc before win32 merge 
2019-12-28 02:22:10 +0000 • A MAJOR Windows and MSVC compatibility update     
2019-12-27 21:59:06 +0000 • Fix potential timestamp conversion shift overflow 
2019-12-27 21:56:14 +0000 • Fix byteswap bug in fractional pen location init  
2019-12-27 00:39:38 +0000 • Don't try to return value from void function      
2019-12-27 00:00:32 +0000 • Fix wrong data size in low-mem Rect setter macro  
2019-12-26 23:00:41 +0000 • Merge branch 'master' of  
2019-12-26 23:00:27 +0000 • Ignore MacOS-specific files in MSVC cmake targets 
2019-12-26 22:58:38 +0000 • MSVC compatible SDL clock (and rotate macros)     
2019-12-27 00:09:04 +0200 • Init PortList and ChunkyDepth                     
2019-12-26 21:18:10 +0200 • Improve InitApplZone, add some CQD low-mem globals
2019-12-26 21:09:34 +0200 • Add proper alpha to SDL RGB output (->pixeldouble)
2019-12-26 21:08:03 +0200 • Add temporary IODone stack hack for MacTCP driver 
2019-12-26 21:04:59 +0200 • Use new enum for killCode in Sound Driver         
2019-12-26 21:04:20 +0200 • Add more logging to .IPP driver 

Happy Holidays!

It’s again the Christmas season, and time again for the annual holiday update, now for the second time! As our greeting to you, here’s the (apparently now traditional) Christmas tree easter egg screenshots from Dark Castle running the latest M.A.C.E. version (it appears only when the game notices that the system time is set to 25th of December in UTC time):

Dark Castle was one of the first games we actually tried M.A.C.E. on over one year ago, and it was already working quite well on the previous Christmas. At that time, the CPU bugs were preventing FireBall levels from being played, but luckily those issues were fixed during this summer, and now all the levels are in playable state.

There are however still minor hiccups, such as weirdly behaving robots, dungeon key being always on the right-most side in the Trouble 3 level, Mutants spawning too quickly, Burning Eye not shooting fireballs, etc. Pukka thinks a common denominator for these issues might be some random number generation code in Dark Castle, but it still needs to be analyzed further.

To celebrate the progress, we recorded a short video of Dark Castle gameplay (with Christmas tree in The Great Hall) on this Christmas Day for your entertainment – all rooms were visited, but sadly I was not lucky enough to topple the Black Knight off his throne this time, even after two tries:

Dark Castle running on M.A.C.E. (Christmas Day easter egg)

Teasers for 2020

Sadly the holiday season has been very busy, which has also slowed down the project progress a little bit. There’s still some teasers for upcoming features which are almost complete, but not yet ready for release:

MacTCP driver

After we tested Bolo in M.A.C.E., we got inspired by the network support it has and had a idea about trying to implement a simple MacTCP driver in M.A.C.E., which would allow us to try out Bolo’s network gameplay we used to play with long time ago. However, the non-standard IODone mechanism, and Bolo’s tricky network performance measurement code, there is still a bit of work to be done to get that into playable state. However, MacTCP Ping seems to be working already quite well, including the DNS resolver:

There is though a “record route” option in “Options” menu, which we could not test because for some reason even using the same option on the real ping (ping -R) on Mac OS X causes the echo packets to get lost.

A more proper introduction about how this all works will be added later when we get the entire driver to work. For now, at least UDP calls to the .IPP driver seem to be working on an “okay” level, although they have so far been really tested only with Bolo, and only for the very first couple UDP packets exchanged by it.

Windows support

As many people have requested, we are already experimenting with adding a third platform into the build system, Windows (from Microsoft, the notorious arch-enemy of Apple Computer 🙂

We already fixed a couple thousand build errors, but there is still a lot of work to be done. For example, the MSVC compiler has a lot of source-code level differences in the C compiler, which need to be abstracted to allow the code to compile both with LLVM/GCC and MSVC targets. Additionally, the networking, file system APIs – and a bunch of other things we have – are POSIX/Unix-only at the moment, which need Win32/64 equivalents to be implemented.

Beyond those two work-in-progress features, we are also still working on increasing stability through bug fixing and debugging. You can always follow the progress on this blog, and check the list of compatible applications in the “Status” page. Thank you for you interest in our efforts, have a merry Christmas!

Full list of changes since last post

2019-12-21 14:09:25 +0200 • Fix VerticalRetraceMgr byteswap bug in inVBL flag 
2019-12-21 14:08:18 +0200 • Add UDPWrite implementation to MacTCP emulation   
2019-12-20 03:14:50 +0200 • First successful UDPRead in MacTCP call (w/ Bolo) 
2019-12-20 01:00:52 +0200 • Implemented UDPCreate for MacTCP driver           
2019-12-20 00:01:36 +0200 • Add MacWWW test app (not working, needs color QD!)
2019-12-20 00:00:21 +0200 • Make MacTCP ipctlEchoICMP support async operations
2019-12-19 23:57:26 +0200 • Improve DA/DeviceMgr enums (accXXX, ioInProgress…)
2019-12-19 23:55:07 +0200 • Fix byteswap bug of dCtlDelay in SystemTask       
2019-12-18 19:22:56 +0200 • Disable unused 128-bit float test code            
2019-12-17 04:29:47 +0200 • Reinforce interrupt safety of device manager calls
2019-12-17 04:02:39 +0200 • Don't close the MacTCP driver                     
2019-12-15 05:23:27 +0200 • Add very primitive foundation for MacTCP driver   
2019-12-15 03:42:24 +0200 • Add a couple more kCStackBased mixedmode handlers 
2019-12-15 03:40:51 +0200 • Add missing prWrErr from earlier PRAM modification
2019-12-15 03:39:53 +0200 • Make RSReturnValue argument safe for function call
2019-12-15 03:37:15 +0200 • Add the DRVR 22 MacTCP (.IPP) driver to fake ROM  
2019-12-15 03:35:32 +0200 • Add MacTCP Ping test app to CMake JSON config     
2019-12-15 02:48:56 +0200 • Fix indexing for GetFileInfo/SetFileInfo          
2019-12-15 02:45:45 +0200 • Start work on kCStackBased MixedMode routine type 
2019-12-15 02:44:19 +0200 • Fix off-by-one-byte bug in FindFolder fld# handler
2019-12-13 03:25:39 +0200 • Add dummy ReadXPRam and WriteXPram for Bolo     

Finding the Finder

Recently, somebody was asking on Emaculation forums, what would happen if Apple’s Finder would be attempted to run in M.A.C.E.? That was an interesting question, which motivated us to try it out.

Mac System Software architecture

To think about what would make Finder work, let’s consider the classic Mac system software as an architecture consisting of roughly three layers (in real Macs):

  • ROM: Most of Toolbox APIs, ROM resources and stage 0 boot loader.
  • System: Patches to ROM, extensions, system zone, the so-called “kernel” of old MacOS.
  • Finder: The “desktop metaphor” front-end running as a regular Mac application.

This categorization is very naïve, does not consider details such as role of hard drive drivers in boot process, etc. Additionally, M.A.C.E. combines roles of ROM and System as a single entity implemented in native code.

The interesting part to highlight is how Finder is basically “just another” application running on the System, and was even replaced by alternate startup applications on the old Macs (such as MiniFinder, MultiFinder, or other applications using the “Set Startup” option). As such, especially on System 6.x and older, the undocumented dependencies between System and Finder might be few in number, if any.

The first run

So, the question was, what would happen if we would try to run it? Well, we got this far on the first attempt, and with a couple minor fixes to progress further:

So, almost there. What we needed was a couple new (missing) routines and some fixes:

  • Fixed the 0x16 and 0x17 csCodes for .NativeFS driver, which return the logical/physical ICN# data for the volume icon (as seen on the desktop). We actually had that icon already one year ago, but this was the first time anything wanted to access it. 🙂
  • Added working directory indexing to GetWDInfo, which Finder uses to close all open working directories, presumably left open by misbehaving applications under System 6.x.
  • Fixed a buffer overflow bug in GetVolInfo (in volume name).
  • Implemented File locking APIs, which Finder wants to use to maintain the Desktop file.

Getting to the desktop

After a long and tedious session of debugging, it was discovered that due to a stupid bug in GetWDInfo Finder was crashing upon attempting to enumerate volumes. After that fix, we got nice Finder desktop, and a lot of functionality already working:

Operating on the Finder windows added need to implement a couple other missing traps, although as dummy versions for now (SetCatInfo and SetVolInfo, which Finder attempts to use to write metadata about modifications done in the spatial finder windows, icons, etc). Some points:

  • Finder and system icons appear as documents, but that might be because those don’t yet exist in the System file. Not sure about that yet.
  • It’s nice to see how a Finder 6.1.8 from Apple’s real System 6.0.7 behaves nicely even though M.A.C.E. System declares being version 7.0. 🙂
  • For some reason, doing “Get Info” on our Hard Drive turns our custom icon returned by the .NativeFS DRVR to a generic floppy icon.
  • It’s interesting how Finder considers at the moment our custom Hard Drive as “AppleTalk” device, but that might be because we’re hooking into the ExtFS file manager hooks which *I think* were used by AppleTalk in the real System 6.x. Just another thing which needs more investigation.
  • The modification and creation dates shown in “Get Info” (and list-style finder windows) use International Utilities date & time formatting functions, which are still placeholders. And as such, they only display mostly the numeric value of date-time instead of the proper, human-readable format.

Making the Desktop file work

At this point, we didn’t yet get the proper application and document icons to appear, so we did a bit more debugging on what was happening with the Desktop file – which Finder uses to keep track of known application creator & types, file comments, etc. It turned out, that we accidentally had all the “hasBundle” (0x2000) bits turned off in applications, which is why they were not detected by Finder.

As this issue was fixed, Finder started to process the applications properly, and quickly needed a some improvements to Resource Manager APIs. Mostly, it wanted to use UniqueID to allocate unique IDs for resources inside the Desktop file’s resource fork (to avoid conflicts). After that, updating Desktop file seems to work quite nicely, resulting in some fancy icons now appearing in the Finder under M.A.C.E.:

For now, running the real Finder remains as a curiosity, but nevertheless works as a great test case for a various number of Toolbox File Manager APIs which still need work (among some other minor bugs). The summary of the major known issues is:

  • The launching of programs “almost” works. Everything else appears to be fine, but it suffers from the same issue as previously found out using the “Transfer” command in THINK Pascal: The Font Manager data caches do not clear completely, leaving some dangling handles/pointers to the old application zone, which cause crash on attempting to reference them after the zone has been reinitialized for the new application.
  • Getting back to Finder (or any shell) is not yet possible, as ExitToShell is still hard-coded to terminate the entire emulator, instead of launching LMGetFinderName() application. Getting this to work would also encourage researching the Emscripten and Process Manager compatibility, as all of those features share a common need for a better in-emulator process management.
  • SetCatInfo/SetVolInfo are still dummy placeholders, so Finder is trying to use them to update metadata, though it is not yet saved.
  • Folder creation (_DirCreate), File/Folder deletion (_Delete), renaming (_Rename) are not yet implemented, so attempting those operations on Finder will still fail.
  • The _Eject trap is not yet implemented (and in any case you will not be able to eject the NativeFS drives).
  • As previously pointed out, Date & Time formatting does not yet work
  • The “Rebuild Desktop” operation (though using option + cmd keys at startup) does not yet seem to do the actual rebuild on a “fresh” start (i.e. if Desktop file has been wiped). Additionally, attempting that operation while old Desktop file exist will error out because _Delete is unimplemented, and old file cannot be removed out of the way.
  • Maybe other issues too, those are just the ones found out in the quick testing.

The “generic” M.A.C.E. environment might benefit of this though, as a replacement shell and/or program launcher, that could be optionally used by the end-user.

Full list of changes since last post

2019-12-12 18:19:41 +0200 • Add UniqueID/…1ID, to allow Desktop file updates
2019-12-12 17:49:18 +0200 • Add Disk Initialization Pack2 to keep Finder happy
2019-12-12 17:46:55 +0200 • Fix byteswap bug in NativeFS _Allocate handler
2019-12-12 15:00:12 +0200 • Add missing NativeFS.c changes for previous commit
2019-12-12 04:34:28 +0200 • Add dummy SetCatInfo and SetVolInfo selectors
2019-12-12 04:02:48 +0200 • Fix GetWDInfo bug (ioVRefNum & ioWDVRefNum mixed)
2019-12-09 02:58:47 +0200 • Fix memFullErr check in SetApplLimit
2019-12-08 06:31:06 +0200 • Fix filename overflow in GetVolInfo NativeFS call
2019-12-08 06:30:06 +0200 • Implemented CloseWD
2019-12-08 06:29:03 +0200 • Add WD indexing to GetWDInfo
2019-12-08 06:27:20 +0200 • Add Finder test app to cmake configs
2019-12-08 06:27:01 +0200 • Implement icon csCodes in NativeFS Control call
2019-12-08 06:25:52 +0200 • Make more macros in memory manager MSVC friendly
2019-12-08 06:25:18 +0200 • Add dummy SetFilLock and RstFilLock
2019-12-08 06:23:36 +0200 • Fix FinderName lowmem global
2019-12-06 23:44:06 +0200 • Add Bash Big Blue to cmake config for testing
2019-12-04 21:21:36 +0200 • Fix QD_LOG to respect debug settings
2019-12-04 20:48:17 +0200 • Add Cairo ShootOut! to cmake config for testing
2019-11-30 02:02:05 +0200 • Fix empty VA_ARGS problem in MaceLog macro
2019-11-29 23:55:30 +0000 • Make SWAP and MIN/MAX macros MSVC compatible
2019-11-29 23:54:08 +0000 • Made vararg ellipsis parameters MSVC compatible
2019-11-29 23:52:21 +0000 • Make Memory Manager return macros MSVC compatible
2019-11-29 23:51:27 +0000 • Make ROMScratch macros MSVC compatible
2019-11-29 23:50:08 +0000 • Move SwapPoint to MacQuickDraw.h to make it inline
2019-11-29 23:48:05 +0000 • Change void* to UInt8* in fake ROM (for MSVC)
2019-11-29 23:46:50 +0000 • Make SANE conversion macros MSVC compatible
2019-11-29 23:33:03 +0000 • Merge branch 'master' of
2019-11-29 23:32:43 +0000 • WinAPI EndianXX_Swap macros
2019-11-30 01:30:54 +0200 • Add UInt128 type to EmuMacTypes.h

SoftPC (and the quest for the XT memory map)

Before Macintosh was created, there was a computer architecture called IBM PC. With Intel 8086 processor, it was incompatible with the Motorola 68000 family used in Macintosh computers – and thus, no IBM PC software would work in Macintosh. But there were some really smart people, who created a special application called SoftPC in mid-80’s, which interpreted Intel’s x86 instructions on the fly, and emulated enough PC architecture and BIOS ROM to allow those programs to run on Macintosh. And now, SoftPC finally also works on M.A.C.E.

SoftPC 2.51 architecture

The version of SoftPC we got to run is 2.51, which happened to be compatible with the “Classic”-type 68000 Macintosh computers, one which M.A.C.E. aims to emulate in the Phase 1. That is, it works on 68000 processor, supports the 1-bit “classic” QuickDraw on 512×342 screen, and appears to be compatible with System 6 level Toolbox calls.

The IBM PC architecture which SoftPC 2.51 emulates is IBM XT with 640 kilobytes of RAM, and a CGA monochrome display. It also supports two serial ports (although M.A.C.E. serial port drivers are still unfinished to try them out), a printer port (no printing support for us yet), two hard drives (through disk images), and two physical floppy drives (which we don’t either emulate yet).

The XT memory map

The challenging part of getting SoftPC to work was ingenious way it emulates the PC memory map. As everybody knows, IBM PC has physically 20-bit addressing scheme (through 16-bit segment and offset register pairs, which give 4+16 bits of usable virtual address space, as there is overlap between segments). This 20 bits equals 2^20 = 1048576, or 1 megabyte of address space. What SoftPC does, is that it allocates this entire 1 megabyte area to be linearly accessible throughout the physical Macintosh address space, but it saves memory by allowing this area to have “holes” in it for the non-used areas of the PC memory map. This is basically the layout it creates:

  • 000000-09FFFF: RAM
  • 0A0000-0B7FFF: hole
  • 0B8000-0DDFFF: CGA video memory
  • 0DE000-0EFFFF: hole
  • 0F0000-0F4FFF: ROM BIOS #1
  • 0F5000-0FDFFF: hole
  • 0FE000-100000: ROM BIOS #2

The steps it uses to ensure this linear layout is created is quite unique, and a good challenge to test the memory manager implementation:

  1. For starters, the availability of large enough linear memory space is ensured by doing allocation of 1048576+32 bytes of memory using NewPtr. If this fails, it will know that there won’t be enough memory.
  2. The allocated space is shrunk down to the 640K+32 RAM size using SetPtrSize. (The 32 bytes extra is used for aligning the actual addresses inside allocations to 16-byte boundaries for apparently memory access speed optimization on later Macs).
  3. The three other blocks (CGA memory and two ROM areas) are allocated at correct locations using the following algorithm:
    1. The size of “hole” preceding the allocation is calculated. For example, having video memory at B8000 would leave 18000 bytes space between A0000 and B8000.
    2. Two pointers are allocated after each other using NewPtr: one for the hole (using calculated hole size), and the actual memory block (+32 bytes for alignment).
    3. Now this is where the magic happens: If the latter allocated block’s start would not be within alignment range of the required offset (in CGA case B8000) from start of RAM (the 640K block), the size of hole would be decremented with 16 bytes, the two blocks would be disposed, and allocation re-attempted at step 3-2.
    4. After repeating steps 3-2 through 3-3 enough so that required range is reached, the pointer to the allocated hole block is saved, and next one of the three blocks is allocated starting from step 3-1. (It should be noted, that because of a very minor bug in M.A.C.E. memory manager, the allocation size failed to decrease, and this loop would be terminated after 64 attempts, with incorrect block left allocated.)
  4. After all three blocks have been allocated at correct offsets, the holes preceding each of them would be disposed using DisposePtr. This part of process leaves space inside the emulated PC address space, which the Toolbox can use for any regular memory allocations – pointers and handles, even resources. It is not 100% certain, but it may be that SoftPC may optimize performance in such way, that writing to PC address space at these holes might actually even cause native memory to get corrupted, BUT for now we did not try to see if that might happen.

The issue with Memory Manager in step 3-4 was, that as the DisposePtr call on the two blocks actually creates two adjacent “free” blocks, the allocation of new block using NewPtr right after that with only 16 bytes smaller size, would actually not return a physical block with smaller size. This was, because the block allocation routine checks if the space between allocated and next block would be less than minimum allowed block size (for creating new “free” block between allocation and next block), it would actually merge that small bit of space back to the physical allocation. The bug in Memory Manager was, that the when allocating block in free space, it was supposed to always merge the next “free” block after the allocation, and slice the new “free” space from that. A real Mac merges only one extra “free” block after allocation, but in M.A.C.E. for simplicity we fixed this by merging all free space in one run, thus at the same time reducing clutter of having many adjacent free blocks.

With this fix in Memory Manager, SoftPC is now finally able to boot up. Thanks to the Standard File Package implemented earlier this autumn, we could not only configure the hard disk image (C:/), but also set up a “shared” network disk (E:/) through a folder inside emulated Mac file system. This allows easy access of files (and thus DOS applications) from the M.A.C.E. file system, including some games. The shared disk access routines, however, surfaced luckily a couple File Manager bugs, related to the ioNamePtr handling in _GetCatInfo and _GetFileInfo calls, which possibly also improve compatibility of other applications too.


Below are some screenshots of the configuration dialogs of SoftPC (click for larger image):

And here is DIR command output right after booting up:

Also, there was GWBASIC included with the DOS installation, so we can run GWBASIC compatible BASIC programs:

And also some games work nicely. The Monochrome CGA emulation has interesting approach of emulating the 320×200 resolution with 1.5x scaling as 480×300 pixel bitmap display. The four CGA colors are also mapped into distinct vertical stripe patterns, which might also have been used on some old monochrome CGA displays:

Of the two above games, SOPWITH appears to be quite responsive and playable, but ALLEYCAT controls are very laggy. Also Sierra adventure games seem to run:

The Black Cauldron (pictured above) seems to work just fine, although for some reason the function keys were not working, while they did work in GWBASIC earlier (opening of doors with F6, for example). Also, none of the games produced any sound although the SoftPC boot beep works, so it might be that SoftPC may lack actual PC speaker emulation in this particular version (beyond the beep).

Other issue that we also fixed while working on this was a bug in Scrap Manager, which caused the clipboard to misbehave when working in “on-disk” mode (after _UnloadScrap was called). This allows Copy-Paste operations to work nicely in SoftPC, and it also improves clipboard functionality in other applications.

Only remaining issue with SoftPC is that some routine, possibly in SANE and most likely related to converting PC date & time, is causing divide overflow error to popup at random times, which appears to be related to the actual date & time. This needs to be investigated still at later point.

Full list of changes since last post

2019-11-27 00:34:43 +0200 • Fix a Scrap Manager bugs, fixes SoftPC copy+paste 
2019-11-26 23:06:55 +0200 • Fix ioDirFlag to be 4 which appears to be correct 
2019-11-26 23:06:27 +0200 • Don't crash on invalid zone in Handle validation  
2019-11-26 04:01:31 +0200 • Fix register-based 68k->native UPP calls' D0 nuke 
2019-11-26 03:57:20 +0200 • Don't overwrite *ioNamePtr if not indexing files  
2019-11-22 03:41:15 +0200 • Add FREMS selector to SANE's FP68K dispatcher     
2019-11-22 03:40:22 +0200 • Force merge of free blocks at end of BlockFindSize
2019-11-19 22:59:13 +0200 • Fix bug where everything left of a list got erased
2019-11-19 22:55:27 +0200 • Redraw modified cell in LSetCell                  
2019-11-19 01:42:03 +0200 • Add support 23 new native 68k exception handlers  

Bug fixing & stabilization

Since the previous update, focus has been mostly on improving the compatibility and stability of existing test applications through debugging, bug fixes and finishing some partially implemented features. This has so far had mostly effect on Excel, THINK Pascal and Fokker Triplane Flight Simulator:

Microsoft Excel 3.0 progress

Seems that Excel was complaining the out of memory error only because it could not locate the ‘PACK’ 6 resource (IntlUtils package). Adding a ‘PACK’ wrapper resource to System file, in similar fashion to the one which was added earlier for ResEdit as ‘PACK’ ID = 0, allowed this check to pass. After that a couple of new IntlUtils selectors were needed, with a couple file manager tweaks, and now Excel is able to start up successfully (albeit with a alert about not finding Excel, which can be passed).

It seems that a lot of tools and features are already functional, including basic worksheet creation, cell selection/modification, shape drawing, basic formatting etc. However, the most important feature, text input to allow entering data to worksheet cells, still requires TEDispatch to be implemented.

THINK Pascal 4.0 progress

One application which surfaced a lot of bugs and issues was THINK Pascal 4.0, here’s a rough summary of the issues found & ‘fixed’:

  • Reallocation of resources was not working properly in ChangedResource. Resource Manager did not save & restore active resource entry when measuring space available between current and next resource, which caused the new resource allocation in growth case to end up in wrong resource entry in the map (the next one was reallocated instead of current).
  • Removing name was attempted even if no name existed, causing resource names to get corrupted
  • RmveResource was not offsetting the types properly when removing the last instance of a given type.
  • The internal routine RGetResourceCount was trashing the resource entry pointer in resource manager’s stack state, causing some resources to be skipped altogether in iteration.
  • SetHandleSize was allowing locked blocks to move during the operation, which was explicitly told in Inside Mac documentation would not happen. This bug caused sometimes locked memory to move, with dereferenced pointers becoming invalid, causing crash during pascal code compilation.
  • A very rough approximation of MoveHHi was added. It works well enough to allow THINK Pascal to move resources out of the way to not prevent heap fragmentation from growing size of locked handles – but still causes sometimes fragmentation enough to surface this issue. However, this is for now enough to get the projects compile roughtly 2 to 3 times in one session before memory fragmentation kicks in and crashes the compiler.
  • The resource copy phase of THINK Pascal surfaced a bug in CountResources/GetIndResource, where CurMap was used instead of TopMap (CurMap should only be used when operating on 1-deep versions of the calls, Count1Resources/Get1IndResource). With this fix, the resource file copy phase succeeds.
  • Using “Transfer” command in THINK Pascal can be used to launch another app – in most cases, the application that was just compiled. However, the application zone teardown was – and still is – largely unfinished, having a number of issues. One that was fixed, was that resource manager attempts to release and purge all font caches with allocations in the application zone, which would be invalid upon launching the new program.
  • GetScrap trap had a minor issue, in which the case of hDest being nil it would crash, instead of just returning the scrap size as it was supposed to. This fixes the clipboard to (almost) work in THINK Pascal.

Now even a bit more complex programs can be compiled using THINK Pascal, for example one of Toni’s old games from as early as 1998. However, there are still minor glitches in various places:

  • Sometimes clipboard operation does not work on the first attempt.
  • Replacing existing application with “Build application” & replace dialog does not yet work because _Delete trap is still unfinished.
  • Sometimes text editing has very tiny minor selection glitches (when doing “Search again” in source code, where previous hit was selected and visible in area which was scrolled only little up, the old selection is left on when highlighting the new one).
  • Because resource map compaction is (still) unfinished, each time resources are updated and/or written in resource files, the file size grows indefinitely (by size of modified resource).
  • Compiling only works a couple times (2-3) on large projects, before heap fragmentation crashes the compiler.
  • The “Go” option does not yet work, because when running applications inside the THINK Pascal IDE, it does not actually launch a separate applications process for it. Instead, it loads the application “on top” of the pascal IDE, and in order to do this, it wraps a lot of its handlers to toolbox routines, and to do this, it manipulates the trap tables directly. This however assumes the toolbox trap table is located at 0xC00 on mac plus (0x75)-type machine, while it is currently located at 0xE00 (later machines). Because some currently used low memory globals overlap this area in non-compatible ways (for example, cursor device), they need to be adjusted a bit to behave differently on “Classic” type environment (like on real Mac Plus), and other way on later (slot-based / color-QD) environment.

Fokker Triplane Flight Simulator

It seems that the only issue causing Fokker Triplane to freeze upon starting new game was actually the lack of low-level interrupt handler emulation. The game attempted to override system VBL handler by adding its own VBL interrupt handler in the Lvl1DT low memory area containing the list of VIA’s Level 1 interrupt handler table, and as it was never called, caused the lock-up. The VBL, and 1-second timer, have now proper handlers in this low memory area, which is checked upon triggering the emulated VBL interrupt. This also includes the familiar performance optimization, where unpatched handlers skip the MixedMode interface with direct method call. It seems that with this change, the game is now fully playable with sound effects (although not thoroughly tested).

Full list of changes since last post

2019-11-16 04:08:45 +0200 • Lowlevel VIA interrupt handler for Fokker Triplane
2019-11-13 03:50:11 +0200 • Tweak SndNewChannel to not crash ResEdit          
2019-11-09 09:03:38 +0200 • Dummy OpenDeny/OpenRDeny (=>paramErr for local FS)
2019-11-09 07:51:53 +0200 • Workaround for mapping wideOpen Rgn in DrawPicture
2019-11-09 07:49:02 +0200 • Move File Manager commands to separate module     
2019-11-09 07:47:37 +0200 • Move SoundDriver test code to separate module     
2019-11-09 02:29:58 +0200 • Add dummy BitMapRgn trap for aWorm                
2019-11-06 05:40:10 +0200 • Respect port clipRgn in CopyBits                  
2019-11-06 04:31:42 +0200 • Fix edge cases in UnpackBits                      
2019-11-04 21:32:35 +0200 • If GetScrap argument hDest = nil, return only size
2019-11-04 11:31:38 +0200 • Clear font caches when closing res file w/ fonts  
2019-11-04 04:16:41 +0200 • Add IUMagString & improve Transliterate for Excel 
2019-11-04 03:09:38 +0200 • Fix Count…/GetIndResource to begin at TopMap    
2019-11-04 02:15:21 +0200 • Add memLockedErr enum missing from previous commit
2019-11-04 02:14:56 +0200 • (HACK) MoveHHi added - works, but not as in specs!
2019-11-04 02:12:08 +0200 • Fix SetHandleSize for locked blocks (don't move)  
2019-11-04 02:06:36 +0200 • Fix tail check in the zone check                  
2019-11-04 02:04:53 +0200 • Fix name allocation in AddResource                
2019-11-04 02:03:14 +0200 • StdFile: No "New folder" button in old dialogs    
2019-11-03 05:53:37 +0200 • More verbose heapcheck & optional free space debug
2019-11-02 18:13:37 +0200 • Fix possible TextEdit calibration memory move bug 
2019-11-02 17:40:30 +0200 • Fix resource map validation for maps with no names
2019-11-01 17:55:35 +0200 • Add dummy cstr2dec and pstr2dec selectors in Pack7
2019-11-01 17:54:15 +0200 • Don't trash ResourceEntry ptr in RGetResourceCount
2019-11-01 02:30:02 +0200 • Dummy IUMagWString & Transliterate(Text) for Excel
2019-11-01 00:43:41 +0200 • Add 'PACK' 3,4,5,6&7 mapping (Excel now starts up)
2019-10-31 21:33:21 +0200 • Resource fork compact placeholder code            
2019-10-31 01:01:48 +0200 • Fix RmveResource offset bug at last item of a type
2019-10-30 21:56:35 +0200 • Don't try to remove name if entry doesn't have one
2019-10-30 21:55:55 +0200 • Add map checks to Resource Manager calls for debug
2019-10-30 04:54:54 +0200 • Fix reallocation of resource in ChangedResource   

Continuum + two other new apps & bundle write support

It’s not that long since the previous news update, but there are a couple changes that are especially important:

Application bundle writable file system support

One problem with the app bundles was that by nature, their contents have read-only privileges to prevent unwanted modifications. However, as the emulator’s virtual filesystem needs to be able to not only create new files, but also modify existing ones (such as highscore saving in ZeroGravity and Continuum), using the files directory from inside the app bundle was not suitable.

To make the virtual file system writable, the emulator now relocates it to a safely writable location at /Users/<username>/Library/Application Support/MACE/<application-name>/vfs. This has a couple of neat features:

  • On every launch, any original files which are either not present or zero-length are copied from the app bundle to the writable location. This includes the initial launch, during which the entire filesystem gets replicated there.
  • Holding down the “Shift” key performs a “soft-reset” of the writable filesystem, meaning that all originals files are replicated even if they exist already in the writable filesystem. This is handy in cases if the original system or application files get damaged and would cause the emulation to fail to start. NOTE: There is not yet any prompt when performing the “soft-reset”, but there is plan to add a confirmation dialog (including a option for “hard-reset” feature) later at some time.
  • Any files modified or saved by user are fully accessible through this folder in AppleDouble format, which can be exchanged between applications and/or other emulators (or with appropriate conversion, real Macs).

MacOS Catalina support tweaks

As the new macOS Catalina was released recently, it was discovered that there was a unnecessary privilege used by the SDL2: It was listening to background key presses solely to track state of the caps lock key. Luckily, there was already a patch for this issue in SDL 2.0.10, so updating the SDL2 library (and adjusting some caps lock support code) fixed this problem.

(Please note that there will still be warning for unsigned applications, as to remove this Apple requires not only signing, but since 10.15 also notarization of any downloaded MacOS applications, both which require the paid Apple Developer Program membership.)

New test application: Continuum 1.04

Thanks to the personal permission by Brian Wilson, in combination with the writable bundle support we added this weekend, we have now Continuum 1.04 available as a fully functional MACE app bundle (including planet editor):

You can try the game out by visiting the downloads section. If you would like to know more about Continuum and its history, you can also visit the Continuum web page Brian Wilson has created here.

Other new test applications: Mac Concentration and GunShy 1.3

Thanks to the small fix done to the bug in SANE FP68K trap’s FMULD selector, Mac Concentration now works perfectly (it was previously stuck in game board generation loop due to the messed up multiplication results).

With the writable file system support, GunShy 1.3 is also finally feature-complete as a application bundle, as players need to be able to save & load games.

Like Continuum, these two new app bundles are available freely for trying out in the downloads section.

Full list of changes since last post

2019-10-27 07:49:25 +0200 • Relocate VFS to writable path on Mac OS X startup 
2019-10-27 04:52:17 +0200 • Update Alice, Continuum and GunShy JSON configs   
2019-10-27 04:45:56 +0200 • Adjust CapsLock check to work with new SDL version
2019-10-27 04:44:03 +0200 • Update to SDL2.0.10 to remove scary Catalina popup
2019-10-27 04:21:42 +0200 • Tweak InvalRgn/InvalRect to work better in Conti..
2019-10-26 05:17:58 +0300 • Update cmake JSON config for MacConcentration     
2019-10-26 04:25:41 +0300 • Adjust VBL routine call order for sound refresh   
2019-10-26 03:50:40 +0300 • Fix FMULD bug (param1 not assigned correctly) 

Standard File Package

It’s been quite a while since last update, which is due to combination of us being busy real-life jobs, and focusing work on this project on a monolithic feature, which in this case is nothing less than getting the Standard File Package to work!


This is list of the features which the M.A.C.E. Standard File Package emulation is currently capable of:

  • All 8 selectors for Pack3 (SFPutFile, SFGetFile, SFPPutFile, SFPGetFile, StandardPutFile, StandardGetFile, CustomPutFile, & CustomGetFile). The ones tested are highlighted, but others should work too.
  • Support for custom file dialogs (with assorted hacks to convert MFS-style dialogs, such as the “Save” dialog in MS-BASIC 2.00, to the new HFS-style format)
  • Supports both SFReply and StandardFileReply outputs
  • File listing using List Manager, which displays currently System 6-style SICNs, but with System 7.1+ style spacing (later expandable to use the real icons, when we get Desktop Manager interface)
  • Path popup menu, visually and functionally like on real System 7.x
  • Desktop folder support
  • Focus on selected items (including file list with highlight frame), alterable by mouse or tab key
  • Most of common SF key shortcuts: Clipboard shortcuts, Cmd+S (Save), Cmd+O (Open), Cmd+N (New folder), Cmd+D (Go to desktop), Cmd+Up (Go to parent), Cmd+Shift+Up (Go to root/desktop), Cmd+Down (Open folder), (Cmd+Left/Right to browse volumes not yet implemented)
  • Filename field input filtering (prevents “:” from being used in filenames, which is path separator). Also, copy-pasted filenames will be filtered with proper alert messages.
  • Most of SF items/hooks implemented:
    • Items: sfItemOpenButton, sfItemCancelButton, sfItemVolumeUser, sfItemEjectButton, sfItemDesktopButton, sfItemFileListUser, sfItemPopUpMenuUser, sfItemDividerLinePict, sfItemFileNameTextEdit, sfItemPromptStaticText, sfItemNewFolderUser,
    • Hooks: sfHookFirstCall, sfHookCharOffset, sfHookNullEvent, sfHookRebuildList, sfHookFolderPopUp, sfHookOpenFolder, sfHookLastCall, sfHookGoToDesktop
    • Not yet implemented: sfHookOpenAlias, sfHookGoToAliasTarget, sfHookGoToNextDrive, sfHookGoToPrevDrive, sfHookChangeSelection, sfHookSetActiveOffset
  • File type filtering supported, both by typeList and FileFilterProc
A GIF animation showing the progress done in the past month, from scratch to the latest version

Known issues

Although most of the Standard File Package is functional, and usable, there are still some issues left:

  • Because DirCreate is not yet implemented in NativeFS layer, FindFolder cannot create the Desktop Folder/Trash folders to the file system, thus at least Desktop Folder needs to exist to allow access to “Desktop” level in the SF dialogs. This also prevents “New folder” from actually creating the folders.
  • Eject button does not yet do anything, as the NativeFS volumes are non-ejectable
  • There are minor differences to real System 7.x style SF dialogs, for example with certain elements being a few pixels off their intended locations, and popup menu’s width not always expanding
  • Some custom dialogs don’t yet work exactly as they should, for example THINK Pascal 4.0 “Add files” dialog erases left edge of the applications own custom list located below the SF file list, and for some reason it allows attempts to add folders as source files…
  • Location of the SF dialog is sometimes not correct (for example, Railroad Tycoon’s “Save game” dialog is partially under the menu bar)
  • We cannot yet create app bundles for the currently working freeware/shareware applications that use StandardFile, because when sandboxed the bundle file system is read-only, and thus attempting to save anything to it would straight out fail. To work around this, we need to implement certain changes to the way file system in bundled applications is handled, but we are already working on that for the next release

Other improvements made for Standard File

There were a couple features that were implemented as part of Standard File Package implementation, some of which were necessary to make it work

NativeFS AVL tree balancing and iteration support

One important feature was the need for catalog iteration, which is used by Standard File dialogs to enumerate the files in current folder to be displayed in the file list. This allows for example GetCatInfo to use ioFDirIndex in the parameter block to index specific files inside given directory.

Also, this gave a good excuse to finally implement the actual AVL balancing algorithm in the NativeFS file system, which until now had behaved mostly as a dummy binary tree. Below is a screenshot of how the file system structure was changed by the balancing algorithm:

“Before” and “After” debug visualizations of the NativeFS binary tree data structure (click for larger view)

On the right-hand side, is the unbalanced “dummy” binary tree, and on left-hand side is the same file system, when using AVL balancing algorithm to do the insertions. The deepest nodes were reduced from, in this case, from way over 100+ key comparisons into a rough maximum of 10+.

Popup Menu Control

One important feature of the HFS-style Standard File dialogs is the navigation aid provided by the path popup menu. For this, the Popup Menu Control CDEF 63 was implemented. On real Macs, this was originally part of Communications Toolbox, before it was merged to the System 7.x at some point. The Standard File dialogs use only a subset of its features, but foundation for most use cases was built at the same time, so taking it into more common use should be quite easy. As it uses the Menu Manager’s PopUpMenuSelect trap call, the actual menu selection was already there.

One fun and tricky part though was the need to add MDEF “wrapper” for SF popup path menu, to ensure that the opened popup menu would never be narrower than width of the popup control. To do this, the control imitates how the real Macs did this by adding temporarily a MDEF “wrapper”, which injects modified menuWidth value to the menu after it receives a mSizeMsg message from the Menu Manager, thus modifying the resulting popup menu size.

Picture Button Control

The CDEF 61, picture button, was implemented just to allow adding the “New folder” button to the “put” dialogs. It is quite simple, at least in monochrome version, just drawing a PICT resource as content of a regular push button

Dialog Manager improvements

The StdFilter, which is also used by Standard File dialogs, was improved to add features used by it:

  • Outlining default button with FrameRoundRect
  • Handle “cancel” item’s shortcut key as escape/cmd+dot
  • Track cursor to turn it into i-beam over enabled textedit fields
  • Handle update events for default items

Also, the default shortcut keys (Cmd+X/C/V for Cut/Copy/Paste) were also implemented in DialogSelect trap.

Other news: 68020/68040 support

In other news, Pukka has also been busy adding 68020/68040 support, which includes:

  • Bitfield instructions (bfins, bfset, bftst, bfchg, bfclr, bfextu, bfffo)
  • cas2.b/w/l instruction
  • divs.l/divu.l 32-bit division instructions
  • move16 instruction for 68040
  • Disassembler support for the new and improved instructions
  • Various other improvements

Full list of changes since last post

2019-10-21 02:25:22 +0300 • GetResource falls back to TopMap if CurMap invalid
2019-10-20 23:00:18 +0300 • Fix byteswap bug in LDEF -4000 (item font & size) 
2019-10-19 21:44:23 +0300 • Update ArmorAlley JSON config, it now almost works
2019-10-19 02:18:39 +0300 • Fix _Allocate, use ioFRefNum/FCB to get the vcbPtr
2019-10-19 02:06:57 +0300 • Make MemoryManager allocation alignment adjustable
2019-10-19 01:54:24 +0300 • Fix AddResource bug, ResErr not cleared on success
2019-10-19 01:44:31 +0300 • Implemented RmveResource                          
2019-10-18 17:44:45 +0300 • Set ioFDirIndex for GetCatInfo in SF popup refresh
2019-10-18 17:21:28 +0300 • Desktop folder support improved in SFUpdateReply  
2019-10-18 17:08:07 +0300 • Show files in Desktop Folders on desktop          
2019-10-18 16:25:39 +0300 • Update StdFile Eject button enable/disable state  
2019-10-18 03:39:11 +0300 • Close app resource file on exit from emulator     
2019-10-18 03:07:05 +0300 • Draw CDEF 63 popup triangle & hack to resize menu 
2019-10-17 00:07:14 +0300 • Fix StdFile dirID byteswap bug for popup menu item
2019-10-17 00:05:13 +0300 • Rough proto of autoTrack to CDEF 63 popup tracking
2019-10-16 23:28:35 +0300 • Add sfHookFolderPopUp trigger & handler to StdFile
2019-10-16 23:27:14 +0300 • Implement testCntl in CDEF 63 (& refactor headers)
2019-10-16 22:47:54 +0300 • Merge branch 'master' of  
2019-10-16 22:47:13 +0300 • Fix popup menu creation (fix title & set icon cmd)
2019-10-16 22:45:09 +0300 • Work on CDEF 63 (draw menu in the control)        
2019-10-16 22:44:10 +0300 • Implement mDrawItemMsg in MDEF 0                  
2019-10-16 22:40:13 +0300 • fix initializing 68040 processor type and linkin..
2019-10-16 04:50:31 +0300 • Implement mCalcItemMsg in MDEF 0                  
2019-10-16 03:59:46 +0300 • Implement calculation of popup bounds in CDEF 63  
2019-10-16 03:58:56 +0300 • Make Mac_GetMenu visible in public headers        
2019-10-16 03:58:31 +0300 • Fix bugs in StdFile path popup folder iteration   
2019-10-15 02:25:13 +0300 • Work on CDEF 63 init, dispose and calc messages   
2019-10-14 21:40:29 +0300 • disassembler fixes and support for bit field ins..
2019-10-14 02:50:31 +0300 • Work on CDEF 63: Init StdFile dir popup contents  
2019-10-13 07:21:56 +0300 • Fix filename in GetFileInfo for ioFDirIndex > 0   
2019-10-12 23:57:53 +0300 • Fix old-style StdFile filelist bounds byteswap bug
2019-10-12 23:56:36 +0300 • Fix ioFDirIndex>0 case for GetFileInfo in NativeFS
2019-10-12 04:29:25 +0300 • "New folder" dialog added, and many fixes & tweaks
2019-10-12 02:09:45 +0300 • Cmd+Down in SF & fix list arrow when no selection 
2019-10-11 22:40:18 +0300 • Handle Cmd+S, Cmd+O, cmd+D and cmd+N in StdFile   
2019-10-11 22:21:15 +0300 • Fix crash in CDEF 61 dispCntl message handler     
2019-10-11 05:12:59 +0300 • Enable "new folder" button in StdFile put dialogs 
2019-10-11 05:11:37 +0300 • Implemented CDEF 61 ('PICT' button control for SF)
2019-10-11 02:44:50 +0300 • Don't try to go to the parent of Desktop          
2019-10-11 02:39:49 +0300 • Open parent with cmd+up, desktop with cmd+shift+up
2019-10-11 01:49:34 +0300 • Implement cut/copy/paste handling in DialogSelect 
2019-10-11 00:08:41 +0300 • Fix inverted zonecheck result in handle validation
2019-10-11 00:06:45 +0300 • Finish IsCmdChar implementation (& fix signature) 
2019-10-11 00:05:16 +0300 • Fix KCHR load from ROM (RomMapInsert & TmpResLoad)
2019-10-10 22:27:30 +0300 • Cache KCHR 0 in script manager expand mem globals 
2019-10-10 10:32:50 +0300 • Handle escape key in StdFilter                    
2019-10-10 10:32:26 +0300 • Add dummy IsCmdChar to ScriptUtil dispatcher      
2019-10-10 02:43:08 +0300 • Handle iBeam cursor in StdFilter null/updateEvents
2019-10-10 02:25:40 +0300 • Frame default button in StdFilter (also disabled) 
2019-10-10 01:53:25 +0300 • Handle desktop folder and related buttons         
2019-10-09 22:58:06 +0300 • Use new defines for FindFolder folders in StdFile 
2019-10-09 22:57:33 +0300 • Call DirCreate in FindFolder when createFolder set
2019-10-09 22:56:44 +0300 • Add dummy DirCreate placeholder to FSDispatch     
2019-10-09 22:55:41 +0300 • Merge branch 'master' of  
2019-10-09 22:55:37 +0300 • Fix font strike size to inRec size scale ratio    
2019-10-09 22:20:59 +0300 • disassembler support for move16                   
2019-10-09 21:54:33 +0300 • remove unused sr_bits field from instruction data 
2019-10-09 21:33:53 +0300 • finish implementing move16 instruction            
2019-10-09 21:26:06 +0300 • update xcode 6 project                            
2019-10-09 17:23:48 +0300 • Fix FindFolder memory corrupt (ioNamePtr not set) 
2019-10-09 11:16:53 +0300 • Fix byteswap bug in fld# type comparison          
2019-10-09 11:15:00 +0300 • Fix fld# search to work on non-system folder lists
2019-10-09 03:46:40 +0300 • Add linecount script                              
2019-10-09 03:46:28 +0300 • Add empty desktop/trash folders to THINK Pascal   
2019-10-09 03:32:46 +0300 • AliasManager added, to implement FindFolder for SF
2019-10-09 02:42:02 +0300 • Implemented HOpenResFile                          
2019-10-08 00:43:44 +0300 • Implement sfHookCharOffset and sHookRebuildList   
2019-10-07 21:56:21 +0300 • Found hidden ListManager selector, used by StdFile
2019-10-07 21:55:09 +0300 • Add PageUp/Down and Home/End keys to SDL keymapper
2019-10-07 04:57:10 +0300 • Use inThumb also to draw control on SetCtlMin/Max 
2019-10-07 04:55:48 +0300 • Fix wrong zero-case part code bug in HiliteControl
2019-10-07 03:16:46 +0300 • Fix ignore dot & '%'-prefix items in InsertResMenu
2019-10-07 02:19:28 +0300 • Fix memory leak in DrawPicture                    
2019-10-07 02:18:10 +0300 • Fix conversion of uncompressed pixmap data to b&w 
2019-10-06 23:37:38 +0300 • fix divs.l, start implementing move16 instruction 
2019-10-06 00:00:12 +0300 • allocate move16 instruction                       
2019-10-05 23:07:36 +0300 • fixes for divs.l/divu.l instruction               
2019-10-05 22:00:21 +0300 • Merge branch 'master' of  
2019-10-05 21:59:44 +0300 • implement chk2.b/w/l instructions                 
2019-10-05 21:57:57 +0300 • Merge branch 'master' of  
2019-10-05 21:57:22 +0300 • Fix resource name remove bug                      
2019-10-05 21:27:28 +0300 • implement cas2.w and cas2.l instructions          
2019-10-05 20:34:46 +0300 • finish cas.b/w/l instruction implementation       
2019-10-05 04:50:14 +0300 • Fix bug in FindWindow (theWindow not initialized) 
2019-10-05 04:10:11 +0300 • Merge branch 'master' of  
2019-10-05 00:11:35 +0300 • make bsr instruction branchless                   
2019-10-04 23:43:40 +0300 • THINK Pascal def missing from root CMakeLists.txt 
2019-10-04 23:25:35 +0300 • register variants for bfins, bfset and bftst      
2019-10-04 23:05:14 +0300 • remove unused c16 param from bfxxx_read/write     
2019-10-04 22:42:22 +0300 • use read_pc_immediate for bit field extension     
2019-10-04 22:30:25 +0300 • fixes for bit field instructions                  
2019-10-04 01:06:20 +0300 • Add THINK Pascal 4.0 test app JSON config to CMake
2019-10-04 01:06:00 +0300 • Implemented MaxSizeRsrc                           
2019-10-03 22:25:37 +0300 • Reinforce fake handle handling in memory manager  
2019-10-03 22:21:15 +0300 • bfchg, bfclr, bfext, bfextu and bfffo instructio..
2019-10-03 22:09:06 +0300 • Revert "bfchg, bfclr, bfext, bfextu and bfffo in..
2019-10-03 22:08:15 +0300 • bfchg, bfclr, bfext, bfextu and bfffo instructio..
2019-10-03 04:04:45 +0300 • Escape MacRoman filenames & avoid UTF8 conversions
2019-10-03 00:27:19 +0300 • SF key filtering (max length, skip ':' & CR, etc.)
2019-10-03 00:26:24 +0300 • Support "autoKey" in keyboard and platform modules
2019-10-02 02:55:34 +0300 • Handle tab key in SFDialogFilter                  
2019-10-02 02:14:00 +0300 • Tweak list ListManagerClickTrackProc visible size 
2019-10-02 02:00:26 +0300 • Fix missing sfHookLastCall set on SF dialog close 
2019-10-02 01:58:50 +0300 • Escape characters in NFS (and fix full-path bug)  
2019-10-02 00:08:29 +0300 • Adjust Art Class JSON to use 68020 machine config 
2019-10-02 00:07:57 +0300 • Update SF reply records during event loop         
2019-10-02 00:07:24 +0300 • Handle invalid names and replace in "save" dialogs
2019-10-02 00:05:56 +0300 • Reduce keyboard debug logging                     
2019-10-01 22:34:26 +0300 • Fix missing origName in SFPutFile                 
2019-10-01 22:06:24 +0300 • Merge branch 'master' of  
2019-10-01 22:06:17 +0300 • Tweak Gestalt and fix M68kHelper for 68020 support
2019-10-01 21:35:17 +0300 • kemu header cleanup                               
2019-10-01 21:33:14 +0300 • update xcode6 project                             
2019-10-01 20:38:00 +0300 • 020 bit field instructions, optimizations, some ..
2019-10-01 17:01:23 +0300 • First successful "open" from Standard File        
2019-10-01 15:37:53 +0300 • Missing header update for no-read privilege flag  
2019-10-01 15:37:03 +0300 • Add missing part of previous LayerDispatch fix    
2019-10-01 15:36:20 +0300 • Handle cancel button & implement closing dialogs  
2019-10-01 15:20:57 +0300 • Handle opening of folder in file list             
2019-10-01 15:20:00 +0300 • Don't hilite disabled items in file list lDrawMsg 
2019-10-01 14:58:06 +0300 • Error dialog support for Standard File            
2019-10-01 14:57:19 +0300 • Add some more TODOs to StdFilter proc             
2019-10-01 14:56:52 +0300 • Fix bug in AutoPositionWindow lcParentWindow case 
2019-10-01 13:42:47 +0300 • Fix redraw bug in file list item selection        
2019-10-01 13:40:58 +0300 • Detect when a folder is opened instead of file    
2019-10-01 13:39:08 +0300 • Fix accidental file list framing in "Get" dialogs 
2019-10-01 03:24:36 +0300 • Update save/open button state (and title)         
2019-10-01 01:21:11 +0300 • Add Desktop Folder and Trash to TeachText config  
2019-10-01 01:20:45 +0300 • Add empty folder creation support to make.cmake   
2019-10-01 01:06:51 +0300 • Go to parent folder by clicking volume name       
2019-09-30 02:06:23 +0300 • Handle more events in SF(update, activate & mouse)
2019-09-30 02:02:42 +0300 • Fix byteswap bug in FindDialogItem                
2019-09-29 03:39:31 +0300 • SF activation handling: set reply & frame filelist
2019-09-29 03:35:48 +0300 • Fix more maxIndex bugs in LGetSelect and LSearch  
2019-09-28 03:54:21 +0300 • Add file type filtering & call custom file filters
2019-09-28 03:53:38 +0300 • Fix bug in Standard File dialog autopositioning   
2019-09-28 03:28:31 +0300 • Fix SF special folder detection bytes-wap bug     
2019-09-28 03:27:37 +0300 • Fix ioDrDirID for folders in GetCatInfo           
2019-09-28 03:08:52 +0300 • Handle list clicking in SF dialog event handler   
2019-09-28 03:08:12 +0300 • Fix maxIndex case in LClick selection clearing    
2019-09-28 03:07:09 +0300 • Set mouseLoc in ListRec in LClick                 
2019-09-28 03:05:32 +0300 • Fix ioDirFlg setup in GetCatInfo                  
2019-09-28 01:59:31 +0300 • Re-enable EraseRect calls in SF dialog item redraw
2019-09-28 01:57:24 +0300 • Fix ioNamePtr handling in GetCatInfo              
2019-09-28 01:56:01 +0300 • Draw volume icon & name in Standard File dialogs  
2019-09-27 15:40:16 +0300 • Finalize LDEF -4000 drawing for standard file list
2019-09-27 15:38:52 +0300 • Fix file type mapping bugs in standard file pack  
2019-09-27 15:37:44 +0300 • Add Scratch20 low memory global                   
2019-09-27 04:21:58 +0300 • First real filelist shown in Standard File Dialogs
2019-09-26 22:56:17 +0300 • Add balancing algorithm to the AVL tree (+debug)  
2019-09-26 22:54:32 +0300 • Add missing header from previous commit           
2019-09-26 22:53:19 +0300 • Finish volume/directory setup in SF initialization
2019-09-26 11:30:42 +0300 • Reset to VCBQHdr after last VCB in SF volume scan 
2019-09-26 04:06:05 +0300 • Work on volume state initialization in SF package 
2019-09-26 04:03:16 +0300 • Tweak FMGetDrive to allow passing nil driverRefNum
2019-09-26 04:02:01 +0300 • Support GetVolInfo calls with drvNum as vRefNum   
2019-09-26 04:01:13 +0300 • Add four flag bytes in front of DrvQEl in NativeFS
2019-09-25 04:33:14 +0300 • Set default SF volume&folder to application folder
2019-09-25 04:11:00 +0300 • Add indexing to GetCatInfo + fetch real ioDrNmFls 
2019-09-25 04:09:38 +0300 • Add rough iteration support to file system AVLTree
2019-09-22 13:09:58 +0300 • Refresh file list in StdFile dialogs              
2019-09-22 05:17:32 +0300 • First StdFile dialogs visible, not yet functional 
2019-09-22 05:15:58 +0300 • Support opcodes 0x12, 0x13 and 0x14 in pictures   
2019-09-22 04:41:36 +0300 • More progress on StdFilePack                      
2019-09-22 04:39:36 +0300 • Minor List Manager fixes and tweaks               
2019-09-22 04:37:15 +0300 • Placeholder for popup CDEF (63)                   
2019-09-19 23:06:31 +0300 • Finalize CheckWindow selector for LayerDispatch   
2019-09-19 03:25:17 +0300 • More work on Standard File Package                
2019-09-19 03:23:39 +0300 • Add two new selectors to LayerDispatch for StdFile
2019-09-18 03:58:15 +0300 • Some work on Standard File Package                
2019-09-18 03:54:32 +0300 • Use _RelString in IUMagIDString for now           
2019-09-13 01:48:34 +0300 • Mac OS X 10.6.8 compatibility                     
2019-09-11 21:30:30 +0300 • Enable GetNextEvent CPU throttle for Arkanoid     
2019-09-11 18:25:41 +0300 • Add Crystal Quest and Armor Alley test apps       
2019-09-09 01:31:04 +0300 • Bump up runtime version for new bundles           
2019-09-09 00:58:48 +0300 • Tweak IAGO cmake config                           
2019-09-07 14:04:32 +0300 • Add two more test app configs, IAGO and EveryMan 1
2019-09-07 14:04:02 +0300 • Add substitution for missing fonts in Font Manager