		TTL		CLI-Colors
*
*******************************************************************************
*									      *
*	CLI-Colors							      *
*									      *
*	Copyright (c) 1987-89 by Michael Sinz    MKSoft Development	      *
*									      *
*	AmigaDOS EXEC release 1.2 or greater...				      *
*									      *
*******************************************************************************
*									      *
*	To assemble, I used the Amiga Macro Assembler			      *
*									      *
*	It should assemble without any problems on most Amiga assemblers      *
*									      *
*******************************************************************************
*									      *
*	The code is position independant and fully re-entrant.  Thus you      *
*	can use this as RESIDENT code.  You should set the PURE bit to	      *
*	mark this executable as such.					      *
*									      *
*******************************************************************************
*									      *
*	Reading legal mush can turn your bain into guacamole!		      *
*									      *
*		So here is some of that legal mush:			      *
*									      *
* Permission is hereby granted to distribute this program's source	      *
* executable, and documentation for non-comercial purposes, so long as the    *
* copyright notices are not removed from the sources, executable or	      *
* documentation.  This program may not be distributed for a profit without    *
* the express written consent of the author Michael Sinz.		      *
*									      *
* This program is not in the public domain.				      *
*									      *
* Fred Fish is expressly granted permission to distribute this program's      *
* source and executable as part of the "Fred Fish freely redistributable      *
* Amiga software library."						      *
*									      *
* Permission is expressly granted for this program and it's source to be      *
* distributed as part of the Amicus Amiga software disks, and the	      *
* First Amiga User Group's Hot Mix disks.				      *
*									      *
*******************************************************************************
*
* The following INCLUDE files are needed to make this program assemble.
* They come with Amiga Macro-Assembler Packages and the developer updates.
*
	NOLIST					; No need to list these
	INCLUDE	"EXEC/Types.i"
	INCLUDE	"EXEC/Libraries.i"
	INCLUDE	"EXEC/Ables.i"
	INCLUDE	"EXEC/EXECbase.i"
	INCLUDE	"EXEC/funcdef.i"
	INCLUDE	"EXEC/EXEC_lib.i"
	INCLUDE	"Libraries/DOSextens.i"
	INCLUDE	"Intuition/IntuitionBase.i"
	INCLUDE	"Intuition/Intuition.i"
	LIST					; Ok, lets start the listing
*
*******************************************************************************
*
* We need to define a structure that has StandardPacket and InfoData in it...
* This is used when we send the packet to the console device for our window
* in order to find the Intuition Window Pointer for it...
*
	STRUCTURE		FindWindow,0
			STRUCT	FW_Pack,sp_SIZEOF
			STRUCT	FW_Info,id_SIZEOF
			LABEL	FW_SIZEOF
*
*******************************************************************************
*
* This is the only fixed address in the system...
*
		xref	_AbsExecBase
*
*******************************************************************************
*
* Some macros that make calling the system routines easier...
*
CALLSYS		MACRO
		xref	_LVO\1		; Set the external reference
		CALLLIB	_LVO\1		; Call the EXEC definied macro
		ENDM
*
*******************************************************************************
*									      *
* Register usage through this system...					      *
*									      *
*	a0	- Scrap							      *
*	a1	- Scrap							      *
*	a2	- Pointer to FW_Info					      *
*	a3	- EXEC base save					      *
*	a4	- Task							      *
*	a5	- FindWindow struct					      *
*	a6	- ExecBase / IntuitionBase				      *
*	a7	- Stack pointer...  What else?				      *
*									      *
*	d0	- Scrap							      *
*	d1	- Scrap							      *
*	d2	- Window pointer					      *
*	d3	- pr_Console handler					      *
*	d4	- Block pen color					      *
*	d5	- Detail pen color					      *
*	d6	- CLI Task number (Used to make the colors)		      *
*	d7	- Zero...						      *
*									      *
*******************************************************************************
*
CLIColors:	move.l	_AbsExecBase,a6		; Get EXECbase...
		move.l	a6,a3			; Save it in a3 for later...
		moveq.l	#0,d7			; Clear our ZERO register...
		move.l	d7,a1			; Clear a1 for find-task...
		CALLSYS	FindTask		; Get our task...
		move.l	d0,a4			; Store the task...
		tst.l	pr_CLI(a4)		; Check if started from CLI
		bne.s	FromCLI			; If from CLI, all ok...
*
*******************************************************************************
*
* Since this program is to change CLI colors, if started from WorkBench, we
* will just exit cleanly...
*
		lea	pr_MsgPort(a1),a0	; Get message port...
		move.l	a0,a2			; Temp Storage...
		CALLSYS	WaitPort		; wait for WorkBench message...
		move.l	a2,a0			; Get message port again...
		CALLSYS	GetMsg			; Get the message...
		move.l	d0,a1			; Put message into a1
		FORBID
						; You must FORBID before
		CALLSYS	ReplyMsg		;    returning the WB message.
		rts				; And exit...
*
*******************************************************************************
*
* So, we are a CLI task, so lets generate the colors we want...
*
FromCLI:	move.l	pr_TaskNum(a4),d6	; Get CLI task number...
		move.l	d6,d4			; Get the task number...
		andi.w	#3,d4			; Mask out most of it...
		ori.w	#2,d4			; Color should be 2 or 3...
		move.l	d6,d5			; Get task number...
		addq.l	#1,d5			; Add 1...
		asr.w	#1,d5			; Divide by 2...
		add.w	d4,d5			; Add the other color...
		andi.w	#3,d5			; There are only 2-bit planes
		cmp.w	d5,d4			; Check if they are the same...
		bne.s	ColorIt			; If not, all ok...
		moveq	#1,d4			; Set BlockPen to 1...
