#set WIMP_Version		= 300
#set WIMP_Poll_Mask		= %110001
#set Window_Info = 0
#set Window_Max = 0			;maximum windows ID in use
#set Menu_VPosition = 96+(44*5)		;vertical position of Filer menu

.Entry_start
 LDR     R12, [R12, #0]			;check if this is a 2nd instance
 TEQ     R12, #0			;Don't allow re-init
 SWIEQ   XOS_Exit			;PRM1-303

 ADD     R13, R12, #VARS.stack		;setup stack pointer

 BL      is_Wimp_active
 SWINE   XOS_Exit			;NO, exit

 MOV     R0, #WIMP_Version		;create WIMP task
 LDR     R1, WIMP_Task
 ADR     R2, WIMP_Task_Title
 ADR     R3, WIMP_Messages_Accepted
 SWI     XWimp_Initialise		;PRM3-85
 BVS     Exit_Module
 STR     R1, [R12, #VARS.wimp_taskhandle]	;store WIMP handle for later

 MOV     R0, #SpriteOp_ReadSpriteInfo	;get size of icon bar
 ADR     R2, WIMP_Icon_Name
 SWI     XWimp_SpriteOp			;PRM1-818

 MOV     R0, R6
 MOV     R1, #5				;ModeVariable_YEig
 SWIVC   XOS_ReadModeVariable		;PRM1-736
 BVS     Exit_Module

 MOV     R0, #20			;Maximum y of icon
 ADD     R5, R0, R4, LSL R2		;add sprite height to icon bounding box
 ADR     R8, WIMP_Icon_Validation	;update the pointer to our Icon validation string
 ADR     R0, WIMP_Icon_Block_init	;initialise the Icon block
 LDMIA   R0, {R1-R4, R6-R7, R9}
 ADD     R0, R12, #VARS.WIMP_Icon_Block
 STMIA   R0, {R1-R9}
					;read window templates
 ADR     R1, WIMP_Template_File		;load our template file
 SWI     XWimp_OpenTemplate		;PRM3-165
 BVS     Exit_Module
					;initiate registers for template load
 ADD     R9, R12, #VARS.window_handles
 ADD     R11, R12, #VARS.window_indirects
 ADD     R1, R12, #VARS.template_buffer
 ADD     R2, R12, #VARS.template_indirect_buffer
 ADD     R3, R2, #template_indirect_buffer_size
 MVN     R4, #0
 FNload_template Window_Info
 SWI     XWimp_CloseTemplate		;PRM3-166
 BL      fix_relative_addresses		;correct relative addresses
 BL      add_drive_icons		;add mounted drive icons

.poll_loop				;Main WIMP polling loop
 SWI     XOS_ReadMonotonicTime		;PRM1-446
 ADD     R2, R0, #1000			;poll every 10 seconds, or on event
 MOV     R0, #WIMP_Poll_Mask
 ADD     R1, R12, #VARS.WIMP_Poll_Block
 SWI     XWimp_PollIdle			;PRM3-181

 TEQ     R0, #1				;PRM3-116
 BEQ     WIMP_redraw_window		;redraw window

 TEQ     R0, #2				;PRM3-116
 BEQ     WIMP_open_window		;open window (eg drag action)

 TEQ     R0, #3				;PRM3-116
 BEQ     WIMP_close_window		;close window

 TEQ     R0, #9				;PRM3-120
 BEQ     WIMP_menu_selection		;menu selection

 TEQ     R0, #6				;PRM3-117
 BEQ     WIMP_mouse_click		;mouse click

 TEQ     R0, #17			;message?
 TEQNE   R0, #18
 BEQ     WIMP_user_message
B       poll_loop




;Open_Filer
;----------
;opens a filer windows for the drive

;Entry:
; R0 - drive number
; R12 - pointer to VARS
;
;Exit:
; R0 - corrupt

.Open_Filer
 STMFD   R13!, {R1-R5, R11, R14}

 LDR     R1, [R12, #VARS.wimp_taskhandle]
 TEQ     R1, #0				;is the Wimp task running
 LDMEQFD R13!, {R1-R5, R11, PC}

 BL      construct_wimp_message
 BL      wimp_context_start
 BL      broadcast_message
 BL      wimp_context_end
 SUBS    R0, R0, R0			;clear V
LDMFD   R13!, {R1-R5, R11, PC}




;broadcast_message
;-----------------
;broadcasts the message in the wimp_message buffer

.broadcast_message
 STMFD   R13!, {R14}
 MOV     R0, #WIMP_User_Message
 MOV     R2, #0				;broadcast message
 ADD     R1, R12, #VARS.wimp_message
 SWI     XWimp_SendMessage
LDMFD   R13!, {PC}




;Send_Add_Icon_Message
;---------------------
;send a message from the SVC side of the Module to the WIMP side to add
;a Filer icon for a drive

;Entry:
; VARS.wimp_message = message to send to our WIMP task

;Exit:
; R0 - corrupted

.Send_Add_Icon_Message
 STMFD   R13!, {R1-R5, R11, R14}
 LDR     R2, [R12, #VARS.wimp_taskhandle]	;send to us
 TEQ     R2, #0					;is the Wimp task running
 LDMEQFD R13!, {R1-R5, R11, PC}			;NO
 
 MOV     R0, #WIMP_User_Message
 ADD     R1, R12, #VARS.wimp_message
 SWI     XWimp_SendMessage
 LDMVCFD R13!, {R1-R5, R11, PC}
					;if we got here, might be non-WIMP
 BL      wimp_context_start
 MOV     R0, #WIMP_User_Message
 SWI     XWimp_SendMessage
 BL      wimp_context_end
LDMFD   R13!, {R1-R5, R11, PC}




;Add_Icon_from_Message
;---------------------
;adds an icon for the drive being mounted

;Entry:
; R1 - pointer to User_Message block
; R12 - pointer to VARS

.Add_Icon_from_Message
 LDR     R2, [R12, #VARS.wimp_taskhandle]
 LDR     R0, [R1, #User_Message.your_ref]
 EOR     R0, R0, R2, LSL #8		;validation, will be <8 if valid
 CMP     R0, #8				;are we requesting a icon?
 BLLO    add_icon_directly		;YES
B       poll_loop




;add_icon_directly
;-----------------
;adds a drive icon to the Icon bar

; Entry:
; R0 - drive #
; R12 - pointer to VARS

.add_icon_directly
 STMFD   R13!, {R0-R5, R14}
 ADD     R5, R12, #VARS.drive_info
 ADD     R5, R5, R0, LSL #Drive_struct	;R5=pointer to Drive struct
 LDR     R0, [R5, #Drive.size]
 TEQ     R0, #0				;is the drive mounted?
 LDMEQFD R13!, {R0-R5, PC}		;NO

 ADD     R2, R5, #Drive.name		;update the pointer to our Icon text
 MOV     R3, R2
 ._L1
   LDRB     R0, [R3], #1
   CMP      R0, #32
 BHI     _L1
 SUB     R3, R3, R2			;R3=length of string

 ADD     R1, R12, #VARS.WIMP_Icon_Block
 MOV     R0, #&70000000			;create an icon on the icon bar
 STR     R2, [R1, #WIMP_Taskbar_Icon.text]
 STR     R3, [R1, #WIMP_Taskbar_Icon.text_length]
 SWI     XWimp_CreateIcon		;PRM3-93
 STRVC   R0, [R5, #Drive.icon_handle]
 SUBS    R0, R0, R0			;clear V
LDMFD   R13!, {R0-R5, PC}




;add_drive_icons
;---------------
;adds drive icons for all mounted drives to the icon bar

; Entry:
; R12 - pointer to VARS

.add_drive_icons
 STMFD   R13!, {R0, R14}

 MOV     R0, #0
 ._L1
   BL      add_icon_directly
   ADD     R0, R0, #1
   TEQ     R0, #8
 BNE     _L1
LDMFD   R13!, {R0, PC}




;is_Wimp_active
;--------------
;EQ if Wimp is active

.is_Wimp_active
 STMFD   R13!, {R0, R14}
 MOV     R0, #WimpSysInfo_ActiveTasks
 SWI     XWimp_ReadSysInfo		;PRM3-216
 CMP     R0, #0				;is WIMP active?
 MOVHI   R0, #1
 EORS    R0, R0, #1
LDMFD   R13!, {R0, PC}




;Remove_Icon
;-----------
;removes an icon from the taskbar

;Entry:
; R0 - icon handle
; R12 - pointer to VARS

.Remove_Icon
 STMFD   R13!, {R1-R2, R14}

 BL      is_Wimp_active			;are we in the Wimp?
 LDMNEFD R13!, {R1-R2, PC}		;NO

 ADD     R1, R12, #VARS.wimp_message
 STR     R0, [R1, #4]
 MOV     R0, #Iconbar_Window_Handle
 STR     R0, [R1, #0]
 SWI     XWimp_DeleteIcon
LDMVCFD R13!, {R1-R2, PC}
					;if we got here, might be non-WIMP
 BL      wimp_context_start
 SWI     XWimp_DeleteIcon
 BL      wimp_context_end
LDMFD   R13!, {R1-R2, PC}




.wimp_context_start
 STMFD   R13!, {R0-R3, R14}
 MOV     R0, #200			;create a temp WIMP task
 LDR     R1, WIMP_Task
 ADR     R2, _temp_task
 SWI     XWimp_Initialise		;PRM3-85
 MOV     R11, R1
LDMFD   R13!, {R0-R3, PC}

 ._temp_task DCB "HDFFS Filer Temp", 0
 ALIGN

.wimp_context_end
 STMFD   R13!, {R0-R3, R14}
 LDR     R1, WIMP_Task
 MOV     R0, R11
 SWI     XWimp_CloseDown
LDMFD   R13!, {R0-R3, PC}




;Entry:
; R0 - drive number
; R12 - pointer to VARS

.construct_wimp_message
 STMFD   R13!, {R0-R5, R14}
 ADD     R5, R0, #ASC("0")		;R5=drive number

 ADD     R1, R12, #VARS.wimp_message
 MOV     R0, #0				;don't add a drive icon
 STR     R0, [R1, #User_Message.your_ref]
 MOV     R0, #64
 STR     R0, [R1, #User_Message.length]	;message length
 MOV     R0, #WIMP_Message_FilerOpenDir
 STR     R0, [R1, #User_Message.message_code]
 LDRB    R0, FS_Create_Block + 3	;Filing system number
 STR     R0, [R1, #User_Message.filing_system]
 MOV     R0, #0
 STR     R0, [R1, #User_Message.my_ref]
 STR     R0, [R1, #User_Message.flags]

 ADR     R2, Drive_Path
 ADD     R3, R1, #User_Message.directory
 ._L1
   LDRB    R0, [R2], #1
   TEQ     R0, #1
   MOVEQ   R0, R5			;drive number
   STRB    R0, [R3], #1
   TEQ     R0, #0
 BNE     _L1

 MOV     R0, #37			;Canonicalise path
 ADD     R1, R1, #User_Message.directory	;pointer to "HDFFS::x.$"
 MOV     R3, #0
 MOV     R4, #0
 MOV     R2, R1				;use the same buffer for result
 MOV     R5, #User_Message.size - User_Message.directory	;size of buffer
 SWI     XOS_FSControl
LDMFD   R13!, {R0-R5, PC}




;Entry:
; R1 - pointer to HDFFS::<discname>
; R12 - pointer to VARS

.construct_wimp_message_from_name
 STMFD   R13!, {R0-R5, R14}
 MOV     R2, R1

 ADD     R1, R12, #VARS.wimp_message
 MOV     R0, #64
 STR     R0, [R1, #User_Message.length]		;message length
 MOV     R0, #WIMP_Message_FilerOpenDir
 STR     R0, [R1, #User_Message.message_code]
 LDRB    R0, FS_Create_Block + 3		;Filing system number
 STR     R0, [R1, #User_Message.filing_system]
 MVN     R0, #0					;don't create an icon
 STR     R0, [R1, #User_Message.my_ref]
 STR     R0, [R1, #User_Message.your_ref]
 STR     R0, [R1, #User_Message.flags]

 ADD     R3, R1, #User_Message.directory
 ._L1
   LDRB    R0, [R2], #1
   STRB    R0, [R3], #1
   TEQ     R0, #0
 BNE     _L1

 MOV     R0, #ASC(".")
 STRB    R0, [R3, #-1]
 MOV     R0, #ASC("$")
 STRB    R0, [R3, #0]
 MOV     R0, #0
 STRB    R0, [R3, #1]
LDMFD   R13!, {R0-R5, PC}




;WIMP_redraw_window
;------------------
;WIMP issued a redraw window request

.WIMP_redraw_window
 SWI     XWimp_RedrawWindow		;PRM3-126
B       poll_loop




;WIMP_open_window
;----------------
;WIMP issued an open window request

.WIMP_open_window
 SWI     XWimp_OpenWindow		;PRM3-109
B       poll_loop




;WIMP_close_window
;-----------------
;WIMP issued a close window request

.WIMP_close_window
 SWI     XWimp_CloseWindow		;PRM3-111
B       poll_loop




;WIMP_menu_select
;----------------
;WIMP notify a menu select has occured
;
;Entry:
; R1 - pointer to WIMP block (PRM3-120)

.WIMP_menu_selection
 LDR     R0, [R1, #0]			;menu entry pressed
 LDR     R2, [R1, #4]			;submenu entry pressed

 LDR     R8, [R12, #VARS.current_drive]	;R8=Drive struct menu was opened for
 TEQ     R0, #1				;Name disc
 TEQEQ   R2, #0
 BEQ     Menu_Selected_Namedisc
 TEQ     R0, #2				;Dismount
 BEQ     Menu_Selected_Dismount
 TEQ     R0, #3				;Free
 BEQ     Menu_Selected_Free
 TEQ     R0, #4				;Eject
 BEQ     Menu_Selected_Eject
B       poll_loop


.Menu_Selected_Namedisc
 MOV     R0, R8
 BL      construct_wimp_message
 ADD     R1, R12, #VARS.wimp_message
 MOV     R0, #WIMP_Message_FilerCloseDir
 STR     R0, [R1, #User_Message.message_code]
 BL      broadcast_message

 LDR     R1, [R12, #VARS.menu_main]	;our menu block, also "HDFFS::n"
 LDR     R2, [R1, #28 + (24 * 1) + Menu_Item.submenu]	;R8=namedisc submenu pointer
 LDR     R2, [R2, #28 + Menu_Item.text]	;R2=pointer to new disc name

 ADD     R5, R12, #VARS.drive_info
 ADD     R5, R5, R8, LSL #Drive_struct	;R5=pointer to Drive struct

 MOV     R0, #50
 SWI     XOS_FSControl			;PRM2-135

 ADD     R1, R5, #Drive.name
 ._L1					;update our copy of the discname
   LDRB    R0, [R2], #1
   STRB    R0, [R1], #1
   TEQ     R0, #0
 BNE     _L1

 MOV     R0, R8
 SWI     XHDFFS_Remount
B       poll_loop


.Menu_Selected_Dismount
 MOV    R0, R8				;R0=drive #
 BL     internal_dismount
B       poll_loop


.Menu_Selected_Eject
 MOV    R0, R8				;R0=drive #
 BL     internal_eject
B       poll_loop


.Menu_Selected_Free
 MOV     R3, R1				;R3=buffer for *command
 ADR     R2, ShowFree
 ._L1
   LDRB    R0, [R2], #1
   STRB    R0, [R3], #1
   TEQ     R0, #0
 BNE     _L1

 ADD     R0, R8, #ASC("0")
 STRB    R0, [R3, #-2]
 MOV     R0, R1
 SWI     XOS_CLI			;*ShowFree -FS HDFFS n
B       poll_loop




;WIMP_mouse_click
;----------------
;WIMP detected a mouse click, we have to figure out which
;window / menu it was on and what to do.
;
;Entry:
; R1 + 12 - window handle

.WIMP_mouse_click
 ADD     R9, R12, #VARS.window_handles
 LDR     R0, [R1, #12]			;get the window handle

 LDR     R2, [R9, #Window_Info << 2]
 TEQ     R0, R2				;Info window
 BEQ     poll_loop
					;if we got here, it's a menu
 LDR     R0, [R1, #8]			;which button
 TST     R0, #%010			;select or adjust?
 BNE     display_menu			;NO, menu button then

 ADD     R1, R1, #12			;R1=pointer to IconState block
 SWI     XWimp_GetIconState
 LDR     R2, [R1, #8 + WIMP_Icon.text]	;R2=pointer to icon text
 LDR     R3, [R1, #8 + WIMP_Icon.text_length]
 ADD     R3, R3, R2			;R3=pointer to icon text end

 BL      build_discname_from_icon
 BL      construct_wimp_message_from_name
 BL      broadcast_message
B       poll_loop




;WIMP_user_message
;-----------------
;WIMP issued a message, PRM3-124
;
;Entry:
; R1 + 0  - size of block in bytes
; R1 + 4  - task handle of message sender
; R1 + 8  - my_ref - the senders reference
; R1 + 12 - your_ref - set to my_ref on return, or 0 if not replying
; R1 + 16 - Message action code
; R1 + 20 - message data

.WIMP_user_message
 LDR     R0, [R1, #User_Message.message_code]

 TEQ     R0, #WIMP_Message_Quit
 BEQ     WIMP_exit			;WIMP requested end process

 TEQ     R0, #WIMP_Message_FilerOpenDir
 BEQ     Add_Icon_from_Message		;YES
B       poll_loop




;WIMP_exit
;---------
;Exit cleanly when the desktop shuts down

.WIMP_exit
 BL      WIMP_closedown
SWI   XOS_Exit




.WIMP_closedown
 STMFD   R13!, {R0-R1, R14}
 LDR     R0, [R12, #VARS.wimp_taskhandle]	;is the filer running?
 TEQ     R0, #0
 LDMEQFD R13!, {R0-R1, PC}			;NO

 LDR     R1, WIMP_Task				;yes, close it down
 SWI     XWimp_CloseDown			;PRM3-172

 SUBS    R0, R0, R0				;clear V
 STR     R0, [R12, #VARS.wimp_taskhandle]
LDMFD   R13!, {R0-R1, PC}




;display_menu
;------------
;Displays the main menu
;
;Entry:
; R1 - pointer to WIMP block (PRM3-112)

.display_menu
 LDR     R2, [R1, #0]			;mouse x
 SUB     R10, R2, #64			;move menu left

 ADD     R1, R1, #12			;R1=pointer to IconState block
 SWI     XWimp_GetIconState
 LDR     R2, [R1, #8 + WIMP_Icon.text]	;R2=pointer to icon text

 SUB     R9, R2, #Drive.name		;R9=pointer to Drive struct
 ADD     R1, R12, #VARS.drive_info
 SUB     R0, R9, R1
 MOV     R0, R0, LSR #Drive_struct	;R0=drive #
 STR     R0, [R12, #VARS.current_drive]

 ADD     R0, R0, #ASC("0")
 MOV     R3, #Menu_VPosition		;fixed y
 MOV     R2, R10
 LDR     R1, [R12, #VARS.menu_main]	;our menu block
 STRB    R0, [R1, #LEN("HDFFS::")]	;change the menu title to HDFFS::n

 LDR     R8, [R1, #28 + (24 * 1) + Menu_Item.submenu]	;R8=namedisc submenu pointer
 LDR     R5, [R8, #28 + Menu_Item.text]	;R2=pointer to new disc name

 ADD     R7, R9, #Drive.name
 MOV     R6, #10
 ._L1
   LDRB    R0, [R7], #1
   STRB    R0, [R5], #1
   SUBS    R6, R6, #1
 BNE     _L1

 SWI     XWimp_CreateMenu		;PRM3-153
B       poll_loop




;Exit_Module
;-----------
;Close down WIMP task and exit to the OS
;
;Entry:
; R10 - error if V set

.Exit_Module
 MOVVC   R10, #0
 MOVVS   R10, R0			;V is set it we were passed an error

ADD R0, R10, #4
SWIVS OS_Write0
 BL      WIMP_closedown

 MOVS    R0, R10			;report any errors
 MOVNE   R1, #&58454241
 MOVEQ   R1, #0
 MOV     R2, #1
 ADR     R3, HDFFS_Title
SWI     OS_ExitAndDie			;PRM1-323




;convert the relative address to fixed addresses
;Exit:
; R0-R4 corrupt

.fix_relative_addresses
 ADR     R0, address_fixlist		;the list of address to switch from relative to fixed
 MOV     R1, R0				;our code base
 ADD     R4, R12, #VARS.window_handles	;list of window handles
 SUB     R4, R4, #1 << 2		;the window ID is offset by 1

 ._loop
   LDMIA   R0!, {R2, R3}		;load the address pair
					;R2 is the offset from code base, to update
					;R3 is the relative address to store there
   CMP     R3, #0			;if R3 is 0, we've hit the end of the list
   BEQ     _exit			;exit if we hit the end of the list

   ADDPL   R3, R3, R1			;if its +, its an address within menu block
   RSBMI   R3, R3, #0			;if its -, its a window pointer
   LDRMI   R3, [R4, R3, LSL #2]		;...load the window handle

   STR     R3, [R1, R2]			;store the fixed address
 B       _loop

 ._exit
 STR     R0, [R12, #VARS.menu_main]	;update pointer to main menu
MOV     PC, R14




; load_template
; -------------
; Loads a template window
;
; Entry:
;   R1-R4, R9, R11 must be initiated
;   R9  - Window handle table
;   R11 - Indirected data workspace
; Exit:
;   R0 - Window ID
;   R1 - preserved
;   R2 - pointer to next free indirect memory location
;   R3 - preserved
;   R4 - preserved
;   R5 - pointer to actual window name
;   R6 - pointer to next entry in Template file

MACRO FNload_template window_ID:I
{
  STR     R2, [R11, #window_ID << 2]	;store the indirected data address
  MOV     R6, #window_ID + ASC("0")
  STR     R6, [R13, #-12]!
  MOV     R6, #0			;position to search from in template
  STR     R6, [R13, #4]
  STR     R6, [R13, #8]
  MOV     R5, R13			;window name to load
  SWI     XWimp_LoadTemplate		;PRM3-167
  ADD     R13, R13, #12			;drop name from stack

  SWIVC   XWimp_CreateWindow		;PRM3-87
  BVS     Exit_Module
  STR     R0, [R9, #window_ID << 2]	;store the window handle
}




; open_window
; -----------
; Open a window
;
; Entry:
;   Window ID

MACRO FNopen_window window_ID:I
{
  ADD     R1, R12, #VARS.window_handles	;get our handle list
  LDR     R0, [R1, #window_ID << 2]	;load the Wimp window handle

  ADD     R1, R12, #VARS.open_window_block	;get the window block
  STR     R0, [R1]			;store the id we want

  SWI     XWimp_GetWindowState		;PRM3-132
  SWI     XWimp_OpenWindow		;PRM3-109
}