Received: from j.cc.purdue.edu by VM.CC.PURDUE.EDU ; Thu, 23 Jun 88 08:02:49 EST
Received: by j.cc.purdue.edu (5.54/1.14)
    id AA08053; Thu, 23 Jun 88 08:00:39 EST
Date: Thu, 23 Jun 88 08:00:39 EST
From: ain@j.cc.purdue.edu (Patrick White)
Message-Id: <8806231300.AA08053@j.cc.purdue.edu>
To: fys-ma@fintuvm.BITNET
Subject: comp.sources.amiga:   sources/amiga/volume5/vscreen.s.sh.1of2
 
Newsgroups: comp.sources.amiga
Subject: vscreen (sources 1 of 2)
Keywords: virtuial, screen, superbitmap, uncompiled
Approved: ain@j.cc.purdue.edu    (Patrick White)
 
Program Name:    vscreen  (sources 1 of 2)
Submitted by:    dpvc@tut.cc.rochester.edu  (David P. Cervone)
Summary:    Make virtual screens lager than will fit on monitor.
Poster Boy:    Patrick White    (ain@j.cc.purdue.edu)
Archive Name:    sources/amiga/volume5/vscreen.s.sh.1of2.Z
tested but not compiled.
 
NOTES:
   The source is for Lattice -- I didn't even try compiling it.
   It is a bit messy when resizing in that it dosen't seem to send window
resize messages when you change the size of a window, or when you exit vscreen,
but it works otherwise.. I feel it might be useful despite these bugs so I'm
posting it anyway.
.
 
 
-- Pat White   (co-moderator comp.sources/binaries.amiga)
ARPA/UUCP: j.cc.purdue.edu!ain  BITNET: PATWHITE@PURCCVM  PHONE: (317) 743-8421
U.S.  Mail:  320 Brown St. apt. 406,    West Lafayette, IN 47906
 
========================================
 
#    This is a shell archive.
#    Remove everything above and including the cut line.
#    Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:    Shell Archiver
#    Run the following text with /bin/sh to create:
#    vScreen-Handler.lnk
#    vScreen.lnk
#    wList.lnk
#    wMax.lnk
#    wMove.lnk
#    wSize.lnk
#    vScreenStubs.a
#    vScreenStubs.o.uu
#    vScreen.h
#    vScreen-Handler.c
# This archive created: Wed Jun 22 11:34:42 1988
# By:    Patrick White (PUCC Land, USA)
echo shar: extracting vScreen-Handler.lnk '(120 characters)'
cat << \SHAR_EOF > vScreen-Handler.lnk
FROM vScreen-Handler.o+
     vScreenStubs.o
TO vScreen-Handler
LIB LIB:lc.lib+LIB:amiga.lib
NODEBUG
SMALLCODE
SMALLDATA
SHAR_EOF
if test 120 -ne "`wc -c vScreen-Handler.lnk`"
then
echo shar: error transmitting vScreen-Handler.lnk '(should have been 120
 characters)'
fi
echo shar: extracting vScreen.lnk '(118 characters)'
cat << \SHAR_EOF > vScreen.lnk
FROM LIB:c.o+
     vScreen.o+
     vScreenSetup.o
TO vScreen
LIB LIB:lc.lib+LIB:amiga.lib
NODEBUG
SMALLCODE
SMALLDATA
SHAR_EOF
if test 118 -ne "`wc -c vScreen.lnk`"
then
echo shar: error transmitting vScreen.lnk '(should have been 118 characters)'
fi
echo shar: extracting wList.lnk '(73 characters)'
cat << \SHAR_EOF > wList.lnk
FROM LIB:c.o+wList.o
TO wList
LIB LIB:lc.lib
NODEBUG
SMALLCODE
SMALLDATA
SHAR_EOF
if test 73 -ne "`wc -c wList.lnk`"
then
echo shar: error transmitting wList.lnk '(should have been 73 characters)'
fi
echo shar: extracting wMax.lnk '(71 characters)'
cat << \SHAR_EOF > wMax.lnk
FROM LIB:c.o+wMax.o
TO wMax
LIB LIB:lc.lib
NODEBUG
SMALLCODE
SMALLDATA
SHAR_EOF
if test 71 -ne "`wc -c wMax.lnk`"
then
echo shar: error transmitting wMax.lnk '(should have been 71 characters)'
fi
echo shar: extracting wMove.lnk '(73 characters)'
cat << \SHAR_EOF > wMove.lnk
FROM LIB:c.o+wMove.o
TO wMove
LIB LIB:lc.lib
NODEBUG
SMALLCODE
SMALLDATA
SHAR_EOF
if test 73 -ne "`wc -c wMove.lnk`"
then
echo shar: error transmitting wMove.lnk '(should have been 73 characters)'
fi
echo shar: extracting wSize.lnk '(87 characters)'
cat << \SHAR_EOF > wSize.lnk
FROM LIB:c.o+wSize.o
TO wSize
LIB LIB:lc.lib+LIB:amiga.lib
NODEBUG
SMALLCODE
SMALLDATA
SHAR_EOF
if test 87 -ne "`wc -c wSize.lnk`"
then
echo shar: error transmitting wSize.lnk '(should have been 87 characters)'
fi
echo shar: extracting vScreenStubs.a '(3382 characters)'
cat << \SHAR_EOF > vScreenStubs.a
        CSECT       text
 
        XREF        _myHandler
        XDEF        _myHandlerStub
 
        XREF        _cAutoRequest
        XREF        _cBuildSysRequest
        XREF        _cCloseScreen
        XREF        _cLoadView
        XREF        _cMoveSprite
 
        XDEF        _aAutoRequest
        XDEF        _aBuildSysRequest
        XDEF        _aCloseScreen
        XDEF        _aLoadView
        XDEF        _aMoveSprite
 
        XDEF        _AutoRequestJmpAddress
        XDEF        _BuildSysRequestJmpAddress
        XDEF        _CloseScreenJmpAddress
        XDEF        _LoadViewJmpAddress
        XDEF        _MoveSpriteJmpAddress
 
 
