;*******************************************************************************
; Director - Filter
;
; 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.Filter
; Name
;   Filter
;
; Purpose
;   Filter
;------
;*******************************************************************************


		TTL	> Filter

		GET	OSLib:oslib.hdr.Wimp
		GET	OSLib:oslib.hdr.OSByte
		GET	OSLib:oslib.hdr.Filter
		GET	OSLib:oslib.hdr.Filer
		GET	OSLib:oslib.hdr.TaskManager
		GET	AsmLib2:hdr.RegsBoth
		GET	AsmLib2:hdr.MacrosBoth
		GET	AsmLib2:hdr.Macros26		; for 26-bit support
		GET	h.WorkSpace
		GET	h.ListMacros
		GET	h.Constants
		GET	h.Memory
		GET	h.ModuleHead
		GET	h.Task
		GET	h.BMG
		GET	h.Menus
		GET	h.Memoriser

		AREA	|Filter|, CODE, READONLY


;*******************************************************************************
;----s- Director.s.Filer.FilterBlock
; Name
;   FilterBlock
;
; Purpose
;   FilterBlock structure
;
; Source

			^	0
FilterBlock_link	#	4
FilterBlock_name	#	4
FilterBlock_taskname	#	4
FilterBlock_taskhandle	#	4
FilterBlock_menu	#	4
FilterBlock_icon	#	4
FilterBlock_flags	#	4
FilterBlock		EQU	:INDEX: @

;------
;*******************************************************************************


; Bits to show which filters are running

FilerFilterBit		EQU	1 << 1
ClickFilterBit		EQU	1 << 2


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


			^	(:INDEX: FilterVars), wp

MouseBlock		#	Wimp_Pointer
MouseButtons		#	4
LastFilerMenu		#	4
LastPressedButtons	#	4
InterceptMouseButtons	#	4
FilerFilterStatus	#	4
FilerFilterKeys		#	4
FilerFilterFses		#	4

			ASSERT	@ <= EndFilterVars


;*******************************************************************************
;----f- Director.s.Filter.FilterInitialise
; Name
;   FilterInitialise
;
; Purpose
;   This initialises the Filter
;
; Entry
;
;
; Exit
;   It may return an error
;------
;*******************************************************************************


FilterInitialise	ROUTINE	"", EXPORT

		MOV	r0, #MouseV
		ADRL	r1, OSMouseHandler
		MOV	r2, wp
		SWI	XOS_Claim			; claim calls to OS_Mouse

		BLVC	FilterInitialiseFilters

		EXIT


;*******************************************************************************
;----f- Director.s.Filter.FilterInitialiseFilters
; Name
;   FilterInitialiseFilters
;
; Purpose
;   This initialises the Wimp filters
;
; Entry
;
;
; Exit
;
;------
;*******************************************************************************


FilterInitialiseFilters	ROUTINE	"r0-r11", EXPORT

		LDR	r11, FiltersRunning

		TST	r11, #FilerFilterBit
		BNE	nofiler$l

		ADR	r0, FilerName
		BL	FindTaskHandle
		CMP	r0, #0
		BEQ	nofiler$l
		STR	r0, FilerHandle

		ADR	r0, FilterName
		ADRL	r1, FilerFilter
		MOV	r2, wp
		LDR	r3, FilerHandle
		LDR	r4, =-1 :EOR: (1 << Wimp_MouseClick) :EOR: (1 << Wimp_MenuSelection) :EOR: (1 << Wimp_UserMessage) :EOR: (1 << Wimp_UserMessageRecorded)	;what to filter
		SWI	XFilter_RegisterPostFilter
		ORRVC	r11, r11, #FilerFilterBit
nofiler$l

		TST	r11, #ClickFilterBit
		BNE	noclick$l

		ADR	r0, FilterName
		ADRL	r1, ClickFilter
		MOV	r2, wp
		MOV	r3, #0				; all tasks
		LDR	r4, =-1 :EOR: (1 << Wimp_MouseClick) :EOR: (1 << Wimp_UserMessage) :EOR: (1 << Wimp_UserMessageRecorded)
		SWI	XFilter_RegisterPostFilter
		ORRVC	r11, r11, #ClickFilterBit
noclick$l

		STR	r11, FiltersRunning

		ClearV
		EXIT

FilerName	DCB	"Filer", 0
FilterName	DCB	"$Name", 0
		ALIGN


;*******************************************************************************
;----f- Director.s.Filter.FilterFinalise
; Name
;   FilterFinalise
;
; Purpose
;   This finalises the Filter
;
; Entry
;
;
; Exit
;
;------
;*******************************************************************************


