• Updated 2023-07-12: Hello, Guest! Welcome back, and be sure to check out this follow-up post about our outage a week or so ago.

[C programming] Gracefully force 1-bit graphics in a wide ranging selection of 68k macs

Mu0n

Well-known member
Black and white compact macs targetting mostly 512x342 in 1-bit color depth field

BUT

-must not crash if a more recent machine is used
-System 7.5.5 is the most recent that I target
-When possible and not too feature rich, System 1.1 on a 400k MFS disk should run my stuff
-must gracefully center the image if a higher res is used
-must deal with color depth field if it's detected but still use 1-bit gfx data
-must deal with gracefully using graceful detection routines
-great if a Mac128 runs it, but not a big deal if not.
-great if a Mac512 runs it, it should in theory but I don't own one.
-Mac Plus is the natural main target that I can easily test out on real metal



Here's what my current checklist algorithm does. Suggestions and warnings about omissions are very welcome:

Step 1:
Declare a SysEnvRec (system environment record)
Fetch information using SysEnvirons( )
If the mac environment (machine and system/finder) is too old, it should return an error code but that's probably good, since you can expect 1-bit depth in this case. No need to deal with color depth modes!
If the mac environment is too new, then the record returned will be too big, and I still have to figure that out. Maybe a non-issue if I cap things to Sys 7.5.5.
If it's just right, then I can safely declare that if the record's systemVersion is less than 6.0.4 ( less than 0x0604) and/or the machineType record is less than 0, then 1-bit depth is guaranteed (right?)

Step 2:
If 6.0.4+ is here or if the machine isn't old, then the next step that should work is to use Gestalt( )

if an error is reported, then I think it's safe to assume that the program weaved between the cracks and is a 1-bit depth mac (right?)
if a report is obtained, then gestaltQuickdrawVersion is checked and if it is gestaltOriginalQD, then it's 1-bit
if it's not, then you have to deal with PixMap structures in GDHandle where you've fished out the pixelDepth Go to step 3b

Step 3a: if 1-bit
Use qd.thePort and plug your 1-bit depth gfx happily in the screen bitmap, offscreen bitmaps


Step 3b: if not 1-bit
Use GDHandle, assign it GetNextDevice (it gets more complicated if you want to plan for multiple screen, but eesh, no thanks)
get the pixel depth with:

PixMapHandle screenPMH;
short pixelDepth;

screenPMH = (**(theDevice)).gdPMap;
pixelDepth = ((**screenPMH)).pixelSize;
and make sure your 1-bit graphics gracefully insert themselves in the right spots of the higher structure color bitmaps...or ask the user to switch to monochrome mode.
 

Crutch

Well-known member
I have some thoughts here but can you clarify your exact goal? Are you just trying to avoid using CopyBits to blit a 1-bit bitmap for speed or something?
 

Crutch

Well-known member
Anyway, is there a reason you can’t just check to see if _GetNextDevice is unimplemented? If it is, you have a 1-bit Mac. If it’s not, check the pixelSize of the device of your choice.
 

Mu0n

Well-known member
Yes, but thanks for reminding me that CopyBits steamrolls the bit depth in during the copy. I may not stick with CopyBits in all cases, though. It's perfect for slow applications though. This worked nicely under various conditions in Basilisk II and I get a nice monochrome image pasted in from an unpacked MacPaint image first copied to an offscreen BitMap.

Is the _GetNextDevice implementation test exhaustive enough for all System versions?
 

cheesestraws

Well-known member
The SysEnvirons and Gestalt dance seems very complicated to me when you could test directly for the existence of _Gestalt?

But yes, if all you want is to check 1-bitness, @Crutch's solution seems neatest.

Is the _GetNextDevice implementation test exhaustive enough for all System versions?

Yes. If _GetNextDevice is unimplemented, you are definitely running on a 1-bit machine. And if it is, it will tell you itself what the bit depth is.
 

Mu0n

Well-known member
But that covers what's every system version between the first and 6.0.3 (or under 6.0m4), so it's not exhaustive, meaning I don't catch every situation where I can comfortably not have to deal with color pixel depth.