_aAutoRequest:
        MOVEM.L     D0-D7/A0-A6,-(SP)        ; save registers on stack
        MOVE.L      A0,-(SP)                 ; save window pointer
        JSR         _cAutoRequest            ; call our C AutoRequest
        ADD.L       #4,SP                    ; pop pointer
        MOVEM.L     (SP)+,D0-D7/A0-A6        ; restore registers
        JSR         _AutoRequestJmpAddress   ; JMP that we will fill in later
   _AutoRequestJmpAddress:
        RTS
 
 
_aBuildSysRequest:
        JSR         _BuildSysRequestJmpAddress  ; JMP that we will fill in later
   _BuildSysRequestJmpAddress:
        MOVEM.L     D0-D7/A0-A6,-(SP)           ; save registers on stack
        MOVE.L      D0,-(SP)                    ; save window pointer
        JSR         _cBuildSysRequest           ; call our C BuildSysRequest
        ADD.L       #4,SP                       ; pop pointer
        MOVEM.L     (SP)+,D0-D7/A0-A6           ; restore registers
        RTS
 
 
_aCloseScreen:
        MOVEM.L     D0-D7/A0-A6,-(SP)        ; save registers on stack
        MOVE.L      A0,-(SP)                 ; save Screen pointer
        JSR         _cCloseScreen            ; call our C CloseScreen
        ADD.L       #4,SP                    ; pop pointer
        MOVEM.L     (SP)+,D0-D7/A0-A6        ; restore registers
        JSR         _CloseScreenJmpAddress   ; JMP that we will fill in later
   _CloseScreenJmpAddress:
        RTS
 
 
_aLoadView:
        MOVEM.L     D0-D7/A0-A6,-(SP)      ; save registers on stack
        MOVE.L      A1,-(SP)               ; push view pointer
        JSR         _cLoadView             ; call our C LoadView
        ADD.L       #4,SP                  ; pop view pointer
        MOVEM.L     (SP)+,D0-D7/A0-A6      ; restore registers
        JSR         _LoadViewJmpAddress    ; JMP that we will fill in later
   _LoadViewJmpAddress:
        RTS
 
 
_aMoveSprite:
        MOVEM.L     D2-D7/A0-A6,-(SP)      ; save registers on stack
        MOVE.L      D1,-(SP)               ; push y value
        MOVE.L      D0,-(SP)               ; push x value
        MOVE.L      A1,-(SP)               ; push SimpleSprite pointer
        JSR         _cMoveSprite           ; call our C MoveSprite
        ADD.L       #4,SP                  ; pop SimpleSprite
        MOVE.L      (SP)+,D0               ; use modified x
        MOVE.L      (SP)+,D1               ; use modified y
        MOVEM.L     (SP)+,D2-D7/A0-A6      ; restore registers
        JSR         _MoveSpriteJmpAddress  ; JMP that we will fill in later
   _MoveSpriteJmpAddress:
        RTS
 
 
_myHandlerStub:
        MOVEM.L A0/A1,-(SP)
        JSR     _myHandler
        ADDQ.L  #8,SP
        RTS
 
        END
 
SHAR_EOF
if test 3382 -ne "`wc -c vScreenStubs.a`"
then
echo shar: error transmitting vScreenStubs.a '(should have been 3382
 characters)'
fi
echo shar: extracting vScreenStubs.o.uu '(1039 characters)'
cat << \SHAR_EOF > vScreenStubs.o.uu
begin 17 vScreenStubs.o
M```#YP````-V4V-R965N4W1U8G,```/H`````71E>'0```/I````*TCG__XOW
M"$ZY`````-_\````!$S??_].N0```!Q.=4ZY````)$CG__XO`$ZY`````-_\E
M````!$S??_].=4CG__XO"$ZY`````-_\````!$S??_].N0```%A.=4CG__XO?
M"4ZY`````-_\````!$S??_].N0```'9.=4CG/_XO`2\`+PE.N0````#?_```]
M``0@'R(?3-]__$ZY````G$YU2.<`P$ZY`````%"/3G4```/L````!0``````<
M``"8````<@```%0````@````&`````````/O@0``!%]C075T;U)E<75E<W0`1
M```````!````"($```5?8T)U:6QD4WES4F5Q=65S=`````````$````L@0``7
M!%]C0VQO<V538W)E96X````````!````1($```-?8TQO8616:65W```````!#
M````8H$```-?8TUO=F53<')I=&4````!````A($```-?;7E(86YD;&5R````"
M```!````I`$```1?;7E(86YD;&5R4W1U8@``````G@$```1?84%U=&]297%UD
M97-T``````````$```5?84)U:6QD4WES4F5Q=65S=````````!X!```$7V%#0
M;&]S95-C<F5E;@```````#P!```#7V%,;V%D5FEE=P``````6@$```-?84UO(
M=F53<')I=&4```!X`0``!E]!=71O4F5Q=65S=$IM<$%D9')E<W,``````!P!\
M```'7T)U:6QD4WES4F5Q=65S=$IM<$%D9')E<W,``````"0!```&7T-L;W-EK
M4V-R965N2FUP061D<F5S<P``````6`$```5?3&]A9%9I97=*;7!!9&1R97-S2
M`````'8!```&7TUO=F53<')I=&5*;7!!9&1R97-S````````G`````````/RH
``
end
SHAR_EOF
if test 1039 -ne "`wc -c vScreenStubs.o.uu`"
then
echo shar: error transmitting vScreenStubs.o.uu '(should have been 1039
 characters)'
