One more example: a System Extension (INIT)

This commit is contained in:
Wolfgang Thaller 2015-07-18 01:14:43 +02:00
parent ccd227e67c
commit 7aaa3174df
11 changed files with 248 additions and 6 deletions

View File

@ -31,6 +31,7 @@ add_subdirectory(Samples/HelloWorld)
add_subdirectory(Samples/Raytracer)
add_subdirectory(Samples/Launcher)
add_subdirectory(Samples/Dialog)
add_subdirectory(Samples/SystemExtension)
else()
configure_file(cmake/retro68.toolchain.cmake.in cmake/retro68.toolchain.cmake @ONLY)

View File

@ -0,0 +1,16 @@
add_executable(SystemExtension
SystemExtension.c
SystemExtension.r
ShowInitIcon.c
ShowInitIcon.h)
set_target_properties(SystemExtension PROPERTIES OUTPUT_NAME SystemExtension.flt)
add_custom_command(
OUTPUT SystemExtension.dsk
COMMAND ${REZ} ${CMAKE_CURRENT_SOURCE_DIR}/SystemExtension.r
--copy ${CMAKE_CURRENT_SOURCE_DIR}/Icons.rsrc.bin
-o SystemExtension.dsk
-t INIT
DEPENDS SystemExtension SystemExtension.r Icons.rsrc.bin)
add_custom_target(SystemExtension_INIT ALL DEPENDS SystemExtension.dsk)

Binary file not shown.

View File

@ -0,0 +1,161 @@
// 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.
// 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 "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 LMVCheckSum (* (unsigned short*) 0x928)
#define LMVCoord (* ( short*) 0x92A)
#define LMHCoord (* ( short*) 0x92C)
#define LMHCheckSum (* (unsigned 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 (short x);
static void ComputeIconRect (Rect* iconRect, Rect* screenBounds);
static void AdvanceIconPosition (Rect* iconRect);
static void DrawBWIcon (short iconID, Rect *iconRect);
// ---------------------------------------------------------------------------------------------------------------------
// Main routine.
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;
SysEnvRec environment; // Machine configuration.
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
SysEnvirons(curSysEnvVers, &environment); // Find out what kind of machine this is
ComputeIconRect(&destRect, &qds.qd.screenBits.bounds); // Compute where the icon should be drawn
if (environment.systemVersion >= 0x0700 && environment.hasColorQD) {
OpenCPort(&colorPort);
PlotIconID(&destRect, atNone, ttNone, iconFamilyID);
CloseCPort(&colorPort);
}
else {
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 (short x)
{
return (unsigned short)(((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 = (short)(screenBounds->bottom - 40);
if (LMHCoord + 34 > screenBounds->right) { // Check whether we must wrap
iconRect->left = 8;
iconRect->top = (short)(LMVCoord - 40);
}
else {
iconRect->left = LMHCoord;
iconRect->top = LMVCoord;
}
iconRect->right = (short)(iconRect->left + 32);
iconRect->bottom = (short)(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 = (short)(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);
}
}
// ---------------------------------------------------------------------------------------------------------------------
// Notes
// Checking for PlotIconID:
// We (PNL) now check for system 7 and colour QD, and use colour graf ports and PlotIconID only if both are true
// Otherwise we use B&W grafport and draw using PlotBWIcon.

View File

@ -0,0 +1,21 @@
#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.
#ifdef __cplusplus
extern "C" {
#endif
pascal void ShowInitIcon (short iconFamilyID, Boolean advance);
#ifdef __cplusplus
}
#endif
#endif /* __ShowInitIcon__ */

View File

@ -0,0 +1,16 @@
#include <OSUtils.h>
#include "ShowInitIcon.h"
#include "Retro68Runtime.h"
void _start()
{
RETRO68_RELOCATE();
Retro68CallConstructors();
ShowInitIcon(130, false);
Delay(20, NULL);
ShowInitIcon(128, true);
Delay(40, NULL);
Retro68FreeGlobals();
}

View File

@ -0,0 +1,13 @@
type 'INIT' (0) {
hex string dontBreakAtEntry = $"", breakAtEntry = $"A9FF";
longint = 0x61000002; // bsr *+2
integer = 0x0697; // addi.l #_, (a7)
longint = $$long(fltfile + 8*8) + 8;
integer = 0x4e75; // rts
fltfile:
hex string;
};
resource 'INIT' (0) {
dontBreakAtEntry, $$read("SystemExtension.flt");
};

View File

@ -33,4 +33,4 @@ add_library(retrocrt
consolehooks.c)
install(TARGETS retrocrt DESTINATION lib)
install(FILES Retro68Runtime.h DESTINATION include)

View File

@ -42,5 +42,6 @@
void Retro68Relocate();
void Retro68CallConstructors();
void Retro68FreeGlobals();
#define RETRO68_RELOCATE() RETRO68_CALL_UNRELOCATED(Retro68Relocate,())

View File

@ -66,7 +66,7 @@ extern void __fini_section_end(void);
static long headerVirtualAddress = -0x40;
static Ptr savedBSS = (Ptr) -1;
static Ptr bssPtr = (Ptr) -1;
#define ACCESS_DISPLACED(VAR) \
( * (typeof(&VAR)) ((char*)(&VAR) + displacement) )
@ -92,10 +92,14 @@ void Retro68Relocate()
long data_end = header->data_end - 0x40;
long bss_displacement = 0;
Ptr bss = ACCESS_DISPLACED(savedBSS);
Ptr bss = ACCESS_DISPLACED(bssPtr);
if(bss == (Ptr)-1)
{
bss = NewPtrClear(bss_size);
THz zone = ApplicationZone();
if(!zone || (char*)header < (char*)zone)
bss = NewPtrSysClear(bss_size);
else
bss = NewPtrClear(bss_size);
bss_displacement = (long)bss - data_end;
}
@ -121,7 +125,7 @@ void Retro68Relocate()
// accessing globals and calling functions is OK below here.
headerVirtualAddress += displacement;
savedBSS = bss;
bssPtr = bss;
}
void Retro68CallConstructors()
@ -135,3 +139,13 @@ void Retro68CallConstructors()
p += 6;
}
}
void Retro68FreeGlobals()
{
if(bssPtr != (Ptr) -1)
{
DisposePtr(bssPtr);
bssPtr = (Ptr) -1;
}
}

View File

@ -25,7 +25,6 @@
#include <stdint.h>
#include <stdlib.h>
#include <SegLoad.h>
#include "Retro68Runtime.h"