Edit: oh wait, that's for Gestalt
 

Crutch

Well-known member
Right, so if indeed all you want to do is to the bit depth in a way that should work will all machines, pretty sure the the “right” way to do that is to check for the existence of _GetNextDevice. If it’s implemented, get the bit depth. If it’s not, you’re already on a 1-bit machine. Easy peasy.

An even easier way that till work 99.9999% of the time is to check whether screenBits.bounds is 512 x 342. If it is, pretty sure you have a 1-bit machine unless you are worried about running on a Macintosh XL. Graphics devices/slots/external monitors and color were all introduced at the same time.
 

cheesestraws

Well-known member
But that covers what's every system version between the first and 6.0.3 (or under 6.0m4), so it's not exhaustive, meaning I don't catch every situation where I can comfortably not have to deal with color pixel depth.

Either I'm missing something here or you are, and I'm not sure which. Let's see if we can work out which :). I think you're confusing "check whether _GetNextDevice exists" and "call _GetNextDevice". Does this make it clearer?:
  • As soon as colour devices became available, it became possible to query a device for how many colours it supported, for obvious reasons.
  • So, if you cannot query a device at all, you are on a black and white machine, because that feature wasn't necessary until colour came in.
  • Querying a device for its information is what _GetNextDevice is for.
  • You can check for whether the _GetNextDevice trap is present regardless of OS version. Use GetTrapAddress to find out whether it exists or not. GetTrapAddress is there all the way back.
  • If it is present, you can call it and just check. This branch will work on all colour-capable machines.
  • If it is not present (if it points to _Unimplemented), then you know you're in monochrome. This will work on everything else, regardless of OS version.
This covers all OS versions, and is much better because instead of testing for an OS version, it checks to see whether a behaviour is actually there or not. It's always better to check specifically for what you're trying to do, rather than trust a version number.
 

Mu0n

Well-known member
It's all good, comparing _Unimplemented to a trap name you want to check is something I read a few days ago while I jumped around in the excellent vintageapple.org collection of programming books. I'm glad it's that easy for my purpose!

Thanks guys.

Also if a MacXL user gets an error due to my code, then nothing will happen because they are already so lucky to own that rare piece of hardware, they can stomach getting a few compatibility error here and there. HA!
 

Crutch

Well-known member
(correcting my slightly unclear suggestion above: if the screenBits.bounds is 512x342, then you are running in 1-bit mode … if not, either (1) color QuickDraw and _GetNextDevice etc. will be available, or (2) you are running on a Mac XL … which by the way you can check for with the legacy _Environs trap, if you are worried about it!)
 

Crutch

Well-known member
By the way I highly recommend THINK Reference. If you have it, search for “About Compatibility” for detailed sample code including checking for unimplemented traps in a ridiculously thorough way.
 

cheesestraws

Well-known member
+1 for THINK Reference. If you're using a more modern set of headers, the Apple Toolbox Assistant is also handy. It's not as good as THINK Reference by a long chalk, but it is newer, and sometimes it's good having two independent explanations of what something is doing...
 

Mu0n

Well-known member
I've used THINK Reference Viewer forever, don't worry. I've seen that section last night.
 

NJRoadfan

Well-known member
Isn't the Macintosh Portable an edge case here too? It's a 1-bit machine, but has a resolution above 512x342. Also, not all early software assumes fixed resolutions. Much to my surprise, my early 1985 copy of Microsoft Multiplan opened windows that filled the Portable's whole screen by default!
 

Crutch

Well-known member
Yeah Apple encouraged checking screenBits.bounds from the very beginning.

I don’t think the Portable breaks my logic. It has a 1-bit screen but requires 6.0.4 and will, I believes, always support a call to _GetNextDevice (which will then happily tell you it’s a 1-bit machine). (When I said “if screernBits.bounds > 512x342 then color QuickDraw is available” I meant that the color QuickDraw traps and associated things can be invoked without a crash, not that the machine necessarily supports color.)
 
Top