*
*   Standard Application Shell  - Assembly Version
*             Developer Technical Support
*
*     v3.0    Mensch & Rollin, Deatherage & Luther
*
*    Developer Technical Support Apple II Sample Code
*
*    Copyright (c) Apple Computer, Inc. 1988-1990
*               All Rights Reserved.
*
*   ------------------------------------------------------
*
*   This program and its derivatives are licensed only for
*   use on Apple computers.
*
*   Works based on this program must contain and
*   conspicuously display this notice.
*
*   This software is provided for your evaluation and to
*   assist you in developing software for the Apple IIGS
*   computer.
*
*   DISCLAIMER OF WARRANTY
*
*   THE SOFTWARE IS PROVIDED "AS IS" WITHOUT
*   WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
*   WITH RESPECT TO ITS MERCHANTABILITY OR ITS FITNESS
*   FOR ANY PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO
*   THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
*   YOU.  SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU (AND
*   NOT APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE)
*   ASSUME THE ENTIRE COST OF ALL NECESSARY SERVICING,
*   REPAIR OR CORRECTION.
*
*   Apple does not warrant that the functions
*   contained in the Software will meet your requirements
*   or that the operation of the Software will be
*   uninterrupted or error free or that defects in the
*   Software will be corrected.
*
*   SOME STATES DO NOT ALLOW THE EXCLUSION
*   OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY
*   NOT APPLY TO YOU.  THIS WARRANTY GIVES YOU SPECIFIC
*   LEGAL RIGHTS AND YOU MAY ALSO HAVE OTHER RIGHTS
*   WHICH VARY FROM STATE TO STATE.
*
	EJECT
	PRINT NOGEN,NOHDR

	STRING ASIS

	PRINT PUSH,OFF
	INCLUDE 'E16.Types'
	INCLUDE 'M16.Util'
	INCLUDE 'M16.GSOS'
	INCLUDE 'E16.GSOS'
	INCLUDE 'M16.Locator'
	INCLUDE 'E16.Locator'
	INCLUDE 'M16.ADB'
	INCLUDE 'E16.ADB'
	INCLUDE 'M16.IntMath'
	INCLUDE 'E16.IntMath'
	INCLUDE 'M16.TextTool'
	INCLUDE 'E16.TextTool'
	INCLUDE 'M16.Memory'
	INCLUDE 'E16.Memory'
	INCLUDE 'M16.SANE'
	INCLUDE 'E16.SANE'
	INCLUDE 'M16.ACE'
	INCLUDE 'E16.ACE'
	INCLUDE 'M16.Resources'
	INCLUDE 'E16.Resources'
	INCLUDE 'M16.MiscTool'
	INCLUDE 'E16.MiscTool'
	INCLUDE 'M16.Scheduler'
	INCLUDE 'E16.Scheduler'
	INCLUDE 'M16.Loader'
	INCLUDE 'E16.Loader'
	INCLUDE 'M16.Quickdraw'
	INCLUDE 'E16.Quickdraw'
	INCLUDE 'M16.QDAux'
	INCLUDE 'E16.QDAux'
	INCLUDE 'M16.Event'
	INCLUDE 'E16.Event'
	INCLUDE 'M16.Control'
	INCLUDE 'E16.Control'
	INCLUDE 'M16.Window'
	INCLUDE 'E16.Window'
	INCLUDE 'M16.Menu'
	INCLUDE 'E16.Menu'
	INCLUDE 'M16.LineEdit'
	INCLUDE 'E16.LineEdit'
	INCLUDE 'M16.Dialog'
	INCLUDE 'E16.Dialog'
	INCLUDE 'M16.Sound'
	INCLUDE 'E16.Sound'
	INCLUDE 'M16.NoteSyn'
	INCLUDE 'E16.NoteSyn'
	INCLUDE 'M16.NoteSeq'
	INCLUDE 'E16.NoteSeq'
	INCLUDE 'M16.MIDI'
	INCLUDE 'E16.MIDI'
	INCLUDE 'M16.StdFile'
	INCLUDE 'E16.StdFile'
	INCLUDE 'M16.Scrap'
	INCLUDE 'E16.Scrap'
	INCLUDE 'M16.Desk'
	INCLUDE 'E16.Desk'
	INCLUDE 'M16.List'
	INCLUDE 'E16.List'
	INCLUDE 'M16.Font'
	INCLUDE 'E16.Font'
	INCLUDE 'M16.Print'
	INCLUDE 'E16.Print'
	INCLUDE 'M16.TextEdit'
	INCLUDE 'E16.TextEdit'
	INCLUDE 'M16.Video'
	INCLUDE 'E16.Video'

	PRINT POP