fi
echo shar: extracting vScreen.h '(4685 characters)'
cat << \SHAR_EOF > vScreen.h
/*
 *  VSCREEN.C       Creates virtual screens that can be larger than
 *                  the actual display area of your monitor.  The virtual
 *                  screen scrolls when the mouse moves off the edge of
 *                  the display.
 *
 *                  Copyright 1988 by Davide P. Cervone, all rights reserved.
 *
 *                  You may may distibute this code as is, for non-commercial
 *                  purposes, provided that this notice remains intact and the
 *                  documentation file is distributed with it.
 *
 *                  You may not modify this code or incorporate it into your
 *                  own programs without the permission of the author.
 */
 
/*
 *  WARNING:  This code uses and even modifies the INTUITIONPRIVATE
 *  area of the IntuitionBase structure.  Use it at your own risk.  It is
 *  likely to break under a future release of Intuition.
 */
 
#define INTUITIONPRIVATE
 
#include <exec/types.h>
#include <exec/semaphores.h>
#include <exec/interrupts.h>
#include <exec/memory.h>
#include <devices/input.h>
#include <graphics/sprite.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <intuition/screens.h>
#include <libraries/dos.h>
#ifndef MANX
   #ifdef PROTO
      #include <proto/intuition.h>
      #include <proto/exec.h>
      #include <proto/graphics.h>
      #include <proto/layers.h>
      #include <proto/dos.h>
   #endif
#endif
 
 
#define USAGE       "VSCREEN width height [screen]"
#define COPYRIGHT   "Copyright 1988 by Davide P. Cervone, all rights reserved"
 
#define PORTNAME    "vScreenPort"
 
 
#define INTUITION_REV   0L
#define GRAPHICS_REV    0L
#define LAYERS_REV      0L
 
#define ERROR_EXIT      RETURN_ERROR
#define OK_EXIT         RETURN_OK
 
extern struct IntuitionBase *IntuitionBase;
extern struct GfxBase *GfxBase;
#ifndef PROTO
extern struct DOSBase *DOSBase;
#endif
 
 
/*
 *  This structure is used to pass information from the Handler to the
 *  loader.  It contins pointers to the variables that the loader will
 *  have to initialize, and to the routines that it has to call, or
 *  SetFunction into the libraries.  A pointer to this structure is
 *  stored in the MsgPort so that the loader can find and remove the handler
 *  once it's job is done.
 */
 
struct vScreenInfo
{
   short MajVers,MinVers, LoadVers;     /* version of handler and loader */
   char *Program;                       /* name of the handler program */
   char *PortName;                      /* name of the public port */
   long Segment;                        /* SegList loaded by loader */
   struct Interrupt *HandlerInfo;       /* Input.Device handler */
   struct IntuitionBase **IntuitionBase;
   struct GfxBase **GfxBase;
 
   struct Screen **VScreen;             /* the virtual screen */
   SHORT *ScreenWidth,*ScreenHeight;    /* the new width and height */
   SHORT *OldWidth,*OldHeight;          /* old screen size */
   SHORT **RxOffset,**RyOffset;         /* pointer to RasInfo offsets */
   SHORT *RxOffset2,*RyOffset2;         /* normalized offsets */
   LONG  *LaceScreen,*LaceShift;        /* LACE screen? */
   LONG  *HiResScreen,*HiResShift;      /* HIRES screen ? */
   WORD  *OldMaxDH,*OldMaxDR,*OldMaxDW; /* old IntuitionBase MaxDisplays */
 
   /*
    *  These routines are called by the loader:
    */
 
   void (*SetVScreen)();
   void (*ResetVScreen)();
   void (*FixView)();
 
   /*
    *  These routines replace the Intution and Graphics library routines:
    */
 
   void (*aCloseScreen)();
   void (*aBuildSysRequest)();
   void (*aAutoRequest)();
   void (*aLoadView)();
   void (*aMoveSprite)();
 
   /*
    *  These are the addresses of the JSR or JMP instructions that
    *  need to be changed to call the old library vectors:
    */
 
   long *CloseScreenJmpTarget;
   long *BuildSysRequestJmpTarget;
   long *AutoRequestJmpTarget;
   long *LoadViewJmpTarget;
   long *MoveSpriteJmpTarget;
 
   /*
    *  These are the old function vectors returned by SetFunction():
    */
 
   long OldCloseScreen;
   long OldBuildSysRequest;
   long OldAutoRequest;
   long OldLoadView;
   long OldMoveSprite;
};
 
 
/*
 *  These macros give easy access to the vScreenInfo structure:
 */
 
#define VAR(x)      (*(vScreenData->x))
#define var(x)      (vScreenData->x)
 
 
/*
 *  External routine declarations:
 */
 
#ifndef PROTO
extern struct Window *OpenWindow();
extern struct IntuiMessage *GetMsg();
extern APTR OpenLibrary();
extern PLANEPTR AllocRaster();
extern UBYTE *AllocMem();
extern struct MsgPort *CreatePort();
extern struct IOStdReq *CreateStdIO();
extern LONG OpenDevice();
extern struct MsgPort *FindPort();
extern long LoadSeg();
#endif
SHAR_EOF
if test 4685 -ne "`wc -c vScreen.h`"
then
echo shar: error transmitting vScreen.h '(should have been 4685 characters)'
fi
echo shar: extracting vScreen-Handler.c '(24962 characters)'
cat << \SHAR_EOF > vScreen-Handler.c
/*
 *  VSCREEN-HANDLER.C
 *
 *                  Creates virtual screens that can be larger than
 *                  the actual display area of your monitor.  The virtual
 *                  screen scrolls when the mouse moves off the edge of
 *                  the display.
 *
 *                  Copyright 1988 by Davide P. Cervone, all rights reserved.
 *
 *                  You may may distibute this code as is, for non-commercial
 *                  purposes, provided that this notice remains intact and the
 *                  documentation file is distributed with it.
 *
 *                  You may not modify this code or incorporate it into your
 *                  own programs without the permission of the author.
 */
 
