;*******************************************************************************
; Director - Task
;
; Copyright (C) 2003, Nick Craig-Wood and Philip Ludlam
;
;This program is free software; you can redistribute it and/or modify it under
;the terms of the GNU General Public License as published by the Free Software
;Foundation; either version 2 of the License, or (at your option) any later
;version.
;
;This program is distributed in the hope that it will be useful, but WITHOUT ANY
;WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
;PARTICULAR PURPOSE. See the GNU General Public License for more details.
;
;You should have received a copy of the GNU General Public License along with
;this program; if not, write to the Free Software Foundation, Inc., 59 Temple
;Place - Suite 330, Boston, MA 02111-1307, USA
;
;*******************************************************************************
;----h- Director.s.Task
; Name
;   Task
;
; Purpose
;   Task
;------
;*******************************************************************************


		TTL	>Task

		GET	OSLib:oslib.hdr.Wimp
		GET	OSLib:oslib.hdr.WimpReadSysInfo
		GET	OSLib:oslib.hdr.DragASprite
		GET	OSLib:oslib.hdr.Filer
		GET	OSLib:oslib.hdr.FilerAction
		GET	OSLib:oslib.hdr.Help
		GET	OSLib:oslib.hdr.OSModule
		GET	OSLib:oslib.hdr.OSFile
		GET	OSLib:oslib.hdr.OSFSControl
		GET	OSLib:oslib.hdr.OSGBPB
		GET	OSLib:oslib.hdr.OSByte
		GET	OSLib:oslib.hdr.OSWord
		GET	OSLib:oslib.hdr.InetSuite
		GET	AsmLib2:hdr.RegsBoth
		GET	AsmLib2:hdr.MacrosBoth
		GET	AsmLib2:hdr.DebugBoth
		GET	h.Constants
		GET	h.WorkSpace
		GET	h.ListMacros
		GET	h.ModuleHead
		GET	h.Memory
		GET	h.Menus
		GET	h.Memoriser
		GET	h.Messages
		GET	h.Icons
		GET	h.Windows
		GET	h.Filter
		GET	h.Edit
		GET	h.URL
		GET	h.BMG
		GET	h.Version

		AREA	|Task|, CODE, READONLY


;;;; Could remove the template space when have created the windows?

PollPeriod	EQU	100

		^	0
save_icon	#	1


;*******************************************************************************
;Variables local to the Task
;These are allocated from a block in the main workspace
;*******************************************************************************


			^	(:INDEX: TaskVars), wp
PollType		#	4
LastMenu		#	4
LastMenu_x		#	4
LastMenu_y		#	4
IgnoreMenusDeleted	#	4
ValidWimpPointer	#	4
DragPath		#	4
SaveWindowPath		#	4

			ASSERT	@ <= EndTaskVars


;*******************************************************************************
;This is for producing messages for debugging display
;it preserves all registers and flags
;*******************************************************************************


		MACRO
$label		DebugAlert	$message

$label		STMFD	sp!, {r0}

		ADR	r0, %FT00
		BL	Alert
		B	%FT10
00
		ERROR	"$message", 1
10
		LDMFD	sp!, {r0}

		MEND


;*******************************************************************************
;----f- Director.s.Task.TaskShutDown
; Name
;   TaskShutDown
;
; Purpose
;   This shuts down the task
;
; Entry
;   none
;
; Exit
;   none
;------
;*******************************************************************************


TaskShutDown	ROUTINE_SF	"r0-r11", EXPORT
buffer$l	#	StringSize
		END_SF

		MOV	r1, #$Name._Status_Quit
		STR	r1, Status

		LDR	r0, TaskHandle
		CMP	r0, #0				; are we already running?
		BEQ	exit$l				; if not, exit

		ADR	r1, buffer$l
		MOV	r3, #0				; context
loop$l		ADR	r0, name$l
		MOV	r2, #StringSize - 1		; buffer length
		MOV	r4, #OS_VartypeExpanded
		SWI	XOS_ReadVarVal
		BVS	cont$l				; ignore errors
		CMP	r2, #0
		BEQ	loop$l				; no bytes read
		BLT	cont$l
		MOV	lr, #0
		STRB	lr, [r1, r2]			; 0 terminate
		MOV	r0, r1
		BL	StartWimpTask			; ignore errors
		B	loop$l				; and continue
cont$l

		BL	FilterFinalise
		BL	MemoriserFinalise
		BL	MessageFinalise			; release hold on messages file.


		ADR	r0, MenuDisplayedAnchor
		BL	MenuBlockListDestroy		; delete all menu blocks

		ADR	r0, MenuStoredAnchor
		BL	MenuBlockListDestroy		; delete all menu blocks

		BL	IconBlockListDestroy
		BL	WindowBlockListDestroy
		BL	EditBlockListDestroy
		BL	URLBlockListDestroy

		LDR	r0, TaskHandle
		LDR	r1, TASK
		SWI	XWimp_CloseDown			; if so close us down
		MOV	r0, #0
		STR	r0, TaskHandle			; mark us as inactive

exit$l		EXIT

name$l		DCB	"$Name.$AtExit*", 0
		ALIGN


;*******************************************************************************
;----f- Director.s.Task.TaskShutDownAndKill
; Name
;   TaskShutDownAndKill
;
; Purpose
;   This shuts down the task and kills the module
;
; Entry
;   none
;
; Exit
;   none
;------
;*******************************************************************************


TaskShutDownAndKill	ROUTINE	"r0-r11", EXPORT

		BL	TaskShutDown

		MOV	r0, #0
		MOV	r1, #0
		MOV	r2, #0
		ADRL	r3, ModuleTitle
		SWI     OS_ExitAndDie			; expire, taking module with us

		EXIT


;*******************************************************************************
;----f- Director.s.Task.Star_DeskTop_Director
; Name
;   Star_DeskTop_Director
;
; Purpose
;   This starts off the Task as a Wimp Task
;
; Entry
;   none
;
; Exit
;   none
;------
;*******************************************************************************


Help_DeskTop_$Name	FOREXPORT
		[	OSVersion = 310
		DCB	"Do not use *DeskTop_$Name, use *DeskTop instead.", 13
		|
		DCB	"Help_DeskTop_Director", 0
		]

Syntax_DeskTop_$Name	FOREXPORT
		[	OSVersion = 310
		DCB	"Syntax: *DeskTop_$Name", 0
		|
		DCB	"Syntax_DeskTop_Director", 0
		]
		ALIGN

TaskTitle
ModuleTitle	EQUS0A	"$Name"
TASK		EQUSA	"TASK"

Star_DeskTop_$Name	ROUTINE	"r1-r3", EXPORT
		MOV	r0, #WimpReadSysInfo_DesktopState
		SWI	XWimp_ReadSysInfo
		SWIVS	OS_GenerateError
		CMP	r0, #WimpReadSysInfo_StateCommands
		BEQ	NotATask

		MOV	r2, r0				; r2 points at command tail
		ADR	r1, ModuleTitle			; r1 points at module name
		MOV	r0, #2				; Enter Module
		SWI	XOS_Module
		EXIT					; it shouldn't return, but exit with flags if it does

NotATask	ADR	r0, NotATaskError
		BL	MessageErrorLookup
		SetV
		EXIT

NotATaskError	ERROR	"$NotDeskTop", Error_NotDeskTop


;*******************************************************************************
;----f- Director.s.Task.GetIconAddresses
; Name
;   GetIconAddresses
;
; Purpose
;   This gets the addresses of the indirect text buffers for the icon
;
; Entry
;   r0 = window handle
;   r1 = icon number
;
; Exit
;   r0  indirect text
;   r1  validation
;------
;*******************************************************************************


GetIconAddresses	ROUTINE_SF
iconstate$l	#	Wimp_IconState
		END_SF

		STR	r0, iconstate$l + Wimp_IconState_w
		STR	r1, iconstate$l + Wimp_IconState_i
		ADR	r1, iconstate$l
		SWI	XWimp_GetIconState		; read state of icon
		BVS	TaskError
		LDR	r0, iconstate$l + Wimp_IconState_icon + Wimp_Icon_data + Wimp_IconData_indirected_text_text
		LDR	r1, iconstate$l + Wimp_IconState_icon + Wimp_Icon_data + Wimp_IconData_indirected_text_validation

		EXIT


;*******************************************************************************
;----f- Director.s.Task.SetIconState
; Name
;   SetIconState
;
; Purpose
;   This updates an icons state
;
; Entry
;   r0 = window
;   r1 = icon
;   r2 = clear
;   r3 = set
;
; Exit
;
;------
;*******************************************************************************


SetIconState	ROUTINE	"r0-r3", EXPORT

		MOV	r1, sp				; point to regs on stack
		SWI	XWimp_SetIconState
		BVS	TaskError

		EXIT


;*******************************************************************************
;----f- Director.s.Task.ORR_PollWord
; Name
;   ORR_PollWord
;
; Purpose
;   This orrs some bits into the PollWord with interrupts disabled
;   i.e. it sets selected bits in the PollWord.
;   used if Director needs to do something on the next WimpPoll
;
; Entry
;   r0 = bits to ORR into the pollword
;
; Exit
;   none
;------
;*******************************************************************************


ORR_PollWord	ROUTINE	"", EXPORT

		SWI	XOS_IntOff

		LDR	lr, PollWord
		ORR	lr, lr, r0
		STR	lr, PollWord

		SWI	XOS_IntOn

		EXIT


;*******************************************************************************
;----f- Director.s.Task.BIC_PollWord
; Name
;   BIC_PollWord
;
; Purpose
;   This BICs the supplied bits in the PollWord with interrupts disabled
;   i.e. it clears the bits.
;   It shoyld be called by routines which are invoked when the PollWord
;   is non zero.
;
; Entry
;   r0 = bits to BIC into the pollword
;
; Exit
;   none
;------
;*******************************************************************************


BIC_PollWord	ROUTINE	"", EXPORT

		SWI	XOS_IntOff

		LDR	lr, PollWord
		BIC	lr, lr, r0
		STR	lr, PollWord

		SWI	XOS_IntOn

		EXIT


;*******************************************************************************
;----f- Director.s.Task.LoadWindow
; Name
;   LoadWindow
;
; Purpose
;   This is called by the language entry point for the module in USR mode
;   with no stack
;
; Entry
;
;
; Exit
;
;------
;*******************************************************************************


LoadWindow	ROUTINE

		MOV	r1, r11
		ADR	r3, IndirectSpaceEnd
		MOV	r4, #-1
		MOV	r6, #0
		SWI	XWimp_LoadTemplate
		BVS	TaskError

		EXIT


;*******************************************************************************
;----f- Director.s.Task.CreateWindow
; Name
;   CreateWindow
;
; Purpose
;
;
; Entry
;
;
; Exit
;
;------
;*******************************************************************************


CreateWindow	ROUTINE

		MOV	r1, r11
		SWI	XWimp_CreateWindow
		BVS	TaskError

		EXIT


;*******************************************************************************
;----f- Director.s.Task.TaskStart
; Name
;   TaskStart
;
; Purpose
;
;
; Entry
;
;
; Exit
;
;------
;*******************************************************************************


TaskStart	FOREXPORT

		LDR	wp, [wp]			; get workspace pointer

;;;;		CMP	wp, #0
;;;;		BLE	NoWorkSpace
;;;;		need to check wimp is active before starting?
;;;;		and if not use one of those funny service calls later

		ADR	sp, TaskStack			; set up the stack pointer at top of PollBlock

		BL	TaskShutDown			; shut down any old versions of us

		ADR	r0, TaskVars
		MOV	r1, #EndTaskVars-TaskVars
		BL	memclear			; clear the task workspace

		MOV	r0, #$Name._Status_Init
		STR	r0, Status			; Initialising <- TRUE

		LDR	r0, =Wimp_VersionRO3
		LDR	r1, TASK
		ADRL	r2, TaskTitle
		ADR	r3, MessageList
		SWI	XWimp_Initialise		; initialise us as a task
		BVS	TaskError
		STR	r1, TaskHandle			; store our task handle for posterity


		BL	MessageInitialise		; start off MessageTrans
		BVS	TaskError

		BL	FilterInitialise		; start off the filter
		BVS	TaskError

		BL	MemoriserInitialise		; start off the memoriser
		BVS	TaskError

