Skip to content

Commit a055036

Browse files
committed
Icons now drawn on B&W Macs + MacsBug check
`CKHasDebugger` is added to check if Macsbug is installed before calling DebugStr, which was causing crashes on mini vMac.
1 parent 6312ec9 commit a055036

5 files changed

Lines changed: 182 additions & 29 deletions

File tree

include/ckCanvas.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,7 @@ class CKCanvas : public CKControl {
3737

3838
private:
3939
GWorldPtr __gworldptr = NULL;
40+
bool __hasQueuedIcon = false;
41+
short __queuedIconResourceId = 0;
42+
CKPoint __queuedIconWhere;
4043
};

include/ckUtils.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,5 +155,6 @@ void __CKWriteToExitFile(const char* s, ...);
155155

156156
bool CKHasAppearanceManager();
157157
bool CKHasColorQuickDraw();
158+
bool CKHasIconUtilities();
158159
bool CKHasDebugger();
159160
UInt32 CKMillis();

src/ckApp.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ CKWindow* CKApp::__CreateAlertDialog(const char* message, const char* title, con
371371
CKWindow* toReturn = this->CKNewWindow(params);
372372

373373
int labelX = padding;
374-
const bool shouldShowIcon = icon != CKSystemIcon::noIcon && CKHasColorQuickDraw();
374+
const bool shouldShowIcon = icon != CKSystemIcon::noIcon;
375375
if (shouldShowIcon) {
376376
labelX += 32 + padding;
377377
}

src/ckCanvas.cpp

Lines changed: 118 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,55 @@
1414
#include "ckCanvas.h"
1515
#include "ckWindow.h"
1616
#include <Quickdraw.h>
17+
#include <Icons.h>
1718
#include <Resources.h>
19+
#include <Memory.h>
20+
21+
static bool __CKPlotBWIcon(short resourceId, const Rect& destRect, const WindowPtr window) {
22+
23+
Handle iconHandle = GetResource('ICN#', resourceId);
24+
bool hasMask = true;
25+
if (!iconHandle) {
26+
iconHandle = GetResource('ICON', resourceId);
27+
hasMask = false;
28+
}
29+
30+
if (!iconHandle) {
31+
CKLog("Resource %d not found.", resourceId);
32+
return false;
33+
}
34+
35+
HLock(iconHandle);
36+
const UInt8* data = (const UInt8*)*iconHandle;
37+
38+
const UInt8* maskData = hasMask ? data : nullptr;
39+
const UInt8* iconData = hasMask ? data + 128 : data;
40+
41+
BitMap srcBM;
42+
srcBM.baseAddr = (Ptr)iconData;
43+
srcBM.rowBytes = 4;
44+
SetRect(&srcBM.bounds, 0, 0, 32, 32);
45+
46+
const BitMap* dstBits = &(window->portBits);
47+
48+
Rect srcRect = srcBM.bounds;
49+
Rect dstRectCopy = destRect;
50+
51+
if (hasMask) {
52+
BitMap maskBM;
53+
maskBM.baseAddr = (Ptr)maskData;
54+
maskBM.rowBytes = 4;
55+
SetRect(&maskBM.bounds, 0, 0, 32, 32);
56+
Rect maskRect = maskBM.bounds;
57+
CopyMask(&srcBM, &maskBM, dstBits, &srcRect, &maskRect, &dstRectCopy);
58+
} else {
59+
CopyBits(&srcBM, dstBits, &srcRect, &dstRectCopy, srcCopy, NULL);
60+
}
61+
62+
HUnlock(iconHandle);
63+
ReleaseResource(iconHandle);
64+
return true;
65+
}
1866

1967
CKCanvas::CKCanvas(const CKControlInitParams& params)
2068
: CKControl(params, CKControlType::Canvas) {
@@ -24,7 +72,7 @@ CKCanvas::CKCanvas(const CKControlInitParams& params)
2472
this->__gworldptr = NULL;
2573

2674
if (!CKHasColorQuickDraw()) {
27-
CKLog("CKCanvas requires Color QuickDraw; offscreen drawing disabled.");
75+
CKLog("Color QuickDraw not available; offscreen drawing disabled (drawing directly to window).");
2876
return;
2977
}
3078

@@ -55,7 +103,47 @@ void CKCanvas::Redraw() {
55103
return;
56104
}
57105

106+
// No offscreen buffer – draw directly into the window (mono fallback).
58107
if (!this->__gworldptr) {
108+
if (!this->__hasQueuedIcon) {
109+
return;
110+
}
111+
112+
GrafPtr oldPort;
113+
GetPort(&oldPort);
114+
SetPort(this->owner->GetWindowPtr());
115+
116+
short top = this->rect->origin->y + this->__queuedIconWhere.y;
117+
short left = this->rect->origin->x + this->__queuedIconWhere.x;
118+
Rect destRect = {(short)top, (short)left, (short)(top + 32), (short)(left + 32)};
119+
120+
const bool hasIconUtils = CKHasIconUtilities();
121+
const bool hasColorQD = CKHasColorQuickDraw();
122+
123+
if (!hasColorQD || !hasIconUtils) {
124+
if (!__CKPlotBWIcon(this->__queuedIconResourceId, destRect, this->owner->GetWindowPtr())) {
125+
this->__hasQueuedIcon = false;
126+
}
127+
} else {
128+
129+
CIconHandle cIconHandle = GetCIcon(this->__queuedIconResourceId);
130+
if (!cIconHandle) {
131+
Handle iconHandle = GetIcon(this->__queuedIconResourceId);
132+
if (!iconHandle) {
133+
CKLog("Resource %d not found.", this->__queuedIconResourceId);
134+
this->__hasQueuedIcon = false;
135+
SetPort(oldPort);
136+
return;
137+
}
138+
PlotIcon(&destRect, iconHandle);
139+
ReleaseResource(iconHandle);
140+
} else {
141+
PlotCIcon(&destRect, cIconHandle);
142+
DisposeCIcon(cIconHandle);
143+
}
144+
}
145+
146+
SetPort(oldPort);
59147
return;
60148
}
61149

@@ -74,7 +162,7 @@ void CKCanvas::Redraw() {
74162
return;
75163
}
76164

77-
Rect destRect = {this->rect->origin->x, this->rect->origin->y, (short)(this->rect->size->height + this->rect->origin->y), (short)(this->rect->size->width + this->rect->origin->x)};
165+
Rect destRect = {(short)this->rect->origin->x, (short)this->rect->origin->y, (short)(this->rect->size->height + this->rect->origin->y), (short)(this->rect->size->width + this->rect->origin->x)};
78166
Rect srcRect = {0, 0, (short)this->rect->size->height, (short)this->rect->size->width};
79167

80168
CopyBits((BitMap*)&(**offscreenPixMap),
@@ -198,7 +286,20 @@ void CKCanvas::DrawLine(CKPoint start, CKPoint end, CKColor c) {
198286

199287
bool CKCanvas::DrawResourceIcon(short resourceId, CKPoint where) {
200288

289+
this->__hasQueuedIcon = true;
290+
this->__queuedIconResourceId = resourceId;
291+
this->__queuedIconWhere = where;
292+
201293
if (!this->__gworldptr) {
294+
if (this->owner) {
295+
this->MarkAsDirty();
296+
}
297+
return true;
298+
}
299+
300+
if (!CKHasIconUtilities()) {
301+
CKLog("Icon Utilities unavailable; cannot draw icons.");
302+
this->__hasQueuedIcon = false;
202303
return false;
203304
}
204305

@@ -213,29 +314,35 @@ bool CKCanvas::DrawResourceIcon(short resourceId, CKPoint where) {
213314
GetGWorld(&oldPort, &oldGD); // Save the old port
214315
SetGWorld(this->__gworldptr, NULL); // Set the GWorld as the current port
215316

317+
const bool hasIconUtils = CKHasIconUtilities();
318+
const bool hasColorQD = CKHasColorQuickDraw();
319+
216320
CIconHandle cIconHandle = nullptr;
217321
Handle iconHandle = nullptr;
218322

219323
// Try color first.
220-
cIconHandle = GetCIcon(resourceId);
221-
bool isColor = true;
324+
if (hasIconUtils && hasColorQD) {
325+
cIconHandle = GetCIcon(resourceId);
326+
}
222327
if (!cIconHandle) {
223328
// OK, try monochrome.
224329
iconHandle = GetIcon(resourceId);
225-
isColor = false;
226330
if (!iconHandle) {
227331
CKLog("Resource %d not found.", resourceId);
332+
this->__hasQueuedIcon = false;
228333
SetGWorld(oldPort, oldGD);
229334
UnlockPixels(offscreenPixMap);
230335
return false;
231336
}
232337
}
233-
Rect destRect = {0, 0, 32, 32};
338+
Rect destRect = {(short)where.y, (short)where.x, (short)(where.y + 32), (short)(where.x + 32)};
234339

235-
if (isColor) {
340+
if (cIconHandle) {
236341
PlotCIcon(&destRect, cIconHandle);
237342
} else {
238-
PlotIcon(&destRect, iconHandle);
343+
if (hasIconUtils) {
344+
PlotIcon(&destRect, iconHandle);
345+
}
239346
}
240347

241348
SetGWorld(oldPort, oldGD); // Restore the old port
@@ -247,5 +354,8 @@ bool CKCanvas::DrawResourceIcon(short resourceId, CKPoint where) {
247354
}
248355

249356
UnlockPixels(offscreenPixMap);
357+
if (this->owner) {
358+
this->MarkAsDirty();
359+
}
250360
return true;
251361
}

src/ckUtils.cpp

Lines changed: 59 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,8 @@
1414
#include "ckUtils.h"
1515
#include <Appearance.h>
1616
#include <Gestalt.h>
17-
#include <Timer.h>
1817
#include <Quickdraw.h>
19-
20-
#ifndef gestaltQuickdrawFeatures
21-
#define gestaltQuickdrawFeatures 'qd '
22-
#endif
23-
24-
#ifndef gestaltHasColor
25-
#define gestaltHasColor 0
26-
#endif
27-
28-
#ifndef gestaltHasDeepGWorlds
29-
#define gestaltHasDeepGWorlds 1
30-
#endif
18+
#include <Timer.h>
3119

3220
#ifdef kCKAPPDEBUG
3321
std::vector<CKProfilerData*> _profilerData;
@@ -92,7 +80,9 @@ void __CKDebugLog(int level, const char* s, ...) {
9280
// Allocate a larger buffer to avoid overflows
9381
char* buffer = (char*)dlmalloc(250);
9482
if (!buffer) {
95-
DebugStr("\pCant Allocate Mem to Print Debug Str! (1)");
83+
if (CKHasDebugger()) {
84+
DebugStr("\pCant Allocate Mem to Print Debug Str! (1)");
85+
}
9686
ExitToShell();
9787
return;
9888
}
@@ -103,7 +93,9 @@ void __CKDebugLog(int level, const char* s, ...) {
10393
va_end(va);
10494

10595
if (ret < 0 || ret >= 250) { // Check if vsprintf overflowed
106-
DebugStr("\pCant do vsprintf to Print Debug Str!");
96+
if (CKHasDebugger()) {
97+
DebugStr("\pCant do vsprintf to Print Debug Str!");
98+
}
10799
dlfree(buffer);
108100
return;
109101
}
@@ -125,7 +117,9 @@ void __CKDebugLog(int level, const char* s, ...) {
125117
// Create a new buffer for the prefixed log
126118
char* finalBuffer = (char*)dlmalloc(300);
127119
if (!finalBuffer) {
128-
DebugStr("\pCant Allocate Mem to Print Debug Str! (2)");
120+
if (CKHasDebugger()) {
121+
DebugStr("\pCant Allocate Mem to Print Debug Str! (2)");
122+
}
129123
dlfree(buffer);
130124
ExitToShell();
131125
return;
@@ -159,9 +153,15 @@ void CKConsolePrint(const char* toPrint) {
159153
if (!toPrint)
160154
return; // Avoid passing NULL to DebugStr
161155

156+
if (!CKHasDebugger()) {
157+
return;
158+
}
159+
162160
unsigned char* toPStrd = CKC2P(toPrint);
163161
if (!toPStrd) {
164-
DebugStr("\pCant Allocate Mem to Print Debug Str! (2)");
162+
if (CKHasDebugger()) {
163+
DebugStr("\pCant Allocate Mem to Print Debug Str! (2)");
164+
}
165165
ExitToShell();
166166
} else {
167167
DebugStr(toPStrd);
@@ -179,7 +179,9 @@ void __CKWriteToExitFile(const char* s, ...) {
179179
char* buffer = (char*)CKMalloc(250);
180180
if (!buffer) {
181181
// We are in deep shit.
182-
DebugStr("\pCant Allocate Mem to Print Debug Str! (1)");
182+
if (CKHasDebugger()) {
183+
DebugStr("\pCant Allocate Mem to Print Debug Str! (1)");
184+
}
183185
ExitToShell();
184186
return;
185187
}
@@ -190,7 +192,9 @@ void __CKWriteToExitFile(const char* s, ...) {
190192
va_end(va);
191193

192194
if (ret < 0) {
193-
DebugStr("\pCant do vsprintf to Print Debug Str!");
195+
if (CKHasDebugger()) {
196+
DebugStr("\pCant do vsprintf to Print Debug Str!");
197+
}
194198
return;
195199
}
196200

@@ -281,13 +285,48 @@ bool CKHasAppearanceManager() {
281285
bool CKHasColorQuickDraw() {
282286

283287
long result;
284-
if (Gestalt(gestaltQuickdrawFeatures, &result) != noErr) {
288+
if (Gestalt(gestaltQuickdrawVersion, &result) != noErr) {
285289
return false;
286290
}
287291

288292
return (result & (1 << gestaltHasColor)) != 0;
289293
}
290294

295+
/**
296+
* @ingroup Utils
297+
* @brief Checks if Icon Utilities are available (PlotIcon/GetCIcon, etc.)
298+
* @return True if Icon Utilities are available.
299+
*/
300+
bool CKHasIconUtilities() {
301+
302+
long result;
303+
if (Gestalt(gestaltIconUtilitiesAttr, &result) != noErr) {
304+
return false;
305+
}
306+
307+
return (result & (1 << gestaltIconUtilitiesPresent)) != 0;
308+
}
309+
310+
/**
311+
* @ingroup Utils
312+
* @brief Checks if a low-level debugger (like MacsBug) is installed and callable.
313+
* @return True if a low-level debugger is installed and callable.
314+
*/
315+
bool CKHasDebugger() {
316+
317+
// Same logic as Debugging.h's ISLOWLEVELDEBUGGERCALLABLE().
318+
const volatile UInt8* macJmpFlag = (const volatile UInt8*)0x0BFF;
319+
const volatile unsigned long* macJmp = (const volatile unsigned long*)0x0120;
320+
321+
const UInt8 flag = *macJmpFlag;
322+
const unsigned long jmp = *macJmp;
323+
324+
return (flag != (UInt8)0xFF) &&
325+
((flag & (UInt8)0xE0) == (UInt8)0x60) &&
326+
(jmp != 0) &&
327+
(jmp != (unsigned long)0xFFFFFFFF);
328+
}
329+
291330
/**
292331
* @ingroup Utils
293332
* @brief Return the number of milliseconds since computer booted up.

0 commit comments

Comments
 (0)