*******************************************************************************
*
*    Equates used in this program.
*

; Offsets into direct page
Deref	equ 0	; for temporary dereferencing

; menu item numbers for standard DA menu items
UndoID	equ 250
CutID	equ 251
CopyID	equ 252
PasteID	equ 253
ClearID	equ 254
CloseID	equ 255

; application menu item numbers
AboutID	equ $1101	; 1st item of 1st menu of 1st menu bar
QuitID	equ $1202	; 2nd item of 2nd menu of 1st menu bar

; application menu numbers
AppleMenuID	equ $1100	; 1st menu of 1st menu bar
FileMenuID	equ $1200	; 2nd menu of 1st menu bar
EditMenuID	equ $1300	; 3rd menu of 1st menu bar

; resource ID numbers
BaseResID	equ $00000000	; start of resource ID numbers
MenuBarOneRID	equ $00001000	; resource ID of menu bar

MyTaskMask	equ $001FFFFF	; Handle all events possible

	EJECT
*******************************************************************************
*
main	PROC
*
* Description:	This is the main routine. It calls procedures to startup
*	the tools, initialize application specific data, run the
*	main eventLoop, close the application, and shutdown the
*	tools.  Then it calls the GS/OS Quit command.
*
* Inputs:	NONE
* Outputs:	NONE
* External Refs:
	import initTools
	import initApp
	import eventLoop
	import closeApp
	import closeTools
	import QuitParms
* Entry Points:	NONE
*
	jsr initTools	; Initialize tools.
	jsr initApp	; Initialize application specific
		; stuff.

	jsr eventLoop	; Do application stuff until user 
		; wants to do something else!
	
	jsr closeApp	; ShutDown application specific things.
	jsr closeTools	; ShutDown the tools.

	_QuitGS QuitParms	; and Quit
	ENDP

	EJECT
*******************************************************************************
*
Globals	Record
*
* Description:	Holder of all of our data.
*
* Inputs:	N/A
* Outputs:	N/A
* External Refs:	NONE
* Entry Points:
	export QuitParms	; used by main
*

; Standard global variables here
MyMemoryID	ds.B 2	; Application's memory ID
Done	ds.W 1	; flag to show when to quit application
ToolRecRef	ds.B 4	; StartStopRec from StartUpTools
WindowKind	ds.B 2	; type of top window from GetWKind call
MenuHeight	ds.B 2	; Stored height of menu bar
QuitParms	dc.W $00	; pCount = 0

; The following is the record that is used by TaskMaster to return
; events. It is similar to a regular event record, except that there are
; additional fields at the end. The first additional field is used to convey
; some TaskMaster specific data back to the application. The second additional
; field is called the TaskMask and is used to tell TaskMaster what situations
; to handle.  In this shell, we tell TaskMaster to handle everything by
; setting all currently defined bits to 1 (MyTaskMask) in the initApp
; routine.

MyEvent
EventWhat	ds.B 2
EventMessage	ds.B 4
EventWhen	ds.B 4
EventWhere	ds.B 4
EventModifiers	ds.B 2
TaskData	ds.B 4
TaskMask	dc.L MyTaskMask
LastClickTick	ds.B 4
ClickCount	ds.B 2
TaskData2	ds.B 4
TaskData3	ds.B 4
TaskData4	ds.B 4
LastClickPtY	ds.B 2
LastClickPtX	ds.B 2

	EndR

	EJECT
*******************************************************************************
*
initTools	PROC
*
* Description:	Load and startup the tools needed. Errors are detected
*	and fatalError is called if any occur.
*
* Inputs:	NONE
* Outputs:	NONE
* External Refs:
	import fatalError
* Entry Points:	NONE
*
	with Globals

	phk	; save program bank register and
	plb	; load it as the data bank register

	_TLStartup	; start up Tool Locator
	bcc initMM
	ldx #$1	; if error, then set the error
		; reference number
	jmp fatalError	; and jump to fatal routine

initMM	pha	; space for result
	_MMStartup	; start up memory manager
	bcc getMMID
	ldx #$2	; if error, then set the error
		; reference number
	jmp fatalError	; and jump to fatal routine

