Subversion Repositories filter_foundry

Rev

Rev 193 | Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. #include <Types.h>
  2. #include <Menus.h>
  3. #include <Quickdraw.h>
  4. #include <Windows.h>
  5.  
  6. struct ZoomData {
  7.         GDHandle                screenWithLargestPartOfWindow;
  8.         unsigned long   largestArea;
  9.         Rect                    windowBounds;
  10. };
  11. typedef struct ZoomData ZoomData, *ZoomDataPtr;
  12.  
  13. typedef void (*CalcIdealDocumentSizeProcPtr)(WindowPtr theWindow, Rect *idealContentSize);
  14.  
  15. enum {
  16.         kNudgeSlop      =       4,
  17.         kIconSpace      =       64
  18. };
  19.  
  20. void ZoomTheWindow(WindowPeek theWindow, short zoomState,
  21.                                         CalcIdealDocumentSizeProcPtr calcRoutine);
  22. pascal void CalcWindowAreaOnScreen(short depth, short deviceFlags, GDHandle targetDevice,
  23.                                                                         long userData);
  24. short CalculateOffsetAmount(short idealStartPoint, short idealEndPoint,
  25.                                                         short idealOnScreenStartPoint, short idealOnScreenEndPoint,
  26.                                                         short screenEdge1, short screenEdge2);
  27.  
  28. static RgnHandle GetWindowContentRegion(WindowPeek theWindow);
  29. static RgnHandle GetWindowStructureRegion(WindowPeek theWindow);
  30. static void GetWindowPortRect(WindowPeek theWindow, Rect *portRect);
  31. static void SetWindowStandardState(WindowPeek theWindow, const Rect *standardState);
  32. static void GetWindowUserState(WindowPeek theWindow, Rect *userState);
  33.  
  34.  
  35. void ZoomTheWindow(WindowPeek theWindow, short zoomState,
  36.                                         CalcIdealDocumentSizeProcPtr calcRoutine)
  37. {
  38.         ZoomData        zoomData;
  39.         Rect            newStandardRect;
  40.         Rect            scratchRect;
  41.         Rect            screenRect;
  42.         Rect            portRect;
  43.         Rect            contentRegionBoundingBox;
  44.         Rect            structureRegionBoundingBox;
  45.         Rect            deviceLoopRect;
  46.         GrafPtr         currentPort;
  47.         RgnHandle       scratchRegion;
  48.         RgnHandle       contentRegion;
  49.         RgnHandle       structureRegion;
  50.         GDHandle        mainDevice;
  51.         short           horizontalAmountOffScreen;
  52.         short           verticalAmountOffScreen;
  53.         short           windowFrameTopSize;
  54.         short           windowFrameLeftSize;
  55.         short           windowFrameRightSize;
  56.         short           windowFrameBottomSize;
  57.        
  58.  
  59.         GetPort(&currentPort);
  60.         SetPort((WindowPtr) theWindow);
  61.         contentRegion = GetWindowContentRegion(theWindow);
  62.         structureRegion = GetWindowStructureRegion(theWindow);
  63.         GetWindowPortRect(theWindow, &portRect);
  64.         contentRegionBoundingBox = (**contentRegion).rgnBBox;
  65.         structureRegionBoundingBox = (**structureRegion).rgnBBox;
  66.        
  67.         // Determine the size of the window frame
  68.         windowFrameTopSize = contentRegionBoundingBox.top -
  69.                                                                         structureRegionBoundingBox.top;
  70.         windowFrameLeftSize = contentRegionBoundingBox.left -
  71.                                                                         structureRegionBoundingBox.left;
  72.         windowFrameRightSize = structureRegionBoundingBox.right -
  73.                                                                         contentRegionBoundingBox.right;
  74.         windowFrameBottomSize = structureRegionBoundingBox.bottom -
  75.                                                                         contentRegionBoundingBox.bottom;
  76.                                                                        
  77.         // If the window is being zoomed into the standard state, calculate the best size
  78.         // to display the windowÕs information.
  79.         mainDevice = GetMainDevice();
  80.         if (zoomState == inZoomOut) {
  81.                 zoomData.screenWithLargestPartOfWindow = mainDevice;
  82.                 zoomData.largestArea = 0;
  83.        
  84.                 // Usually, we would use the content regionÕs bounding box to determine the monitor
  85.                 // with largest portion of the windowÕs area. However, if the entire content region
  86.                 // of the window is not on any screen, the structure region should be used instead.
  87.                 scratchRegion = NewRgn();
  88.                 SectRgn(GetGrayRgn(), contentRegion, scratchRegion);
  89.                 if (EmptyRgn(scratchRegion))
  90.                         zoomData.windowBounds = structureRegionBoundingBox;
  91.                 else
  92.                         zoomData.windowBounds = contentRegionBoundingBox;
  93.        
  94.                 // Use DeviceLoop to walk through all the active screens to find the one with the
  95.                 // largest portion of the zoomed window
  96.                 deviceLoopRect = zoomData.windowBounds;
  97.                 GlobalToLocal((Point *)&deviceLoopRect);
  98.                 GlobalToLocal((Point *)&deviceLoopRect.bottom);
  99.                 RectRgn(scratchRegion, &deviceLoopRect);
  100.                 DeviceLoop(scratchRegion, &CalcWindowAreaOnScreen, (long) &zoomData,
  101.                                         (DeviceLoopFlags) singleDevices);
  102.                 DisposeRgn(scratchRegion);
  103.                 screenRect = (**(zoomData.screenWithLargestPartOfWindow)).gdRect;
  104.                
  105.                 // If the monitor being zoomed to is the main monitor, change the top of the
  106.                 // useable screen area to avoid putting the title bar underneath the menubar.
  107.                 if (zoomData.screenWithLargestPartOfWindow == mainDevice)
  108.                         screenRect.top += GetMBarHeight();
  109.                        
  110.                 // Go figure out the perfect size for the window as if we had an infinitely large
  111.                 // screen
  112.                 (*calcRoutine)((WindowPtr) theWindow, &newStandardRect);
  113.                
  114.                 // Anchor the new rectangle at the windowÕs current top left corner
  115.                 OffsetRect(&newStandardRect, -newStandardRect.left, -newStandardRect.top);
  116.                 OffsetRect(&newStandardRect, contentRegionBoundingBox.left,
  117.                                         contentRegionBoundingBox.top);
  118.                
  119.                 // newStandardRect is the ideal size for the content area. The window frame
  120.                 // needs to be accounted for when we see if the window needs to be moved,
  121.                 // or resized, so add in the dimensions of the window frame.
  122.                 newStandardRect.top -= windowFrameTopSize;
  123.                 newStandardRect.left -= windowFrameLeftSize;
  124.                 newStandardRect.right += windowFrameRightSize;
  125.                 newStandardRect.bottom += windowFrameBottomSize;
  126.                
  127.                 // If the new rectangle falls off the edge of the screen, nudge it so that itÕs just
  128.                 // on the screen. CalculateOffsetAmount determines how much of the window is offscreen.
  129.                 SectRect(&newStandardRect, &screenRect, &scratchRect);
  130.                 if (!EqualRect(&newStandardRect, &scratchRect)) {
  131.                         horizontalAmountOffScreen = CalculateOffsetAmount(newStandardRect.left,
  132.                                                                                                                            newStandardRect.right,
  133.                                                                                                                            scratchRect.left,
  134.                                                                                                                            scratchRect.right,
  135.                                                                                                                            screenRect.left,
  136.                                                                                                                            screenRect.right);
  137.                         verticalAmountOffScreen = CalculateOffsetAmount(newStandardRect.top,
  138.                                                                                                                         newStandardRect.bottom,
  139.                                                                                                                         scratchRect.top,
  140.                                                                                                                         scratchRect.bottom,
  141.                                                                                                                         screenRect.top,
  142.                                                                                                                         screenRect.bottom);
  143.                         OffsetRect(&newStandardRect, horizontalAmountOffScreen,
  144.                                                 verticalAmountOffScreen);
  145.                 }
  146.        
  147.                 // If weÕre still falling off the edge of the screen, that means that the perfect
  148.                 // size is larger than the screen, so we need to shrink down the standard size
  149.                 SectRect(&newStandardRect, &screenRect, &scratchRect);
  150.                 if (!EqualRect(&newStandardRect, &scratchRect)) {
  151.  
  152.                 // First shrink the width of the window. If the window is wider than the screen
  153.                 // it is zooming to, we can just pin the standard rectangle to the edges of the
  154.                 // screen, leaving some slop. If the window is narrower than the screen, we know
  155.                 // we just nudged it into position, so nothing needs to be done.
  156.                         if ((newStandardRect.right - newStandardRect.left) >
  157.                                 (screenRect.right - screenRect.left)) {
  158.                                 newStandardRect.left = screenRect.left + kNudgeSlop;
  159.                                 newStandardRect.right = screenRect.right - kNudgeSlop;
  160.  
  161.                                 if ((zoomData.screenWithLargestPartOfWindow == mainDevice) &&
  162.                                         (newStandardRect.right > (screenRect.right - kIconSpace)))
  163.                                         newStandardRect.right = screenRect.right - kIconSpace;
  164.                         }
  165.  
  166.                         // Move in the top. Like the width of the window, nothing needs to be done unless
  167.                         // the window is taller than the height of the screen.
  168.                         if ((newStandardRect.bottom - newStandardRect.top) >
  169.                                 (screenRect.bottom - screenRect.top)) {
  170.                                 newStandardRect.top = screenRect.top + kNudgeSlop;
  171.                                 newStandardRect.bottom = screenRect.bottom - kNudgeSlop;
  172.                         }
  173.                 }
  174.  
  175.                 // WeÕve got the best possible window position. Remove the
  176.                 // frame, slam it into the WStateData record and let ZoomWindow
  177.                 // take care of the rest.
  178.                 newStandardRect.top += windowFrameTopSize;
  179.                 newStandardRect.left += windowFrameLeftSize;
  180.                 newStandardRect.right -= windowFrameRightSize;
  181.                 newStandardRect.bottom -= windowFrameBottomSize;
  182.                 SetWindowStandardState(theWindow, &newStandardRect);
  183.         }
  184.         else
  185.                 GetWindowUserState(theWindow, &newStandardRect);
  186.                
  187.         // If the window is still anchored at the current location, then just resize it
  188.         if ((newStandardRect.left == contentRegionBoundingBox.left) &&
  189.                 (newStandardRect.top == contentRegionBoundingBox.top)) {
  190.                 OffsetRect(&newStandardRect, -newStandardRect.left, -newStandardRect.top);
  191.                 SizeWindow((WindowPtr) theWindow, newStandardRect.right, newStandardRect.bottom,
  192.                                         true);
  193.         }
  194.         else {
  195.                 scratchRegion = NewRgn();
  196.                 GetClip(scratchRegion);
  197.                 ClipRect(&portRect);
  198.                 EraseRect(&portRect);
  199.                 ZoomWindow((WindowPtr) theWindow, zoomState, false);
  200.                 SetClip(scratchRegion);
  201.                 DisposeRgn(scratchRegion);
  202.         }
  203.        
  204.         SetPort(currentPort);
  205. }
  206.  
  207. pascal void     CalcWindowAreaOnScreen(short depth, short deviceFlags, GDHandle targetDevice, long userData)
  208. {
  209. #pragma unused (depth, deviceFlags)
  210.         ZoomDataPtr     zoomData = (ZoomDataPtr) userData;
  211.         long            windowAreaOnScreen;
  212.         Rect            windowPortionOnScreen;
  213.        
  214.         // Find the rectangle that encloses the intersection of the window and this screen.
  215.         SectRect(&(zoomData->windowBounds), &((**targetDevice).gdRect), &windowPortionOnScreen);
  216.        
  217.         // Offset the rectangle so that itÕs right and bottom are also itÕs width and height.
  218.         OffsetRect(&windowPortionOnScreen, -windowPortionOnScreen.left, -windowPortionOnScreen.top);
  219.        
  220.         // Calculate the area of the portion of the window thatÕs on this screen.
  221.         windowAreaOnScreen = (long) windowPortionOnScreen.right * (long) windowPortionOnScreen.bottom;
  222.        
  223.         // If this is the largest portion of the window that has been encountered so far,
  224.         // remember this screen as the potential screen to zoom to.
  225.         if (windowAreaOnScreen > zoomData->largestArea) {
  226.                 zoomData->largestArea = windowAreaOnScreen;
  227.                 zoomData->screenWithLargestPartOfWindow = targetDevice;
  228.         }
  229. }
  230.  
  231. // Figure out how much we need to move the window to get it entirely on the monitor.  If
  232. // the window wouldnÕt fit completely on the monitor anyway, donÕt move it at all; weÕll
  233. // make it fit later on.
  234.  
  235. short CalculateOffsetAmount(short idealStartPoint, short idealEndPoint, short idealOnScreenStartPoint,
  236.                                                         short idealOnScreenEndPoint, short screenEdge1, short screenEdge2)
  237. {
  238.         short   offsetAmount;
  239.  
  240.         // First check to see if the window fits on the screen in this dimension.
  241.         if ((idealStartPoint < screenEdge1) && (idealEndPoint > screenEdge2))
  242.                 offsetAmount = 0;
  243.         else {
  244.        
  245.                 // Find out how much of the window lies off this screen by subtracting the amount of the window
  246.                 // that is on the screen from the size of the entire window in this dimension. If the window
  247.                 // is completely offscreen, the offset amount is going to be the distance from the ideal
  248.                 // starting point to the first edge of the screen.
  249.                 if ((idealOnScreenStartPoint - idealOnScreenEndPoint) == 0) {
  250.                         // See if the window is lying to the left or above the screen
  251.                         if (idealEndPoint < screenEdge1)
  252.                                 offsetAmount = screenEdge1 - idealStartPoint + kNudgeSlop;
  253.                         else
  254.                         // Otherwise, itÕs below or to the right of the screen
  255.                                 offsetAmount = screenEdge2 - idealEndPoint - kNudgeSlop;
  256.                 }
  257.                 else {
  258.                         // Window is already partially or completely on the screen
  259.                         offsetAmount = (idealEndPoint - idealStartPoint) -
  260.                                                         (idealOnScreenEndPoint - idealOnScreenStartPoint);
  261.        
  262.                         // If we are offscreen a little, move the window in a few more pixels from the edge of the screen.
  263.                         if (offsetAmount != 0)
  264.                                 offsetAmount += kNudgeSlop;
  265.                        
  266.                         // Check to see which side of the screen the window was falling off of, so that it can be
  267.                         // nudged in the opposite direction.
  268.                         if (idealEndPoint > screenEdge2)
  269.                                 offsetAmount = -offsetAmount;
  270.                 }
  271.         }
  272.        
  273.         return offsetAmount;
  274. }
  275.  
  276. /*
  277.         WindowRecord accessor functions
  278. */
  279.  
  280. RgnHandle GetWindowContentRegion(WindowPeek theWindow)
  281. {
  282.         return (theWindow->contRgn);
  283. }
  284.  
  285. RgnHandle GetWindowStructureRegion(WindowPeek theWindow)
  286. {
  287.         return (theWindow->strucRgn);
  288. }
  289.  
  290. void GetWindowPortRect(WindowPeek theWindow, Rect *portRect)
  291. {
  292.         *portRect = theWindow->port.portRect;
  293. }
  294.  
  295. void SetWindowStandardState(WindowPeek theWindow, const Rect *standardState)
  296. {
  297.         (**((WStateDataHandle) theWindow->dataHandle)).stdState = *standardState;
  298. }
  299.  
  300. void GetWindowUserState(WindowPeek theWindow, Rect *userState)
  301. {
  302.         *userState = (**((WStateDataHandle) theWindow->dataHandle)).userState;
  303. }
  304.