FilterFinalise	ROUTINE	"r0-r11", EXPORT

		BL	FilterBlockListDestroy		; destroy the filters list
		BL	FilterFinaliseFilters

		MOV	r0, #MouseV
		ADRL	r1, OSMouseHandler
		MOV	r2, wp
		SWI	XOS_Release			; release vector, ignore errors

		ClearV
		EXIT


;*******************************************************************************
;----f- Director.s.Filter.FilterFinaliseFilters
; Name
;   FilterFinaliseFilters
;
; Purpose
;   This finalises the Wimp filters
;
; Entry
;
;
; Exit
;
;------
;*******************************************************************************


FilterFinaliseFilters	ROUTINE	"r0-r11", EXPORT

		LDR	r11, FiltersRunning

		TST	r11, #ClickFilterBit
		BEQ	noclick$l

		ADR	r0, FilterName
		ADRL	r1, ClickFilter
		MOV	r2, wp
		MOV	r3, #0				; all tasks
		LDR	r4, =-1 :EOR: (1 << Wimp_MouseClick) :EOR: (1 << Wimp_UserMessage) :EOR: (1 << Wimp_UserMessageRecorded)
		SWI	XFilter_DeRegisterPostFilter
		BICVC	r11, r11, #ClickFilterBit
noclick$l

		TST	r11, #FilerFilterBit
		BEQ	nofiler$l

		ADR	r0, FilterName
		ADRL	r1, FilerFilter
		MOV	r2, wp
		LDR	r3, FilerHandle
		LDR	r4, =-1 :EOR: (1 << Wimp_MouseClick) :EOR: (1 << Wimp_MenuSelection) :EOR: (1 << Wimp_UserMessage) :EOR: (1 << Wimp_UserMessageRecorded)	;what to filter
		SWI	XFilter_DeRegisterPostFilter
		BICVC	r11, r11, #FilerFilterBit
nofiler$l

		STR	r11, FiltersRunning

		ClearV
		EXIT


;*******************************************************************************
;----f- Director.s.Filter.FilterBlockFind
; Name
;   FilterBlockFind
;
; Purpose
;   This finds the given menu string in the menu list
;   or returns a pointer to the previous item
;
; Entry
;   r0  name of filter
;
; Exit
;   r0  filter block
;   r1  previous filter block (if found)
;   Flags:
;     EQ means found
;     NE means not found
;------
;*******************************************************************************


FilterBlockFind	ROUTINE	"r2-r4", EXPORT

		ADR	r4, FiltersAnchor		; r4  list anchor

