/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: macroot.cpp,v 1.7.20.1 2004/07/09 01:59:02 hubbe Exp $
 * 
 * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
 * 
 * The contents of this file, and the files included with this file,
 * are subject to the current version of the RealNetworks Public
 * Source License (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (the "RCSL") available at
 * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
 * will apply. You may also obtain the license terms directly from
 * RealNetworks.  You may not use this file except in compliance with
 * the RPSL or, if you have a valid RCSL with RealNetworks applicable
 * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
 * the rights, obligations and limitations governing use of the
 * contents of the file.
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 * 
 * This file is part of the Helix DNA Technology. RealNetworks is the
 * developer of the Original Code and owns the copyrights in the
 * portions it created.
 * 
 * This file, and the files included with this file, is distributed
 * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
 * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
 * ENJOYMENT OR NON-INFRINGEMENT.
 * 
 * Technology Compatibility Kit Test Suite(s) Location:
 *    http://www.helixcommunity.org/content/tck
 * 
 * Contributor(s):
 * 
 * ***** END LICENSE BLOCK ***** */

#include "hxcom.h"

#include "hxtypes.h"
#include "hxwintyp.h"
#include "hxmap.h"
#include "hxslist.h"
#include "ihxpckts.h"
#include "hxwin.h"
#include "hxengin.h"
#include "hxsite2.h"
#include "chxxtype.h"
#include "hxvctrl.h"
#include "hxvsurf.h"
#include "hxcodec.h"
#include "surface.h"
#include "vidosurf.h"
#include "sitetext.h"
#include "chxpckts.h"
#include "hxevent.h"
#include "bltpatch.h"
#include "hxprefs.h"

#include "hxevent.h"
#include "hxthread.h"

#include "basesite.h"
#include "platform/mac/macroot.h"

#include "platform/mac/macsite.h"
#include "platform/mac/macsurf.h"

#include "platform/mac/hx_moreprocesses.h"

#ifndef _MAC_UNIX
#include "hxmm.h"
#endif

#include "hxcore.h"

#ifndef _MACINTOSH
#ifndef _MAC_UNIX
#error This is the Macintosh platform specific implementation.
#endif
#endif

#if !defined(_CARBON) && !defined(_MAC_UNIX)
#error This is an OS X and later implementation!
#endif

#include "hxheap.h"
#ifdef _DEBUG
#undef HX_THIS_FILE		
static const char HX_THIS_FILE[] = __FILE__;
#endif

UINT32 CMacRootSurface::zm_uNumberOfAttachedDevices = 0;
GDHandle CMacRootSurface::zm_AttachedDevice[CMacRootSurface::kMaxMonitors];
CHXSimpleList CMacRootSurface::zm_RootSurfaceList;

CMacRootSurface::OverlayInfoStruct CMacRootSurface::zm_OverlayInfo[CMacRootSurface::kMaxMonitors];


/************************************************************************
 *  Method:
 *    CMacRootSurface constructor
 */
CMacRootSurface::CMacRootSurface(IUnknown* pContext, CHXBaseSite* pSite)
 : CBaseRootSurface(pContext, pSite)
 , m_bItsOKToDoAnInterruptBlit(FALSE)
 , m_pVisRgnRects(NULL)
 , m_LastVisRgn(NULL)
 , m_bNeedToForceVisRgnUpdate(FALSE)
 , m_nBlitDepthEnum(-1)
 , m_bInBlueBox(FALSE)
 , m_bAllowedToITBInBlueBox(TRUE)
{
    m_pVisRgnRects = new CHXSimpleList();
    
    int i;
    for (i = 0; i < kNumberOfDepths; i++)
    {
	m_RootSurfaceGWorld[i] = nil;
	m_RootGWorldPixMap[i] = nil;
    }

    if (zm_uNumberOfAttachedDevices == 0)
    {
	// OK, first zero it all out
	for (i=0; i < kMaxMonitors; i++)
	{
	    zm_AttachedDevice[i] = NULL;
	    
	    zm_OverlayInfo[i].b_OverlayExists = FALSE;
	    zm_OverlayInfo[i].b_OverlayInitialized = FALSE;
	}
	
	// now fill it in with all attached devices!
	
	// check for multiple monitors. Also grab main device...
	GDHandle mainGD = ::GetMainDevice();
	GDHandle gdH = ::GetDeviceList();
	while ( gdH )
	{
	    zm_AttachedDevice[zm_uNumberOfAttachedDevices] = gdH;
	    zm_uNumberOfAttachedDevices++;
	    gdH = ::GetNextDevice( gdH );
	    
	    if (zm_uNumberOfAttachedDevices >= kMaxMonitors)
	    {
		gdH = nil; // stop counting after ten monitors!
	    }
	}
    }
    
    long blueBoxParams = 0;
    short err = Gestalt('bbox', &blueBoxParams);
    if (!err && blueBoxParams & 0x00000001)
    {
	m_bInBlueBox = TRUE;
    }
    
    m_LocalToGlobalCoords.h = -32768;
    m_LocalToGlobalCoords.v = -32768;
    zm_RootSurfaceList.AddTail(this);
}

/************************************************************************
 *  Method:
 *    CMacRootSurface destructor
 */
CMacRootSurface::~CMacRootSurface()
{
    LISTPOSITION pos = zm_RootSurfaceList.Find(this);
    zm_RootSurfaceList.RemoveAt(pos);
    
    int i;
    for (i = 0; i < kNumberOfDepths; i++)
    {
	if (m_RootSurfaceGWorld[i] != NULL)
	{
	    ::UnlockPixels(m_RootGWorldPixMap[i]);
	    ::DisposeGWorld(m_RootSurfaceGWorld[i]);
	    m_RootSurfaceGWorld[i] = NULL;
	    m_RootGWorldPixMap[i] = NULL;
	}
    }
    
    if (m_LastVisRgn)
    {
	::DisposeRgn(m_LastVisRgn);
	m_LastVisRgn = nil;
    }
    delete m_pVisRgnRects;
    m_pVisRgnRects = NULL;
}

/************************************************************************
 *  Method:
 *    CMacRootSurface::_GetYUVScratchWidthHeight
 */
void
CMacRootSurface::_GetYUVScratchWidthHeight(UINT32* pWidth, UINT32* pHeight)
{
}


/************************************************************************
 *  Method:
 *    CMacRootSurface::_CreateYUVScratchSurface
 */
void
CMacRootSurface::_CreateYUVScratchSurface(UINT32 width, UINT32 height)
{
}


/************************************************************************
 *  Method:
 *    CMacRootSurface::_GetYUVScratchSurfacePointer
 */
void
CMacRootSurface::_GetYUVScratchSurfacePointer(UCHAR** pYUVBits, INT32* YUVPitch)
{
}


/************************************************************************
 *  Method:
 *    CMacRootSurface::CreateScratchSurface
 */
HX_RESULT
CMacRootSurface::CreateScratchSurface(int nCompositionSurfaceCID, HXxSize* pSize)
{
    return HXR_OK;
}


/************************************************************************
 *  Method:
 *    CMacRootSurface::ScratchLock
 */
HX_RESULT
CMacRootSurface::ScratchLock(UCHAR** pBits, INT32* pPitch_)
{
    return HXR_OK;
}


/************************************************************************
 *  Method:
 *    CMacRootSurface::ScratchUnlock
 */
HX_RESULT
CMacRootSurface::ScratchUnlock(UCHAR* pBits)
{
    return HXR_OK;
}


/************************************************************************
 *  Method:
 *    CMacRootSurface::_BltFromScratchToComposition
 */
void
CMacRootSurface::_BltFromScratchToComposition(HXxRect& rDestRect, HXxRect& rSrcRect)
{
}


/************************************************************************
 *  Method:
 *    CMacRootSurface::_DebugBlt
 */
HX_RESULT
CMacRootSurface::_DebugBlt( UCHAR*               pImageData,
                        HXBitmapInfoHeader* pBitmapInfo,
                        REF(HXxRect)         rDestRect,
                        REF(HXxRect)         rSrcRect)
{
    return HXR_OK;
}

/************************************************************************
 *  Method:
 *    CMacRootSurface::_MinimalUnlock
 */
HX_RESULT
CMacRootSurface::_MinimalUnlock(HXxWindow* pWindow)
{
    return HXR_OK;
}


/************************************************************************
 *  Method:
 *    CMacRootSurface::_LockComposition
 */
HX_RESULT
CMacRootSurface::_LockComposition(UCHAR** pBits, INT32* pPitch)
{
    if (m_bItsOKToDoAnInterruptBlit)
    {
        // if the OK to ITB boolean still needs to be set,
        // the region will be force-updated at an appropriate
        // time.
        
        // ensure that region is updated.
        Rect r;
        r.left = m_boundsRect.left;
        r.top = m_boundsRect.top;
        r.right = m_boundsRect.right;
        r.bottom = m_boundsRect.bottom;
        UpdateRegionIfNecessary(r, m_LocalToGlobalCoords, m_bNeedToForceVisRgnUpdate);
        m_bNeedToForceVisRgnUpdate = FALSE;
    }
    return HXR_OK;
}


/************************************************************************
 *  Method:
 *    CMacRootSurface::_CreateCompositionSurface
 */
HX_RESULT
CMacRootSurface::_CreateCompositionSurface()
{
    // XXXbobclark The composition surface -- where stuff gets blitted
    // on an interim basis prior to being blitted straight to the screen
    // -- works most optimally if it's the same depth as the screen.
    // When all this shtuff was in comlib I did this by having possibly
    // three interim GWorlds, one each of depths 8-bit, 16-bit, and 32-bit.
    // Note that interrupt-time blitting REQUIRES a composition surface of the
    // same depth as the screen 'cause CopyBits() doesn't work. And multiple
    // monitors imply that multiple depths may need to be active simultaneously.

    // Since this gets called so often I'll never dispose the GWorld
    // in _DestroyCompositionSurface() so it won't recreate it here. But if
    // it stays this way then I'll need to check the size here to see if I
    // need to dispose the current GWorld and create a new, correctly-sized
    // one.

    if (m_compositionSize.cx > m_allocatedCompositionSize.cx || m_compositionSize.cy > m_allocatedCompositionSize.cy)
    {
	::UnlockPixels(m_RootGWorldPixMap[kThirtyTwoBitDepth]);
	::DisposeGWorld(m_RootSurfaceGWorld[kThirtyTwoBitDepth]);
	m_RootSurfaceGWorld[kThirtyTwoBitDepth] = nil;
	m_RootGWorldPixMap[kThirtyTwoBitDepth] = nil;
	m_pCompositionSurface = nil;
	m_nBlitDepthEnum = -1;
    }
    
    if (!m_pCompositionSurface)
    {

	short thePixelDepth = 32;
	Rect r;
	SetRect(&r, 0, 0, m_compositionSize.cx, m_compositionSize.cy);

	// It's possible that this is getting called extremely often -- like
	// once per blit! and it's also getting called occasionally at interrupt
	// time. So I need to get this being built at appropriate times only,
	// and then I think that copying it over in _MinimalBlt() I can blit it over
	// to the window and maybe just maybe I'll have something visible. Sheesh.

	::NewGWorld(&m_RootSurfaceGWorld[kThirtyTwoBitDepth], thePixelDepth, &r, nil, nil, useTempMem);
	if (!m_RootSurfaceGWorld[kThirtyTwoBitDepth])
	{
	    // it failed to create it in temp mem so try creating it in the application heap.
	    ::NewGWorld(&m_RootSurfaceGWorld[kThirtyTwoBitDepth], thePixelDepth, &r, nil, nil, 0);
	    
	    if (!m_RootSurfaceGWorld[kThirtyTwoBitDepth]) return HXR_FAIL;
	}

	m_RootGWorldPixMap[kThirtyTwoBitDepth] = GetPortPixMap(m_RootSurfaceGWorld[kThirtyTwoBitDepth]);
	::LockPixels(m_RootGWorldPixMap[kThirtyTwoBitDepth]);

	m_pCompositionSurface = (unsigned char*)GetPixBaseAddr(m_RootGWorldPixMap[kThirtyTwoBitDepth]);
	m_nBlitDepthEnum = kThirtyTwoBitDepth;

	m_allocatedCompositionSize = m_compositionSize;
	m_nCompositionPitch = (**m_RootGWorldPixMap[kThirtyTwoBitDepth]).rowBytes & 0x3fff;

	m_boundsRect.left = r.left;
	m_boundsRect.top = r.top;
	m_boundsRect.right = r.right;
	m_boundsRect.bottom = r.bottom;

	m_nCompositionSurfaceCID = CID_RGB32;
    }

    return HXR_OK;
}


/************************************************************************
 *  Method:
 *    CMacRootSurface::_DestroyCompositionSurface
 */
HX_RESULT
CMacRootSurface::_DestroyCompositionSurface()
{

    // XXXbobclark I've gotta figure out what the story is here,
    // 'cause right now it's getting called every blit.
    // I certainly don't want to be destroying the whole GWorld!
    // So currently I'll never destroy it. Ehhh.
    
    return HXR_OK;
}

/************************************************************************
 *  Method:
 *    CMacRootSurface::_MinimalBlt
 */
void
CMacRootSurface::_MinimalBlt(HXxRect& src, HXxRect& dst)
{
    {
	GrafPtr savePort;
	::GetPort(&savePort);
	WindowPtr macWindow;
	macWindow = m_pSite->m_pWindow ? (WindowPtr)m_pSite->m_pWindow->window : NULL;
	
	if (CHXMacSite::zm_bFullScreenActive)
	{
	    CHXMacSite* pMacSite = (CHXMacSite*)m_pSite;
	    if (pMacSite->m_pHXxFullScreenWindow)
	    {
		macWindow = (WindowPtr)pMacSite->m_pHXxFullScreenWindow->window;
	    }
	}
	
	::SetPort(GetWindowPort(macWindow));

	// XXXbobclark The "old site" surface implementation's innermost
	// blitting API, "BltImage", always happened to have the dest
	// rectangle at (0,0) and relied on SetOrigin to set it up
	// correctly. The "new site" implementation's innermost blittin
	// API is "_MinimalBlt", and in this case the rectangle is relative
	// to the core's area. So I remember the current origin (so I can
	// restore it 'cause some renderers need it) and reset it to the
	// core's offset.
	Point oldOrigin;
	Rect portRect;
	GetPortBounds(GetWindowPort(macWindow), &portRect);
	oldOrigin.h = portRect.left;
	oldOrigin.v = portRect.top;
	HXxWindow* pWindow = m_pSite->GetWindow();
	if (pWindow)
	{
	    SetOriginAndMaintainClipRgn(-pWindow->x,-pWindow->y);
	}


	m_LocalToGlobalCoords.h = 0;
	m_LocalToGlobalCoords.v = 0;
	::LocalToGlobal(&m_LocalToGlobalCoords);
	
	m_bItsOKToDoAnInterruptBlit = TRUE;
	
	Rect dstR;

	dstR.left = dst.left;
	dstR.top = dst.top;
	dstR.right = dst.right;
	dstR.bottom = dst.bottom;

	// Forcing the source rect to equal the destination rect; all the
	// complicated math actually takes place elsewhere so this is an
	// OK thing to do.
	Rect srcR = dstR;

	if (CHXMacSite::zm_bFullScreenActive)
	{
	    CHXMacSite* pMacSite = (CHXMacSite*)m_pSite;
	    if (!pMacSite->m_bInternalResizeOnFullscreen)
	    {
		dstR.right = dstR.left + (long)(((double)dstR.right - (double)dstR.left)*pMacSite->m_fStretchMultiple);
		dstR.bottom = dstR.top + (long)(((double)dstR.bottom - (double)dstR.top)*pMacSite->m_fStretchMultiple);
	    }
	}

	if (m_nBlitDepthEnum >= 0)
	{
	    RGBColor blackRGB = {0x0000, 0x0000, 0x0000};
	    RGBColor whiteRGB = {0xffff, 0xffff, 0xffff};
	    
	    ColorSpec prevFore;
	    ColorSpec prevBack;
	    
	    ::SaveFore(&prevFore);
	    ::SaveBack(&prevBack);
	    
	    ::RGBForeColor(&blackRGB);
	    ::RGBBackColor(&whiteRGB);
            
	    ::CopyBits( (BitMap*)*m_RootGWorldPixMap[m_nBlitDepthEnum],
		    GetPortBitMapForCopyBits(GetWindowPort(macWindow)),
		    &srcR, &dstR, srcCopy, nil );
	    
	    ::QDFlushPortBuffer( ::GetWindowPort(macWindow), NULL );
	    ::RestoreFore(&prevFore);
	    ::RestoreBack(&prevBack);
	}

	SetOriginAndMaintainClipRgn(oldOrigin.h, oldOrigin.v);
	::SetPort(savePort);
    }
}


unsigned long
CMacRootSurface::_GetScreenPixelValue(long globX, long globY)
{
    unsigned long retVal = 0;
    int whichDevice;
    for (whichDevice = 0; whichDevice < zm_uNumberOfAttachedDevices; whichDevice++)
    {
	HX_ASSERT(zm_AttachedDevice[whichDevice]);
	
	PixMapHandle thePMH = (**zm_AttachedDevice[whichDevice]).gdPMap;
	unsigned long dstPtr = (unsigned long)::GetPixBaseAddr(thePMH);
	int pixelSize = (**thePMH).pixelSize;
	
	Rect deviceRect = (**zm_AttachedDevice[whichDevice]).gdRect;
	
	if (globX >= deviceRect.left && globX <= deviceRect.right
		&& globY >= deviceRect.top && globY <= deviceRect.bottom)
	{
	    int rowOffset = (globY - deviceRect.top) * ((**thePMH).rowBytes & 0x3fff);
	    int columnOffset = (globX - deviceRect.left) * pixelSize / 8;
	    dstPtr += rowOffset + columnOffset;
	    switch (pixelSize)
	    {
		case 32:
		    retVal = *(unsigned long*)dstPtr;
		    break;

		case 16:
		    retVal = *(unsigned short*)dstPtr;
		    break;

		case 8:
		    retVal = *(unsigned char*)dstPtr;
		    break;
	    }
	}
    }
    return retVal;
}

unsigned long
CMacRootSurface::_GetGWorldPixelValue(int whichDepth, long x, long y)
{
    unsigned long retVal = 0;
    unsigned long offscreenPtr = (unsigned long)GetPixBaseAddr(m_RootGWorldPixMap[whichDepth]);
    offscreenPtr += y * ((**m_RootGWorldPixMap[whichDepth]).rowBytes & 0x3fff);
    switch (whichDepth)
    {
	case kEightBitDepth:
	    offscreenPtr += x;
	    retVal = *(unsigned char*)offscreenPtr;
	    break;
	case kSixteenBitDepth:
	    offscreenPtr += 2*x;
	    retVal = *(unsigned short*)offscreenPtr;
	    break;
	case kThirtyTwoBitDepth:
	    offscreenPtr += 4*x;
	    retVal = *(unsigned long*)offscreenPtr;
	    break;
    }
    return retVal;
}

/************************************************************************
 *  Method:
 *    CMacRootSurface::InternalReflectRect
 *
 *    Note that theRectToBlit needs to be in global coords!
 *
 *    This is the function that slams it home. All obscuring menus have
 *    been taken care of. Any vis region holes have been taken care of.
 *    The rectangles that arrive at this rectangle are honest-to-God
 *    blittable rectangles.
 *
 */
void
CMacRootSurface::InternalReflectRect(Rect theRectToBlit)
{
    int whichDevice;
    for (whichDevice = 0; whichDevice < zm_uNumberOfAttachedDevices; whichDevice++)
    {
	HX_ASSERT(zm_AttachedDevice[whichDevice]);
	
	PixMapHandle thePMH = (**zm_AttachedDevice[whichDevice]).gdPMap;
	unsigned char* dstPtr = (unsigned char*)::GetPixBaseAddr(thePMH);
	int pixelSize = (**thePMH).pixelSize;
	
	INT32 whichDepth = DepthToDepthEnum(pixelSize);
	
	if ( 1 /* m_RootSurfaceGWorld[whichDepth] */ ) // <== this may be useful later but for now I want the assert to be executed that's maybe a dozen lines down.
	{
	    Rect deviceRect = (**zm_AttachedDevice[whichDevice]).gdRect;
	    
	    Rect intersectionRect; // <== should always be equal to theRectToBlit I think XXXbobclark
	    if (::SectRect(&theRectToBlit, &deviceRect, &intersectionRect))
	    {
		// XXXbobclark
		// in the old site code we manually trimmed theRectToBlit to the limits of
		// intersectionRect; but since nowadays we're supposedly ensuring that we're
		// only getting rects wholly enclosed by their monitors we shouldn't need
		// to do that. Theoretically the only reason to do SectRect is to see if
		// this is actually the monitor that we need to blit to right now.
		
		
		HX_ASSERT(m_RootSurfaceGWorld[whichDepth]);
		if (!m_RootSurfaceGWorld[whichDepth]) return;
		
		unsigned char* offscreenPtr = (unsigned char*)GetPixBaseAddr(m_RootGWorldPixMap[whichDepth]);
		
		int localLeft = intersectionRect.left - m_LocalToGlobalCoords.h;
		int localTop = intersectionRect.top - m_LocalToGlobalCoords.v;
		int localRight = intersectionRect.right - m_LocalToGlobalCoords.h;
		int localBottom = intersectionRect.bottom - m_LocalToGlobalCoords.v;
		
		int localScreenLeft = intersectionRect.left - (**zm_AttachedDevice[whichDevice]).gdRect.left;
		int localScreenRight = intersectionRect.right - (**zm_AttachedDevice[whichDevice]).gdRect.left;
		int localScreenTop = intersectionRect.top - (**zm_AttachedDevice[whichDevice]).gdRect.top;
		int localScreenBottom = intersectionRect.bottom - (**zm_AttachedDevice[whichDevice]).gdRect.top;
		
		for (int localScreenRow = localScreenTop; localScreenRow < localScreenBottom; localScreenRow++)
		{
		    int bytesPerPixel = pixelSize / 8;
		    if (bytesPerPixel >= 1) // only ITB if at least 8-bit monitor
		    {
			int localRow = (localScreenRow-localScreenTop) + localTop;
			long offscreenOffset = ((**m_RootGWorldPixMap[whichDepth]).rowBytes & 0x3fff) * localRow + localLeft * bytesPerPixel;
			long localScreenOffset = ((**thePMH).rowBytes & 0x3fff) * localScreenRow + localScreenLeft * bytesPerPixel;
			
			long srcP = (long)offscreenPtr + offscreenOffset;
			long dstP = (long)dstPtr + localScreenOffset;
			
			switch (bytesPerPixel)
			{
			    case 4:
				// XXXbobclark
				// now we'll trash srcP and dstP...
				// it turns out that poking longs by hand is a lot faster
				// than going through BlockMoveData for some reason. In a
				// simplified test case, it was using 7-8 microseconds for
				// poking by hand, compared to 17-18 microseconds for using
				// BlockMoveData.
				
				{
                                    long maxP = dstP + (localRight-localLeft) * bytesPerPixel;
                                    for ( ; dstP < maxP; )
                                    {
                                        // if the pixel is lined up on an eight-byte boundary
                                        // and won't overwrite the right edge of the rectangle
                                        // then copy eight bytes at once.
                                        if ( (dstP % 8 == 0) && (maxP - dstP >= 8) )
                                        {
                                            *(double*)dstP = *(double*)srcP;
                                            srcP += 8;
                                            dstP += 8;
                                        }
                                        else
                                        {
                                            *(long*)dstP = *(long*)srcP;
                                            srcP += 4;
                                            dstP += 4;
                                        }
                                    }
                                }
				break;
			    
			    default:
				// XXXbobclark
				// I could do something similar to the 32-bit case here,
				// where I attempt to outdo BlockMoveData()... but for
				// one thing, it would be even clunkier, since I'd need
				// more cases when it doesn't happen to line up on eight-
				// byte boundaries for super-fast copies, plus non-32-bit
				// cases are rarer than 32-bit cases.
				::BlockMoveData( (void*)srcP, (void*)dstP, (localRight-localLeft)*bytesPerPixel );
				break;
			}
		    }
		}
	    }
	}
    }
}


/************************************************************************
 *  Method:
 *    CMacRootSurface::InternalReflectRectInVisRegion
 *
 *    Note that theRectToBlit needs to be in global coords!
 *
 */
void
CMacRootSurface::InternalReflectRectInVisRegion(Rect theRectToBlit)
{
    CHXSimpleList::Iterator ndx = m_pVisRgnRects->Begin();
    for (; ndx != m_pVisRgnRects->End(); ++ndx)
    {
	Rect* r = (Rect*)(*ndx);
	
	Rect blittableRect = theRectToBlit;
	
	if (blittableRect.left < r->left) blittableRect.left = r->left;
	if (blittableRect.top < r->top) blittableRect.top = r->top;
	if (blittableRect.right > r->right) blittableRect.right = r->right;
	if (blittableRect.bottom > r->bottom) blittableRect.bottom = r->bottom;
	
	if (blittableRect.left < blittableRect.right && blittableRect.top < blittableRect.bottom)
	{
	    InternalReflectRect(blittableRect);
	}
    }
}



/************************************************************************
 *  Method:
 *    CMacRootSurface::PotentiallyAddRect
 *
 *    Useful shortcut for constructing lists of rectangles for
 *    menu-down blitting.
 *
 */
void
CMacRootSurface::PotentiallyAddRect( CHXSimpleList* theList, Rect originalVisRect, short left, short top, short right, short bottom )
{
    if ( left < originalVisRect.left ) left = originalVisRect.left;
    if ( top < originalVisRect.top ) top = originalVisRect.top;
    if ( right > originalVisRect.right ) right = originalVisRect.right;
    if ( bottom > originalVisRect.bottom ) bottom = originalVisRect.bottom;
    
    if ( left < right && top < bottom )
    {
	// OK, it's a legal rect so let's add it.
	Rect* r = new Rect;
	r->left = left;
	r->top = top;
	r->right = right;
	r->bottom = bottom;
	theList->AddTail( r );
    }
}


/************************************************************************
 *  Method:
 *    CMacRootSurface::ReflectRectToFullScreen
 *
 *    Note that theOriginalRectToBlit needs to be in global coords!
 *
 */
void
CMacRootSurface::ReflectRectToFullScreen(Rect theOriginalRectToBlit)
{
    // xxxbobclark assumptions include that this rectangle
    // is smaller than the main screen (which is where it
    // assumes the full-screen is playing).
    
    // See InternalReflectRect for details of what up
    
    HX_ASSERT(CHXMacSite::zm_bFullScreenActive);
    
    int whichDevice;
    for (whichDevice = 0; whichDevice < zm_uNumberOfAttachedDevices; whichDevice++)
    {
	PixMapHandle thePMH = (**zm_AttachedDevice[whichDevice]).gdPMap;
	unsigned char* dstPtr = (unsigned char*)::GetPixBaseAddr(thePMH);
	int honestScreenRowBytes = (**thePMH).rowBytes & 0x3fff;
	int pixelSize = (**thePMH).pixelSize;
	
	INT32 whichDepth = DepthToDepthEnum(pixelSize);
	
	if (m_RootSurfaceGWorld[whichDepth])
	{
	    Rect adjustedRect;
	    CHXMacSite* pMacSite = (CHXMacSite*)m_pSite;
	    double stretch = pMacSite->m_fStretchMultiple;
	    
	    adjustedRect.left = theOriginalRectToBlit.left + stretch * (theOriginalRectToBlit.left - m_LocalToGlobalCoords.h);
	    adjustedRect.top = theOriginalRectToBlit.top + stretch * (theOriginalRectToBlit.top - m_LocalToGlobalCoords.v);
	    adjustedRect.right = theOriginalRectToBlit.left + stretch * (theOriginalRectToBlit.right - m_LocalToGlobalCoords.h);
	    adjustedRect.bottom = theOriginalRectToBlit.top + stretch * (theOriginalRectToBlit.bottom - m_LocalToGlobalCoords.v);
	    
	    Rect deviceRect = (**zm_AttachedDevice[whichDevice]).gdRect;
	    if (adjustedRect.left >= deviceRect.left
		&& adjustedRect.top >= deviceRect.top
		&& adjustedRect.right <= deviceRect.right
		&& adjustedRect.bottom <= deviceRect.bottom)
	    {
		// xxxbobclark whew, we can blit here since it's full
		// screen and wholly enclosed.
		
		int bytesPerPixel = pixelSize / 8;
		if (bytesPerPixel < 1) return; // ack, can't handle less than 8-bit!
		
		unsigned char* offscreenPtr = (unsigned char*)GetPixBaseAddr(m_RootGWorldPixMap[whichDepth]);
		int honestOffscreenRowBytes = (**m_RootGWorldPixMap[whichDepth]).rowBytes & 0x3fff;
		
		int fromLeft = theOriginalRectToBlit.left - m_LocalToGlobalCoords.h;
		int fromTop = theOriginalRectToBlit.top - m_LocalToGlobalCoords.v;
		int fromRight = theOriginalRectToBlit.right - m_LocalToGlobalCoords.h;
		int fromBottom = theOriginalRectToBlit.bottom - m_LocalToGlobalCoords.v;
		
		for (int fromRow = fromTop; fromRow < fromBottom; fromRow++)
		{
		    for (int fromColumn = fromLeft; fromColumn < fromRight; fromColumn++)
		    {
			// xxxbobclark OK now here we have one pixel
			// in the offscreen. This could grow to
			// multiple pixels on screen so we'll have to
			// blit all of them.
			
			long* pixelPtr = (long*)((long)offscreenPtr + fromRow*(long)honestOffscreenRowBytes);
			pixelPtr = (long*)((long)pixelPtr + bytesPerPixel * fromColumn);
			
			long pixelValue = *pixelPtr;
			
			// ok, got the pixel value, now figure out where all we
			// need to poke it.
			
			int destLeft = (int)((double)(fromColumn - fromLeft) * stretch + (double)adjustedRect.left);
			int destTop = (int)((double)(fromRow - fromTop) * stretch + (double)adjustedRect.top);
			int destRight = (int)((double)(fromColumn - fromLeft + 1) * stretch + (double)adjustedRect.left);
			int destBottom = (int)((double)(fromRow - fromTop + 1) * stretch + (double)adjustedRect.top);
			
			pixelPtr = (long*)((long)dstPtr + destTop * honestScreenRowBytes);
			pixelPtr = (long*)((long)pixelPtr + bytesPerPixel * destLeft);
			
			for (int destRow = destTop; destRow < destBottom; destRow++)
			{
			    for (int destColumn = destLeft; destColumn < destRight; destColumn++)
			    {
				*pixelPtr = pixelValue;
				
				pixelPtr = (long*)((long)pixelPtr + bytesPerPixel);
			    }
			    pixelPtr = (long*)((long)pixelPtr + honestScreenRowBytes - (bytesPerPixel * (destRight-destLeft)));
			}
		    }
		}
	    }
	}
    }
}


/************************************************************************
 *  Method:
 *    CMacRootSurface::DepthToDepthEnum
 */
int
CMacRootSurface::DepthToDepthEnum( short depth )
{
    int result = kEightBitDepth;
    switch ( depth )
    {
	case 32:
	    result = kThirtyTwoBitDepth;
	    break;
	case 16:
	    result = kSixteenBitDepth;
	    break;
    }
    return result;
}


/************************************************************************
 *  Method:
 *    CMacRootSurface::VisRgnChangedCallback
 *
 *    This is called from several trap patches which can
 *    change the vis region. This prevents subsequent blits
 *    until the vis region we know about can be updated.
 */

/* static */
pascal void
CMacRootSurface::VisRgnChangedCallback(void)
{
#ifndef _MAC_UNIX
    HXMM_INTERRUPTON();
#endif
    // since the visRgn probably changed in the patched trap, let's wait until
    // we can update our version of the visRgn before doing any more interrupt-
    // time blits.
    
    CHXSimpleList::Iterator ndxSite = zm_RootSurfaceList.Begin();

    for (;  ndxSite != zm_RootSurfaceList.End(); ++ndxSite)
    {
	CMacRootSurface* pRootSurface = (CMacRootSurface*)(*ndxSite);
	
	if ( pRootSurface )
	{
	    pRootSurface->m_bItsOKToDoAnInterruptBlit = FALSE;
	}
    }
    
    if (CMacSurface::zm_pOverlaySurface)
    {
	CMacSurface::zm_bSafeToOverlayBlit = FALSE;
    }
#ifndef _MAC_UNIX
    HXMM_INTERRUPTOFF();
#endif
}

#define kSizeOfSimpleRectangleRegion 10

/************************************************************************
 *  Method:
 *    CMacRootSurface::CheckRectRgn
 *
 */

void CMacRootSurface::CheckRectRgn( Rect r, RgnHandle rgn, Point globalOffset )
{
    if ( r.bottom <= r.top || r.right <= r.left || !RectInRgn( &r, rgn ) )
    {
	// if the rect is empty or ain't in the region, bail.
	return;
    }
    
    if ( IsRegionRectangular( rgn ) )
    {
	// since the region is a rectangle, add that rectangle and bail.
	Rect* newRect = new Rect;
	GetRegionBounds(rgn, newRect);
	
	newRect->left += globalOffset.h;
	newRect->top += globalOffset.v;
	newRect->right += globalOffset.h;
	newRect->bottom += globalOffset.v;
	
	m_pVisRgnRects->AddTail( newRect );
	return;
    }
    
    // we've established that it's not clearly defined, so divide and conquer.
    
    Rect newRect1 = r;
    Rect newRect2 = r;
    
    if ( r.bottom - r.top > r.right - r.left )
    {
	// more vertically oriented
	short interimValue = ( r.bottom + r.top ) / 2;
	newRect1.bottom = interimValue;
	newRect2.top = interimValue;
    }
    else
    {
	// more horizontally oriented
	short interimValue = ( r.left + r.right ) / 2;
	newRect1.right = interimValue;
	newRect2.left = interimValue;
    }
    
    RgnHandle newRgn1 = NewRgn();
    RgnHandle newRgn2 = NewRgn();
    
    RectRgn( newRgn1, &newRect1 );
    RectRgn( newRgn2, &newRect2 );
    
    SectRgn( rgn, newRgn1, newRgn1 );
    SectRgn( rgn, newRgn2, newRgn2 );
    
    CheckRectRgn( newRect1, newRgn1, globalOffset );
    CheckRectRgn( newRect2, newRgn2, globalOffset );
    
    DisposeRgn( newRgn1 );
    DisposeRgn( newRgn2 );
}

/************************************************************************
 *  Method:
 *    CMacRootSurface::UpdateRegionIfNecessary
 *
 */

void
CMacRootSurface::UpdateRegionIfNecessary(Rect boundingRect, Point globalOffset, BOOL bForceItToUpdate /* = FALSE */ )
{
#if defined(_CARBON) || defined(_MAC_UNIX)
    return; // xxxbobclark just to keep from crashing???
#else
    HX_ASSERT(!HXMM_ATINTERRUPT());
    
    if (HXMM_ATINTERRUPT()) return;
    
    GrafPtr savePort;
    ::GetPort(&savePort);
    
    WindowPtr macWindow = m_pSite->GetWindow() ? (WindowPtr)m_pSite->GetWindow()->window : NULL;

    if (CHXMacSite::zm_bFullScreenActive)
    {
	CHXMacSite* pMacSite = (CHXMacSite*)m_pSite;
	if (pMacSite->m_pHXxFullScreenWindow)
	{
	    macWindow = (WindowPtr)pMacSite->m_pHXxFullScreenWindow->window;
	}
    }

    HX_ASSERT(macWindow);
    
    if (!macWindow) return;
    
#if defined(_CARBON) || defined(_MAC_UNIX)
    ::SetPort( GetWindowPort( macWindow ) );
#else
    ::SetPort(macWindow);
#endif
    
    RgnHandle theClippedVisRgn = ::NewRgn();
#if defined(_CARBON) || defined(_MAC_UNIX)
    RgnHandle visRgn = ::NewRgn();
    ::GetPortVisibleRegion( GetWindowPort(macWindow), visRgn );
    RgnHandle clipRgn = ::NewRgn();
    ::GetPortClipRegion( GetWindowPort(macWindow), clipRgn );
    ::SectRgn( visRgn, clipRgn, theClippedVisRgn );
    ::DisposeRgn( clipRgn );
    ::DisposeRgn( visRgn );
#else
    ::SectRgn( macWindow->visRgn, macWindow->clipRgn, theClippedVisRgn );
#endif
    
    // first, dispose and null out m_LastVisRgn if necessary (or forced)
    if ( m_LastVisRgn && ( bForceItToUpdate || !::EqualRgn(theClippedVisRgn, m_LastVisRgn) ) )
    {
	::DisposeRgn(m_LastVisRgn);
	m_LastVisRgn = NULL;
    }
    
    if (!m_LastVisRgn)
    {
	m_LastVisRgn = ::NewRgn();
	
	::CopyRgn(theClippedVisRgn, m_LastVisRgn);
	RgnHandle interimRgn = ::NewRgn();
	::RectRgn(interimRgn, &boundingRect);
	::SectRgn(m_LastVisRgn, interimRgn, interimRgn);
	
	while (m_pVisRgnRects->GetCount())
	{
	    Rect* r = (Rect*)m_pVisRgnRects->RemoveHead();
	    delete r;
	}
	CheckRectRgn(boundingRect, interimRgn, globalOffset);
//	RegionToRectsByNoodlingThroughRegion(interimRgn, globalOffset, m_VisRgnRects);
	::DisposeRgn(interimRgn);
    }
    
    ::DisposeRgn(theClippedVisRgn);
    
    ::SetPort(savePort);
#endif
}




/************************************************************************
 *  Method:
 *    CMacRootSurface::_PreFlightBlt
 *
 *    This is called AFTER the current sub-rectangle has been determined,
 *    but BEFORE any assumptions about screen depth or anything have been
 *    made. Basically this is where I can hijack the cross-platform code's
 *    assumptions and surreptitiously slide in an appropriate
 *    m_pCompositionSurface and other variables.
 *
 */

void
CMacRootSurface::_PreFlightBlt(HXxRect& dst)
{
    if (!m_bItsOKToDoAnInterruptBlit) return;
    
    m_pCompositionSurface = nil;
    m_nBlitDepthEnum = -1;
    
    Rect r;
    r.left = dst.left + m_LocalToGlobalCoords.h;
    r.top = dst.top + m_LocalToGlobalCoords.v;
    r.right = dst.right + m_LocalToGlobalCoords.h;
    r.bottom = dst.bottom + m_LocalToGlobalCoords.v;
    
#ifdef USE_LOW_LEVEL_QT_API
    int i = zm_uNumberOfAttachedDevices;
#else
    for (int i = 0; i < zm_uNumberOfAttachedDevices; i++)
#endif
    {
	Rect intersectionRect;
	
	if ((i == zm_uNumberOfAttachedDevices) || (::SectRect(&r, &(**zm_AttachedDevice[i]).gdRect, &intersectionRect)))
	{
	    // now figure out which GWorld we need to use.
	    
	    // XXXbobclark I'm starting out with a copy-n-paste of
	    // _CreateCompositionSurface(). Ewww. But the problem is that
	    // we don't know -- until now -- which depths and therefore
	    // which GWorlds we need. Dayum. ...And what makes it worse is
	    // that it might be interrupt time before stuff's created. That
	    // will be a weird circumstance -- and one where the blit won't
	    // actually succeed -- but it might screw things up in the
	    // meantime, like if it tries to blit into the NULL composition
	    // surface. Crash. So maybe if it fails everywhere else I'll
	    // force the composition surface to be the 32-bit one that's
	    // created in _CreateCompositionSurface just so the color
	    // converter has SOMETHING to blit into even though it will
	    // subsequently get ignored. Shee-it.
	    
	    // All (potentially three) offscreens will be full-sized. This
	    // could be a "waste" of memory, but solving it is excruciatingly
	    // subtle and has many tendrils, such as telling the color converter
	    // to convert into non 0,0-based rectangles, yeesh. The good news
	    // -- and an improvement over the older site code -- is that it
	    // only color-converts into the parts of the offscreen that
	    // eventually gets blitted to screen. So there's not a lot of
	    // wasted color conversion.
	    
	    PixMapHandle thePMH = NULL;
	    int pixelSize = 0;
	    INT32 whichDepth;
	    
#ifdef USE_LOW_LEVEL_QT_API
	    if (i == zm_uNumberOfAttachedDevices)
	    {
		whichDepth = kYUVDepth;
	    }
	    else
#endif
	    {
		thePMH = (**zm_AttachedDevice[i]).gdPMap;
		pixelSize = (**thePMH).pixelSize;
		whichDepth = DepthToDepthEnum(pixelSize);
	    }

	    if (m_RootSurfaceGWorld[whichDepth])
	    {
		// now see if it needs to be reinitialized.
		
		Rect thePortRect;
#if defined(_CARBON) || defined(_MAC_UNIX)
		GetPortBounds(m_RootSurfaceGWorld[whichDepth], &thePortRect);
#else
		thePortRect = m_RootSurfaceGWorld[whichDepth]->portRect;
#endif
		
		BOOL bNeedToRecreate = FALSE;
		
		if (m_compositionSize.cx > thePortRect.right - thePortRect.left) bNeedToRecreate = TRUE;
		if (m_compositionSize.cy > thePortRect.bottom - thePortRect.top) bNeedToRecreate = TRUE;
		
#ifdef USE_LOW_LEVEL_QT_API
		if (whichDepth == kYUVDepth)
		{
		    // xxxbobclark if it's using YUV then the QT calls assume that the whole
		    // GWorld is being used, so using just the upper-left portion
		    // doesn't work.
		    if (m_compositionSize.cx != thePortRect.right-thePortRect.left) bNeedToRecreate = TRUE;
		    if (m_compositionSize.cy != thePortRect.bottom-thePortRect.top) bNeedToRecreate = TRUE;
		}
#endif
		
		if (bNeedToRecreate)
		{
		    ::UnlockPixels(m_RootGWorldPixMap[whichDepth]);
		    ::DisposeGWorld(m_RootSurfaceGWorld[whichDepth]);
		    m_RootSurfaceGWorld[whichDepth] = nil;
		    m_RootGWorldPixMap[whichDepth] = nil;
		}
	    }
	    
	    if (!m_RootSurfaceGWorld[whichDepth])
	    {
		// need to (re)create it
		
		Rect r;
		::SetRect(&r, 0, 0, m_compositionSize.cx, m_compositionSize.cy);
		
#ifdef USE_LOW_LEVEL_QT_API

		if (whichDepth == kYUVDepth)
		{
		    ::QTNewGWorld(&m_RootSurfaceGWorld[whichDepth], 'yuvs', &r, nil, nil, useTempMem | 16 | 32);
		    if (!m_RootSurfaceGWorld[whichDepth])
		    {
			::QTNewGWorld(&m_RootSurfaceGWorld[whichDepth], 'yuvs', &r, nil, nil, useTempMem | 32);
		    }
		    if (!m_RootSurfaceGWorld[whichDepth])
		    {
			::QTNewGWorld(&m_RootSurfaceGWorld[whichDepth], 'yuvs', &r, nil, nil, useTempMem | 16);
		    }
		    if (!m_RootSurfaceGWorld[whichDepth])
		    {
			::QTNewGWorld(&m_RootSurfaceGWorld[whichDepth], 'yuvs', &r, nil, nil, 16 | 32);
		    }
		    if (!m_RootSurfaceGWorld[whichDepth])
		    {
			::QTNewGWorld(&m_RootSurfaceGWorld[whichDepth], 'yuvs', &r, nil, nil, 32);
		    }
		    if (!m_RootSurfaceGWorld[whichDepth])
		    {
			::QTNewGWorld(&m_RootSurfaceGWorld[whichDepth], 'yuvs', &r, nil, nil, 16);
		    }
		    if (!m_RootSurfaceGWorld[whichDepth])
		    {
			::QTNewGWorld(&m_RootSurfaceGWorld[whichDepth], 'yuvs', &r, nil, nil, useTempMem);
		    }
		    if (!m_RootSurfaceGWorld[whichDepth])
		    {
			return;
		    }
		}
		else
#endif

		{
		    ::NewGWorld(&m_RootSurfaceGWorld[whichDepth], pixelSize, &r, nil, nil, useTempMem);
		    if (!m_RootSurfaceGWorld[whichDepth])
		    {
			::NewGWorld(&m_RootSurfaceGWorld[whichDepth], pixelSize, &r, nil, nil, 0);

			if (!m_RootSurfaceGWorld[whichDepth]) return;
		    }
		}
		
#if defined(_CARBON) || defined(_MAC_UNIX)
		m_RootGWorldPixMap[whichDepth] = GetPortPixMap(m_RootSurfaceGWorld[whichDepth]);
#else
		m_RootGWorldPixMap[whichDepth] = m_RootSurfaceGWorld[whichDepth]->portPixMap;
#endif
		::LockPixels(m_RootGWorldPixMap[whichDepth]);
		
	    }
	    
	    // OK now the offscreen stuff should all be reinitialized if
	    // it came to that... in any case we're now ready to do the
	    // actual work? nah... kludgey? nah... surreptitious! stuff.
	    
	    if (m_RootSurfaceGWorld[whichDepth] && m_RootGWorldPixMap[whichDepth])
	    {
		m_pCompositionSurface = (unsigned char*)::GetPixBaseAddr(m_RootGWorldPixMap[whichDepth]);
		m_nBlitDepthEnum = whichDepth;
		Rect hold;
#if defined(_CARBON) || defined(_MAC_UNIX)
		GetPortBounds(m_RootSurfaceGWorld[whichDepth], &hold);
#else
		hold = m_RootSurfaceGWorld[whichDepth]->portRect;
#endif
		m_allocatedCompositionSize.cx = hold.right-hold.left;
		m_allocatedCompositionSize.cy = hold.bottom-hold.top;
		m_nCompositionPitch = (**m_RootGWorldPixMap[whichDepth]).rowBytes & 0x3fff;
		m_boundsRect.left = 0;
		m_boundsRect.top = 0;
		m_boundsRect.right = m_allocatedCompositionSize.cx;
		m_boundsRect.bottom = m_allocatedCompositionSize.cy;
		
		switch (whichDepth)
		{
		    case kThirtyTwoBitDepth:
			m_nCompositionSurfaceCID = CID_RGB32;
			break;
			
		    case kSixteenBitDepth:
			m_nCompositionSurfaceCID = CID_RGB555;
			break;
			
#ifdef USE_LOW_LEVEL_QT_API
		    case kYUVDepth:
			m_nCompositionSurfaceCID = CID_YUY2;
			break;
#endif

		    default:
			m_nCompositionSurfaceCID = CID_RGB8;
			break;
		}
	    }
	}
    }
    
    if (!m_pCompositionSurface)
    {
	// this is possible if we're at interrupt time and we're trying to
	// blit to bad places.
	if (m_RootSurfaceGWorld[kThirtyTwoBitDepth] && m_RootGWorldPixMap[kThirtyTwoBitDepth])
	{
	    m_pCompositionSurface = (unsigned char*)GetPixBaseAddr(m_RootGWorldPixMap[kThirtyTwoBitDepth]);
	    m_nBlitDepthEnum = kThirtyTwoBitDepth;

	    m_nCompositionPitch = (**m_RootGWorldPixMap[kThirtyTwoBitDepth]).rowBytes & 0x3fff;

	    m_boundsRect.left = 0;
	    m_boundsRect.top = 0;
	    m_boundsRect.right = m_compositionSize.cx;
	    m_boundsRect.bottom = m_compositionSize.cy;

	    m_nCompositionSurfaceCID = CID_RGB32;
	    
	}
    }
}


/************************************************************************
 *  Method:
 *    CMacRootSurface::_GetNumberOfMonitors
 *
 */

UINT32 CMacRootSurface::_GetNumberOfMonitors()
{
    return zm_uNumberOfAttachedDevices;
}


/************************************************************************
 *  Method:
 *    CMacRootSurface::_RectOnNthMonitor
 *
 */

BOOL CMacRootSurface::_RectOnNthMonitor(HXxRect rect, UINT32 uMonitor, HXxRect& intersectRect)
{
    HX_ASSERT(uMonitor < zm_uNumberOfAttachedDevices);
    
    if (/*It's using an overlay*/1)
    {
	if (uMonitor == 0)
	{
	    intersectRect = rect;
	    return TRUE;
	}
	else
	{
	    return FALSE;
	}
    }
    
    if (!m_bItsOKToDoAnInterruptBlit)
    {
	// XXXbobclark well, um, the thing is, if it's at interrupt time
	// we'll bail out this instant; if it's at system time that means
	// we can probably pass through a (possibly bogus) rectangle so
	// the code in _MinimalBlt() catches it and can set m_bItsOKToAn-
	// InterruptBlit to true.
	
	intersectRect = rect;
	return TRUE;
    }
    
    Rect r;
    r.left = rect.left + m_LocalToGlobalCoords.h;
    r.top = rect.top + m_LocalToGlobalCoords.v;
    r.right = rect.right + m_LocalToGlobalCoords.h;
    r.bottom = rect.bottom + m_LocalToGlobalCoords.v;
    
    Rect intR;
    if (::SectRect(&r, &(**zm_AttachedDevice[uMonitor]).gdRect, &intR))
    {
	intersectRect.left = intR.left - m_LocalToGlobalCoords.h;
	intersectRect.top = intR.top - m_LocalToGlobalCoords.v;
	intersectRect.right = intR.right - m_LocalToGlobalCoords.h;
	intersectRect.bottom = intR.bottom - m_LocalToGlobalCoords.v;

	return TRUE;
    }
    return FALSE;
}
