[comp.sources.amiga] vscreen

ain@j.cc.purdue.edu (Patrick White) (06/23/88)

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.d.sh.Z binaries/amiga/volume6/vscreen.d.sh.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.doc
# This archive created: Wed Jun 22 11:39:41 1988
# By:	Patrick White (PUCC Land, USA)
echo shar: extracting vScreen.doc '(21519 characters)'
cat << \SHAR_EOF > vScreen.doc

OVERVIEW:

VSCREEN allows you to have screens that are larger than the actual display 
area of your monitor.  These larger "virtual" screens scroll when you move the
mouse off the edge of the visible section of the screen.  vScreen allows you
to create a screen large enough for a full page of editing, for example.  Not
all programs are set up to take advantage of vScreen, however, but most 
programs that provide winodow-sizing gadgets can benefit from vScreen.

WARNING:  vScreen does devious and illegal things with the INTUITIONPRIVATE
section of the IntuitionBase structure.  Use it at your own risk.  vScreen is
likely to be incompatible with a future release of the system software.


HOW TO USE VSCREEN:

You should place vScreen in your C: directory (or in your current PATH).  
vScreen-Handler should be in the L: directory (or the current directory).  To
start vScreen, issue the following command:

    1> VSCREEN width height ["screen-name"]

where  width  is the new width for the virtual screen,  height  is the new
height, and  "screen-name"  is the name of the screen that you want to make
larger.  If the screen name includes spaces or other special characters, you
should enclose it in quotation marks.  If you do not supply a screen name, 
vScreen will enlarge the active screen.  

The width and height should be at least as large as the current size of the
screen, and width and height should not be larger than 1024 (see the section
titled USAGE NOTES below).

For example, if you type

    1> VSCREEN 800 400

then the workbench screen will be enlarged to 800 by 400.

When you receive the "vScreen Installed" message, your screen will be a
virtual screen of the size you specified.

To view other parts of the virtual screen, simply move the mouse off the edge
of the visible portion of the screen so that it moves over the portion of the
screen that you want to see.  For example, if the upper left-hand corner of
the screen is showing, and you want to see the lower right-hand corner, just
move the mouse off the lower right-hand edge of the display.  The screen will
scroll to show you more of the screen in the direction that you moved the
mouse. 

Note that the screen will scroll even when you are doing things that normally 
"lock" the screen.  For example, if you are changing the size of a window or
dragging a window, and you move the mouse off the edge of the displayed
portion of the screen, the screen will still scroll.  The screen will not
scroll if you are dragging the screen, however, or if the virtual screen is 
not the active screen.

You can force the screen to scroll without moving the mouse to the edge of the
screen by holding down the left-amiga key and moving the mouse.  This scrolls
the virtual screen while keeping the mouse at the same location on the display.

Note:  you can only have one virtual screen at a time under the current
release of vScreen (1.0.1).


If you want to remove vScreen and restore the normal sized screen, simply call
vScreen again:

    1> VSCREEN

You should receive a "vScreen removed" message.  vScreen will make sure that 
all the windows currently open on the screen are moved and sized so that they 
will fit on the normal sized screen.


USAGE NOTES:

When you enlarge a window using vScreen, the entire new screen is stored in
CHIP memory (not just the part that is currently showing).  For this reason,
vScreen may use up large pieces of CHIP memory.  Don't specify a screen that
is too large for the amount of memory that you have.  vScreen does not recover
well from low-memory conditions.

Although vScreen will allow you to specify a screen wider than 1024, you
should be aware that screens of this size can be a problem.  The blitter has a
limitation on the size of a block that it will move.  The RKM puts this limit
at 976 (see BltBitMap() in the autodocs), but empirical testing indicates that 
values up to 1024 will work.  Above this size, blit operations fail to work
properly, so in a screen larger than 1024, dragged window may not update
correctly and the menu bar will not appear. 

Similarly, screens taller than 1024 lines also can cause update problems.

vScreen will allow you to specify dimentions that are SMALLER than the current
screen, but this is not recommended.  vScreen will not function properly if a
screen is reduced in size.  Unexpected display effects will occur when the
screen is scrolled.

Due to the method used to display only a portion of the larger screen,
dragging a screen may incur noticably more overhead than usual.  This occurs
only when the virtual screen is the top-most screen and there is another
screen visable.  See the section on HOW VSCREEN WORKS for more details.

vScreen inserts an input handler in the Input.Device input chain and uses the
SetFunction() routine to replace Intuition and Graphics library routines.  For
this reason, only one copy of vScreen should be running at one time.  This
means that, under the current version of vScreen, you may only have one
virtual screen at a time.  If there is popular demand, a future release will
lift this restriction, and will provide a programmer's interface to vScreen.

If the virtual screen closes while vScreen is running, vScreen will become
disabled, but will not actaully be removed from the input chain or the library
vector tables (in order to keep the resident portion of vScreen as small as
possible, these functions are performed by the loader).  In order to actually
remove vScreen from the system, you must call vScreen a second time.  Note
that if you have set the workbench screen as a virtual screen and an
application calls CloseWorkBench() (and the screen actually closes), then when
the workbench is opened again, it no longer will be a virtual screen:  it will
have changed back to its original size.  You will have to remove the old copy
of vScreen (by calling vScreen with no parameters), and then re-install it to
make the workbench virtual again.

vScreen works with all view modes (lo-res, hi-res, interlace and HAM).  HAM
screens, however, may have discoloration along the left border when the left
edge is not showing.  This is due to the fact that the left edge of the
display will be the background color rather than the color of the previous
pixel that is not being displayed.

If the active screen is in front of the virtual screen and you move the mouse 
so that it passes over the virtual screen, then the top window of the virtual 
screen will become active (and the previous active screen will become 
inactive).  See the section on HOW VSCREEN WORKS for more details on why
this is necessary under the current release of Intuition.

The Intuition window structure includes fields for the maximum size that the
window may have.  Most current programs that allow their windows to be
sized specify that the windows can be made arbitrarily large.  Some older
programs, however, specify maximum sizes equal to a standard sized screen 
(e.g. 640 x 200).  These windows may not be able to grow as large as a virtual
screen.  For this reason, vScreen comes with a number of utilities that help
you to manipulate windows "by hand" (see OTHER UTILITIES below).


OTHER UTILITIES:

vScreen comes with four utility programs to help you manipulate windows on
virtual screens:  wSize wMove wMax and wList.

wSize allows you to change the size of any window, even if it does not have a
window sizing gadget.  To use wSize, issue the command:

    1> wSize dx dy ["window" ["screen" [IGNOREMAX]]]

where  dx  and  dy  are the number of pixels that the window should grow by in
the  x  and  y  directions (note that negative values are allowed).  "Window"
is the name of the window that is to be changed (if the name includes spaces
or other special characters it should be enclosed in quotation marks).  If no
name is specified then the active window is changed.  "Screen" is the name of
the screen where the window can be found (enclosed in quotation marks of the
name includes spaces).  If no screen name is specified then the active screen
is used.  The window will not shrink smaller than its minimum allowable size
(as stored in its window structure), and it will not grow larger than the 
size of the screen, nor larger than its maximum size (as stored in its window
structure) unless IGNOREMAX is specified.

For example:

    1> wSize 50 25 "AmigaDOS"

will increase the size of the window named "AmgiaDOS" (on the current screen)
by 50 pixels in the  x  direction and 25 in the  y  direction.

You can use wSize to enlarge backdrop windows on screens that have them. 
This is useful, for instance, for paint programs that render your picture
into a backdrop window without a sizing gadget.


wMove is similar to wSize, except that it moves the window rather than change
its size.  The parameters are the same (except there is no IGNOREMAX flag):

    1> wMove dx dy ["window" ["screen"]]

where  dx  and  dy  are the amounts by which to move the window, "window" is 
the name of the window to move, and "screen" is the screen where that window 
can be found.  The screen defaults to the current screen, and the window 
defaults to the active window.  A window will not be moved off the edge of 
the screen.


wMax allows you to change the maximum size setting that is stored in the
window's structure.  Call it with the following parameters:

    1> wMax x y ["window" ["screen"]] 

