From
[email protected] Sat Sep 11 18:54:18 1993
Path: news.itd.umich.edu!destroyer!sol.ctr.columbia.edu!spool.mu.edu!olivea!apple.com!claris!outpost.SF-Bay.org!peirce
From:
[email protected] (Michael Peirce)
Newsgroups: comp.sys.mac.programmer
Subject: "System" menu code
Message-ID: <
[email protected]>
Date: 11 Sep 93 19:56:12 GMT
Reply-To:
[email protected] (Michael Peirce)
Organization: Peirce Software
Lines: 487
X-Mailer: uAccess - Macintosh Release: 1.6v2
Earlier this week I asked about how to add a "system" menu to the menu bar, one that
will stick around all the time. I got a number of very helpful responses. Here is
a bare bones implementation I worked up with real code.
I though I'd post it for two reasons (one altruistic, one selfish).
(1) This info isn't well documented and by posting it, people can see how it's done.
(2) Others can point out flaws in my approach.
A couple of notes: This is written in MPW C and ASM. It requires System 7 (and doesn't
check - it's only example code :-). It uses a static menu - if you want a changing menu,
you have to do more work messing with SelectMenu; that's why I have the empty patch to
SelectMenu in there. And finally, it uses a fixed menu id. I'm told this is evil and
that I should walk the menu list and make sure I use an unused id.
Alsothus uses Icons.h, you can get this from the latest E.T.O.
Thanks for the pointers!
-- michael
---------- StarMenuINIT.c ---------------------------------------
/*
StarMenuINIT.c
Copyright )1993 Peirce Software.
All rights reserved
Change History:
09-11-93 Michael Peirce Add this.
*/
#include "Icons.h"
#include "StarMenu.h"
#include "Traps.h"
#pragma segment Main
pascal OSErr DetachIcons(ResType theType, Handle *theIcon, void *yourDataPtr);
//
// This is our INIT code. It does all the setup and installation required to patch
// our traps and setup the storage for doing what we want to do.
//
// NOTE: Remove the DebugStr() stuff in production code.
//
pascal void STARMENUENTRY()
{
Handle patchCode;
long patchDrawMenuBar,patchSystemMenu,patchMenuSelect;
long oldDrawMenuBar,oldSystemMenu,oldMenuSelect;
long storageAddr;
STORAGEH storage;
OSErr stat;
Handle iconSuite;
// Install resident code resource
SetZone(SystemZone());
patchCode = Get1Resource('rCod',1);
if (!patchCode) {
DebugStr("\pNo patch code found");
return;
}
DetachResource(patchCode);
HNoPurge(patchCode);
HLock(patchCode);
// Setup the vectors
// *** Be VERY careful this matches the layout of StarMenuPatch.a.
patchDrawMenuBar = ((long)*patchCode) + 0;
patchSystemMenu = patchDrawMenuBar + 2;
patchMenuSelect = patchSystemMenu + 2;
oldDrawMenuBar = patchMenuSelect + 4;
oldSystemMenu = oldDrawMenuBar + 6;
oldMenuSelect = oldSystemMenu + 6;
storageAddr = oldMenuSelect + 4;
// allocate some storage and store a reference to it into our block
storage = (STORAGEH) NewHandle(sizeof(STORAGERec));
if (storage == nil)
return;
*((long*) storageAddr) = (long) storage;
// load up our icon suite for the menu "title"
stat = GetIconSuite(&iconSuite,128,svAllAvailableData);
if (stat != noErr)
DebugStr("\p Error in NewIconSuite");
stat = ForEachIconDo(iconSuite,svAllAvailableData,DetachIcons,0);
if (stat != noErr)
DebugStr("\p Error in ForEachIconDo");
_MenuIconFamily = iconSuite;
_OurMenuHandle = 0;
// We should make this dynamic, so as not to conflict, but for now...
// Must be in the range < -16384
_MenuID = -19061;
// Patch the traps
*((long*) oldDrawMenuBar) = NGetTrapAddress(_DrawMenuBar, ToolTrap);
NSetTrapAddress(patchDrawMenuBar,_DrawMenuBar,ToolTrap);
*((long*) oldSystemMenu) = NGetTrapAddress(_SystemMenu, ToolTrap);
NSetTrapAddress(patchSystemMenu,_SystemMenu,ToolTrap);
*((long*) oldMenuSelect) = NGetTrapAddress(_MenuSelect, ToolTrap);
NSetTrapAddress(patchMenuSelect,_MenuSelect,ToolTrap);
SetZone(ApplicZone());
}
//
// DetachIcons - is called to detach each icon resource from its file and make
// it into a regular handle so it will stick around after INIT time.
//
pascal OSErr DetachIcons(ResType theType, Handle *theIcon, void *yourDataPtr) {
#pragma unused(theType)
#pragma unused(yourDataPtr)
if (*theIcon != nil) {
DetachResource(*theIcon);
HNoPurge(*theIcon);
return ResError();
} else {
return noErr;
}
}
---------- StarMenuPatch.a ---------------------------------------
;
; StarMenuPatch.a
;
; Copyright )1993 Apple Computer, Inc.
; All rights reserved
;
; Change History:
;
; 09-11-93 Michael Peirce Set us this header
;
; This code must be the first code in the segment. The first few lines are
; our patch vectors. They are kept there so we can easily calculate their
; location as we load them in.
;
; After the patch vectors and storage space, we have our actual patches. These
; only do as much as we need in assembler, then call C routines to do the real work.
;
BLANKS ON
INCLUDE '::AIncludes:SysEqu.a'
INCLUDE '::AIncludes:SysErr.a'
INCLUDE '::AIncludes:Traps.a'
IMPORT CDRAWMENUBAR
IMPORT CSYSTEMMENU
IMPORT CMENUSELECT
;------------------------------------------------------------------------------------
STRING ASIS
PATCHES PROC EXPORT
BRA.S @ADRAWMENUBAR ; Entry for DrawMenuBar patch
BRA.S @ASYSTEMMENU ; Entry for SystemMenu patch
BRA.S @AMENUSELECT ; Entry for MenuSelect patch
@oldDMB DC.W $4EF9 ; JMP.L
DC.L 0 ; Original address of DrawMenuBar
@oldSM DC.W $4EF9 ; JMP.L
DC.L 0 ; Original address of SystemMenu
@oldMS DC.W $4EF9 ; JMP.L
DC.L 0 ; Original address of MenuSelect
@STORAGEH DC.L 0 ; This is were we stash our storage
NOP
NOP ; Lets Jasik display things better
;------------------------------------------------------------------------------------
; Our DrawMenuBar patch
;
@ADRAWMENUBAR
MOVE.L @STORAGEH,A0 ; get handle to our storage
MOVE.L A0,-(A7) ; pass it on the stack
JSR CDRAWMENUBAR ; call our routine
BRA.S @oldDMB ; go to original code
;------------------------------------------------------------------------------------
; Our DrawMenuBar patch
;
@ASYSTEMMENU
LINK A6,#0
MOVE.L 8(A6),-(A7) ; put the SystemMenu paramter on the stack
MOVE.L @STORAGEH,A0 ; get handle to our storage
MOVE.L A0,-(A7) ; pass it on the stack
JSR CSYSTEMMENU ; call our routine
UNLK A6
BRA.S @oldSM ; go to original code
;------------------------------------------------------------------------------------
; Our DrawMenuBar patch
;
@AMENUSELECT
BRA.S @oldMS ; go to original code
END
---------- StarMenuPatch.c ---------------------------------------
/*
StarMenuPatch.c
Copyright )1993 Peirce Software.
All rights reserved
Change History:
09-11-93 Michael Peirce Add this.
*/
#include <Memory.h>
#include <Traps.h>
#include "Icons.h"
#include <SysEqu.h>
#include "StarMenu.h"
#pragma segment Main
//
// CDRAWMENUBAR - The C routine that is our patch to DrawMenuBar. It is called
// by our assembly language patch. We can do all our work here and have all
// the ease of using a "high level language" instead of assembler.
//
// In this routine we always insert our menu into the bar. The first time
// through, we construct the menu since we couldn't at INIT time (the menu
// manager might not have been intialized).
//
pascal void CDRAWMENUBAR(STORAGEH storage)
{
MenuHandle ourMenu;
ourMenu = _OurMenuHandle;
if (ourMenu == nil) { // initialize our menu
THz currentHeapZone;
char newMenuName[] = "\p12345";
currentHeapZone = GetZone();
SetZone(SystemZone());
newMenuName[1] = 1;
BlockMove(&_MenuIconFamily,&newMenuName[2],4);
ourMenu = NewMenu(_MenuID,newMenuName);
AppendMenu(ourMenu,"\pBeep Once");
AppendMenu(ourMenu,"\pBeep Twice");
AppendMenu(ourMenu,"\pBeep Thrice");
AppendMenu(ourMenu,"\pBeep Four Times");
_OurMenuHandle = ourMenu;
SetZone(currentHeapZone);
}
InsertMenu(ourMenu,0);
}
//
// CSYSTEMMENU - The C routine that is our patch to SystemMenu It is called
// by our assembly language patch. We can do all our work here and have all
// the ease of using a "high level language" instead of assembler.
//
// In this routine, we check for a hot on our menu. If so we handle it.
//
pascal void CSYSTEMMENU(short menuItem, short menuID, STORAGEH storage)
{
#pragma unused(storage)
short i;
if (menuID == _MenuID) {
for (i=0;i<menuItem;i++)
SysBeep(5);
}
HiliteMenu(0);
}
pascal void CMENUSELECT(STORAGEH storage)
{
#pragma unused(storage)
}
---------- StarMenu.h ---------------------------------------
/*
StarMenu.h
Copyright )1993 Peirce Software.
All rights reserved
Change History:
09-11-93 Michael Peirce Add this.
*/
#include <Types.h>
#include <Menus.h>
#include <Memory.h>
#include <Quickdraw.h>
#include <Dialogs.h>
#include <Events.h>
#include <Devices.h>
#include <Packages.h>
#include <Fonts.h>
#include <GestaltEqu.h>
#include <Folders.h>
#include <Resources.h>
#include <ToolUtils.h>
//
// STORAGERec is where we stash all our global variables used
// throughout the various patches that make up this extension.
//
typedef struct STORAGERec
{
MenuHandle ourMenuHandle;
Handle menuIconFamily;
short menuID;
} STORAGERec, *STORAGEPtr, **STORAGEH;
//
// Easy access macros for accessing our globals through the handle.
//
#define _OurMenuHandle ((**storage).ourMenuHandle)
#define _MenuIconFamily ((**storage).menuIconFamily)
#define _MenuID ((**storage).menuID)
---------- StarMenuPatch.r ---------------------------------------
/*
StarMenuPatch.r
Copyright )1993 Peirce Software.
All rights reserved
Change History:
09-11-93 Michael Peirce Add this.
*/
#include "types.r"
resource 'ics4' (128) {
$"0000 FFFF FFFF 0000 000F FE88 88EF F000"
$"00AF 8888 8888 FF00 0AF8 AA88 88AA 8FF0"
$"FF8A FFA8 8AFF A8FF FE8A FFA8 8AFF A8EF"
$"F888 AA88 88AA 888F F888 8888 8888 888F"
$"F88E FFFF FFFF E88F F88F DDDD DDDD F88F"
$"FE8F DDDD DDDD F8EF FF8E FFFF FFFF E8FF"
$"0FF8 8888 8888 8FF0 00FF 8888 8888 FF00"
$"000F FE88 88EF F000 0000 FFFF FFFF"
};
resource 'ics#' (128) {
{ /* array: 2 elements */
/* [1] */
$"0FF0 1818 300C 6C36 D24B 9249 8C31 8001"
$"8FF1 9009 9009 CFF3 6006 300C 1818 0FF0",
/* [2] */
$"0FF0 1FF8 3FFC 7FFE FFFF FFFF FFFF FFFF"
$"FFFF FFFF FFFF FFFF 7FFE 3FFC 1FF8 0FF0"
}
};
resource 'ics8' (128) {
$"0000 0000 FFFF FFFF FFFF FFFF 0000 0000"
$"0000 00FF FFA5 E3E3 E3E3 A5FF FF00 0000"
$"0000 FDFF E3E3 E3E3 E3E3 E3E3 FFFF 0000"
$"00FD FFE3 FDFD E3E3 E3E3 FDFD E3FF FF00"
$"FFFF E3FD FFFF FDE3 E3FD FFFF FDE3 FFFF"
$"FFA5 E3FD FFFF FDE3 E3FD FFFF FDE3 A5FF"
$"FFE3 E3E3 FDFD E3E3 E3E3 FDFD E3E3 E3FF"
$"FFE3 E3E3 E3E3 E3E3 E3E3 E3E3 E3E3 E3FF"
$"FFE3 E3A5 FFFF FFFF FFFF FFFF A5E3 E3FF"
$"FFE3 E3FF 3333 3333 3333 3333 FFE3 E3FF"
$"FFA5 E3FF 3333 3333 3333 3333 FFE3 A5FF"
$"FFFF E3A5 FFFF FFFF FFFF FFFF A5E3 FFFF"
$"00FF FFE3 E3E3 E3E3 E3E3 E3E3 E3FF FF00"
$"0000 FFFF E3E3 E3E3 E3E3 E3E3 FFFF 0000"
$"0000 00FF FFA5 E3E3 E3E3 A5FF FF00 0000"
$"0000 0000 FFFF FFFF FFFF FFFF"
};
data 'sysz' (0) {
$"0000 5000" /* ..P. */
};
---------- StarMenu.make ---------------------------------------
#
# StarMenu.make
#
# Copyright )1993 Peirce Software.
# All rights reserved
#
# Change History:
#
# 09-11-93 Michael Peirce Add this.
#
# make -f StarMenu.make > StarMenu.make.out; StarMenu.make.out; Beep
COptions = -d MPW3 -r -sym full -b2 -mbg ch8 # define MPW3, turn on strict prototyping (-r option)
ObjDir = ":Objects:"
InitObjs = {ObjDir}StarMenuInit.c.o 6
{ObjDir}StarMenuPatch.c.o 6
"{Libraries}"Interface.o
InitpObjs = {ObjDir}StarMenuPatch.a.o 6
{ObjDir}StarMenuPatch.c.o 6
"{Libraries}"Interface.o
StarMenu ff {InitObjs} StarMenu.make
echo '#.# Linking StarMenu INIT'
Link -o {Targ} -t INIT -c STAR -rt INIT=0 -m STARMENUENTRY {InitObjs} && 6
Setfile StarMenu -a B && 6
Duplicate -y StarMenu "{SystemFolder}Extensions:"
StarMenu ff {InitpObjs} StarMenu.make
echo '#.# Linking StarMenu Patches'
Link -o {Targ} -t INIT -c STAR -rt rCod=1 -m PATCHES {InitpObjs} && 6
Setfile StarMenu -a B && 6
Duplicate -y StarMenu "{SystemFolder}Extensions:"
StarMenu ff StarMenu.r StarMenu.make
echo '#.# Rezzing StarMenu.r'
Rez -o {Targ} StarMenu.r -t INIT -c STAR -rd -append && 6
Setfile StarMenu -a B && 6
Duplicate -y StarMenu "{SystemFolder}Extensions:"
{ObjDir}StarMenuPatch.c.o f StarMenuPatch.c StarMenu.h StarMenu.h
echo '#.# Compiling StarMenuPatch.c'
c {COptions} StarMenuPatch.c -o {ObjDir}StarMenuPatch.c.o
{ObjDir}StarMenuInit.c.o f StarMenuInit.c StarMenu.h
echo '#.# Compiling StarMenuInit.c'
c {COptions} StarMenuInit.c -o {ObjDir}StarMenuInit.c.o
{ObjDir}StarMenuPatch.a.o f StarMenuPatch.a StarMenu.h
echo '#.# Assembling StarMenuPatch.a'
asm StarMenuPatch.a -o {ObjDir}StarMenuPatch.a.o
---------- end ---------------------------------------
--
-- Michael Peirce --
[email protected]
-- Peirce Software -- Suite 301, 719 Hibiscus Place
-- -- San Jose, California USA 95117
-- Makers of: -- voice: +1.408.244.6554 fax: +1.408.244.6882
-- Smoothie -- AppleLink: peirce & America Online: AFC Peirce