Subversion Repositories filter_foundry

Rev

Rev 193 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
259 daniel-mar 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
}