home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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.
- --MORE--(38%) */
- /*
- * 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 */
- --MORE--(40%)
- /*
- * 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;
- --MORE--(42%) } 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
- --MORE--(43%) * 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)
- --MORE--(45%) {
- 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;
- --MORE--(46%) }
- }
- 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);
- }
- /*
- --MORE--(47%) * 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;
- --MORE--(49%) 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
- --MORE--(51%) * 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);
- --MORE--(52%) 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()
- *
- --MORE--(54%) * 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;
- --MORE--(55%) 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;
- --MORE--(57%) 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).
- --MORE--(58%) *
- * 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.
- *
- --MORE--(61%) * 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;
- --MORE--(63%) 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);
- }
- --MORE--(64%)
- /*
- * 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));
- --MORE--(66%) 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);
- }
- }
- --MORE--(67%)
- /*
- * 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;
- }
- --MORE--(69%)/*
- * 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);
- }
-