ShowInitIcon/ShowInitIcon.c

// 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 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.
 
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 (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);
    }
}
 
// ---------------------------------------------------------------------------------------------------------------------
// 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.