Download
vkoskiv
/MacNTP
/ShowInitIcon.c
(View History)
vkoskiv Implement a very rough first-pass control panel + fallback option | Latest amendment: 16 on 2023-09-13 |
1 | // ShowInitIcon - version 1.0.1, May 30th, 1995 |
2 | // This code is intended to let INIT writers easily display an icon at startup time. |
3 | // View in Geneva 9pt, 4-space tabs |
4 | |
5 | // Written by: Peter N Lewis <peter@mail.peter.com.au>, Jim Walker <JWWalker@aol.com> |
6 | // and François Pottier <pottier@dmi.ens.fr>, with thanks to previous ShowINIT authors. |
7 | // Send comments and bug reports to François Pottier. |
8 | |
9 | // Hacked a bit by Valtteri Koskivuori on 08.09.2023: |
10 | // * Removed Sys7/Color QD code |
11 | // * Added missing QDGlobals struct |
12 | // * Now compiles in Think C 5.0.1 under System 6 |
13 | |
14 | |
15 | // This version features: |
16 | // - Short and readable code. |
17 | // - Correctly wraps around when more than one row of icons has been displayed. |
18 | // - works with System 6 |
19 | // - Built with Universal Headers & CodeWarrior. Should work with other headers/compilers. |
20 | |
21 | #include <Memory.h> |
22 | #include <Resources.h> |
23 | #include <Icons.h> |
24 | #include <OSUtils.h> |
25 | #include <Quickdraw.h> |
26 | #include "ShowInitIcon.h" |
27 | |
28 | // You should set SystemSixOrLater in your headers to avoid including glue for SysEnvirons. |
29 | |
30 | // --------------------------------------------------------------------------------------------------------------------- |
31 | // Set this flag to 1 if you want to compile this file into a stand-alone resource (see note below). |
32 | // Set it to 0 if you want to include this source file into your INIT project. |
33 | |
34 | #if 0 |
35 | #define ShowInitIcon main |
36 | #endif |
37 | |
38 | // --------------------------------------------------------------------------------------------------------------------- |
39 | // The ShowINIT mechanism works by having each INIT read/write data from these globals. |
40 | // The MPW C compiler doesn't accept variables declared at an absolute address, so I use these macros instead. |
41 | // Only one macro is defined per variable; there is no need to define a Set and a Get accessor like in <LowMem.h>. |
42 | |
43 | #define LMVCoord (* (short*) 0x92A) |
44 | #define LMVCheckSum (* (short*) 0x928) |
45 | #define LMHCoord (* (short*) 0x92C) |
46 | #define LMHCheckSum (* (short*) 0x92E) |
47 | |
48 | // --------------------------------------------------------------------------------------------------------------------- |
49 | // Prototypes for the subroutines. The main routine comes first; this is necessary to make THINK C's "Custom Header" option work. |
50 | |
51 | static unsigned short CheckSum (unsigned short x); |
52 | static void ComputeIconRect (Rect* iconRect, Rect* screenBounds); |
53 | static void AdvanceIconPosition (Rect* iconRect); |
54 | static void DrawBWIcon (short iconID, Rect *iconRect); |
55 | |
56 | // --------------------------------------------------------------------------------------------------------------------- |
57 | // Main routine. |
58 | |
59 | // vkoskiv 08.09.2023: |
60 | // This file is probably too new for our Sys6 environment, since Think C 5 |
61 | // doesn't know about QDGlobals. Luckily they document it, so I'll just patch |
62 | // in a suitable struct. |
63 | |
64 | // The offsets from A5 are negative, so we flip the order they appear in the doc |
65 | typedef struct { |
66 | char privates[76]; // No idea what this is, spotted it elsewhere |
67 | long randSeed; |
68 | BitMap screenBits; |
69 | Cursor arrow; |
70 | Pattern dkGray; |
71 | Pattern ltGray; |
72 | Pattern gray; |
73 | Pattern black; |
74 | Pattern white; |
75 | GrafPtr thePort; |
76 | } QDGlobals; |
77 | |
78 | typedef struct { |
79 | QDGlobals qd; // Storage for the QuickDraw globals |
80 | long qdGlobalsPtr; // A5 points to this place; it will contain a pointer to qd |
81 | } QDStorage; |
82 | |
83 | pascal void ShowInitIcon (short iconFamilyID, Boolean advance) |
84 | { |
85 | long oldA5; // Original value of register A5 |
86 | QDStorage qds; // Fake QD globals |
87 | CGrafPort colorPort; |
88 | GrafPort bwPort; |
89 | Rect destRect; |
90 | |
91 | oldA5 = SetA5((long) &qds.qdGlobalsPtr); // Tell A5 to point to the end of the fake QD Globals |
92 | InitGraf(&qds.qd.thePort); // Initialize the fake QD Globals |
93 | |
94 | ComputeIconRect(&destRect, &qds.qd.screenBits.bounds); // Compute where the icon should be drawn |
95 | |
96 | OpenPort(&bwPort); |
97 | DrawBWIcon(iconFamilyID, &destRect); |
98 | ClosePort(&bwPort); |
99 | |
100 | if (advance) AdvanceIconPosition (&destRect); |
101 | |
102 | SetA5(oldA5); // Restore A5 to its previous value |
103 | } |
104 | |
105 | // --------------------------------------------------------------------------------------------------------------------- |
106 | // A checksum is used to make sure that the data in there was left by another ShowINIT-aware INIT. |
107 | |
108 | static unsigned short CheckSum (unsigned short x) |
109 | { |
110 | return ((x << 1) | (x >> 15)) ^ 0x1021; |
111 | } |
112 | |
113 | // --------------------------------------------------------------------------------------------------------------------- |
114 | // ComputeIconRect computes where the icon should be displayed. |
115 | |
116 | static void ComputeIconRect (Rect* iconRect, Rect* screenBounds) |
117 | { |
118 | if (CheckSum(LMHCoord) != LMHCheckSum) // If we are first, we need to initialize the shared data. |
119 | LMHCoord = 8; |
120 | if (CheckSum(LMVCoord) != LMVCheckSum) |
121 | LMVCoord = screenBounds->bottom - 40; |
122 | |
123 | if (LMHCoord + 34 > screenBounds->right) { // Check whether we must wrap |
124 | iconRect->left = 8; |
125 | iconRect->top = LMVCoord - 40; |
126 | } |
127 | else { |
128 | iconRect->left = LMHCoord; |
129 | iconRect->top = LMVCoord; |
130 | } |
131 | iconRect->right = iconRect->left + 32; |
132 | iconRect->bottom = iconRect->top + 32; |
133 | } |
134 | |
135 | // AdvanceIconPosition updates the shared global variables so that the next extension will draw its icon beside ours. |
136 | |
137 | static void AdvanceIconPosition (Rect* iconRect) |
138 | { |
139 | LMHCoord = iconRect->left + 40; // Update the shared data |
140 | LMVCoord = iconRect->top; |
141 | LMHCheckSum = CheckSum(LMHCoord); |
142 | LMVCheckSum = CheckSum(LMVCoord); |
143 | } |
144 | |
145 | // DrawBWIcon draws the 'ICN#' member of the icon family. It works under System 6. |
146 | |
147 | static void DrawBWIcon (short iconID, Rect *iconRect) |
148 | { |
149 | Handle icon; |
150 | BitMap source, destination; |
151 | GrafPtr port; |
152 | |
153 | icon = Get1Resource('ICN#', iconID); |
154 | if (icon != NULL) { |
155 | HLock(icon); |
156 | // Prepare the source and destination bitmaps. |
157 | source.baseAddr = *icon + 128; // Mask address. |
158 | source.rowBytes = 4; |
159 | SetRect(&source.bounds, 0, 0, 32, 32); |
160 | GetPort(&port); |
161 | destination = port->portBits; |
162 | // Transfer the mask. |
163 | CopyBits(&source, &destination, &source.bounds, iconRect, srcBic, nil); |
164 | // Then the icon. |
165 | source.baseAddr = *icon; |
166 | CopyBits(&source, &destination, &source.bounds, iconRect, srcOr, nil); |
167 | //HUnlock(icon); |
168 | } |
169 | } |