; Patch ObtainGIRPort() to fix MagicMenu

	INCLUDE	'intuition/cghooks.i'

ObtainGIRPort	EQU	-$22E
DisplayBeep		EQU	-$60

OpenLibrary		EQU	-$228
CloseLibrary	EQU	-$19E
SetFunction		EQU	-$1A4
Forbid			EQU	-$84
Permit			EQU	-$8A
Wait			EQU	-$13E
CacheClearU		EQU	-$27c

Delay			EQU -$C6
PutStr			EQU	-$3B4

AttemptLockLayerRom	EQU	-$28E
UnlockLayerRom	EQU	-$1B6
	
SIGBREAKF_CTRL_C	EQU 1<<12
	
	section text,code
	
_PatchOGR:
	moveq	#20,d7

	; Open libraries	
	lea		gfxname(pc),a1
	moveq	#0,d0
	move.l	4,a6
	jsr		OpenLibrary(a6)
	lea		GfxBase(pc),a0
	move.l	d0,(a0)
	beq		fail1
	
	lea		dosname(pc),a1
	moveq	#0,d0
	jsr		OpenLibrary(a6)
	lea		DOSBase(pc),a0
	move.l	d0,(a0)
	beq		fail2
	
	lea		intuiname(pc),a1
	moveq	#36,d0
	jsr		OpenLibrary(a6)
	lea		IBase(pc),a0
	move.l	d0,(a0)
	beq		fail3
	
	jsr		Forbid(a6)

	; Install patch
	move.l	d0,a1
	lea		newObtainGIRPort(pc),a0
	move.l	a0,d0
	move.l	#ObtainGIRPort,a0
	jsr		SetFunction(a6)
	lea		oldObtainGIRPort(pc),a0
	move.l	d0,(a0)
	
	; Clear CPU caches to flush data/instruction cache incoherence
	jsr		CacheClearU(a6)
	
	jsr		Permit(a6)

loop:
	move.l	4,a6
	
	; Wait for ctrl-C
	move.l	#SIGBREAKF_CTRL_C,d0
	jsr		Wait(a6)
	
	jsr		Forbid(a6)

	; Attempt to remove the patch
	move.l	IBase(pc),a1
	move.l	oldObtainGIRPort(pc),d0
	move.l	#ObtainGIRPort,a0
	jsr		SetFunction(a6)
	lea		newObtainGIRPort(pc),a0
	cmp.l	a0,d0
	beq		ok
	
	; Oops, someone has patched over, put it back
	move.l	IBase(pc),a1
	move.l	#ObtainGIRPort,a0
	jsr		SetFunction(a6)
	jsr		Permit(a6)
	
	; We can't quit, so notify user with a beep
	move.l	IBase(pc),a6
	move.l	#0,a0
	jsr		DisplayBeep(a6)
	
	bra		loop
	
ok:
	jsr		Permit(a6)

	move.l	DOSBase(pc),a6

	; Notify user of subsequent quit
	lea		exitmsg(pc),a0
	move.l	a0,d1
	jsr 	PutStr(a6)
	
	; Wait a second to let other tasks exit from the patch code
	; We can't be absolutely sure but this should be enough of a safeguard
	moveq	#50,d1
	jsr		Delay(a6)
	
	moveq	#0,d7

	; Close libraries and exit	
	move.l	4,a6
	move.l	IBase(pc),a1
	jsr		CloseLibrary(a6)
	
fail3:
	move.l	DOSBase(pc),a1
	jsr		CloseLibrary(a6)
	
fail2:
	move.l	GfxBase(pc),a1
	jsr		CloseLibrary(a6)
	
fail1:
	move.l	d7,d0
	rts

newObtainGIRPort:
	; First we should check for valid input
	cmp.l	#0,a0
	; We'll call ObtainGIPort anyway, even if the GadgetInfo is NULL..
	beq		null1
	
	tst.l	ggi_Layer(a0)
	beq		null1
	
	movem.l	a5/a6,-(sp)
	move.l	a0,-(sp)

	; non-NULL GadgetInfo->gi_Layer, try to lock it
	move.l	GfxBase(pc),a6
	move.l	ggi_Layer(a0),a5
	jsr		AttemptLockLayerRom(a6)
	move.l	(sp)+,a0
	tst.w	d0
	beq		null2

	; Got a lock, free it
	move.l	a0,-(sp)
	move.l	ggi_Layer(a0),a5
	jsr		UnlockLayerRom(a6)
	
	move.l	(sp)+,a0
	movem.l	(sp)+,a5/a6

null1:
	; call original function
	move.l	oldObtainGIRPort(pc),a1
	jmp		(a1)
	
null2:
	; Attempt to lock the layer failed, return NULL
	movem.l	(sp)+,a5/a6
	move.l	#0,d0
	rts

oldObtainGIRPort:
	dc.l	0

DOSBase:
	dc.l	0
IBase:
	dc.l	0
GfxBase:
	dc.l	0

dosname:
	dc.b	"dos.library",0
intuiname:
	dc.b	"intuition.library",0
gfxname:
	dc.b	"graphics.library",0
exitmsg:
	dc.b	"NewObtainGIRPort exiting..",10,0

	dc.b	"$VER: NewObtainGIRPort 1.1 (29.1.95)",0

	END