/*
 *  WARNING:  This code uses and even modifies the INTUITIONPRIVATE
 *  area of the IntuitionBase structure.  Use it at your own risk.  It is
 *  likely to break under a future release of Intuition.
 */
 
#include "vScreen.h"
 
static char program[] = "vScreen-Handler";  /* the program name */
static char author[]  = COPYRIGHT;          /* the copyright notice */
#define MAJVER  1                           /* major version number */
#define MINVER  0                           /* minor version number */
 
 
/*
 *  Macros for normalizing screen Y coordinates to absolute display
 *  corrdinates (using the LaceShift and LaceScreen variables).
 */
 
#define TWICE_Y(y)       ((y)<<LaceShift)
#define NTWICE_Y(y)      ((LaceScreen)?(y)<<1:(y))
#define HALF_Y(y)        ((y)>>LaceShift)
#define NHALF_Y(y)       ((LaceScreen)?(y)>>1:(y))
 
 
/*
 *  Macros for normalizing screen X coordinates to absolute display
 *  corrdinates (using the HiResShift and HiResScreen variables).
 */
 
#define TWICE_X(x)       ((x)<<HiResShift)
#define NTWICE_X(x)      ((HiResScreen)?(x)<<1:(x))
#define HALF_X(x)        ((x)>>HiResShift)
#define NHALF_X(x)       ((HiResScreen)?(x)>>1:(x))
 
 
/*
 *  The qualifiers used to check whether the left command key is pressed
 */
 
#define SHIFTQUALS      (~IEQUALIFIER_RELATIVEMOUSE)
 
 
static struct Screen *VScreen;          /* pointer to the virtual screen */
static SHORT ScreenWidth,ScreenHeight;  /* the new width and height */
static SHORT OldWidth,OldHeight;        /* the old width and height */
static SHORT *RxOffset,*RyOffset;       /* pointers to the RasInfo offsets */
static SHORT RxOffset2,RyOffset2;       /* normalized RxOffset and RyOffset */
static LONG  LaceScreen,LaceShift;      /* used to normalize Y positions */
static LONG  HiResScreen,HiResShift;    /* used to normalize X positions */
static WORD  OldMaxDH,OldMaxDR,OldMaxDW; /* Old MaxDisplay values */
 
static WORD MinXMouse,MaxXMouse,MinYMouse,MaxYMouse;
   /* the Display min and max values (as opposed to the Intuition values) */
static WORD Xshift = 0;                 /* how far to shift VScreen */
static WORD Yshift = 0;                 /* how far to shift VScreen */
 
static struct Screen *OldScreen = NULL; /* pointer to last active screen */
static WORD ScreenTop,ScreenBottom;     /* Y position of vScreen borders */
static short NotVScreen = FALSE;        /* TRUE when mouse not over VScreen */
 
#define BOTTOMSCREEN    1               /* Mouse over screen below  VScreen */
#define TOPSCREEN      -1               /* mouse over screen behind VScreen */
#define OVERVSCREEN     (NotVScreen == FALSE)
 
 
extern struct vScreenInfo vScreenData;  /* the data neede by vScreen */
 
 
/*
 *  Setup()
 *
 *  This routine gets called by vScreen after vScreen-Handler gets LoadSeged.
 *  Setup must return the pointer to the data structure that vScreen uses
 *  to initialize vScreen-Handler's variables.
 *
 *  vScreen passes its version number to Setup().  If Setup() detects a
 *  version mismatch, it should return NULL.
 */
 
struct vScreenInfo *Setup(version)
int version;
{
   return(&vScreenData);
}
 
 
/*
 *  SetScreenMinMax()
 *
 *  Set the OldScreen to the current ActiveScreen.  If it is VScreen,
 *  the set the Min and Max Mouse values to the virtual screen sizes,
 *  otherwise, set them to the current display edges (in the coordinate
 *  system of the virtual screen; i.e., origin is offset by RxOffset and
 *  RyOffset).
 */
 
static void SetScreenMinMax()
{
   if ((OldScreen = IntuitionBase->ActiveScreen) == VScreen)
   {
      IntuitionBase->MinXMouse = 0;
      IntuitionBase->MaxXMouse = TWICE_X(ScreenWidth) - 1;
      IntuitionBase->MinYMouse = IntuitionBase->MouseYMinimum;
      IntuitionBase->MaxYMouse = TWICE_Y(ScreenHeight) - 1;
   } else {
      IntuitionBase->MinXMouse = RxOffset2;
      IntuitionBase->MaxXMouse = OldMaxDW + RxOffset2 - 1;
      IntuitionBase->MinYMouse = IntuitionBase->MouseYMinimum + RyOffset2;
      IntuitionBase->MaxYMouse = OldMaxDR + RyOffset2;
   }
}
 
 
/*
 *  ResetVScreen()
 *
 *  When the mouse moves over a screen other than the virtual screen, we need
 *  to reset the modified Intuition fields to their normal values so that if
 *  the mouse is pressed over the other screen, it hits the right position.
 *
 *  Set OldScreen to the ActiveScreen.
 *  Set the Min and Max Mouse values where scrolling will occur to the
 *    display edges (relative to the non-virtual screen).
 *  Set the Intuition MaxDisplay values to their original dimensions.
 *  Subtract the RxOffset and RyOffsets from the Intuition mouse coordinates
 *    (they are now relative to the screen the mouse is moving over).
 */
 
