home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 1 / GoldFishApril1994_CD2.img / d4xx / d494 / vscreen / source / vscreen-handler.c next >
C/C++ Source or Header  |  1991-06-06  |  25KB  |  745 lines

  1. /*
  2.  *  VSCREEN-HANDLER.C
  3.  *
  4.  *                  Creates virtual screens that can be larger than
  5.  *                  the actual display area of your monitor.  The virtual
  6.  *                  screen scrolls when the mouse moves off the edge of
  7.  *                  the display.
  8.  *
  9.  *                  Copyright 1988 by Davide P. Cervone, all rights reserved.
  10.  *
  11.  *                  You may may distibute this code as is, for non-commercial
  12.  *                  purposes, provided that this notice remains intact and the
  13.  *                  documentation file is distributed with it.
  14.  *
  15.  *                  You may not modify this code or incorporate it into your
  16.  *                  own programs without the permission of the author.
  17.  */
  18.  
  19. /*
  20.  *  WARNING:  This code uses and even modifies the INTUITIONPRIVATE
  21.  *  area of the IntuitionBase structure.  Use it at your own risk.  It is
  22.  *  likely to break under a future release of Intuition.
  23.  */
  24.  
  25. #include "vScreen.h"
  26.  
  27. static char program[] = "vScreen-Handler";  /* the program name */
  28. static char author[]  = COPYRIGHT;          /* the copyright notice */
  29. #define MAJVER  1                           /* major version number */
  30. #define MINVER  0                           /* minor version number */
  31.  
  32.  
  33. /*
  34.  *  Macros for normalizing screen Y coordinates to absolute display
  35.  *  corrdinates (using the LaceShift and LaceScreen variables).
  36.  */
  37.  
  38. #define TWICE_Y(y)       ((y)<<LaceShift)
  39. #define NTWICE_Y(y)      ((LaceScreen)?(y)<<1:(y))
  40. #define HALF_Y(y)        ((y)>>LaceShift)
  41. #define NHALF_Y(y)       ((LaceScreen)?(y)>>1:(y))
  42.  
  43.  
  44. /*
  45.  *  Macros for normalizing screen X coordinates to absolute display
  46.  *  corrdinates (using the HiResShift and HiResScreen variables).
  47.  */
  48.  
  49. #define TWICE_X(x)       ((x)<<HiResShift)
  50. #define NTWICE_X(x)      ((HiResScreen)?(x)<<1:(x))
  51. #define HALF_X(x)        ((x)>>HiResShift)
  52. #define NHALF_X(x)       ((HiResScreen)?(x)>>1:(x))
  53.  
  54.  
  55. /*
  56.  *  The qualifiers used to check whether the left command key is pressed
  57.  */
  58.  
  59. #define SHIFTQUALS      (~IEQUALIFIER_RELATIVEMOUSE)
  60.  
  61.  
  62. static struct Screen *VScreen;          /* pointer to the virtual screen */
  63. static SHORT ScreenWidth,ScreenHeight;  /* the new width and height */
  64. static SHORT OldWidth,OldHeight;        /* the old width and height */
  65. static SHORT *RxOffset,*RyOffset;       /* pointers to the RasInfo offsets */
  66. static SHORT RxOffset2,RyOffset2;       /* normalized RxOffset and RyOffset */
  67. static LONG  LaceScreen,LaceShift;      /* used to normalize Y positions */
  68. static LONG  HiResScreen,HiResShift;    /* used to normalize X positions */
  69. static WORD  OldMaxDH,OldMaxDR,OldMaxDW; /* Old MaxDisplay values */
  70.  
  71. static WORD MinXMouse,MaxXMouse,MinYMouse,MaxYMouse;
  72.    /* the Display min and max values (as opposed to the Intuition values) */
  73. static WORD Xshift = 0;                 /* how far to shift VScreen */
  74. static WORD Yshift = 0;                 /* how far to shift VScreen */
  75.  
  76. static struct Screen *OldScreen = NULL; /* pointer to last active screen */
  77. static WORD ScreenTop,ScreenBottom;     /* Y position of vScreen borders */
  78. static short NotVScreen = FALSE;        /* TRUE when mouse not over VScreen */
  79.  
  80. #define BOTTOMSCREEN    1               /* Mouse over screen below  VScreen */
  81. #define TOPSCREEN      -1               /* mouse over screen behind VScreen */
  82. #define OVERVSCREEN     (NotVScreen == FALSE)
  83.  
  84.  
  85. extern struct vScreenInfo vScreenData;  /* the data neede by vScreen */
  86.  
  87.  
  88. /*
  89.  *  Setup()
  90.  *
  91.  *  This routine gets called by vScreen after vScreen-Handler gets LoadSeged.
  92.  *  Setup must return the pointer to the data structure that vScreen uses
  93.  *  to initialize vScreen-Handler's variables.
  94.  *
  95.  *  vScreen passes its version number to Setup().  If Setup() detects a
  96.  *  version mismatch, it should return NULL.
  97.  */
  98.  
  99. struct vScreenInfo *Setup(version)
  100. int version;
  101. {
  102.    return(&vScreenData);
  103. }
  104.  
  105.  
  106. /*
  107.  *  SetScreenMinMax()
  108.  *
  109.  *  Set the OldScreen to the current ActiveScreen.  If it is VScreen,
  110.  *  the set the Min and Max Mouse values to the virtual screen sizes,
  111.  *  otherwise, set them to the current display edges (in the coordinate
  112.  *  system of the virtual screen; i.e., origin is offset by RxOffset and
  113.  *  RyOffset).
  114.  */
  115.  
  116. static void SetScreenMinMax()
  117. {
  118.    if ((OldScreen = IntuitionBase->ActiveScreen) == VScreen) 
  119.    {
  120.       IntuitionBase->MinXMouse = 0;
  121.       IntuitionBase->MaxXMouse = TWICE_X(ScreenWidth) - 1;
  122.       IntuitionBase->MinYMouse = IntuitionBase->MouseYMinimum;
  123.       IntuitionBase->MaxYMouse = TWICE_Y(ScreenHeight) - 1;
  124.    } else {
  125.       IntuitionBase->MinXMouse = RxOffset2;
  126.       IntuitionBase->MaxXMouse = OldMaxDW + RxOffset2 - 1;
  127.       IntuitionBase->MinYMouse = IntuitionBase->MouseYMinimum + RyOffset2;
  128.       IntuitionBase->MaxYMouse = OldMaxDR + RyOffset2;
  129.    }
  130. }
  131.  
  132.  
  133. /*
  134.  *  ResetVScreen()
  135.  *
  136.  *  When the mouse moves over a screen other than the virtual screen, we need 
  137.  *  to reset the modified Intuition fields to their normal values so that if
  138.  *  the mouse is pressed over the other screen, it hits the right position.
  139.  *
  140.  *  Set OldScreen to the ActiveScreen.
  141.  *  Set the Min and Max Mouse values where scrolling will occur to the 
  142.  *    display edges (relative to the non-virtual screen).
  143.  *  Set the Intuition MaxDisplay values to their original dimensions.
  144.  *  Subtract the RxOffset and RyOffsets from the Intuition mouse coordinates
  145.  *    (they are now relative to the screen the mouse is moving over).
  146.  */
  147.  
  148. static void ResetVScreen()
  149. {
  150.    OldScreen = IntuitionBase->ActiveScreen;
  151.    MinXMouse = IntuitionBase->MinXMouse = 0;
  152.    MaxXMouse = IntuitionBase->MaxXMouse = OldMaxDW - 1;
  153.    MinYMouse = IntuitionBase->MinYMouse = IntuitionBase->MouseYMinimum;
  154.    MaxYMouse = IntuitionBase->MaxYMouse = OldMaxDR;
  155.    IntuitionBase->MaxDisplayHeight = OldMaxDH;
  156.    IntuitionBase->MaxDisplayRow    = OldMaxDR;
  157.    IntuitionBase->MaxDisplayWidth  = OldMaxDW;
  158.    IntuitionBase->MouseX -= RxOffset2;
  159.    IntuitionBase->MouseY -= RyOffset2;
  160. }
  161.  
  162.  
  163. /*
  164.  *  SetVScreen()
  165.  *
  166.  *  When the mouse moves back over the virtual screen, we need to change to
  167.  *  Intuition Mouse corrdinates to be relative to the virtual screen again,
  168.  *  so that if the mouse is pressed, it will hit the right spot.
  169.  *
  170.  *  Set the Min and Max values for the Intuition Mouse.
  171.  *  Set the Min and Max values where scrolling will occur (relative to 
  172.  *    the virtual screen origin).
  173.  *  Set the Intuition MaxDisplay values to the full screen size (so that
  174.  *    Intuition will allow the mouse to move to the edge of the virtual
  175.  *    screen).
  176.  *  Add the RxOffset and RyOffset to the Intuition Mouse position so that
  177.  *    Intuition thinks the mouse is positioned relative correctly on the
  178.  *    virtual screen (we compensate for this in MoveSprite).
  179.  */
  180.  
  181. static void SetVScreen()
  182. {
  183.    SetScreenMinMax();
  184.    MinXMouse = RxOffset2;
  185.    MaxXMouse = OldMaxDW + RxOffset2 - 1;
  186.    MinYMouse = IntuitionBase->MouseYMinimum + RyOffset2;
  187.    MaxYMouse = OldMaxDR + RyOffset2;
  188.    IntuitionBase->MaxDisplayHeight = TWICE_Y(ScreenHeight);
  189.    IntuitionBase->MaxDisplayRow    = TWICE_Y(ScreenHeight) - 1;
  190.    IntuitionBase->MaxDisplayWidth  = TWICE_X(ScreenWidth);
  191.    IntuitionBase->MouseX += RxOffset2;
  192.    IntuitionBase->MouseY += RyOffset2;
  193. }
  194.  
  195.  
  196. /*
  197.  *  FindBounds()
  198.  *
  199.  *  Locate the absolute display position of the top of the virtual screen
  200.  *  and of the top of the highest screen that is on top of the virtual
  201.  *  screen.  That is, if the mouse is between the TopScreen and BottomScreen
  202.  *  Y values, then it is positioned over top pf the visible portion of the
  203.  *  virtual screen.  If the screen is not showing, then BottomScreen will
  204.  *  be less that TopScreen.
  205.  *
  206.  *  Note that TopScreen and BottomScreen are relative to a 320 x 200 screen,
  207.  *  since they are compared to the mouse pointer coordinates (since the pointer
  208.  *  is a sprite, its coordinates always are LoRes and Non-Interlaced).
  209.  */
  210.  
  211. static void FindBounds()
  212. {
  213.    struct Screen *theScreen = IntuitionBase->FirstScreen;
  214.    WORD Top;
  215.    
  216.    ScreenTop = NHALF_Y(VScreen->TopEdge) - 1;
  217.    ScreenBottom = IntuitionBase->MaxDisplayRow;
  218.    while (theScreen && theScreen != VScreen)
  219.    {
  220.       Top = theScreen->TopEdge;
  221.       if (theScreen->ViewPort.Modes & LACE) Top >>= 1;
  222.       if (Top < ScreenBottom) ScreenBottom = Top;
  223.       theScreen = theScreen->NextScreen;
  224.    }
  225. }
  226.  
  227.  
  228. /*
  229.  *  FixView()
  230.  *
  231.  *  When the virtual Screen is the first screen, its viewport will try to 
  232.  *  display ALL of the vertical length of the screen.  This might cause an
  233.  *  overscan display when there is not supposed to be one, so when this
  234.  *  occurs, we set the ViewPort height manually, remake the Screen, and
  235.  *  merge the copper list into the rest of the display.  This routine gets
  236.  *  called whenever the intuition View is loaded.  Since this happens
  237.  *  whenever a screen changes position, this is a good place to check the
  238.  *  screen top and bottom bounds.
  239.  */
  240.  
  241. static void FixView(ForceUpdate)
  242. int ForceUpdate;
  243. {
  244.    short TooBig = (VScreen->ViewPort.DHeight > OldHeight);
  245.  
  246.    if (TooBig || ForceUpdate)
  247.    {
  248.       if (TooBig) VScreen->ViewPort.DHeight = OldHeight;
  249.       MakeScreen(VScreen);
  250.       MrgCop(&(IntuitionBase->ViewLord));
  251.    }
  252.    FindBounds();
  253. }
  254.  
  255.  
  256. /*
  257.  *  CheckShift()
  258.  *
  259.  *  Check that a forced screen shoft will not go too far.  If it does, then
  260.  *  clear the InputEvent mouse movement so that the mouse doesn't move
  261.  *  when the screen can't scroll any more.
  262.  *
  263.  *  If the mouse is not over the virtual screen, then we don't want the
  264.  *  mouse to move at all, so clear the InputEvent mouse movement.
  265.  */
  266.  
  267. static void CheckShift(Xshift,Yshift,theEvent)
  268. WORD *Xshift,*Yshift;
  269. struct InputEvent *theEvent;
  270. {
  271.    if (*Xshift < -RxOffset2 ||
  272.        *Xshift > TWICE_X(ScreenWidth-OldWidth)-RxOffset2)
  273.    {
  274.       *Xshift -= theEvent->ie_X;
  275.       theEvent->ie_X = 0;
  276.    }
  277.    if (*Yshift < -RyOffset2 ||
  278.        *Yshift > TWICE_Y(ScreenHeight-OldHeight)-RyOffset2)
  279.    {
  280.       *Yshift -= theEvent->ie_Y;
  281.       theEvent->ie_Y = 0;
  282.    }
  283.    if (NotVScreen) theEvent->ie_X = theEvent->ie_Y = 0;
  284. }
  285.  
  286.  
  287. /*
  288.  *  ShiftVScreen()
  289.  *
  290.  *  Shift the virtual screen by the specified amount.
  291.  *
  292.  *  If there is movement in the X direction,
  293.  *    Check that the screen does not scroll too far to the left or right.
  294.  *    If it does, then reduce the move so that the screen scrolls to the edge.
  295.  *    If the mouse is over the virtual screen, then
  296.  *      Adjust the Min and Max values for when scrolling occurs.
  297.  *    Increment the Screen's ViewPort RasInfo RxOffset by the amount of
  298.  *      the scroll, and record the normalized value for later use.
  299.  *      The RxOffset is what tells the graphics library which part of the
  300.  *      larger bitmap should actually be displayed.
  301.  *
  302.  *  Similarly for the Y shift.
  303.  *
  304.  *  Finally, if there was actually movement in either direction,
  305.  *    Fix the View (FixView calls MakeScreen() and MrgCop()) and 
  306.  *    Load the new View.
  307.  */
  308.  
  309. static void ShiftVScreen(Xmove,Ymove)
  310. WORD Xmove,Ymove;
  311. {
  312.    WORD xOffset, yOffset;
  313.  
  314.    if (Xmove)
  315.    {
  316.       xOffset = *RxOffset + Xmove;
  317.       if (xOffset < 0) Xmove -= xOffset;
  318.       if (xOffset > ScreenWidth-OldWidth)
  319.          Xmove += (ScreenWidth-OldWidth - xOffset);
  320.       if (OVERVSCREEN)
  321.       {
  322.          MinXMouse += TWICE_X(Xmove);
  323.          MaxXMouse += TWICE_X(Xmove);
  324.       }
  325.       *RxOffset += Xmove;
  326.       RxOffset2  = TWICE_X(*RxOffset);
  327.    }
  328.  
  329.    if (Ymove)
  330.    {
  331.       yOffset = *RyOffset + Ymove;
  332.       if (yOffset < 0) Ymove -= yOffset;
  333.       if (yOffset > ScreenHeight-OldHeight)
  334.          Ymove += (ScreenHeight-OldHeight - yOffset);
  335.       if (OVERVSCREEN)
  336.       {
  337.          MinYMouse += TWICE_Y(Ymove);
  338.          MaxYMouse += TWICE_Y(Ymove);
  339.       }
  340.       *RyOffset += Ymove;
  341.       RyOffset2  = TWICE_Y(*RyOffset);
  342.    }
  343.  
  344.    if (Xmove || Ymove)
  345.    {
  346.       FixView(TRUE);
  347.       LoadView(&(IntuitionBase->ViewLord));
  348.    }
  349. }
  350.  
  351.  
  352. /*
  353.  *  cLoadView()
  354.  *
  355.  *  Replaces the LoadView function in the graphics library (the stub calls
  356.  *  the old LoadView() after cLoadView() runs).
  357.  *
  358.  *  If the virtual screen is still open, and the view is the Intuition View,
  359.  *  the Fix the view (make sure that the height is no larger than the 
  360.  *  old MaxDisplayHeight).
  361.  *
  362.  *  Note:  when you drag a screen up and down, Intuition calls RemakeDisplay()
  363.  *  which in turn calls MakeScreen() on each screen, MrgCop() and finally
  364.  *  LoadView().  cLoadView() gets called in place of LoadView(), and it will
  365.  *  call FixView(), which calls MakeScreen() and MrgCop() again.  This are high
  366.  *  overhead calls, so when the virtual screen is the FirstScreen and there is
  367.  *  another screen showing behind it, this can nearly double the overhead of
  368.  *  dragging a screen.
  369.  */
  370.  
  371. void cLoadView(view)
  372. struct View *view;
  373. {
  374.    if (VScreen && view == &(IntuitionBase->ViewLord)) FixView(FALSE);
  375. }
  376.  
  377.  
  378. /*
  379.  *  cMoveSprite();
  380.  *
  381.  *  Repaces MoveSprite() in the graphics library (the stub calls the old
  382.  *  MoveSprive() after cMoveSprite() runs).
  383.  *
  384.  *  If the sprite being moved is sprite zero (the pointer sprite), and
  385.  *  the virtual screen is still open, then
  386.  *    If the pointer is over the virtual screen
  387.  *      Subtract the offsets (relative to a 320 x 200 screen, since this
  388.  *      is a sprite).  We must do this, since we added RxOffset and RyOffset
  389.  *      to the Intuition MouseX and MouseY values.  Since Intuition does not
  390.  *      take the RxOffset and RyOffset into account, we have to subtract
  391.  *      the values here in order to keep the pointer on the display area.
  392.  *
  393.  *    If the Min and Max X Mouse values are equal, a screen is being dragged.
  394.  *    If the LayerInfo Lock has a NestCount, then the layers are locked.
  395.  *
  396.  *    If the mouse is not over the virtual screen then
  397.  *      Set the MinY for scrolling to the top of the view.
  398.  *      If we used to be over the virtual screen and 
  399.  *         we're not currently dragging a screen, then
  400.  *        If the virtual screen is not locked, then
  401.  *          Reset the coordinate system to fit the screen we are over.
  402.  *          Save which type of screen we're over.
  403.  *         otherwise (the screen is locked; e.g., the user has the
  404.  *                    menu button down, or is dragging a window),
  405.  *          so scroll the screen if we move off the top.
  406.  *    Otherwise (the mouse IS over the virtual screen)
  407.  *      Set the MinY for scrolling to the top of the view relative to the 
  408.  *        virtual screen origin.
  409.  *      If we used to be over some other screen, and we're not dragging
  410.  *         a screen, and the current screen is not locked, then
  411.  *        (we need to change coordinates to the virtual screen coordinates)
  412.  *        If we are going from a bottom screen onto the virtual screen
  413.  *          then activate the cirtual screen (I couldn't find a way to do
  414.  *          the coordinate transfer without this).
  415.  *        Set the coordinates relative to the virtual screen.
  416.  *        Record that we are over the virtual screen.
  417.  *
  418.  *    If a new screen has become active then
  419.  *      If we were over the virtual screen, check that we still are
  420.  *      Record the active screen
  421.  *
  422.  *    If the user is dragging the screen, don't let him drag it off
  423.  *      the bottom of the display area (where he won;t be able to reach it).
  424.  *
  425.  *    If the MouseY has gone past the top of the screen (i.e., if a screen
  426.  *      has closed and the pointer was above it), put the pointer at the
  427.  *      top of the display.
  428.  */
  429.  
  430. void cMoveSprite(ss,x,y)
  431. struct SimpleSprite *ss;
  432. long x,y;
  433. {
  434.    short NotDrag;
  435.    short NotLocked;
  436.  
  437.    if (ss->num == 0 && VScreen)
  438.    {
  439.       if (OVERVSCREEN)
  440.       {
  441.          x -= NHALF_X(*RxOffset);
  442.          y -= NHALF_Y(*RyOffset);
  443.       }
  444.  
  445.       NotDrag = (IntuitionBase->MinXMouse != IntuitionBase->MaxXMouse);
  446.       NotLocked = 
  447.          (IntuitionBase->ActiveScreen->LayerInfo.Lock.ss_NestCount == 0);
  448.  
  449.       if (y < ScreenTop || y >= ScreenBottom)
  450.       {
  451.          MinYMouse = IntuitionBase->MouseYMinimum;
  452.          if (OVERVSCREEN && NotDrag)
  453.          {
  454.             if (NotLocked)
  455.             {
  456.                ResetVScreen();
  457.                NotVScreen = (y < ScreenTop)? TOPSCREEN: BOTTOMSCREEN;
  458.             } else {
  459.                if (y < ScreenTop) ShiftVScreen(0,NTWICE_Y(y-ScreenTop));
  460.             }
  461.          }
  462.       } else {
  463.          MinYMouse = IntuitionBase->MouseYMinimum + RyOffset2;
  464.          if (NotVScreen && NotDrag && NotLocked)
  465.          {
  466.             if (NotVScreen == BOTTOMSCREEN &&
  467.                 IntuitionBase->ActiveScreen != VScreen &&
  468.                 VScreen->FirstWindow) ActivateWindow(VScreen->FirstWindow);
  469.             SetVScreen();
  470.             NotVScreen = FALSE;
  471.          }
  472.       }
  473.  
  474.       if (OldScreen != IntuitionBase->ActiveScreen)
  475.       {
  476.          if (OVERVSCREEN) SetScreenMinMax();
  477.          OldScreen = IntuitionBase->ActiveScreen;
  478.       }
  479.  
  480.       if (NotDrag == FALSE &&
  481.           IntuitionBase->MaxYMouse > OldMaxDR + RyOffset2)
  482.               IntuitionBase->MaxYMouse = OldMaxDR + RyOffset2;
  483.  
  484.       if (IntuitionBase->MouseY < IntuitionBase->MinYMouse)
  485.          IntuitionBase->MouseY = IntuitionBase->MinYMouse;
  486.    }
  487. }
  488.  
  489.  
  490. /*
  491.  *  cAutoRequest()
  492.  *
  493.  *  Replaces AutoRequest() in the Intuition Library (the stub calls 
  494.  *  AutoRequest() after cAutoRequest() runs).
  495.  *
  496.  *  If the AutoRequest is to appear on the virtual screen, then shift
  497.  *  the virtual screen so that the System Request window will be showing.
  498.  *  Note that this could change the screen position even while the user is
  499.  *  doing critical work (e.g., dragging a window, pulling menus, etc).
  500.  *  It would be better to trap this through BuildSysRequest(), but since
  501.  *  Intuition does not use its own vector table, I can not trap all the
  502.  *  calls to BuildSysRequest, specifically, the ones called by AutoRequest().
  503.  */
  504.  
  505. void cAutoRequest(theWindow)
  506. struct Window *theWindow;
  507. {
  508.    if (theWindow == NULL || theWindow->WScreen == VScreen)
  509.    {
  510.       IntuitionBase->MouseX -= RxOffset2;
  511.       IntuitionBase->MouseY -= RyOffset2;
  512.       ShiftVScreen(-(*RxOffset),-(*RyOffset));
  513.    }
  514. }
  515.  
  516.  
  517. /*
  518.  *  cBuildSysRequest()
  519.  *
  520.  *  Replaces BuildSysRequest() in the Intuition Libaray (the stub routine
  521.  *  calls BuildSysRequest() before calling cBuildSysReques()).
  522.  *
  523.  *  If the window (returned by BuildSysRequest) exists, then
  524.  *    If it is on the virtual screen, and it is not completely showing, then
  525.  *      Move the window so that it is in the upper left corner of the
  526.  *        displayed section of the screen.
  527.  *
  528.  *  Note that this is better than what we do with AutoRequest, since the
  529.  *  screen itself does not scroll.
  530.  */
  531.  
  532. void cBuildSysRequest(theWindow)
  533. struct Window *theWindow;
  534. {
  535.    if (theWindow && theWindow != (struct Window *)TRUE)
  536.    {
  537.       if (theWindow->WScreen == VScreen &&
  538.          (theWindow->LeftEdge < *RxOffset ||
  539.           theWindow->TopEdge  < *RyOffset))
  540.              MoveWindow(theWindow,*RxOffset-theWindow->LeftEdge,
  541.                                   *RyOffset-theWindow->TopEdge);
  542.    }
  543. }
  544.  
  545.  
  546. /*
  547.  *  cCloseScreen()
  548.  *
  549.  *  Replaces CloseScreen() in the IntuitionLibrary (the stub routine calls
  550.  *  CloseScreen() after cCloseScreen() runs).
  551.  *
  552.  *  If the virtual screen is still open, and it is the one being closed,
  553.  *    reset the coordinate system, and mark the virtual screen as closed.
  554.  */
  555.  
  556. void cCloseScreen(theScreen)
  557. struct Screen *theScreen;
  558. {
  559.    if (theScreen == VScreen && VScreen != NULL)
  560.    {
  561.       ResetVScreen();
  562.       VScreen = NULL;
  563.    }
  564. }
  565.  
  566.  
  567. /*
  568.  *  myHandler()
  569.  *
  570.  *  This is the input handler that gets added to the Input.Device input
  571.  *  chain.  It is at priority 51, so it is ahead of Intuition.
  572.  *
  573.  *  If a screen is not being dragged, and the virtual screen is still open,
  574.  *    then for each event in the event list,
  575.  *      If the event is a RAWMOUSE event,
  576.  *        If the left Amiga key is held down then
  577.  *          Add it into the forced shift count and
  578.  *          Check that the shift is valid.
  579.  *        Add the movement into the total movement so far.
  580.  *
  581.  *    Find the new MouseX and MouseY positions.
  582.  *    Shift the screen by the forced shift amounts, checking that the 
  583.  *      coordinates are shifted when needed, and retaining any un-used
  584.  *      shift amount (due to LoRes or Non-Interlaced screens).
  585.  *
  586.  *    If the active screen is the virtual screen, then
  587.  *      if the mouse has moved off the left or right edge of the display,
  588.  *      or if the mouse has moved past the Intuition Min or Max values,
  589.  *      then shift the screen by the appropriate amount.  Do this for 
  590.  *      both the X and Y directions.
  591.  *
  592.  *  Finally, return the original event list.
  593.  */
  594.  
  595. struct InputEvent *myHandler(EventList,data)
  596. struct InputEvent *EventList;
  597. APTR data;
  598. {
  599.    struct InputEvent *theEvent = EventList;
  600.    WORD MouseX,MouseY;
  601.    WORD Xmove = 0;
  602.    WORD Ymove = 0;
  603.    WORD Ychange = 0;
  604.    WORD Xchange = 0;
  605.    WORD dx,dy;
  606.    
  607.    if (IntuitionBase->MinXMouse != IntuitionBase->MaxXMouse && VScreen)
  608.    {
  609.       Forbid();
  610.       while (theEvent)
  611.       {
  612.          if (theEvent->ie_Class == IECLASS_RAWMOUSE)
  613.          {
  614.             if ((theEvent->ie_Qualifier & SHIFTQUALS) == IEQUALIFIER_LCOMMAND)
  615.             {
  616.                Xshift += theEvent->ie_X;
  617.                Yshift += theEvent->ie_Y;
  618.                CheckShift(&Xshift,&Yshift,theEvent);
  619.             }
  620.             Xchange += theEvent->ie_X;
  621.             Ychange += theEvent->ie_Y;
  622.          }
  623.          theEvent = theEvent->ie_NextEvent;
  624.       }
  625.       Permit();
  626.    
  627.       MouseX = IntuitionBase->MouseX + HALF_X(Xchange);
  628.       MouseY = IntuitionBase->MouseY + HALF_Y(Ychange);
  629.  
  630.       if (Xshift < 0) dx = -HALF_X(-Xshift); else dx = HALF_X(Xshift);
  631.       if (Yshift < 0) dy = -HALF_Y(-Yshift); else dy = HALF_Y(Yshift);
  632.       if (dx || dy)
  633.       {
  634.          ShiftVScreen(dx,dy);
  635.          if (IntuitionBase->ActiveScreen != VScreen && OVERVSCREEN)
  636.             SetScreenMinMax();
  637.          if (HiResScreen) Xshift = 0; else Xshift %= 2;
  638.          if (LaceScreen)  Yshift = 0; else Yshift %= 2;
  639.       }
  640.  
  641.       if (IntuitionBase->ActiveScreen == VScreen)
  642.       {
  643.          if (MouseX < MinXMouse) Xmove = MouseX - MinXMouse;
  644.          if (MouseX > MaxXMouse) Xmove = MouseX - MaxXMouse;
  645.          if (Xmove == 0)
  646.          {
  647.             if (MouseX < IntuitionBase->MinXMouse)
  648.                Xmove = MouseX - IntuitionBase->MinXMouse;
  649.             if (MouseX > IntuitionBase->MaxXMouse)
  650.                Xmove = MouseX - IntuitionBase->MaxXMouse;
  651.          }
  652.    
  653.          if (MouseY < MinYMouse) Ymove = MouseY - MinYMouse;
  654.          if (MouseY > MaxYMouse) Ymove = MouseY - MaxYMouse;
  655.          if (Ymove == 0)
  656.          {
  657.             if (MouseY < IntuitionBase->MinYMouse)
  658.                Ymove = MouseY - IntuitionBase->MinYMouse;
  659.             if (MouseY > IntuitionBase->MaxYMouse)
  660.                Ymove = MouseY - IntuitionBase->MaxYMouse;
  661.          }
  662.  
  663.          if (Xmove || Ymove) ShiftVScreen(Xmove,Ymove);
  664.       }
  665.    }
  666.    return(EventList);
  667. }
  668.  
  669.  
  670. /*
  671.  *  These are the assembler stubs needed in order to SetFunction some
  672.  *  of the Intuiton and graphics library functions.
  673.  */
  674.  
  675. extern void myHandlerStub();
  676.  
  677. extern void aCloseScreen();
  678. extern void aBuildSysRequest();
  679. extern void aAutoRequest();
  680. extern void aLoadView();
  681. extern void aMoveSprite();
  682.  
  683.  
  684. /*
  685.  *  These are the jump addresses in the assembler routines that need to
  686.  *  be filled in by vScreen once the old SetFunction vectors are known.
  687.  *  This is a kludge, and is a form od self-modifying code, but I can't figure
  688.  *  out a better way that works.  The JSR (Ax) form is only good if there is
  689.  *  a free A register to use, which is not always the case.
  690.  */
  691.  
  692. extern unsigned char *CloseScreenJmpAddress;
  693. extern unsigned char *BuildSysRequestJmpAddress;
  694. extern unsigned char *AutoRequestJmpAddress;
  695. extern unsigned char *LoadViewJmpAddress;
  696. extern unsigned char *MoveSpriteJmpAddress;
  697.  
  698. static char PortName[] = PORTNAME;      /* the name of the named port */
  699.  
  700. static struct Interrupt HandlerInfo =   /* the Interrupt needed to add an */
  701. {                                       /*  input handler to the input chain */
  702.    {NULL, NULL, 0, 51, NULL},           /*  ln_Pri = 51 (before Intuition) */
  703.    NULL,
  704.    &myHandlerStub                       /* the handler to add */
  705. };
  706.  
  707.  
  708. /*
  709.  *  This is the structure passed from the Setup() routine to vScreen.
  710.  *  It includes pointers to the variables that vSCreen needs to initialize,
  711.  *  plus pointers to the routines that vScreen will SetFunction into the
  712.  *  appropriate libraries.
  713.  */
  714.  
  715. struct vScreenInfo vScreenData =
  716. {
  717.    MAJVER,MINVER,0,
  718.    &program[0],
  719.    &PortName[0],
  720.    NULL,
  721.    &HandlerInfo,
  722.    &IntuitionBase, &GfxBase,
  723.  
  724.    &VScreen,
  725.    &ScreenWidth,&ScreenHeight,
  726.    &OldWidth,&OldHeight,
  727.    &RxOffset,&RyOffset,
  728.    &RxOffset2,&RyOffset2,
  729.    &LaceScreen,&LaceShift,
  730.    &HiResScreen,&HiResShift,
  731.    &OldMaxDH,&OldMaxDR,&OldMaxDW,
  732.    
  733.    &SetVScreen, &ResetVScreen, &FixView,
  734.  
  735.    &aCloseScreen, &aBuildSysRequest, &aAutoRequest, &aLoadView, &aMoveSprite,
  736.    
  737.    (long *) &CloseScreenJmpAddress,
  738.    (long *) &BuildSysRequestJmpAddress,
  739.    (long *) &AutoRequestJmpAddress,
  740.    (long *) &LoadViewJmpAddress,
  741.    (long *) &MoveSpriteJmpAddress,
  742.    
  743.    0,0,0,0,0
  744. };
  745.