a1	RN	0
a2	RN	1
a3	RN	2
a4	RN	3
v1	RN	4
v2	RN	5
v3	RN	6
v4	RN	7
v5	RN	8
v6	RN	9
sl	RN	10
fp	RN	11
ip	RN	12

r0	RN	0
r1	RN	1
r2	RN	2
r3	RN	3
r4	RN	4
r5	RN	5
r6	RN	6
r7	RN	7
r8	RN	8
r9	RN	9
r10	RN	10
r11	RN	11
r12	RN	12

sp	RN	13
lr	RN	14
pc	RN	15

V_bit	*	&10000000
C_bit	*	&20000000
Z_bit	*	&40000000
N_bit	*	&80000000
SVC	*	3

X	*	&20000

Service_ModeChange		*	&46
Service_FilterManagerInstalled	*	&87
Service_FilterManagerDying	*	&88

OS_Byte			*	&06
KeyboardStatus	*	202
AltDown		*	1		;When bit 0 is 1 (NE), Alt is down
OS_Exit			*	&11
OS_Claim		*	&1F
OS_Release		*	&20
EventDisable	*	13
EventEnable	*	14
OS_ReadVduVariables	*	&31
XEigFactor	*	4
YEigFactor	*	5
XWindLimit	*	11
YWindLimit	*	12
OS_AddCallBack		*	&54
Wimp_Initialise		*	&400C0
Wimp_CreateWindow	*	&400C1
Wimp_DeleteWindow	*	&400C3
Wimp_OpenWindow		*	&400C5
Wimp_CloseWindow	*	&400C6
Wimp_GetWindowState	*	&400CB
Wimp_GetWindowInfo	*	&400CC
Wimp_CloseDown		*	&400DD
Wimp_SendMessage	*	&400E7
OpenWindowReq	*	2
KeyPressed	*	8
UserMsgAck	*	19
Filter_RegisterPostFilter	*	&42641
Filter_DeRegisterPostFilter	*	&42643

		area	AltTab,CODE

		&	0		;No start code
		&	init
		&	final
		&	services
		&	title
		&	help
		&	0		;No *Commands

