home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 2: PC
/
frozenfish_august_1995.bin
/
bbs
/
d04xx
/
d0494.lha
/
vScreen
/
Source
/
vScreenSetup.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-06-06
|
14KB
|
471 lines
/*
* 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);
}