[comp.sys.amiga] System Wedges and Overscan for V1.2/V1.2.1

bart@amiga.UUCP (Barry A. Whitebook) (11/18/87)

[ eat this source -- please!]

this is amiga!bart:

this demo code was written as ONE (of many possible examples) way of supporting
overscan mouse limits under V1.2 or V1.2.1... it features a new idea of multi-
tasking friendly "wedges" whose primary purpose is to avoid the complications
involved in SetFunction() contention among various processes.

------------------------------- cut here -------------------------------------

#define	INTUITIONPRIVATE

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <graphics/gfx.h>
#include <clib/macros.h>
#include <graphics/view.h>
#include <graphics/gfxbase.h>
#include <graphics/text.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>

#ifdef DEBUG
#define KPRINTF
#endif

#ifdef KPRINTF
#define printf kprintf
#endif

#define DEPTH   2

#define IS_PAL  (((struct GfxBase *)GfxBase)->DisplayFlags & PAL)
#define IS_NTSC (((struct GfxBase *)GfxBase)->DisplayFlags & NTSC)

#define NORMAL_HEIGHT (((struct GfxBase *)GfxBase)->NormalDisplayRows)
#define NORMAL_WIDTH  (((struct GfxBase *)GfxBase)->NormalDisplayColumns)

#define OVERSCAN_WIDTH	704
#define OVERSCAN_HEIGHT 236

#define WINDOW_FLAGS  (ACTIVATE|SIMPLE_REFRESH|BORDERLESS|BACKDROP|RMBTRAP)
#define IDCMP_FLAGS   (ACTIVEWINDOW|INACTIVEWINDOW|MOUSEBUTTONS|MOUSEMOVE)

#define MIN_WIDTH   30
#define MIN_HEIGHT  20

#define ALL_PLANES 0xFF
#define FIRST_PLANE 0x01

#define V1_POINT_2  33
#define V1_POINT_2_POINT_1  34

#define MAXBYTES	256

#define JSR_ABS	0x4EB9
#define JSR_dPC	0x4EBA

#define JMP_ABS	0x4EF9
#define JMP_dPC	0x4EFA

#define	RTS		0x4E75

struct Wedge {
	UWORD	wedge_Vectors[6];
	struct 	Library	wedge_Library;
	WORD	wedge_Offset;
} ;


UBYTE stringbuffer[MAXBYTES] =  {NULL};

UBYTE PAL_STRING[] = 
"this is a PAL machine...";
UBYTE NTSC_STRING[] = 
"this is an NTSC machine...";
UBYTE ACTIVE_STRING[] = 
"this window is active...";
UBYTE INACTIVE_STRING[] = 
"this window is inactive...";
UBYTE SELECTUP_STRING[] = 
"the select button is up...";
UBYTE SELECTDOWN_STRING[] = 
"the select button is down...";
UBYTE MOUSEPOSITION_STRING[] = 
"the mouse position is: x = %u y = %u ...";
UBYTE TRAPDEBUG_STRING[] = 
"trapping lib = %lx offset = %ld ...";
UBYTE MENUDOWN_STRING[] = 
"the menu button is down, about to close the screen...";
UBYTE MOUSEBOUNDS_STRING[] = 
"mousebounds for this screen are : xmax = %u ymax = %u ...";


extern ULONG ibase_lock;
extern struct  ExecBase *SysBase;

extern ULONG trap_function();
extern ULONG wedge;
extern LONG LVOObtainSemaphore;
extern WORD old_mousebounds[];
extern WORD new_mousebounds[];

struct  GfxBase *GfxBase;
struct  IntuitionBase *IntuitionBase;
struct  Screen  *test_screen=NULL;
struct  Window  *test_window=NULL;
struct  NewScreen newscreen;
struct  NewWindow newwindow;
struct  Window  *OpenWindow();
struct  Screen  *OpenScreen();

struct  TextAttr Font =
{
    "topaz.font",
    8,
    FS_NORMAL,
    FPF_ROMFONT,
};

UWORD x_pos= MIN_WIDTH, y_pos= MIN_HEIGHT;