key_handler	teq	r0,#KeyPressed
		movnes	pc,lr
		ldr	r0,[r1,#24]	;get the character
		eor	r0,r0,#&100
		teq	r0,#&8A		;&18A is plain Tab under Wimp
		mov	r0,#KeyPressed
		movnes	pc,lr
		stmfd	sp!,{r0-r6,lr}
		mov	r0,#KeyboardStatus
		movs	r1,#0		;prime EQ in case SWI fails
		mov	r2,#255
		swi	X+OS_Byte
		tstvc	r1,#AltDown
		ldmeqfd	sp!,{r0-r6,pc}^
		mvn	r0,#0
		str	r0,[sp]		;on return, R0 = -1
		adr	r1,wdata
		swi	X+Wimp_CreateWindow
		ldmvsfd	sp!,{r0-r6,pc}^
		str	r0,winfo
		str	r0,[r1,#-4]!
		swi	X+Wimp_OpenWindow
		adrvc	r1,winfo
		swivc	X+Wimp_GetWindowState
		mov	r2,pc
		swi	X+Wimp_DeleteWindow
		teqvcp	r2,#0
		ldmvsfd	sp!,{r0-r6,pc}^
		mov	r6,r1		;Since r1 will need bit 0 set,
					;r6 must be the base from here on
loop_r1		orr	r1,r6,#1	;Ensure icons will *not* be returned
loop		ldr	r2,[r6,#28]
		cmn	r2,#1
		ldmlefd	sp!,{r0-r6,pc}^
		str	r2,[r6]
		swi	X+Wimp_GetWindowInfo	;This is why r1 has bit 0 set
		ldmvsfd	sp!,{r0-r6,pc}^
		ldr	r0,[r6,#32]
		tst	r0,#(1<<17)
		bne	loop
		ldmib	r6,{r0,r3-r5}	;visible Xmin,Ymin,Xmax,Ymax
		cmp	r4,#0
		cmpgt	r5,#0
		adrgt	r4,screen_dims
		ldmgtia	r4,{r4,r5}	;XmaxOS,YmaxOS
		cmpgt	r4,r0
		cmpgt	r5,r3
		ble	loop
		ldr	r0,[r6,#52]
		cmn	r0,#&F0000002	;menus have &FFFFFFE in work-area-max-X
		beq	open
		adr	r1,empty_msg
		mov	r0,#UserMsgAck
		swi	X+Wimp_SendMessage
		ldmvsfd	sp!,{r0-r6,pc}^
		cmp	r2,#0
		ble	loop_r1
		;If we get here with flags = EQ,
		;then we must have branched here after detecting a menu.
		;Otherwise, we'll have just fallen through with flags = GT
open		mvn	r0,#0
		str	r0,[r6,#28]
		adr	r1,winfo
		swieq	X+Wimp_OpenWindow
		movgt	r0,#OpenWindowReq
		swigt	X+Wimp_SendMessage
		ldmfd	sp!,{r0-r6,pc}^

empty_msg	&	16,0,0,0

winfo		%	4+88

		&	0
wdata		&	-36,-36,-4,-4	;visible area is off-screen
		&	0,0		;scroll offsets
		&	-2		;open at stack bottom
		&	&80040050	;window flags:
					;  new format
					;  full size
					;  can be opened off screen
					;  redrawn by Wimp
		=	&ff,0,0,&ff	;window colours:
					;  no control area of frame
					;  transparent background
		=	0,0,0,0		;more colours --- irrelevant
		&	0,-32,32,0	;work area dimensions
		&	0		;title bar flags --- irrelevant
		&	0		;ignore all clicks
		&	0		;no sprites
		&	&00200020	;minimum width and height
		&	0,0,0		;no title
		&	0		;no icons

screen_dims	&	0,0,0,0
screen_vars	&	XEigFactor,YEigFactor,XWindLimit,YWindLimit,-1

get_screen	stmfd	sp!,{r0-r4,lr}
		adr	r0,screen_vars
		adr	r1,screen_dims
		swi	X+OS_ReadVduVariables
		movvs	r0,#32768	;some ridiculously large screen
		movvs	r2,#32768	;some ridiculously large screen
		ldmvcia	r1,{r0,r2-r4}
		addvc	r3,r3,#1
		addvc	r4,r4,#1
		movvc	r0,r3,lsl r0
		movvc	r2,r4,lsl r2
		stmia	r1,{r0,r2}
		ldmfd	sp!,{r0-r4,pc}^

services	teq	r1,#Service_ModeChange
		teqne	r1,#Service_FilterManagerInstalled
		teqne	r1,#Service_FilterManagerDying
		movnes	pc,lr
		teq	r1,#Service_FilterManagerDying
		beq	services_fmd
		teq	r1,#Service_FilterManagerInstalled
		beq	services_fmi
services_mc	stmfd	sp!,{r0-r1,lr}
		adr	r0,get_screen
		mov	r1,r12
		swi	X+OS_AddCallBack
		ldmfd	sp!,{r0-r1,pc}^
services_fmd	mov	r12,#0
		str	r12,filter_flag
		movs	pc,lr
services_fmi	stmfd	sp!,{r0-r1,lr}
		adr	r0,add_filter
		mov	r1,r12
		swi	X+OS_AddCallBack
		ldmfd	sp!,{r0-r1,pc}^

add_filter	stmfd	sp!,{r0-r4,lr}
		bl	filter_regs
		swi	X+Filter_RegisterPostFilter
		strvc	r12,filter_flag
		ldmfd	sp!,{r0-r4,pc}^

filter_flag	&	0

filter_regs	adr	r0,title
		adr	r1,key_handler
		mov	r2,r12
		mov	r3,#0
		ldr	r4,filter_mask
		movs	pc,lr
filter_mask	&	&3FFFFF-(1<<KeyPressed)

init		teq	r11,#0
		adrne	r0,multierr
		orrnes	pc,lr,#V_bit
		mov	r6,lr
		adr	r3,taskinfo
		ldmia	r3!,{r0,r1,r4}
		movs	r4,r4
		adreq	r2,title
		swieq	X+Wimp_Initialise
		movvs	pc,r6
		streq	r1,taskinfo
		streq	r0,taskinfo+8
		bl	filter_regs
		swi	X+Filter_RegisterPostFilter
		strvc	r12,filter_flag
		mov	lr,r6
		b	get_screen

final		ldr	r6,filter_flag
		movs	r6,r6
		mov	r6,lr
		blne	filter_regs
		swine	X+Filter_DeRegisterPostFilter
		movvs	pc,r6
		teq	r10,#0
		adrne	r0,taskinfo
		ldmneia	r0,{r0,r1}
		swine	X+Wimp_CloseDown
		mov	pc,r6

taskinfo	&	310		;Wimp version with required features
					;After initialisation, the task-handle
		=	"TASK"
		&	0		;After initialisation, the Wimp version
		&	0		;NULL-list of Wimp messages wanted

multierr	&	0
		=	"AltTab is already in use",0

title		=	"AltTab",0

help		=	"AltTab",9,9,"0.20 (24 Nov 1998)  Christopher Martin"
		=	13,10
		=	"Flips windows from the back to the front"
		=	0

		end