static void ResetVScreen()
{
   OldScreen = IntuitionBase->ActiveScreen;
   MinXMouse = IntuitionBase->MinXMouse = 0;
   MaxXMouse = IntuitionBase->MaxXMouse = OldMaxDW - 1;
   MinYMouse = IntuitionBase->MinYMouse = IntuitionBase->MouseYMinimum;
   MaxYMouse = IntuitionBase->MaxYMouse = OldMaxDR;
   IntuitionBase->MaxDisplayHeight = OldMaxDH;
   IntuitionBase->MaxDisplayRow    = OldMaxDR;
   IntuitionBase->MaxDisplayWidth  = OldMaxDW;
   IntuitionBase->MouseX -= RxOffset2;
   IntuitionBase->MouseY -= RyOffset2;
}
 
 
/*
 *  SetVScreen()
 *
 *  When the mouse moves back over the virtual screen, we need to change to
 *  Intuition Mouse corrdinates to be relative to the virtual screen again,
 *  so that if the mouse is pressed, it will hit the right spot.
 *
 *  Set the Min and Max values for the Intuition Mouse.
 *  Set the Min and Max values where scrolling will occur (relative to
 *    the virtual screen origin).
 *  Set the Intuition MaxDisplay values to the full screen size (so that
 *    Intuition will allow the mouse to move to the edge of the virtual
 *    screen).
 *  Add the RxOffset and RyOffset to the Intuition Mouse position so that
 *    Intuition thinks the mouse is positioned relative correctly on the
 *    virtual screen (we compensate for this in MoveSprite).
 */
 
static void SetVScreen()
{
   SetScreenMinMax();
   MinXMouse = RxOffset2;
   MaxXMouse = OldMaxDW + RxOffset2 - 1;
   MinYMouse = IntuitionBase->MouseYMinimum + RyOffset2;
   MaxYMouse = OldMaxDR + RyOffset2;
   IntuitionBase->MaxDisplayHeight = TWICE_Y(ScreenHeight);
   IntuitionBase->MaxDisplayRow    = TWICE_Y(ScreenHeight) - 1;
   IntuitionBase->MaxDisplayWidth  = TWICE_X(ScreenWidth);
   IntuitionBase->MouseX += RxOffset2;
   IntuitionBase->MouseY += RyOffset2;
}
 
 
/*
 *  FindBounds()
 *
 *  Locate the absolute display position of the top of the virtual screen
 *  and of the top of the highest screen that is on top of the virtual
 *  screen.  That is, if the mouse is between the TopScreen and BottomScreen
 *  Y values, then it is positioned over top pf the visible portion of the
 *  virtual screen.  If the screen is not showing, then BottomScreen will
 *  be less that TopScreen.
 *
 *  Note that TopScreen and BottomScreen are relative to a 320 x 200 screen,
 *  since they are compared to the mouse pointer coordinates (since the pointer
 *  is a sprite, its coordinates always are LoRes and Non-Interlaced).
 */
 
static void FindBounds()
{
   struct Screen *theScreen = IntuitionBase->FirstScreen;
   WORD Top;
 
   ScreenTop = NHALF_Y(VScreen->TopEdge) - 1;
   ScreenBottom = IntuitionBase->MaxDisplayRow;
   while (theScreen && theScreen != VScreen)
   {
      Top = theScreen->TopEdge;
      if (theScreen->ViewPort.Modes & LACE) Top >>= 1;
      if (Top < ScreenBottom) ScreenBottom = Top;
      theScreen = theScreen->NextScreen;
   }
}
 
 
/*
 *  FixView()
 *
 *  When the virtual Screen is the first screen, its viewport will try to
 *  display ALL of the vertical length of the screen.  This might cause an
 *  overscan display when there is not supposed to be one, so when this
 *  occurs, we set the ViewPort height manually, remake the Screen, and
 *  merge the copper list into the rest of the display.  This routine gets
 *  called whenever the intuition View is loaded.  Since this happens
 *  whenever a screen changes position, this is a good place to check the
 *  screen top and bottom bounds.
 */
 
static void FixView(ForceUpdate)
int ForceUpdate;
{
   short TooBig = (VScreen->ViewPort.DHeight > OldHeight);
 
   if (TooBig || ForceUpdate)
   {
      if (TooBig) VScreen->ViewPort.DHeight = OldHeight;
      MakeScreen(VScreen);
      MrgCop(&(IntuitionBase->ViewLord));
   }
   FindBounds();
}
 
 
/*
 *  CheckShift()
 *
 *  Check that a forced screen shoft will not go too far.  If it does, then
 *  clear the InputEvent mouse movement so that the mouse doesn't move
 *  when the screen can't scroll any more.
 *
 *  If the mouse is not over the virtual screen, then we don't want the
 *  mouse to move at all, so clear the InputEvent mouse movement.
 */
 