/*****************************************************************************
*
*	overscan -- open an overscan screen under V1.2 or V1.2.1 and
*				install a trap to intercept calls to LockIBase()
*				set the mouse limits so that when the overscan screen
*				is first, the mouse can move to the overscan limits:
*				when another screen is first, restore the system limits...
*
*****************************************************************************/

overscan()
{
    int error = FALSE;
    USHORT view_modes = NULL;
    struct  IntuiMessage    *message;

    if ((GfxBase = (struct  GfxBase *)
        OpenLibrary("graphics.library",V1_POINT_2)) == NULL)
    {
        return(-1);
    }


    if(	((IntuitionBase = (struct  IntuitionBase *)
		OpenLibrary("intuition.library",V1_POINT_2)) == NULL)
	  )
    {
        CloseLibrary(GfxBase);
        return(-2);
    }

	if(IntuitionBase->LibNode.lib_Version > V1_POINT_2_POINT_1)
    {
        CloseLibrary(IntuitionBase);
        CloseLibrary(GfxBase);
        return(-3);
    }

    /* values for newscreen */

    newscreen.LeftEdge  = 0;
    newscreen.TopEdge   = 0;
    newscreen.Width     = OVERSCAN_WIDTH;
    newscreen.Height    = OVERSCAN_HEIGHT;
    newscreen.Depth     = DEPTH;
    newscreen.DetailPen = 0xff;
    newscreen.BlockPen  = 0xff;

    /* specify view_modes */

    if(OVERSCAN_WIDTH > 320)  view_modes |= HIRES;

    newscreen.ViewModes = view_modes;

    newscreen.Type      = CUSTOMSCREEN;
    newscreen.Font      = &Font;
    newscreen.DefaultTitle  = NULL;
    newscreen.Gadgets   = NULL;

    test_screen = OpenScreen(&newscreen);

    if (test_screen == 0)
    {
        CloseLibrary(IntuitionBase);
        CloseLibrary(GfxBase);
        return(-4);
    }
	else
	{
		ShowTitle(test_screen,FALSE);
	}

    newwindow.LeftEdge  = 0;
    newwindow.TopEdge   = 0;
    newwindow.Width     = test_screen->Width;
    newwindow.Height    = test_screen->Height;
    newwindow.DetailPen = 11;
    newwindow.BlockPen  = 11;
    newwindow.Flags     = WINDOW_FLAGS;
    newwindow.IDCMPFlags    = IDCMP_FLAGS;
    newwindow.FirstGadget   = NULL;
    newwindow.CheckMark = NULL;
    newwindow.Title     = NULL;
    newwindow.Screen    = test_screen;
    newwindow.BitMap    = NULL;
    newwindow.MinWidth  = MIN_WIDTH;
    newwindow.MinHeight = MIN_HEIGHT;
    newwindow.MaxWidth  = test_screen->Width;
    newwindow.MaxHeight = ~0;   
	/* V1_POINT_2 : tell Intuition to limit the   */
    /* maximum height of this window to screen's  */
    /* height                                     */

    newwindow.Type      = CUSTOMSCREEN;

    test_window = OpenWindow(&newwindow);   

    if(!test_window)
    {
        CloseScreen(test_screen);
        CloseLibrary(IntuitionBase);
        CloseLibrary(GfxBase);
        return(-5);
    }
	else
	{
		fill_window(test_window,ALL_PLANES);
	}

	/* trap to act before screens change */

	print_message
		(test_window->RPort,trapdebug_string(SysBase,&LVOObtainSemaphore));

	/* initialize lock comparison */
	ibase_lock = (ULONG) &IntuitionBase->ISemaphore[IBASELOCK];

	/* protect ourselves */
	LockIBase(0);

	/* save current limits */
	save_mousebounds();

	/* proceed to mess with intuition's fields via the installed trap */
	UnlockIBase(0);

	{
		/* store new limits */
		new_mousebounds[0] = 0;
		new_mousebounds[1] = (view_modes & HIRES)?
							 (test_screen->Width)-1:
							 (test_screen->Width<<1)-1;

		new_mousebounds[2] = 0;
		new_mousebounds[3] = (view_modes & LACE)?
							 (test_screen->Height)-1:
							 (test_screen->Height<<1)-1;

		print_message(test_window->RPort,mousebounds_string(new_mousebounds));
	}

	/* special function will only be executed while ibase_lock is free */
	trap(SysBase,&LVOObtainSemaphore);

    /* tell the user whether we are pal or ntsc */

    error = print_pal_or_ntsc_message(test_window->RPort);

    /* now wait for close message */

WAIT_LOOP:

    /* be nice, let other tasks run */

    WaitPort(test_window->UserPort);

    /* ok, now look at all the messages that have arrived */

    while((message=(struct IntuiMessage *)GetMsg(test_window->UserPort))!=NULL)
    {
        switch(message ->Class)
        { 
			case ACTIVEWINDOW:            
			{
				print_message(test_window->RPort,ACTIVE_STRING);
            }break;
			case INACTIVEWINDOW:            
			{
				print_message(test_window->RPort,INACTIVE_STRING);
            }break;
			case MOUSEBUTTONS:            
			{
				switch(message->Code)
				{
					case SELECTDOWN:            
					{
						print_message
							(test_window->RPort,SELECTDOWN_STRING);
						print_message
							(test_window->RPort,
							 mousebounds_string(new_mousebounds));
						print_message 
							(test_window->RPort,mouseposition_string(message));
					}break;
					case SELECTUP:            
					{
						print_message(test_window->RPort,SELECTUP_STRING);
					}break;
					case MENUDOWN:            
					{
						print_message(test_window->RPort,MENUDOWN_STRING);
					}break;
					case MENUUP:            
					{
						ReplyMsg(message);
						CloseWindow(test_window);
						CloseScreen(test_screen); 
						CloseLibrary(IntuitionBase);
						CloseLibrary(GfxBase);
						untrap(SysBase,&LVOObtainSemaphore);
						return(error);
					}break;
				}
            }break;
			case MOUSEMOVE:            
			{
            }break;
			default:            
			{
            }break;
        } 
        ReplyMsg(message);
    }

    goto WAIT_LOOP;

}   

