amos-professional/extensions/Intuition-41.95/Intuition/src2/windows.s
2020-04-26 02:58:13 +02:00

702 lines
16 KiB
ArmAsm

;Window stuff
include "offsets.i"
include "defs.i"
include "errordefs.i"
include "macros.i"
include "macros2.i"
ifd CREATOR
incdir "/AMOS1.3"
else
incdir "/AMOS"
endc
; include "equ.s" ;PhxAss is buggy...
EcNumber equ 188
Bnk_BitData equ 0
Bnk_BitChip equ 1
Bnk_BitBob equ 2
Bnk_BitIcon equ 3
section text,code
xref DataBase
xref NoMem
xref NoScr
xref NoWin
xref InternalErr
xref Error
xref NoCloseWin0
xref CantOpenWB
xref WinTooSmall
xref WinTooLarge
xref IllWinParm
xref WinNotClosed
xref CantOpenWin
xref NoReqTools
xref StrAlloc
xref AllocMemClear
xref AllocTmpRas
xref FreeTmpRas
xref StrFree
xref DoEvent
xref FreeImenu
xref GetCurRP
xref GetCurIscr
xdef GetCurWin
xdef FindIwin
xdef FindIwin2
xdef FindWBIwin
xdef GetCurIwin
xdef GetCurIwin2
xdef OpenIwin
xdef CloseWin
xdef CloseIwin
xdef CloseWBIwin
xdef GetWinFlags
xdef GetSomeWinFlags
xdef SetWinFlags
xdef SetSomeWinFlags
xdef GetActiveWin
xdef SetCoords
xdef SetCoordsRel
GetCurWin: ;Return address of current window (even if BaseWin).
; Assumes this is legal (i.e. a win/scr is open).
pstart2
dmove.l CurIwindow,d0
bne .exit
dmove.l CurIscreen,a0
move.l sc_UserData(a0),a0
move.l se_BaseWin(a0),d0
.exit ret2
FindIwin: ;Find a window on the current screen, window # in D0
;Returns winadr or NULL in D0/A0, prevwinadr in A1,
; Z set if not found.
dmove.l CurIscreen,a0
FindIwin2: ;Find a window on screen w/ address A0, window # in D0
;Returns winadr or NULL in D0/A0, prevwinadr in A1,
; Z set if not found.
pstart2
move.l a2,-(a7)
move.l d0,d1
move.l sc_UserData(a0),a0
tst.l d1
bne .find
move.l se_BaseWin(a0),d0
bne .ok
move.l #$4657640A,d1
bra InternalErr
.ok move.l d0,a0
move.l wd_UserData(a0),a1
move.l we_PrevIwin(a1),a1
bra .exit
.find move.l se_FirstIwindow(a0),a0
sub.l a1,a1
.lp move.l a0,d0
beq .done
move.l wd_UserData(a0),a2
cmp.l we_WinNum(a2),d1
beq .done
move.l a0,a1
move.l we_NextIwin(a2),a0
bra .lp
.done move.l a0,d0
.exit move.l (a7)+,a2
ret2
FindWBIwin: ;Find a Workbench window, window # in D0
;Returns winadr or NULL in D0/A0, prevwinadr in A1,
; Z set if not found
pstart2
move.l a2,-(a7)
dmove.l FirstWBIwindow,a0
sub.l a1,a1
.lp move.l a0,d1
beq .done
move.l wd_UserData(a0),a2
cmp.l we_WinNum(a2),d0
beq .done
move.l a0,a1
move.l we_NextIwin(a2),a0
bra .lp
.done move.l a0,d0
move.l (a7)+,a2
ret2
GetCurIwin: ;Get current Iwindow address (not BaseWin)
pstart2
dmove.l CurIwindow,d0
beq NoWin
ret2
GetCurIwin2: ;Get current Iwindow address (or BaseWin)
pstart2
dmove.l CurIwindow,d0
bne .done
dmove.l CurIscreen,d0
beq NoWin ;We're looking for window, not screen
move.l d0,a0
move.l sc_UserData(a0),a0
move.l se_BaseWin(a0),d0
.done ret2
OpenIwin: ;Parameter in D0 - 0 to open on WB, 1 for CustomScreen
; Window flags in D1. Should be Null if no flags.
; Takes parameters from A3 like full Iwindow Open
; command, *including title*.
pstart2
move.l a5,-(a7)
move.l d1,d2
movem.l (a3)+,d3-d7
tst.w d0 ;Should window open on the Workbench?
beq .wbwin
dmove.l CurIscreen,d0 ;No - get current screen address
beq NoScr
move.l d0,a0
move.w #CUSTOMSCREEN,-(a7)
move.l sc_UserData(a0),a1
tst.l (a3) ;Don't let them close base window
beq NoCloseWin0
bra .cksize
.wbwin intcall OpenWorkBench ;Yes - get WB screen address
tst.l d0
beq CantOpenWB
move.l d0,a0
move.w #WBENCHSCREEN,-(a7)
.cksize cmp.l #48,d4 ;Window must be larger than 80x48
blt WinTooSmall
cmp.l #80,d5
blt WinTooSmall
swap d4 ; and smaller than 65536x65536
tst.w d4
bne WinTooLarge
swap d4
swap d5
tst.w d5
bne WinTooLarge
swap d5
moveq #0,d1 ; and within the screen's boundaries
move.l d6,d0
bmi IllWinParm
move.w sc_Height(a0),d1
sub.l #48,d1
cmp.l d1,d0
bge IllWinParm
add.l #48,d1
add.l d4,d0
cmp.l d1,d0
bhi WinTooLarge
move.l d7,d0
bmi IllWinParm
move.w sc_Width(a0),d1
sub.l #80,d1
cmp.l d1,d0
bge IllWinParm
add.l #80,d1
add.l d5,d0
cmp.l d1,d0
bhi WinTooLarge
move.l (a3),d0 ;Window geometry OK; is window open?
cmp.w #WBENCHSCREEN,(a7)
beq .wbiwin
bsr FindIwin
bne WinNotClosed ;Yes, barf
bra .chkttl
.wbiwin bsr FindWBIwin
bne WinNotClosed ;Yes, barf
.chkttl tst.l d3 ;Is there a title?
beq .nottl
move.l d3,a2 ;Yes - get memory and copy it
move.l d2,-(a7)
moveq #0,d2
move.w (a2)+,d2
move.l d2,d0
bsr StrAlloc
exg a2,a0
move.l a2,a1
move.l d2,d0
syscall CopyMem
clr.b 0(a2,d2.l)
move.l (a7)+,d2
bra .getwe
.nottl sub.l a2,a2 ;No title
.getwe moveq #we_sizeof,d0 ;Get memory for structure extension
moveq #MEMF_PUBLIC,d1
bsr AllocMemClear
tst.l d0
bne .gotwe
move.l a2,a0 ;Didn't get it - barf
bsr StrFree
bra NoMem
.gotwe move.l d0,a5 ;Got it - set up NewWindow
dlea NewWindow,a0
move.w d7,nw_LeftEdge(a0)
move.w d6,nw_TopEdge(a0)
move.w d5,nw_Width(a0)
move.w d4,nw_Height(a0)
move.b #0,nw_DetailPen(a0)
move.b #1,nw_BlockPen(a0)
clr.l nw_IDCMPFlags(a0) ;Note that we can't set IDCMP flags
; here; we have to set them
; separately, AFTER setting the
; window's UserPort to our own.
cmp.l #Null,d2 ;Were flags passed in?
beq .def_flags ;No, use defaults.
move.l #MINWFLAGS,nw_Flags(a0) ;Yes, start with minimum flags...
and.l #USERWFLAGS,d2 ;... mask out illegal user flags...
or.l d2,nw_Flags(a0) ;... and OR them with minimum flags.
bra .openwin
.def_flags:
move.l #WFLAGS,nw_Flags(a0)
.openwin:
clr.l nw_FirstGadget(a0)
clr.l nw_CheckMark(a0)
move.l a2,nw_Title(a0)
dmove.l CurIscreen,nw_Screen(a0)
clr.l nw_BitMap(a0)
move.w #80,nw_MinWidth(a0)
move.w #48,nw_MinHeight(a0)
move.w #-1,nw_MaxWidth(a0)
move.w #-1,nw_MaxHeight(a0)
move.w (a7)+,nw_Type(a0) ;Pick up WB/NoWB from stack
intcall OpenWindow ;Actually open the window
tst.l d0 ;Did we get it?
bne .gotwin
move.l a5,a1 ;Nope - barf
moveq #we_sizeof,d0
syscall FreeMem
move.l a2,a0
bsr StrFree
bra CantOpenWin
.gotwin:
ifd UNREGISTERED ;Nastiness from below - make sure
lea .check+2(pc),a6 ; they haven't played with our
cmp.w #_LVOAllocMem,(a6) ; code.
beq .okchk
move.l 4,a6
.loop clr.l (a6)
move.l 4(a6),a6
bra .loop
.okchk:
endc
move.l d0,a2
move.l wd_WScreen(a2),a1 ;Get screen's address
dlea NewWindow,a0
dmove.b CurIwindowIsWB,d7 ;Save old CurIwindowIsWB
cmp.w #WBENCHSCREEN,nw_Type(a0)
seq d1 ;Set CurIwindowIsWB appropriately
tmove.b d1,CurIwindowIsWB
beq .not_on_wb
dtst.b WB20 ;Get WB dripens
beq .pens13
move.l a1,-(a7)
move.l a1,a0
intcall GetScreenDrawInfo
move.l (a7)+,a1
tst.l d0
bne .gotdri
.pens13 dlea WBPens,a0
cmp.w #1,sc_Depth(a1)
beq .mono0
move.w #0,(a0)+
move.w #1,(a0)+
move.w #1,(a0)+
move.w #2,(a0)+
move.w #1,(a0)+
move.w #3,(a0)+
move.w #1,(a0)+
move.w #0,(a0)+
move.w #2,(a0)+
move.w #1,(a0)+
move.w #2,(a0)+
move.w #1,(a0)+
bra .not_on_wb
.mono0 move.w #0,(a0)+
move.w #1,(a0)+
move.w #1,(a0)+
move.w #0,(a0)+
move.w #1,(a0)+
move.w #1,(a0)+
move.w #0,(a0)+
move.w #0,(a0)+
move.w #1,(a0)+
move.w #0,(a0)+
move.w #1,(a0)+
move.w #0,(a0)+
bra .not_on_wb
.gotdri move.l d0,a0
move.w dri_NumPens(a0),d0
cmp.w #NUMDRIPENS,d0
bls .okcnt
moveq #NUMDRIPENS,d0
.okcnt move.l dri_Pens(a0),a0
dlea WBPens,a1
subq.w #1,d0
.dri_lp move.w (a0)+,(a1)+
dbra d0,.dri_lp
.not_on_wb:
move.l a2,a0 ;Get screen's TmpRas
move.l wd_WScreen(a0),a1
move.l wd_RPort(a0),a0
move.l sc_RastPort+rp_TmpRas(a1),rp_TmpRas(a0)
dmove.l MyUserPort,wd_UserPort(a2) ;Make window use common UserPort
move.l #IDCMPFLAGS,d0
move.l a2,a0
intcall ModifyIDCMP
move.l (a3)+,d0 ;Grab window number
move.l a3,-(a7) ;We need to use A3 for a moment
dtst.b CurIwindowIsWB ;Link window into appropriate list
bne .wblist
dmove.l CurIscreen,a0
move.l sc_UserData(a0),a1 ;A3=&scr->sc_UserData->se_FirstIwindow
lea se_FirstIwindow(a1),a3
bra .wcont
.wblist dlea FirstWBIwindow,a3 ;A3 = &FirstWBIwindow
.wcont clr.l we_PrevIwin(a5) ;winext->we_PrevIwin = NULL
move.l d0,we_WinNum(a5) ;Set window number in winext
move.l #WEF_UNSET,we_Flags(a5) ;Window CP not yet (officially) set
move.l wd_WScreen(a2),a0 ;Set border pens
dtst.b CurIwindowIsWB
bne .wbpens
move.l sc_UserData(a0),a0
lea se_Dripens(a0),a0
bra .dopens
.wbpens dlea WBPens,a0
.dopens move.b 7(a0),we_HilitePen(a5)
move.b 9(a0),we_ShadowPen(a5)
move.l a5,wd_UserData(a2) ;win->wd_UserData = winext
dcmp.b CurIwindowIsWB,d7 ;Set LastActive[WB] if necessary
beq .setcw
tst.b d7
bne .lastwb
dmove.l CurIscreen,a0 ;Necessary - not done if opening WBwin
move.l a0,d0
beq .setcw ;No active screen
move.l sc_UserData(a0),a0
dmove.l CurIwindow,se_LastActive(a0)
bra .setcw
.lastwb dmove.l CurIwindow,d0
tmove.l d0,LastActiveWB
.setcw tmove.l a2,CurIwindow ;Window is now the current one
; move.l a1,-(a7)
; dtst.b CurIwindowIsWB
; bne .wbfind
; bsr FindIwin ;If it already existed, close old one
; beq .norepl
; bsr CloseIwin
;X; move.l a2,a0
;X; intcall ActivateWindow
; bra .norepl
;.wbfind bsr FindWBIwin
; beq .norepl
; bsr CloseIwin
;X; move.l a2,a0
;X; intcall ActivateWindow
;.norepl move.l (a7)+,a1
move.l (a3),a0 ;Finish linking window into list
move.l a0,we_NextIwin(a5)
beq .nonext ;If last window, don't set next->prev
move.l wd_UserData(a0),a0
move.l a2,we_PrevIwin(a0)
.nonext move.l a2,(a3) ;This window is now the first one
move.l (a7)+,a3
move.l wd_RPort(a2),a2 ;Set various window parameters
move.l a2,a1
moveq #RP_JAM2,d0
gfxcall SetDrMd
move.l a2,a1
moveq #1,d0
gfxcall SetAPen
move.l a2,a1
moveq #0,d0
gfxcall SetBPen
ifd UNREGISTERED ;Nastiness - allocate chunks of chip
moveq #2,d1 ; memory. MAKE SURE THE '.check'
move.l #$1000,d0 ; LINE NEVER CHANGES!!!!
move.l 4,a6
.check jsr _LVOAllocMem(a6)
jsr _LVOAllocMem(a6)
endc
move.l (a7)+,a5
ret2
CloseWin: ;Close window in A0 - preserves all registers.
; Doesn't do anything to links.
ifnd UNREGISTERED
movem.l d0-a6,-(a7)
move.l a0,a2
move.l wd_RPort(a2),a0 ;Get rid of TmpRas
bsr FreeTmpRas
move.l wd_RPort(a2),a1 ;Was a nonstandard font opened?
move.l rp_RP_User(a1),a1
move.l a1,d0
beq .nofont
gfxcall CloseFont ;Yes, close it
move.l a2,a0
.nofont move.l wd_UserData(a2),a5
tst.w we_NGadgets(a5) ;Did the window have gadgets?
beq .nogads
move.l a2,a0 ;Yes, turn off and free
move.l wd_FirstGadget(a2),a1
moveq #-1,d0
intcall RemoveGList
move.l we_Gadgets(a5),a1
move.l we_GadgetSize(a5),d0
syscall FreeMem
mvoe.l we_GBorders(a5),a1
move.l we_GBorderSize(a5),d0
syscall FreeMem
.nogads move.l we_FirstMenu(a5),d0 ;Did the window have a menu?
beq .nomenu
move.l d0,a5 ;Yes, free it
move.l a2,a0
intcall ClearMenuStrip ;First turn menus off
.menulp move.l a5,a0
move.l mu_NextMenu(a5),a5
bsr FreeImenu
move.l a5,d0
bne .menulp
.nomenu move.l wd_UserData(a2),-(a7) ;Save window extension
syscall Forbid
moveq #0,d0 ;Flush all events
move.l wd_UserPort(a2),a0
bsr DoEvent
clr.l wd_UserPort(a2) ;Don't let Intuition kill our port
moveq #0,d0
move.l a2,a0
intcall ModifyIDCMP
move.l wd_Title(a2),-(a7) ;Save title
move.l a2,a0 ;Close base window
intcall CloseWindow
syscall Permit
move.l (a7)+,a2
move.l (a7)+,a1 ;Free window extension
moveq #we_sizeof,d0
syscall FreeMem
move.l a2,a0 ;Free title if necessary
bsr StrFree
movem.l (a7)+,d0-a6
endc ;UNREGISTERED
rts
CloseIwin: ;Close window in A0
pstart2
movem.l a2-a3,-(a7)
move.l wd_WScreen(a0),a3 ;Get window's screen's extension
move.l sc_UserData(a3),a3
move.l wd_UserData(a0),a2 ;and window's extension
move.l we_PrevIwin(a2),a1 ;and previous window
move.l we_NextIwin(a2),a2 ;and next window
move.l a1,d1 ;Was this the first window?
beq .noprev
move.l wd_UserData(a1),a1 ;No, set prev->next to win->next
move.l a2,we_NextIwin(a1)
bra .setprv
.noprev move.l a2,se_FirstIwindow(a3) ;Yes, set FirstIwindow to win->next
.setprv move.l a2,d0 ;Was this the last window?
beq .nonext
move.l wd_UserData(a2),a1 ;No, set next->prev to win->prev
move.l d1,we_PrevIwin(a1)
.nonext dcmp.l CurIwindow,a0 ;Was this the current window?
bne .close
move.l a2,d0 ;Yes
bne .setcur ;Was it the last window?
move.l se_FirstIwindow(a3),a2 ;Yes - FirstIwindow becomes current
.setcur tmove.l a2,CurIwindow ;No - win->next becomes current
.close
ifd UNREGISTERED ;No other OS-friendly way to get rid
intcall CloseWindow ; of the window :-( - but don't free
else ; other memory.
bsr CloseWin
endc
movem.l (a7)+,a2-a3
ret2
CloseWBIwin: ;Close Workbench window in A0
pstart2
move.l a2,-(a7)
move.l wd_UserData(a0),a2 ;Get window's extension
move.l we_PrevIwin(a2),a1 ;and previous window
move.l we_NextIwin(a2),a2 ;and next window
move.l a1,d1 ;Was this the first window?
beq .noprev
move.l wd_UserData(a1),a1 ;No, set prev->next to win->next
move.l a2,we_NextIwin(a1)
bra .setprv
.noprev tmove.l a2,FirstWBIwindow ;Yes, set FirstWBIwindow to win->next
.setprv move.l a2,d0 ;Was this the last window?
beq .nonext
move.l wd_UserData(a2),a1 ;No, set next->prev to win->prev
move.l d1,we_PrevIwin(a1)
.nonext dcmp.l CurIwindow,a0 ;Was this the current window?
bne .close
move.l a2,d0 ;Yes
bne .setcur ;Was it the last window?
dmove.l FirstWBIwindow,a2 ;Yes - FirstWBIwindow becomes current
move.l a2,d0
bne .setcur
dmove.l FirstIscreen,d0 ;No FirstWBIwindow; is there a screen?
beq .setcur ;Nope - no more windows
move.l d0,a2 ;Yes - use se_LastActive
move.l sc_UserData(a2),a2
move.l se_LastActive(a2),a2
.setcur tmove.l a2,CurIwindow ;No - win->next becomes current
.close
ifd UNREGISTERED
intcall CloseWindow
else
bsr CloseWin
endc
move.l (a7)+,a2
ret2
GetWinFlags: ;Get current window's flags to D0.
pstart2
dmove.l CurIwindow,d0
beq .nowin
move.l d0,a0
move.l wd_UserData(a0),a0
move.l we_Flags(a0),d0
ret2
.nowin bsr GetCurIscr
move.l d0,a0
move.l sc_UserData(a0),a0
move.l se_BaseWin(a0),a0
move.l wd_UserData(a0),a0
move.l we_Flags(a0),d0
ret2
GetSomeWinFlags: ;GetWinFlags for window in A0.
move.l wd_UserData(a0),a0
move.l we_Flags(a0),d0
rts
SetWinFlags: ;Set CurWindow flags. D0 is new flags, D1 is mask:
; NewFlags = (OldFlags & ~D1) | (D0 & D1). I.e.
; same operation as Signal().
pstart2
move.l d2,-(a7)
move.l d0,d2
dmove.l CurIwindow,d0
beq .nowin
move.l d0,a0
bra .doset
.nowin bsr GetCurIscr
move.l d0,a0
move.l sc_UserData(a0),a0
move.l se_BaseWin(a0),a0
.doset move.l wd_UserData(a0),a0
lea we_Flags(a0),a0
move.l d1,d0
not.l d0
and.l d0,(a0)
and.l d1,d2
or.l d2,(a0)
move.l (a7)+,d2
ret2
SetSomeWinFlags: ;SetWinFlags for window in A0
move.l wd_UserData(a0),a0
lea we_Flags(a0),a0
and.l d1,d0
not.l d1
and.l d1,(a0)
or.l d0,(a0)
rts
GetActiveWin: ;Get address of currently active window to D0.
pstart2
moveq #0,d0
intcall LockIBase
move.l ib_ActiveWindow(a6),-(a7)
move.l d0,a0
call UnlockIBase
move.l (a7)+,d0
ret2
SetCoords: ;Set coordinates of current window to (D0,D1). Null
; values leave the coordinate unchanged. Assumes
; there really is a current window - if not, up comes
; InternalErr.
pstart2
movem.l d2-d3,-(a7)
moveq #0,d2
moveq #0,d3
move.l d0,-(a7)
dmove.l CurIwindow,a0
move.l a0,d0
beq .usescr
move.b wd_BorderLeft(a0),d2
move.b wd_BorderTop(a0),d3
bra .gotwin
.usescr dmove.l CurIscreen,a0
move.l a0,d0
bne .okscr
move.l #$53436F0C,d1
bsr InternalErr
.okscr
; tst.l sc_DefaultTitle(a0)
; beq .nottl
; move.b sc_BarHeight(a0),d3
; add.b sc_BarVBorder(a0),d3
.nottl move.l sc_UserData(a0),a0
move.l se_BaseWin(a0),a0
.gotwin move.l (a7)+,d0
move.l wd_RPort(a0),a1
cmp.l #Null,d0
beq .nox
add.w d2,d0
bra .gotx
.nox move.w rp_cp_x(a1),d0
.gotx cmp.l #Null,d1
beq .noy
add.w d3,d1
bra .goty
.noy move.w rp_cp_y(a1),d1
.goty gfxcall Move
moveq #0,d0
moveq #WEF_UNSET,d1
bsr SetWinFlags
movem.l (a7)+,d2-d3
ret2
SetCoordsRel: ;Move CP by (x,y) [delta].
pstart2
move.l d0,-(a7)
bsr GetCurRP
move.l d0,a1
move.l (a7)+,d0
bsr GetWinFlags
btst #WEB_UNSET,d0
bne .exit ;If CP not set, can't move
add.w rp_cp_x(a1),d0
add.w rp_cp_y(a1),d1
gfxcall Move
.exit ret2