static void CheckShift(Xshift,Yshift,theEvent)
WORD *Xshift,*Yshift;
struct InputEvent *theEvent;
{
   if (*Xshift < -RxOffset2 ||
       *Xshift > TWICE_X(ScreenWidth-OldWidth)-RxOffset2)
   {
      *Xshift -= theEvent->ie_X;
      theEvent->ie_X = 0;
   }
   if (*Yshift < -RyOffset2 ||
       *Yshift > TWICE_Y(ScreenHeight-OldHeight)-RyOffset2)
   {
      *Yshift -= theEvent->ie_Y;
      theEvent->ie_Y = 0;
   }
   if (NotVScreen) theEvent->ie_X = theEvent->ie_Y = 0;
}
 
 
/*
 *  ShiftVScreen()
 *
 *  Shift the virtual screen by the specified amount.
 *
 *  If there is movement in the X direction,
 *    Check that the screen does not scroll too far to the left or right.
 *    If it does, then reduce the move so that the screen scrolls to the edge.
 *    If the mouse is over the virtual screen, then
 *      Adjust the Min and Max values for when scrolling occurs.
 *    Increment the Screen's ViewPort RasInfo RxOffset by the amount of
 *      the scroll, and record the normalized value for later use.
 *      The RxOffset is what tells the graphics library which part of the
 *      larger bitmap should actually be displayed.
 *
 *  Similarly for the Y shift.
 *
 *  Finally, if there was actually movement in either direction,
 *    Fix the View (FixView calls MakeScreen() and MrgCop()) and
 *    Load the new View.
 */
 
static void ShiftVScreen(Xmove,Ymove)
WORD Xmove,Ymove;
{
   WORD xOffset, yOffset;
 
   if (Xmove)
   {
      xOffset = *RxOffset + Xmove;
      if (xOffset < 0) Xmove -= xOffset;
      if (xOffset > ScreenWidth-OldWidth)
         Xmove += (ScreenWidth-OldWidth - xOffset);
      if (OVERVSCREEN)
      {
         MinXMouse += TWICE_X(Xmove);
         MaxXMouse += TWICE_X(Xmove);
      }
      *RxOffset += Xmove;
      RxOffset2  = TWICE_X(*RxOffset);
   }
 
   if (Ymove)
   {
      yOffset = *RyOffset + Ymove;
      if (yOffset < 0) Ymove -= yOffset;
      if (yOffset > ScreenHeight-OldHeight)
         Ymove += (ScreenHeight-OldHeight - yOffset);
      if (OVERVSCREEN)
      {
         MinYMouse += TWICE_Y(Ymove);
         MaxYMouse += TWICE_Y(Ymove);
      }
      *RyOffset += Ymove;
      RyOffset2  = TWICE_Y(*RyOffset);
   }
 
   if (Xmove || Ymove)
   {
      FixView(TRUE);
      LoadView(&(IntuitionBase->ViewLord));
   }
}
 
 
/*
 *  cLoadView()
 *
 *  Replaces the LoadView function in the graphics library (the stub calls
 *  the old LoadView() after cLoadView() runs).
 *
 *  If the virtual screen is still open, and the view is the Intuition View,
 *  the Fix the view (make sure that the height is no larger than the
 *  old MaxDisplayHeight).
 *
 *  Note:  when you drag a screen up and down, Intuition calls RemakeDisplay()
 *  which in turn calls MakeScreen() on each screen, MrgCop() and finally
 *  LoadView().  cLoadView() gets called in place of LoadView(), and it will
 *  call FixView(), which calls MakeScreen() and MrgCop() again.  This are high
 *  overhead calls, so when the virtual screen is the FirstScreen and there is
 *  another screen showing behind it, this can nearly double the overhead of
 *  dragging a screen.
 */
 
void cLoadView(view)
struct View *view;
{
   if (VScreen && view == &(IntuitionBase->ViewLord)) FixView(FALSE);
}
 
 
/*
 *  cMoveSprite();
 *
 *  Repaces MoveSprite() in the graphics library (the stub calls the old
 *  MoveSprive() after cMoveSprite() runs).
 *
 *  If the sprite being moved is sprite zero (the pointer sprite), and
 *  the virtual screen is still open, then
 *    If the pointer is over the virtual screen
 *      Subtract the offsets (relative to a 320 x 200 screen, since this
 *      is a sprite).  We must do this, since we added RxOffset and RyOffset
 *      to the Intuition MouseX and MouseY values.  Since Intuition does not
 *      take the RxOffset and RyOffset into account, we have to subtract
 *      the values here in order to keep the pointer on the display area.
 *
 *    If the Min and Max X Mouse values are equal, a screen is being dragged.
 *    If the LayerInfo Lock has a NestCount, then the layers are locked.
 *
 *    If the mouse is not over the virtual screen then
 *      Set the MinY for scrolling to the top of the view.
 *      If we used to be over the virtual screen and
 *         we're not currently dragging a screen, then
 *        If the virtual screen is not locked, then
 *          Reset the coordinate system to fit the screen we are over.
 *          Save which type of screen we're over.
 *         otherwise (the screen is locked; e.g., the user has the
 *                    menu button down, or is dragging a window),
 *          so scroll the screen if we move off the top.
 *    Otherwise (the mouse IS over the virtual screen)
 *      Set the MinY for scrolling to the top of the view relative to the
 *        virtual screen origin.
 *      If we used to be over some other screen, and we're not dragging
 *         a screen, and the current screen is not locked, then
 *        (we need to change coordinates to the virtual screen coordinates)
 *        If we are going from a bottom screen onto the virtual screen
 *          then activate the cirtual screen (I couldn't find a way to do
 *          the coordinate transfer without this).
 *        Set the coordinates relative to the virtual screen.
 *        Record that we are over the virtual screen.
 *
 *    If a new screen has become active then
 *      If we were over the virtual screen, check that we still are
 *      Record the active screen
 *
 *    If the user is dragging the screen, don't let him drag it off
 *      the bottom of the display area (where he won;t be able to reach it).
 *
 *    If the MouseY has gone past the top of the screen (i.e., if a screen
 *      has closed and the pointer was above it), put the pointer at the
 *      top of the display.
 */
 