/*****************************************************************************
*
*	support utilities -- handle the details...
*
*****************************************************************************/

trap(lib,offset)
struct Library *lib;
WORD offset;
{
	if((lib)&&(offset<0))
	{
		wedge = install_wedge(lib,offset,trap_function);
	}
}

untrap(lib,offset)
struct Library *lib;
WORD offset;
{
	remove_wedge(wedge);
}

strlen(strptr)
UBYTE *strptr;
{
    unsigned int count = 0;

    while(*strptr != NULL)
    {
        count++;
        strptr++;
    }

    return(count);
}

Position(rp,xp,yp)
struct RastPort *rp;
UWORD *xp, *yp;	
{
	UWORD old_yp = *yp;
	if((*yp=MAX(MIN_HEIGHT,(old_yp+Font.ta_YSize)%test_screen->Height))<old_yp)
	{
		fill_window(test_window,ALL_PLANES);
	}
	Move(rp,*xp,*yp);
}

fill_window(w,planes)
struct Window *w;
UBYTE planes;
{
	struct RastPort *rp;
	struct BitMap *bm;
	if( (w) && (rp=w->RPort) && (bm=rp->BitMap) )
	{
		SetDrMd(rp,JAM1);
		SetAPen(rp,planes);
		RectFill(rp,0,0,((bm->BytesPerRow<<3)-1),(bm->Rows-1));
	}
}

print_pal_or_ntsc_message(rp)
struct RastPort *rp;
{
    int error = FALSE;

    if(IS_PAL)  print_message(rp, PAL_STRING);
    if(IS_NTSC) print_message(rp, NTSC_STRING);

    if((IS_PAL) && (IS_NTSC)) error = TRUE;

    return(error);
}

print_message(rp,string)
struct RastPort *rp;
STRPTR string;
{
    int error = FALSE;

    SetDrMd(rp,JAM1);
    SetAPen(rp,FIRST_PLANE);

    Position(rp,&x_pos,&y_pos);

    Text(rp, string, strlen(string) );

    return(error);
}

mousebounds_string(mb)
WORD mb[];
{
	sprintf(stringbuffer,MOUSEBOUNDS_STRING,mb[1],mb[3]);
	return((int)stringbuffer);
}

mouseposition_string(msg)
struct IntuiMessage *msg;
{
	sprintf(stringbuffer,MOUSEPOSITION_STRING,msg->MouseX,msg->MouseY);
	return((int)stringbuffer);
}