loop$l		ListWalk	r4, r2			; r2  previous, r4  current
		BEQ	notfound$l
		LDR	r1, [r4, #FilterBlock_name]
		BL	strcmpi				; to_find - current
		BGT	loop$l				; continue until alphabetical place found
		BNE	notfound$l

found$l		MOV	r0, r4				; point to current FilterBlock
		MOV	r1, r2
		SetZ
		EXIT

notfound$l	MOV	r0, r4				; point to current FilterBlock
		MOV	r1, r2
		ClearZ
		EXIT

;*******************************************************************************
;----f- Director.s.Filter.FilterBlockCreate
; Name
;   FilterBlockCreate
;
; Purpose
;   This creates a new filter block and links it into the end of the list
;   supplied.
;   It initialises all the fields in the filter block
;
; Entry
;   r0  filter name
;   r1  task name to filter (0 for delete, -1 for all tasks)
;   r2  command to run
;   r3 = icon (&80000000 = none)
;   r4 = flags
;
; Exit
;   r0  filter block (0 if delete only)
;------
;*******************************************************************************


FilterBlockCreate	ROUTINE	"r1-r6", EXPORT

		MOV	r2, r0				; r2  filter name

kill$l		MOV	r0, r2				; name
		BL	FilterBlockFind
		BNE	exitkill$l
		BL	FilterBlockDestroy		; if found delete it
		B	kill$l

exitkill$l	MOV	r4, r1				; r4  link

		LDRSP	r0, r1				; task name
		TEQ	r0, #0
		BEQ	exit$l				; delete filter only, return with r0 = 0

		MOV	r0, #FilterBlock
		BL	malloc
		EXIT	VS				; exit with flags on error

		MOV	r3, r0				; r3 is filter block
		MOV	r1, #FilterBlock
		BL	memclear			; clear the filter block to 0

		MOV	r0, r2
		BL	strdup
		EXIT	VS
		STR	r0, [r3, #FilterBlock_name]

		LDRSP	r0, r1				; task name
		BL	strdup
		EXIT	VS
		STR	r0, [r3, #FilterBlock_taskname]

		LDRSP	r0, r2				; menu
		BL	strdup
		EXIT	VS
		STR	r0, [r3, #FilterBlock_menu]

		LDRSP	r0, r3				; icon
		STR	r0, [r3, #FilterBlock_icon]

		LDRSP	r0, r4				; flags
		STR	r0, [r3, #FilterBlock_flags]

		Link	r3, r4, lr			; link the block into the end of the list

		BL	FilterCheckTasks		; make sure the task handles are up to date

		MOV	r0, r3				; r0  filter block
exit$l		ClearV
		EXIT


;*******************************************************************************
;----f- Director.s.Filter.FilterBlockDestroy
; Name
;   FilterBlockDestroy
;
; Purpose
;   This destroys a filter block and unlinks it from the list.
;   It releases any memory attached also.
;
; Entry
;   r0  filter block
;   r1  previous filter block
;
; Exit
;
;------
;*******************************************************************************


FilterBlockDestroy	ROUTINE	"r0-r3", EXPORT

		MOV	r3, r0				; r3  FilterBlock
		UnLink	r3, r1, lr			; unlink the FilterBlock

		LDR	r0, [r3, #FilterBlock_menu]	; free attached items
		BL	free
		LDR	r0, [r3, #FilterBlock_taskname]
		BL	free
		LDR	r0, [r3, #FilterBlock_name]
		BL	free

		MOV	r0, r3				; free block
		BL	free

		EXIT


;*******************************************************************************
;----f- Director.s.Filter.FilterBlockListDestroy
; Name
;   FilterBlockListDestroy
;
; Purpose
;   This destroys all the filters in the list
;
; Entry
;
;
; Exit
;
;------
;*******************************************************************************


FilterBlockListDestroy	ROUTINE	"r0-r3", EXPORT

		ADR	r0, FiltersAnchor
loop$l		ListWalkForDestruction	r0, r1, r2
		BEQ	exitloop$l
		BL	FilterBlockDestroy
		B	loop$l

exitloop$l	EXIT


;*******************************************************************************
;----f- Director.s.Filter.FindTaskHandle
; Name
;   FindTaskHandle
;
; Purpose
;   This finds the task handle of the task name pointed to by r0
;
; Entry
;   r0 -> name of task
;
; Exit
;   r0 = task handle or 0 for not found
;------
;*******************************************************************************


FindTaskHandle	ROUTINE_SF	"r1-r5"
task$l		#	TaskManager_Task
		END_SF

		MOV	r5, r0				; pointer to name
		MOV	r4, #0				; context
loop$l
		MOV	r0, r4
		ADR	r1, task$l			; block
		MOV	r2, #TaskManager_Task		; get 1 at a time please
		SWI	XTaskManager_EnumerateTasks
		MOVVS	r0, #0
		EXIT	VS				; not found if error
		MOVS	r4, r0				; save context
		MOVMI	r0, #0
		EXIT	MI				; not found

		LDR	r0, task$l + TaskManager_Task_name
		MOV	r1, r5
		BL	strcmpi				; compare name
		BNE	loop$l

		LDR	r0, task$l + TaskManager_Task_task ; found
		EXIT


;*******************************************************************************
;----f- Director.s.Filter.FilterCheckTasks
; Name
;   FilterCheckTasks
;
; Purpose
;   This updates all the task handles in the filters list
;
; Entry
;
;
; Exit
;
;------
;*******************************************************************************


FilterCheckTasks ROUTINE	"r0-r3", EXPORT

		BL	FilterFinaliseFilters
		BL	FilterInitialiseFilters		; check the Wimp filters

		ADR	r3, FiltersAnchor
loop$l		ListWalk	r3, r2
		EXIT	EQ

		LDR	r0, [r3, #FilterBlock_taskname]
		LDRB	lr, [r0, #0]
		TEQ	lr, #'*'
		BNE	notall$l
		LDRB	lr, [r0, #1]
		CMP	lr, #32
		BGE	notall$l
		MOV	r0, #-1				; -1 for all tasks (if name is "*")
		B	taskdone$l
notall$l
		BL	FindTaskHandle
taskdone$l
		STR	r0, [r3, #FilterBlock_taskhandle]

		B	loop$l


;*******************************************************************************
;----f- Director.s.Filter.SendOpenMenu
; Name
;   SendOpenMenu
;
; Purpose
;   This sends a message to our task asking for a menu to be opened
;
; Entry
;   r0  Wimp_Pointer
;   r1  string1 (or 0)
;   r2  string2 (or 0)
;
; Exit
;   It may return errors
;------
;*******************************************************************************


SendOpenMenu	ROUTINE_SF	"r0-r4", EXPORT
openmenu$l	#	512
		END_SF

		MOV	r3, r1				; r3  string1
		MOV	r4, r2				; r4  string2
		MOV	r2, r0				; r2  Wimp_Pointer

		ADR	r0, openmenu$l
		MOV	r1, #512
		BL	memclear			; set message block to 0

		MOV	r0, r2
		ADR	r1, openmenu$l + Wimp_MessageHeader_data + $Name._MessageOpenMenu_ptr
		MOV	r2, #Wimp_Pointer
		BL	memcpy				; copy the Wimp_Pointer block in

		ADR	r1, openmenu$l + Wimp_MessageHeader_data + $Name._MessageOpenMenu_menu

		MOV	lr, #0
		STRB	lr, [r1], #1			; write a null string

		MOVS	r0, r3
		SUBNE	r1, r1, #1			; reverse over terminator
		BLNE	strcpy				; write string1 if non null

		MOVS	r0, r4
		SUBNE	r1, r1, #1			; reverse over terminator
		BLNE	strcpy				; write string2 if non null

		ADR	r0, openmenu$l + Wimp_MessageHeader_data + $Name._MessageOpenMenu_menu
		BL	strlen1
		ADD	r0, r0, #Wimp_MessageHeader_data + $Name._MessageOpenMenu_menu + 3
		BIC	r0, r0, #3			; align
		STR	r0, openmenu$l + Wimp_MessageHeader_size

		LDR	r0, =Message_$Name.OpenMenu
		STR	r0, openmenu$l + Wimp_MessageHeader_action ; type of message

		MOV	r0, #Wimp_UserMessage
		ADR	r1, openmenu$l
		LDR	r2, TaskHandle			; our handle
		SWI	XWimp_SendMessage		; send us a MouseClick event

		STRSP	r0, r0, VS
		EXIT					; return with flags


;*******************************************************************************
;----f- Director.s.Filter.ClickFilterMenu
; Name
;   ClickFilterMenu
;
; Purpose
;   This opens a menu if the Wimp_Pointer indicates that director would like
;   to intercept this particular click
;
; Entry
;   r11  Wimp_Pointer
;
; Exit
;   Flags
;    EQ = menu opened, so claim
;    NE = menu not opened
;------
;*******************************************************************************


ClickFilterMenu	ROUTINE_SF	"r0-r11"
message$l	#	256
		END_SF

		; Now we have read the wimp information, we need to go though
		; the list checking whether the conditions asked for have been
		; met and if so to execute the command.

		LDR	r5, [r11, #Wimp_Pointer_i]	; r5 = which icon we are over

		; need to turn window handle into task handle

		MOV	r0, #Wimp_UserMessageAcknowledge
		ADR	r1, message$l
		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
		LDR	r2, [r11, #Wimp_Pointer_w]	; current window handle
		CMP	r2, #Wimp_IconBar
		MOVEQ	r3, r5				; current icon number (used if this is the icon bar)
		MOVEQ	r5, #Wimp_IconIconBar		; code for an iconbar icon
		SWI	XWimp_SendMessage		; send an ack to window's owner to discover task id in r2 (3-198)
		BVS	error$l
		MOV	r6, r2				; r6 = task handle of window's owner

		; get flags into r7 (mouse buttons and  key state)
		BL	ReadKeyModifiers
		LDR	r7, [r11, #Wimp_Pointer_buttons]
		ORRS	r7, r7, r0, LSR#13		; r7 = 00acssma ALT CTRL SHIFT SELECT MENU ADJUST

		ADR	r4, FiltersAnchor		; r4  list anchor

loop$l		ListWalk	r4, r3			; r3  previous, r4  current
		BEQ	exit$l				; end if we have come to the end of the list

		LDR	r0, [r4, #FilterBlock_taskhandle]
		CMP	r0, #-1				; -1 is all tasks
		TEQNE	r0, r6
		BNE	loop$l				; if task handle doesn't match then continue

		LDR	r0, [r4, #FilterBlock_icon]
		TEQ	r0, #&80000000			; is all icons
		TEQNE	r0, r5
		BNE	loop$l				; if task handle doesn't match then continue

		LDR	r0, [r4, #FilterBlock_flags]
		TEQ	r0, r7				; if flags don't match then continue
		BNE	loop$l

found$l		MOV	r0, r11
		ADR	r1, LastMenuBlock
		MOV	r2, #Wimp_Pointer
		BL	memcpy				; copy away the old menu block

		MOV	r0, r11
		LDR	r1, [r4, #FilterBlock_menu]
		MOV	r2, #0
		BL	SendOpenMenu			;send a message to open the menu (ignore errors)

intercept$l	SetZ
		EXIT

error$l
exit$l		ClearZ
		EXIT

;*******************************************************************************
;----f- Director.s.Filter.OSMouseHandler
; Name
;   OSMouseHandler
;
; Purpose
;   We need to wibble though the list of filters deciding which ones to apply
;   We should go though the list 4 times (?) to make sure the filters are done
;   in the right sequence.
;
; Entry
;   lr = return address for pass on
;   [sp] = return address for intercept
;
; Exit
;   r0 = mouse x coordinate
;   r1 = mouse y coordinate
;   r2 = mouse buttons
;   r3 = time of button change
;------
;*******************************************************************************


OSMouseHandler	ROUTINE_SF	"r0-r8, r11, wp"
		END_SF

		MOV	r8, lr				; r8  OS_Mouse routine
		ADRF	lr, return$l			; lr  return address
		STMFD	sp!, {lr}			; this will be pulled by final intercept
		MOV	pc, r8				; call OS_Mouse with unchanged r10, r11
return$l	LDRSP	wp, wp				; restore our workspace pointer
		BVS	error$l
		ADRSP	lr, r0
		STMIA	lr, {r0-r3}			; save registers for return

		ANDS	r7, r2, #2_111			; r7 = current mouse buttons
		STRNE	r7, LastPressedButtons		; store the last click
		LDRNE	lr, InterceptMouseButtons
		TEQNE	lr, #0
		BNE	intercept$l
		MOV	lr, #0
		STR	lr, InterceptMouseButtons
		LDR	r8, MouseButtons		; r8 = old buttons
		STR	r7, MouseButtons
		TEQ	r7, r8
		BEQ	exit$l				; if buttons have't changed state, then end

		ADR	r11, MouseBlock			; r11  MouseBlock

		MOV	r1, r11
		SWI	XWimp_GetPointerInfo
		BVS	exit$l				; exit if an error occurred

		STR	r7, [r11, #Wimp_Pointer_buttons] ; store the buttons since we are in advance of the wimp
		LDRSP	lr, r0				; mouse x co-ord
		STR	lr, [r11, #Wimp_Pointer_pos + OS_Coord_x]
		LDRSP	lr, r1				; mouse y co-ord
		STR	lr, [r11, #Wimp_Pointer_pos + OS_Coord_y]

		LDR	lr, [r11, #Wimp_Pointer_i]
		CMP	lr, #-2
		BGT	exit$l				; only filter on -ve icons

		BL	ClickFilterMenu
		BNE	exit$l

		MOV	lr, #1
		STR	lr, InterceptMouseButtons
intercept$l
		MOV	lr, #0
		STRSP	lr, r2				; show no mouse buttons down

exit$l		UNSTACK
		LDMFD	sp!, {lr}			; intercept address
		ClearV
		MOV	pc, lr

error$l		UNSTACK_ERR
		LDMFD	sp!, {lr}			; intercept address
		SetV
		MOV	pc, lr


;*******************************************************************************
;----f- Director.s.Filter.ReadKeyModifiers
; Name
;   ReadKeyModifiers
;
; Purpose
;   This reads the key modifiers
;
; Entry
;   none
;
; Exit
;   r0 = 00000acs a = ALT, c = CTRL, s = SHIFT
;------
;*******************************************************************************


ReadKeyModifiers	ROUTINE	"r1-r3", EXPORT

		MOV	r3, #0				; no modifiers

		MOV	r0, #OSByte_InKey
		MOV	r1, #0 :EOR: &FF		; shift
		MOV	r2, #&FF
		SWI	XOS_Byte
		BVS	end$l
		CMP	r2, #&FF
		ORREQ	r3, r3, #ShiftMod

		MOV	r0, #OSByte_InKey
		MOV	r1, #1 :EOR: &FF		; ctrl
		MOV	r2, #&FF
		SWI	XOS_Byte
		BVS	end$l
		CMP	r2, #&FF
		ORREQ	r3, r3, #CtrlMod

		MOV	r0, #OSByte_InKey
		MOV	r1, #2 :EOR: &FF		; alt
		MOV	r2, #&FF
		SWI	XOS_Byte
		BVS	end$l
		CMP	r2, #&FF
		ORREQ	r3, r3, #AltMod

end$l		MOV	r0, r3
		EXIT


;*******************************************************************************
;----f- Director.s.Filter.ClickFilter
; Name
;   ClickFilter
;
; Purpose
;   Click Handler
;
; Entry
;   r0 = event reason code
;   r1  event block as returned from Wimp_Poll
;   r2 = task handle of task being returned to
;   wp = as setup
;
; Exit
;   r0 modified event code or -1 to claim the call
;------
;*******************************************************************************


ClickFilter	TEQ	r0, #Wimp_UserMessage
		TEQNE	r0, #Wimp_UserMessageRecorded
		BEQ	MemoriserFilter			; do the memoriser filter
		TEQ	r0, #Wimp_MouseClick
		BEQ	ClickFilter_
		TEQ	r0, r0				; end if not mouse click
		TEQ	pc, pc
		MOVNES	pc, lr				; 26-bit exit
		MOV	pc, lr				; 32-bit exit

ClickFilter_	ROUTINE	"r0-r11"

		LDR	r0, GiveOldMenu			; do we let this one though?
		CMP	r0, #0
		MOV	r0, #0
		STR	r0, GiveOldMenu			; but never again!
		BNE	exit$l

		MOV	r11, r1				; r11  Poll block (Wimp_Pointer)
		BL	ClickFilterMenu
		MOVEQ	r0, #-1
		STRSP	r0, r0, EQ			; set r0 <- -1 and claim

exit$l		TEQ	r0, r0
		TEQ	pc, pc
		EXITS	NE				; 26-bit exit
		ClearFlags				; 32-bit exit
		EXIT


;*******************************************************************************
;----f- Director.s.Filter.FilerFilter
; Name
;   FilerFilter
;
; Purpose
;   Filter Handler
;
; Entry
;   r0 = event reason code
;   r1  event block as returned from Wimp_Poll
;   r2 = task handle of task being returned to
;   wp = as setup
;
; Exit
;   r0 modified event code or -1 to claim the call
;------
;*******************************************************************************


FilerFilter	ROUTINE_SF	"r0-r11"
scratch$l	#	StringSize
mouseblock$l	#	Wimp_Pointer
messageblock$l	#	Wimp_MessageHeader
		END_SF

		LDR	lr, FilerFilterStatus
		CMP	lr, #0
		BNE	exit$l

		MOV	r11, r1				; r11  Poll block
		MOV	r10, r0				; r10 = event reason code

		ADR	r1, mouseblock$l
		SWI	XWimp_GetPointerInfo		; get position of pointer
		BVS	exit$l

		CMP	r10, #Wimp_MenuSelection
		BEQ	menu_selection$l
		CMP	r10, #Wimp_UserMessage
		CMPNE	r10, #Wimp_UserMessageRecorded
		BEQ	user_message$l
		CMP	r10, #Wimp_MouseClick
		BNE	exit$l

mouse_click$l	LDR	r0, [r11, #Wimp_Pointer_buttons]
		TST	r0, #Wimp_ClickMenu
		LDRNE	r0, [r11, #Wimp_Pointer_w]
		STRNE	r0, LastFilerMenu		; store last menu click from filer
		B	exit$l

user_message$l	LDR	r9, [r11, #Wimp_MessageHeader_action] ; r9  message type
		CMP	r9, #Message_FilerOpenDir
		ADDEQ	r8, r11, #Wimp_MessageHeader_data + Filer_MessageOpenDir_dir_name
		ADDNE	r8, r11, #Wimp_MessageHeader_data + Filer_MessageOpenDirAt_dir_name ; r8  directory name
		LDRNE	lr, =Message_FilerOpenDirAt
		CMPNE	r9, lr
		BNE	exit$l				; only OpenDir or OpenDirAt

		LDR	r0, FilerFilterKeys
		CMP	r0, #0
;		BEQ	no_keys$l
		BLNE	ReadKeyModifiers
		BNE	exit$l

no_keys$l	LDR	r0, LastPressedButtons		; did the user click adjust?
		TST	r0, #Wimp_ClickAdjust
		BEQ	exit$l				; if not end

		LDR	r2, mouseblock$l + Wimp_Pointer_w
		CMP	r2, #Wimp_IconBar
		BNE	exit$l				; end if not over iconbar

		LDR	r3, mouseblock$l + Wimp_Pointer_i
		CMP	r3, #Wimp_Background
		BEQ	exit$l				; end if over the background of the icon bar

;		MOV	r0, #16				; set up message block
;		STR	r0, messageblock$l + Wimp_MessageHeader_size
;;		MOV	r0,
;
;		MOV	r0, #Wimp_UserMessageAcknowledge ; r0 = 19
;		ADR	r1, messageblock$l
;							; r2 = iconbar window handle
;							; r3 = icon handle
;		SWI	Wimp_SendMessage		; get task handle
;
;		MOV	r0, r2				; r0 = task handle
;		SWI	TaskManager_TaskNameFromHandle
;
;		ADR	r1, filer$l
;		BL	strcmpi				; Is it the Filer?
;		BNE	exit$l

		ADR	r0, mouseblock$l
		ADR	r1, path$l
		MOV	r2, r8
		BL	SendOpenMenu			; send a message to open the menu (ignore errors)

		MOV	r0, r10				; type
		MOV	r1, r11				; message
		BL	Ack_				; ack the message if it was recorded (ignore errors)

		B	intercept$l


filer$l		DCB	"Filer", 0
		ALIGN

menu_selection$l
		LDMIA	r11, {r0, r1}			; get menu selection items
		TEQ	r0, #1
		CMPEQ	r1, #-1
		BNE	exit$l				; make sure it is correct entry

		LDR	r0, mouseblock$l + Wimp_Pointer_w
		LDR	r1, mouseblock$l + Wimp_Pointer_i
		STR	r0, scratch$l + Wimp_IconState_w
		STR	r1, scratch$l + Wimp_IconState_i
		ADR	r1, scratch$l
		SWI	XWimp_GetIconState		; get state of icon
		BVS	exit$l

		LDR	r0, scratch$l + Wimp_IconState_icon + Wimp_Icon_flags
		TST	r0, #Wimp_IconIndirected
		BEQ	exit$l				; exit if icon not indirected

		LDR	r8, scratch$l + Wimp_IconState_icon + Wimp_Icon_data + Wimp_IconData_indirected_text_text	;r8  leaf

		MOV	r0, r8
		ADR	r1, scratch$l
		MOV	r8, r1				; r8 point to new string
		BL	strcpy				; copy the string
		MOV	r0, r8
		BL	strlen
		CMP	r0, #3
		BLT	exit$l				; if < 3 chars there is no point
		ADD	r9, r8, r0			; r9  terminator
		LDRB	r0, [r9, #-1]!
		CMP	r0, #"'"
		BNE	exit$l				; end if last character not '
		MOV	r0, #0
		STRB	r0, [r9]			; null terminate leaf

loop$l		CMP	r9, r8
		BLT	exit$l				; if current < start then end
		LDRB	r0, [r9, #-1]!
		CMP	r0, #"'"
		BNE	loop$l
		ADD	r8, r9, #1			; r8  leaf

		ADR	r0, leaf$l			; r0  name
		MOV	r1, r8				; r1  value
		MOV	r4, #OS_VartypeLiteralString
		BL	SetVarVal			; set the system variable
		BVS	exit$l

		LDR	r0, LastFilerMenu
		STR	r0, mouseblock$l + Wimp_Pointer_w ; origin window for filer click

		ADR	r0, mouseblock$l
		ADR	r1, menu$l
		MOV	r2, #0
		BL	SendOpenMenu			; send a message to open the menu (ignore errors)

		MOV	r1, #-1
		SWI	XWimp_CreateMenu		; clear the menu from the screen

intercept$l	MOV	r0, #-1
		STRSP	r0, r0				; set r0 <- -1 and claim

exit$l		TEQ	r0, r0
		TEQ	pc, pc
		EXITS	NE				; 26-bit exit
		ClearFlags				; 32-bit exit
		EXIT

path$l		DCB	"Path:", 0
menu$l		DCB	"MenuMenu:", 0
leaf$l		DCB	"Leaf", 0
		ALIGN


;*******************************************************************************
;----f- Director.s.Filter.Star_DirectorFilter
; Name
;   Star_DirectorFilter
;
; Purpose
;   This installs or removes a filter
;
; Entry
;   r0  command
;
; Exit
;
;------
;*******************************************************************************


Help_$Name.Filter	FOREXPORT
		[	OSVersion = 310
		DCB	"This installs or removes a filter.", 13
		|
		DCB	"Help_DirectorFilter", 0
		]

Syntax_$Name.Filter	FOREXPORT
		[	OSVersion = 310
		DCB	"Syntax: *$Name.Filter <name> <task> <menu> [-icon <n>] "
		DCB	"[-select] [-menu] [-adjust] [-shift] [-ctrl] [-alt] [-remove]", 0
		|
		DCB	"Syntax_DirectorFilter", 0
		]
		ALIGN

Args_$Name.Filter	DCB	"/G/A,/G,/G,icon/E,select/S,menu/S,adjust/S,shift/S,ctrl/S,alt/S,remove/S", 0
		ALIGN

Star_$Name.Filter	FOREXPORT
		LDR	wp, [r12]
Do$Name.Filter	SaveRegs
		ROUTINE_SF	NONE
scratch$l	#	0
arg_name$l	#	4
arg_task$l	#	4
arg_command$l	#	4
arg_icon$l	#	4
arg_select$l	#	4
arg_menu$l	#	4
arg_adjust$l	#	4
arg_shift$l	#	4
arg_ctrl$l	#	4
arg_alt$l	#	4
arg_remove$l	#	4
space$l		#	scratch_size - :INDEX: @
		END_SF

		MOV	r1, r0
		ADR	r0, Args_$Name.Filter
		ADR	r2, scratch$l
		MOV	r3, #scratch_size
		SWI	XOS_ReadArgs
		BVS	ErrorReturn

		LDR	r0, arg_name$l
		BL	sort_out_gstrans
		LDR	r0, arg_task$l
		BL	sort_out_gstrans
		LDR	r0, arg_command$l
		BL	sort_out_gstrans

		LDR	r0, arg_icon$l
		CMP	r0, #0
		MOVEQ	r3, #&80000000			; r0 = 0 => no icon
		BEQ	noicon$l
		BL	read_eval
		MOV	r3, r0				; r3 = icon (&80000000 = none)
noicon$l

		MOV	r4, #0				; r4 = flags

		LDR	lr, arg_select$l
		TEQ	lr, #0
		ORRNE	r4, r4, #1<<2

		LDR	lr, arg_menu$l
		TEQ	lr, #0
		ORRNE	r4, r4, #1<<1

		LDR	lr, arg_adjust$l
		TEQ	lr, #0
		ORRNE	r4, r4, #1<<0

		LDR	lr, arg_shift$l
		TEQ	lr, #0
		ORRNE	r4, r4, #1<<3

		LDR	lr, arg_ctrl$l
		TEQ	lr, #0
		ORRNE	r4, r4, #1<<4

		LDR	lr, arg_alt$l
		TEQ	lr, #0
		ORRNE	r4, r4, #1<<5

		LDR	r0, arg_name$l			; r0  filter name
		LDR	r1, arg_task$l			; r1  task name to filter (0 for delete)
		LDR	lr, arg_remove$l
		TEQ	lr, #0
		MOVNE	r1, #0				; remove if -remove is set
		LDR	r2, arg_command$l		; r2  command to run

		BL	FilterBlockCreate
		BVS	ErrorReturn

		B	NormalReturn


;*******************************************************************************
;----f- Director.s.Filter.Star_DirectorFilerFilter
; Name
;   Star_DirectorFilerFilter
;
; Purpose
;
;
; Entry
;   r0  command
;
; Exit
;   none
;------
;*******************************************************************************


Help_$Name.FilerFilter	FOREXPORT
	[	OSVersion = 310
		DCB	"Set Director's FilerFilter configuration.", 13
	|
		DCB	"Help_DirectorFilerFilter", 0
	]

Syntax_$Name.FilerFilter	FOREXPORT
	[	OSVersion = 310
		DCB	"Syntax: *$Name.FilerFilter <On|Off|1|0|Yes|No|Y|N> [-alt] [-ctrl] [-shift]", 13, 10
		DCB	"[-fs <fses>]", 0
	|
		DCB	"Syntax_DirectorFilerFilter", 0
	]
		ALIGN

Args_$Name.FilerFilter
		DCB	"/G,alt/S,ctrl/S,shift/S,fs/G", 0
		ALIGN

Star_$Name.FilerFilter	FOREXPORT
		LDR	wp, [r12]
Do$Name.FilerFilter	SaveRegs

		ROUTINE_SF	NONE
scratch$l	#	0
arg_status$l	#	4
arg_alt$l	#	4
arg_ctrl$l	#	4
arg_shift$l	#	4
arg_fses$l	#	4
space$l		#	scratch_size - :INDEX: @
		END_SF

		MOV	r1, r0
		ADR	r0, Args_$Name.FilerFilter
		ADR	r2, scratch$l
		MOV	r3, #scratch_size
		SWI	XOS_ReadArgs
		BVS	ErrorReturn

		LDR	r0, arg_status$l
		BL	sort_out_gstrans
;		LDR	r0, arg_alt$l
;		BL	sort_out_gstrans
;		LDR	r0, arg_ctrl$l
;		BL	sort_out_gstrans
;		LDR	r0, arg_shift$l
;		BL	sort_out_gstrans
		LDR	r0, arg_fses$l
		BL	sort_out_gstrans

		; status
		LDR	r0, arg_status$l
		BL	OnOrOff
		BVS	ErrorReturn
		EOR	r0, r0, #1
		STR	r0, FilerFilterStatus

		; keys
		MOV	r3, #0
		LDR	r0, arg_alt$l
		CMP	r0, #0
		ORRNE	r3, r3, #AltMod

		LDR	r1, arg_ctrl$l
		CMP	r1, #0
		ORRNE	r3, r3, #CtrlMod

		LDR	r2, arg_shift$l
		CMP	r2, #0
		ORRNE	r3, r3, #ShiftMod

		STR	r3, FilerFilterKeys

		; fses
		LDR	r0, arg_fses$l
		CMP	r0, #0
		BEQ	NormalReturn		; no value supplied so skip


		B	NormalReturn


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


		END
