vkoskiv
/MacNTP
/amendments
/14
Show icon on startup and remove InitGraf trap
Earlier, I thought that I had to run the NTP querying code in a trap
instead of the main INIT invocation, but I now found that not to be
true. This simplifies main.c quite a bit.
I also fetched a copy of ShowInitIcon, fixed it up a bit, and now we
show the MacNTP icon on startup.
The icon has 3 variants: Pending, Success and Failure.
We initially show the pending variant, and then swap to one of the
other two depending on the result of the NTP query.
vkoskiv made amendment 14 about 1 year ago
--- MacNTP.π.r Thu Sep 7 20:07:34 2023
+++ MacNTP.π.r Fri Sep 8 20:41:01 2023
@@ -1,16 +1,35 @@
+data 'STR ' (128, "NTPSERVER", sysheap) {
+ $"0F74 696D 652E 676F 6F67 6C65 2E63 6F6D" /* .time.google.com */
+};
+
data 'STR ' (129, "UTCOFFSETMINUTES", sysheap) {
- $"0130" /* .0 */
+ $"0331 3830" /* .180 */
};
-data 'STR ' (128, "NTPSERVER", sysheap) {
- $"0F74 696D 652E 676F 6F67 6C65 2E63 6F6D" /* .time.google.com */
+data 'ICN#' (128, "NTPPENDING", sysheap) {
+ $"FFFF FFFF 8080 0001 8080 7C01 8881 8301" /* ....ÄÄ..ÄÄ|.àÅÉ. */
+ $"9482 0081 9484 0041 9484 8041 9488 4421" /* îÇ.ÅîÑ.AîÑÄAîàD! */
+ $"9488 2821 9488 1021 9488 0021 9488 0021" /* îà(!îà.!îà.!îà.! */
+ $"9484 0041 BE84 0041 A282 0081 A281 8301" /* îÑ.AæÑ.A¢Ç.Å¢ÅÉ. */
+ $"BE80 7C01 9480 2801 9480 0001 9480 0001" /* æÄ|.îÄ(.îÄ..îÄ.. */
+ $"9480 0001 9480 2801 9480 7C01 9480 4401" /* îÄ..îÄ(.îÄ|.îÄD. */
+ $"9480 4401 9480 7C01 9480 5401 94AF 93F5" /* îÄD.îÄ|.îÄT.îØì. */
+ $"8880 2801 80AF C7F5 8080 0001 FFFF FFFF" /* àÄ(.ÄØ«.ÄÄ...... */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */
};
-data 'ICN#' (-4064) {
+data 'ICN#' (-4064, preload) {
$"FFFF FFFF 8080 0001 8080 7C01 8881 8301" /* ....ÄÄ..ÄÄ|.àÅÉ. */
- $"9482 1081 9484 1041 9484 1041 9488 1021" /* îÇ.ÅîÑ.AîÑ.Aîà.! */
- $"9488 1021 9488 1021 9488 0821 9489 C421" /* îà.!îà.!îà.!îâƒ! */
- $"9485 8241 BE85 4441 A282 3881 A281 8301" /* îÖÇAæÖDA¢Ç8Å¢ÅÉ. */
+ $"9482 0081 9484 0041 9484 8041 9488 4421" /* îÇ.ÅîÑ.AîÑÄAîàD! */
+ $"9488 2821 9488 1021 9489 C021 9489 8221" /* îà(!îà.!îâ¿!îâÇ! */
+ $"9485 4441 BE84 3841 A282 0081 A281 8301" /* îÖDAæÑ8A¢Ç.Å¢ÅÉ. */
$"BE80 7C01 9480 2801 9480 2801 9480 2801" /* æÄ|.îÄ(.îÄ(.îÄ(. */
$"9480 2801 9480 2801 9480 7C01 9480 4401" /* îÄ(.îÄ(.îÄ|.îÄD. */
$"9480 4401 9480 7C01 9480 5401 94AF 93F5" /* îÄD.îÄ|.îÄT.îØì. */
@@ -25,16 +44,23 @@ data 'ICN#' (-4064) {
$"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */
};
-data 'PICT' (-4041, purgeable) {
- $"0085 00B7 00DF 00C9 00F0 1101 A030 3901" /* .Ö.∑...…....†09. */
- $"000A 00B7 00DF 00C9 00F0 3200 C800 DF00" /* ...∑...…..2.»... */
- $"C900 F090 0004 00B7 00D8 00C8 00F0 00B7" /* …..ê...∑.ÿ.»...∑ */
- $"00DF 00C8 00F0 00B7 00DF 00C8 00F0 0000" /* ...»...∑...».... */
- $"0007 C000 0018 3000 0021 0800 0041 0400" /* ..¿...0..!...A.. */
- $"0081 0200 0081 0200 0101 0100 0101 0100" /* .Å...Å.......... */
- $"0101 0100 0100 8140 0100 4100 3880 22DC" /* ......Å@..A.8Ä". */
- $"A480 1252 A440 0452 2420 0852 2418 3052" /* §Ä.R§@.R$ .R$.0R */
- $"0007 C000 FF" /* ..¿.. */
+data 'ICN#' (130, "NTPFAILED", sysheap) {
+ $"FFFF FFFF 8080 0001 8080 7C01 8881 8301" /* ....ÄÄ..ÄÄ|.àÅÉ. */
+ $"9482 0081 9484 0041 9484 8241 9488 4421" /* îÇ.ÅîÑ.AîÑÇAîàD! */
+ $"9488 2821 9488 1021 9488 2821 9488 4421" /* îà(!îà.!îà(!îàD! */
+ $"9484 8241 BE84 0041 A282 0081 A281 8301" /* îÑÇAæÑ.A¢Ç.Å¢ÅÉ. */
+ $"BE80 7C01 9480 2801 9480 2801 9480 2801" /* æÄ|.îÄ(.îÄ(.îÄ(. */
+ $"9480 2801 9480 2801 9480 7C01 9480 4401" /* îÄ(.îÄ(.îÄ|.îÄD. */
+ $"9480 4401 9480 7C01 9480 5401 94AF 93F5" /* îÄD.îÄ|.îÄT.îØì. */
+ $"8880 2801 80AF C7F5 8080 0001 FFFF FFFF" /* àÄ(.ÄØ«.ÄÄ...... */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* ................ */
};
data 'mach' (-4064, "init", purgeable) {
@@ -43,5 +69,28 @@ data 'mach' (-4064, "init", purgeable) {
data 'sysz' (0) {
$"0002 7100" /* ..q. */
+};
+
+data 'BNDL' (-4064, "init", purgeable) {
+ $"564B 4F53 0000 0001 4652 4546 0001 0000" /* VKOS....FREF.... */
+ $"0080 0001 0081 4943 4E23 0001 0000 F020" /* .Ä...ÅICN#..... */
+ $"0001 F020" /* ... */
+};
+
+data 'VKOS' (0, "Owner resource") {
+ $"1956 616C 7474 6572 6920 4B6F 736B 6976" /* .Valtteri Koskiv */
+ $"756F 7269 2C20 3230 3233" /* uori, 2023 */
+};
+
+data 'FREF' (-4064, purgeable) {
+ $"6364 6576 0000 00" /* cdev... */
+};
+
+data 'FREF' (128) {
+ $"6364 6576 0000 00" /* cdev... */
+};
+
+data 'FREF' (129) {
+ $"494E 4954 0001 00" /* INIT... */
};
--- main.c Fri Sep 8 00:03:01 2023
+++ main.c Fri Sep 8 20:35:25 2023
@@ -14,36 +14,38 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+/*
+TODO:
+- Remove dump_error and save an error to rsrc STR instead
+- Implement cdev
+- Display possible errors in cdev
+*/
+
#include <SetUpA4.h>
-#include <OSUtils.h>
#include "MacNTP.h"
-#include "tcp.h"
-#include "prefs.h"
+#include "ShowInitIcon.h"
// This enables DebugStr() printouts to aid development.
// This also disables the system time check, so it tries NTP
// on every boot.
//#define DEBUGGING
-pascal void NewInitGraf(Ptr globalPtr);
void dump_error(enum MacNTPError error, OSErr oserror);
int TryMacNTP(void);
-void GetOurFilename(Str255 name);
-#define InitGrafTrapnum 0xA86E
-#define NTP_URL_STR_ID 128
-#define UTC_OFFSET_STR_ID 129
+#define SECONDS_TO_02_09_1996 2924510400ul
+#define MACNTP_ICN_ID_PENDING 128
+#define MACNTP_ICN_ID_SUCCESS -4064 // Also used for cdev
+#define MACNTP_ICN_ID_FAILURE 130
-long g_old_initgraf_address;
-int g_ntp_success;
-int g_ntp_error;
Handle g_mtcp_init_handle;
-// NTP URL and UTC offset strings
-// These are loaded into sys heap on boot
+#define NTP_URL_STR_ID 128
StringHandle g_url;
-StringHandle g_utc;
+#define UTC_OFFSET_STR_ID 129
+StringHandle g_utc; // Offset in minutes,
+
#ifdef DEBUGGING
void dump_error(enum MacNTPError error, OSErr oserror) {
Str255 numstr;
@@ -132,44 +134,17 @@ int TryMacNTP(void) {
return 0;
}
-#define SECONDS_TO_02_09_1996 2924510400ul
-
-pascal void NewInitGraf(Ptr globalPtr) {
- unsigned long systime;
- SetUpA4();
- if (g_ntp_success || g_ntp_error) goto skip; // Pretend we weren't here!
-#ifndef DEBUGGING
- // We only try to update the clock if we're well into the 20th century
- ReadDateTime((unsigned long *)&systime);
- if (systime > SECONDS_TO_02_09_1996) {
- g_ntp_success = 1;
- goto skip;
- }
-#endif
-
- if (!TryMacNTP()) {
- g_ntp_success = 1;
- } else {
- g_ntp_error = 1;
- }
-
-skip:
- CallPascal(globalPtr, g_old_initgraf_address);
- RestoreA4();
-}
-
void main() {
- Ptr mtcp_init_ptr;
+ Ptr our_init_ptr;
+ unsigned long systime;
asm {
- move.L A0, mtcp_init_ptr;
+ move.L A0, our_init_ptr;
}
RememberA0();
SetUpA4();
- g_mtcp_init_handle = RecoverHandle(mtcp_init_ptr);
+ g_mtcp_init_handle = RecoverHandle(our_init_ptr);
DetachResource(g_mtcp_init_handle);
- //TODO: Load STR resources, movhhi and lock. Maybe Unlock+dispos in
- // trap ?
g_url = GetString(NTP_URL_STR_ID);
g_utc = GetString(UTC_OFFSET_STR_ID);
if (!g_url || !g_utc) {
@@ -184,12 +159,28 @@ void main() {
MoveHHi(g_utc);
HLock(g_utc);
- g_old_initgraf_address = NGetTrapAddress(InitGrafTrapnum, ToolTrap);
- NSetTrapAddress((long)&NewInitGraf, InitGrafTrapnum, ToolTrap);
+ ShowInitIcon(MACNTP_ICN_ID_PENDING, false);
- g_ntp_success = 0;
- g_ntp_error = 0;
+#ifndef DEBUGGING
+ // We only try to update the clock if we're well into the 20th century
+ ReadDateTime((unsigned long *)&systime);
+ if (systime > SECONDS_TO_02_09_1996) {
+ ShowInitIcon(MACNTP_ICN_ID_SUCCESS, true);
+ goto skip;
+ } else {
+ ShowInitIcon(MACNTP_ICN_ID_PENDING, false);
+ }
+#else
+ ShowInitIcon(MACNTP_ICN_ID_PENDING, false);
+#endif
+ if (!TryMacNTP()) {
+ ShowInitIcon(MACNTP_ICN_ID_SUCCESS, true);
+ } else {
+ ShowInitIcon(MACNTP_ICN_ID_FAILURE, true);
+ }
+
+skip:
error:
RestoreA4();
}
--- ShowInitIcon.c Fri Sep 8 20:25:45 2023
+++ ShowInitIcon.c Fri Sep 8 20:25:45 2023
@@ -0,0 +1,168 @@
+// ShowInitIcon - version 1.0.1, May 30th, 1995
+// This code is intended to let INIT writers easily display an icon at startup time.
+// View in Geneva 9pt, 4-space tabs
+
+// Written by: Peter N Lewis <peter@mail.peter.com.au>, Jim Walker <JWWalker@aol.com>
+// and François Pottier <pottier@dmi.ens.fr>, with thanks to previous ShowINIT authors.
+// Send comments and bug reports to François Pottier.
+
+// Hacked a bit by Valtteri Koskivuori on 08.09.2023:
+// * Removed Sys7/Color QD code
+// * Added missing QDGlobals struct
+// * Now compiles in Think C 5.0.1 under System 6
+
+
+// This version features:
+// - Short and readable code.
+// - Correctly wraps around when more than one row of icons has been displayed.
+// - works with System 6
+// - Built with Universal Headers & CodeWarrior. Should work with other headers/compilers.
+
+#include <Memory.h>
+#include <Resources.h>
+#include <Icons.h>
+#include <OSUtils.h>
+#include <Quickdraw.h>
+#include "ShowInitIcon.h"
+
+// You should set SystemSixOrLater in your headers to avoid including glue for SysEnvirons.
+
+// ---------------------------------------------------------------------------------------------------------------------
+// Set this flag to 1 if you want to compile this file into a stand-alone resource (see note below).
+// Set it to 0 if you want to include this source file into your INIT project.
+
+#if 0
+#define ShowInitIcon main
+#endif
+
+// ---------------------------------------------------------------------------------------------------------------------
+// The ShowINIT mechanism works by having each INIT read/write data from these globals.
+// The MPW C compiler doesn't accept variables declared at an absolute address, so I use these macros instead.
+// Only one macro is defined per variable; there is no need to define a Set and a Get accessor like in <LowMem.h>.
+
+#define LMVCoord (* (short*) 0x92A)
+#define LMVCheckSum (* (short*) 0x928)
+#define LMHCoord (* (short*) 0x92C)
+#define LMHCheckSum (* (short*) 0x92E)
+
+// ---------------------------------------------------------------------------------------------------------------------
+// Prototypes for the subroutines. The main routine comes first; this is necessary to make THINK C's "Custom Header" option work.
+
+static unsigned short CheckSum (unsigned short x);
+static void ComputeIconRect (Rect* iconRect, Rect* screenBounds);
+static void AdvanceIconPosition (Rect* iconRect);
+static void DrawBWIcon (short iconID, Rect *iconRect);
+
+// ---------------------------------------------------------------------------------------------------------------------
+// Main routine.
+
+// vkoskiv 08.09.2023:
+// This file is probably too new for our Sys6 environment, since Think C 5
+// doesn't know about QDGlobals. Luckily they document it, so I'll just patch
+// in a suitable struct.
+
+// The offsets from A5 are negative, so we flip the order they appear in the doc
+typedef struct {
+ char privates[76]; // No idea what this is, spotted it elsewhere
+ long randSeed;
+ BitMap screenBits;
+ Cursor arrow;
+ Pattern dkGray;
+ Pattern ltGray;
+ Pattern gray;
+ Pattern black;
+ Pattern white;
+ GrafPtr thePort;
+} QDGlobals;
+
+typedef struct {
+ QDGlobals qd; // Storage for the QuickDraw globals
+ long qdGlobalsPtr; // A5 points to this place; it will contain a pointer to qd
+} QDStorage;
+
+pascal void ShowInitIcon (short iconFamilyID, Boolean advance)
+{
+ long oldA5; // Original value of register A5
+ QDStorage qds; // Fake QD globals
+ CGrafPort colorPort;
+ GrafPort bwPort;
+ Rect destRect;
+
+ oldA5 = SetA5((long) &qds.qdGlobalsPtr); // Tell A5 to point to the end of the fake QD Globals
+ InitGraf(&qds.qd.thePort); // Initialize the fake QD Globals
+
+ ComputeIconRect(&destRect, &qds.qd.screenBits.bounds); // Compute where the icon should be drawn
+
+ OpenPort(&bwPort);
+ DrawBWIcon(iconFamilyID, &destRect);
+ ClosePort(&bwPort);
+
+ if (advance) AdvanceIconPosition (&destRect);
+
+ SetA5(oldA5); // Restore A5 to its previous value
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+// A checksum is used to make sure that the data in there was left by another ShowINIT-aware INIT.
+
+static unsigned short CheckSum (unsigned short x)
+{
+ return ((x << 1) | (x >> 15)) ^ 0x1021;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+// ComputeIconRect computes where the icon should be displayed.
+
+static void ComputeIconRect (Rect* iconRect, Rect* screenBounds)
+{
+ if (CheckSum(LMHCoord) != LMHCheckSum) // If we are first, we need to initialize the shared data.
+ LMHCoord = 8;
+ if (CheckSum(LMVCoord) != LMVCheckSum)
+ LMVCoord = screenBounds->bottom - 40;
+
+ if (LMHCoord + 34 > screenBounds->right) { // Check whether we must wrap
+ iconRect->left = 8;
+ iconRect->top = LMVCoord - 40;
+ }
+ else {
+ iconRect->left = LMHCoord;
+ iconRect->top = LMVCoord;
+ }
+ iconRect->right = iconRect->left + 32;
+ iconRect->bottom = iconRect->top + 32;
+}
+
+// AdvanceIconPosition updates the shared global variables so that the next extension will draw its icon beside ours.
+
+static void AdvanceIconPosition (Rect* iconRect)
+{
+ LMHCoord = iconRect->left + 40; // Update the shared data
+ LMVCoord = iconRect->top;
+ LMHCheckSum = CheckSum(LMHCoord);
+ LMVCheckSum = CheckSum(LMVCoord);
+}
+
+// DrawBWIcon draws the 'ICN#' member of the icon family. It works under System 6.
+
+static void DrawBWIcon (short iconID, Rect *iconRect)
+{
+ Handle icon;
+ BitMap source, destination;
+ GrafPtr port;
+
+ icon = Get1Resource('ICN#', iconID);
+ if (icon != NULL) {
+ HLock(icon);
+ // Prepare the source and destination bitmaps.
+ source.baseAddr = *icon + 128; // Mask address.
+ source.rowBytes = 4;
+ SetRect(&source.bounds, 0, 0, 32, 32);
+ GetPort(&port);
+ destination = port->portBits;
+ // Transfer the mask.
+ CopyBits(&source, &destination, &source.bounds, iconRect, srcBic, nil);
+ // Then the icon.
+ source.baseAddr = *icon;
+ CopyBits(&source, &destination, &source.bounds, iconRect, srcOr, nil);
+ }
+}
--- ShowInitIcon.h Fri Sep 8 17:34:53 2023
+++ ShowInitIcon.h Fri Sep 8 17:34:53 2023
@@ -0,0 +1,13 @@
+#ifndef __ShowInitIcon__
+#define __ShowInitIcon__
+
+#include <Types.h>
+
+// Usage: pass the ID of your icon family (ICN#/icl4/icl8) to have it drawn in the right spot.
+// If 'advance' is true, the next INIT icon will be drawn to the right of your icon. If it is false, the next INIT icon will overwrite
+// yours. You can use it to create animation effects by calling ShowInitIcon several times with 'advance' set to false.
+
+pascal void ShowInitIcon (short iconFamilyID, Boolean advance);
+
+#endif /* __ShowInitIcon__ */
+