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-8170840445m@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.