trapdebug_string(lib,offset)
struct Library *lib;
WORD offset;
{
	sprintf(stringbuffer,TRAPDEBUG_STRING,lib,offset);
	return((int)stringbuffer);
}

save_mousebounds()
{
	int i = 4;
	WORD *op = old_mousebounds;
	WORD *ml = (WORD *)&IntuitionBase->MinXMouse;

	/* save current limits */
	while(i--) { *op++ = *ml++; }
}

store_mousebounds()
{
	int i = 4;
	WORD *np = new_mousebounds;
	WORD *nl = (WORD *)&IntuitionBase->MinXMouse;

	/* stuff new limits */
	while(i--) { *nl++ = *np++; }
}

restore_mousebounds()
{
	int i = 4;
	WORD *op = old_mousebounds;
	WORD *ml = (WORD *)&IntuitionBase->MinXMouse;

	/* restore current limits */
	while(i--) { *ml++ = *op++; }

	IntuitionBase->MouseX = MAX(IntuitionBase->MouseX,IntuitionBase->MinXMouse);
	IntuitionBase->MouseX = MIN(IntuitionBase->MouseX,IntuitionBase->MaxXMouse);

	IntuitionBase->MouseY = MAX(IntuitionBase->MouseY,IntuitionBase->MinYMouse);
	IntuitionBase->MouseY = MIN(IntuitionBase->MouseY,IntuitionBase->MaxYMouse);
}


/*****************************************************************************
*
*	wedge utilities -- create, install, remove and delete system friendly
*					   wedges that can exist in a multitasking environment.
*
*****************************************************************************/

new_wedge()
{
	struct Wedge *wp = NULL;

	/* allocate a wedge */

	if(wp=(struct Wedge *)AllocMem(sizeof(struct Wedge),MEMF_PUBLIC|MEMF_CLEAR))
	{
		/* initialize the wedge library to default values */

		wp->wedge_Library.lib_Node.ln_Type = NT_LIBRARY;
		wp->wedge_Library.lib_NegSize = 12;
		wp->wedge_Library.lib_PosSize = sizeof(struct Library)+sizeof(WORD);
		wp->wedge_Library.lib_Version = 35;
		wp->wedge_Library.lib_Revision = 1;

		/* initialize the wedge vectors to default values */

		wp->wedge_Vectors[0] = JSR_dPC;
		wp->wedge_Vectors[1] = 0x0004;
		wp->wedge_Vectors[2] = RTS;

		wp->wedge_Vectors[3] = JMP_dPC;
		wp->wedge_Vectors[4] = 0x0002;
		wp->wedge_Vectors[5] = RTS;
	}

	return((ULONG)wp);
}

dispose_wedge(wp)
struct Wedge *wp;
{
	if (wp) FreeMem(wp,sizeof(struct Wedge));
}

test_wedge(wp)
struct Wedge *wp;
{
	ULONG is_wedge = NULL;
	UBYTE *pred;

	/* make certain that wp is not odd -- it will be if wp == default vector */

	if(((ULONG)wp)^1)
	{
		if(wp->wedge_Library.lib_Node.ln_Type == NT_LIBRARY)
		{
			if(pred = wp->wedge_Library.lib_Node.ln_Pred)
			{
				if(((ULONG)pred)^1)
				{
					if(wp==(struct Wedge *)*(ULONG *)(pred+wp->wedge_Offset+2))
					{
						is_wedge = (ULONG)wp;
					}
				}
			}
		}
	}
	return(is_wedge);
}

link_wedge(lib,offset,wedge)
UBYTE *lib;
WORD offset;
struct Wedge *wedge;
{
	ULONG is_wedge = NULL;
	struct Wedge *owp;
	UBYTE *pred;

	if(owp = (struct Wedge *)test_wedge(*(ULONG *)(lib+offset+2)))
	{
		is_wedge = (ULONG)owp;
		owp->wedge_Library.lib_Node.ln_Pred = wedge;
		owp->wedge_Offset = -6;
	}
	return(is_wedge);
}

delink_wedge(lib,offset,wp)
UBYTE *lib;
WORD offset;
struct Wedge *wp;
{
	struct Wedge *owp = NULL;
	struct Wedge *nwp;

