;
; checksd.s
;
; Ask for confirmation on shutdowns
;
;  1995 Straylight
;

;----- Licensing note -------------------------------------------------------
;
; CheckSD 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, or (at your option)
; any later version.
;
; CheckSD 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 CheckSD.  If not, write to the Free Software Foundation,
; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

;----- Standard header ------------------------------------------------------

		GET	libs:header
		GET	libs:swis

		GET	libs:stream

;----- External dependencies ------------------------------------------------

		GET	libs:embTemp.sh.embTemp

		IMPORT	tpl_warning

		IMPORT	|Image$$RW$$Limit|

;----- Main code ------------------------------------------------------------

		AREA	|Asm$$Code|,CODE,READONLY
		ENTRY

; --- main ---
;
; On entry:	--
;
; On exit:	Via OS_Exit
;
; Use:		Initialise the application.

main		ROUT

		BL	cs_init			;Initialise low-level things
		BL	cs_initWimp		;Initialise WIMPy things
		BL	cs_poll			;Enter the poll loop
		SWI	OS_Exit			;And return when done

		LTORG

; --- cs_init ---
;
; On entry:	--
;
; On exit:	R12 == pointer to workspace
;		R13 == stack pointer
;		Other registers corrupted
;
; Use:		Initialises workspace etc.

cs_init		ROUT

		MOV	R0,#4096		;Only need a 4K wimpslot
		MOV	R1,#-1			;Don't change next slot
		SWI	Wimp_SlotSize		;Change my slot, please

		SWI	OS_GetEnv		;Find the memory limit
		MOV	R13,R1			;Put stack at the top
		LDR	R12,=|Image$$RW$$Limit|	;Put workspace at end
		ADD	R0,R12,#cs_wSize	;Add on the workspace size
		CMP	R0,R13			;Do we have enough space?
		MOVCCS	PC,R14			;Yes -- then return to caller

		ADR	R0,cs_noMem		;Point to error message
		SWI	OS_GenerateError	;Raise the error

cs_noMem	DCD	1
		DCB	"Not enough memory for CheckSD to start up",0

; --- cs_initWimp ---
;
; On entry:	--
;
; On exit:	R0-R11 corrupted
;
; Use:		Initialises various WIMPy things.

cs_initWimp	ROUT

		STMFD	R13!,{R14}		;Save return address

		MOV	R0,#200			;RISC OS 2 will do for me
		LDR	R1,=&4B534154		;Get magic WIMP number
		ADR	R2,cs_appName		;Point to application name
		SWI	Wimp_Initialise		;Initialise the WIMP then

		ADRL	R0,tpl_warning		;Find the template
		ADR	R1,cs_pollBlock		;Write window to poll block
		ADR	R2,cs_indBase		;Point to indirect buffer
		ADR	R3,cs_indLimit		;Point to limit of this
		MOV	R4,#1			;Use the Wimp sprite area
		MOV	R5,#1			;For everything, please
		BL	embTemp_extract		;Extract the file
		SWI	Wimp_CreateWindow	;Create the window
		STR	R0,cs_warning		;Save the window handle

		LDMFD	R13!,{PC}^		;Now return to caller

cs_appName	DCB	"CheckShutdowns",0

		LTORG

; --- cs_poll ---
;
; On entry:	--
;
; On exit:	R0-R11 corrupted
;
; Use:		Does the main polling job.

cs_poll		ROUT

		STMFD	R13!,{R14}		;Save return address
00		MOV	R0,#1			;Don't give me null events
		ADR	R1,cs_pollBlock		;Point to my poll block
		SWI	Wimp_Poll		;Get an event, please
		ADR	R14,%b00		;Set up a return address
		CMP	R0,#1			;Is it a redraw event?
		BEQ	cs_redraw		;Yes (weird)
		CMP	R0,#17			;Is this a message?
		CMPNE	R0,#18			;Check both types
		BEQ	cs_message		;Yes -- handle that then
		MOVS	PC,R14			;And loop back round again

		LTORG

; --- cs_redraw ---
;
; On entry:	R1 == pointer to window handle
;
; On exit:	--
;
; Use:		Redraws a window the only way we can.

cs_redraw	ROUT

		STMFD	R13!,{R0,R14}		;Save some registers
		SWI	Wimp_RedrawWindow	;Start a redraw job
		CMP	R0,#0			;Have we finished yet?
00		SWINE	XSculptrix_RedrawWindow	;No -- do 3D bits then
		SWINE	Wimp_GetRectangle	;And get another rectangle
		CMPNE	R0,#0			;Finished now?
		BNE	%b00			;No -- keep looping
		LDMFD	R13!,{R0,PC}^		;And return to caller

		LTORG