; 		BL	WindowInitialise		; start off the windows
		BVS	TaskError

		ADR	r11, PollSpace			; a bit of space to muck about in

		; Load in the templates
		ADR	r11, PollSpace			; some scratch space

		ADR	r1, TemplateFile
		SWI	XWimp_OpenTemplate
		BVS	TaskError

		ADR	r2, IndirectSpace		; workspace for indirect icons

		ADR	r5, InfoTemplate
		BL	LoadWindow
		BL	CreateWindow
		STR	r0, InfoWindow			; store handle of info window

		ADR	r5, SaveTemplate
		BL	LoadWindow
		BL	CreateWindow
		STR	r0, SaveWindow			; store handle of save window

		ADR	r5, KeysTemplate
		BL	LoadWindow
		LDR	r0, [r11, #Wimp_Window_visible + OS_Box_y0] ; move the window off screen
		SUB	r0, r0, #&7000
		STR	r0, [r11, #Wimp_Window_visible + OS_Box_y0]
		LDR	r0, [r11, #Wimp_Window_visible + OS_Box_y1]
		SUB	r0, r0, #&7000
		STR	r0, [r11, #Wimp_Window_visible + OS_Box_y1]
		BL	CreateWindow
		STR	r0, KeysWindow			; store handle of keys window

		SWI	XWimp_CloseTemplate		; close the template file
		BVS	TaskError

		; Write the version string in
		LDR	r0, InfoWindow
		MOV	r1, #4
		BL	GetIconAddresses		; r0  text, r1  validation
		MOV	r1, r0
		LDR	r0, =Version
		LDR	lr, StartModule
		ADD	r0, r0, lr
		BL	strcpy				; write version into indirect data

		; Write the author string in
		LDR	r0, InfoWindow			; = info whandle
		MOV	r1, #2				; = author ihandle
		BL	GetIconAddresses		; r0  text, r1  validation
		MOV	r1, r0
		LDR	r0, =Author			; author string
		LDR	lr, StartModule
		ADD	r0, r0, lr
		BL	strcpy				; write author into indirect data

		; Open the keys window
		LDR	r0, KeysWindow
;	 	MOV	r1, #-3				; Behind BackWindow
		MOV	r1, #Wimp_Bottom
		BL	OpenWindow

		;;;; do more initialisation things here

		MOV	r0, #$Name._Status_Run
		STR	r0, Status
		B	TaskPoll

		LTORG
TemplateFile	DCB	"<$Name.$$Resources>Templates", 0
InfoTemplate	DCB	"info", 0
SaveTemplate	DCB	"save", 0
KeysTemplate	DCB	"keys", 0
BarText		DCB	"", 0
BarString	DCB	"s$Name.Menu", 0
		ALIGN

MessageList 	DCD	Message_DataSaveAck
		DCD	Message_DataLoad
		DCD	Message_DataOpen
		DCD	Message_HelpRequest		; = &502
		DCD	Message_TaskInitialise
		DCD	Message_TaskCloseDown
		DCD	Message_MenuWarning
		DCD	Message_MenusDeleted
		DCD	Message_$Name.OpenMenu
		DCD	Message_$Name.Window
		DCD	Message_InetSuiteOpenURL	; = &4AF80
		DCD	Message_Quit			; must be last


;*******************************************************************************
;----f- Director.s.Task.ShowError
; Name
;   ShowError
;
; Purpose
;   This shows an error.
;
; Entry
;   r0  error
;
; Exit
;   If the user presses cancel then we quit.
;------
;*******************************************************************************


ShowErrorMT	ROUTINE "", EXPORT

		BL	MessageErrorLookup
		BL	ShowError

		EXIT


ShowError	ROUTINE	"r0-r3", EXPORT

		LDR	r1, Status
		CMP	r1, #$Name._Status_Init
		SWIEQ	OS_GenerateError		; an error while initialising is fatal

		MOV	r1, #Wimp_ErrorBoxOKIcon + Wimp_ErrorBoxCancelIcon	; r1 = &3
		ADR	r2, TaskTitle
		SWI	XWimp_ReportError		; ignore error
		CMP	r1, #2
		BEQ	DoMessage_Quit			; if cancel then end

		EXIT


;*******************************************************************************
;----f- Director.s.Task.AlertMT
; Name
;   AlertMT
;
; Purpose
;   This translates the error block text and then calls Alert
;
; Entry
;   none
;
; Exit
;   none
;------
;*******************************************************************************


AlertMT		ROUTINE	"r1", EXPORT

		BL	MessageErrorLookup
		BL	Alert

		EXIT


;*******************************************************************************
;----f- Director.s.Task.Alert
; Name
;   Alert
;
; Purpose
;   This displays the error string pointed to by r0 in an alert box
;
; Entry
;
;
; Exit
;
;------
;*******************************************************************************


Alert		ROUTINE	"r0-r3", EXPORT

		MOV	r1, #2_1
		ADRL	r2, TaskTitle
		SWI	XWimp_ReportError		; ignore error

		EXIT


;*******************************************************************************
;----f- Director.s.Task.Wimp_Poll
; Name
;   Wimp_Poll
;
; Purpose
;   This is the wimp poll routine for the Task
;
; Entry
;
;
; Exit
;
;------
;*******************************************************************************


TaskErrorMT	BL	MessageErrorLookup

TaskError	BL	ShowError

TaskPoll	ADR	sp, TaskStack + TaskStackSize	; set up the stack pointer

		SWI	XOS_ReadMonotonicTime
		BVS	TaskError
		ADD	r2, r0, #PollPeriod		; and don't come back until I tell you!
		LDR	r0, =(1 << Wimp_PointerLeavingWindow) + (1 << Wimp_PointerEnteringWindow) + (1 << Wimp_LoseCaret) + (1 << Wimp_GainCaret) + Wimp_GivenPollword ; mask
		ADR	r11, PollSpace
		MOV	r1, r11				; poll space
		ADR	r3, PollWord
		SWI	XWimp_PollIdle
		BVS	TaskError

		STR	r0, PollType
		CMP	r0, #Wimp_MouseClick		; CMP r0, #6
		MOVEQ	lr, #1
		MOVNE	lr, #0
		STR	lr, ValidWimpPointer		; signal that PollSpace contains a valid Wimp_Pointer
		ADR	lr, TaskPoll			; on return, do some more polling

		CMP	r0, #(JumpTableEnd - JumpTableStart)/4
		ADDCC	pc, pc, r0, LSL #2
		MOV	pc, lr

JumpTableStart
		B	NullReasonCode			;  0
;		B	RedrawWindowRequest		;  1
		MOV	pc, lr				;  1
		B	OpenWindowRequest		;  2
		B	CloseWindowRequest		;  3
;		B	PointerLeavingWindow		;  4
		MOV	pc, lr				;  4
;		B	PointerEnteringWindow		;  5
		MOV	pc, lr				;  5
		B	MouseClick			;  6
		B	UserDragBox			;  7
		B	KeyPressed			;  8
		B	MenuSelection			;  9
;		B	ScrollRequest			; 10
		MOV	pc, lr				; 10
;		B	LoseCaret			; 11
		MOV	pc, lr				; 11
;		B	GainCaret			; 12
		MOV	pc, lr				; 12
		B	PollwordNonZero			; 13
		MOV	pc, lr				; 14
		MOV	pc, lr				; 15
		MOV	pc, lr				; 16
		B	UserMessage			; 17
		B	UserMessageRecorded		; 18
		B	UserMessageAcknowledge		; 19
		MOV	pc, lr				; 20
		MOV	pc, lr				; 21
;		B	PollWord_			; 22
		MOV	pc, lr				; 22
;		B	PollwordPriority		; 23
		MOV	pc, lr				; 23
;		B	WimpFP				; 24
		MOV	pc, lr				; 24
JumpTableEnd
		LTORG


;*******************************************************************************
;----f- Director.s.Task.NullReasonCode
; Name
;   NullReasonCode
;
; Purpose
;   Handle Wimp_Poll Null poll events
;
; Entry
;
;
; Exit
;
;------
;*******************************************************************************


NullReasonCode	ROUTINE

		BL	IconBlockListNull
		BL	WindowBlockListNull

		EXIT


;*******************************************************************************
;----f- Director.s.Task.PollwordNonZero
; Name
;   PollwordNonZero
;
; Purpose
;   Called from Wimp_Poll routine when the Wimp returns with the
;   PollWordNonZero condidtion
;
; Entry
;   none
;
; Exit
;   none
;------
;*******************************************************************************


PollwordNonZero	ROUTINE

		LDR	r10, PollWord

		TST	r10, #$Name._PollWord_CreateIcon ; r10 AND 1
		BLNE	IconBlockListCreateIcons
		BVS	TaskError

		TST	r10, #$Name._PollWord_DirectorEdit ; r10 AND 2
		BLNE	EditBlockListDirectorEdit
		BVS	TaskError

		TST	r10, #$Name._PollWord_DirectorURL ; r10 AND 4
		BLNE	URLBlockListDirectorURL
		BVS	TaskError

		TST	r10, #$Name._PollWord_CreateWindow ; r10 AND 8
		BLNE	WindowCreateWindowPollWord
		BVS	TaskError

		TST	r10, #$Name._PollWord_DeleteWindow ; r10 AND 16
		BLNE	WindowDeleteWindowPollWord
		BVS	TaskError

		EXIT


;*******************************************************************************
;----f- Director.s.Task.KeyPressed
; Name
;   KeyPressed
;
; Purpose
;   Called from Wimp_Poll routine when the Wimp returns with the
;   KeyPressed condidtion
;
; Entry
;   none
;
; Exit
;   none
;------
;*******************************************************************************


KeyPressed	ROUTINE

		LDR	r10, [r11, #Wimp_Key_c]		; r10 = key
		MOV	r9, r10
		UpperCase	r9, lr			; r9 = uppercased key
		BL	ReadKeyModifiers
		ORR	r9, r9, r0			; glue on modifiers

		MOV	r0, r9
		ADR	r1, MenuStoredAnchor
		BL	FindHotKey
		CMP	r0, #0
		BNE	found$l

		MOV	r0, r9
		ADR	r1, MenuDisplayedAnchor
		BL	FindHotKey
		CMP	r0, #0
		BNE	found$l

		MOV	r0, r10
		SWI	XWimp_ProcessKey		; return the key to the wimp
		BVS	TaskError
		EXIT

found$l		CMP	r1, #0
		BEQ	openmenu$l
		MOV	r3, #Wimp_ClickAdjust
		BL	MenuCommand
		BVS	TaskError
		EXIT

openmenu$l	LDR	r0, [r0, #MenuBlock_name]
		BL	RunMenu
		BVS	TaskError
		EXIT


;*******************************************************************************
;----f- Director.s.Task.FindHotKey
; Name
;   FindHotKey
;
; Purpose
;
;
; Entry
;   r0 = key
;   r1  MenuBlock anchor
;
; Exit
;   r0  MenuBlock holding selected item, 0 for not found
;   r1  selected item, or 0 for a menu hot key
;   r2 = type of selected item
;------
;*******************************************************************************


FindHotKey	ROUTINE	"r3-r11"

		MOV	r11, r1				; r11  MenuBlock
		MOV	r10, r0				; r10 = key

loop$l		ListWalk	r11, lr
		MOVEQ	r0, #0
		EXIT	EQ				; end if not found

		LDR	r5, [r11, #MenuBlock_keys]
		CMP	r5, #0
		BEQ	loop$l
		LDR	r4, [r11, #MenuBlock_key_defs + StringBlock_buffer]

loop2$l		LDR	r0, [r4, #KeyBlock_key]
		CMP	r0, r10
		BEQ	found$l
		ADD	r4, r4, #KeyBlock
		SUBS	r5, r5, #1
		BGT	loop2$l

		B	loop$l

found$l		LDR	r1, [r4, #KeyBlock_entry]	; entry number
		CMP	r1, #0				; whole menu
		MOVLT	r1, #0				; so entry pointer is 0
		BLT	ok_end$l

		MOV	r0, #Wimp_MenuEntry
		MOV	lr, #Wimp_Menu_entries
		MLA	r1, r0, r1, lr			; offset to entry
		LDR	lr, [r11, #MenuBlock_menu + StringBlock_buffer]
		ADD	r1, r1, lr			; r1  pointer to entry

		LDR	r2, [r1, #Wimp_MenuEntry_icon_flags]
		AND	r2, r2, #Wimp_IconESG
		MOV	r2, r2, LSR #Wimp_IconESGShift	; r2 = type of icon

ok_end$l	MOV	r0, r11				; r0  MenuBlock
		EXIT


;*******************************************************************************
;----f- Director.s.Task.UserDragBox
; Name
;   UserDragBox
;
; Purpose
;   UserDragBox
;
; Entry
;
;
; Exit
;
;------
;*******************************************************************************


UserDragBox	ROUTINE
		SWI	XDragASprite_Stop
		BVS	TaskError

		LDR	r8, DragPath			; r8  full path

		ADD	r1, r11, #256			; get pointer info
		SWI	XWimp_GetPointerInfo
		BVS	TaskError
		LDR	r0, [r11, #256 + Wimp_Pointer_w]
		LDR	r1, [r11, #256 + Wimp_Pointer_i]
		LDR	r2, [r11, #256 + Wimp_Pointer_pos + OS_Coord_x]
		LDR	r3, [r11, #256 + Wimp_Pointer_pos + OS_Coord_y]

		LDRB	lr, [r8]
		CMP	lr, #'*'			; is this really a menu?
		BNE	not_menu$l

		; r0 = window handle
		ADR	r1, PollSpace + Wimp_Message	; path
		ADR	r2, PollSpace + Wimp_Message + StringSize ; scratch space
		BL	FindPath
		EXIT	EQ				; exit quietly if there was no path

		ADR	r0, PollSpace + Wimp_Message	; path
		BL	SetCurrentPath			; set up Director$CurrentPath etc
		BVS	TaskError

		ADD	r0, r8, #1			; skip the leading *
		BL	RunMenu
		BVS	TaskError
		EXIT
not_menu$l

		LDMIA	r11, {r4-r7}			; r4 = x0, r5 = y0, r6 = x1, r7 = y1

		; Store co-ord into for dataload
		STR	r0, [r11, #Wimp_MessageHeader_data + Wimp_MessageDataXfer_w]
		STR	r1, [r11, #Wimp_MessageHeader_data + Wimp_MessageDataXfer_i]
		STR	r2, [r11, #Wimp_MessageHeader_data + Wimp_MessageDataXfer_pos + OS_Coord_x]
		STR	r3, [r11, #Wimp_MessageHeader_data + Wimp_MessageDataXfer_pos + OS_Coord_y]

		; Make Message_FilerSelection
		ADD	lr, r11, #256 + Wimp_MessageHeader_data + Filer_MessageSelection_bbox + OS_Box_x0
		STMIA	lr, {r4-r7}
		SUB	r0, r6, r4
		SUB	r1, r7, r5
		STR	r0, [r11, #256 + Wimp_MessageHeader_data + Filer_MessageSelection_width]
		STR	r1, [r11, #256 + Wimp_MessageHeader_data + Filer_MessageSelection_height]

		MOV	r0, #0
		STR	r0, [r11, #256 + Wimp_MessageHeader_data + Filer_MessageSelection_col0]
		STR	r0, [r11, #256 + Wimp_MessageHeader_data + Filer_MessageSelection_row0]
		STR	r0, [r11, #256 + Wimp_MessageHeader_data + Filer_MessageSelection_col1]
		STR	r0, [r11, #256 + Wimp_MessageHeader_data + Filer_MessageSelection_row1]
		STR	r0, [r11, #256 + Wimp_MessageHeader_data + Filer_MessageSelection_display]
		STR	r0, [r11, #256 + Wimp_MessageHeader_your_ref]
		LDR	r0, =Message_FilerSelection
		STR	r0, [r11, #256 + Wimp_MessageHeader_action]
		MOV	r0, #Wimp_MessageHeader_data + Filer_MessageSelection
		STR	r0, [r11, #256 + Wimp_MessageHeader_size]

		; Send Message_FilerSelection
		MOV	r0, #Wimp_UserMessage		; notify tasks of a selection
		ADD	r1, r11, #256
		LDR	r2, [r11, #Wimp_MessageHeader_data + Wimp_MessageDataXfer_w]
		LDR	r3, [r11, #Wimp_MessageHeader_data + Wimp_MessageDataXfer_i]
		SWI	XWimp_SendMessage
		BVS	TaskError
		LDR	lr, FilerHandle
		CMP	lr, r2
		MOVNE	r10, #0				; Its not the filer
		MOVEQ	r10, #1				; Oh yes it its

		MOV	r0, r8
		CMP	r10, #0
		BLNE	PathParse			; get leaf name to r0 instead
		ADD	r1, r11, #Wimp_MessageHeader_data + Wimp_MessageDataXfer_file_name
		BL	strcpy				; copy file name in

		ADD	r0, r11, #Wimp_MessageHeader_data + Wimp_MessageDataXfer_file_name
		BL	strlen1
		ADD	r0, r0, #Wimp_MessageHeader_data + Wimp_MessageDataXfer_file_name + 3 + 8
		BIC	r0, r0, #3			; align
		STR	r0, [r11, #Wimp_MessageHeader_size] ; size of message
		ADD	r0, r11, r0			; point to end of message
		MOV	lr, #0
		STR	lr, [r0, #-8]			; row = 0
		STR	lr, [r0, #-4]			; column = 0

		MOV	r0, #OSFile_ReadStampedNoPath
		MOV	r1, r8
		SWI	XOS_File
		BVS	TaskError
		STR	r4, [r11, #Wimp_MessageHeader_data + Wimp_MessageDataXfer_est_size]
		STR	r6, [r11, #Wimp_MessageHeader_data + Wimp_MessageDataXfer_file_type]

		MOV	r0, #0
		STR	r0, [r11, #Wimp_MessageHeader_your_ref]
		CMP	r10, #0
		MOVEQ	r0, #Message_DataLoad
		MOVNE	r0, #Message_DataSave		; send a datasave to the filer only
		STR	r0, [r11, #Wimp_MessageHeader_action]

		MOV	r0, #Wimp_UserMessageRecorded
		MOV	r1, r11
		LDR	r2, [r11, #Wimp_MessageHeader_data + Wimp_MessageDataXfer_w]
		LDR	r3, [r11, #Wimp_MessageHeader_data + Wimp_MessageDataXfer_i]
		SWI	XWimp_SendMessage
		BVS	TaskError

		EXIT
		LTORG


;*******************************************************************************
;An item has been chosen off a menu
;*******************************************************************************


		MACRO
$label		IsMenu	$name
$label		TEQ	r0, #$name
		BEQ	Do$name
		MEND


;*******************************************************************************
;----f- Director.s.Task.MenuSelection
; Name
;   MenuSelection
;
; Purpose
;   Handle menu selection events from Wimp_poll
;
; Entry
;
;
; Exit
;
;------
;*******************************************************************************


MenuSelection	ROUTINE_SF
mouseblock$l	#	Wimp_Pointer
		END_SF

		BL	LastDisplayed
		CMP	r0, #0
		EXIT	EQ				; end if no menu displayed
		LDR	r1, LastMenu
		CMP	r0, r1
		BNE	exit_ne$l

		ADR	r1, mouseblock$l
		SWI	XWimp_GetPointerInfo		; read info for working out whether menu adjusted

		ADD	r0, r11, #Wimp_Block_selection	; point to selected so far
		BL	FindSelectedItem
		BVC	skiperror1$l
		BL	ShowError
		B	reopen$l

skiperror1$l	LDR	r4, LastMenu			; r4  last menu opened

		LDR	r3, mouseblock$l + Wimp_Pointer_buttons
		BL	MenuCommand			; do the menu command
		BVC	skiperror2$l
		BL	ShowError
		B	reopen$l

skiperror2$l	LDR	r0, mouseblock$l + Wimp_Pointer_buttons ; did the user click adjust?
		TST	r0, #Wimp_ClickAdjust
		BNE	reopen$l
		LDR	r0, IgnoreMenusDeleted
		CMP	r0, #0				; if IgnoreMenusDeleted then don't clear
		LDREQ	r0, LastMenu
		CMPEQ	r0, r4				; if LastMenu unchanged
		BLEQ	ClearDisplayed			; clear the menu
		EXIT

reopen$l	LDR	r1, LastMenu
		LDR	r2, LastMenu_x
		LDR	r3, LastMenu_y
		SWI	XWimp_CreateMenu		; if so recreate menu
		EXIT	VC				; exit if there was no error
		BL	ClearDisplayed
		B	TaskError
		EXIT

exit_ne$l	SWI	XOS_WriteI + 7			; beep
		EXIT					; not our menu so end


;*******************************************************************************
;----f- Director.s.Task.ClearDisplayedList
; Name
;   ClearDisplayedList
;
; Purpose
;   This clears the displayed menus list
;   and sets LastMenu <- 0
;
; Entry
;
;
; Exit
;
;------
;*******************************************************************************


ClearDisplayedList	ROUTINE	"r0-r3"
		LDR	r0, LastMenu			; r0  LastMenu
		CMP	r0, #0
		EXIT	EQ				; end if no menu displayed

		ADR	r0, MenuDisplayedAnchor
		BL	MenuBlockListClear		; if not clear down the menu tree

		MOV	r0, #0
		STR	r0, LastMenu			; show no menu displayed
		EXIT


;*******************************************************************************
;----f- Director.s.Task.ClearDisplayed
; Name
;   ClearDisplayed
;
; Purpose
;   This clears the displayed menus and deletes the Menu tree
;
; Entry
;
;
; Exit
;
;------
;*******************************************************************************


ClearDisplayed	ROUTINE	"r0-r3"
		LDR	r0, LastMenu			; r0  LastMenu
		CMP	r0, #0
		EXIT	EQ				; end if no menu displayed

		BL	ClearDisplayedList

		CMP	r0, #0
		MOV	r1, #-1
		SWINE	XWimp_CreateMenu		; clear the current displayed menu
		BVS	TaskError

		MOV	r0, #1
		STR	r0, IgnoreMenusDeleted		; ignore the next MenusDeleted message

		EXIT


;*******************************************************************************
;This deals with messages received
;*******************************************************************************

		MACRO
		IsMessage	$name
	[	$name < &100
		TEQ	r10, #$name
		BEQ	Do$name
	|
		LDR	r0, =$name
		TEQ	r0, r10
		BEQ	Do$name
	]
		MEND

UserMessage
UserMessageRecorded
		LDR	r10, [r11, #Wimp_MessageHeader_action]

;		IsMessage	Message_DataSave
		IsMessage	Message_DataSaveAck
		IsMessage	Message_DataLoad
;		IsMessage	Message_DataLoadAck
;		IsMessage	Message_DataOpen
		IsMessage	Message_HelpRequest
;		IsMessage	Message_HelpReply
;		IsMessage	Message_ModeChange
		IsMessage	Message_TaskInitialise
		IsMessage	Message_TaskCloseDown
		IsMessage	Message_MenuWarning
		IsMessage	Message_MenusDeleted
		IsMessage	Message_$Name.OpenMenu
		IsMessage	Message_$Name.Window
		IsMessage	Message_Quit

		MOV	pc, lr
		LTORG


;*******************************************************************************
;----f- Director.s.Task.DoMessage_Quit
; Name
;   DoMessage_Quit
;
; Purpose
;   Respond to the wimp quit message.
;
; Entry
;
;
; Exit
;
;------
;*******************************************************************************


DoMessage_Quit	ROUTINE
		BL	TaskShutDownAndKill
		EXIT


;*******************************************************************************
;----f- Director.s.Task.DoMessage_HelpRequest
; Name
;   DoMessage_HelpRequest
;
; Purpose
;   Respond to any help request messages.
;
; Entry
;
;
; Exit
;
;------
;*******************************************************************************


DoMessage_HelpRequest	ROUTINE_SF
menu_selection	#	10*4
                END_SF

		LDR	r2, [r11, #Wimp_MessageHeader_data + Help_MessageRequest_w]
		LDR	r3, [r11, #Wimp_MessageHeader_data + Help_MessageRequest_i]

		LDR	r0, SaveWindow
		TEQ	r0, r2
		ADREQ	r0, HelpSaveWindow
		BEQ	do_mt$l

		LDR	r0, InfoWindow
		TEQ	r0, r2
		ADREQ	r0, HelpInfoWindow
		BEQ	do_mt$l

		BL	DoMessage_HelpRequest_Window
		BEQ	exit$l				; 'exit' if it was able to handle the help request

		CMP	r2, #Wimp_IconBar
		ADREQ	r0, HelpIconBar
		BEQ	do_mt$l

		CMP	r3, #-1
		BEQ	none$l

		MOV	r0, #1
		ADR	r1, menu_selection
		SWI	XWimp_GetMenuState
		BVS	none$l
		ADR	r0, HelpMenu
		B	do_mt$l

;;;;
;		; Find selected item can't delete the tree with use with !help
;		MOV	r0, #0
;		BL	FindSelectedItem
;		BVS	TaskError
;		; r0  MenuBlock holding selected item
;		; r1  selected item
;		; r2 = type of selected item
;
;		B	exit$l

		LTORG

HelpMessage	DCB	"Help_Default", 0
HelpSaveWindow	DCB	"Help_Window_SaveWindow", 0
HelpInfoWindow	DCB	"Help_Window_InfoWindow", 0
HelpIconBar	DCB	"Help_IconBar_Default", 0
HelpMenu	DCB	"Help_Menu_Default", 0
		ALIGN

		;;;; menu checking here

none$l		ADR	r0, HelpMessage
do_mt$l		MOV	r1, #0				; Use a MessageTrans internal buffer.
		BL	MessageLookup
exit$l		ADD	r1, r11, #Wimp_MessageHeader_data
		BL	strcpy				; copy help text in

		ADD	r0, r11, #Wimp_MessageHeader_data
		BL	strlen1
		ADD	r0, r0, #Wimp_MessageHeader_data + 3
		BIC	r0, r0, #3			; align
		STR	r0, [r11, #Wimp_MessageHeader_size] ; size of message

		LDR	r0, [r11, #Wimp_MessageHeader_my_ref]
		STR	r0, [r11, #Wimp_MessageHeader_your_ref] ; your_ref = my_ref

		LDR	r0, =Message_HelpReply
		STR	r0, [r11, #Wimp_MessageHeader_action] ; send help reply

		MOV	r0, #Wimp_UserMessage
		MOV	r1, r11
		LDR	r2, [r11, #Wimp_MessageHeader_sender]
		SWI	XWimp_SendMessage
		BVS	TaskError

		EXIT


;*******************************************************************************
;----f- Director.s.Task.
; Name
;   DoMessage_DataLoad
;
; Purpose
;   We get this message if someone drags a file from the filer onto one of
;of our icons.
;
; Entry
;
;
; Exit
;
;------
;*******************************************************************************


DoMessage_DataLoad	ROUTINE
		ADD	r0, r11, #Wimp_MessageHeader_data + Wimp_MessageDataXfer_file_name ; r0  file name

		LDR	r1, [r11, #Wimp_MessageHeader_data + Wimp_MessageDataXfer_w] ; window

		LDR	r2, SaveWindow
		TEQ	r1, r2
		BEQ	ack$l				; ack and end

		CMP	r1, #Wimp_IconBar
		EXIT	NE				; end if this wasn't the save window or the icon bar

		BL	SetCurrentPath			; set up Director$CurrentPath etc
		BVS	TaskError

		LDR	r0, [r11, #Wimp_MessageHeader_data + Wimp_MessageDataXfer_i]
		MOV	r1, #&1000			; drag to
		BL	IconBarClick
		BVS	TaskError

ack$l		BL	SetUpSaveWindow			; this was the save window
		LDR	r0, [r11, #Wimp_MessageHeader_my_ref]
		STR	r0, [r11, #Wimp_MessageHeader_your_ref]

		MOV	r0, #Message_DataLoadAck	; send back a dataload ack
		STR	r0, [r11, #Wimp_MessageHeader_action]

		MOV	r0, #Wimp_UserMessage
		MOV	r1, r11
		LDR	r2, [r11, #Wimp_MessageHeader_sender]
		SWI	XWimp_SendMessage
		BVS	TaskError

		EXIT


;*******************************************************************************
;----f- Director.s.Task.DoMessage_TaskInitialise
; Name
;   DoMessage_TaskInitialise
;
; Purpose
;
;
; Entry
;
;
; Exit
;
;------
;This informs the filter module of tasks starting and closing down
;*******************************************************************************


DoMessage_TaskInitialise


;*******************************************************************************
;----f- Director.s.Task.DoMessage_TaskCloseDown
; Name
;   DoMessage_TaskCloseDown
;
; Purpose
;
;
; Entry
;
;
; Exit
;
;------
;*******************************************************************************


DoMessage_TaskCloseDown
		B	FilterCheckTasks


;*******************************************************************************
;----f- Director.s.Task.Ack_
; Name
;   Ack_
;
; Purpose
;   This acknowledges the message pointed to by r1 if r0 says it should be
;
; Entry
;   r0 = message type (Wimp_UserMessageRecorded or Wimp_UserMessageAcknowledge)
;   r1  message
;
; Exit
;
;------
;*******************************************************************************


Ack_		ROUTINE	"r0-r3", EXPORT

		CMP	r0, #Wimp_UserMessageRecorded
		EXIT	NE

		LDR	r0, [r1, #Wimp_MessageHeader_my_ref]
		STR	r0, [r1, #Wimp_MessageHeader_your_ref]

		MOV	r0, #Wimp_UserMessageAcknowledge
		LDR	r2, [r1, #Wimp_MessageHeader_sender]
		SWI	XWimp_SendMessage		; ack the message

		STRSP	r0, r0, VS			; if an error occured put the current value of r0 on the stack
		EXIT


;*******************************************************************************
;----f- Director.s.Task.Ack
; Name
;   Ack
;
; Purpose
;   This acknowledges the message in PollSpace and PollType
;
; Entry
;
;
; Exit
;
;------
;*******************************************************************************


Ack		ROUTINE	"r0-r1"

		LDR	r0, PollType
		ADR	r1, PollSpace
		BL	Ack_
		BVS	TaskError

		EXIT


;*******************************************************************************
;----f- Director.s.Task.DoMessage_DirectorOpenMenu
; Name
;   DoMessage_DirectorOpenMenu
;
; Purpose
;   This is our message for opening menus
;
; Entry
;
;
; Exit
;
;------
;*******************************************************************************


DoMessage_$Name.OpenMenu	ROUTINE

		ADD	r0, r11, #Wimp_MessageHeader_data + $Name._MessageOpenMenu_ptr
		MOV	r1, r11
		MOV	r2, #Wimp_Pointer
		BL	memcpy				; move Wimp_Pointer to start of pollspace

		MOV	lr, #1
		STR	lr, ValidWimpPointer		; signal that PollSpace contains a valid Wimp_Pointer

		ADD	r0, r11, #Wimp_MessageHeader_data + $Name._MessageOpenMenu_menu ; point to name of menu
		BL	RunMenu
		BVS	TaskError

		BL	Ack

		EXIT


;*******************************************************************************
;----f- Director.s.Task.DoMessage_DirectorWindow
; Name
;   DoMessage_DirectorWindow
;
; Purpose
;   This is our message for diddling with windows
;
; Entry
;
;
; Exit
;
;------
;*******************************************************************************


DoMessage_$Name.Window	ROUTINE

		MOV	r0, r11
;		BL	WindowBlockMessage2
		ADR	r0, e$l
		B	Alert

		; Do not ack this message

		EXIT

e$l		DCD	0
		DCB	"WindowBlockMessage2-T", 0


;*******************************************************************************
;----f- Director.s.Task.DoMessage_DataSaveAck
; Name
;   DoMessage_DataSaveAck
;
; Purpose
;   This is the reply from a message giving us a pathname to save to
;
; Entry
;
;
; Exit
;
;------
;*******************************************************************************


DoMessage_DataSaveAck	ROUTINE
		LDR	r0, [r11, #Wimp_MessageHeader_data + Wimp_MessageDataXfer_est_size]
		CMP	r0, #-1
		BEQ	onlytofiler$l

		ADR	r0, Filer_Action
		BL	StartWimpTask
		BVS	TaskError
		MOV	r10, r0				; r10 is handle of our filer action task

		LDR	r8, DragPath			; r8  full path

		MOV	r0, r8
		ADD	r1, r11, #256
		BL	strcpy				; make a copy of the path

		ADD	r0, r11, #256
		BL	PathParse
		BEQ	noterm$l			; don't terminate
		LDRB	lr, [r0, #-1]			; what was terminator?
		CMP	lr, #'.'			; r6  terminator
		MOV	lr, #0
		STREQB	lr, [r0, #-1]			; 0 terminate path (over write '.')
		STRNEB	lr, [r0]			; 0 terminate path (write past ':')
noterm$l

		MOV	r0, r10
		ADD	r1, r11, #256			; directory name
		SWI	XFilerAction_SendSelectedDirectory
		BVS	TaskError

		MOV	r0, r8
		BL	PathParse
		MOV	r1, r0
		MOV	r0, r10
		SWI	XFilerAction_SendSelectedFile
		BVS	TaskError

		MOV	r0, #OSByte_ReadCMOS
		MOV	r1, #198			; desktop state
		SWI	XOS_Byte			; read the CMOS flags
		BVS	TaskError
		MOV	r0, r2				; r0 = CMOS ram options
		MOV	r2, #0				; r2 = options
		TST	r0, #2_01000000			; verbose
		ORRNE	r2, r2, #2_0001
		TST	r0, #2_00100000			; confirm
		ORRNE	r2, r2, #2_0010
		TST	r0, #2_00010000			; force
		ORRNE	r2, r2, #2_0100
		TST	r0, #2_10000000			; newer
		ORRNE	r2, r2, #2_1000

		ADD	r3, r11, #Wimp_MessageHeader_data + Wimp_MessageDataXfer_file_name ; point to destination
		MOV	r0, r3
		BL	PathParse
		BEQ	noterm2$l			; don't terminate
		LDRB	lr, [r0, #-1]			; what was terminator?
		CMP	lr, #'.'			; r6  terminator
		MOV	lr, #0
		STREQB	lr, [r0, #-1]			; 0 terminate path (over write '.')
		STRNEB	lr, [r0]			; 0 terminate path (write past ':')
noterm2$l
		MOV	r0, r3
		BL	strlen1
		MOV	r4, r0				; length of name + null
		MOV	r0, r10
		MOV	r1, #FilerActionSendStartOperation_Copy
		SWI	XFilerAction_SendStartOperation
		BVS	TaskError

		EXIT

onlytofiler$l	ADR	r0, only2filermsg$l
		B	TaskErrorMT

Filer_Action	EQUS0A	"Filer_Action"
only2filermsg$l	ERROR	"$OnlyToFiler", Error_OnlyToFiler

;*******************************************************************************
; This is called with un-acked message
;
; Entry
;  r11  message block
;*******************************************************************************


		MACRO
		IsMessageAck	$name
	[	$name < &100
		TEQ	r10, #$name
		BEQ	Do$name._Ack
	|
		LDR	r0, =$name
		TEQ	r0, r10
		BEQ	Do$name._Ack
	]
		MEND

UserMessageAcknowledge

		LDR	r10, [r11, #Wimp_MessageHeader_action]

		IsMessageAck	Message_DataSave
		IsMessageAck	Message_DataOpen
		IsMessageAck	Message_InetSuiteOpenURL ; = &4AF80

		MOV	pc, lr
		LTORG


;*******************************************************************************
;----f- Director.s.Task.DoMessage_DataSave_Ack
; Name
;   DoMessage_DataSave_Ack
;
; Purpose
;   DoMessage_DataSave_Ack
;
; Entry
;
;
; Exit
;
;------
;
;*******************************************************************************


DoMessage_DataSave_Ack	ROUTINE

		ADR	r0, errormsg$l
		B	TaskErrorMT

		EXIT

errormsg$l	ERROR	"$NoReplyToDataSave", Error_NoReplyToDataSave

;*******************************************************************************
;----f- Director.s.Task.command_parse
; Name
;   command_parse
;
; Purpose
;   This gets a pointer to the command string and runs it
;
; Entry
;   r0 = number of command string
;   r8  menu item
;
; Exit
;   It may return an error
;------
;*******************************************************************************


command_parse	ROUTINE	"r0-r7"

		MOV	r6, r0				; how many command strings

		LDR	r7, [r8, #Wimp_MenuEntry_data + Wimp_IconData_indirected_text_validation]

		MOV	r0, r7				; skip validation string
		BL	strlen1
		ADD	r7, r7, r0

		LDR	r0, [r8, #Wimp_MenuEntry_sub_menu]
		CMP	r0, #-1
		CMPNE	r0, #0
		BEQ	skip_cmnd$l
		MOV	r0, r7				; skip sub menu if there is one
		BL	strlen1
		ADD	r7, r7, r0			; r7  command1

skip_cmnd$l	CMP	r6, #0				; skip command1 if necessary
		BEQ	skip_cmnd1$l
		MOV	r0, r7				; skip sub menu if there is one
		BL	strlen1
		ADD	r7, r7, r0			; r7  command1

skip_cmnd1$l	MOV	r0, r7
		BL	DoCommand

		STRSP	r0, r0, VS			; if an error occured put the current value of r0 on the stack
		EXIT


;*******************************************************************************
;----f- Director.s.Task.MenuCommand
; Name
;   MenuCommand
;
; Purpose
;   This does the command associated with a menu
;
; Entry
;   r0  MenuBlock holding selected item
;   r1  selected item
;   r2 = type of selected item
;   r3 = button state of selection
;   r11  poll block for scratch
;
; Exit
;   It may return errors
;------
;*******************************************************************************


MenuCommand	ROUTINE	"r0-r11"
		MOV	r10, r0				; r10  MenuBlock
		MOV	r9, r3				; r9 = button state
		MOV	r8, r1				; r8  menu item
		TEQ	r2, #MenuEntryPath
		TEQNE	r2, #MenuEntryPathUp
		TEQNE	r2, #MenuEntryPathMenuMenu
		BEQ	pathmenu$l
		TEQ	r2, #MenuEntryFile
		BEQ	filemenu$l
		TEQ	r2, #MenuEntryText
		BEQ	textmenu$l
		TEQ	r2, #MenuEntryCommand1
		BEQ	command1$l
		TEQ	r2, #MenuEntryCommand2
		BEQ	command2$l
		B	ok_exit$l			; end if not an action type

pathmenu$l	LDR	r7, [r8, #Wimp_MenuEntry_data + Wimp_IconData_indirected_text_validation]
		MOV	r0, r7				; skip validation string
		BL	strlen1
		ADD	r7, r7, r0			; r7  path

		MOV	r0, r7
		BL	SetCurrentPath
		BVS	error$l

;;;;		TEQ	r2, #MenuEntryPathMenuMenu
;;;;		BEQ	menumenu$l

		B	fileropen$l

filemenu$l	LDR	r3, [r8, #Wimp_MenuEntry_data + Wimp_IconData_indirected_text_text] ; r3  menu entry text

		MOV	r0, r3
		ADD	r4, r10, #MenuBlock_strings
		BL	StringFindMark
		BVS	error$l
		ADD	r4, r0, #1			; r4  path

		MOV	r0, r4
		MOV	r1, r11				; use Poll block as scratch
		BL	strcpy				; start of path

		LDRB	lr, [r1, #-2]
		CMP	lr, #':'
		MOVNE	lr, #'.'
		STRNEB	lr, [r1, #-1]			; write a dot at the end of the path
		SUBEQ	r1, r1, #1			; or reverse over terminator
		MOV	r0, r3
		BL	strcpy				; copy the leaf name on

		MOV	r0, r11
		BL	SetCurrentPath
		BVS	error$l

fileropen$l	TST	r9, #Wimp_ClickMenu
		BEQ	oscli$l

menumenu$l      BL	MemoriseMenuMenu		; Memorise the MenuMenu file
							; skip command if not required
		ADR	r0, MenuMenu
		BL	RunMenu
		BVS	error$l
		B	ok_exit$l

oscli$l
;	skip the next two SWI calls if you don't want files canonicalised

			; What really is <Director$CurrentPath>?
		MOV	r0, #OSFSControl_CanonicalisePath ; = 25
		ADR	r1, Object
		ADR	r2, TempSpace
		MOV	r3, #0
		MOV	r4, #0
		MOV	r5, #256
		SWI	XOS_FSControl
		BVS	error$l
						; r5 = space left in buffer

			; Now put that back into <Director$CurrentPath>
		ADR	r0, ObjectVar
		ADR	r1, TempSpace
		SUB	r5, r5, r5, LSL #1		; = -ve space left
		ADD	r2, r5, #256			; = 256 + (-space)
		MOV	r3, #0
		MOV	r4, #OS_VartypeString		; = 0
		SWI	XOS_SetVarVal
		BVS	error$l

		MOV	r0, #OSFile_ReadStampedNoPath	; = 23
		ADR	r1, Object
		SWI	XOS_File
		BVS	error$l
		CMP	r0, #OSFile_NotFound		; 0
		BEQ	error$l
		CMP	r0, #OSFile_IsFile		; 1	; is it a file?
		CMPNE	r0, #OSFile_IsImage		; 3 	; or an image file?
		CMPNE	r6, #OSFile_TypeApplication	; &2000	; or an application?
		BEQ	filer_run$l			;	; is so, run it.

filer_opendir$l						; it's a directory
		ADR	r0, Filer_OpenDir
		SWI	XOS_CLI				; do Filer_OpenDir <path>.<leaf>
		BVS	error$l
		B	ok_exit$l

filer_run$l
		ADR	r0, Filer_Run
		SWI	XOS_CLI				; do Filer_Run <path>.<leaf>
		BVS	error$l
		B	ok_exit$l

			; Vars moved higher in the source code
Object			DCB	"<$Name.$$CurrentPath>", 0
			ALIGN
ObjectVar		DCB	"$Name.$$CurrentPath", 0
			ALIGN
Filer_Run		DCB	"$Name.Do Filer_Run <$Name.$$CurrentPath>", 0
			ALIGN
Filer_OpenDir		DCB	"$Name.Do Filer_OpenDir <$Name.$$CurrentPath>", 0
			ALIGN
MenuMenu		DCB	"GSTrans:"
MenuMenuAfterGSTrans	DCB	"<$Name.$$MenuMenu>", 0
			ALIGN

textmenu$l
		LDR	r0, [r8, #Wimp_MenuEntry_sub_menu]
		CMP	r0, #-1
		CMPNE	r0, #0
		BEQ	ok_exit$l			; end if no sub-menu

		LDR	r1, [r8, #Wimp_MenuEntry_data + Wimp_IconData_indirected_text_validation]
		MOV	r0, r1
		BL	strlen1
		ADD	r0, r1, r0			; r0  sub menu name
		BL	RunMenu
		BVS	error$l
		B	ok_exit$l

command1$l	MOV	r0, #0
		BL	command_parse
		BVS	error$l
		B	ok_exit$l

command2$l	LDR	r0, [r8, #Wimp_MenuEntry_menu_flags]
		EOR	r1, r0, #Wimp_MenuTicked		; changed ticked state
		STR	r1, [r8, #Wimp_MenuEntry_menu_flags]
		AND	r0, r0, #Wimp_MenuTicked		; just ticked state
		BL	command_parse
		BVS	error$l

ok_exit$l	ClearV
		EXIT

error$l		SetV
		EXIT_ERR


;*******************************************************************************
;----f- Director.s.Task.DoMessage_MenuWarning
; Name
;   DoMessage_MenuWarning
;
; Purpose
;   This deals with opening any sub menus
;
; Entry
;   r11  Wimp_MessageMenuWarning block
;
; Exit
;
;------
;*******************************************************************************


DoMessage_MenuWarning	ROUTINE

		ADD	r0, r11, #Wimp_MessageHeader_data + Wimp_MessageMenuWarning_selection ; point to selected so far
		BL	FindSelectedItem
		BVS	TaskError
		MOV	r10, r0				; r10  MenuBlock
		MOV	r8, r1				; r8  menu item
		TEQ	r2, #MenuEntryPath
		TEQNE	r2, #MenuEntryPathUp
		TEQNE	r2, #MenuEntryPathMenuMenu
		BEQ	pathmenu$l
		TEQ	r2, #MenuEntryFile
		BEQ	filemenu$l
		TEQ	r2, #MenuEntryText
		TEQNE	r2, #MenuEntryCommand1
		TEQNE	r2, #MenuEntryCommand2
		BEQ	submenu$l
		B	end$l				; end if not an action type

pathmenu$l	LDR	r1, [r8, #Wimp_MenuEntry_data + Wimp_IconData_indirected_text_validation]
		MOV	r0, r1				; skip validation string
		BL	strlen1
		ADD	r0, r1, r0			; r0  path
		TEQ	r2, #MenuEntryPathMenuMenu
		BEQ	menumenu$l
		TEQ	r2, #MenuEntryPathUp
		MOVEQ	r1, #1				; up directories
		MOVNE	r1, #0				; no up directories
		BL	FileMenuCreate
		BVS	TaskError
		LDR	r0, [r0, #MenuBlock_menu + StringBlock_buffer] ; point to menu block
		B	opensubmenu$l

menumenu$l	BL	SetCurrentPath			; make sure the path variables are set up
		BL	MemoriseMenuMenu		; Add file to Memoriser.
							; Skip this command if not required.
		ADR	r0, MenuMenu
		BL	DoSubMenu
		BVS	TaskError
		B	opensubmenu$l

filemenu$l	LDR	r3, [r8, #Wimp_MenuEntry_data + Wimp_IconData_indirected_text_text] ; r3  menu entry text

		MOV	r0, r3
		ADD	r4, r10, #MenuBlock_strings
		BL	StringFindMark
		ADD	r0, r0, #1			; r0  path

		ADD	r1, r11, #256			; skip current info
		BL	strcpy				; start of path
		LDRB	lr, [r1, #-2]
		CMP	lr, #':'
		MOVNE	lr, #'.'
		STRNEB	lr, [r1, #-1]			; write a dot at the end of the path
		SUBEQ	r1, r1, #1			; or reverse over terminator
		MOV	r0, r3
		BL	strcpy				; copy the leaf name on

		MOV	r0, r3
		BL	strcpy				; copy the leaf name on

		ADD	r0, r11, #256			; string
		MOV	r1, #0				; no up directories
		BL	FileMenuCreate
		BVS	TaskError
		LDR	r0, [r0, #MenuBlock_menu + StringBlock_buffer] ; point to menu block
		B	opensubmenu$l

submenu$l	LDR	r1, [r8, #Wimp_MenuEntry_data + Wimp_IconData_indirected_text_validation]
		MOV	r0, r1
		BL	strlen1
		ADD	r0, r1, r0			; r0  sub menu name
		BL	DoSubMenu
		BVS	TaskError			; r0  menu block

		; r0  menu to open
		; r8  menu entry
		; r10  MenuBock
		; r11  PollBlock
opensubmenu$l	MOVS	r1, r0
		BEQ	end$l				; end if null sub-menu

		STR	r1, [r8, #Wimp_MenuEntry_sub_menu] ; make sub menu pointer point to this menu
		LDR	r2, [r11, #Wimp_MessageHeader_data + Wimp_MessageMenuWarning_pos + OS_Coord_x]
		LDR	r3, [r11, #Wimp_MessageHeader_data + Wimp_MessageMenuWarning_pos + OS_Coord_y]
		SWI	XWimp_CreateSubMenu
		BVC	end$l
		LDR	r1, [r0]				; r1 = error number
		LDR	r2, =&289			; Error_WimpTooMenus
		CMP	r1, r2
		BNE	TaskError

end$l		EXIT


;*******************************************************************************
;----f- Director.s.Task.LastDisplayed
; Name
;   LastDisplayed
;
; Purpose
;   This works out whether the last menu displayed by us menu on display is the
;   one in the Displayed List
;
; Entry
;
;
; Exit
;   r0  First menu in menu tree or 0 for no menus
;------
;*******************************************************************************


LastDisplayed	ROUTINE	"r1"

		MOV	r0, #0

		ADR	r1, MenuDisplayedAnchor
		ListWalk	r1, lr
		EXIT	EQ				; not our menu since we haven't got one up

		LDR	r0, [r1, #MenuBlock_menu + StringBlock_buffer]

		EXIT


;*******************************************************************************
;----f- Director.s.Task.DoMessage_MenusDeleted
; Name
;   DoMessage_MenusDeleted
;
; Purpose
;   This clears the displayed list of menus if has been displayed
;
; Entry
;   r11  Wimp_MessageMenusDeletes block
;
; Exit
;
;------
;*******************************************************************************


DoMessage_MenusDeleted	ROUTINE
		LDR	r0, IgnoreMenusDeleted
		CMP	r0, #0
		MOVNE	r0, #0
		STRNE	r0, IgnoreMenusDeleted
		EXIT	NE				; skip if IgnoreMenusDeleted is set

		BL	LastDisplayed			; r0  First Menu in Displayed list
		CMP	r0, #0
		EXIT	EQ				; end if no menu displayed

		LDR	r1, [r11, #Wimp_MessageHeader_data + Wimp_MessageMenusDeleted_menu]	; r1  menu that was deleted
		CMP	r0, r1

		BLEQ	ClearDisplayedList		; delete menus if displayed

		EXIT


;*******************************************************************************
;----f- Director.s.Task.FindSelectedItem
; Name
;   FindSelectedItem
;
; Purpose
;   Given a list of menu entries pointed to by r0 this finds the MenuBlock
;   that the menu is in and makes a pointer to the menu item
;   It also deletes any menus deeper in the menu tree since these are
;   no longer needed
;
; Entry
;   r0  list of selected item numbers, -1 terminated
;
; Exit
;   r0  MenuBlock holding selected item
;   r1  selected item
;   r2 = type of selected item
;   It may return errors
;------
;*******************************************************************************


FindSelectedItem	ROUTINE	"r3-r7"

		MOV	r4, r0				; r4  current selected item
		LDR	r2, [r4]			; get current selected item
		CMP	r2, #-1
		BEQ	not_found$l			; -1 => no selection at all (shouldn't happen)

		ADR	r6, MenuDisplayedAnchor
		ListWalk	r6, r7
		BEQ	not_found$l			; EQ here => empty menu list

find$l		LDR	r2, [r4, #4]			; is next one the terminator?
		CMP	r2, #-1
		BEQ	end_list$l
		ListWalk	r6, r7			; move on one list item
		BEQ	not_found$l			; end of list => not found since next menu item is ok
		ADD	r4, r4, #4			; move on one menu item
		B	find$l

		; r6  MenuBlock holding selected item
		; r7  menublock previous to that
end_list$l	MOV	r0, r6				; r0  MenuBlock
		BL	MenuBlockListClear		; clear any deeper menus (but not current one)

		; r6  MenuBlock
		; r4  selected item
		LDR	r5, [r6, #MenuBlock_menu + StringBlock_buffer] ; get pointer to the menu
		ADD	r5, r5, #Wimp_Menu_entries	; point to the first entry
		LDR	r2, [r4]			; number of selected item
		MOV	lr, #Wimp_MenuEntry		; size of an entry
		MLA	r5, r2, lr, r5			; r5  selected menu item

		LDR	r2, [r5, #Wimp_MenuEntry_icon_flags]
		AND	r2, r2, #Wimp_IconESG
		MOV	r2, r2, LSR#Wimp_IconESGShift	; r2 = type of icon

		ADR	r0, menutext$l			; r0  name
		LDR	r1, [r5, #Wimp_MenuEntry_data + Wimp_IconData_indirected_text_text] ; r1  value
		MOV	r4, #OS_VartypeLiteralString
		BL	SetVarVal			; set MenuText system variable

		MOV	r0, r6				; r0  MenuBlock
		MOV	r1, r5				; r1  selected item

		ClearV
		EXIT

not_found$l	ADR	r0, error$l
		BL	MessageErrorLookup
		SetV
		EXIT

menutext$l	EQUS0A	"MenuText"
error$l		ERROR	"$MenuNotFound", Error_MenuNotFound


;*******************************************************************************
;----f- Director.s.Task.StartDrag
; Name
;   StartDrag
;
; Purpose
;   This starts of a drag from an icon
;
; Entry
;   r0 = window handle
;   r1 = icon handle
;   r2 = path to drag or *menu to open
;
; Exit
;   It will call TaskError to report errors
;------
;*******************************************************************************


StartDrag	ROUTINE_SF	"r0-r8", EXPORT
		[	Wimp_IconState > Wimp_WindowState
state$l		#	Wimp_IconState
		|
state$l		#	Wimp_WindowState
		]
		END_SF

		STR	r2, DragPath

		STR	r0, state$l + Wimp_WindowState_w
		ADR	r1, state$l
		SWI	XWimp_GetWindowState		; get the window state
		BVS	TaskError

		LDR	r4, state$l + Wimp_WindowState_visible + OS_Box_x0
		LDR	lr, state$l + Wimp_WindowState_xscroll
		SUB	r4, r4, lr			; r4 = x position of window

		LDR	r5, state$l + Wimp_WindowState_visible + OS_Box_y1
		LDR	lr, state$l + Wimp_WindowState_yscroll
		SUB	r5, r5, lr			; r5 = y position of window

		LDRSP	r0, r1				; icon handle
		STR	r0, state$l + Wimp_IconState_i
		ADR	r1, state$l
		SWI	XWimp_GetIconState		; get the icon state
		BVS	TaskError

		LDR	r0, state$l + Wimp_IconState_icon + Wimp_Icon_extent + OS_Box_x0
		ADD	r0, r0, r4
		STR	r0, state$l + Wimp_IconState_icon + Wimp_Icon_extent + OS_Box_x0

		LDR	r1, state$l + Wimp_IconState_icon + Wimp_Icon_extent + OS_Box_y0
		ADD	r1, r1, r5
		STR	r1, state$l + Wimp_IconState_icon + Wimp_Icon_extent + OS_Box_y0

		LDR	r2, state$l + Wimp_IconState_icon + Wimp_Icon_extent + OS_Box_x1
		ADD	r2, r2, r4
		STR	r2, state$l + Wimp_IconState_icon + Wimp_Icon_extent + OS_Box_x1

		LDR	r3, state$l + Wimp_IconState_icon + Wimp_Icon_extent + OS_Box_y1
		ADD	r3, r3, r5
		STR	r3, state$l + Wimp_IconState_icon + Wimp_Icon_extent + OS_Box_y1

		LDRSP	r0, r0				; window handle
		LDRSP	r1, r1				; icon handle
		BL	GetIconAddresses		; r0  indirect text, r1  validation
		ADD	r2, r1, #1			; r2  sprite name

		MOV	r0, #DragASprite_HPosCentre + DragASprite_VPosTop + DragASprite_NoBound + DragASprite_BoundPointer + DragASprite_DropShadow
		MOV	r1, #1				; wimp sprite Area
		ADR	r3, state$l + Wimp_IconState_icon + Wimp_Icon_extent
		SWI	XDragASprite_Start
		BVS	TaskError

		EXIT


;*******************************************************************************
;----f- Director.s.Task.MouseClick
; Name
;   MouseClick
;
; Purpose
;   This deals with any mouse clicks
;
; Entry
;
;
; Exit
;
;------
;
;*******************************************************************************


MouseClick	ROUTINE

		LDR	r0, [r11, #Wimp_Pointer_w]	; what window was icon in?
		CMP	r0, #Wimp_IconBar
		BNE	noticonbar$l

		LDR	r0, [r11, #Wimp_Pointer_i]	; what icon
		LDR	r1, [r11, #Wimp_Pointer_buttons] ; what buttons
		BL	IconBarClick
		BVS	TaskError
		EXIT

noticonbar$l	LDR	r1, SaveWindow
		CMP	r0, r1
		BNE	notsavewindow$l
		BL	SaveClick
		EXIT

notsavewindow$l	BL	WindowClick
		BVS	TaskError
		EXIT

		; Click in the save window

SaveClick	ROUTINE

		LDR	r0, [r11, #Wimp_Pointer_i]	; icon number
		CMP	r0, #save_icon
		BEQ	clickicon$l
		EXIT

clickicon$l	LDR	r0, [r11, #Wimp_Pointer_buttons]
		TST	r0, #Wimp_DragAdjust + Wimp_DragSelect
		EXIT	EQ				; wait for a drag

		LDR	r0, SaveWindow			; window handle
		MOV	r1, #save_icon			; icon handle
		LDR	r2, SaveWindowPath		; path to open
		BL	StartDrag

		EXIT


;*******************************************************************************
;----f- Director.s.Task.OpenWindow
; Name
;   OpenWindow
;
; Purpose
;   This opens a window
;
; Entry
;   r0 = window handle
;   r1 = position to open
;     0 => where it is, and don't open if it is not open
;     &80000000 => under pointer, on top
;
; Exit
;
;------
;*******************************************************************************


OpenWindow	ROUTINE_SF	"r0-r2"
state$l		#	Wimp_WindowState
mouseblock$l	#	Wimp_Pointer
		END_SF

		MOV	r2, r1				; r2 = position

		STR	r0, state$l + Wimp_WindowState_w
		ADR	r1, state$l
		SWI	XWimp_GetWindowState		; read position of window
		BVS	TaskError

		CMP	r2, #&80000000
		BNE	notpointer$l
		MOV	r2, #Wimp_Top			; open under pointer, on top

		ADR	r1, mouseblock$l
		SWI	XWimp_GetPointerInfo		; read current pointer info
		BVS	TaskError

;  w = wstate.openblock.screenrect.max.x - wstate.openblock.screenrect.min.x
;  wstate.openblock.screenrect.min.x = moveto.x
;  wstate.openblock.screenrect.max.x = wstate.openblock.screenrect.min.x + w

		LDR	r0, mouseblock$l + Wimp_Pointer_pos + OS_Coord_x
		SUB	r0, r0, #64
		LDR	r1, state$l + Wimp_WindowState_visible + OS_Box_x0
		STR	r0, state$l + Wimp_WindowState_visible + OS_Box_x0
		LDR	lr, state$l + Wimp_WindowState_visible + OS_Box_x1
		SUB	r1, lr, r1
		ADD	lr, r0, r1
		STR	lr, state$l + Wimp_WindowState_visible + OS_Box_x1

;  h = wstate.openblock.screenrect.max.y - wstate.openblock.screenrect.min.y;
;  wstate.openblock.screenrect.max.y = moveto.y;
;  wstate.openblock.screenrect.min.y = wstate.openblock.screenrect.max.y - h;

		LDR	r0, mouseblock$l + Wimp_Pointer_pos + OS_Coord_y
	;	ADD	r0, r0, #64
		LDR	r1, state$l + Wimp_WindowState_visible + OS_Box_y1
		STR	r0, state$l + Wimp_WindowState_visible + OS_Box_y1
		LDR	lr, state$l + Wimp_WindowState_visible + OS_Box_y0
		SUB	r1, r1, lr
		SUB	lr, r0, r1
		STR	lr, state$l + Wimp_WindowState_visible + OS_Box_y0
notpointer$l

		CMP	r2, #0
		STRNE	r2, state$l + Wimp_WindowState_next
		LDREQ	r1, state$l + Wimp_WindowState_flags
		TSTEQ	r1, #Wimp_WindowOpen
		EXIT	EQ				; return if window is closed

		ADR	r1, state$l
		SWI	XWimp_OpenWindow		; open the window
		BVS	TaskError
		EXIT


;*******************************************************************************
;----f- Director.s.Task.CloseWindow
; Name
;   CloseWindow
;
; Purpose
;   This closes the window referred to by r0
;
; Entry
;
;
; Exit
;
;------
;*******************************************************************************


;;;;CloseWindow	ROUTINE	"r0-r1", 4
;;;;
;;;;		STR	r0, [sp, #0]
;;;;		MOV	r1, sp
;;;;		SWI	XWimp_CloseWindow
;;;;		BVS	TaskError
;;;;
;;;;		EXIT


;*******************************************************************************
;----f- Director.s.Task.SetUpSaveWindow
; Name
;   SetUpSaveWindow
;
; Purpose
;   This sets up the icons in the SaveWindow to be in accord with the path
;   passed in r0.
;   Will call TaskError
;
; Entry
;   r0  path to put into save box, or 0 for don't change
;
; Exit
;
;------
;*******************************************************************************


SetUpSaveWindow	ROUTINE	"r0-r8"

		CMP	r0, #0
		EXIT	EQ				; end if no path

		MOV	r8, r0				; r8  path
		BL	PathParse
		MOV	r7, r0				; r7  leaf

		LDR	r0, SaveWindow
		MOV	r1, #save_icon
		BL	GetIconAddresses		; r0  text, r1  validation
		MOV	r6, r1				; r6  validation
		MOV	r1, r0
		MOV	r0, r7
		BL	strcpy				; Write leaf into save box
		MOV	r0, r8
		STR	r1, SaveWindowPath		; point to the path of the save window
		BL	strcpy				; Write path into save box

		MOV	r0, #OSFile_ReadNoPath
		MOV	r1, r8
		SWI	XOS_File
		MOVVS	r0, #OSFile_NotFound		; error => not found
		MOV	r1, r0				; r1 = type
		MOV	r3, r7				; r3  leaf
		BL	LoadAddrToType

		MOV	r0, r6				; r0  validation
		MOV	r4, #1				; large icons please
		BL	FileSprite

		LDR	r0, SaveWindow
		MOV	r1, #save_icon
		MOV	r2, #0
		MOV	r3, #0
		BL	SetIconState			; update the icon

		EXIT


;*******************************************************************************
;----f- Director.s.Task.FindPath
; Name
;   FindPath
;
; Purpose
;   This looks at the title bar of the window whose handle is in r0 and
;   gets a path out of it to the buffer supplied.
;   May not call task error
;
; Entry
;   r0 = handle of window
;   r1 = pointer to buffer for string
;   r2 = pointer to scratch space
;
; Exit
;   NE = good, EQ = bad
;------
;*******************************************************************************


FindPath	ROUTINE	"r0-r11", EXPORT

		MOV	r8, r1				; r8  string buffer
		MOV	r9, r0				; r9 is window handle
		MOV	r11, r2				; r11  scratch

		STR	r9, [r11, #Wimp_WindowInfo_w]	; window to get info of
		ORR	r1, r11, #1			; address of block with bit 0 set for no icons
		SWI	XWimp_GetWindowInfo
		BVS	bad$l

		LDR	r0, [r11, #Wimp_WindowInfo_title_flags]
		TST	r0, #Wimp_IconIndirected
		BEQ	bad$l				; don't look at non-indirected title bars

		LDR	r7, [r11, #Wimp_WindowInfo_title_data + 0] ; point to path name

		MOV	r0, #Wimp_UserMessageAcknowledge
		ADD	r1, r11, #Wimp_WindowInfo
		MOV	lr, #Wimp_MessageHeader_data
		STR	lr, [r1, #Wimp_MessageHeader_size] ; make a valid message block
		MOV	lr, #0
		STR	lr, [r1, #Wimp_MessageHeader_your_ref] ; your_ref = 0, so don't do anything
		MOV	r2, r9				; current window handle
		SWI	XWimp_SendMessage		; send an ack to window's owner to discover task id in r2 (3-198)
		BVS	bad$l

		MOV	r0, r2				; source task
		LDR	r2, TaskHandle			; destination task
		CMP	r0, r2				; is it Director?
		BEQ	bad$l				; if so, exit.
		MOV	r1, r7				; source buffer
		MOV	r3, r8				; destination buffer
		MOV	r4, #StringSize			; buffer length
		SWI	XWimp_TransferBlock		; copy a block of memory from the source task
		BVS	bad$l

		MOV	r0, #0
		STRB	r0, [r8, #StringSize - 1]	; null terminate extreme length

		MOV	r0, r8
space$l		LDRB	lr, [r0], #1
		CMP	lr, #32				; look for control char or space
		BGT	space$l
		MOV	lr, #0
		STRB	lr, [r0, #-1]			; null terminate

		MOV	r0, #OSFile_ReadNoPath		; r0 = 17
		MOV	r1, r8
		SWI	XOS_File
		BVS	bad$l				; end if error
		CMP	r0, #OSFile_NotFound
		BEQ	isitpipe$l			; end if file not found

ok$l		ClearZ					; ok (NE)
		EXIT

isitpipe$l						; r1  filename
		ADR	r0, pipe$l			; r0  "pipe:$"
		BL	strcmpil			; compare, regardless of length
		BEQ	ok$l

bad$l		SetZ					; bad (EQ)
		EXIT

pipe$l		DCB	"pipe:$", 0


;*******************************************************************************
;----f- Director.s.Task.OpenMenu
; Name
;   OpenMenu
;
; Purpose
;   This opens a menu
;
; Entry
;   r0 = 0 for normal menu (at mouse pointer) or height of menu (at icon bar)
;   r1  menu block
;   r2  a current Wimp_Pointer block
;
; Exit
;
;------
;*******************************************************************************


OpenMenu	ROUTINE	"r0-r4"

		MOV	r4, r2				; r2  Wimp_Pointer
		LDR	r2, [r4, #Wimp_Pointer_pos + OS_Coord_x]
		SUB	r2, r2, #64
		CMP	r0, #0
		ADDNE	r3, r0, #96
		LDREQ	r3, [r4, #Wimp_Pointer_pos + OS_Coord_y]
		STR	r1, LastMenu
		STR	r2, LastMenu_x
		STR	r3, LastMenu_y
		SWI	XWimp_CreateMenu
		BVS	TaskError

		ClearV
		EXIT


;*******************************************************************************
;----f- Director.s.Task.OpenMenuNow
; Name
;   OpenMenuNow
;
; Purpose
;   This opens the menu in r10, r11
;   It reads the last message type
;   If it was Wimp_MouseClick then it opens menu at position specified by
;   PollBlock, otherwise it reads the mouse position and opens the menu there
;
; Entry
;   r10  menu block
;   r11  MenuBlock
;
; Exit
;   It may return errors
;------
;*******************************************************************************


OpenMenuNow	ROUTINE_SF	"r0-r3"
mouseblock$l	#	Wimp_Pointer
		END_SF

		LDR	r0, ValidWimpPointer
		CMP	r0, #0
		ADRNE	r2, PollSpace			; r2  current Wimp_Pointer
		BNE	dontread$l

		ADR	r1, mouseblock$l
		SWI	XWimp_GetPointerInfo		; read pointer info
		BVS	error$l
		ADR	r2, mouseblock$l			; r2  current Wimp_Pointer

dontread$l	LDR	lr, [r2, #Wimp_Pointer_w]
		CMP	lr, #Wimp_IconBar		; Were we over the icon bar?
		MOVNE	r0, #0				; no
		LDREQ	r0, [r11, #MenuBlock_height]	; yes
		MOV	r1, r10				; r1  menu
		BL	OpenMenu
		BVS	error$l

error$l		STRSP	r0, r0, VS
ok$l		EXIT					; return with flags


;*******************************************************************************
;----f- Director.s.Task.SetPointerPosition
; Name
;   SetPointerPosition
;
; Purpose
;   This sets the current pointer position
;
; Entry
;   r0 = x
;   r1 = y
;
; Exit
;   It may return an error
;------
;*******************************************************************************


SetPointerPosition	ROUTINE_SF	"r0-r3"
block$l		#	8
		AlignSpace
		END_SF

		STRB	r0, block$l + 1
		MOV	r0, r0, LSR#8
		STRB	r0, block$l + 2
		STRB	r1, block$l + 3
		MOV	r1, r1, LSR#8
		STRB	r1, block$l + 4
		MOV	r0, #OSWordPointer_OpSetPosition
		STRB	r0, block$l + 0

		MOV	r0, #OSWord_Pointer
		ADR	r1, block$l
		SWI	XOS_Word

		EXIT


;*******************************************************************************
;----f- Director.s.Task.find_path
; Name
;   find_path
;
; Purpose
;   This finds the path pointed to by r8 or if r8 is null then
;   it finds the path or the window the pointer is over
;
; Entry
;   r8  path
;
; Exit
;   r0  path or 0 for not found
;------
;*******************************************************************************


find_path	ROUTINE	"r1-r3", EXPORT

		LDRB	lr, [r8]
		CMP	lr, #32
		BLT	read$l				; if path is null then read it from pointer position

		MOV	r0, r8				; r0  path
		ADR	r1, PollSpace + Wimp_Message + StringSize
		MOV	r2, #StringSize
		SWI	XOS_GSTrans
		BVS	TaskError
		BCS	DoTooSmall

		ADR	r0, PollSpace + Wimp_Message + StringSize ; point to string

		EXIT

read$l		LDR	r0, PollSpace + Wimp_Pointer_w
		ADR	r1, PollSpace + Wimp_Message
		ADR	r2, PollSpace + Wimp_Message + StringSize ; scratch space
		BL	FindPath
		MOVEQ	r0, #0
		ADRNE	r0, PollSpace + Wimp_Message	; r0  file path

		EXIT

DoTooSmall	ADR	r0, TooSmall
		B	TaskErrorMT
TooSmall	ERROR	"$BufferTooSmall", Error_BufferTooSmall

DirectorMenu	DCB	"Director$Menu", 0
		ALIGN


;*******************************************************************************
;----f- Director.s.Task.DoSubMenu, RunMenu and DoCommand
; Name
;   DoSubMenu, RunMenu and DoCommand
;
; Purpose
;   This opens menus and runs commands
;
;   Via wimp message (from the Filters)
;
;   Via mouse click (clicking on the icon bar say)
;
;   Via sub-menu (sliding to the right)
;
;   Via menu-selection (when click on an item with a sub-menu or command)
;
;   Via Hot-key (when hotkey an item with a sub-menu or command)
;
;   If a sub-menu-ed item has no command then clicking on it ought to open the
;   sub-menu
;
;   Want one routine to deal with all those cases
;
;   "Text" for normal command or sub-menu
;   "Menu:Name" to bring up menu
;   "Save:Path" for save box (path may be * to use path of window that pointer is over)
;   "Path:Path"" for menu of that path (")
;   "Command:Text" runs the text as if it were a command
;   "Quit:" Quits
;   "Info:" Brings up info window
;
; Entry
;   r0  Menu name or Command text
;
; Exit
;   r0  menu or 0
;------
;*******************************************************************************


DoSubMenu	ROUTINE	"r1"
		MOV	r1, #2
		BL	DoCommand_
		EXIT					; return with flags

RunMenu		ROUTINE	"r1", EXPORT
		MOV	r1, #1
		BL	DoCommand_
		EXIT					; return with flags

DoCommand	ROUTINE	"r1"
		MOV	r1, #0
		BL	DoCommand_
		EXIT					; return with flags


;*******************************************************************************
;----f- Director.s.Task.DoCommand_
; Name
;   DoCommand_
;
; Purpose
;
;
; Entry
;   r0  Menu name or Command text
;   r1 = type
;     0 = command
;     1 = menu
;     2 = sub-menu
;
; Exit
;   r0  New menu block or 0
;   it may return an error
;------
;*******************************************************************************


DoCommand_	ROUTINE_SF	"r1-r11"
string$l	#	StringSize
whandle$l	#	Wimp_W
windowstate$l	#	Wimp_WindowState		; For OldMenu
		END_SF

		MOV	r7, r0				; r7  text
		MOV	r9, r1				; r9 = type
restart$l
		MOV	r10, #0				; r10  menu
		MOV	r11, #0				; r11  MenuBlock

		; First parse the text to see whether it has any commands

		MOV	r8, r7				; r8  command proper
parse$l		LDRB	r0, [r8], #1
		UpperCase	r0, lr
		CMP	r0, #':'			; command separator
		BEQ	prefix$l
		CMP	r0, #'A'
		BLT	noprefix$l
		CMP	r0, #'Z'
		BLE	parse$l				; look though A-Z only

		; here we have ascertained the command has no prefix
		; so we must do the default action for its type

noprefix$l	MOV	r8, r7				; r8  command

		CMP	r9, #0
		BEQ	Command$l			; treat as command
		B	Menu$l				; otherwise menu

		; here we have found the command has a prefix
		; so we must see whether it is a valid one
		; and if not treat it as non-existent

prefix$l	LDRB	r4, [r8, #-1]			; to replace
		MOV	lr, #0
		STRB	lr, [r8, #-1]			; null terminate the prefix

		MACRO
$label		IsIt	$name
$label		ADR	r0, %FT00
		BL	strcmpi
		STREQB	r4, [r8, #-1]			; put ':' back in
		BEQ	$name.$l
		B	%FT10
00
		DCB	"$name", 0
		ALIGN
10
		MEND

		MOV	r1, r7				; r1  option text
		IsIt	Menu
		IsIt	Save
		IsIt	Path
		IsIt	Command
		IsIt	Quit
		IsIt	Info
		IsIt	OldMenu
		IsIt	MenuMenu
		IsIt	Memoriser
		IsIt	Dynamic
		IsIt	GSTrans
		IsIt	Window

		STRB	r4, [r8, #-1]			; put ':' back in
		B	noprefix$l			; not found so run as no prefix

		; Open the save box

Save$l		LDR	r10, SaveWindow			; open save window as sub-menu
		BL	find_path			; r0  path
		BL	SetUpSaveWindow			; set this path in the window
		B	openwindow$l

		; Open a window

Window$l	MOV	r0, r8				; r0  name
		BL	WindowBlockOpen
;		BVS	error$l
		BVS	ok$l				;  don't report error if window isn't loaded
		MOV	r10, r0				; r10 = window handle
		B	openwindow$l

		; Open the info box

Info$l		LDR	r10, InfoWindow			; open info window as sub-menu

openwindow$l	CMP	r9, #2				; sub-menu?
		BEQ	ok$l

		MOV	r0, r10
		MOV	r1, #&80000000
		BL	OpenWindow			; open window under pointer
		B	ok$l

		; Quit the task

Quit$l		B	TaskShutDownAndKill		; Finalise the Wimp task

GSTrans$l
;	ADRL	r0, alias$l
;	SWI	XWimp_CommandWindow
;	MOV	r0, r8
;	SWI	XOS_Write0
;	SWI	XOS_NewLine
;	MOV	r0, #0
;	SWI	XWimp_CommandWindow
		MOV	r0, r8				; GSTrans the command
		ADR	r1, string$l
		MOV	r2, #StringSize
		SWI	XOS_GSTrans
		BVS	error$l
		ADRCSL	r0, TooSmall
		BCS	error$l
		ADR	r7, string$l			; r7  text
		B	restart$l

		; This opens a menu as a menu or sub-menu

Menu$l		MOV	r0, r8
		ADR	r1, MenuStoredAnchor
		BL	MenuBlockFind
		MOVEQ	r11, r0				; r11  new menu block
		MOVNE	r11, #0				; or not found

		CMP	r9, #2				; if not sub-menu
		BEQ	is_sub_menu$l
		BLNE	ClearDisplayed			; make sure all old menus are missing

		CMP	r11, #0
		MOVEQ	r0, r8
		ADREQ	r1, MenuStoredAnchor
		BLEQ	MenuBlockFind
		MOVEQ	r11, r0				; r11  new menu block

is_sub_menu$l
		CMP	r11, #0				; have we found the block yet?
		BEQ	ok$l				; exit with no error if menu not found in display or stored

		CMP	r9, #2				; if not sub-menu
		BLNE	ClearDisplayed			; make sure all old menus are missing

		BL	MenuBlockForDisplay		; find the sub-menu and get it ready for display
		BVS	error$l
		LDR	r10, [r11, #MenuBlock_menu + StringBlock_buffer] ; r10  points to menu

		CMP	r9, #2				; sub-menu?
		BEQ	ok$l				; if yes then don't display

		BL	OpenMenuNow
		BVS	error$l
		B	ok$l

		; Do a command

Command$l	ADR	r0, alias$l		 	; r0  name
		MOV	r1, r8			 	; r1  value
		MOV	r4, #OS_VartypeString	 	; a gstransable string
		BL	SetVarVal		 	; set the system variable
		BVS	error$l

		;;;; This doesn't always read Wimp_Pointer properly as PollSpace doesn't always contain one

		LDR	r0, PollSpace + Wimp_Pointer_w
		LDR	r1, PollSpace + Wimp_Pointer_i
		LDR	r2, PollSpace + Wimp_Pointer_buttons
		BL	WindowSetVars
		BVS	error$l

		ADR	r0, DirectorMenu
		BL	UnsetVarVal		 	; unset Director$Menu, ignore errors

		ADR	r0, command$l
		BL	StartWimpTask		 	; run the command
		BVS	error$l
		B	ok$l

		; Do a dynamic menu

Dynamic$l	ADR	r0, alias$l		 	; r0  name
		MOV	r1, r8			 	; r1  value
		MOV	r4, #OS_VartypeString	 	; a gstransable string
		BL	SetVarVal		 	; set the system variable
		BVS	error$l

		;;;; This doesn't always read Wimp_Pointer properly as PollSpace doesn't always contain one

		LDR	r0, PollSpace + Wimp_Pointer_w
		LDR	r1, PollSpace + Wimp_Pointer_i
		LDR	r2, PollSpace + Wimp_Pointer_buttons
		BL	WindowSetVars
		BVS	error$l
		ADR	r0, DirectorMenu
		BL	UnsetVarVal			; unset Director$Menu, ignore errors

		ADR	r0, command$l
		BL	StartWimpTask			; run the command
		BVS	error$l

;		ADR	r0, dynamicvar$l
;		ADR	r1, string$l
;		MOV	r2, #StringSize-1
;		MOV	r3, #0
;		MOV	r4, #OS_VartypeExpanded
;		SWI	XOS_ReadVarVal
;		BVS	error$l
;		ADR	r8, string$l			; r8 -> name of menu to open
;		MOV	r0, #0
;		STRB	r0, [r8, r2]			; terminate string

		ADR	r8, dynamicvar$l		; r8 -> name of menu to open

		B	GSTrans$l			; trans the variable and do it
;		B	ok$l

alias$l		DCB	"Alias$"
command$l	DCB	"$Name.Run", 0
dynamicvar$l	DCB	"<$Name.$$Menu>", 0
newpath$l	DCB	"<$Name.$$CurrentPath>.<Leaf>", 0
		ALIGN

		; Open a path menu
Path$l
		BL	find_path			; r0  path
		CMP	r0, #0
		BEQ	ok$l				; end if no path

		CMP	r9, #2				; if not sub-menu
		BLNE	ClearDisplayed			; make sure all old menus are missing

		MOV	r1, #1				; up directories
		BL	FileMenuCreate			; r0  MenuBlock
		BVS	error$l
		MOV	r11, r0				; r11  MenuBlock

		LDR	r10, [r11, #MenuBlock_menu + StringBlock_buffer] ; point to menu

		CMP	r9, #2				; sub menu?
		BEQ	ok$l				; have finished if sub-menu

		BL	OpenMenuNow
		B	ok$l

		; This opens the menu that was there previously
OldMenu$l	ADR	r3, LastMenuBlock
		LDR	r2, [r3, #Wimp_Pointer_w]	; r2 = window handle
		CMP	r2, #0
		BEQ	ok$l				; if we haven't had an old menu then don't try to use it!

		; Find out about the window
		ADR	r4, windowstate$l
		STR	r2, [r4]
		MOV	r1, r4
		SWI	XWimp_GetWindowState
		BVS	ok$l				; exit if it no longer exists

		; Is it open
		LDR	r1, [r4, #Wimp_WindowState_flags]
		TST	r1, #1 << 16
		BEQ	ok$l

		; Is it hidden behind the pinboard/iconized?
;;;;		; To do
;;;;		MOV	r1, r4
;;;;		MOV	r0, #-3
;;;;		STR	r0, [r1]
;;;;		SWI	XWimp_GetWindowState
;;;;
;;;;		LDR	r1, [r4, #Wimp_WindowState_next]
;;;;		ADR	r0, tp2$l
;;;;		BL	SetVarValN
;;;;;		CMP	r1, #-3
;;;;;		BEQ	ok$l
		MOV	r0, #1
		STR	r0, GiveOldMenu			; let this one though the filter
		LDR	r0, [r3, #Wimp_Pointer_pos + OS_Coord_x] ; r0 = x
		LDR	r1, [r3, #Wimp_Pointer_pos + OS_Coord_y] ; r1 = y
		BL	SetPointerPosition
		BVS	TaskError
		MOV	r4, r0				; r4 = x
		MOV	r5, r1				; r5 = y
		MOV	r0, #Wimp_MouseClick
		ADR	r1, LastMenuBlock
		SWI	XWimp_SendMessage
		BVS	TaskError
		B	ok$l

		; This opens the MenuMenu after setting the path
MenuMenu$l	BL	find_path		 	; get a path
		CMP	r0, #0
		BEQ	ok$l				; end if no path
		BL	SetCurrentPath
		BVS	error$l
		ADR	r0, newpath$l
		BL	SetCurrentPath
		BVS	error$l
		BL	MemoriseMenuMenu		; Add file to Memoriser.
							; Skip this command if not required.
		ADRL	r8, MenuMenuAfterGSTrans
		B	GSTrans$l			; open the MenuMenu

		; This opens the Memoriser menu

Memoriser$l	CMP	r9, #2				; if not sub-menu
		BLNE	ClearDisplayed			; make sure all old menus are missing

		LDRB	r0, [r8, #0]			; get the parameter
		LDRB	r1, [r8, #1]			; get the parameter
		CMP	r0, #32
		MOVLT	r0, #2_111			; everything if no parameter
		ANDGE	r0, r0, #2_111			; flags
		BL	MemoriserMenuCreate		; r0  MenuBlock
		BVS	error$l
		MOV	r11, r0				; r11  MenuBlock

		LDR	r10, [r11, #MenuBlock_menu + StringBlock_buffer] ; point to menu

		CMP	r9, #2				; sub menu?
		BEQ	ok$l				; have finished if sub-menu

		BL	OpenMenuNow
;		B	ok$l

		; End with no errors

ok$l		MOV	r0, r10				; r0  menu
		ClearV
		EXIT

error$l		SetV
		EXIT

;*******************************************************************************

		END