void cMoveSprite(ss,x,y)
struct SimpleSprite *ss;
long x,y;
{
   short NotDrag;
   short NotLocked;
 
   if (ss->num == 0 && VScreen)
   {
      if (OVERVSCREEN)
      {
         x -= NHALF_X(*RxOffset);
         y -= NHALF_Y(*RyOffset);
      }
 
      NotDrag = (IntuitionBase->MinXMouse != IntuitionBase->MaxXMouse);
      NotLocked =
         (IntuitionBase->ActiveScreen->LayerInfo.Lock.ss_NestCount == 0);
 
      if (y < ScreenTop || y >= ScreenBottom)
      {
         MinYMouse = IntuitionBase->MouseYMinimum;
         if (OVERVSCREEN && NotDrag)
         {
            if (NotLocked)
            {
               ResetVScreen();
               NotVScreen = (y < ScreenTop)? TOPSCREEN: BOTTOMSCREEN;
            } else {
               if (y < ScreenTop) ShiftVScreen(0,NTWICE_Y(y-ScreenTop));
            }
         }
      } else {
         MinYMouse = IntuitionBase->MouseYMinimum + RyOffset2;
         if (NotVScreen && NotDrag && NotLocked)
         {
            if (NotVScreen == BOTTOMSCREEN &&
                IntuitionBase->ActiveScreen != VScreen &&
                VScreen->FirstWindow) ActivateWindow(VScreen->FirstWindow);
            SetVScreen();
            NotVScreen = FALSE;
         }
      }
 
      if (OldScreen != IntuitionBase->ActiveScreen)
      {
         if (OVERVSCREEN) SetScreenMinMax();
         OldScreen = IntuitionBase->ActiveScreen;
      }
 
      if (NotDrag == FALSE &&
          IntuitionBase->MaxYMouse > OldMaxDR + RyOffset2)
              IntuitionBase->MaxYMouse = OldMaxDR + RyOffset2;
 
      if (IntuitionBase->MouseY < IntuitionBase->MinYMouse)
         IntuitionBase->MouseY = IntuitionBase->MinYMouse;
   }
}
 
 
/*
 *  cAutoRequest()
 *
 *  Replaces AutoRequest() in the Intuition Library (the stub calls
 *  AutoRequest() after cAutoRequest() runs).
 *
 *  If the AutoRequest is to appear on the virtual screen, then shift
 *  the virtual screen so that the System Request window will be showing.
 *  Note that this could change the screen position even while the user is
 *  doing critical work (e.g., dragging a window, pulling menus, etc).
 *  It would be better to trap this through BuildSysRequest(), but since
 *  Intuition does not use its own vector table, I can not trap all the
 *  calls to BuildSysRequest, specifically, the ones called by AutoRequest().
 */
 
void cAutoRequest(theWindow)
struct Window *theWindow;
{
   if (theWindow == NULL || theWindow->WScreen == VScreen)
   {
      IntuitionBase->MouseX -= RxOffset2;
      IntuitionBase->MouseY -= RyOffset2;
      ShiftVScreen(-(*RxOffset),-(*RyOffset));
   }
}
 
 
/*
 *  cBuildSysRequest()
 *
 *  Replaces BuildSysRequest() in the Intuition Libaray (the stub routine
 *  calls BuildSysRequest() before calling cBuildSysReques()).
 *
 *  If the window (returned by BuildSysRequest) exists, then
 *    If it is on the virtual screen, and it is not completely showing, then
 *      Move the window so that it is in the upper left corner of the
 *        displayed section of the screen.
 *
 *  Note that this is better than what we do with AutoRequest, since the
 *  screen itself does not scroll.
 */
 
void cBuildSysRequest(theWindow)
struct Window *theWindow;
{
   if (theWindow && theWindow != (struct Window *)TRUE)
   {
      if (theWindow->WScreen == VScreen &&
         (theWindow->LeftEdge < *RxOffset ||
          theWindow->TopEdge  < *RyOffset))
             MoveWindow(theWindow,*RxOffset-theWindow->LeftEdge,
                                  *RyOffset-theWindow->TopEdge);
   }
}
 
 
/*
 *  cCloseScreen()
 *
 *  Replaces CloseScreen() in the IntuitionLibrary (the stub routine calls
 *  CloseScreen() after cCloseScreen() runs).
 *
 *  If the virtual screen is still open, and it is the one being closed,
 *    reset the coordinate system, and mark the virtual screen as closed.
 */
 
void cCloseScreen(theScreen)
struct Screen *theScreen;
{
   if (theScreen == VScreen && VScreen != NULL)
   {
      ResetVScreen();
      VScreen = NULL;
   }
}
 
 
/*
 *  myHandler()
 *
 *  This is the input handler that gets added to the Input.Device input
 *  chain.  It is at priority 51, so it is ahead of Intuition.
 *
 *  If a screen is not being dragged, and the virtual screen is still open,
 *    then for each event in the event list,
 *      If the event is a RAWMOUSE event,
 *        If the left Amiga key is held down then
 *          Add it into the forced shift count and
 *          Check that the shift is valid.
 *        Add the movement into the total movement so far.
 *
 *    Find the new MouseX and MouseY positions.
 *    Shift the screen by the forced shift amounts, checking that the
 *      coordinates are shifted when needed, and retaining any un-used
 *      shift amount (due to LoRes or Non-Interlaced screens).
 *
 *    If the active screen is the virtual screen, then
 *      if the mouse has moved off the left or right edge of the display,
 *      or if the mouse has moved past the Intuition Min or Max values,
 *      then shift the screen by the appropriate amount.  Do this for
 *      both the X and Y directions.
 *
 *  Finally, return the original event list.
 */
 