; --- cs_message ---
;
; On entry:	R1 == pointer to message block
;
; On exit:	R0-R11 corrupted
;
; Use:		Handles messages

cs_message	ROUT

		LDR	R0,[R1,#16]		;Load the message type
		CMP	R0,#0			;Is this a quit?
		LDMEQFD	R13!,{PC}^		;Yes -- then stop right now
		CMP	R0,#8			;Is this a pre-quit?
		MOVNES	PC,R14			;No -- ignore it then
		LDR	R0,[R1,#0]		;Load the message size
		CMP	R0,#20			;Is this the old size?
		LDRNE	R0,[R1,#20]		;No -- load the flags word
		TSTNE	R0,#1			;Test the flag bit
		MOVNES	PC,R14			;And return if not shutdown

		STMFD	R13!,{R14}		;Save a register
		SUB	R13,R13,#48		;Drop stack pointer further
		LDR	R0,cs_warning		;Load the window handle
		STR	R0,[R13,#0]		;Store it away
		MOV	R1,R13			;Point to it there
		SWI	Wimp_GetWindowState	;Find the window size
		LDMIB	R1,{R2-R5}		;Load them out
		SUB	R13,R13,#16		;Make space on the stack
		ADR	R0,cs_vduvars		;Point to VDU variables
		MOV	R1,R13			;Output on the stack
		SWI	OS_ReadVduVariables	;Read them then
		LDMIA	R13!,{R6-R9}		;Load them
		ADD	R8,R8,#1		;Find the screen width
		ADD	R9,R9,#1		;And its height
		MOV	R8,R8,LSL R6		;Work out widht in OS units
		MOV	R9,R9,LSL R7		;And the height too
		SUB	R4,R4,R2		;Find the window width
		SUB	R5,R5,R3		;And its height
		SUB	R2,R8,R4		;Find centre position
		SUB	R3,R9,R5		;Vertically too
		MOV	R2,R2,LSR #1		;And work out the positions
		MOV	R3,R3,LSR #1		;To centre on the screen
		ADD	R4,R2,R4		;Get the limit coords too now
		ADD	R5,R3,R5		;So we can store them back
		MOV	R1,R13			;Point to the poll block
		STMIB	R1,{R2-R5}		;Save all of them away
		SWI	Wimp_OpenWindow		;Display it on the screen

		; --- Constrain the mouse pointer ---

		MOV	R14,#1			;A word to shift about
		SUB	R2,R2,R14,LSL R6	;Knock pixel of left side
		SUB	R3,R3,R14,LSL R7	;And off the top
		BL	cs_constrain		;Constrain mouse here

		BL	cs_beep			;Maybe make a noise
		BL	cs_redraw		;Force it to redraw

		; --- Work out position of buttons ---

		ADD	R14,R1,#20		;Point to scroll offsets
		LDMIA	R14,{R10,R11}		;Load them
		SUB	R10,R2,R10		;Find the x origin position
		SUB	R11,R5,R11		;And the y origin position

		MOV	R14,#3			;Find default button
		STR	R14,[R1,#4]		;Store that in the block
		SWI	Wimp_GetIconState	;Read the icon block
		ADD	R14,R1,#8		;Point to the sizes
		LDMIA	R14,{R4-R7}		;Load them out
		ADD	R4,R4,R10		;Transform these
		ADD	R5,R5,R11
		ADD	R6,R6,R10
		ADD	R7,R7,R11

		MOV	R14,#4			;Find cancel button
		STR	R14,[R1,#4]		;Store that in the block
		SWI	Wimp_GetIconState	;Read the icon block
		ADD	R14,R1,#8		;Point to the sizes
		LDMIA	R14,{R0-R3}		;Load them out
		ADD	R8,R0,R10		;Transform these
		ADD	R9,R1,R11
		ADD	R10,R2,R10
		ADD	R11,R3,R11

		; --- Now enter a loop thing ---

		SWI	OS_Mouse		;Read the mouse state
		MOV	R14,R2			;Look after current state

05		SWI	OS_Mouse		;Read the mouse state
		BIC	R3,R2,R14		;Clear bits already set
		ANDS	R3,R3,#5		;Only look at sel and adj
		BEQ	%f00			;If no buttons, skip

		CMP	R0,R4			;Check for default button
		CMPCS	R1,R5
		CMPCS	R6,R0
		CMPHI	R7,R1
		MOVHI	R0,#3			;If so, get default
		BHI	%10cs_message		;And handle that

		CMP	R0,R8			;Check for cancel button
		CMPCS	R1,R9
		CMPCS	R10,R0
		CMPHI	R11,R1
		MOVHI	R0,#4			;If so, get cancel
		BHI	%10cs_message		;And handle that

		; --- Check for key presses ---

00		MOV	R14,R2			;Remember new current state
		MOV	R0,#129			;Read a keypress
		MOV	R1,#0			;Don't wait for it
		MOV	R2,#0			;Really don't
		SWI	OS_Byte			;Read that
		MOV	R0,#0			;Clear a word
		CMP	R1,#&0D			;Return pressed?
		EOREQ	R0,R0,#3 :EOR: 4	;Yes -- choose default
		CMPNE	R1,#&1B			;Or escape?
		EOREQ	R0,R0,#4		;Yes -- choose cancel
		BNE	%b05			;Otherwise loop

		; --- Choose a button ---

10cs_message	MOV	R11,R0			;Look after the icon
		SUB	R13,R13,#16		;Make a slab block
		MOV	R1,R0			;Get the icon handle
		LDR	R0,cs_warning		;Get the warning box
		MOV	R2,R13			;Point to slab block
		SWI	XSculptrix_SlabIcon	;Slab the icon
		ADR	R1,cs_warning		;Point to window handle
		SWI	Wimp_CloseWindow	;Take the window down
		SWI	XSculptrix_UnslabIcon	;And unslab the icon
		ADD	R13,R13,#16		;Reclaim the block

		; --- Unconstrain the mouse ---

		SUB	R13,R13,#16		;Make space on the stack
		ADR	R0,cs_vduvars		;Point to VDU variables
		MOV	R1,R13			;Output on the stack
		SWI	OS_ReadVduVariables	;Read them then
		LDMIA	R13!,{R2-R5}		;Load them
		MOV	R4,R4,LSL R2		;Work out widht in OS units
		MOV	R5,R5,LSL R3		;And the height too
		MOV	R2,#0			;Start at bottom left
		MOV	R3,#0			;Set both up
		BL	cs_constrain		;Set the rectangle

		; --- Now sort out what to do now ---

		CMP	R11,#4			;Cancel shutdown?
		BNE	%f00			;No -- skip onwards
		ADR	R1,cs_pollBlock		;Point to the poll block
		LDR	R14,[R1,#8]		;Load his ref
		STR	R14,[R1,#12]		;This is my ref
		LDR	R2,[R1,#4]		;Load his task handle
		MOV	R0,#19			;Ack the message
		SWI	Wimp_SendMessage	;Abort the shutdown

		; --- Now tidy up and return ---

00		ADD	R13,R13,#48		;Restore the stack
		LDMFD	R13!,{PC}^		;And return to caller

cs_vduvars	DCD	4,5,11,12,-1

		LTORG

; --- cs_constrain ---
;
; On entry:	R2-R5 == coordinates to constrain to
;
; On exit:	--
;
; Use:		Constrain the mouse to a rectangle.

cs_constrain	ROUT

		STMFD	R13!,{R0-R2,R14}	;Save some registers
		MOV	R0,#1			;Subreason code
		ORR	R0,R0,R2,LSL #8
		ORR	R0,R0,R3,LSL #24
		MOV	R1,R3,LSR #8
		ORR	R1,R1,R4,LSL #8
		ORR	R1,R1,R5,LSL #24
		MOV	R2,R5,LSR #8
		STMFD	R13!,{R0-R2}		;Save them on the stack
		MOV	R0,#21			;Do mouse things
		MOV	R1,R13			;Point to the block
		SWI	OS_Word			;Do the job
		ADD	R13,R13,#12		;Restore stack pointer
		LDMFD	R13!,{R0-R2,PC}^	;And return to caller

		LTORG


; --- cs_beep ---
;
; On entry:	--
;
; On exit:	--
;
; Use:		Sounds the bell (VDU 7) if the CMOS settings dictate that
;		error boxes should cause a beep.

cs_beep		ROUT

		STMFD	R13!,{R0-R2,R14}	;Save some registers
		MOV	R0,#161			;Read CMOS locations nicely
		MOV	R1,#197			;Read WimpFlags location
		SWI	OS_Byte			;Do the read operation
		TST	R2,#1<<4		;Do we make noises then?
		SWIEQ	OS_WriteI+7		;Yes -- bleep
		LDMFD	R13!,{R0-R2,PC}^	;Return to caller

		LTORG

;----- Workspace ------------------------------------------------------------

		^	0,R12
cs_wStart	#	0

cs_warning	#	4
cs_pollBlock	#	256
cs_indBase	#	256
cs_indLimit	#	0
cs_stack	#	256

cs_wSize	EQU	{VAR}-cs_wStart

;----- That's all, folks ----------------------------------------------------

		END