	if(wp)
	{
		/* prevent unpleasant suprises */

		Disable();

		/* is this still a valid wedge? */

		if(owp = (struct Wedge *)test_wedge(wp))
		{
			struct Library *pred = owp->wedge_Library.lib_Node.ln_Pred;

			/* yes, valid. does this wedge point to another wedge? */

			if( nwp = (struct Wedge *)
					test_wedge(*(ULONG *)(&owp->wedge_Vectors[4]))
			  )
			{
				nwp->wedge_Library.lib_Node.ln_Pred = pred;
			}

			/* does the previous library point to this wedge's library */

			if(pred->lib_Node.ln_Succ == &owp->wedge_Library)
			{
				/* yes, make previous library point to next wedge's library */

				pred->lib_Node.ln_Succ == &nwp->wedge_Library;
			}

			/* make previous vector point to next vector */	

			SetFunction( wp->wedge_Library.lib_Node.ln_Pred,
						 wp->wedge_Offset,
						 *(ULONG *)(&wp->wedge_Vectors[4]));
		}
		else
		{
			/* not validated... */
			/* assume both that has been setfunction'ed away, */
			/* and may be setfunction'ed back in the near future: */
			/* so replace current vector with default... */

			wp->wedge_Vectors[0] = JSR_dPC;
			wp->wedge_Vectors[1] = 0x0004;
			wp->wedge_Vectors[2] = RTS;
		}

		/* suprises ok now, i guess... */
		Enable();
	}

	return((ULONG)owp);
}

install_wedge(lib,offset,entry)
struct Library *lib;
WORD offset;
ULONG entry;
{
	struct Wedge *wp = NULL;

	if( (entry) && (wp = (struct Wedge *)new_wedge()) )
	{
		/* prevent unpleasant suprises */

		Disable();

		/* point this wedge at our new entry */

		wp->wedge_Vectors[0] = JSR_ABS;
		*(ULONG *)(&wp->wedge_Vectors[1]) = entry;

		/* point this wedge at the previous entry */

		wp->wedge_Library.lib_Node.ln_Pred = lib;
		wp->wedge_Offset = offset;

		/* link this wedge to existing wedge? */

		wp->wedge_Library.lib_Node.ln_Succ = 
			(struct Node *) link_wedge(lib,offset,wp);

		/* install this wedge in place of the old entry */

		wp->wedge_Vectors[3] = JMP_ABS;
		*(ULONG *)(&wp->wedge_Vectors[4]) = SetFunction(lib,offset,wp);

		/* suprises ok now, i guess... */

		Enable();
	}

	return((ULONG)wp);
}

remove_wedge(wedge)
struct Wedge *wedge;
{
	dispose_wedge(delink_wedge(wedge));
}

/*****************************************************************************
*
*	main -- open a screen as large as possible and print a message in it
*
*****************************************************************************/

main()
{
    int error = FALSE;

    error = overscan();

    /* success, or a negative code to indicate a failure.            */
    /* exit and return an appropriate success/failure code to system */

    exit(error);
}