struct InputEvent *myHandler(EventList,data)
struct InputEvent *EventList;
APTR data;
{
   struct InputEvent *theEvent = EventList;
   WORD MouseX,MouseY;
   WORD Xmove = 0;
   WORD Ymove = 0;
   WORD Ychange = 0;
   WORD Xchange = 0;
   WORD dx,dy;
 
   if (IntuitionBase->MinXMouse != IntuitionBase->MaxXMouse && VScreen)
   {
      Forbid();
      while (theEvent)
      {
         if (theEvent->ie_Class == IECLASS_RAWMOUSE)
         {
            if ((theEvent->ie_Qualifier & SHIFTQUALS) == IEQUALIFIER_LCOMMAND)
            {
               Xshift += theEvent->ie_X;
               Yshift += theEvent->ie_Y;
               CheckShift(&Xshift,&Yshift,theEvent);
            }
            Xchange += theEvent->ie_X;
            Ychange += theEvent->ie_Y;
         }
         theEvent = theEvent->ie_NextEvent;
      }
      Permit();
 
      MouseX = IntuitionBase->MouseX + HALF_X(Xchange);
      MouseY = IntuitionBase->MouseY + HALF_Y(Ychange);
 
      if (Xshift < 0) dx = -HALF_X(-Xshift); else dx = HALF_X(Xshift);
      if (Yshift < 0) dy = -HALF_Y(-Yshift); else dy = HALF_Y(Yshift);
      if (dx || dy)
      {
         ShiftVScreen(dx,dy);
         if (IntuitionBase->ActiveScreen != VScreen && OVERVSCREEN)
            SetScreenMinMax();
         if (HiResScreen) Xshift = 0; else Xshift %= 2;
         if (LaceScreen)  Yshift = 0; else Yshift %= 2;
      }
 
      if (IntuitionBase->ActiveScreen == VScreen)
      {
         if (MouseX < MinXMouse) Xmove = MouseX - MinXMouse;
         if (MouseX > MaxXMouse) Xmove = MouseX - MaxXMouse;
         if (Xmove == 0)
         {
            if (MouseX < IntuitionBase->MinXMouse)
               Xmove = MouseX - IntuitionBase->MinXMouse;
            if (MouseX > IntuitionBase->MaxXMouse)
               Xmove = MouseX - IntuitionBase->MaxXMouse;
         }
 
         if (MouseY < MinYMouse) Ymove = MouseY - MinYMouse;
         if (MouseY > MaxYMouse) Ymove = MouseY - MaxYMouse;
         if (Ymove == 0)
         {
            if (MouseY < IntuitionBase->MinYMouse)
               Ymove = MouseY - IntuitionBase->MinYMouse;
            if (MouseY > IntuitionBase->MaxYMouse)
               Ymove = MouseY - IntuitionBase->MaxYMouse;
         }
 
         if (Xmove || Ymove) ShiftVScreen(Xmove,Ymove);
      }
   }
   return(EventList);
}
 
 
/*
 *  These are the assembler stubs needed in order to SetFunction some
 *  of the Intuiton and graphics library functions.
 */
 
extern void myHandlerStub();
 
extern void aCloseScreen();
extern void aBuildSysRequest();
extern void aAutoRequest();
extern void aLoadView();
extern void aMoveSprite();
 
 
/*
 *  These are the jump addresses in the assembler routines that need to
 *  be filled in by vScreen once the old SetFunction vectors are known.
 *  This is a kludge, and is a form od self-modifying code, but I can't figure
 *  out a better way that works.  The JSR (Ax) form is only good if there is
 *  a free A register to use, which is not always the case.
 */
 
extern unsigned char *CloseScreenJmpAddress;
extern unsigned char *BuildSysRequestJmpAddress;
extern unsigned char *AutoRequestJmpAddress;
extern unsigned char *LoadViewJmpAddress;
extern unsigned char *MoveSpriteJmpAddress;
 
static char PortName[] = PORTNAME;      /* the name of the named port */
 
static struct Interrupt HandlerInfo =   /* the Interrupt needed to add an */
{                                       /*  input handler to the input chain */
   {NULL, NULL, 0, 51, NULL},           /*  ln_Pri = 51 (before Intuition) */
   NULL,
   &myHandlerStub                       /* the handler to add */
};
 
 
/*
 *  This is the structure passed from the Setup() routine to vScreen.
 *  It includes pointers to the variables that vSCreen needs to initialize,
 *  plus pointers to the routines that vScreen will SetFunction into the
 *  appropriate libraries.
 */
 
struct vScreenInfo vScreenData =
{
   MAJVER,MINVER,0,
   &program[0],
   &PortName[0],
   NULL,
   &HandlerInfo,
   &IntuitionBase, &GfxBase,
 
   &VScreen,
   &ScreenWidth,&ScreenHeight,
   &OldWidth,&OldHeight,
   &RxOffset,&RyOffset,
   &RxOffset2,&RyOffset2,
   &LaceScreen,&LaceShift,
   &HiResScreen,&HiResShift,
   &OldMaxDH,&OldMaxDR,&OldMaxDW,
 
   &SetVScreen, &ResetVScreen, &FixView,
 
   &aCloseScreen, &aBuildSysRequest, &aAutoRequest, &aLoadView, &aMoveSprite,
 
   (long *) &CloseScreenJmpAddress,
   (long *) &BuildSysRequestJmpAddress,
   (long *) &AutoRequestJmpAddress,
   (long *) &LoadViewJmpAddress,
   (long *) &MoveSpriteJmpAddress,
 
   0,0,0,0,0
};
SHAR_EOF
if test 24962 -ne "`wc -c vScreen-Handler.c`"
then
echo shar: error transmitting vScreen-Handler.c '(should have been 24962
 characters)'
fi
#    End of shell archive
exit 0