getMMID	PullWord MyMemoryID	; Get the Memory ID returned

	PushLong #$0	; space for the Record returned
	PushWord MyMemoryID	; our User ID
	PushWord #refIsResource ; the StartStopRec is a resource
	PushLong #BaseResID+1 ; the actual resource ID
	_StartUpTools
	bcc getToolRecRef
	ldx #$3	; if error, then set the error
		; reference number
	jmp fatalError	; and jump to fatal routine

getToolRecRef	PullLong ToolRecRef ; Store the reference returned

	rts
	ENDP

	EJECT
*******************************************************************************
*
fatalError	PROC
*
* Description:	Routine that is called whenever an error is detected
*	that can not be recovered from. This routine prints an
*	error message, waits for a keypress, then quits back
*	to whoever started this application up!
*
* Inputs:	A = Error number
*	X = the reference number that tells you where in
*	initTools the error happened.
* Outputs:	NONE (program exits)
* External Refs:
	import closeTools
* Entry Points:	NONE
*
	with Globals

	phx	; save the "where" reference number
	
	pha	; Push the error code
	PushLong #errNumStr	; Address of storage area
	PushWord #$4	; Length of string
	_Int2Hex

	pla	; get the "where" reference number
	pha	; and push it
	PushLong #errWhereStr ; Address of storage area
	PushWord #$4	; Length of string
	_Int2Hex
	
	_GrafOff	; If QD Started, shut off graphics

	PushLong #ErrStr	; Write error message to the screen
	_WriteCString
	
	_SysBeep	; ring the bell

	pha	; Space for result
	PushWord #noEcho	; No echo
	_ReadChar	; Wait for a key to be pressed
	pla	; Discard the key

	jsr closeTools	; Shut down all the tools in case
		; any got started up

	_QuitGS QuitParms	; Quit back to where we came from.

; Quit can only fail with GS/OS busy, so we never come back from the quit call.
	
ErrStr	dc.B 'Fatal error $'
ErrNumStr	dc.B 'xxxx has occured at '
ErrWhereStr	dc.B 'xxxx. Press any key to exit:',0

	ENDP

	EJECT
*******************************************************************************
*
initApp	PROC
*
* Description:	Perform any application specific initialization. For this
*	app, we initialize the Done to false, set WindowKind to
*	an application window kind, and initialize all of the
*	menus.
*
*	You might use this procedure to create windows, initialize
*	variables and allocate memory needed for the entire
*	program.
*
* Inputs:	NONE
* Outputs:	NONE
* External Refs:	NONE
* Entry Points:	NONE
*
	with Globals

	stz Done	; we aren't done yet
	stz WindowKind	; window kind = application

;
; create default system menu bar from a resource and make it the
; current menu bar
;
	pha
	pha	; space for result
	PushWord #refIsResource ; reference is resource
	PushLong #MenuBarOneRID ; menu bar resource ID
	PushLong #$0	; system menu bar
	_NewMenuBar2
		
	_SetSysBar	; and this is the system bar
	
	PushLong #$0	; zero means use the system menu bar
	_SetMenuBar
	
	PushLong #$0	; refresh the whole desktop
	_RefreshDeskTop

	_InitCursor	; normal arrow cursor

	PushWord #AppleMenuID ; Add NDA's
	_FixAppleMenu

	pha	; Call FixMenuBar to cause the menu
	_FixMenuBar	; Compute standard menu sizes
	PullWord MenuHeight	; and store the menu height for later

	_DrawMenuBar	; Finally, draw it.

	rts
	ENDP

	EJECT
*******************************************************************************
*
eventLoop	PROC
*
* Description:	The Event Loop. Handle things until user selects Quit.
*
* Inputs:	NONE
* Outputs:	NONE
* External Refs:
	import doMenu
	import testTopWindow
* Entry Points:	NONE
*
	with Globals

	jsr testTopWindow	; test to see if top window is a DA
	
	pha	; Push on space for TaskMaster result
	PushWord #EveryEvent ; GetNextEvent mask
	PushLong #MyEvent	; Pointer to Event Record
	_TaskMaster
	pla	; Get TaskMaster result
	
; Now we have the task type

	ldx #endTaskTable-taskTable-4
checkNextItem	cmp taskTable,x	; are we handling this event?
	beq doRoutine	; yes, then call a routine
	dex	; no, then keep checking
	dex
	dex
	dex
	bpl checkNextItem	; keep scanning table
	
	bra eventLoop	; event not handled, so get another	
	