/*****************************************************************************
*
*	trap function -- assembly language routine to install as a wedge
*					 intercept calls to LockIBase... avoid recursion
*
******************************************************************************

	INCLUDE	"exec/types.i"
	INCLUDE	"exec/nodes.i"
	INCLUDE	"exec/lists.i"
	INCLUDE	"exec/semaphores.i"
	INCLUDE	"intuition/intuitionbase.i"

	XREF	_save_mousebounds
	XREF	_store_mousebounds
	XREF	_restore_mousebounds

	XREF	_IntuitionBase
	XREF	_test_screen

	XDEF	_wedge
	XDEF	_trap_function
	XDEF	_ibase_lock
	XDEF	_old_mousebounds
	XDEF	_new_mousebounds
	XDEF	store_flag
	XDEF	restore_flag

	CNOP	0,4	; make sure vector is long word aligned

_wedge:

	DC.L	-1

_ibase_lock:

	DC.L	-1

_old_mousebounds:

	DC.W	0
	DC.W	0
	DC.W	0
	DC.W	0

_new_mousebounds:

	DC.W	0
	DC.W	0
	DC.W	0
	DC.W	0

local_flag:
	DC.L	-1

store_flag:
	DC.L	-1

restore_flag:
	DC.L	-1

_trap_function:

	MOVEM.L	D0-D1/A0-A1,-(SP)		; your mileage may vary...
	LEA.L	_ibase_lock,A1
	CMPA.L	(A1),A0					; are we about to obtain ibase_lock ?
	BNE.S	not_free
	MOVE.L	(A1),A1	
	TST.W	SS_QUEUECOUNT(A1) 		; is it currently unlocked ?
	BGE.S	not_free

	MOVE.L	_IntuitionBase,A1		; get ibase
	MOVE.L	ib_FirstScreen(A1),A0	; pointer to the first_screen 
	CMPA.L	_test_screen,A0			; is it us ? 
	BNE.S	not_first

	LEA.L	local_flag,A1				; are we recursing ?
	ADDQ.L	#1,(A1) 
	BNE.S	not_again

	LEA.L	store_flag,A1			; must keep poking until not first
	TST.L	(A1) 
	BEQ.S	not_increment
	ADDQ.L	#1,(A1) 

	LEA.L	_save_mousebounds,A0	; save current bounds then swap in new ones
	JSR		(A0)

not_increment:

	LEA.L	restore_flag,A1			; toggle flags
	MOVE.L	#-1,(A1) 				; reset

	LEA.L	_store_mousebounds,A0	; swap in new mousebounds (again)
	JSR		(A0)

not_again:

	LEA.L	local_flag,A1
	SUBQ.L	#1,(A1) 
	BRA.S	not_free

not_first:

	LEA.L	local_flag,A1			; are we recursing ?
	ADDQ.L	#1,(A1) 
	BNE.S	not_again

	LEA.L	restore_flag,A1			; only need to restore once when not first
	TST.L	(A1) 
	BEQ.S	not_again

	ADDQ.L	#1,(A1) 
	LEA.L	store_flag,A1			; toggle flags
	MOVE.L	#-1,(A1) 				; reset

	LEA.L	_restore_mousebounds,A0
	JSR		(A0)

	BRA.S	not_again

not_free:

	MOVEM.L	(SP)+,D0-D1/A0-A1

	RTS
	
	END

***************************** end-of-file ***********************************/  

-- 
     //----------------------------------------------------- ----------\\
    //|  Bart Whitebook                                     | {|V|)))  |\\
      |                                                     | ()^()-)))|
      |  16795 Lark Avenue, Suite #106, Los Gatos, CA 95030 |  /_   ?))|
      |  UUCP: pyramid!oliveb!amiga!bart                    | { _ } )\ |
      |  BIX:  amiga_bart                                   | \   //   | 
    \\|_____________________________________________________|__\//____ |//
     \\                                                                //

keithd@cadovax.UUCP (Keith Doyle) (11/19/87)

Jeez, Bart, an incredible effort.  Thanks a million.

Now none of the rest of you guys better say anything about Commodore Amiga 
not being responsive to developers needs, or you're likely to get flamed
from me (if you're not already in my kill file).

Keith Doyle
#  {ucbvax,decvax}!trwrb!cadovax!keithd  Contel Business Systems 213-323-8170

840445m@aucs.UUCP (ALAN) (11/21/87)

	Hi again folks.  Just a quicky question about the Amiga 1000 
	expasion bus.  I am interested in developing a number of periph's
	for my Amiga.  I need some tech stuff on the bus, Zorro, Auto-Config,
	Pass - through , etc.,etc.  Do I have to get this form C=. If so do
	I have to pay to be a registered developer.  I am not really interested
	in marketing my projects (yet) I just want to "play" with everything
	my machine has to offer.  Could some one please tell me where a can
	get the above info.  Any one from C= A wish to divulge?
	
			Thanks in advance ......

==============================================================================
 		"The average mathematician should never forget
	 	    that INTUITION is the final authority "
		
				- J. Barkley Posser


			     __@_  \ 
			    / || \  |\         "Hang 10"
			      /\   /   \     
		       ______' |  /      \     - Alan W. McKay
			     --+#   	   \       #1 Amigan in N.S
			      /	     	     \          CANADA
~~~~~~~~~~~~~~~~~~~~~~~~~~~/                   ~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    Amy Tech  B.B.S  (902) 542 SWAK     Nighttime and when not using AMY.