where  x  is the maximum size horizontally, y  is the maximum size vertically, 
"window" is the name of the window to change, and "screen" is the name of the
screen where that window can be found.  If the screen or window name contains 
a space or special character, enclose the name in quotation marks.  If no
screen is specified, the active screen is used.  If no window is specified,
the active window is changed.  A size of -1 means that the window can be
stretched to any size in that direction.

For example:

    1> wMax -1 -1

allows the active window to grow to any size.


wList prints a list of all the windows on a specific screen, or all the
screens:

    1> wList ["screen"]

where "screen" is the name of the screen whose windows will be listed.  If 
the screen name includes spaces or special characters, then enclose it in
quotation marks.  If no screen name is specified, then the names of all the 
windows on all the screens are printed.

For example:

    1> wList "Workbench Screen"

will list the names of all the windows on the workbench.


HOW VSCREEN WORKS:

The graphics library defines a structure called a View, which represents the
entire visible area of the display.  The View is broken down into separate
ViewPorts.  Each ViewPort can have its own view mode (hi-res, interlace, HAM,
etc.), and each ViewPort can be a different size.

Intuition maintains a View (called the ViewLord), where each ViewPort
corresponds to an Intuition Screen (that's how screens can be of different
sizes and resolutions).  Windows within those screens have no direct analog
in the Graphics library (they correspond to Layers in the Layers library).

Each ViewPort has a related RasInfo structure that includes a pointer to its
bitmap.  When vScreen runs, it allocates new, larger bitplanes for the
ViewPort, and copies the data from the old planes into the new ones.  This
provides a larger bitmap for the corresponding screen.  Once this larger
bitmap is in place, all graphics calls proceed normally, as the Graphics
library handles the larger bitmap without trouble.

The RasInfo structure also includes two other fields:  RxOffset and RyOffset.
These represent the upper, left-hand corner of the section of bitmap that will 
appear within the ViewPort.  Translated into Intuition terms, this tells what 
part of a Screen's larger bitmap will be showing.  vScreen uses these offsets 
to allow you to scroll the virtual screen; no memory is copied, so the 
scrolling is very fast.

Unfortunately, Intuition does not take these offsets into account when it
figures the position of the mouse (when buttons are pressed, gadgets are
clicked, etc.).  The bulk of the vScreen-Handler is devoted to tricking
Intuition into handling these offset values correctly.

Initially, vScreen sets the screen width and height to the new size of the
screen.  When MakeScreen() is called for the virtual screen, and the screen is
the front screen, Intuition will set the ViewPort height to be the height of
the screen.  This would cause the screen to become an "overscan" screen when 
it's not supposed to be.  

Ideally, vScreen would trap the MakeScreen() call and change the value back.  
Unfortunately, however, MakeScreen() is called by RethinkDisplay() and 
RemakeDisplay(), which are both called by Intuition itself (when a new screen 
is opened or moved, for example).  Since Intuition does not call its own jump 
table vectors, we are not able to trap ALL the calls to MakeScreen(), so that 
is not an effective method of fixing the problem.

Most often, after a MakeScreen() call, there will be calls to MrgCop() and
LoadView() (this is what happens with RethinkDisplay() and RemakeDisplay()). 
Since LoadView() is in the Graphics library, not the Intuition library,
Intuition DOES call LoadView() through the graphics library vector table. 
This provides a viable hook that we can use to fix the overscan problem. 
Whenever LoadView() is called on the Intuition ViewLord, we check that the
ViewPort for the virtual screen does not have a height that is too large.  If
it does, we reduce the height and call MrgCop() again (this is what slows down
dragging the virtual screen when it is on top).

This fix to LoadView() makes the larger virtual screens display properly for
any given set of RxOffset and RyOffset.  The input handler is what changes
these offsets.  The handler adds up all the mouse movements within the input
event list, and adds them to the current Intuition MouseX and MouseY values. 
If these would cause the mouse to move off the edge of the displayed area of
the screen, then the handler sets the offsets so that the mouse stays on the
screen.  The handler also checks for forced shifts (left amiga held down while 
moving the mouse).

Once the screen is shifted, however, the mouse X and Y values can get very
large.  When Intuition positions the sprite that represents the mouse pointer,
it does not take RxOffset and RyOffset into account and hence can position
the pointer off the edge of the display.  For this reason, vScreen traps the
MoveSprite() graphics function, and when the virtual screen is active and
sprite zero is positioned, vScreen compensates for the offsets itself.  This
guarantees that the mouse pointer is positioned over the correct part of the
shifted virtual screen.

Intuition uses the MaxDisplayRows and MaxDisplayWidth to calculate the range
of X and Y values over which the mouse can travel (MinXMouse, MaxXMouse,
MinYMouse, and MaxYMouse).  The min and max values are changed when you drag a
window or screen, and when you change a window's size through its sizing
gadget.  In order to make it possible to move windows over the entire area of
the virtual screen, vScreen modifies the MaxDisplay values that Intuition uses.

At this point, the virtual screen works correctly; however, interactions
between the virtual screen and other screens do not.  Intuition does not take
into account the RasInfo offsets when it calculates the position of the top of
the screen.  For example, if the virtual screen is shifted vertially so that 
the top 20 lines are not showing, and another screen is visible behind the 
virtual screen, and you click in that screen but within 20 lines of the top of
the virtual screen, Intuition will think you clicked in the virtual screen
itself (in the upper area that is not currently showing).  Worse yet, if you
click higher up in the other screen (over 20 lines above the top of the
virtual screen), Intuition will see that you hit the other screen, but will
think the mouse is 20 lines lower than it is.  This is because the Intuition
MouseY value is off by RyOffset pixels.

To avoid these problems, vScreen monitors the mouse movements to tell when the
mouse changes from being over the virtual screen to being over some other
screen.  When the pointer moves over some other screen, vScreen resets the
MouseX and MouseY values to their normal positions.  That way, if a mouse
click occurs in the other screen, it will occur at the proper place.  When the
pointer moves back over the virtual screen, the MouseX and MouseY are returned
to their positions relative to the virtual screen's RxOffset and RyOffset
values.

This works fine whenever the virtual screen is the active screen and the
pointer moves over another screen either in front of or behind the virtual
screen.  It also works if a screen behind the virtual screen is active and
the mouse moves over the virtual screen.  It does not work, however, if a
screen in front of the virtual screen is active and the mouse moves over the
virtual screen.  In this case, if the MouseY value were changed and the mouse
button pressed, Intuition would incorrectly think the mouse was positioned 
over the active screen.  For this reason, when a non-virtual screen is active
and in front of the virtual screen, and the mouse moves over the virtual
screen, the virtual screen is activated.  This is not consistant with normal
Intuition actions, but does ensure that mouse clicks will be reported correctly.

Normally, you can move the mouse pointer past the top edge of a screen so that
it is over another screen and the virtual screen will not scroll until the
pointer hits the top of the physical display.  If you are dragging a window,
however, or are holding down the menu button, or doing some other action that 
locks the screen layers, then the screen will scroll when you move the pointer
past the top of the screen (rather than waiting until it reaches the top of
the display).  This makes it easier to select menus when the screen is
scrolled vertically, for instance.

If an AutoRequest() occurs on the virtual screen, the screen will automatically
shift so that the upper left-hand corner is showing (just like the screen
where an AutoRequest occurs will be brought to the front).

If BuildSysRequest() is called on the virtual screen, then rather than shift 
the screen, vScreen moves the request window so that it appears in the upper 
left-hand corner of the displayed area of the screen.  Ideally, this is what 
we should do for AutoRequest(), but since Intuition does not call its own 
vector table, we can not trap the BuildSysRequest() call made by AutoRequest().

Finally, vScreen traps calls to CloseScreen() so that it can tell when the
virtual screen is closed.  If the virtual screen closes, vScreen will cease
all its functions, but will not actually restore the trapped vectors or remove
the input handler or free its memory until you remove vScreen by calling
vScreen a second time.