doRoutine	jsr (taskTable+2,x)	; call the routine
	
	lda Done	; Quit selected?
	beq eventLoop	; no - keep looping

	rts	; yes- leave the program

; With most of these events, we do nothing (in fact, most applications will
; never see some of these events). You should cut or comment out the lines
; for events your application does not use out of this table (as we've done).
; Any of these events your application does use should call a routine to
; handle the event.

taskTable
;	dc.W nullEvt,	doNullEvt
;	dc.W mouseDownEvt, 	doMouseDownEvt
;	dc.W mouseUpEvt,	doMouseUpEvt
;	dc.W keyDownEvt,	doKeyDownEvt
;	dc.W autoKeyEvt,	doAutoKeyEvt
;	dc.W updateEvt,	doUpdateEvt
;	dc.W activateEvt,	doActivateEvt
;	dc.W switchEvt,	doSwitchEvt
;	dc.W deskAccEvt,	doDeskAccEvt
;	dc.W driverEvt,	doDriverEvt
;	dc.W app1Evt,	doApp1Evt
;	dc.W app2Evt,	doApp2Evt
;	dc.W app3Evt,	doApp3Evt
;	dc.W app4Evt,	doApp4Evt
;	dc.W wInDesk,	doWInDesk
	dc.W wInMenuBar,	doMenu
;	dc.W wClickCalled,	doWClickCalled
;	dc.W wInContent,	doWInContent
;	dc.W wInDrag,	doWInDrag
;	dc.W wInGrow,	doWInGrow
;	dc.W wInGoAway,	doWInGoAway
;	dc.W wInZoom,	doWInZoom
;	dc.W wInInfo,	doWInInfo
	dc.W wInSpecial,	doMenu
;	dc.W wInDeskItem,	doWInDeskItem
;	dc.W wInFrame,	doWInFrame
;	dc.W wInactMenu,	doWInactMenu
;	dc.W wClosedNDA,	doWClosedNDA
;	dc.W wCalledSysEdit,doWCalledSysEdit
;	dc.W wTrackZoom,	doWTrackZoom
;	dc.W wHitFrame,	doWHitFrame
;	dc.W wInControl,	doWInControl
;	dc.W wInControlMenu,doWInControlMenu
endTaskTable	

	ENDP

	EJECT
*******************************************************************************
*
closeApp	PROC
*
* Description:	Close down things. This disposes of all items and memory
*	that we allocated. Usually undoes what was done in
*	initApp.  We don't close our window since _WindShutDown
*	does it for us.
*
* Inputs:	NONE
* Outputs:	NONE
* External Refs:	NONE
* Entry Points:	NONE
*
	with Globals
	
; do nothing in this shell

	rts
	ENDP

	EJECT
*******************************************************************************
*
closeTools	PROC
*
* Description:	Shut down the tools I started.
*
* Inputs:	NONE
* Outputs:	NONE
* External Refs:	NONE
* Entry Points:	NONE
*
	with Globals

	PushWord #refIsHandle ; A handle (since StartUp returned it)
	PushLong ToolRecRef ; The value returned by StartUpTools
	_ShutDownTools
	
	PushWord MyMemoryID
	_MMShutDown
	_TLShutDown

	rts
	ENDP

	EJECT
*******************************************************************************
*
testTopWindow	PROC
*
* Description:	This routine is called on every NULL event. It checks the
*	type of the top window, if it has changed from App window
*	to system window or back, this routine will call
*	doSysChange.
*
* Inputs:	NONE
* Outputs:	NONE
* External Refs:
	import doSysChange
* Entry Points:	NONE
*
	with Globals
	
	PushLong #$0	; first get a pointer to the frontmost
	_FrontWindow	; window
	PullLong Deref	; store it in deref temporarily
	
	lda Deref	; first test for a NIL pointer. If its
	ora Deref+2	; NIL then we do not have to do the 
	beq checkKind	; getWKind call
	
	PushWord #$0	; if not a NIL pointer then get the
	PushLong Deref	; Kind of window
	_getWKind
	pla
	
checkKind	cmp WindowKind	; Now test the window kind to see if it
	beq noChange	; has changed, if not then ignore it
	
	sta WindowKind	; if the window kind has changed, then
	jsr doSysChange	; save the new value and change menus

noChange	rts
	EndP

	EJECT
*******************************************************************************
*
doSysChange	PROC
*
* Description:	Called by eventLoop when the upper most window
*	has changed to or from a system window.
*
* Inputs:	<A> Bit 15 of WindowKind is 0 if top window is an
*	application window, 1 if top window is a system window.
* Outputs:	NONE
* External Refs:	NONE
* Entry Points:	NONE
*
	with Globals

	and #%1000000000000000
	bpl SysDeact	; if high bit clear then App Window

; This routine enables the edit menu when a system window becomes active

SysActivate	PushWord #UndoID	; its an activate event so go thru and
	_EnableMItem	; enable all the edit items and the
	
	PushWord #CutID	; close Item
	_EnableMItem
	
	PushWord #CopyID
	_EnableMItem
	
	PushWord #PasteID
	_EnableMItem
	
	PushWord #ClearID
	_EnableMItem
	
	PushWord #CloseID
	_EnableMItem
	
; If your edit menu has items that are selectable when a DA is not front-most,
; remove the next six lines.
	PushWord #enableMenu ; defined in E16.Menu
	PushWord #EditMenuID
	_SetMenuFlag
	pea $0000	; FALSE
	PushWord #EditMenuID
	_HiliteMenu
	
	rts

; This routine disables the edit menu when an system window is not active

SysDeact	PushWord #UndoID	; its an deactivate event so go thru 
	_DisableMItem	; and disable all the edit items and 
	
	PushWord #CutID	
	_DisableMItem
	
	PushWord #CopyID
	_DisableMItem
	
	PushWord #PasteID
	_DisableMItem
	
	PushWord #ClearID
	_DisableMItem

	PushWord #CloseID	; the close Item
	_DisableMItem

; If your edit menu has items that are selectable when a DA is not front-most,
; remove the next six lines.
	PushWord #disableMenu ; defined in E16.Menu
	PushWord #EditMenuID
	_SetMenuFlag
	pea $0000	; FALSE
	PushWord #EditMenuID
	_HiliteMenu
	
	rts
	ENDP

	EJECT
*******************************************************************************
*
doMenu	PROC
*
* Description:	This routine is called when TaskMaster returns a menu
*	event. It takes the menu item that was hit and calls the
*	proper routine, and then unhilites the menu when it is
*	done. 
*
* Inputs:	TaskData holds menu item selected.
* Outputs:	NONE
* External Refs:
	import doAbout
	import doQuit
* Entry Points:	NONE
*
	with Globals
	
	lda TaskData	; get ID of selected menu item
	
	ldx #endMenuTable-menuTable-4
checkNextItem	cmp menuTable,x
	beq doRoutine
	dex
	dex
	dex
	dex
	bpl checkNextItem

	pha	; space for result
	PushWord #$4	; reference is resource
	PushLong #$0	; no substitution strings currently
	PushLong #BaseResID+2 ; alertString resource ID
	_AlertWindow
	pla	; get the button number and dispose
	bra finishUp
	
doRoutine	jsr (menuTable+2,x)	; and call the routine
	
finishUp	PushWord #$0	; Routine done - unhilite the menubar.
	PushWord taskData+2 ; the menu number
	_HiLiteMenu

	rts
	
; Menu items that are ignored in this shell are included, but commented out.

menuTable
;	dc.W UndoID,  doUndo
;	dc.W CutID,   doCut
;	dc.W CopyID,  doCopy
;	dc.W PasteID, doPaste
;	dc.W ClearID, doClear
;	dc.W CloseID, doClose ; close handled by TaskMaster
	dc.W AboutID, doAbout ; show about dialog
	dc.W QuitID,  doQuit  ; set Done flag
endMenuTable	

	ENDP

	EJECT
*******************************************************************************
*
doAbout	PROC
*
* Description:	Bring up an Alert Dialog box with our about message in it.
*
* Inputs:	NONE
* Outputs:	NONE
* External Refs:	NONE
* Entry Points:	NONE
*
	with Globals

	pha	; space for result
	PushWord #$4	; reference is resource
	PushLong #$0	; no substitution strings currently
	PushLong #BaseResID+1
		; alertString resource ID
	_AlertWindow
	pla	; get the button number and dispose

	rts
	ENDP

	EJECT
*******************************************************************************
*
doQuit	PROC
*
* Description:	Set the Done flag to true. This tells the Event loop to
*	exit.
*
* Inputs:	NONE
* Outputs:	Done set to $FFFF (true)
* External Refs:	NONE
* Entry Points:	NONE
*
	with Globals

	lda #$FFFF	; load any non-zero value
	sta Done	; and save it in the Done
	rts
	ENDP

	END
