1 line
15 KiB
C
Executable File
1 line
15 KiB
C
Executable File
/* Copyright (c) 2017, Computer History Museum
|
|
All rights reserved.
|
|
Redistribution and use in source and binary forms, with or without modification, are permitted (subject to
|
|
the limitations in the disclaimer below) provided that the following conditions are met:
|
|
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
|
|
disclaimer in the documentation and/or other materials provided with the distribution.
|
|
* Neither the name of Computer History Museum nor the names of its contributors may be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE
|
|
COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
DAMAGE. */
|
|
|
|
#include "floatingwin.h"
|
|
#define FILE_NUM 89
|
|
// Copyright ¨ 1997 by QUALCOMM Incorporated
|
|
/**********************************************************************
|
|
* code to support floating windows
|
|
**********************************************************************/
|
|
|
|
#ifdef FLOAT_WIN
|
|
|
|
#pragma segment MyWindow
|
|
|
|
void DockedDragProc(Point *pt,RgnHandle winRgn,long refCon);
|
|
void GetScreenRect(WindowPtr theWindow, Rect *rWin, Rect *rScreen);
|
|
MyWindowPtr FindLastFloaterLo(short *count,Boolean *layerProblem);
|
|
|
|
/**********************************************************************
|
|
* MySelectWindow - patch for SelectWindow that makes sure floaters
|
|
* remain on top, and non floaters remain underneath them.
|
|
**********************************************************************/
|
|
void MySelectWindow(WindowPtr winWP)
|
|
{
|
|
SelectWindow(winWP);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* FindLastFloater - returns a pointer to the last floater
|
|
**********************************************************************/
|
|
MyWindowPtr FindLastFloater(void)
|
|
{
|
|
short count;
|
|
Boolean layerProblem;
|
|
|
|
return FindLastFloaterLo(&count,&layerProblem);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* FindLastFloaterLo - returns a pointer to the last floater and counts
|
|
* number of floaters
|
|
**********************************************************************/
|
|
MyWindowPtr FindLastFloaterLo(short *count,Boolean *layerProblem)
|
|
{
|
|
WindowPtr wp,
|
|
lastFloater = nil;
|
|
Boolean nonFloaterFound = false;
|
|
|
|
*count = 0;
|
|
*layerProblem = false;
|
|
|
|
for (wp = GetWindowList (); wp; wp = GetNextWindow (wp))
|
|
if (IsFloating(wp))
|
|
{
|
|
lastFloater=wp;
|
|
(*count)++;
|
|
if (nonFloaterFound) *layerProblem = true;
|
|
}
|
|
else if ((GetWindowKind(wp)!=dialogKind && !IsModalPlugwindow(wp)) || IsModelessDialog (wp)) nonFloaterFound = true;
|
|
|
|
return (GetWindowMyWindowPtr(lastFloater));
|
|
}
|
|
|
|
/**********************************************************************
|
|
* MyDragWindow - patch for DragWindow to properly draw drag outlines.
|
|
**********************************************************************/
|
|
void MyDragWindow (WindowPtr winWP, Point start, Rect *boundsRect)
|
|
{
|
|
DragWindow(winWP, start, boundsRect);
|
|
PositionDockedWindow(winWP);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* DockedDragProc - callback for dragging docked window around edge of screen
|
|
**********************************************************************/
|
|
void DockedDragProc(Point *pt,RgnHandle winRgn,long refCon)
|
|
{
|
|
short dx,dy,dx1,dy1,dx2,dy2;
|
|
Rect rWin,rScreen;
|
|
WindowPtr theWindow = (WindowPtr) refCon;
|
|
|
|
// Get bounds of window at new location
|
|
GetRegionBounds(winRgn,&rWin);
|
|
OffsetRect(&rWin,pt->h-rWin.left,pt->v-rWin.top);
|
|
|
|
GetScreenRect(theWindow,&rWin,&rScreen);
|
|
|
|
dx1 = rWin.left - rScreen.left;
|
|
dy1 = rWin.top - rScreen.top;
|
|
dx2 = rScreen.right - rWin.right;
|
|
dy2 = rScreen.bottom - rWin.bottom;
|
|
dx = dy = 0;
|
|
|
|
// Make sure we're on screen
|
|
if (dx1<0) dx = -dx1;
|
|
else if (dx2 < 0) dx = dx2;
|
|
if (dy1<0) dy = -dy1;
|
|
else if (dy2 < 0) dy = dy2;
|
|
|
|
if (!dx && !dy)
|
|
{
|
|
// Move to edge. Find the edge we are closest to
|
|
short dTop,dLeft,dBottom,dRight;
|
|
|
|
dTop = rWin.top - rScreen.top;
|
|
dLeft = rWin.left - rScreen.left;
|
|
dBottom = rScreen.bottom - rWin.bottom;
|
|
dRight = rScreen.right - rWin.right;
|
|
if (dLeft < dTop && dLeft < dRight && dLeft < dBottom)
|
|
dx = -dx1; // Move to left edge
|
|
else if (dTop < dRight && dTop < dBottom)
|
|
dy = -dy1; // Move to top edge
|
|
else if (dRight < dBottom)
|
|
dx = dx2; // Move to right edge
|
|
else if (dRight == dBottom)
|
|
{
|
|
dy = dy2; // Move to bottom/right corner
|
|
dx = dx2;
|
|
}
|
|
else
|
|
dy = dy2; // Move to bottom
|
|
}
|
|
|
|
// Stay away from any other docked windows
|
|
if (theWindow)
|
|
{
|
|
WindowPtr winWP;
|
|
MyWindowPtr win;
|
|
OffsetRect(&rWin,dx,dy);
|
|
|
|
for (winWP = FrontWindow (); winWP; winWP = GetNextWindow (winWP))
|
|
{
|
|
win = GetWindowMyWindowPtr (winWP);
|
|
if (winWP!=theWindow && IsWindowVisible (winWP) && IsFloating(winWP) && win->windowType==kDockable)
|
|
{
|
|
Rect rSect,rDocked;
|
|
|
|
GetWindowStructureBounds(winWP,&rDocked);
|
|
if (SectRect(&rWin,&rDocked,&rSect))
|
|
{
|
|
// Overlap with this docked window
|
|
Boolean roomAbove = rDocked.top-rScreen.top >= RectHi(rWin);
|
|
Boolean roomBelow = rScreen.bottom-rDocked.bottom > RectHi(rWin);
|
|
Boolean roomLeft = rDocked.left-rScreen.left > RectWi(rWin);
|
|
Boolean roomRight = rScreen.right-rDocked.right > RectWi(rWin);
|
|
Boolean moveLeft = (rWin.left+rWin.right)/2 < (rDocked.left+rDocked.right)/2;
|
|
Boolean moveAbove = (rWin.top+rWin.bottom)/2 < (rDocked.top+rDocked.bottom)/2;
|
|
Boolean moveVertical = RectHi(rSect) < RectWi(rSect);
|
|
|
|
if (moveVertical)
|
|
{
|
|
if (!roomAbove && !roomBelow)
|
|
moveVertical = false;
|
|
}
|
|
else if (!roomLeft && !roomRight)
|
|
moveVertical = true;
|
|
|
|
if (moveVertical)
|
|
{
|
|
// Move above or below
|
|
if (moveAbove)
|
|
{
|
|
if (!roomAbove) moveAbove = false;
|
|
}
|
|
else
|
|
if (!roomBelow) moveAbove = true;
|
|
|
|
if (moveAbove)
|
|
dy -= rWin.bottom-rDocked.top; // Move above
|
|
else
|
|
dy += rDocked.bottom-rWin.top; // Move below
|
|
}
|
|
else
|
|
{
|
|
// Move left or right
|
|
if (moveLeft)
|
|
{
|
|
if (!roomLeft) moveLeft = false;
|
|
}
|
|
else
|
|
if (!roomRight) moveLeft = true;
|
|
|
|
if (moveLeft)
|
|
dx -= rWin.right-rDocked.left; // Move left
|
|
else
|
|
dx += rDocked.right-rWin.left; // Move right
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pt->h += dx;
|
|
pt->v += dy;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* GetScreenRect - get rect of screen containing specified window
|
|
**********************************************************************/
|
|
void GetScreenRect(WindowPtr theWindow, Rect *rWin, Rect *rScreen)
|
|
{
|
|
GDHandle gd;
|
|
|
|
if (theWindow && GetWindowKind(theWindow)==AD_WIN)
|
|
// If ad window, constrain to main screen
|
|
gd = MyGetMainDevice();
|
|
else
|
|
{
|
|
utl_GetRectGD(rWin,&gd);
|
|
if (!gd)
|
|
// Not on any screen! Use main screen.
|
|
gd = MyGetMainDevice();
|
|
}
|
|
|
|
// Get screen rect minus menu bar, dock, etc.
|
|
GetAvailableWindowPositioningBounds(gd,rScreen);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* PositionDockedWindow - make sure docked window is positioned correctly
|
|
**********************************************************************/
|
|
void PositionDockedWindow(WindowPtr winWP)
|
|
{
|
|
MyWindowPtr win = GetWindowMyWindowPtr (winWP);
|
|
Point pt;
|
|
RgnHandle rgn = nil;
|
|
Rect rStruc,rCont;
|
|
|
|
if (!win || !IsMyWindow(winWP) || win->windowType != kDockable || !IsWindowVisible (winWP)) return;
|
|
|
|
GetWindowStructureBounds(winWP,&rStruc);
|
|
pt.v = rStruc.top;
|
|
pt.h = rStruc.left;
|
|
DockedDragProc(&pt,rgn?rgn:MyGetWindowStructureRegion(winWP),(long)winWP);
|
|
if (rgn) DisposeRgn(rgn);
|
|
if (pt.h!=rStruc.left || pt.v!=rStruc.top)
|
|
{
|
|
// pt is location of strucRgn. Move region needs location of contRgn
|
|
GetWindowContentBounds(winWP,&rCont);
|
|
MoveWindow(winWP,pt.h+rCont.left-rStruc.left,pt.v+rCont.top-rStruc.top,false);
|
|
}
|
|
}
|
|
|
|
/**********************************************************************
|
|
* PositionDockedWindows - make sure docked windows are positioned correctly
|
|
**********************************************************************/
|
|
void PositionDockedWindows(void)
|
|
{
|
|
WindowPtr theWindow;
|
|
|
|
for (theWindow = GetWindowList(); theWindow; theWindow = GetNextWindow (theWindow))
|
|
PositionDockedWindow(theWindow);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* DockWinReduce - reduce a rect to not include docked windows
|
|
**********************************************************************/
|
|
void DockedWinReduce(WindowPtr checkWinWP, Rect *winRect, Rect *r)
|
|
{
|
|
WindowPtr winWP;
|
|
MyWindowPtr win;
|
|
Rect rWin;
|
|
|
|
if (winRect) rWin = *winRect;
|
|
else if (checkWinWP) rWin = CurState(checkWinWP);
|
|
|
|
for (winWP = GetWindowList (); winWP; winWP = GetNextWindow (winWP))
|
|
{
|
|
win = GetWindowMyWindowPtr (winWP);
|
|
if (IsKnownWindowMyWindow(winWP) && win && (win)->windowType == kDockable && IsWindowVisible (winWP))
|
|
{
|
|
Rect rDocked,rSect;
|
|
|
|
GetWindowStructureBounds(winWP,&rDocked);
|
|
if (SectRect(&rDocked,checkWinWP?&rWin:r,&rSect))
|
|
{
|
|
// The window intersects a docked window
|
|
Rect rScreen;
|
|
enum { kNone,kTop,kLeft,kBottom,kRight } where;
|
|
short minDelta = REAL_BIG;
|
|
|
|
GetScreenRect(checkWinWP,&rDocked,&rScreen);
|
|
|
|
// Determine which screen edge we need to move away from
|
|
// Use the one that's the shortest distance
|
|
if (rDocked.bottom - rScreen.top < minDelta)
|
|
{
|
|
minDelta = rDocked.bottom - rScreen.top;
|
|
where = kTop;
|
|
}
|
|
if (rDocked.right - rScreen.left < minDelta)
|
|
{
|
|
minDelta = rDocked.right - rScreen.left;
|
|
where = kLeft;
|
|
}
|
|
if (rScreen.bottom - rDocked.top < minDelta)
|
|
{
|
|
minDelta = rScreen.bottom - rDocked.top;
|
|
where = kBottom;
|
|
}
|
|
if (rScreen.right - rDocked.left < minDelta)
|
|
{
|
|
minDelta = rScreen.right - rDocked.left;
|
|
where = kRight;
|
|
}
|
|
|
|
switch (where)
|
|
{
|
|
case kTop:
|
|
if (r->top < rDocked.bottom)
|
|
{
|
|
r->top = rDocked.bottom + 2;
|
|
OffsetRect(&rWin,0,rDocked.bottom+2-rWin.top);
|
|
}
|
|
break;
|
|
case kLeft:
|
|
if (r->left < rDocked.right)
|
|
{
|
|
r->left = rDocked.right + 2;
|
|
OffsetRect(&rWin,rDocked.right+2-rWin.left,0);
|
|
}
|
|
break;
|
|
case kBottom:
|
|
if (r->bottom > rDocked.top) r->bottom = rDocked.top - 2;
|
|
break;
|
|
case kRight:
|
|
if (r->right > rDocked.left) r->right = rDocked.left - 2;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**********************************************************************
|
|
* DockedWinRemove - subtract docked windows from a region
|
|
**********************************************************************/
|
|
void DockedWinRemove(RgnHandle rgn,WindowPtr ignoreWinWP)
|
|
{
|
|
WindowPtr winWP;
|
|
MyWindowPtr win;
|
|
|
|
for (winWP = GetWindowList (); winWP; winWP = GetNextWindow (winWP))
|
|
{
|
|
win = GetWindowMyWindowPtr (winWP);
|
|
if (winWP!=ignoreWinWP && IsKnownWindowMyWindow(winWP) && win && (win)->windowType == kDockable)
|
|
{
|
|
Rect rDocked;
|
|
|
|
GetWindowStructureBounds(winWP,&rDocked);
|
|
RgnMinusRect(rgn,&rDocked);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**********************************************************************
|
|
* Returns true if this is the frontmost, non floating window
|
|
**********************************************************************/
|
|
Boolean IsTopNonFloater(WindowPtr theWindow)
|
|
{
|
|
return (theWindow == MyFrontNonFloatingWindow());
|
|
}
|
|
/**********************************************************************
|
|
* Return a pointer to the frontmost, non floating, visible window.
|
|
*
|
|
* In OS X, invisible windows can be at the head of the window list.
|
|
* Eudora opens a lot of invisible windows, and assumes they're not
|
|
* in the list at all. This routine exists to help work around this
|
|
* development, and return the topmost, VISIBLE window. It should
|
|
* replace calls to FrontWindow_() when we're looking for the frontmost
|
|
* visible window.
|
|
*
|
|
* Changing MyFrontNonFloatingWindow() to return the topmost, visible,
|
|
* non-floating window should be perfectly safe. In the classic
|
|
* version, MyFrontNonFloatingWindow NEVER returns an invisible window.
|
|
**********************************************************************/
|
|
WindowPtr MyFrontNonFloatingWindow(void)
|
|
{
|
|
return FrontNonFloatingWindow();
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* Return a pointer to the window that is topmost on this part of the
|
|
* screen. Return 0 if there are no windows here, or those that are
|
|
* aren't floating windows.
|
|
**********************************************************************/
|
|
MyWindowPtr FloaterAtPoint(Point mouse)
|
|
{
|
|
WindowPtr aFloater = NULL;
|
|
Rect r;
|
|
|
|
LocalToGlobal(&mouse);
|
|
|
|
if (IsFloating(FrontWindow()))
|
|
{
|
|
aFloater = FrontWindow();
|
|
|
|
while (aFloater && IsFloating(aFloater))
|
|
{
|
|
GetWindowContentBounds(aFloater,&r);
|
|
if (PtInRect(mouse,&r)) return (GetWindowMyWindowPtr(aFloater));
|
|
aFloater = GetNextWindow(aFloater);
|
|
}
|
|
}
|
|
|
|
return (nil);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* Hide a window, but activate the next non-floating window.
|
|
**********************************************************************/
|
|
void MyHideWindow(WindowPtr theWindow)
|
|
{
|
|
|
|
HideWindow(theWindow);
|
|
WindowIsInvisibleClassic(theWindow);
|
|
if (IsFloating(theWindow)) SetKeyFocusedFloater(nil);
|
|
if (!IsFloating(theWindow) && GetNextWindow(theWindow)) ActivateMyWindow(theWindow, !InBG);
|
|
}
|
|
|
|
/**********************************************************************
|
|
* IsFloating - returns true if this window floats above others.
|
|
* Currently this includes kFloating and kDockable windows.
|
|
**********************************************************************/
|
|
Boolean IsFloating(WindowPtr winWP)
|
|
{
|
|
MyWindowPtr win = GetWindowMyWindowPtr (winWP);
|
|
|
|
return (IsKnownWindowMyWindow(winWP) && win && ((win->windowType == kFloating) || (win->windowType == kDockable)));
|
|
}
|
|
|
|
/**********************************************************************
|
|
* SetKeyFocusFloater - sets floating window to receive key focus if window supports keys
|
|
**********************************************************************/
|
|
void SetKeyFocusedFloater(MyWindowPtr win)
|
|
{
|
|
ASSERT(!keyFocusedFloater || win && keyFocusedFloater==win);
|
|
// Don't allow ad window to receive focus although it has a Pete handle
|
|
keyFocusedFloater = win && win->pte && GetWindowKind (GetMyWindowWindowPtr (win)) != AD_WIN ? win : nil;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* FloatingWinIdle - periodically make sure no non-floaters are on top
|
|
* the only windows I'm aware of that can do this are plug-in windows
|
|
**********************************************************************/
|
|
void FloatingWinIdle(void)
|
|
{
|
|
}
|
|
|
|
|
|
#endif //FLOAT_WIN
|