*
*******************************************************************************
*
* Now to find the window...	Need to send packet...  :-(
*
ColorIt:	move.l	pr_ConsoleTask(a4),d3	; Get console task...
		beq	ErrorExit		; Exit if no console task...
*
*******************************************************************************
*
* This is my little Packet Sending code.  In this case, I have defined a
* new structure that contains the StandardPacket structure and the InfoData
* structure needed for this call.  For quick work and smaller code, I allocate
* the packet from the stack.  Since packets *MUST* be long word aligned, a bit
* of work must be done to make sure that the memory is aligned...
*
		lea	-(FW_SIZEOF+4)(sp),sp	; Move stack to allocate space
*
* I allocate 4 bytes more than needed since I may need to move the pointer
* a bit.  I could actually do this by allocating 2 bytes more since
* the stack is always word aligned.  However, if the stack is long-word
* aligned, I want to keep it that way since code runs faster on the 68020/030
* when the stack is long-word aligned.
*
* As you can see, the address we get from the stack is then bumped by 3 and
* then the bottom 2 bits are cleared.  The new address is then either
* the original or 2 bytes further down the stack.  (Stack was already
* word aligned so those are the only possibilities.)
*
		move.l	sp,d1			; Get address
		addq.l	#3,d1			;   and make sure
		and.b	#$FC,d1			;   it is long word aligned
		move.l	d1,a5			; Point to the thing...
*
* Ok, so we have a packet at a5.  Now, we need to set the stange links
* that packets use.  Address of the packet gets stored in the messages
* list node name pointer  (??Weird stuf??)  and the packet's link stores
* the pointer to the message structure...
*
		lea	(FW_Pack+sp_Pkt)(a5),a1	; Get adress of FW_Pack.sp_Pkt
		move.l	a1,(FW_Pack+sp_Msg+LN_NAME)(a5)	; Store sp_Pkt in name
		move.l	a5,(FW_Pack+sp_Pkt+dp_Link)(a5)	; Store sp_Msg in link
*
* Packets are weird in that the packet reply port is not the standard
* message reply port (packets use their own reply methods...)
*
		lea	pr_MsgPort(a4),a0	; Set the reply port...
		move.l	a0,(FW_Pack+sp_Pkt+dp_Port)(a5)
*
* To get the address of the window a console task has, we do a packet
* of type ACTION_DISK_INFO.  (?!?)  This packet type takes a special
* InfoData structure that will contain the results of this call.
*
		move.l	#ACTION_DISK_INFO,(FW_Pack+sp_Pkt+dp_Type)(a5)
*
* So, we now have to set up a pointer to the InfoData structure.  However,
* this pointer is defined (due to BCPL AmigaDOS) as a BCPL pointer.  These
* pointers are simply the address of the item pointed to left-shifted 2.
* In other words, the bottom two bits are dropped.  This is why all of the
* AmigaDOS structures MUST BE long word aligned.  AmigaDOS can not address
* (via BCPL) non-long word addresses.
*
		lea	FW_Info(a5),a2		; InfoData structre address
		move.l	a2,d2
		asr.l	#2,d2			; Make BPTR out of it...
		move.l	d2,(FW_Pack+sp_Pkt+dp_Arg1)(a5)
*
* Ok, the packet is set up and ready to go.  We take our reply port
* (which is still in a0 from the steps above) and store it in a register
* that will not get modified by the call.  Then we just send the packet
* and wait for it to return.
*
		move.l	a0,d2		; Save our port address
		move.l	d3,a0		; Get console port address
		move.l	a5,a1		; Get message packet address
		CALLSYS	PutMsg		; Send Packet
		move.l	d2,a0		; Our message port...
		CALLSYS	WaitPort	; Wait for return
		move.l	d2,a0		; Restore it again...
		CALLSYS	GetMsg		; Get it from the port
*
* The packet came back and we should now do some testing for errors.
*
		move.l	id_VolumeNode(a2),d2		; Get window
		move.l	(FW_Pack+sp_Pkt+dp_Res1)(a5),d0	; Check return code...
		lea	(FW_SIZEOF+4)(sp),sp	; Move stack to deallocate
		addq.l	#1,d0			; Bump TRUE return to 0...
		bne.s	ErrorExit		; Exit if returned error...
		tst.l	d2			; Check the window...
		beq.s	ErrorExit		; Do color if there is one...
*
*******************************************************************************
*
ColorOk:	lea	intuitionName(pc),a1	; Now open Intuition...
		move.l	d7,d0			; ANY version will do...
		CALLSYS	OpenLibrary		; Open it...
		move.l	d0,a6			; Save it as our pointer...
		tst.l	d0			; Check it...
		beq.s	ErrorExit		; If none, exit...
		move.l	d2,a0			; Window into address register
		move.b	d5,wd_DetailPen(a0)	; Store the colors
		move.b	d4,wd_BlockPen(a0)	;   that we just made...
		CALLSYS	RefreshWindowFrame	; Refresh it...
*
*******************************************************************************
*
* Now, close intuition and we are done...
*
NoWindow:	move.l	a6,a1			; Get intuitionbase...
		move.l	a3,a6			; (Get execbase back...)
		CALLSYS	CloseLibrary
*
*******************************************************************************
*
ErrorExit:	move.l	d7,d0			; Clear return result
		rts				; Exit...
*
*******************************************************************************
*
* Data...
*
intuitionName:	dc.b	'intuition.library',0
*
*******************************************************************************
*
* And, with that we come to the end of another full-length feature staring
* that wonderful MC680x0 and the Amiga system.  Join us again next time
* for more Wonderful World of Amiga...  Until next time, keep boinging...
*
		END
