sys7.1-doc-wip/ProcessMgr/LayerMgrPatches.c

512 lines
13 KiB
C

/*
File: LayerMgrPatches.c
Contains: Glue between Process Mgr and the Layer Manager.
Written by: Ed Tecot
Copyright: © 1989-1992 by Apple Computer, Inc., all rights reserved.
Change History (most recent first):
<6> 4/9/92 KST JH,There is only one float layer now instead of one float layer
for each application.
<5> 10/9/91 YK Added NewFloatLayer and DisposeFloatLayer.
<4> 5/23/91 dba do a style of coercion that MPW 3.2 C likes
<3> 1/21/91 DFH (KSM) Process Menu is now called Application Menu.
<0> 4/18/89 EMT New Today.
*/
#pragma segment kernel_segment
#include <types.h>
#include <toolutils.h>
#include <osutils.h>
#include <memory.h>
#include <quickdraw.h>
#include <events.h>
#include <resources.h>
#include <retrace.h>
#include <windows.h>
#include <palette.h>
#include <errors.h>
#include "Glue.h"
#include "Lomem.h"
#include "Data.h"
#include "ScrapCoercion.h"
#include "OSDispatchPrivate.h"
Point GetApplicationMenuLeftCoord(void);
pascal void ZoomRect(Rect *, Rect *, Boolean);
/* GetLayer. This routine returns the layer pointer for the current
* process.
*/
pascal LayerPtr
c_getlayer(void)
{
unsigned long olda5;
LayerPtr retval;
olda5 = ProcessMgrA5SimpleSetup();
retval = pCurrentProcess->p_layer;
A5SimpleRestore(olda5);
return(retval);
}
/* LayerInsert. Can't support anymore. SysError instead. (June 89) */
pascal void
c_layerinsert(LayerPtr, LayerPtr)
{
SysError(dsCoreErr);
}
/* LayerDelete. Can't support anymore. SysError instead. (June 89) */
pascal LayerPtr
c_layerdelete(LayerPtr)
{
SysError(dsCoreErr);
return nil;
}
/* LNewWindow. Can't support anymore. SysError instead. (June 89) */
pascal void
c_lnewwindow(WindowPeek)
{
SysError(dsCoreErr);
}
/* LCloseWindow. Can't support anymore. SysError instead. (June 89) */
pascal void
c_lclosewindow(WindowPeek)
{
SysError(dsCoreErr);
}
/* LCalcVis. Don't support anymore. SysError instead. (April 90) */
pascal void
c_LCalcVis(LayerPtr, WindowPeek)
{
SysError(dsCoreErr);
}
/* LCVBehind. Don't support anymore. SysError instead. (April 90) */
pascal void
c_LCVBehind(LayerPtr, WindowPeek, RgnHandle)
{
SysError(dsCoreErr);
}
/* LPaintOne. Don't support anymore. SysError instead. (April 90) */
pascal void
c_LPaintOne(LayerPtr, WindowPeek, RgnHandle)
{
SysError(dsCoreErr);
}
/* LPaintBehind. Don't support anymore. SysError instead. (April 90) */
pascal void
c_LPaintBehind(LayerPtr, WindowPeek, RgnHandle)
{
SysError(dsCoreErr);
}
/* LShowHide. Don't need anymore. SysError instead. (March 90) */
pascal void
c_LShowHide(LayerPtr, Boolean)
{
SysError(dsCoreErr);
}
/* LClipAbove. ClipAbove knowing about layers closer to the front. */
pascal void
c_LClipAbove(LayerPtr layer, WindowPeek window)
{
layer = SwapCurLayer(layer);
ClipAbove(window);
SetCurLayer(layer);
}
/* MakeTopLayer. This routine will make the given layer the frontmost
* layer, doing the necessary redrawing and visRgn recomputation. We avoid
* calling SelectWindow, since it will generate an extra deactivate/activate.
*/
pascal void
c_maketoplayer(LayerPtr layer)
{
WindowPtr topWindow;
unsigned long olda5;
THz tempZone;
olda5 = ProcessMgrA5Setup();
/* Recalculate vis regions, etc. Switch to the system heap since this is a
* cross-application operation, and we don't want to penalize the current
* application's zone for the memory needed to do the region operations.
* Layer operations are to us what window operations are to apps.
*/
SafeSetZone(tempZone, SYSZONE);
BringToFront(layer);
SafeRestoreZone(tempZone);
/* Highlight the front window (before making layer visible, to avoid flash). */
if ((topWindow = FrontWindowIn(layer)) != nil)
{
HiliteWindow(topWindow, true);
if (Colorized)
ActivatePalette(topWindow);
}
/* Bring layer back out of hiding */
if (((LayerPeek) layer)->visible == false)
HideLayer(layer, true);
A5Restore(olda5);
}
/* Closelayer. This routine is called by exiting processes to remove the
* layer from the screen. Although it is named layerCLOSE, it actually
* destroys the layer. If the layer is owned by the owner of the desktop,
* we also close the desktop layer.
* NOTE: This will not be good if the desktop owner has multiple layers,
* and just wants to close one of them!
*/
pascal void
c_layerclose(LayerPtr layer)
{
/* We own the desklayer too. */
if ((LayerOwner(layer) == desklayerowner))
desklayerowner = nil;
DisposeWindow(layer);
}
/* LayerInit. This routine will initialize the current process' layer. If the
* process is a normal one, the layer goes to the front of the list. If the process
* is a background layer, he goes to the back of the list.
* NOTE: We assume that launch called SetCurLayer(MFLayer). This keeps the layer/window
* lists synchronized before this call, and ensures proper placement of the layer we
* create here.
*/
pascal void
c_layerinit(void)
{
register PEntryPtr pCurrProc;
LayerPtr behind;
unsigned long olda5;
olda5 = ProcessMgrA5Setup();
pCurrProc = pCurrentProcess;
if (pCurrProc->p_layer != nil)
dbmsg("Current application called InitWindows twice");
/* Figure out where the layer should go (foreground vs background). */
behind = (pCurrProc == pFrontProcess) ? (LayerPtr) -1 : nil;
(void) NewLayer(&pCurrProc->p_layer, true, false, behind, (long) pCurrProc);
SetCurLayer(pCurrProc->p_layer);
A5Restore(olda5);
}
/* c_LGetNextLayer. Given a layer, returns the next layer in the list. Given nil,
* returns first.
*/
pascal LayerPtr
c_LGetNextLayer(LayerPtr pCurLayer, Boolean wantVisiblesOnly)
{
unsigned long olda5;
olda5 = ProcessMgrA5Setup();
/* Nil means start at the first layer */
pCurLayer = (pCurLayer == nil) ? GetFrontAppLayer() : ((LayerPeek) pCurLayer)->nextWindow;
/* If the caller will take any layer, return the pCurLayer.
* Otherwise, find the first visible one.
*/
while (pCurLayer != nil)
{
if (wantVisiblesOnly == false || ((LayerPeek) pCurLayer)->visible)
break;
pCurLayer = ((LayerPeek) pCurLayer)->nextWindow;
}
A5Restore(olda5);
return(pCurLayer);
}
/* LayerFind. Given a global mouse coordinate, this routine will snoop through all of
* the layers' windowlists looking for the frontmost layer which contains this mouse
* point. The layer pointer is returned if the mouse is in a layer, otherwise zero is
* returned. Note that it no longer checks the deskrgn.
*/
pascal LayerPtr
c_layerfind(Point where)
{
LayerPtr pLayer, saveLayer;
unsigned long olda5;
olda5 = ProcessMgrA5Setup();
saveLayer = SwapCurLayer(MFLayer);
if (FindLayer(where, &pLayer) != inContent)
pLayer = nil;
SetCurLayer(saveLayer);
A5Restore(olda5);
return(pLayer);
}
/* LGetAuxWin. This routine returns the AuxWin Handle for the given window in the
* given layer. If the window is nil, the handle to the default record is returned.
* The boolean return is TRUE if a unique aux handle was found, FALSE if the default
* is returned.
*/
pascal short
c_lgetauxwin(LayerPtr layer, WindowPeek window, AuxWinHandle awh)
{
short result;
layer = SwapCurLayer(layer);
result = GetAuxWin(window, awh);
SetCurLayer(layer);
return result;
}
/* ColorInvalRect. This routine intersects every displayed window with the given
* device rectangle; for those that intersect, an update is generated.
* NOTE: This routine may change thePort.
*/
pascal void
c_lcolorinvalrect(Rect *pDevRect, short, short sysupdates)
{
#pragma unused (sysupdates)
RgnHandle clobberedRgn;
clobberedRgn = NewRgn();
RectRgn(clobberedRgn, pDevRect);
PaintOnePal(nil, clobberedRgn);
DisposeRgn(clobberedRgn);
}
#define ARE_EQUAL_BOOLEANS(b1, b2) ((((b1) ^ (b2)) & 1) == 0)
#define ARE_NOT_EQUAL_BOOLEANS(b1, b2) ((((b1) ^ (b2)) & 1) != 0)
/* HideLayer. Do the user interface-y aspects of layer hiding.
* NOTE: Requires A5 == PROCESSMGRGLOBALS
*/
Rect hideDstRect; /* Set up at init time */
pascal void
HideLayer(LayerPtr layer, Boolean showFlag)
{
register WindowPeek pFrontWindow;
PEntryPtr pProc;
/* Do nothing if layer is already in requested state (to prevent zooming) */
if (ARE_EQUAL_BOOLEANS(((LayerPeek) layer)->visible, showFlag))
return;
/* Locate topmost visible window. */
pFrontWindow = FrontWindowIn(layer);
do
{
/* Escape from loop if there are no visibles */
if (pFrontWindow == nil)
break;
/* Ignore window if it has nothing on the screen (empty strucRgn), or it is
* a fake DA window (p_wptr is a pointer to it).
*/
if (pFrontWindow->visible)
{
pProc = LayerOwner(layer);
if ( (EmptyRgn(pFrontWindow->strucRgn) == false)
&& (pFrontWindow != pProc->p_wptr) )
break;
}
/* Link to next window back in layer */
pFrontWindow = pFrontWindow->nextWindow;
}
while (true);
/* If hiding, hide windows before zoom */
if (!showFlag)
ShowHide(layer, false);
/* Zoom the top window, if any. */
if (pFrontWindow != nil)
{
Rect hideDstRect, globalOfPortRect;
Rect *pPortBitsBounds;
register short globalToLocalY;
register short globalToLocalX;
/* Create the rect for the top window */
pPortBitsBounds = (pFrontWindow->port.portBits.rowBytes < 0)
? &(*((CGrafPtr)pFrontWindow)->portPixMap)->bounds
: &pFrontWindow->port.portBits.bounds;
globalToLocalY = pPortBitsBounds->top;
globalToLocalX = pPortBitsBounds->left;
/* Create the rect for the Application menu. */
*((Point *)&hideDstRect.top) = *((Point *)&hideDstRect.bottom) = GetApplicationMenuLeftCoord();
/* Convert the "global" port rect to global coords */
globalOfPortRect = pFrontWindow->port.portRect;
globalOfPortRect.top -= globalToLocalY;
globalOfPortRect.left -= globalToLocalX;
globalOfPortRect.bottom -= globalToLocalY;
globalOfPortRect.right -= globalToLocalX;
/* Zoom it, globally */
ZoomRect(&hideDstRect, &globalOfPortRect, showFlag);
}
/* If showing, show windows now that zoom is done. */
if (showFlag)
ShowHide(layer, true);
}
/* ShowHideOthers. Set the invisibility of all layers but the current app and the
* desk layer.
*/
void
ShowHideOthers(Boolean showFlag)
{
LayerPtr pLayer;
pLayer = GetFrontAppLayer();
while ((pLayer = ((LayerPeek) pLayer)->nextWindow) != nil)
ShowHide(pLayer, showFlag);
}
/* ---------------------------------------------------------------------
*
* Below are the kernel support routines for the layer manager.
*
* --------------------------------------------------------------------- */
/* FindAppLayer. For the given window, this routine finds the ancestral
* layer which is a child of MFLayer. If it can't be found, returns nil.
*/
LayerPtr
FindAppBaseLayer(WindowPtr window, LayerPtr layerPtr)
{
register LayerPtr ancestor;
/* Paddle upriver. Must call GetParent the first time, since WindowRecords have
* no "parent" field (parent must be derived). Once we know we have a layer, we
* can use the "parent" field directly.
*/
ancestor = GetParent(window);
while ((ancestor != nil) && (ancestor != layerPtr))
{
window = ancestor;
ancestor = ((LayerPeek) ancestor)->parent;
}
/* No-find means the given layer not below MFLayer. By (the current)
* definition, applications do not control such layers.
*/
if (ancestor == nil)
window = nil;
return (LayerPtr) window;
}
/* CancelUpdateAction. An action procedure which sets the update region to empty. */
pascal OSErr
CancelUpdateAction(WindowPeek window, LayerPeek, void *)
{
SetEmptyRgn(window->updateRgn);
return noErr;
}
/* CancelPendingUpdates. For the given layer, set the update regions of every
* window to the empty region.
*/
void
CancelPendingUpdates(LayerPtr layerPtr)
{
(void) EachWindow(layerPtr, ((LayerPeek)layerPtr)->nextWindow, nil, CancelUpdateAction, nil);
}
/* Floating Window stuff */
#pragma parameter __D0 GetHelpLayer(__D0);
pascal LayerPtr GetHelpLayer()
= {
0x2078,0x02B6, // MOVE.L ExpandMem,A0
0x2068,0x0078, // MOVE.L ExpandMemRec.emHelpGlobals(A0),A0
0x2028,0x00E6 // MOVE.L hmgLayer(A0),D0
};
pascal OSErr
C_NewFloatLayer( LayerPtr *newFloatLayer)
{
LayerPtr hmLayer;
LayerPtr currLayer;
OSErr err = noErr;
unsigned long olda5;
THz tempZone;
olda5 = ProcessMgrA5Setup();
if ( (*newFloatLayer = pCurrentProcess->p_floatLayer)!=nil )
{
A5Restore(olda5);
return noErr;
}
currLayer = SwapCurLayer( GetRootLayer());
SafeSetZone(tempZone, SYSZONE);
if ( IMLayer==nil )
{
if ( ( hmLayer = GetHelpLayer() )==nil )
{
hmLayer = (LayerPtr)-1;
}
err = NewLayer( &IMLayer, true, true, hmLayer, (long)nil);
}
/****
if ( err==noErr )
{
SetCurLayer( IMLayer);
err = NewLayer( newFloatLayer, true, true, (WindowPtr)-1, (long)pCurrentProcess);
}
****/
SafeRestoreZone(tempZone);
//pCurrentProcess->p_floatLayer = *newFloatLayer;
*newFloatLayer = IMLayer;
SetCurLayer( currLayer);
A5Restore(olda5);
return err;
}
pascal OSErr
C_DisposeFloatLayer( LayerPtr *floatLayer)
{
OSErr err = noErr;
unsigned long olda5;
olda5 = ProcessMgrA5Setup();
if ( pCurrentProcess->p_floatLayer == (*floatLayer) )
{
DisposeWindow(*floatLayer);
*floatLayer = nil;
}
else
err = paramErr;
A5Restore(olda5);
return err;
}