home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 144.lha / VScreen_Src / vScreenSetup.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-11-21  |  14.2 KB  |  413 lines

  1. /*
  2.  *  VSCREENSETUP.C  Creates virtual screens that can be larger than
  3.  *                  the actual display area of your monitor.  The virtual
  4.  *                  screen scrolls when the mouse moves off the edge of
  5.  *                  the display.
  6.  *
  7.  *                  Copyright 1988 by Davide P. Cervone, all rights reserved.
  8.  *
  9.  *                  You may may distibute this code as is for non-commercial
  10.  *                  purposes, provided that this notice remains intact and the
  11.  *                  documentation file is distributed with it.
  12.  *
  13.  *                  You may not modify this code or incorporate it into your
  14.  *                  own programs without the permission of the author.
  15. --MORE--(38%) */
  16. /*
  17.  *  WARNING:  This code uses and even modifies the INTUITIONPRIVATE
  18.  *  area of the IntuitionBase structure.  Use it at your own risk.  It is
  19.  *  likely to break under a future release of Intuition.
  20.  */
  21. #include "vScreen.h"
  22. struct LayersBase *LayersBase = NULL;       /* the Layers Library */
  23. extern struct vScreenInfo *vScreenData;     /* the data from the Handler */
  24. extern struct Screen *VScreen;              /* the virtual screen pointer */
  25. extern SHORT ScreenWidth,ScreenHeight;      /* the new width and height */
  26. static UBYTE OldDepth;                      /* the screen depth */
  27. extern void CheckLibOpen();
  28. extern void DoExit();
  29. #define BLT_COPY    0xC0                    /* blitter copy function */
  30. #define MIN(x,y)    (((x)<(y))?(x):(y))     /* MIN macro */
  31. --MORE--(40%)
  32. /*
  33.  *  FindScreen()
  34.  *
  35.  *  If a screen name was specified, look through the Intuition screens
  36.  *  for the first one that matches the specified name (case does not matter),
  37.  *  otherwise, use the active screen.
  38.  *  if the screen was not found, exit with an error message.
  39.  */
  40. struct Screen *FindScreen(ScreenName)
  41. char *ScreenName;
  42. {
  43.    struct Screen *theScreen;
  44.    Forbid();
  45.    if (ScreenName && ScreenName[0])
  46.    {
  47.       theScreen = IntuitionBase->FirstScreen;
  48.       while (theScreen && (theScreen->Title == NULL ||
  49.              stricmp(theScreen->Title,ScreenName) != 0))
  50.                 theScreen = theScreen->NextScreen;
  51. --MORE--(42%)   } else {
  52.       theScreen = IntuitionBase->ActiveScreen;
  53.    }
  54.    Permit();
  55.    if (theScreen == NULL) DoExit("Can't find screen '%s'",ScreenName);
  56.    return(theScreen);
  57. }
  58. /*
  59.  *  CheckWindows()
  60.  *
  61.  *  Make sure that all the windows on the virtual screen will fit on the
  62.  *  screen when we reduce it to its original size.
  63.  *
  64.  *  For each window on the screen,
  65.  *    check that its right edge will be on the smaller-sized screen.
  66.  *    if not, move it to the left so that it will be.
  67.  *      if that would move the left egde off the screen, then
  68.  *        shrink the window so that it fits.
  69.  *    Check the the bottom edge will be on the smaller screen.
  70.  *    if no, then move it up so that it will be.
  71.  *      if that would move the top edge off the screen, then
  72. --MORE--(43%) *         shrink the window so that it fits.
  73.  *    If the window needs to change size or position, do so, and record
  74.  *      the number of changes made.
  75.  *
  76.  *  if any windows were changed, delay long enough for Intuition to update
  77.  *    the windows before we actually restore the screen size.  (This is a
  78.  *    kludge, but I don't know a better method that this.  You may need to
  79.  *    adjust the timing factore for busier screens).
  80.  */
  81. static void CheckWindows(theScreen,theWidth,theHeight)
  82. struct Screen *theScreen;
  83. SHORT theWidth,theHeight;
  84. {
  85.    struct Window *theWindow;
  86.    SHORT x,y, w,h;
  87.    SHORT Wx,Wy, Ww,Wh;
  88.    short wChanged = 0;
  89.    if (theScreen)
  90.    {
  91.       theWindow = theScreen->FirstWindow;
  92.       while (theWindow)
  93. --MORE--(45%)      {
  94.          Wx = x = theWindow->LeftEdge;
  95.          Wy = y = theWindow->TopEdge;
  96.          Ww = w = theWindow->Width;
  97.          Wh = h = theWindow->Height;
  98.          
  99.          if (x+w > theWidth)
  100.          {
  101.             x = theWidth - w;
  102.             if (x < 0)
  103.             {
  104.                x = 0;
  105.                w = theWidth;
  106.             }
  107.          }
  108.          if (y+h > theHeight)
  109.          {
  110.             y = theHeight - h;
  111.             if (y < 0)
  112.             {
  113.                y = 0;
  114.                h = theHeight;
  115. --MORE--(46%)            }
  116.          }
  117.          if (x != Wx || y != Wy)
  118.          {
  119.             MoveWindow(theWindow,x-Wx,y-Wy);
  120.             wChanged++;
  121.          }
  122.          
  123.          if (w != Ww || h != Wh)
  124.          {
  125.             SizeWindow(theWindow,w-Ww,h-Wh);
  126.             wChanged++;
  127.          }
  128.          theWindow = theWindow->NextWindow;
  129.       }
  130.    }
  131.    if (wChanged) Delay(wChanged * 30L);
  132. }
  133. /*
  134. --MORE--(47%) *  GetPlane()
  135.  *
  136.  *  Allocate a bitplane and copy one of the VScren bitplanes into it, then 
  137.  *  free the old bitplane and replace it with the new one.
  138.  *
  139.  *  Two temporary bitmaps are used so that we can call BltBitMap.  The
  140.  *  new bitplane is cleared in case it is larger than the old one, then
  141.  *  the old one is copied.  Since BltBitMap is asynchronous, we call BltClear
  142.  *  on a dummy section of memory to synchronize with the BltBitMap.  That way
  143.  *  we don't free the old raster until it is fully copied.
  144.  *
  145.  *  GetPlane() is used to get the larger bitmap as well as the smaller one 
  146.  *  when we restore the original screen, so MIN() is used to determine
  147.  *  the size of the BltBitMap() action.
  148.  */
  149. static int GetPlane(i,Map1,Map2,junk)
  150. int i;
  151. struct BitMap *Map1,*Map2;
  152. UBYTE *junk;
  153. {
  154.    int error = TRUE;
  155.    long w1 = (Map1->BytesPerRow) << 3;
  156. --MORE--(49%)   long h1 = Map1->Rows;
  157.    long w2 = (Map2->BytesPerRow) << 3;
  158.    long h2 = Map2->Rows;
  159.    Map2->Planes[0] = VScreen->BitMap.Planes[i];
  160.    Map1->Planes[0] = AllocRaster(w1,h1);
  161.    if (Map1->Planes[0])
  162.    {
  163.       BltClear(Map1->Planes[0],RASSIZE(w1,h1),0L);
  164.       BltBitMap(Map2,0L,0L,Map1,0L,0L,MIN(w1,w2),MIN(h1,h2),BLT_COPY,0xFF,NULL);      BltClear(junk,8L,0L);  /* synchronize with BltBitMap */
  165.       VScreen->BitMap.Planes[i] = Map1->Planes[0];
  166.       FreeRaster(Map2->Planes[0],w2,h2);
  167.       error = FALSE;
  168.    }
  169.    return(error);
  170. }
  171. /*
  172.  *  GetBitMap()
  173.  *
  174.  *  GetBitMap allocates and copies a new, larger bitmap for the virtual
  175. --MORE--(51%) *  screen.  It does so one plane at a time, however, in order avoid having
  176.  *  the complete old screen and the complete new screen in memory at the
  177.  *  same time.  Two temporary bitmaps are used to perform the single-plane
  178.  *  copies.  The junk memory is used to synchronize the BltBitMap calls (see
  179.  *  GetPlane() above).
  180.  *
  181.  *  For each bitplane in the screen, get a new plane of the proper
  182.  *  size.  If the allocation fails, try to clean up (it's usually too
  183.  *  late, however).
  184.  *
  185.  *  Modify the screen's bitmap to reflect the changed size.
  186.  *  Free the junk space.
  187.  */
  188. static void GetBitMap()
  189. {
  190.    struct BitMap MyBitMap;
  191.    struct BitMap theBitMap;
  192.    int i;
  193.    UBYTE *junk;
  194.    junk = AllocMem(8L,MEMF_CHIP);
  195.    InitBitMap(&MyBitMap,1L,ScreenWidth,ScreenHeight);
  196. --MORE--(52%)   InitBitMap(&theBitMap,1L,VAR(OldWidth),VAR(OldHeight));
  197.    for (i=0; i<OldDepth; i++)
  198.    {
  199.       if (GetPlane(i,&MyBitMap,&theBitMap,junk))
  200.       {
  201.          for(i--; i; i--)
  202.          {
  203.             if (GetPlane(i,&theBitMap,&MyBitMap,junk))
  204.                DoExit("Bail Out!  Serious Trouble Restoring Bit Planes!");
  205.          }
  206.          FreeMem(junk,8L);
  207.          DoExit("Can't Get Memory for Large Bit Planes");
  208.       }
  209.    }
  210.    VScreen->BitMap.BytesPerRow = MyBitMap.BytesPerRow;
  211.    VScreen->BitMap.Rows = MyBitMap.Rows;
  212.    FreeMem(junk,8L);
  213. }
  214. /*
  215.  *  FreeBitMap()
  216.  *
  217. --MORE--(54%) *  Similar to GetBitMap, except that FreeBitMap trys to allocate a bitmap
  218.  *  the size of the original screen.
  219.  */
  220. static void FreeBitMap()
  221. {
  222.    struct BitMap MyBitMap;
  223.    struct BitMap theBitMap;
  224.    short i;
  225.    UBYTE *junk;
  226.    junk = AllocMem(8L,MEMF_CHIP);
  227.    InitBitMap(&MyBitMap,1L,ScreenWidth,ScreenHeight);
  228.    InitBitMap(&theBitMap,1L,VAR(OldWidth),VAR(OldHeight));
  229.    for (i=0; i<OldDepth; i++)
  230.    {
  231.       if (GetPlane(i,&theBitMap,&MyBitMap,junk))
  232.       {
  233.          FreeMem(junk,8L);
  234.          DoExit("Help!  Failed to Restore Bit Planes!");
  235.       }
  236.    }
  237.    VScreen->BitMap.BytesPerRow = theBitMap.BytesPerRow;
  238. --MORE--(55%)   VScreen->BitMap.Rows = theBitMap.Rows;
  239.    FreeMem(junk,8L);
  240. }
  241. /*
  242.  *  SetClipRects()
  243.  *
  244.  *  Since the screen size is changing, we need to modify the ClipRects
  245.  *  for the menubar's Layer.  This allows the layer to update itself
  246.  *  properly.
  247.  *
  248.  *  Set the menubar bounds-rectangle size.
  249.  *  For each ClipRect in the menubar layer,
  250.  *    If the bounds-rectangle's right edge is at the edge of the old screen
  251.  *      then set it to be the edge of the new screen.
  252.  */
  253. static void SetClipRects(OldX,NewX)
  254. WORD OldX,NewX;
  255. {
  256.    struct ClipRect *theClipRect = VScreen->BarLayer->ClipRect;
  257. --MORE--(57%)   OldX--; NewX--;
  258.    VScreen->BarLayer->bounds.MaxX = NewX;
  259.    while (theClipRect)
  260.    {
  261.       if (theClipRect->bounds.MaxX == OldX)
  262.          theClipRect->bounds.MaxX = NewX;
  263.       theClipRect = theClipRect->Next; 
  264.    }
  265. }
  266. /*
  267.  *  EnlargeScreen()
  268.  *
  269.  *  Store the current state of the screen and change what needs to be 
  270.  *  changed in order to make it bigger.
  271.  *
  272.  *  Open the Layers Library so that we can call LockLayers().
  273.  *  Lock the Layers for the screen.  The Forbid() may not be necessary.
  274.  *
  275.  *  Get the HIRES and LACE flags for the screen.  Set up the Shift values
  276.  *  needed to convert the screen's local coordinates to actual display
  277.  *  coordinates (always considered 640 x 400 mode).
  278. --MORE--(58%) *
  279.  *  Get the pointers to the RxOffset and RyOffset variables of the RasInfo
  280.  *  for the ViewPort of the virtual Screen.  These are what tell the
  281.  *  graphics library which part of the bitmap to display.  These are what
  282.  *  make it possible to scroll the screen quickly and easily.  Without them,
  283.  *  vScreen would be impossible, but luckily, the graphics library knows how
  284.  *  to use them.  Unfortunately, Intuition does not, so we have to bend
  285.  *  over backwards to fool intuition.  See vScreen-Handler.c for details.
  286.  *
  287.  *  Get the old width and height of the screen, and the depth.
  288.  *  Get the new, larger bitplanes for the screen.
  289.  *
  290.  *  Set the screen width and height, and repair the ClipRects in the
  291.  *  menubar Layer.
  292.  *
  293.  *  Get the old MaxDisplay values.
  294.  *
  295.  *  Call the handler's SetVScreen() routine (it sets the MaxDisplay
  296.  *  values, the Max and Min Mouse values, and some other stuff),
  297.  *  and the FixView() routine, which calls MakeVPort() and MrgCop() to
  298.  *  incorporate the screen changes into the Intuition View structure.
  299.  *  Finally, load the new View so taht the larger screen will be displayed.
  300.  *
  301. --MORE--(61%) *  Unlock the layers and close the library.
  302.  *
  303.  *  Call ShowTitle, so that the menubar layer will be updated (so that
  304.  *  it is as wide as the new screen).
  305.  */
  306. void EnlargeScreen()
  307. {
  308.    CheckLibOpen(&LayersBase,"layers.library",LAYERS_REV);
  309.    LockLayers(&(VScreen->LayerInfo));
  310.    Forbid();
  311.    VAR(HiResScreen) = (VScreen->ViewPort.Modes & HIRES);
  312.    VAR(LaceScreen)  = (VScreen->ViewPort.Modes & LACE);
  313.    VAR(HiResShift) = (VAR(HiResScreen))? 0: 1;
  314.    VAR(LaceShift)  = (VAR(LaceScreen))? 0: 1;
  315.    VAR(RxOffset) = &(VScreen->ViewPort.RasInfo->RxOffset);
  316.    VAR(RyOffset) = &(VScreen->ViewPort.RasInfo->RyOffset);
  317.    VAR(RxOffset2) = (*(VAR(RxOffset))) << VAR(HiResShift);
  318.    VAR(RyOffset2) = (*(VAR(RyOffset))) << VAR(LaceShift);
  319.    VAR(OldWidth)  = VScreen->Width;
  320. --MORE--(63%)   VAR(OldHeight) = VScreen->Height;
  321.    OldDepth = VScreen->BitMap.Depth;
  322.    GetBitMap();
  323.    VScreen->Width  = ScreenWidth;
  324.    VScreen->Height = ScreenHeight;
  325.    SetClipRects(VAR(OldWidth),ScreenWidth);
  326.    VAR(OldMaxDH) = IntuitionBase->MaxDisplayHeight;
  327.    VAR(OldMaxDR) = IntuitionBase->MaxDisplayRow;
  328.    VAR(OldMaxDW) = IntuitionBase->MaxDisplayWidth;
  329.    VAR(SetVScreen)();
  330.    VAR(FixView)(TRUE);
  331.    LoadView(&(IntuitionBase->ViewLord));
  332.    Permit();
  333.    UnlockLayers(&(VScreen->LayerInfo));
  334.    CloseLibrary(LayersBase); LayersBase = NULL;
  335.    ShowTitle(VScreen,(VScreen->Flags & SHOWTITLE)? TRUE: FALSE);
  336. }
  337. --MORE--(64%)
  338. /*
  339.  *  RestoreScreen()
  340.  *
  341.  *  If the screen still exists (i.e.,it was not closed while vScreen was
  342.  *  running), then check the windows to be sure that they all will fit on
  343.  *  the original-sized screen.
  344.  *  Open the Layers Library, and lock the screen layers.
  345.  *  Reset the old screen size, and set the menubar ClipRects to the old size.
  346.  *  Set the offsets to zero, and call the Handler's ResetVScreen() routine
  347.  *  (which resets Intuitions MaxDisplay and Min and Max Mouse fields).
  348.  *  Get the screen depth and restore the old bitmap.
  349.  *  Finally, unlock the screen, and remake the Intuition display so that
  350.  *  the new sized screen is displayed.
  351.  *  update the title bar so that it is the right size.
  352.  */
  353. void RestoreScreen()
  354. {
  355.    if (VScreen)
  356.    {
  357.       CheckWindows(VScreen,VAR(OldWidth),VAR(OldHeight));
  358. --MORE--(66%)      CheckLibOpen(&LayersBase,"layers.library",LAYERS_REV);
  359.       LockLayers(&(VScreen->LayerInfo));
  360.       Forbid();
  361.       VScreen->Width  = VAR(OldWidth);
  362.       VScreen->Height = VAR(OldHeight);
  363.       SetClipRects(ScreenWidth,VAR(OldWidth));
  364.       *(VAR(RxOffset)) = 0;
  365.       *(VAR(RyOffset)) = 0;
  366.       VAR(ResetVScreen)();
  367.       OldDepth = VScreen->BitMap.Depth;
  368.       FreeBitMap();
  369.       Permit();
  370.       UnlockLayers(&(VScreen->LayerInfo));
  371.       CloseLibrary(LayersBase); LayersBase = NULL;
  372.       RemakeDisplay();
  373.       ShowTitle(VScreen,(VScreen->Flags & SHOWTITLE)? TRUE: FALSE);
  374.    }
  375. }
  376. --MORE--(67%)
  377. /*
  378.  *  SetVariables()
  379.  *
  380.  *  Store that vScreenData pointer in the MsgPort structure so we can look
  381.  *  it up later (in order to remove the handler).  Save the library pointers
  382.  *  so that the handler can use them, and save the pointer to the virtual 
  383.  *  screen abd its new width and height.
  384.  */
  385. void SetVariables(NamedPort)
  386. struct MsgPort *NamedPort;
  387. {
  388.    NamedPort->mp_SigTask = (struct Task *) vScreenData;
  389.    VAR(IntuitionBase) = IntuitionBase;
  390.    VAR(GfxBase)       = GfxBase;
  391.    VAR(VScreen)       = VScreen;
  392.    VAR(ScreenWidth)   = ScreenWidth;
  393.    VAR(ScreenHeight)  = ScreenHeight;
  394. }
  395. --MORE--(69%)/*
  396.  *  GetVariables()
  397.  *
  398.  *  Retrieve the vScreenData pointer from the MsgPort were we stored it
  399.  *  earlier.  Get back the library pointers so that we can use them and close
  400.  *  them.  Get back the pointer to the virtual screen and its new width
  401.  *  and height.
  402.  */
  403. void GetVariables(NamedPort)
  404. struct MsgPort *NamedPort;
  405. {
  406.    vScreenData   = (struct vScreenInfo *) (NamedPort->mp_SigTask);
  407.    IntuitionBase = VAR(IntuitionBase);
  408.    GfxBase       = VAR(GfxBase);
  409.    VScreen       = VAR(VScreen);
  410.    ScreenWidth   = VAR(ScreenWidth);
  411.    ScreenHeight  = VAR(ScreenHeight);
  412. }
  413.