;
; transWin.s
;
; Transient window handling (MDW)
;
;  1994-1998 Straylight
;

;----- Licensing note -------------------------------------------------------
;
; This file is part of Straylight's Sapphire library.
;
; Sapphire 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.
;
; Sapphire 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 Sapphire.  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	sapphire:event
		GET	sapphire:sapphire

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

		AREA	|Sapphire$$Code|,CODE,READONLY

; --- transWin_subWaiting ---
;
; On entry:	--
;
; On exit:	CS if a submenu is waiting to be opened, CC otherwise
;
; Use:		Informs the caller whether the menu system is waiting for
;		a submenu to be attached.

		EXPORT	transWin_subWaiting
transWin_subWaiting ROUT

		ORR	R14,R14,#C_flag		;Assume there is one waiting
		STMFD	R13!,{R0,R1,R12,R14}	;Save some registers
		WSPACE	tw__wSpace		;Find my workspace

		; --- First, try asking TMS ---

		LDR	R1,tw__twin		;Load the global area address
		LDR	R1,[R1,#twin_tmsHook]	;Load the hook address
		CMP	R1,#1			;Has the hook been set up?
		MOVCS	R14,PC			;Yes -- set up return address
		ADDCS	PC,R1,#tmsh__subWaiting	;And call the routine
		LDMCSFD	R13!,{R0,R1,R12,PC}^	;Return true

		; --- Now find out about the normal WIMP ---

		BL	event_last		;Find the last event
		CMP	R0,#17			;Is it some kind of message?
		CMPNE	R0,#18			;Either type of message?
		LDREQ	R0,[R1,#16]		;Get the message code
		MOVEQ	R14,#&40000		;The message base number
		ORREQ	R14,R14,#&000C0		;We're looking for submenus
		CMPEQ	R0,R14			;Do they match?
		LDMEQFD	R13!,{R0,R1,R12,PC}^	;Return true
		LDMFD	R13!,{R0,R1,R12,R14}	;Unstack some registers
		BICS	PC,R14,#C_flag		;Return false

		LTORG

; --- transWin_openSub ---
;
; On entry:	R0 == window handle to open
;
; On exit:	--
;
; Use:		Opens the given window as a submenu.

		EXPORT	transWin_openSub
transWin_openSub ROUT

		STMFD	R13!,{R0-R3,R12,R14}	;Save some registers
		WSPACE	tw__wSpace		;Find my workspace

		; --- First of all, try TMS ---

		LDR	R1,tw__twin		;Load the global area address
		LDR	R1,[R1,#twin_tmsHook]	;Load the hook address
		CMP	R1,#1			;Has the hook been set up?
		MOVCS	R14,PC			;Yes -- set up return address
		ADDCS	PC,R1,#tmsh__subWaiting	;And call the routine
		MOVCS	R14,PC			;If it is waiting...
		ADDCS	PC,R1,#tmsh__openSub	;...get it to open the menu
		BCS	%90transWin_openSub	;And then return to caller

		; --- Now try the normal system ---

		MOV	R2,R0			;Look after the window handle
		BL	event_last		;Find the last event
		CMP	R0,#17			;Is it some kind of message?
		CMPNE	R0,#18			;Either type of message?
		LDREQ	R0,[R1,#16]		;Get the message code
		MOVEQ	R14,#&40000		;The message base number
		ORREQ	R14,R14,#&000C0		;We're looking for submenus
		CMPEQ	R0,R14			;Do they match?
		BNE	%99transWin_openSub	;No -- return then

		; --- Open as a normal submenu ---

		ADD	R14,R1,#24		;Point to the coordinates
		MOV	R1,R2			;Get the window handle back
		LDMIA	R14,{R2,R3}		;Read the coordinates
		SWI	Wimp_CreateSubMenu	;Display the menu nicely
		MOV	R0,R1			;Get window handle in R0

		; --- Register the transient menu

90		BL	transWin_register	;Register the window
99		LDMFD	R13!,{R0-R3,R12,PC}^	;And return to caller

		LTORG

; --- transWin_register ---
;
; On entry:	R0 == window handle to register
;
; On exit:	--
;
; Use:		Registers a window as being the current transient window.

		EXPORT	transWin_register
transWin_register ROUT

		STMFD	R13!,{R12,R14}		;Save some registers
		WSPACE	tw__wSpace		;Find my workspace
		LDR	R12,tw__twin		;Find the global area
		STR	R0,[R12,#twin_trans]	;Save the transient window
		LDR	R14,[R12,#twin_flags]	;Load the TWIN flags word
		BIC	R14,R14,#twinFlag_recrt	;Don't recreate the menu
		STR	R14,[R12,#twin_flags]	;Save the flags back again
		LDMFD	R13!,{R12,PC}^		;And return to caller

		LTORG

; --- transWin_close ---
;
; On entry:	R0 == window handle to close
;
; On exit:	--
;
; Use:		Closes the current transient window.

		EXPORT	transWin_close
transWin_close	ROUT

		STMFD	R13!,{R0,R1,R10,R12,R14} ;Save some registers
		WSPACE	tw__wSpace		;Find my workspace
		LDR	R14,tw__flags		;Load my flags word
		TST	R14,#twFlag__wimpCls	;Did the WIMP close it?
		MOVEQ	R1,#-1			;No -- kill the whole menu
		SWIEQ	Wimp_CreateMenu		;Using this neat trick
		MOV	R1,R13			;Point at caller's handle
		SWI	Wimp_CloseWindow	;Close the window
		LDR	R0,[R13,#0]		;Load his window again
		LDR	R12,tw__twin		;Find the global area
		LDR	R14,[R12,#twin_trans]	;Load the current transient
		SUBS	R14,R0,R14		;Do they match nicely?
		STREQ	R14,[R12,#twin_trans]	;Yes -- zero the current one
		LDMFD	R13!,{R0,R1,R10,R12,PC}^ ;And return to caller

		LTORG

; --- tw__faker ---
;
; On entry:	R0 == event code
;		R1 == pointer to event data
;
; On exit:	CS and new event set up, or CC and registers preserved
;
; Use:		Generates dummy close events for transient windows.

tw__faker	ROUT

		; --- Ignore redraw events ---

		CMP	R0,#1			;Is it a redraw event?
		MOVEQS	PC,R14			;Yes -- return right now

		; --- Start up the faking business ---

		STMFD	R13!,{R9,R10,R14}	;Save some registers
		LDR	R14,tw__flags		;Load my flags word
		BIC	R14,R14,#twFlag__wimpCls ;Wimp hasn't closed it
		STR	R14,tw__flags		;Save the flags back again

		LDR	R10,tw__twin		;Find the global area
		LDR	R9,[R10,#twin_trans]	;Load the transient window
		CMP	R9,#0			;Is there one defined?
		LDMEQFD	R13!,{R9,R10,PC}^	;No -- return right now

		; --- See if the window's still open ---

		CMP	R0,#9			;Is this a menu hit event?
		BEQ	%10tw__faker		;Yes -- window will close

		STMFD	R13!,{R0,R1}		;Save some more registers
		SUB	R13,R13,#36		;Make some stack space
		STR	R9,[R13,#0]		;Save window handle in there
		MOV	R1,R13			;Point at the block
		SWI	Wimp_GetWindowState	;Read the window information
		LDR	R14,[R13,#32]		;Load the window flags
		TST	R14,#&00010000		;Is the window open still?
		ADD	R13,R13,#36		;Reclaim the stack space?
		LDMNEFD	R13!,{R0,R1,R9,R10,PC}^	;Yes -- return to caller
		LDMFD	R13!,{R0,R1}		;Restore those registers

		; --- Fake the event ---

		LDR	R14,tw__flags		;Load my flags word
		ORR	R14,R14,#twFlag__wimpCls ;Wimp has closed the window
		STR	R14,tw__flags		;Save the flags back again
10tw__faker	STR	R9,[R1,#0]		;Save window handle in block
		MOV	R0,#3			;It's a close event
		LDMFD	R13!,{R9,R10,R14}	;Unstack the registers
		ORRS	PC,R14,#C_flag		;And return with C set

		LTORG

; --- transWin_init ---
;
; On entry:	--
;
; On exit:	--
;
; Use:		Initialises the transWin system.

		EXPORT	transWin_init
transWin_init	ROUT

		STMFD	R13!,{R12,R14}		;Save some registers
		WSPACE	tw__wSpace		;Find my workspace

		; --- Make sure I'm not already running ---

		LDR	R14,tw__flags		;Load my flags word
		TST	R14,#twFlag__inited	;Is my initialised flag set?
		LDMNEFD	R13!,{R12,PC}^		;Yes -- return to caller
		MOV	R14,#twFlag__inited	;Set the intialised flag
		STR	R14,tw__flags		;And save the flags back

		; --- Set up the TWIN global area ---

		STMFD	R13!,{R0-R2}		;Save some more registers
		LDR	R0,tw__TWIN		;Load the global name word
		MOV	R1,#twin_size		;And the size value
		BL	sapphire_global		;Find the global area
		STR	R0,tw__twin		;Save the address of this
		BCS	%10transWin_init	;If already created, skip on

		MOV	R1,#0			;No flags set currently
		MOV	R2,#0			;No transient window set up
		MOV	R14,#0			;TMS hasn't registered itself
		STMIA	R0,{R1,R2,R14}		;Save them in the area

		; --- Now set up my fake event handler ---

10transWin_init	BL	event_init		;Make sure event is awake
		ADR	R0,tw__faker		;Point to the fake handler
		MOV	R1,R12			;Pass it my workspace address
		BL	event_fakeHandler	;Register the handler
		LDMFD	R13!,{R0-R2,R12,PC}^	;And return to caller

tw__TWIN	DCB	"TWIN"

		LTORG

tw__wSpace	DCD	0

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

		; --- TWIN global area layout ---
		;
		; This global area is intended to allow communication
		; between transWin and menu system providers.
		;
		; The TMS hook is set by TMS to point to a pair of branch
		; instructions to routines tmsh_subWaiting and tmsh_openSub
		; respectively.
		;
		; tmsh_subWaiting should return CS if TMS is waiting to open
		; a submenu, and CC otherwise.  tmsh_openSub is passed a
		; window handle in R0, which it should open as a submenu in
		; whatever way it sees fit.
		;
		; If the tmsHook pointer is zero, transWin will assume that
		; TMS is not available.

		^	0
twin_flags	#	4			;Various useful flags
twin_trans	#	4			;The current transient window
twin_tmsHook	#	4			;A hook to the TMS system
twin_size	#	0			;The size of the global area

twinFlag_recrt	EQU	(1<<0)			;Menu will be recreated

tmsh__subWaiting EQU	0
tmsh__openSub	EQU	4

		; --- Workspace ---

		^	0,R12
tw__wStart	#	0

tw__flags	#	4			;Various useful flags
tw__twin	#	4			;Pointer to the TWIN global

tw__wSize	EQU	{VAR}-tw__wStart

twFlag__inited	EQU	(1<<0)			;We have been initialised
twFlag__wimpCls	EQU	(1<<1)			;Wimp closed last dbox

		AREA	|Sapphire$$LibData|,CODE,READONLY

		DCD	tw__wSize
		DCD	tw__wSpace
		DCD	0
		DCD	transWin_init

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

		END