I do not recommend that you use this approach in your own programs. 
Modifying, or even viewing, the INTUITIONPRIVATE data structure is frowned
upon by Commodore-Amiga, and will make your programs unreliable in future
versions of Intuition.  Furthermore, if more than one program uses this
method, they will probably interact destructively.  If there is sufficient
demand, and provided Commodore does not incorporate something like this in a
future release of Intuition, I may be convinced to put this functionality
into a library with a callable interface for programs to use.


COMPILING VSCREEN:

vScreen was developed using the Lattice C compiler v4.0 on a 512K Amiga 1000.
It probably will need to be changed in order to work with Manx Aztec C.  To
compile and link vScreen use the following commands:

    1> lc -v -b0 vScreen vScreenSetup vScreen-Handler
    1> asm vScreenStubs
    1> blink with vScreen.lnk
    1> blink with vScreen-Handler.lnk

I prefer not to use the Lattice function prototypes, but I like to use the
direct-library-call preprocessor commands, therefore, I have modified my
prototype include files to remove the function prototypes (via an #ifdef).
If you compile the source files with the -dPROTO flag, then the Lattice proto
include files will be used (there will be compile-time warnings), otherwise,
they will not be included.


AUTHOR:

vScreen and vScreen-Handler
Copyright 1988 by Davide P. Cervone, All rights reserved.

You may distribute this program and source code for non-commercial purposes, 
provided you include this documentation.  You may not ditribute this program 
as part of a commercial product without the author's written permission.  
You may not include this source code as part of your own programs.

(Sorry about the restrictions on the use of vScreen, but I think that using
the INTUITIONPRIVATE stuff is a terrible thing to do, and I don't want it to
appear in any commercial products.  I'm hoping that Commodore-Amiga will pick
up on the idea and incorporate it into Intuition, where it belongs, and where
it would be much easier to do.  If they don't, then I plan to do my own
virtual screen library, and I don't want anyone else's programs to break, or
to get in the way).

If you find an interesting use for vScreen, please drop me a note.


Davide P. Cervone
University or Rochester Computing Center            dpvc@tut.cc.rochester.edu
Taylor Hall                                         dpvc@ur-tut.UUCP
Rochester, New York  14627                          DPVC@UORDBV.BITNET
(716) 275-2811
SHAR_EOF
if test 21519 -ne "`wc -c vScreen.doc`"
then
echo shar: error transmitting vScreen.doc '(should have been 21519 characters)'
fi
#	End of shell archive
exit 0

ain@j.cc.purdue.edu (Patrick White) (06/24/88)

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.2of2.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.c
#	vScreenSetup.c
#	wList.c
#	wMax.c
#	wMove.c
#	wSize.c
# This archive created: Wed Jun 22 11:35:24 1988
# By:	Patrick White (PUCC Land, USA)
echo shar: extracting vScreen.c '(14176 characters)'
cat << \SHAR_EOF > vScreen.c
/*
 *  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.
 */

#include "vScreen.h"

static char *program = "vScreen";           /* the program name */
static char *author  = COPYRIGHT;           /* the copyright notice */
#define LOADVERS        1                   /* this program's version */

static char *handler = "L:vScreen-Handler"; /* the name of the handler */
#define HANDLER         &(handler[2])       /* same but in the current dir */


extern struct LayersBase *LayersBase;       /* the Layers library */
 
struct vScreenInfo *vScreenData;            /* data needed by the handler */
struct Screen *VScreen = NULL;              /* the virtual screen */
static long Segment = NULL;                 /* the loaded handler */
SHORT ScreenWidth,ScreenHeight;             /* the new screen sizes */

static struct MsgPort *NamedPort = NULL;    /* used to find the handler later */
static struct MsgPort *InputPort = NULL;    /* to talk to Input.Device */
static struct IOStdReq *InputBlock = NULL;  /* IO block for Input.Device */
static short  InputDevice = FALSE;          /* is Input.Device open? */
static int    Enlarged = FALSE;             /* is screen changed? */


/*
 *  These routines are in vScreenSetup.c
 */

extern struct Screen *FindScreen();
extern void SetVariables();
extern void GetVariables();
extern int  EnlargeScreen();
extern void RestoreScreen();

 
#ifndef PROTO
extern long SetFunction();
#endif

/*
 *  We trap these routines via SetFunction in order to make vSscreen work.
 */

#ifndef PROTO
extern void MoveSprite();
extern void LoadView();
extern void AutoRequest();
extern void BuildSysRequest();
extern void CloseScreen();
#endif

extern long LVOMoveSprite;
extern long LVOLoadView;
extern long LVOAutoRequest;
extern long LVOBuildSysRequest;
extern long LVOCloseScreen;


/*
 *  CreateNonSigPort()
 *
 *  Creates a message port with signal type PA_IGNORE.  Based on
 *  CreatePort() from the exec support functions documented in the RKM.
 */

struct MsgPort *CreateNonSigPort(name,pri)
char *name;
BYTE pri;
{
   struct MsgPort *thePort;
   
   thePort = (struct MsgPort *)AllocMem((ULONG)sizeof(struct MsgPort),
                                         MEMF_PUBLIC | MEMF_CLEAR);
   if (thePort)
   {
      thePort->mp_Node.ln_Name = name;
      thePort->mp_Node.ln_Pri  = pri;
      thePort->mp_Node.ln_Type = NT_MSGPORT;
      
      thePort->mp_Flags = PA_IGNORE;
      thePort->mp_SigBit = 0;
      thePort->mp_SigTask = NULL;
      
      if (name)
         AddPort(thePort);
        else
         NewList(&(thePort->mp_MsgList));
   }
   return(thePort);
}


/*
 *  DeleteNonSigPort()
 *
 *  Deletes a message port with signal type PA_IGNORE.  Based on
 *  DeletePort() from the exec support functions documented in the RKM
 */

void DeleteNonSigPort(thePort)
struct MsgPort *thePort;
{
   if (thePort->mp_Node.ln_Name) RemPort(thePort);
   thePort->mp_Node.ln_Type = 0xFF;
   thePort->mp_MsgList.lh_Head = (struct Node *) -1;
   FreeMem(thePort,(ULONG)sizeof(struct MsgPort));
}


/*
 *  DoExit()
 *
 *  Exit with error status.  Print a message with up to three parameters
 *  and then clean up everything (restore the screen if it is enlarged,
 *  unload the handler if it is loaded, close the Input.Device and free
 *  its IO blocks and ports, and close any open libraries).  Return the
 *  error status.
 */

void DoExit(s,x1,x2,x3)
char *s, *x1,*x2,*x3;
{
   int status = OK_EXIT;

   if (s)
   {
      printf(s,x1,x2,x3);
      printf("\n");
      status = ERROR_EXIT;
   }
   if (Enlarged)        RestoreScreen();
   if (NamedPort)       DeleteNonSigPort(NamedPort);
   if (Segment)         UnLoadSeg(Segment);
   if (InputDevice)     CloseDevice(InputBlock);
   if (InputBlock)      DeleteStdIO(InputBlock);
   if (InputPort)       DeletePort(InputPort);
   if (IntuitionBase)   CloseLibrary(IntuitionBase);
   if (GfxBase)         CloseLibrary(GfxBase);
   if (LayersBase)      CloseLibrary(LayersBase);
   exit(status);
}


/*
 *  CheckLibOpen()
 *
 *  Call OpenLibrary() for the specified library, and check that the 
 *  open succeeded.
 */

void CheckLibOpen(lib,name,rev)
APTR *lib;
char *name;
int rev;
{
   #ifndef PROTO
   extern APTR OpenLibrary();
   #endif
   
   if ((*lib = OpenLibrary(name,(ULONG)rev)) == NULL)
      DoExit("Can't open '%s'",name);
}


/*
 *  GetInt()
 *
 *  Read the first integer from the given string variable (used to parse
 *  the command-line arguments).  If no integer can be read, exit and
 *  show the usage string.
 */

static long GetInt(s)
char *s;
{
   long i;

   if (sscanf(s,"%ld",&i) != 1) DoExit("Usage:  %s",USAGE);
   return(i);
}


/*
 *  ParseArguments()
 *
 *  Parse the command-line arguments.  If there are too many or too few
 *  arguments, exit with an error message, otherwise get the width and height
 *  agruments.  If there was a screen name specified, record that.
 *  Find the specified screen.
 */

static void ParseArguments(argc,argv)
int argc;
char *argv[];
{
   char *ScreenName = NULL;

   if (argc < 3) DoExit("Width and Height are required\nUsage:  %s",USAGE);
   if (argc > 4) DoExit("Too many arguments");
   ScreenWidth  = GetInt(argv[1]);
   ScreenHeight = GetInt(argv[2]);
   if (ScreenWidth <= 0 || ScreenHeight <= 0)
      DoExit("Screen height and width must be positive");
   if (ScreenWidth > 1024 || ScreenHeight > 1024)
      printf("Warning:  sizes greater than 1024 may cause Blitter problems\n");
   if (argc > 3 && argv[3] && argv[3][0] != '\0') ScreenName = argv[3];
   VScreen = FindScreen(ScreenName);
}


/*
 *  LoadHandler()
 *
 *  Try to LoadSeg the handler from the current directory, and if it is not
 *  found, try the L: directory.  If neither can be loaded, exit with a 
 *  message.  Once the handler is loaded, call its Setup routine passing it
 *  our version number.  The handler will check the versions for compatability,
 *  and return NULL for version mismatch, or a pointer to its data structure
 *  with pointers to the variables that vScreen will initialize for it.
 *  LoadHandler() sets the pointer to the handlers SegList, and sets the
 *  loader version number
 */

static void LoadHandler()
{
   struct vScreenInfo *(*Setup)();

   if ((Segment = LoadSeg(HANDLER)) == NULL)
      if ((Segment = LoadSeg(handler)) == NULL)
         DoExit("Can't Load '%s'",handler);
   Setup = (struct vScreenInfo *(*)()) ((Segment << 2) + 4);
   
   vScreenData   = (*Setup)(LOADVERS);
   if (vScreenData)
   {
      if (var(MajVers) > 1) DoExit("version mismatch with '%s'",HANDLER);
   } else {
      DoExit("'%s' reports a version mismatch",HANDLER);
   }

   var(Segment)  = Segment;
   var(LoadVers) = LOADVERS;
}


/*
 *  TellInputDevice()
 *
 *  Create a port and I/O block, then open the input device.  Set up the
 *  I/O block to add or remove the input handler, and send the request
 *  to the input device.  Finally, close the device and delete the
 *  I/O block and port.
 */
 
void TellInputDevice(function)
int function;
{
   long status;

   if ((InputPort = CreatePort(0,0)) == NULL) DoExit("Can't Create Port");
   if ((InputBlock = CreateStdIO(InputPort)) == NULL)
      DoExit("Can't Create Standard IO Block");
   InputDevice = (OpenDevice("input.device",0,InputBlock,0) == 0);
   if (InputDevice == FALSE) DoExit("Can't Open 'input.device'");
   
   InputBlock->io_Command = (long) function;
   InputBlock->io_Data    = (APTR) vScreenData->HandlerInfo;
   if (status = DoIO(InputBlock)) DoExit("Error from DoIO:  %ld",status);

   CloseDevice(InputBlock); InputDevice = FALSE;
   DeleteStdIO(InputBlock); InputBlock = NULL;
   DeletePort(InputPort);   InputPort = NULL;
}


/*
 *  SetVectors()
 *
 *  Call SetFunction() to replace the library vectores for the routines that
 *  we need to trap.  Use the routines that the handler has supplied (they
 *  were passed to us in the vScreenData structure).  Save the old vectors
 *  in the vScreenData strucutre so we can replace them later.  Set the 
 *  jump addresses so that the stub routines can call the old vectors.
 *  I Know this is a kludge, and is a form of self-modifying code, but I
 *  can't figure out a better method.  The JSR (Ax) is only good when there
 *  is a free A register, which is not always the case.
 */

void SetVectors()
{
   var(OldCloseScreen) =
       SetFunction(IntuitionBase,&LVOCloseScreen,var(aCloseScreen));
   var(CloseScreenJmpTarget)[-1] = (long) var(OldCloseScreen);

   var(OldBuildSysRequest) =
       SetFunction(IntuitionBase,&LVOBuildSysRequest,var(aBuildSysRequest));
   var(BuildSysRequestJmpTarget)[-1] = (long) var(OldBuildSysRequest);

   var(OldAutoRequest) =
      SetFunction(IntuitionBase,&LVOAutoRequest,var(aAutoRequest));
   var(AutoRequestJmpTarget)[-1] = (long) var(OldAutoRequest);

   var(OldLoadView) = SetFunction(GfxBase,&LVOLoadView,var(aLoadView));
   var(LoadViewJmpTarget)[-1] = (long) var(OldLoadView);

   var(OldMoveSprite) = SetFunction(GfxBase,&LVOMoveSprite,var(aMoveSprite));
   var(MoveSpriteJmpTarget)[-1] = (long) var(OldMoveSprite);
}


/*
 *  UnSetVectors()
 *
 *  Put back the old jump vectors for the routines that we replaced.
 *  Make sure that no one else has replced them behind our backs, however.
 *  If they are not the same way we left them, return an error status.
 */

int UnSetVectors()
{
   long NewCloseScreen,NewBuildSysRequest,NewAutoRequest,
        NewLoadView,NewMoveSprite;
   int status = TRUE;

   NewCloseScreen =
      SetFunction(IntuitionBase,&LVOCloseScreen,var(OldCloseScreen));
   NewBuildSysRequest =
      SetFunction(IntuitionBase,&LVOBuildSysRequest,var(OldBuildSysRequest));
   NewAutoRequest =
      SetFunction(IntuitionBase,&LVOAutoRequest,var(OldAutoRequest));
   NewLoadView   = SetFunction(GfxBase,&LVOLoadView,var(OldLoadView));
   NewMoveSprite = SetFunction(GfxBase,&LVOMoveSprite,var(OldMoveSprite));

   if (NewCloseScreen     != (long) var(aCloseScreen) ||
       NewBuildSysRequest != (long) var(aBuildSysRequest) ||
       NewAutoRequest     != (long) var(aAutoRequest) ||
       NewLoadView        != (long) var(aLoadView) ||
       NewMoveSprite      != (long) var(aMoveSprite))
   {
      SetFunction(IntuitionBase,&LVOCloseScreen,NewCloseScreen);
      SetFunction(IntuitionBase,&LVOBuildSysRequest,NewBuildSysRequest);
      SetFunction(IntuitionBase,&LVOAutoRequest,NewAutoRequest);
      SetFunction(GfxBase,&LVOLoadView,NewLoadView);
      SetFunction(GfxBase,&LVOMoveSprite,NewMoveSprite);
      status = FALSE;
   }
   return(status);
}


/*
 *  main()
 *
 *  Look for the vScreen port.
 *  If one does not exist then vScreen is not currently active, so
 *    open the intuition and graphics libraries.
 *    Parse the command-line arguments to get the width, height, and screen.
 *    Load the handler code, and check its version.
 *    Create the named port used to store information about the handler.
 *    Setup some of the variables needed by the handler, and save a pointer
 *      to the handler data in the named port.
 *    Try to enlarge the size of the screen bitmap, and set more variables.
 *    Add the input handler into the input chain.
 *    SetFunction the neede vectors.  At this point vScreen is active.
 *    Print a message that reports the version numbers.
 *  Otherwise (the port already exists, so vScreen already is active)
 *    Get the pointer to the vScreenData structure from the port.
 *    If they user had supplied arguments, tell him vScreen already is running.
 *    Try to unset the routines we replaced earlier.
 *    If the vectors we removed successfully then
 *      Remove the input handler.
 *      Restore the screen to its original size.
 *      Delete the (no-longer-needed) named port.
 *      Unload the handler code.
 *      Tell the user that the code is removed.
 *      Close the libraries (note that these remained open between calls 
 *        to vScreen, while the handler was active).
 *    Otherwise (we could not replce the function vectors)
 *      Report the problem, and leave the handler running.
 */

void main(argc,argv)
int argc;
char *argv[];
{
   NamedPort = FindPort(PORTNAME);
   if (NamedPort == NULL)
   {
      CheckLibOpen(&IntuitionBase,"intuition.library",INTUITION_REV);
      CheckLibOpen(&GfxBase,"graphics.library",GRAPHICS_REV);

      ParseArguments(argc,argv);
      LoadHandler();
      if ((NamedPort = CreateNonSigPort(var(PortName),0L)) == NULL)
         DoExit("Can't Create Message Port '%s'",var(PortName));

      SetVariables(NamedPort);
      Enlarged = EnlargeScreen();
      TellInputDevice(IND_ADDHANDLER);
      SetVectors();

      printf("%s v%d.%d.%d Installed\n",program,
         var(MajVers),var(MinVers),var(LoadVers));
   } else {
      GetVariables(NamedPort);
      if (argc > 1)
      {
         printf("%s already active on screen '%s'\n",program,VScreen->Title);
      } else {
         if (UnSetVectors())
         {
            TellInputDevice(IND_REMHANDLER);
            RestoreScreen();
            DeleteNonSigPort(NamedPort);
            UnLoadSeg(var(Segment));
            printf("%s Removed\n",program);
            CloseLibrary(IntuitionBase);
            CloseLibrary(GfxBase);
         } else {
            printf("SetFunction vectors have been changed!\n");
            printf("%s Not Removed\n",program);
         }
      }
   }
}
SHAR_EOF
if test 14176 -ne "`wc -c vScreen.c`"
then
echo shar: error transmitting vScreen.c '(should have been 14176 characters)'
fi
echo shar: extracting vScreenSetup.c '(14356 characters)'
cat << \SHAR_EOF > vScreenSetup.c
/*
 *  VSCREENSETUP.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"

struct LayersBase *LayersBase = NULL;       /* the Layers Library */

extern struct vScreenInfo *vScreenData;     /* the data from the Handler */
extern struct Screen *VScreen;              /* the virtual screen pointer */
extern SHORT ScreenWidth,ScreenHeight;      /* the new width and height */
static UBYTE OldDepth;                      /* the screen depth */

extern void CheckLibOpen();
extern void DoExit();


#define BLT_COPY    0xC0                    /* blitter copy function */
#define MIN(x,y)    (((x)<(y))?(x):(y))     /* MIN macro */


/*
 *  FindScreen()
 *
 *  If a screen name was specified, look through the Intuition screens
 *  for the first one that matches the specified name (case does not matter),
 *  otherwise, use the active screen.
 *  if the screen was not found, exit with an error message.
 */

struct Screen *FindScreen(ScreenName)
char *ScreenName;
{
   struct Screen *theScreen;

   Forbid();
   if (ScreenName && ScreenName[0])
   {
      theScreen = IntuitionBase->FirstScreen;
      while (theScreen && (theScreen->Title == NULL ||
             stricmp(theScreen->Title,ScreenName) != 0))
                theScreen = theScreen->NextScreen;
   } else {
      theScreen = IntuitionBase->ActiveScreen;
   }
   Permit();
   if (theScreen == NULL) DoExit("Can't find screen '%s'",ScreenName);
   return(theScreen);
}


/*
 *  CheckWindows()
 *
 *  Make sure that all the windows on the virtual screen will fit on the
 *  screen when we reduce it to its original size.
 *
 *  For each window on the screen,
 *    check that its right edge will be on the smaller-sized screen.
 *    if not, move it to the left so that it will be.
 *      if that would move the left egde off the screen, then
 *        shrink the window so that it fits.
 *    Check the the bottom edge will be on the smaller screen.
 *    if no, then move it up so that it will be.
 *      if that would move the top edge off the screen, then
 *         shrink the window so that it fits.
 *    If the window needs to change size or position, do so, and record
 *      the number of changes made.
 *
 *  if any windows were changed, delay long enough for Intuition to update
 *    the windows before we actually restore the screen size.  (This is a
 *    kludge, but I don't know a better method that this.  You may need to
 *    adjust the timing factore for busier screens).
 */

static void CheckWindows(theScreen,theWidth,theHeight)
struct Screen *theScreen;
SHORT theWidth,theHeight;
{
   struct Window *theWindow;
   SHORT x,y, w,h;
   SHORT Wx,Wy, Ww,Wh;
   short wChanged = 0;

   if (theScreen)
   {
      theWindow = theScreen->FirstWindow;
      while (theWindow)
      {
         Wx = x = theWindow->LeftEdge;
         Wy = y = theWindow->TopEdge;
         Ww = w = theWindow->Width;
         Wh = h = theWindow->Height;
         
         if (x+w > theWidth)
         {
            x = theWidth - w;
            if (x < 0)
            {
               x = 0;
               w = theWidth;
            }
         }

         if (y+h > theHeight)
         {
            y = theHeight - h;
            if (y < 0)
            {
               y = 0;
               h = theHeight;
            }
         }

         if (x != Wx || y != Wy)
         {
            MoveWindow(theWindow,x-Wx,y-Wy);
            wChanged++;
         }
         
         if (w != Ww || h != Wh)
         {
            SizeWindow(theWindow,w-Ww,h-Wh);
            wChanged++;
         }

         theWindow = theWindow->NextWindow;
      }
   }
   if (wChanged) Delay(wChanged * 30L);
}


/*
 *  GetPlane()
 *
 *  Allocate a bitplane and copy one of the VScren bitplanes into it, then 
 *  free the old bitplane and replace it with the new one.
 *
 *  Two temporary bitmaps are used so that we can call BltBitMap.  The
 *  new bitplane is cleared in case it is larger than the old one, then
 *  the old one is copied.  Since BltBitMap is asynchronous, we call BltClear
 *  on a dummy section of memory to synchronize with the BltBitMap.  That way
 *  we don't free the old raster until it is fully copied.
 *
 *  GetPlane() is used to get the larger bitmap as well as the smaller one 
 *  when we restore the original screen, so MIN() is used to determine
 *  the size of the BltBitMap() action.
 */

static int GetPlane(i,Map1,Map2,junk)
int i;
struct BitMap *Map1,*Map2;
UBYTE *junk;
{
   int error = TRUE;
   long w1 = (Map1->BytesPerRow) << 3;
   long h1 = Map1->Rows;
   long w2 = (Map2->BytesPerRow) << 3;
   long h2 = Map2->Rows;

   Map2->Planes[0] = VScreen->BitMap.Planes[i];
   Map1->Planes[0] = AllocRaster(w1,h1);
   if (Map1->Planes[0])
   {
      BltClear(Map1->Planes[0],RASSIZE(w1,h1),0L);
      BltBitMap(Map2,0L,0L,Map1,0L,0L,MIN(w1,w2),MIN(h1,h2),BLT_COPY,0xFF,NULL);
      BltClear(junk,8L,0L);  /* synchronize with BltBitMap */
      VScreen->BitMap.Planes[i] = Map1->Planes[0];
      FreeRaster(Map2->Planes[0],w2,h2);
      error = FALSE;
   }
   return(error);
}


/*
 *  GetBitMap()
 *
 *  GetBitMap allocates and copies a new, larger bitmap for the virtual
 *  screen.  It does so one plane at a time, however, in order avoid having
 *  the complete old screen and the complete new screen in memory at the
 *  same time.  Two temporary bitmaps are used to perform the single-plane
 *  copies.  The junk memory is used to synchronize the BltBitMap calls (see
 *  GetPlane() above).
 *
 *  For each bitplane in the screen, get a new plane of the proper
 *  size.  If the allocation fails, try to clean up (it's usually too
 *  late, however).
 *
 *  Modify the screen's bitmap to reflect the changed size.
 *  Free the junk space.
 */

static void GetBitMap()
{
   struct BitMap MyBitMap;
   struct BitMap theBitMap;
   int i;
   UBYTE *junk;

   junk = AllocMem(8L,MEMF_CHIP);
   InitBitMap(&MyBitMap,1L,ScreenWidth,ScreenHeight);
   InitBitMap(&theBitMap,1L,VAR(OldWidth),VAR(OldHeight));
   for (i=0; i<OldDepth; i++)
   {
      if (GetPlane(i,&MyBitMap,&theBitMap,junk))
      {
         for(i--; i; i--)
         {
            if (GetPlane(i,&theBitMap,&MyBitMap,junk))
               DoExit("Bail Out!  Serious Trouble Restoring Bit Planes!");
         }
         FreeMem(junk,8L);
         DoExit("Can't Get Memory for Large Bit Planes");
      }
   }
   VScreen->BitMap.BytesPerRow = MyBitMap.BytesPerRow;
   VScreen->BitMap.Rows = MyBitMap.Rows;
   FreeMem(junk,8L);
}


/*
 *  FreeBitMap()
 *
 *  Similar to GetBitMap, except that FreeBitMap trys to allocate a bitmap
 *  the size of the original screen.
 */

static void FreeBitMap()
{
   struct BitMap MyBitMap;
   struct BitMap theBitMap;
   short i;
   UBYTE *junk;

   junk = AllocMem(8L,MEMF_CHIP);
   InitBitMap(&MyBitMap,1L,ScreenWidth,ScreenHeight);
   InitBitMap(&theBitMap,1L,VAR(OldWidth),VAR(OldHeight));
   for (i=0; i<OldDepth; i++)
   {
      if (GetPlane(i,&theBitMap,&MyBitMap,junk))
      {
         FreeMem(junk,8L);
         DoExit("Help!  Failed to Restore Bit Planes!");
      }
   }
   VScreen->BitMap.BytesPerRow = theBitMap.BytesPerRow;
   VScreen->BitMap.Rows = theBitMap.Rows;
   FreeMem(junk,8L);
}


/*
 *  SetClipRects()
 *
 *  Since the screen size is changing, we need to modify the ClipRects
 *  for the menubar's Layer.  This allows the layer to update itself
 *  properly.
 *
 *  Set the menubar bounds-rectangle size.
 *  For each ClipRect in the menubar layer,
 *    If the bounds-rectangle's right edge is at the edge of the old screen
 *      then set it to be the edge of the new screen.
 */

static void SetClipRects(OldX,NewX)
WORD OldX,NewX;
{
   struct ClipRect *theClipRect = VScreen->BarLayer->ClipRect;

   OldX--; NewX--;
   VScreen->BarLayer->bounds.MaxX = NewX;
   while (theClipRect)
   {
      if (theClipRect->bounds.MaxX == OldX)
         theClipRect->bounds.MaxX = NewX;
      theClipRect = theClipRect->Next; 
   }
}


/*
 *  EnlargeScreen()
 *
 *  Store the current state of the screen and change what needs to be 
 *  changed in order to make it bigger.
 *
 *  Open the Layers Library so that we can call LockLayers().
 *  Lock the Layers for the screen.  The Forbid() may not be necessary.
 *
 *  Get the HIRES and LACE flags for the screen.  Set up the Shift values
 *  needed to convert the screen's local coordinates to actual display
 *  coordinates (always considered 640 x 400 mode).
 *
 *  Get the pointers to the RxOffset and RyOffset variables of the RasInfo
 *  for the ViewPort of the virtual Screen.  These are what tell the
 *  graphics library which part of the bitmap to display.  These are what
 *  make it possible to scroll the screen quickly and easily.  Without them,
 *  vScreen would be impossible, but luckily, the graphics library knows how
 *  to use them.  Unfortunately, Intuition does not, so we have to bend
 *  over backwards to fool intuition.  See vScreen-Handler.c for details.
 *
 *  Get the old width and height of the screen, and the depth.
 *  Get the new, larger bitplanes for the screen.
 *
 *  Set the screen width and height, and repair the ClipRects in the
 *  menubar Layer.
 *
 *  Get the old MaxDisplay values.
 *
 *  Call the handler's SetVScreen() routine (it sets the MaxDisplay
 *  values, the Max and Min Mouse values, and some other stuff),
 *  and the FixView() routine, which calls MakeVPort() and MrgCop() to
 *  incorporate the screen changes into the Intuition View structure.
 *  Finally, load the new View so taht the larger screen will be displayed.
 *
 *  Unlock the layers and close the library.
 *
 *  Call ShowTitle, so that the menubar layer will be updated (so that
 *  it is as wide as the new screen).
 */

void EnlargeScreen()
{
   CheckLibOpen(&LayersBase,"layers.library",LAYERS_REV);
   LockLayers(&(VScreen->LayerInfo));
   Forbid();

   VAR(HiResScreen) = (VScreen->ViewPort.Modes & HIRES);
   VAR(LaceScreen)  = (VScreen->ViewPort.Modes & LACE);
   VAR(HiResShift) = (VAR(HiResScreen))? 0: 1;
   VAR(LaceShift)  = (VAR(LaceScreen))? 0: 1;

   VAR(RxOffset) = &(VScreen->ViewPort.RasInfo->RxOffset);
   VAR(RyOffset) = &(VScreen->ViewPort.RasInfo->RyOffset);
   VAR(RxOffset2) = (*(VAR(RxOffset))) << VAR(HiResShift);
   VAR(RyOffset2) = (*(VAR(RyOffset))) << VAR(LaceShift);

   VAR(OldWidth)  = VScreen->Width;
   VAR(OldHeight) = VScreen->Height;
   OldDepth = VScreen->BitMap.Depth;
   GetBitMap();

   VScreen->Width  = ScreenWidth;
   VScreen->Height = ScreenHeight;
   SetClipRects(VAR(OldWidth),ScreenWidth);

   VAR(OldMaxDH) = IntuitionBase->MaxDisplayHeight;
   VAR(OldMaxDR) = IntuitionBase->MaxDisplayRow;
   VAR(OldMaxDW) = IntuitionBase->MaxDisplayWidth;

   VAR(SetVScreen)();
   VAR(FixView)(TRUE);
   LoadView(&(IntuitionBase->ViewLord));

   Permit();
   UnlockLayers(&(VScreen->LayerInfo));
   CloseLibrary(LayersBase); LayersBase = NULL;

   ShowTitle(VScreen,(VScreen->Flags & SHOWTITLE)? TRUE: FALSE);
}


/*
 *  RestoreScreen()
 *
 *  If the screen still exists (i.e.,it was not closed while vScreen was
 *  running), then check the windows to be sure that they all will fit on
 *  the original-sized screen.
 *  Open the Layers Library, and lock the screen layers.
 *  Reset the old screen size, and set the menubar ClipRects to the old size.
 *  Set the offsets to zero, and call the Handler's ResetVScreen() routine
 *  (which resets Intuitions MaxDisplay and Min and Max Mouse fields).
 *  Get the screen depth and restore the old bitmap.
 *  Finally, unlock the screen, and remake the Intuition display so that
 *  the new sized screen is displayed.
 *  update the title bar so that it is the right size.
 */

void RestoreScreen()
{
   if (VScreen)
   {
      CheckWindows(VScreen,VAR(OldWidth),VAR(OldHeight));

      CheckLibOpen(&LayersBase,"layers.library",LAYERS_REV);
      LockLayers(&(VScreen->LayerInfo));
      Forbid();

      VScreen->Width  = VAR(OldWidth);
      VScreen->Height = VAR(OldHeight);
      SetClipRects(ScreenWidth,VAR(OldWidth));

      *(VAR(RxOffset)) = 0;
      *(VAR(RyOffset)) = 0;
      VAR(ResetVScreen)();

      OldDepth = VScreen->BitMap.Depth;
      FreeBitMap();

      Permit();
      UnlockLayers(&(VScreen->LayerInfo));
      CloseLibrary(LayersBase); LayersBase = NULL;

      RemakeDisplay();
      ShowTitle(VScreen,(VScreen->Flags & SHOWTITLE)? TRUE: FALSE);
   }
}


/*
 *  SetVariables()
 *
 *  Store that vScreenData pointer in the MsgPort structure so we can look
 *  it up later (in order to remove the handler).  Save the library pointers
 *  so that the handler can use them, and save the pointer to the virtual 
 *  screen abd its new width and height.
 */

void SetVariables(NamedPort)
struct MsgPort *NamedPort;
{
   NamedPort->mp_SigTask = (struct Task *) vScreenData;
   VAR(IntuitionBase) = IntuitionBase;
   VAR(GfxBase)       = GfxBase;
   VAR(VScreen)       = VScreen;
   VAR(ScreenWidth)   = ScreenWidth;
   VAR(ScreenHeight)  = ScreenHeight;
}


/*
 *  GetVariables()
 *
 *  Retrieve the vScreenData pointer from the MsgPort were we stored it
 *  earlier.  Get back the library pointers so that we can use them and close
 *  them.  Get back the pointer to the virtual screen and its new width
 *  and height.
 */

void GetVariables(NamedPort)
struct MsgPort *NamedPort;
{
   vScreenData   = (struct vScreenInfo *) (NamedPort->mp_SigTask);
   IntuitionBase = VAR(IntuitionBase);
   GfxBase       = VAR(GfxBase);
   VScreen       = VAR(VScreen);
   ScreenWidth   = VAR(ScreenWidth);
   ScreenHeight  = VAR(ScreenHeight);
}
SHAR_EOF
if test 14356 -ne "`wc -c vScreenSetup.c`"
then
echo shar: error transmitting vScreenSetup.c '(should have been 14356 characters)'
fi
echo shar: extracting wList.c '(2260 characters)'
cat << \SHAR_EOF > wList.c
#include <exec/types.h>
#include <intuition/intuitionbase.h>
#include <intuition/screens.h>
#include <proto/intuition.h>
#include <proto/exec.h>

#define INTUITION_REV   0L
extern struct IntuitionBase *IntuitionBase;
extern struct IntuitionBase *OpenLibrary();


static void ShowUsage()
{
   printf("Usage:  WLIST [screen]\n");
   exit(10L);
}


static struct Screen *FindScreen(ScreenName)
char *ScreenName;
{
   struct Screen *theScreen;

   if (ScreenName && ScreenName[0])
   {
      Forbid();
      theScreen = IntuitionBase->FirstScreen;
      while (theScreen && (theScreen->Title == NULL ||
             stricmp(theScreen->Title,ScreenName) != 0))
                theScreen = theScreen->NextScreen;
      Permit();
   } else {
      Forbid();
      theScreen = IntuitionBase->FirstScreen;
      Permit();
   }

   if (theScreen == NULL)
   {
      Permit();
      printf("Can't find screen '%s'\n",ScreenName);
      exit(10L);
   }
   return(theScreen);
}


static void PrintWindowTitle(theWindow)
struct Window *theWindow;
{
   if (theWindow && theWindow->Title)
      printf("   '%s'\n",theWindow->Title);
     else
      printf("   [No Title]\n");
}

static void PrintScreenTitle(theScreen)
struct Screen *theScreen;
{
   if (theScreen && theScreen->Title)
      printf("'%s'\n",theScreen->Title);
     else
      printf("[No Title]\n");
}


static void PrintScreenWindows(theScreen)
struct Screen *theScreen;
{
   struct Window *theWindow = theScreen->FirstWindow;
   
   while (theWindow)
   {
      PrintWindowTitle(theWindow);
      theWindow = theWindow->NextWindow;
   }
}


void main(argc,argv)
int argc;
char *argv[];
{
   char *ScreenName = NULL;
   struct Screen *theScreen;

   if (argc > 2) ShowUsage();
   if (argc > 1 && argv[1] && argv[1][0] != '\0') ScreenName = argv[1];
   
   IntuitionBase = OpenLibrary("intuition.library",INTUITION_REV);
   if (IntuitionBase)
   {
      theScreen = FindScreen(ScreenName);

      printf("\n");
      while (theScreen)
      {
         PrintScreenTitle(theScreen);
         PrintScreenWindows(theScreen);
         if (ScreenName)
            theScreen = NULL;
           else
            theScreen = theScreen->NextScreen;
      }
      printf("\n");
      CloseLibrary(IntuitionBase);
   }
}

SHAR_EOF
if test 2260 -ne "`wc -c wList.c`"
then
echo shar: error transmitting wList.c '(should have been 2260 characters)'
fi
echo shar: extracting wMax.c '(2831 characters)'
cat << \SHAR_EOF > wMax.c
#include <exec/types.h>
#include <intuition/intuitionbase.h>
#include <intuition/screens.h>
#include <proto/intuition.h>
#include <proto/exec.h>

#define INTUITION_REV   0L
extern struct IntuitionBase *IntuitionBase;
extern struct IntuitionBase *OpenLibrary();


static void ShowUsage()
{
   printf("Usage:  WMAX x y [window [screen]]\n");
   exit(10L);
}


static void GetInt(i,s)
long *i;
char *s;
{
   if (sscanf(s,"%ld",i) != 1) ShowUsage();
}

static struct Screen *FindScreen(ScreenName)
char *ScreenName;
{
   struct Screen *theScreen;

   if (ScreenName && ScreenName[0])
   {
      theScreen = IntuitionBase->FirstScreen;
      while (theScreen && (theScreen->Title == NULL ||
             stricmp(theScreen->Title,ScreenName) != 0))
                theScreen = theScreen->NextScreen;
   } else {
      theScreen = IntuitionBase->ActiveScreen;
   }

   if (theScreen == NULL)
   {
      Permit();
      printf("Can't find screen '%s'\n",ScreenName);
      exit(10L);
   }
   return(theScreen);
}


static struct Window *FindWindow(WindowName,theScreen)
char *WindowName;
struct Screen *theScreen;
{
   struct Window *theWindow;

   if (WindowName && WindowName[0])
   {
      theWindow = theScreen->FirstWindow;
      while (theWindow && (theWindow->Title == NULL ||
             stricmp(theWindow->Title,WindowName) != 0))
                theWindow = theWindow->NextWindow;
   } else {
      theWindow = IntuitionBase->ActiveWindow;
   }

   if (theWindow == NULL)
   {
      Permit();
      printf("Can't find window '%s' on screen '%s'\n",
         WindowName,theScreen->Title);
      exit(10L);
   }
   Permit();
   return(theWindow);
}


void main(argc,argv)
int argc;
char *argv[];
{
   char *WindowName = NULL;
   char *ScreenName = NULL;
   long x,y;
   struct Window *theWindow;
   struct Screen *theScreen;

   if (argc < 3 || argc > 5) ShowUsage();
   GetInt(&x,argv[1]);
   GetInt(&y,argv[2]);
   if (argc > 3 && argv[3] && argv[3][0] != '\0') WindowName = argv[3];
   if (argc > 4 && argv[4] && argv[4][0] != '\0') ScreenName = argv[4];
   
   IntuitionBase = OpenLibrary("intuition.library",INTUITION_REV);
   if (IntuitionBase)
   {
      Forbid();
      theScreen = FindScreen(ScreenName);
      theWindow = FindWindow(WindowName,theScreen);
      Permit();

      printf("\nWindow '%s' on Screen '%s'\n",
         theWindow->Title,theWindow->WScreen->Title);
      printf("   Old Max:  (%d,%d)    Old Min:  (%d,%d)\n",
         theWindow->MaxWidth,theWindow->MaxHeight,
         theWindow->MinWidth,theWindow->MinHeight);
      if (x || y)
      {
         Forbid();
         theWindow->MaxWidth  = x;
         theWindow->MaxHeight = y;
         Permit();
         printf("   New Max:  (%d,%d)\n\n",
            theWindow->MaxWidth,theWindow->MaxHeight);
      }
      CloseLibrary(IntuitionBase);
   }
}
SHAR_EOF
if test 2831 -ne "`wc -c wMax.c`"
then
echo shar: error transmitting wMax.c '(should have been 2831 characters)'
fi
echo shar: extracting wMove.c '(3182 characters)'
cat << \SHAR_EOF > wMove.c
#include <exec/types.h>
#include <intuition/intuitionbase.h>
#include <intuition/screens.h>
#include <proto/intuition.h>
#include <proto/exec.h>

#define INTUITION_REV   0L
extern struct IntuitionBase *IntuitionBase;
extern struct IntuitionBase *OpenLibrary();


static void ShowUsage()
{
   printf("Usage:  WMOVE dx dy [window [screen]]\n");
   exit(10L);
}


static void GetInt(i,s)
long *i;
char *s;
{
   if (sscanf(s,"%ld",i) != 1) ShowUsage();
}

static struct Screen *FindScreen(ScreenName)
char *ScreenName;
{
   struct Screen *theScreen;

   if (ScreenName && ScreenName[0])
   {
      theScreen = IntuitionBase->FirstScreen;
      while (theScreen && (theScreen->Title == NULL ||
             stricmp(theScreen->Title,ScreenName) != 0))
                theScreen = theScreen->NextScreen;
   } else {
      theScreen = IntuitionBase->ActiveScreen;
   }

   if (theScreen == NULL)
   {
      Permit();
      printf("Can't find screen '%s'\n",ScreenName);
      exit(10L);
   }
   return(theScreen);
}


static struct Window *FindWindow(WindowName,theScreen)
char *WindowName;
struct Screen *theScreen;
{
   struct Window *theWindow;

   if (WindowName && WindowName[0])
   {
      theWindow = theScreen->FirstWindow;
      while (theWindow && (theWindow->Title == NULL ||
             stricmp(theWindow->Title,WindowName) != 0))
                theWindow = theWindow->NextWindow;
   } else {
      theWindow = IntuitionBase->ActiveWindow;
   }

   if (theWindow == NULL)
   {
      Permit();
      printf("Can't find window '%s' on screen '%s'\n",
         WindowName,theScreen->Title);
      exit(10L);
   }
   Permit();
   return(theWindow);
}


void main(argc,argv)
int argc;
char *argv[];
{
   char *WindowName = NULL;
   char *ScreenName = NULL;
   long dx,dy;
   struct Window *theWindow;
   struct Screen *theScreen;

   if (argc < 3 || argc > 5) ShowUsage();
   GetInt(&dx,argv[1]);
   GetInt(&dy,argv[2]);
   if (argc > 3 && argv[3] && argv[3][0] != '\0') WindowName = argv[3];
   if (argc > 4 && argv[4] && argv[4][0] != '\0') ScreenName = argv[4];
   
   IntuitionBase = OpenLibrary("intuition.library",INTUITION_REV);
   if (IntuitionBase)
   {
      Forbid();
      theScreen = FindScreen(ScreenName);
      theWindow = FindWindow(WindowName,theScreen);
      Permit();

      if (dx < -(theWindow->LeftEdge)) dx = -(theWindow->LeftEdge);
      if (dy < -(theWindow->TopEdge))  dy = -(theWindow->TopEdge);
      
      if (theWindow->LeftEdge + dx + theWindow->Width > theScreen->Width)
         dx = theScreen->Width - theWindow->Width - theWindow->LeftEdge;
      if (theWindow->TopEdge + dy + theWindow->Height > theScreen->Height)
         dy = theScreen->Height - theWindow->Height - theWindow->TopEdge;

      printf("\nWindow '%s' on Screen '%s'\n",
         theWindow->Title,theWindow->WScreen->Title);
      printf("   Old position:  (%d,%d)\n",
         theWindow->LeftEdge,theWindow->TopEdge);
      if (dx || dy)
      {
         printf("   New position:  (%d,%d)\n   Changed:       (%d,%d)\n\n",
            theWindow->LeftEdge+dx,theWindow->TopEdge+dy,dx,dy);
         MoveWindow(theWindow,dx,dy);
      }
      CloseLibrary(IntuitionBase);
   }
}
SHAR_EOF
if test 3182 -ne "`wc -c wMove.c`"
then
echo shar: error transmitting wMove.c '(should have been 3182 characters)'
fi
echo shar: extracting wSize.c '(3542 characters)'
cat << \SHAR_EOF > wSize.c
#include <exec/types.h>
#include <intuition/intuitionbase.h>
#include <intuition/screens.h>
#include <proto/intuition.h>
#include <proto/exec.h>

#define INTUITION_REV   0L
extern struct IntuitionBase *IntuitionBase;
extern struct IntuitionBase *OpenLibrary();


static void ShowUsage()
{
   printf("Usage:  WSIZE dx dy [window [screen [IGNOREMAX]]\n");
   exit(10L);
}


static void GetInt(i,s)
long *i;
char *s;
{
   if (sscanf(s,"%ld",i) != 1) ShowUsage();
}

static struct Screen *FindScreen(ScreenName)
char *ScreenName;
{
   struct Screen *theScreen;

   if (ScreenName && ScreenName[0])
   {
      theScreen = IntuitionBase->FirstScreen;
      while (theScreen && (theScreen->Title == NULL ||
             stricmp(theScreen->Title,ScreenName) != 0))
                theScreen = theScreen->NextScreen;
   } else {
      theScreen = IntuitionBase->ActiveScreen;
   }

   if (theScreen == NULL)
   {
      Permit();
      printf("Can't find screen '%s'\n",ScreenName);
      exit(10L);
   }
   return(theScreen);
}


static struct Window *FindWindow(WindowName,theScreen)
char *WindowName;
struct Screen *theScreen;
{
   struct Window *theWindow;

   if (WindowName && WindowName[0])
   {
      theWindow = theScreen->FirstWindow;
      while (theWindow && (theWindow->Title == NULL ||
             stricmp(theWindow->Title,WindowName) != 0))
                theWindow = theWindow->NextWindow;
   } else {
      theWindow = IntuitionBase->ActiveWindow;
   }

   if (theWindow == NULL)
   {
      Permit();
      printf("Can't find window '%s' on screen '%s'\n",
         WindowName,theScreen->Title);
      exit(10L);
   }
   Permit();
   return(theWindow);
}


void main(argc,argv)
int argc;
char *argv[];
{
   char *WindowName = NULL;
   char *ScreenName = NULL;
   long dx,dy;
   struct Window *theWindow;
   struct Screen *theScreen;
   long UseMax = TRUE;

   if (argc < 3 || argc > 6) ShowUsage();
   GetInt(&dx,argv[1]);
   GetInt(&dy,argv[2]);
   if (argc > 3 && argv[3] && argv[3][0] != '\0') WindowName = argv[3];
   if (argc > 4 && argv[4] && argv[4][0] != '\0') ScreenName = argv[4];
   if (argc > 5) UseMax = FALSE;
   
   IntuitionBase = OpenLibrary("intuition.library",INTUITION_REV);
   if (IntuitionBase)
   {
      Forbid();
      theScreen = FindScreen(ScreenName);
      theWindow = FindWindow(WindowName,theScreen);
      Permit();

      if (theWindow->LeftEdge + theWindow->Width + dx > theScreen->Width)
         dx = theScreen->Width - theWindow->LeftEdge - theWindow->Width;
      if (theWindow->Width + dx < theWindow->MinWidth)
         dx = theWindow->MinWidth - theWindow->Width;
      if (theWindow->Width + dx > theWindow->MaxWidth && UseMax)
         dx = theWindow->MaxWidth - theWindow->Width;

      if (theWindow->TopEdge + theWindow->Height + dy > theScreen->Height)
         dy = theScreen->Height - theWindow->TopEdge - theWindow->Height;
      if (theWindow->Height + dy < theWindow->MinHeight)
         dy = theWindow->MinHeight - theWindow->Height;
      if (theWindow->Height + dy > theWindow->MaxHeight && UseMax)
         dy = theWindow->MaxHeight - theWindow->Height;

      printf("\nWindow '%s' on Screen '%s'\n",
         theWindow->Title,theWindow->WScreen->Title);
      printf("   Old size:  (%d,%d)\n",theWindow->Width,theWindow->Height);
      if (dx || dy)
      {
         printf("   New size:  (%d,%d)\n   Changed:   (%d,%d)\n\n",
            theWindow->Width+dx,theWindow->Height+dy,dx,dy);
         SizeWindow(theWindow,dx,dy);
      }
      CloseLibrary(IntuitionBase);
   }
}
SHAR_EOF
if test 3542 -ne "`wc -c wSize.c`"
then
echo shar: error transmitting wSize.c '(should have been 3542 characters)'
fi
#	End of shell archive
exit 0