/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: winsite.cpp,v 1.4.34.2 2004/07/26 08:59:45 pankajgupta 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 "ihxpckts.h"
#include "hxwin.h"
#include "hxengin.h"
#include "hxsite2.h"
#include "hxevent.h"
#include "hxcomm.h"
#include "hxstrutl.h"

#include "hxvsurf.h"
#include "basesite.h"
#include "winsite.h"
//#include "hxwinver.h"
#include "diballoc.h"

#include "ihxpckts.h"
#include "hxprefs.h"
#include "hxtick.h"
#include "sitetext.h"
#include "hxcore.h"
#include "hxthread.h"

#include "hxheap.h"
#include "basesurf.h"
#include "mmx_util.h"

#include "colormap.h"

#ifdef _DEBUG
#undef HX_THIS_FILE
static const char HX_THIS_FILE[] = __FILE__;
#endif

#define MODE_SEPERATOR                          "|"
#define REGKEY_FULLSCREEN_DATA                  "FullScreenData"
#define REGKEY_FULLSCREEN_TEST_MODES            "TestModes"
#define REGKEY_FULLSCREEN_PREFERED_MODE         "PreferedMode"
#define TEST_THRESHOLD                          30
#define REGKEY_FULLSCREEN_POSTAGE_STAMP         "PostageStamp"
#define TEST_LENGTH                             6000

// These SPI_ flags are not defined in header files with MSDEV 5.0, so
// that is why these are needed.  These can be removed when we compile
// with a newer version of the compiler
#ifndef SPI_GETFOREGROUNDLOCKTIMEOUT
#define SPI_GETFOREGROUNDLOCKTIMEOUT 0x2000
#endif /* SPI_GETFOREGROUNDLOCKTIMEOUT */

#ifndef SPI_SETFOREGROUNDLOCKTIMEOUT
#define SPI_SETFOREGROUNDLOCKTIMEOUT 0x2001
#endif /* SPI_SETFOREGROUNDLOCKTIMEOUT */


#define NO_HOOK_FOUND_RETURNING_WITH_ZERO 0
CHXMapPtrToPtr      CHXWinSite::zm_ParentWnds;
CHXMapPtrToPtr      CHXWinSite::zm_ParentsThreadList;
CHXMapPtrToPtr      CHXWinSite::zm_SubclassedWnds;
CHXMapPtrToPtr      CHXWinSite::zm_ScrollBarWnds;
CHXMapPtrToPtr      CHXWinSite::zm_ListOfHiddenWindows;
char*               CHXWinSite::zm_pszWindowClassName       = "HXWinVideoClass";
char*               CHXWinSite::zm_pszWindowName            = "HXWinVideoWindow";
INT32               CHXWinSite::zm_nInstanceCount           = 0;

BOOL g_bPrintSiteData = FALSE;


// convert from HXxPoint pt to Windows POINT
POINT WINPOINT(HXxPoint pt)
{
    POINT winPt;

    winPt.x = pt.x;
    winPt.y = pt.y;

    return winPt;
}

BOOL CALLBACK HXxRemoveWindows( HWND hwnd, LPARAM lParam)
{
    void* This;
    BOOL bVisible;

    if (!CHXWinSite::zm_SubclassedWnds.Lookup((void*)hwnd,This))
    {
        bVisible = IsWindowVisible(hwnd);
        if (bVisible)
        {
            CHXWinSite::zm_ListOfHiddenWindows.SetAt(hwnd, hwnd);
            ::ShowWindow(hwnd, SW_HIDE);
        }
    }

    return TRUE;
}


/************************************************************************
 *  Method:
 *    Constructor
 */
CHXWinSite::CHXWinSite(IUnknown* pContext, IUnknown* pUnkOuter, INT32 lZorder)
    : CHXBaseSite(pContext, pUnkOuter, lZorder)
    , m_oldWndProc(NULL)
    , m_hXSlider(NULL)
    , m_hYSlider(NULL)
    , m_windowParent(NULL)
    , m_pContainingWindow(NULL)
{
    InitializeCriticalSection(&m_CriticalSection);
    m_ulSiteThreadID = GetCurrentThreadId();
}


/************************************************************************
 *  Method:
 *    Destructor
 */
CHXWinSite::~CHXWinSite()
{
    DeleteCriticalSection(&m_CriticalSection);
    UnHookParents();
}

void
CHXWinSite::_NeedWindowedSite()
{
    UINT32 ulFlags = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
    if (m_bIsVisible)
    {
        ulFlags |= WS_VISIBLE;
    }

    if (m_pTopLevelSite && m_pTopLevelSite->m_pWindow)
    {
        Create(m_pTopLevelSite->m_pWindow->window, ulFlags);
    }
}

/************************************************************************
 *  Method:
 *    IHXSiteWindowed::Create
 */
void*
CHXWinSite::_Create(void* ParentWindow, UINT32 style)
{
/*
 * Make sure the window class is registered.
 */

    RegisterClass();

    HWND hWnd = CreateWindowEx(NULL,
                               zm_pszWindowClassName,
                               zm_pszWindowName,
                               style,
                               0,
                               0,
                               0,
                               0,
                               (HWND)ParentWindow,
                               NULL,
                               GetModuleHandle(NULL),
                               NULL);

    return hWnd;
}

/************************************************************************
 *  Method:
 *    IHXSiteWindowed::Destroy
 */
void
CHXWinSite::_Destroy(HXxWindow* pWindow)
{
    BOOL retVal = ::DestroyWindow((HWND) pWindow->window);
    UnRegisterClass();
}

/************************************************************************
 *  Method:
 *    CHXBaseSite::AttachWindow
 */
void
CHXWinSite::_AttachWindow()
{
    HX_ASSERT(GetWindow() && GetWindow()->window);

    m_oldWndProc = (WNDPROC)::GetWindowLong((HWND)GetWindow()->window, GWL_WNDPROC);
    ::SetWindowLong((HWND)GetWindow()->window, GWL_WNDPROC,(DWORD)HXxWinHookSiteProc);
    zm_SubclassedWnds.SetAt(GetWindow()->window,this);

    if (!m_pParentSite)
    {
        HookParents();
    }
}


/************************************************************************
 *  Method:
 *    IHXSiteWindowed::DetachWindow
 */
void CHXWinSite::_DetachWindow()
{
    ::SetWindowLong((HWND)GetWindow()->window, GWL_WNDPROC,(DWORD)m_oldWndProc);
    zm_SubclassedWnds.RemoveKey(GetWindow()->window);

    UnHookParents();
    m_oldWndProc = NULL;
}

/************************************************************************
 *  Function:
 *    CHXWinSiteWindowedProc
 */
LRESULT HXEXPORT CHXWinSiteWindowedProc
(
    HWND hWnd,
    UINT message,
    WPARAM uParam,
    LPARAM lParam
    )
{
    return (DefWindowProc(hWnd, message, uParam, lParam));
}


/************************************************************************
 *  Function:
 *    RegisterClass
 */
void
CHXWinSite::RegisterClass()
{
    if (0 == zm_nInstanceCount)
    {
        WNDCLASS wndClass;
        ATOM result;

        wndClass.style = 0;
        wndClass.lpfnWndProc = CHXWinSiteWindowedProc;
        wndClass.cbClsExtra = 0;
        wndClass.cbWndExtra = 0;
        wndClass.hInstance = GetModuleHandle(NULL);
        wndClass.hIcon = NULL;
        wndClass.hCursor = NULL;
        wndClass.hbrBackground = NULL;
        wndClass.lpszMenuName = NULL;
        wndClass.lpszClassName = zm_pszWindowClassName;

        result = ::RegisterClass(&wndClass);
        HX_ASSERT(result);
    }
    zm_nInstanceCount++;
}

/************************************************************************
 *  Function:
 *    UnRegisterClass
 */
void
CHXWinSite::UnRegisterClass()
{
    HX_ASSERT(zm_nInstanceCount > 0);

    if (zm_nInstanceCount > 0)
    {
        zm_nInstanceCount--;
    }

    if (0 == zm_nInstanceCount)
    {
        BOOL result = ::UnregisterClass(zm_pszWindowClassName,GetModuleHandle(NULL));
        HX_ASSERT(result);
    }
}

void CHXWinSite::HookParents()
{
    HWND hWnd = (HWND)GetWindow()->window;

    DWORD process = 0;

    while (hWnd)
    {
        int thread = GetWindowThreadProcessId(hWnd, &process);
        CParentWindowThreadData* pData = NULL;
        int threadRefCount = 0;

        if (!CHXWinSite::zm_ParentsThreadList.Lookup((void*)thread, (void*&) pData))
        {
            pData = new CParentWindowThreadData();
            pData->m_hHook              = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)HXxWinHookChar, NULL, thread);
            pData->m_hHookAllMessage    = SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC)HXxWinHookAllMessages, NULL, thread);
            CHXWinSite::zm_ParentsThreadList.SetAt((void*)thread, (void*)pData);
        }

        /*
         *  Don't I wish I could keep a simple RefCount. The problem with that
         *  would be if ANY of these parent poped out of the chain (a possiblility)
         *  then we would not remove the hook. And you know what happens if we
         *  do not remove the hook ... boom *crash IE*. And people do not like that.
         */

        if (!pData->m_ListOfTopLevelSites.Find(m_pTopLevelSite))
        {
            pData->m_ListOfTopLevelSites.AddTail(m_pTopLevelSite);
        }

        CHXSimpleList* pChildrenList;
        if (!CHXWinSite::zm_ParentWnds.Lookup((void*)hWnd,(void*&) pChildrenList))
        {
            pChildrenList = new CHXSimpleList;
            CHXWinSite::zm_ParentWnds.SetAt((void*)hWnd, (void*)pChildrenList);
        }

        LISTPOSITION pos = pChildrenList->Find(this);
        HX_ASSERT(pos == NULL);
        if (!pos)
        {
            pChildrenList->AddTail(this);
        }
        hWnd = GetParent(hWnd);
    }
}

void
CHXWinSite::UnHookParents()
{
/*
 * make sure to remove any reference to this object from the parent map.
 * We do not use Getparent calls here since the parent chain may have
 * changed AFTER call to HookParents().
 *
 */
    HWND hWnd;
    CHXSimpleList* pChildrenList;
    POSITION pos = zm_ParentWnds.GetStartPosition();
    while (pos)
    {
        zm_ParentWnds.GetNextAssoc(pos, (void*&) hWnd, (void*&) pChildrenList);
        LISTPOSITION listpos = pChildrenList->Find(this);

        if (listpos)
        {
            pChildrenList->RemoveAt(listpos);

            if (!pChildrenList->GetCount())
            {
                pos = CHXWinSite::zm_ParentWnds.Remove((void*)hWnd);
                HX_DELETE(pChildrenList);
            }
        }
    }

    /* are we a top level site? If so we may have to clean up
     * some of our Window Hooks.
     */

    if (m_pTopLevelSite == this)
    {
        DWORD thread;
        CParentWindowThreadData* pData = NULL;
        POSITION pos = zm_ParentsThreadList.GetStartPosition();
        while (pos)
        {
            zm_ParentsThreadList.GetNextAssoc(pos, (void*&) thread, (void*&) pData);
            LISTPOSITION listpos = pData->m_ListOfTopLevelSites.Find(this);

            if (listpos)
            {
                pData->m_ListOfTopLevelSites.RemoveAt(listpos);

                if (!pData->m_ListOfTopLevelSites.GetCount())
                {
                    UnhookWindowsHookEx(pData->m_hHook);
                    UnhookWindowsHookEx(pData->m_hHookAllMessage);
                    pos = CHXWinSite::zm_ParentsThreadList.Remove((void*)thread);

                    delete pData;
                }
            }
        }
    }

}

void
CHXWinSite::_SetSize(HXxSize size)
{
    // generate an OS event
    HX_ASSERT(m_pWindow && m_pWindow->window);
    /*
     * Change the size of the window using platform specific calls.
     * Note: the size being requested is the "client" size for the
     * window, so we need to actually determine the outer rect size.
     * We do this by getting the current window rect and client rect,
     * the difference is the "extra" size associated with any window
     * dressing.
     */
    HWND tempHwnd = (HWND) GetWindow()->window;
    RECT rect1;
    ::GetWindowRect(tempHwnd,&rect1);
    MapWindowPoints(NULL, GetParent(tempHwnd), (POINT*)&rect1, 2);
    SafeMoveWindow( tempHwnd,
                    (int)rect1.left, (int)rect1.top,
                    (int)size.cx, (int)size.cy,
                    m_bIsVisible);
}

void CHXWinSite::_SetPosition(HXxPoint position)
{
    //Since I just flattened the window structure this function has to
    //me modified to take that into account.
    if(m_pWindow->window && !m_bWindowCreatedByCreate)
    {
        SafeMoveWindow((HWND)m_pWindow->window,
                       (int)m_topleft.x,
                       (int)m_topleft.y,
                       (int)m_size.cx ,
                       (int)m_size.cy ,
                       m_bIsVisible);
    }
    else
    {
        SafeMoveWindow((HWND) GetWindow()->window,
                       (int)position.x,
                       (int)position.y,
                       (int)m_size.cx ,
                       (int)m_size.cy ,
                       m_bIsVisible);
    }
}

void CHXWinSite::_DamageRect(HXxRect rect)
{
//     if (m_pVideoSurface && m_pVideoSurface->m_nBltMode == HX_OVERLAY_BLT)
//     {
//         return;
//     }

//     // We need to tell the os that we are modifing the video window.
//     // The mechanism for doing this is to call invaliadteRect, and
//     // then to respond to the WM_PAINT. Of course we are going to
//     // respond to the 'WM_PAINT' before we get the WM_PAINT by the
//     // renderer calling forceRedraw. Thus, we will remember the rect
//     // and see if it bounds the PaintStruct we get in our subsequent
//     // paint. If so then we will ignore it. While this is not the
//     // optimal solution, we have little choice due to dead locking
//     // issues.
//     HXxWindow* pwindow = GetWindow();

//     if(pwindow && pwindow->window)
//     {
//         RECT overAllrect;
//         HDC hdc = ::GetDC((HWND)pwindow->window);

//         int retVal = ::GetClipBox(hdc, &overAllrect);
//         ::IntersectRect( (RECT*)&rect, (RECT*)&rect, &overAllrect );

//         if (retVal != NULLREGION)
//         {
//             //If any of a set of test points is not visible, then we
//             //will assume there is a drop down menu over us and invalidate
//             //it.
//             //XXXgfw Currect test points will be four corners and center point.
//             BOOL bVisible = TRUE;
//             int  middleY  = rect.top+(rect.bottom-rect.top)/2;
//             int  middleX  = rect.left+(rect.right-rect.left)/2;

//             bVisible = bVisible && ::PtVisible( hdc, rect.left,    rect.top);
//             bVisible = bVisible && ::PtVisible( hdc, rect.right-1, rect.top);
//             bVisible = bVisible && ::PtVisible( hdc, rect.left,    rect.bottom-1);
//             bVisible = bVisible && ::PtVisible( hdc, rect.right-1, rect.bottom-1);
//             bVisible = bVisible && ::PtVisible( hdc, middleX,      middleY );

//             //XXXgfw We are still getting artifacts from drop down
//             //menus that go too fast. Guess we have to invalidate our
//             //whole window.
//             if( !bVisible )
//             {
//                 ::InvalidateRect((HWND)pwindow->window, (RECT*)NULL, FALSE);
//             }
//         }
//         ReleaseDC((HWND)pwindow->window, hdc);
//     }
}

BOOL CHXWinSite::_ShouldEnterForceRedraw()
{
    if (InterlockedIncrement(&m_lBltEntryCount) > 1)
    {
        InterlockedDecrement(&m_lBltEntryCount);
        return FALSE;
    }

    return TRUE;
}

void
CHXWinSite::_ExitForceRedraw()
{
    InterlockedDecrement(&m_lBltEntryCount);
}

void
CHXWinSite::_SendOSUpdateMessage()
{
    InvalidateRect((HWND) GetWindow()->window, NULL, FALSE);
    SafeUpdateWindow((HWND) GetWindow()->window);
}

void
CHXWinSite::_ShowSite(BOOL bShow)
{
    if( m_pWindow && m_pWindow->window)
    {
        SafeShowWindow((HWND)m_pWindow->window, bShow ? SW_SHOW : SW_HIDE);
    }
}

BOOL
CHXWinSite::_AtSystemTime()
{
    return (m_ulSiteThreadID == GetCurrentThreadId());
}

BOOL
CHXWinSite::_HandleOSEvents(HXxEvent* /*IN*/ pEvent)
{
    BOOL ret = FALSE;
    switch (pEvent->event)
    {
       case WM_NCHITTEST:
           if (m_pTopLevelSite->m_bSetCaptureOn)
           {
               if( m_pTopLevelSite->m_pCaptureUser )
                   m_pTopLevelSite->m_pCaptureUser->HandleEvent(pEvent);
           }
           ret = TRUE;
           break;
       case WM_CHAR:
       case WM_KEYDOWN:
       case WM_KEYUP:
       {
           //Check to see if focus has been set if so send the message
           //only to that window.

           //XXXgfw, we need to revisit this idea of a focus site.
           //with this code added only the site that was last clicked
           //gets the native event. No children, no nothing. The user
           //is bound to click a site at random just to bring the player
           //to the top of the window stack for example...
//           CHXBaseSite* pFocusSite;
//           pFocusSite = m_pTopLevelSite->GetFocusSite();
//           if (pFocusSite)
//           {
//              if (pFocusSite == this)
//              {
//                 // we have already called HandleEvent on the original
//                 // user in HandleWndProc
//                 if (pEvent->window != GetWindow()->window)
//                 {
//                    m_pUser->HandleEvent(pEvent);
//                 }
//                 else
//                 {
//                    goto cleanup;
//                 }
//              }
//              else
//              {
//                 pFocusSite->EventOccurred(pEvent);
//              }
//           }
//           else
       {
           //Tell our user that the event has occured.
           if (m_pUser)
               m_pUser->HandleEvent(pEvent);

           if( !pEvent->handled )
           {
             mapchanged1:
               int mapCount = m_ChildrenMap.GetCount();
               CHXMapPtrToPtr::Iterator i = m_ChildrenMap.Begin();
               while( i!= m_ChildrenMap.End() && !pEvent->handled)
               {
                   CHXWinSite* pSite = (CHXWinSite*) *i;
                   pSite->EventOccurred(pEvent);

                   //wow. :-(
                   if (m_ChildrenMap.GetCount() != mapCount)
                   {
                       goto mapchanged1;
                   }
                   ++i;
               }
           }
       }

       //We always convert the event to an generic event now.
       //If we don't we don't get generic events....
       ret = FALSE;
       break;
       }
    }
//  cleanup:
    return ret;
}

//XXXgfw, remove this if we end up not using it after release.
void CHXWinSite::_SizeSliders()
{
}

/************************************************************************
 *  Function:
 *    HXxWinHookSiteProc
 *
 */
LRESULT HXEXPORT
HXxWinHookSiteProc
(
    HWND hWnd,
    UINT message,
    WPARAM uParam,
    LPARAM lParam
    )
{
    LRESULT             lResult = 0;
    CHXWinSite* pThis = 0;

    CHXWinSite::zm_SubclassedWnds.Lookup((void*)hWnd,(void*&)pThis);

    if (!pThis)
    {
        HX_ASSERT(0);
        return DefWindowProc(hWnd, message, uParam, lParam);
    }

    if (pThis->HandleWndProc(hWnd,message,uParam,lParam,lResult))
    {
        return (lResult);
    }

    return CallWindowProc(pThis->m_oldWndProc, hWnd, message, uParam, lParam);
}


/************************************************************************
 *  Function:
 *    HXxWinHookChar
 *
 */
//LRESULT HXEXPORT
LRESULT CALLBACK
HXxWinHookChar(int nCode,WPARAM wParam,LPARAM lParam)
{
    if (nCode <0 || nCode != HC_NOREMOVE)
    {
        int isKeyDown = (KF_UP & lParam);

        if (!isKeyDown)
        {
            LRESULT             lResult = 0;
            CHXWinSite* pThis;

            CHXMapPtrToPtr::Iterator i = CHXWinSite::zm_SubclassedWnds.Begin();

            for(;i!= CHXWinSite::zm_SubclassedWnds.End(); ++i)
            {
                pThis = (CHXWinSite*) *i;
                if (pThis->IsFullScreen())
                {
                    if (pThis->HandleWndProc((HWND)i.get_key(),WM_CHAR,wParam,lParam,lResult))
                    {
                        return (lResult);
                    }
                }
            }
        }
    }

    /*
     *  Sweet Jesus. They do not give us a window handle. Ok. Call GetCurrentThreadId.
     */

    DWORD id = GetCurrentThreadId();
    CParentWindowThreadData* pData = NULL;

    if (CHXWinSite::zm_ParentsThreadList.Lookup((void*)id, (void*&) pData))
    {
        return CallNextHookEx(pData->m_hHook,nCode,wParam,lParam);
    }

    /*
     *  If we get here we are in some SERIOUS hurt.
     */

    HX_ASSERT(NO_HOOK_FOUND_RETURNING_WITH_ZERO);
    return 0;
}

/************************************************************************
 *  Function:
 *    WinDrawHelperCallWndProc
 */
LRESULT HXEXPORT
HXxWinHookAllMessages
(
    int        nCode,
    WPARAM  wParam,
    LPARAM  lParam
    )
{

    CWPSTRUCT*  pCWPStruct  = (CWPSTRUCT*)lParam;
    HWND        hWnd        = pCWPStruct->hwnd;
    UINT        message     = pCWPStruct->message;

    /*
     * We watch for movement of the topmost parent of any of our
     * windraw objects, and if so then we tell windraw to update
     * the frame for those windraw objects. Outter check is for
     * the message in question so that we don't waste too much time.
     */
    const UINT msgMoving        = WM_MOVING;
    const UINT msgPosChanging   = WM_WINDOWPOSCHANGING;

    /*
     *  If I see any reason to use these other messages in the future
     *   message == WM_MOVING || message == WM_WINDOWPOSCHANGING
     */
    if (message == WM_MOVE)
    {
        CHXSimpleList* pChildrenList;
        if (CHXWinSite::zm_ParentWnds.Lookup((void*)hWnd,(void*&)pChildrenList))
        {
            CHXSimpleList::Iterator i = pChildrenList->Begin();
            for(; i!= pChildrenList->End(); ++i)
            {
                CHXWinSite* pSite = (CHXWinSite*) *i;
                pSite->HandleParentMessages(pCWPStruct->hwnd,pCWPStruct->message,pCWPStruct->wParam,pCWPStruct->lParam);
            }
        }
        else
        {
            //Try to detect reparenting.
            HWND hTmpWnd;
            BOOL areWeDone = FALSE;
            POSITION pos = CHXWinSite::zm_ParentWnds.GetStartPosition();
            while(pos && !areWeDone)
            {
                CHXWinSite::zm_ParentWnds.GetNextAssoc(pos, (void*&) hTmpWnd, (void*&) pChildrenList);
                //hTmpWnd = ::GetParent(hTmpWnd);
                while( hTmpWnd && !areWeDone )
                {
                    if( hTmpWnd == hWnd )
                    {
                        //reparent and leave
                        LISTPOSITION listpos = pChildrenList->GetHeadPosition();
                        CHXWinSite* pSite = (CHXWinSite*)pChildrenList->GetAt(listpos);
                        if( pSite && pSite->m_pTopLevelSite )
                            ((CHXWinSite*)pSite->m_pTopLevelSite)->ReHookParents();
                        areWeDone = TRUE;
                    }
                    hTmpWnd = ::GetParent(hTmpWnd);
                }
            }
        }
    }

    if (message == WM_DISPLAYCHANGE)
    {
        CHXSimpleList* pChildrenList;
        if (CHXWinSite::zm_ParentWnds.Lookup((void*)hWnd,(void*&)pChildrenList))
        {
            CHXSimpleList::Iterator i = pChildrenList->Begin();
            for(; i!= pChildrenList->End(); ++i)
            {
                CHXWinSite* pSite = (CHXWinSite*) *i;
                pSite->CheckDisplayMode(NULL);
            }
        }
    }


    /*
     *  Sweet Jesus, they did not give us a window handle in the keyboard hook. So we might as
     *  well use the same messed up method here. Call GetCurrentThreadId. I hope to heck this
     *  works out.
     */

    DWORD id = GetCurrentThreadId();
    CParentWindowThreadData* pData = NULL;

    if (CHXWinSite::zm_ParentsThreadList.Lookup((void*)id, (void*&) pData))
    {
        return CallNextHookEx(pData->m_hHookAllMessage,nCode,wParam,lParam);
    }

    /*
     *  If we get here we are in some SERIOUS hurt.
     */

    HX_ASSERT(NO_HOOK_FOUND_RETURNING_WITH_ZERO);
    return 0;
}

void
CHXWinSite::HandleParentMessages(HWND hWnd,UINT message,WPARAM uParam,LPARAM lParam)
{
    AddRef();

    if (m_ulSiteThreadID != GetCurrentThreadId())
    {
        if (m_pTopLevelSite)
        {
            // If we are in overlay mode, we need a SiteMoving to
            // update the overaly's location - a repaint will not
            // help us here.  Proxy a MOVE message to the main app thread.
            if (m_pVideoSurface->m_nBltMode == HX_OVERLAY_BLT)
                m_pTopLevelSite->ScheduleCallback(MOVE, 0);
            else
            {
                m_pTopLevelSite->ScheduleCallback(REPAINT, 0);
                m_bRepaintScheduled = TRUE;
            }
        }
    }
    else
    {
        if (message == WM_MOVE)
        {
            _TLSLock();

            /*
             * Site moving used to take an X, Y parameter, but since we changed it to
             * go to GDI mode, that is no longer relevant.
             */
            m_pTopLevelSite->SiteMoving(0, 0);
            m_pTopLevelSite->m_nLastMoveTime = HX_GET_TICKCOUNT();
            m_pTopLevelSite->ScheduleCallback(MOUSE, 100);
            _TLSUnlock();
        }
    }

    Release();
    return;
}

BOOL
CHXWinSite::HandleWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT& lResult)
{
    //Give the event to windraw, we may be in 8 bit mode, and it will
    //want to know about it.
    if (m_pRootSurface)
    {
        WINDRAW* pWindraw;
        pWindraw = ((CWinBaseRootSurface*)m_pRootSurface)->GetWinDraw();
        WinDraw2_OnPaletteChange(pWindraw, hWnd, message);
    }

    //Before we do anything we give the native event to the renderer.
    HXxEvent     event = {0,0,0,0,0,0};

    AddRef();

    BOOL retValue = FALSE;

    if (m_pUser)
    {
        HXxEvent event = {message, (void*)hWnd, (void*)wParam, (void*)lParam, 0, 0};
        if (message == WM_DESTROY && m_bDetachWndMsgPending && m_pUser)
        {
            m_bDetachWndMsgPending = FALSE;
            event.event   = HX_DETACH_WINDOW;
            if (HXR_OK == m_pUser->HandleEvent(&event))
            {
                lResult = (LRESULT)event.result;
            }
            event.event  = WM_DESTROY;
        }
        if (!event.handled && m_pUser)
        {
            m_pUser->HandleEvent(&event);
        }
        if (event.handled)
        {
            retValue = TRUE;
            goto leave;
        }

        //This is an iffy decision. It could go either way. This does
        //not fix any bug that I am aware of, and may create others so
        //perhaps it should not go in.  The idea is that if the
        //renderer needs windowed sites, then we should not do any
        //further processing on the message. Don't know if this would
        //be a good thing.
        if (m_pUser && m_pUser->NeedsWindowedSites())
        {
            //retValue = FALSE;
            //goto leave;
        }
    }

    // Was this a scroll message? If so we need to process it here.
    if (message == WM_HSCROLL || message == WM_VSCROLL )
    {
        CHXWinSite* pParent;

        void* hwndScrollBar = (void*) lParam;
        if (zm_ScrollBarWnds.Lookup(hwndScrollBar, (void*&)pParent))
        {
            int nScrollCode = (int) LOWORD(wParam); // scroll bar value
            int nPos = (int) HIWORD(wParam);   // scroll box position
            BOOL bNeedRedraw = FALSE;

            SCROLLINFO info;
            memset(&info, 0, sizeof(SCROLLINFO));
            info.cbSize = sizeof(SCROLLINFO);
            info.fMask     = SIF_POS;
            info.nPos      = nPos;

            HXxSize size;
            HXxRect rect;
            pParent->GetWindowRect(&rect);
            size.cx = rect.right - rect.left;
            size.cy = rect.bottom - rect.top;

            if (SB_THUMBPOSITION == nScrollCode || SB_THUMBTRACK == nScrollCode)
            {
                SetScrollInfo((HWND)hwndScrollBar, SB_CTL, &info, FALSE);
                /* !(*&*(@ Shitty code becuase GetScrollInfo seems to be causing deadlocks. */

                if (message == WM_HSCROLL)
                {
                    pParent->m_XSliderPos = nPos;
                }
                else
                {
                    pParent->m_YSliderPos = nPos;
                }

                bNeedRedraw = TRUE;
            }

            if (SB_LINEUP == nScrollCode)
            {
                if (message == WM_HSCROLL)
                {
                    if (pParent->m_XSliderPos) pParent->m_XSliderPos--;
                    info.nPos = pParent->m_XSliderPos;
                }
                else
                {
                    if (pParent->m_YSliderPos) pParent->m_YSliderPos--;
                    info.nPos = pParent->m_YSliderPos;
                }
                SetScrollInfo((HWND)hwndScrollBar, SB_CTL, &info, TRUE);

                bNeedRedraw = TRUE;
            }

            if (SB_LINEDOWN == nScrollCode)
            {

                if (message == WM_HSCROLL)
                {
                    if (pParent->m_XSliderPos < (pParent->m_XSliderRange - size.cx) ) pParent->m_XSliderPos++;
                    info.nPos = pParent->m_XSliderPos;
                }
                else
                {
                    if (pParent->m_YSliderPos < (pParent->m_YSliderRange - size.cy) ) pParent->m_YSliderPos++;
                    info.nPos = pParent->m_YSliderPos;
                }
                SetScrollInfo((HWND)hwndScrollBar, SB_CTL, &info, TRUE);

                bNeedRedraw = TRUE;
            }

            if (SB_PAGEUP == nScrollCode)
            {
                if (message == WM_HSCROLL)
                {
                    pParent->m_XSliderPos -= size.cx;
                    if (pParent->m_XSliderPos < 0)
                    {
                        pParent->m_XSliderPos = 0;
                    }
                    info.nPos = pParent->m_XSliderPos;
                }
                else
                {
                    pParent->m_YSliderPos -= size.cy;
                    if (pParent->m_YSliderPos < 0)
                    {
                        pParent->m_YSliderPos = 0;
                    }
                    info.nPos = pParent->m_YSliderPos;
                }
                SetScrollInfo((HWND)hwndScrollBar, SB_CTL, &info, TRUE);

                bNeedRedraw = TRUE;
            }

            if (SB_PAGEDOWN == nScrollCode)
            {
                if (message == WM_HSCROLL)
                {
                    pParent->m_XSliderPos += size.cx;
                    if (pParent->m_XSliderPos > pParent->m_XSliderRange - size.cx)
                    {
                        pParent->m_XSliderPos = pParent->m_XSliderRange - size.cx;
                    }
                    info.nPos = pParent->m_XSliderPos;
                }
                else
                {
                    pParent->m_YSliderPos += size.cy;
                    if (pParent->m_YSliderPos > pParent->m_YSliderRange - size.cy)
                    {
                        pParent->m_YSliderPos = pParent->m_YSliderRange - size.cy;
                    }
                    info.nPos = pParent->m_YSliderPos;
                }
                SetScrollInfo((HWND)hwndScrollBar, SB_CTL, &info, TRUE);

                bNeedRedraw = TRUE;
            }
            if (bNeedRedraw)
            {
		//We have scrolled by at least one line. This invalidates the
		//whole rect.

		HXxRect pTmp = { pParent->m_topleft.x,
			pParent->m_topleft.y,
			pParent->m_topleft.x + pParent->m_size.cx,
			pParent->m_topleft.y + pParent->m_size.cy };
		m_pTopLevelSite->_RecursiveDamageRect(&pTmp, TRUE);
		pParent->InternalForceRedraw();
            }
        }
        retValue = TRUE;
        goto leave;
    }

    //
    // Need to translate native events to HXxEvents.
    //
    UINT32       hxEventType;
    hxEventType = 0;

    HXxPoint     pxMouse;
    HXxRect      boundsRect;
    pxMouse.x = LOWORD(lParam) - m_screenOffset.x;
    pxMouse.y = HIWORD(lParam) - m_screenOffset.y;
                   // XXXAH WHOOPS! Currently in the paint function I am
               // assuming that you are painting the enitire rectangle.
               // So for the moment we will be painting the whole thing.

               boundsRect.left     = 0;
               boundsRect.right    = m_size.cx;
               boundsRect.top      = 0;
               boundsRect.bottom   = m_size.cy;


    UINT32 flags;
    flags = 0;
    if (wParam & MK_SHIFT)
        flags += HX_SHIFT_KEY;
    if (wParam & MK_CONTROL)
        flags += HX_CTRL_KEY;
    if (GetAsyncKeyState(VK_MENU) & (1<<16))
        flags += HX_ALT_COMMAND_KEY;
    if (wParam & MK_LBUTTON)
        flags += HX_PRIMARY_BUTTON;
    if (wParam & MK_RBUTTON)
        flags += HX_CONTEXT_BUTTON;
    if (wParam & MK_MBUTTON)
        flags += HX_THIRD_BUTTON;

    switch (message)
    {
       case WM_PAINT:
           PAINTSTRUCT ps;
           ::BeginPaint(hWnd,&ps);
           boundsRect.left    = ps.rcPaint.left;
           boundsRect.right   = ps.rcPaint.right;
           boundsRect.top     = ps.rcPaint.top;
           boundsRect.bottom  = ps.rcPaint.bottom;

           m_pTopLevelSite->CheckDisplayMode(ps.hdc);
           ::EndPaint(hWnd,&ps);

           //Take care of all the dirty rects for all sites
           m_pTopLevelSite->ManageExposeEvents(&boundsRect);

//            // Check to see if this is a spurrious WM_PAINT generated by
//            // our Invalidate rect calls.
//            if (!(m_pDirtyRegion->numRects &&
//                  boundsRect.left   >= m_pDirtyRegion->extents.x1   &&
//                  boundsRect.right  <= m_pDirtyRegion->extents.x2   &&
//                  boundsRect.top    >= m_pDirtyRegion->extents.y1   &&
//                  boundsRect.bottom <= m_pDirtyRegion->extents.y2 ) &&
//                (boundsRect.left != boundsRect.right && boundsRect.top != boundsRect.bottom)
//                )
//            {

//                FillColorKey();

//                //Tell all of my children to update their overlays next time.
//                ResetUpdateOverlay();
//                if (m_pParentSite)
//                {
//                    // Taking the easy way out (would you expect anything
//                    // less of me?)  The hard, but better, way would be to
//                    // extract from the composition surface.  *sigh* but I
//                    // am too lazy right now ... maybe later ... AS IF!
//                    // XXXAH
//                    m_bDoNotGenerateWMPPaint = TRUE;
//                    InternalForceRedraw();
//                    m_bDoNotGenerateWMPPaint = FALSE;
//                    m_pTopLevelSite->_ForceRedrawAll();
//                }
//                else
//                {
//                    m_pTopLevelSite->_ForceRedrawAll();
//                }
//                RecursiveSizeSliders();
//           }

           lResult = 0;
           retValue = TRUE;
           goto leave;
           break;
       case WM_MOUSEMOVE:
           CheckCapture();
           SetCaptureMessage(hWnd, message, wParam, lParam);
           SetEvent(event, HX_MOUSE_MOVE, (void*)hWnd, (void*)&pxMouse, (void*)&flags);
           break;

       case WM_LBUTTONDOWN:
#ifdef _DEBUG
           if( wParam & MK_CONTROL )
           {
               DisplayAllSiteData();
           }
           if( wParam & MK_SHIFT)
           {
               DisplaySiteData("");
           }
#endif
           CheckCapture();
           SetCaptureMessage(hWnd, message, wParam, lParam);
           SetEvent(event, HX_PRIMARY_BUTTON_DOWN, (void*)hWnd, (void*)&pxMouse, (void*)&flags);
           break;

       case WM_RBUTTONDOWN:
           CheckCapture();
           SetCaptureMessage(hWnd, message, wParam, lParam);
           SetEvent(event, HX_CONTEXT_BUTTON_DOWN, (void*)hWnd, (void*)&pxMouse, (void*)&flags);
           break;

       case WM_LBUTTONUP:
           CheckCapture();
           SetCaptureMessage(hWnd, message, wParam, lParam);
           SetEvent(event, HX_PRIMARY_BUTTON_UP, (void*)hWnd, (void*)&pxMouse, (void*)&flags);
           break;

       case WM_RBUTTONUP:
           CheckCapture();
           SetCaptureMessage(hWnd, message, wParam, lParam);
           SetEvent(event, HX_CONTEXT_BUTTON_UP, (void*)hWnd, (void*)&pxMouse, (void*)&flags);
           break;
       case WM_LBUTTONDBLCLK:
           CheckCapture();
           SetCaptureMessage(hWnd, message, wParam, lParam);
           SetEvent(event, HX_PRIMARY_DBLCLK, (void*)hWnd, (void*)&pxMouse, (void*)&flags);
           break;
       case WM_RBUTTONDBLCLK:
           CheckCapture();
           SetCaptureMessage(hWnd, message, wParam, lParam);
           SetEvent(event, HX_CONTEXT_DBLCLK, (void*)hWnd, (void*)&pxMouse, (void*)&flags);
           break;

       case WM_CHAR:
       case WM_KEYDOWN:
       case WM_KEYUP:
       case WM_NCHITTEST:
           SetEvent(event, message, (void*)hWnd, (void*)wParam, (void*)&lParam);
           break;

           /*
            *  Some silly plugins call SetCapture. SO we have to keep on sending them mouse messages
            *  like crazy.
            */

       case WM_CAPTURECHANGED:
           m_pTopLevelSite->m_bSetCaptureOn = (void*)lParam == GetWindow()->window;
           if (m_pTopLevelSite->m_bSetCaptureOn)
           {
               if( m_pTopLevelSite->m_pCaptureUser)
                   m_pTopLevelSite->m_pCaptureUser = m_pTopLevelSite->m_pLastUser;
           }
           else
           {
               if( m_pTopLevelSite->m_pCaptureUser)
                   m_pTopLevelSite->m_pCaptureUser = NULL;
           }
           break;

       case WM_SIZE:
       case WM_MOVE:
       case WM_SIZING:
       case WM_MOVING:
       case WM_WINDOWPOSCHANGED:
       case WM_WINDOWPOSCHANGING:
#ifdef _CHECK_CREATE
       {
           RECT rect;
           ::GetWindowRect((HWND)GetWindow()->window, &rect);
           FILE* f1 = fopen("c:\\create.txt", "a+"); /* Flawfinder: ignore */
           fprintf(f1, "%p WM_SIZE: %p  hwnd: %p  internalSize: (%d, %d) external Size: (%d, %d)\n", GetCurrentThreadId(),this, GetWindow()->window, m_size.cx, m_size.cy, rect.right -rect.left, rect.bottom - rect.top);
           fclose(f1);
       }
#endif
       if (m_bInFullScreen)
       {
           lResult = DefWindowProc( hWnd, message, wParam, lParam);
           retValue = TRUE;
           goto leave;
       }
       else
       {
           retValue = FALSE;
           goto leave;
       }
       break;
#ifndef _HAMEL
       case WM_ACTIVATE:
       case WM_ACTIVATEAPP:
       {

           DWORD fActive = LOWORD(wParam);

           if (m_bInFullScreen && m_pUser && !fActive)
           {
               HXxEvent event = {WM_CHAR, GetWindow()->window, (void*)VK_ESCAPE, 0, 0, 0};
               m_pUser->HandleEvent(&event);
           }
           retValue = FALSE;
           goto leave;
       }
#endif
       case WM_CLOSE:
       {
           if (m_bInFullScreen && m_pUser)
           {
               HXxEvent event = {WM_CHAR, GetWindow()->window, (void*)VK_ESCAPE, 0, 0, 0};
               m_pUser->HandleEvent(&event);
               lResult = TRUE;
               retValue = TRUE;
               goto leave;
           }
           retValue = FALSE;
           goto leave;
       }

       case WM_SETFOCUS:
           lResult = 1;
           break;


       case WM_KILLFOCUS :
           lResult = 1;
           break;

    }

    if (event.window)
    {
        EventOccurred(&event);
        lResult = event.handled;
        retValue = event.handled;
        goto leave;
    }

    if (message == WM_SETCURSOR)
    {
        lResult = TRUE;
        retValue = TRUE;
        goto leave;
    }

    retValue = FALSE;
    goto leave;

  leave:
    Release();
    return retValue;
}

/************************************************************************
 *  Function:
 *    HXxHookSiteProc
 *
 */
LRESULT HXEXPORT
HXxHookSiteProc
(
    HWND hWnd,
    UINT message,
    WPARAM uParam,
    LPARAM lParam
    )
{
    LRESULT             lResult = 0;
    CHXWinSite*         pThis = 0;

    CHXWinSite::zm_SubclassedWnds.Lookup((void*)hWnd,(void*&)pThis);

    if (!pThis)
    {
        HX_ASSERT(0);
        return DefWindowProc(hWnd, message, uParam, lParam);
    }

    if (pThis->HandleWndProc(hWnd,message,uParam,lParam,lResult))
    {
        return (lResult);
    }

    return CallWindowProc(pThis->m_oldWndProc, hWnd, message, uParam, lParam);
}


/************************************************************************
 *  Function:
 *    HXxHookChar
 *
 *   Uhm, why is this function here?
 */
LRESULT HXEXPORT
HXxHookChar(int nCode,WPARAM wParam,LPARAM lParam)
{
    if (nCode <0 || nCode != HC_NOREMOVE)
    {
        int isKeyDown = (KF_UP & lParam);

        if (!isKeyDown)
        {
            LRESULT             lResult = 0;
            CHXWinSite*         pThis;

            CHXMapPtrToPtr::Iterator i = CHXWinSite::zm_SubclassedWnds.Begin();

            for(;i!= CHXWinSite::zm_SubclassedWnds.End(); ++i)
            {
                pThis = (CHXWinSite*) *i;
                if (pThis->IsFullScreen())
                {
                    if (pThis->HandleWndProc((HWND)i.get_key(),WM_CHAR,wParam,lParam,lResult))
                    {
                        return (lResult);
                    }
                }
            }
        }
    }

    /*
     *  Sweet Jesus. They do not give us a window handle. Ok. Call GetCurrentThreadId.
     */

    DWORD id = GetCurrentThreadId();
    CParentWindowThreadData* pData = NULL;

    if (CHXWinSite::zm_ParentsThreadList.Lookup((void*)id, (void*&) pData))
    {
        return CallNextHookEx(pData->m_hHook,nCode,wParam,lParam);
    }

    /*
     *  If we get here we are in some SERIOUS hurt.
     */

    HX_ASSERT(NO_HOOK_FOUND_RETURNING_WITH_ZERO);
    return 0;
}





void CHXWinSite::_GetDeviceCaps(void* h, UINT16& uBitesPerPixel, UINT16& uHorzRes, UINT16& uVertRes)
{
    HDC hdc = (HDC) h;

    if (!hdc)
    {
        hdc = GetDC(0);
    }

    uBitesPerPixel  = ::GetDeviceCaps(hdc, BITSPIXEL);
    uHorzRes        = ::GetDeviceCaps(hdc, HORZRES);
    uVertRes        = ::GetDeviceCaps(hdc, VERTRES);

    // did we create it? if so, release it as well
    if (hdc && hdc != h)
    {
        ReleaseDC(0, hdc);
    }
}



void CHXWinSite::_DestroySliders()
{
    if(m_hXSlider)
    {
        ::DestroyWindow(m_hXSlider);
        zm_ScrollBarWnds.RemoveKey(m_hXSlider);
        m_hXSlider = NULL;
    }

    if(m_hYSlider)
    {
        ::DestroyWindow(m_hYSlider);
        zm_ScrollBarWnds.RemoveKey(m_hYSlider);
        m_hYSlider = NULL;
    }
}

void CHXWinSite::_GenerateOSEvent(HXxEvent* pEvent, HXxEvent* pEvent2)
{
    //  Give all of those crappy renderers (you know who I am talking
    //  about flash!)  a WM_ message.
    HXxEvent winDozEvent;

    if(NULL==m_pUser)
        return;

    memcpy(&winDozEvent, pEvent, sizeof(HXxEvent)); /* Flawfinder: ignore */
    winDozEvent.param1 = pEvent->param2;
    winDozEvent.param2 = (void*) ((INT32) ((HXxPoint*)pEvent->param1)->y << 16 | ((HXxPoint*)pEvent->param1)->x);
    switch(pEvent2->event)
    {
       case HX_CONTEXT_BUTTON_DOWN:
           winDozEvent.event  = WM_RBUTTONDOWN;
           break;
       case HX_CONTEXT_BUTTON_UP:
           winDozEvent.event  = WM_RBUTTONUP;
           break;
       case HX_PRIMARY_BUTTON_DOWN:
           winDozEvent.event  = WM_LBUTTONDOWN;
           break;
       case HX_PRIMARY_BUTTON_UP:
           winDozEvent.event  = WM_LBUTTONUP;
           break;
       case HX_MOUSE_MOVE:
           winDozEvent.event  = WM_MOUSEMOVE;
           break;
       case HX_PRIMARY_DBLCLK:
           winDozEvent.event = WM_LBUTTONDBLCLK;
           break;
       case HX_CONTEXT_DBLCLK:
           winDozEvent.event = WM_RBUTTONDBLCLK;
           break;
       default:
           HX_ASSERT( "invalid RMA event for translation" );
           break;
    }

    m_pUser->HandleEvent(&winDozEvent);
    pEvent2->handled = winDozEvent.handled;
}


void CHXWinSite::_GenerateSetCursorEvent()
{
    HXxEvent setCursorEvent = {WM_SETCURSOR, GetWindow()->window, 0, 0, 0, FALSE};
    m_pUser->HandleEvent(&setCursorEvent);
}

HX_RESULT CHXWinSite::_EnterFullScreen()
{
    /* for the moment this will be COMPLETLY OS Specific */

    m_windowParent = GetParent((HWND) GetWindow()->window);

    HWND hParent = (HWND) GetWindow()->window;
    HWND hNextParent = NULL;

    while ((hNextParent = GetParent(hParent)) != NULL)
    {
        hParent = hNextParent;
    }

    // ask if it is topmost
    m_bWasTopMost = (GetWindowLong(hParent, GWL_EXSTYLE) & WS_EX_TOPMOST);

    if (m_bWasTopMost)
    {
        SafeSetWindowPos(hParent, HWND_NOTOPMOST, 0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
    }

    POINT point;
    memset(&point, 0, sizeof(POINT));
    MapWindowPoints( (HWND) GetWindow()->window, m_windowParent, &point, 1);

    RECT rect;
    ::GetWindowRect( (HWND) GetWindow()->window, &rect);

    m_windowPosition.x = point.x;
    m_windowPosition.y = point.y;
    m_windowSize.cx = rect.right - rect.left;
    m_windowSize.cy = rect.bottom - rect.top;

    m_bDisableForceRedraw = TRUE;

    if (zm_bInFullScreenTest)
    {
        HWND retVal = SetParent( (HWND) GetWindow()->window, NULL);
    }
    else
    {
        m_pContainingWindow = new CHXWinFullScreenWindow(this);
        m_pContainingWindow->Create();
        m_pContainingWindow->Show();
        HWND retVal = SetParent( (HWND) GetWindow()->window, m_pContainingWindow->GetWindow());
    }

    SetDisplayMode();

    // calculate new position

//      double stretchRatio, xRatio, yRatio;
//      IHXPreferences*        pPreferences    = NULL;
//      IHXBuffer*             pBuffer         = NULL;
//      BOOL            bPostageStamp   = FALSE;
//      char            szBuffer[255];

//      xRatio = (double)GetSystemMetrics(SM_CXSCREEN)/ (double)m_size.cx ;
//      yRatio = (double)GetSystemMetrics(SM_CYSCREEN)/ (double)m_size.cy ;

//      if (xRatio<yRatio)
//      {
//      stretchRatio = xRatio;
//      }
//      else
//      {
//      stretchRatio = yRatio;
//      }

//      m_screenOffset.x = (GetSystemMetrics(SM_CXSCREEN) - (int)((double)m_size.cx*stretchRatio))/2;
//      m_screenOffset.y = (GetSystemMetrics(SM_CYSCREEN) - (int)((double)m_size.cy*stretchRatio))/2;

//      HXxSize size;
//      size.cx = (int) ((double) m_size.cx * stretchRatio + 0.5);
//      size.cy = (int) ((double) m_size.cy * stretchRatio + 0.5);

    //Say we are in full screen mode
    m_bInFullScreen = TRUE;

    //Set up the windowing
    HXxSize newsize;
    newsize.cx = GetSystemMetrics(SM_CXSCREEN);
    newsize.cy = GetSystemMetrics(SM_CYSCREEN);

    //Tell the top level site that it has changed.
//    SetSize(size);
    SetSize(m_size);

    if (zm_bInFullScreenTest)
    {
        SafeSetWindowPos((HWND) GetWindow()->window, HWND_TOPMOST, 0, 0, newsize.cx, newsize.cy, NULL);
    }
    else
    {
        SafeMoveWindow((HWND) GetWindow()->window, 0, 0, newsize.cx, newsize.cy, FALSE);
    }

    /*
     * Get rid of all child windows.
     */

    zm_ListOfHiddenWindows.RemoveAll();
    EnumChildWindows( (HWND) GetWindow()->window, (WNDENUMPROC)HXxRemoveWindows, NULL);

    /*
     * Tell all renderers to repaint themselves
     */
    m_pTopLevelSite->m_bDisableForceRedraw = FALSE;
    ((CWinBaseRootSurface*)m_pRootSurface)->PrepareFullScreen();
    _ForceRedrawAll();
    ((CWinBaseRootSurface*)m_pRootSurface)->SetFullScreen();
    ((CWinBaseRootSurface*)m_pRootSurface)->FillBorders();


    if (zm_ListOfHiddenWindows.GetCount())
    {
        CHXMapPtrToPtr::Iterator i = zm_ListOfHiddenWindows.Begin();
        for(;i!=zm_ListOfHiddenWindows.End();++i)
        {
            SafeShowWindow((HWND) i.get_key(), SW_SHOW);
        }
        zm_ListOfHiddenWindows.RemoveAll();
    }

    m_nDelayFillBorders = 3;
    ScheduleCallback(MOUSE, 0);

    SetFocus((HWND)GetWindow()->window);

    /*
     * Now tell the status text that it's parent has changed size.
     */

    if (m_pStatusText)
    {
        m_pStatusText->ParentChangedSize();
    }

    return HXR_OK;
}

HX_RESULT CHXWinSite::_ExitFullScreen()
{
    m_pTopLevelSite->m_bDisableForceRedraw = TRUE;
    memset(&m_screenOffset, 0, sizeof(HXxPoint));
    //  SetSize(m_windowSize);
    ((CWinBaseRootSurface*)m_pRootSurface)->PrepareExitFullScreen();

    EnterCriticalSection(&(((CHXWinSite*)m_pTopLevelSite)->m_CriticalSection));

    DestroySurfaces();
    ((CWinBaseRootSurface*)m_pRootSurface)->RestoreResolution();
    ReInitSurfaces();

    LeaveCriticalSection(&(((CHXWinSite*)m_pTopLevelSite)->m_CriticalSection));


    HWND retVal = SetParent((HWND)GetWindow()->window, m_windowParent);
    if (!zm_bInFullScreenTest)
    {
        m_pContainingWindow->Hide();
        m_pContainingWindow->Destroy();
        HX_DELETE(m_pContainingWindow);
    }

    SafeSetWindowPos((HWND) GetWindow()->window, HWND_TOP, 0,0,0,0,SWP_NOMOVE  | SWP_NOSIZE );

    SafeMoveWindow((HWND) GetWindow()->window, m_windowPosition.x, m_windowPosition.y, m_windowSize.cx, m_windowSize.cy, FALSE);

    m_pTopLevelSite->m_bDisableForceRedraw = FALSE;
    memset(&m_screenOffset, 0, sizeof(HXxPoint));

    HWND hParent = (HWND) GetWindow()->window;
    HWND hNextParent = NULL;

    while ((hNextParent = GetParent(hParent)) != NULL)
    {
        hParent = hNextParent;
    }

    if (m_bWasTopMost)
    {
        /*
         *  Check to see if the player is playing, if it is then reset the player window to
         *   topmost.
         */

        IHXClientEngine* pEngine;
        IUnknown* pUnknown;
        IHXPlayer* pPlayer;

        BOOL bIsDone  = TRUE;

        if (HXR_OK == m_pContext->QueryInterface(IID_IHXClientEngine, (void**) &pEngine))
        {
            UINT16 count = pEngine->GetPlayerCount();
            while(count)
            {
                count--;
                if (HXR_OK == pEngine->GetPlayer(count, pUnknown))
                {
                    if (HXR_OK == pUnknown->QueryInterface(IID_IHXPlayer, (void**) &pPlayer))
                    {
                        bIsDone &= pPlayer->IsDone();
                        HX_RELEASE(pPlayer);
                    }
                    HX_RELEASE(pUnknown);
                }
            }
            HX_RELEASE(pEngine);
        }

        if (!bIsDone)
        {
            SafeSetWindowPos(hParent, HWND_TOPMOST, 0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
        }
        m_bWasTopMost = FALSE;
    }

    m_bInFullScreen = FALSE;

    SetSize(m_windowSize);

    m_pTopLevelSite->_ForceRedrawAll();

    if (m_pStatusText)
    {
        m_pStatusText->ParentChangedSize();
        m_pStatusText->Hide();
    }

    m_nDelayFillBorders = 0;
    SetFocus((HWND)GetWindow()->window);

    return HXR_OK;
}


HX_RESULT CHXWinSite::_TestFullScreen(void* hTestBitmap,const char* pszStatusText)
{
    EnterCriticalSection(&(((CHXWinSite*)m_pTopLevelSite)->m_CriticalSection));

    HX_RESULT retVal = HXR_FAIL;
    CHXWinSite* pTempWindow = new CHXWinSite(m_pContext, FALSE);
    zm_bInFullScreenTest = TRUE;

    if (pTempWindow)
    {
        pTempWindow->AddRef();
        retVal = pTempWindow->InternalTestFullScreen(hTestBitmap, pszStatusText);
        zm_bInFullScreenTest = FALSE;
        pTempWindow->Release();
    }

    LeaveCriticalSection(&(((CHXWinSite*)m_pTopLevelSite)->m_CriticalSection));
    return retVal;
}

/*
 *  XXXAH all of this code that reads prefs can be move to the cross platform code.
 */

HX_RESULT CHXWinSite::InternalTestFullScreen(LPVOID hTestBitmap,const char* pszStatusText)
{
/*
 *       Check to see if we have a HWND.
 *       If not, create one, DirectDraw is going to require one.
 */

    BOOL bInternalTestWindow = FALSE;
    if (!m_pWindow || !m_pWindow->window)
    {
        bInternalTestWindow = TRUE;
        Create(NULL, WS_POPUP);
    }

    /*
     * Get the modes to be tested from the regestry.
     */

    IHXPreferences*    pPreferences    = NULL;
    IHXBuffer*         pBuffer         = NULL;
    char*               pszModesToTest  = NULL;
    char                szBuffer[255]; /* Flawfinder: ignore */

    m_pContext->QueryInterface(IID_IHXPreferences,(void**)&pPreferences);

    SafeStrCpy(szBuffer, REGKEY_FULLSCREEN_DATA, 255);
    SafeStrCat(szBuffer, "\\", 255);
    SafeStrCat(szBuffer, REGKEY_FULLSCREEN_TEST_MODES, 255);

    pPreferences->ReadPref(szBuffer, pBuffer);

    // if we were called without a mode to test this means that
    // the top level client wants to know what modes are
    // availiable. So we will call enumerate modes fix-up the
    // regestry and return.

    if (pBuffer && strlen((char*)pBuffer->GetBuffer()))
    {
        char* pszModesToTest = (char*)pBuffer->GetBuffer();

        /*
         *  Test each of the modes which are in the Mode Description
         *  String.
         */

        int stringLength = strlen(pszModesToTest);
        char* pszTempString = new char[stringLength+1];
        CHXSimpleList modesList;
        memcpy(pszTempString, pszModesToTest, stringLength+1); /* Flawfinder: ignore */

        // Whoops! Since we use strtok in the following calls we
        // had better strtok this here and store the
        // tokens in a list!

        char* token = strtok( pszTempString, MODE_SEPERATOR);
        while( token != NULL )
        {
            modesList.AddTail(token);
            token  = strtok( NULL, MODE_SEPERATOR);
        }

        if (bInternalTestWindow)
        {
            ShowSite(TRUE);
        }

        CHXSimpleList::Iterator i;
        for(i = modesList.Begin(); i!=modesList.End(); ++i)
        {
            TestMode((const char*) *i, hTestBitmap, pszStatusText);
        }

        delete[] pszTempString;
    }
    else
    {
        UpdateModes();
    }

    HX_RELEASE(pBuffer);
    HX_RELEASE(pPreferences);

    if (bInternalTestWindow)
    {
        Destroy();
    }

    return HXR_OK;
}

HX_RESULT CHXWinSite::TestMode(const char* pszModeDescription, void* hTestBitmap, const char* pszText)
{
/*
 *       1st Parse the Modes Description string
 *
 */

    INT32                       resolutionX     = 0;
    INT32                       resolutionY     = 0;
    INT32                       colorDepth      = 0;

    IHXPreferences*    pPreferences    = NULL;
    IHXBuffer*         pBuffer         = NULL;
    char*               pszModesToTest  = NULL;
    char                szBuffer[255]; /* Flawfinder: ignore */

    if (HXR_OK == ConvertStringToXYDepth(pszModeDescription, resolutionX, resolutionY, colorDepth))
    {
        if (HXR_OK == m_pContext->QueryInterface(IID_IHXPreferences,(void**)&pPreferences))
        {
            /*
             * Set the Size and Position
             */
            HXxSize     oldSize;
            HXxPoint    oldPos;
            HXxSize     newSize;
            HXxPoint    newPosition;
            memcpy(&oldSize, &m_size, sizeof(HXxSize)); /* Flawfinder: ignore */
            GetPosition(oldPos);
            newSize.cx  = GetSystemMetrics(SM_CXSCREEN);
            newSize.cy  = GetSystemMetrics(SM_CYSCREEN);
            SetSize(newSize);
            memset(&newPosition,0,sizeof(HXxPoint));
            SetPosition(newPosition);

            /* tell full screen what mode to use */
            pBuffer = new CHXBuffer();
            pBuffer->Set((UCHAR*) pszModeDescription, strlen(pszModeDescription)+1);
            SafeStrCpy(szBuffer, REGKEY_FULLSCREEN_DATA, 255);
            SafeStrCat(szBuffer, "\\", 255);
            SafeStrCat(szBuffer, REGKEY_FULLSCREEN_PREFERED_MODE, 255);
            pPreferences->WritePref(szBuffer, pBuffer);
            HX_RELEASE(pBuffer);
            EnterFullScreen();
            int testResult = TestFullScreenPerformance(hTestBitmap, pszText);
            ExitFullScreen();

            SetSize(oldSize);
            SetPosition(oldPos);

            // update the prefs.
            if (testResult)
            {
                UpdatePrefs(resolutionX, resolutionY, colorDepth, testResult, testResult>TEST_THRESHOLD, 1);
            }
        }
    }

    return HXR_OK;
}

int CHXWinSite::TestFullScreenPerformance(void* hTestBitmap, const char* pszText)
{
    HBITMAP hBitmap = (HBITMAP)hTestBitmap;
    HXxRect destRect;

    /*
     *  Get the bits
     */

    HDC hDC = GetDC((HWND)GetWindow()->window);

    CHXDIBits dib;
    LPBITMAPINFOHEADER      pinfo = NULL;
    UCHAR* pBits = NULL;

    if (HXR_OK != dib.GetDIBits(hDC, hBitmap, pBits, pinfo))
    {
        return 0;
    }

    /*
     *  Setup the font
     */

    HFONT hFont;
    int oldMappingMode = SetMapMode( hDC, MM_TEXT );
    int nHeight = -MulDiv(15, GetDeviceCaps(hDC, LOGPIXELSY), 72);
    hFont = CreateFont(nHeight, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Ariel");
    SetMapMode( hDC, oldMappingMode);
    HFONT hOldFont = (HFONT)SelectObject(hDC, hFont);
    SIZE textSize;
    GetTextExtentPoint(hDC, "XXX", 4, &textSize);
    int textHeight = textSize.cy + 2;

    /*
     * Setup our drawing tools
     */

    HBRUSH  hBlackBrush = (HBRUSH) GetStockObject(BLACK_BRUSH);
    HBRUSH  hOldBrush   = (HBRUSH) SelectObject(hDC, hBlackBrush);
    HPEN    hNullPen    = (HPEN) GetStockObject(NULL_PEN);
    HPEN    hOldPen     = (HPEN) SelectObject(hDC, hNullPen);
    COLORREF oldColor   = SetTextColor(hDC, 0x0000FF00);
    COLORREF oldBkColor = SetBkColor(hDC, 0x00000000);

    /*
     *  Set up our rects
     */

    HXxRect srcRect;
    memset(&destRect, 0, sizeof(HXxRect));
    memset(&srcRect, 0, sizeof(HXxRect));
    srcRect.right   = pinfo->biWidth;
    srcRect.bottom  = pinfo->biHeight;

    int offsetY = (GetSystemMetrics(SM_CYSCREEN) - pinfo->biHeight * 2) / 2;
    int offsetX = (GetSystemMetrics(SM_CXSCREEN) - pinfo->biWidth * 2) / 2;

    destRect.top    = (long) offsetY;
    destRect.left   = (long) offsetX;
    destRect.bottom = (long) offsetY + pinfo->biHeight * 2;
    destRect.right  = (long) offsetX + pinfo->biWidth * 2;

    /*
     *  Start timing.
     */

    GetAsyncKeyState(VK_ESCAPE);
    UINT32  nStartTime = HX_GET_TICKCOUNT();
    UINT32  nNowTime;
    UINT32  timeToUpdateCounter = 0;
    char    szStatus[255]; /* Flawfinder: ignore */
    int     counter = 0;

    while(1)
    {
        m_pRootSurface->Lock(0);
        m_pRootSurface->Blt((UCHAR*)pBits, (HXBitmapInfoHeader*) pinfo, destRect, srcRect, this);
        m_pRootSurface->Unlock(0, GetWindow());

        //      m_pVideoSurface->Blt((UCHAR*)pBits, (HXBitmapInfoHeader*) &info.bmiHeader, destRect, srcRect);

        /*
         *  Ok now blt to the primary surface
         */

        nNowTime = HX_GET_TICKCOUNT();
        if (nNowTime - nStartTime > timeToUpdateCounter)
        {
            /*
             * Update the display
             */
            RECT rect;
            rect.left = 0;
            rect.bottom = GetSystemMetrics(SM_CYSCREEN) + 1;
            rect.top = rect.bottom - textHeight;
            rect.right =  GetSystemMetrics(SM_CXSCREEN) + 1;
            Rectangle(hDC, rect.left, rect.top, rect.right, rect.bottom);
            timeToUpdateCounter += 1000;
            SafeSprintf(szStatus, 255, "%s %d", pszText, (TEST_LENGTH - timeToUpdateCounter)/1000);
            DrawText(hDC, szStatus, strlen(szStatus), &rect, DT_CENTER | DT_VCENTER);
            if (timeToUpdateCounter == TEST_LENGTH)
            {
                break;
            }
        }
        counter++;

        /*
         *  Was escape pressed? If so break
         */
        if (GetAsyncKeyState(VK_ESCAPE))
        {
            // eat the key stroke
            MSG msg;
            while (PeekMessage (&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
            break;
        }
    }

    SetTextColor(hDC, oldColor);
    SetBkColor(hDC, oldBkColor);
    SelectObject(hDC, hOldPen);
    SelectObject(hDC, hOldBrush);

    ReleaseDC((HWND)GetWindow()->window, hDC);

    nNowTime = HX_GET_TICKCOUNT();
    int bltsPerSecond = counter*1000 / CALCULATE_ELAPSED_TICKS(nStartTime, nNowTime);
    return bltsPerSecond;
#if 0
    /*
     *   The following code will take the given bit map and blt it
     *   multiple times to the screen. Each time it will change the
     *    saturation, and contrast causing the bitmap to fade in and out
     *    at the same time it will shrink and expand the bitmap. This
     *    will make a pretty animation.
     *    However, this exercises the YUV->RGB code. This code has some problems
     *    currently. When the YUV->RGB code is fixed we may re-instate this code.
     *
     */


    /*
     *  Get information on the bitmap
     */

    char szStatus[255]; /* Flawfinder: ignore */
    HDC hDC = GetDC(NULL);
    BITMAPINFO info;
    memset(&info, 0, sizeof(BITMAPINFO));
    info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    int retVal = GetDIBits(hDC, (HBITMAP)hTestBitmap, 0, 1, NULL, &info, DIB_RGB_COLORS);

    // add the relevant black border to the bitmap (the bitmap looks like crap if
    // if is stretched to the whole width of the screen).
    int bitmapX = info.bmiHeader.biWidth *2;
    bitmapX +=  bitmapX % 8 ? 8 - bitmapX % 8 : 0;
    int bitmapY = info.bmiHeader.biHeight * 2;

    HBITMAP hBitmap = CreateCompatibleBitmap(hDC, bitmapX, bitmapY);

    HDC hMemDC = CreateCompatibleDC(hDC);

    HBITMAP hOldBitmap = (HBITMAP) SelectObject(hMemDC, hBitmap);
    HBRUSH  hBlackBrush = (HBRUSH) GetStockObject(BLACK_BRUSH);
    HBRUSH  hOldBrush   = (HBRUSH) SelectObject(hMemDC, hBlackBrush);
    HPEN    hNullPen    = (HPEN) GetStockObject(NULL_PEN);
    HPEN    hOldPen     = (HPEN) SelectObject(hMemDC, hNullPen);

    Rectangle(hMemDC, 0, 0, bitmapX, bitmapY);

    HXxRect destRect;
    destRect.left   = (bitmapX - info.bmiHeader.biWidth) / 2;
    destRect.top    = (bitmapY - info.bmiHeader.biHeight) / 2;
    destRect.right  = destRect.left + info.bmiHeader.biWidth;
    destRect.bottom = destRect.top + info.bmiHeader.biHeight;

    HDC hMemDC2 = CreateCompatibleDC(hDC);
    HBITMAP hOldBitmap2 = (HBITMAP) SelectObject(hMemDC2, (HBITMAP)hTestBitmap);
    BitBlt(hMemDC, destRect.left, destRect.top, info.bmiHeader.biWidth, info.bmiHeader.biHeight, hMemDC2, 0, 0, SRCCOPY);
    SelectObject(hMemDC, hOldPen);
    SelectObject(hMemDC, hOldBrush);
    SelectObject(hMemDC, hOldBitmap);
    SelectObject(hMemDC2, hOldBitmap2);
    DeleteDC(hMemDC);
    DeleteDC(hMemDC2);

    hOldPen             = (HPEN)SelectObject(hDC, hNullPen);
    hOldBrush           = (HBRUSH)SelectObject(hDC, hBlackBrush);
    COLORREF oldColor   = SetTextColor(hDC, 0x0000FF00);
    COLORREF oldBkColor = SetBkColor(hDC, 0x00000000);

    /*
     *  Get the Bits
     */
    memset(&info, 0, sizeof(BITMAPINFO));
    info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    retVal = GetDIBits(hDC, (HBITMAP)hBitmap, 0, 1, NULL, &info, DIB_RGB_COLORS);
    void* pBits = (void*) new char[info.bmiHeader.biSizeImage];
    retVal = GetDIBits(hDC, (HBITMAP)hBitmap, 0, info.bmiHeader.biHeight, pBits, &info, DIB_RGB_COLORS);
    DeleteObject(hBitmap);

    // Create a YUV BITMAPINFO
    BITMAPINFO YUVBmi;
    memset(&YUVBmi, 0, sizeof (BITMAPINFO));
    MakeBitmap((LPBITMAPINFO)&YUVBmi, sizeof(BMI), CID_I420, info.bmiHeader.biWidth, info.bmiHeader.biHeight, NULL, NULL);

    // Convert to YUV
    int pitchIn = GetBitmapPitch((LPBITMAPINFO)&info);
    int pitchOut = GetBitmapPitch((LPBITMAPINFO)&YUVBmi);
    int cidIn = GetBitmapColor((LPBITMAPINFO) &info);
    void* pYUVBits = (void*) new char[info.bmiHeader.biSizeImage];

    BOOL bConverter = zm_pColorAcc->CheckColorConverter(cidIn, CID_I420);
    ColorConverterRequest(cidIn, CID_I420, bConverter);
    int returnVal       = 0;

    if (bConverter)
    {
        zm_pColorAcc->ColorConvert(CID_I420, (UCHAR*)pYUVBits, info.bmiHeader.biWidth, info.bmiHeader.biHeight,
                            pitchOut, 0,0, info.bmiHeader.biWidth, info.bmiHeader.biHeight,
                            cidIn, (UCHAR*)pBits, info.bmiHeader.biWidth, info.bmiHeader.biHeight, pitchIn,
                            0,0,info.bmiHeader.biWidth, info.bmiHeader.biHeight);
    }


    // now just blt like crazy.

    /*
     *  However for efficient blt-ing we should REALLY be using windraw2 directly
     *  since rootSurface is simply not up to snuff right now.
     *   We will create a temporary RGB surface of the same dimensions as the RGB bitmap
     *  we created above.
     *   We will then color-convert to this surface.
     *   We will then blt to the destination rect (stretching with direct draw).
     */

    /*
     *  Create RGB surface.
     */

    WINDRAW* pWinDraw = ((CWinBaseRootSurface*)m_pRootSurface)->GetWinDraw();
    ((CWinBaseRootSurface*)m_pRootSurface)->OpenWindraw();
    BMI primaryBMI;
    memset(&primaryBMI, 0, sizeof(BMI));
    WinDraw2_GetDisplayFormat(pWinDraw, &primaryBMI);
    int nCID = GetBitmapColor((LPBITMAPINFO)&primaryBMI);
    memset(&primaryBMI, 0, sizeof(BMI));
    MakeBitmap((LPBITMAPINFO)&primaryBMI, sizeof(BMI), nCID, info.bmiHeader.biWidth, info.bmiHeader.biHeight, NULL, NULL);
    WINDRAWSURFACE surface;
    UCHAR*   pSurfaceLock = NULL;
    LONG     nPitchOut = 0;
    memset(&surface, 0, sizeof(WINDRAWSURFACE));

    IHXPreferences*    pPreferences    = NULL;
    IHXBuffer*         pBuffer         = NULL;

    BOOL    bUseWindraw     = TRUE;
    if (HXR_OK == m_pContext->QueryInterface(IID_IHXPreferences,(void**)&pPreferences))
    {
        if (pPreferences->ReadPref("UseWinDraw", pBuffer) == HXR_OK)
        {
            bUseWindraw = ::atoi((char*) pBuffer->GetBuffer()) == 1;
        }
        HX_RELEASE(pBuffer);
    }
    HX_RELEASE(pPreferences);

    if (NOERROR != WinDraw2_CreateSurface(pWinDraw, &surface, &primaryBMI, bUseWindraw ? WINDRAWSURFACE_DIRECTDRAW : 0, 0, 0))
    {
        return 0;
    }

    /*
     *  Setup the font
     */

    HFONT hFont;
    int oldMappingMode = SetMapMode( hDC, MM_TEXT );
    int nHeight = -MulDiv(15, GetDeviceCaps(hDC, LOGPIXELSY), 72);
    hFont = CreateFont(nHeight, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Ariel");
    SetMapMode( hDC, oldMappingMode);
    HFONT hOldFont = (HFONT)SelectObject(hDC, hFont);
    SIZE textSize;
    GetTextExtentPoint(hDC, "XXX", 4, &textSize);
    int textHeight = textSize.cy + 2;

    HXxRect srcRect;
    memset(&destRect, 0, sizeof(HXxRect));
    memset(&srcRect, 0, sizeof(HXxRect));
    srcRect.right   = info.bmiHeader.biWidth;
    srcRect.bottom  = info.bmiHeader.biHeight;

    UINT32 timeToUpdateCounter = 0;
    UINT32 nNowTime;

    float sat = DEF_SATURATION;
    float inc = (float)0.1;
    int   counter = 0;

    float tolerance_x = 100.0;
    float tolerance_y = tolerance_x * (float) GetSystemMetrics(SM_CYSCREEN) / (float)(GetSystemMetrics(SM_CXSCREEN) - textHeight);

    float currentModifier_x = (float) 0.0;
    float currentModifier_y = (float) 0.0;
    float currentVelocity_x = (float) 1.0;
    float currentVelocity_y = (float) (tolerance_y / tolerance_x);

    GetAsyncKeyState(VK_ESCAPE);
    UINT32 nStartTime = HX_GET_TICKCOUNT();

    while(1)
    {
        sat += inc;

        if (sat> MAX_SATURATION || sat< MIN_SATURATION )
        {
            inc *= -1;
        }

        destRect.top    = (long) currentModifier_x;
        destRect.left   = (long) currentModifier_y;
        destRect.bottom = (long) (GetSystemMetrics(SM_CYSCREEN) - currentModifier_x - textHeight);
        destRect.right  = (long) (GetSystemMetrics(SM_CXSCREEN) - currentModifier_y);

        /*
         * Color convert onto the small RGB surface
         */
        int cidIn   = GetBitmapColor((LPBITMAPINFO) &YUVBmi);
        int pitchIn = GetBitmapPitch((LPBITMAPINFO) &YUVBmi);

        bConverter = zm_pColorAcc->CheckColorConverter(cidIn, nCID);
        ColorConverterRequest(cidIn, nCID, bConverter);

        //      CWinBaseRootSurface::zm_pColorAcc->SetColorAdjustments(sat, sat, sat, sat);
        zm_pColorAcc->SetColorAdjustments(sat, sat, sat, DEF_HUE);

        if (NOERROR == WinDrawSurface_Lock(pWinDraw, &surface, 0, (void**) &pSurfaceLock, (LONG*)&nPitchOut))
        {
            if (bConverter)
            {
                zm_pColorAcc->CheckColorConvert(nCID, pSurfaceLock,
                                        info.bmiHeader.biWidth, info.bmiHeader.biHeight, nPitchOut,
                                        0, 0, info.bmiHeader.biWidth, info.bmiHeader.biHeight,
                                        cidIn, (UCHAR*)pYUVBits,
                                        info.bmiHeader.biWidth, info.bmiHeader.biHeight, pitchIn,
                                        0,0, info.bmiHeader.biWidth, info.bmiHeader.biHeight);
            }
            WinDrawSurface_Unlock(pWinDraw, &surface, 0);
        }

        /*
         *  Ok now blt to the primary surface
         */

        HRESULT res = WinDrawSurface_Blt(pWinDraw, &surface, (RECT*)&destRect, (RECT*)&srcRect);

        nNowTime = HX_GET_TICKCOUNT();
        if (nNowTime - nStartTime > timeToUpdateCounter)
        {
            /*
             * Update the display
             */
            RECT rect;
            rect.left = 0;
            rect.bottom = GetSystemMetrics(SM_CYSCREEN) + 1;
            rect.top = rect.bottom - textHeight;
            rect.right =  GetSystemMetrics(SM_CXSCREEN) + 1;
            Rectangle(hDC, rect.left, rect.top, rect.right, rect.bottom);
            timeToUpdateCounter += 1000;
            SafeSprintf(szStatus, 255, "%s %d", pszText, (TEST_LENGTH - timeToUpdateCounter)/1000);
            DrawText(hDC, szStatus, strlen(szStatus), &rect, DT_CENTER | DT_VCENTER);
            if (timeToUpdateCounter == TEST_LENGTH)
            {
                break;
            }
        }
        counter++;

        if (currentModifier_x > tolerance_x || currentModifier_x < 0)
        {
            currentVelocity_x *=-1;
            currentVelocity_y *=-1;
        }

        currentModifier_x += currentVelocity_x;
        currentModifier_y += currentVelocity_y;

        /*
         *  Was escape pressed? If so break
         */
        if (GetAsyncKeyState(VK_ESCAPE))
        {
            // eat the key stroke
            MSG msg;
            while (PeekMessage (&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE));
            break;
        }
    }

    WinDraw2_ReleaseSurface(pWinDraw, &surface);

    zm_pColorAcc->SetColorAdjustments(DEF_BRIGHTNESS, DEF_CONTRAST, DEF_SATURATION, DEF_HUE);
    SetTextColor(hDC, oldColor);
    SetBkColor(hDC, oldBkColor);
    SelectObject(hDC, hOldPen);
    SelectObject(hDC, hOldBrush);
    HX_DELETE(pYUVBits);

    ReleaseDC(NULL, hDC);

    nNowTime = HX_GET_TICKCOUNT();
    int bltsPerSecond = counter*1000 / CALCULATE_ELAPSED_TICKS(nStartTime, nNowTime);
    return bltsPerSecond;
#endif
}


void CHXWinSite::_TryCreateXSlider()
{
//      if (!m_hXSlider)
//      {
//        _CreateXSlider(range);
//      }
}

void CHXWinSite::_SetXSliderValues(INT32 range, INT32 pageSize)
{
    if (!m_hXSlider)
    {
        _CreateXSlider(range);
    }

    SCROLLINFO info;
    memset(&info, 0, sizeof(SCROLLINFO));
    info.cbSize = sizeof(SCROLLINFO);
    info.fMask  = SIF_PAGE | SIF_RANGE;
    info.nMax   = range;
    info.nPage  = pageSize;
    SetScrollInfo( m_hXSlider, SB_CTL, &info, TRUE);
    m_XSliderRange = range;
}

void CHXWinSite::_TryCreateYSlider()
{
//      if (!m_hYSlider)
//      {
//        _CreateYSlider(range);
//      }
}

int CHXWinSite::_CreateXSlider(int range)
{
    HXxWindow* pwindow = GetParentWindow();
    HWND hwnd = (HWND)pwindow->window;

    int height = GetSystemMetrics(SM_CYHSCROLL);
    HXxPoint* pPoint = GetOrigin();

    HX_ASSERT(m_size.cy > height);

    if (m_size.cy < height)
    {
        height = m_size.cy /2;
    }

    m_hXSlider = CreateWindowEx(0, "SCROLLBAR", (LPSTR) NULL, WS_CHILD | SBS_HORZ,
                                pPoint->x, pPoint->y + m_size.cy - height,
                                m_size.cx, height,
                                hwnd, (HMENU) NULL, GetModuleHandle(NULL), (LPVOID) NULL);

    zm_ScrollBarWnds.SetAt(m_hXSlider, this);

    SCROLLINFO info;
    memset(&info, 0, sizeof(SCROLLINFO));
    info.cbSize = sizeof(SCROLLINFO);
    info.fMask    = SIF_PAGE | SIF_RANGE;
    HXxSize parentSize;
    memset(&parentSize, 0, sizeof(HXxSize));
    if (m_pParentSite)
    {
        m_pParentSite->GetSize(parentSize);
    }
    info.nPage    = parentSize.cx;
    info.nMax   = range;
    SetScrollInfo( m_hXSlider, SB_CTL, &info, TRUE);
    m_XSliderRange  = range;

    SizeSliders();
    return (int) m_hXSlider;
}

int CHXWinSite::_CreateYSlider(int range)
{
    HXxWindow* pwindow = GetParentWindow();
    HWND hwnd = (HWND) pwindow->window;

    int width = GetSystemMetrics(SM_CXVSCROLL);
    HXxPoint* pPoint = GetOrigin();

    HX_ASSERT(m_size.cx > width);

    if (m_size.cx < width)
    {
        width = m_size.cx /2;
    }

    m_hYSlider = CreateWindowEx(0, "SCROLLBAR", (LPSTR) NULL, WS_CHILD | SBS_VERT,
                                pPoint->x + m_size.cx - width, pPoint->y,
                                width, m_size.cy,
                                hwnd, (HMENU) NULL, GetModuleHandle(NULL), (LPVOID) NULL);

    zm_ScrollBarWnds.SetAt(m_hYSlider, this);

    SCROLLINFO info;
    memset(&info, 0, sizeof(SCROLLINFO));
    info.cbSize = sizeof(SCROLLINFO);
    info.fMask    = SIF_PAGE | SIF_RANGE;
    HXxSize parentSize;
    memset(&parentSize, 0, sizeof(HXxSize));
    if (m_pParentSite)
    {
        m_pParentSite->GetSize(parentSize);
    }
    info.nPage    = parentSize.cy;
    info.nMax   = range;
    SetScrollInfo( m_hYSlider, SB_CTL, &info, TRUE);
    m_YSliderRange  = range;

    SizeSliders();
    return (int) m_hYSlider;
}

void CHXWinSite::_SetYSliderValues(INT32 range, INT32 pageSize)
{
    if (!m_hYSlider)
    {
        _CreateYSlider(range);
    }

    SCROLLINFO info;
    memset(&info, 0, sizeof(SCROLLINFO));
    info.cbSize = sizeof(SCROLLINFO);
    info.fMask  = SIF_PAGE | SIF_RANGE;
    info.nMax   = range;
    info.nPage  = pageSize;
    SetScrollInfo( m_hYSlider, SB_CTL, &info, TRUE);
    m_YSliderRange = range;
}
void CHXWinSite::_GetSystemSizeOfSliders(INT32* pWidth, INT32* pHeight)
{
    *pWidth     = GetSystemMetrics(SM_CXVSCROLL);
    *pHeight    = GetSystemMetrics(SM_CYHSCROLL);
}

BOOL CHXWinSite::_IsWindowVisible()
{
    BOOL siteVisible = FALSE;

    RECT overAllrect;
    HXxWindow* pwindow = GetWindow();
    if (pwindow && pwindow->window)
    {
        HDC hdc = GetDC((HWND)pwindow->window);
        int retVal = GetClipBox(hdc, &overAllrect);
        if (retVal != NULLREGION)
        {
            siteVisible = TRUE;
        }
        ReleaseDC((HWND)pwindow->window, hdc);
    }
    return siteVisible;
}

void CHXWinSite::_ShowXSlider(BOOL bShow)
{
    if (m_hXSlider)
    {
        SafeShowWindow(m_hXSlider, bShow? SW_SHOW : SW_HIDE);
    }
}

void CHXWinSite::_MoveXSlider(INT32 left, INT32 top, INT32 right, INT32 bottom, BOOL bRedraw)
{
    if (m_hXSlider)
    {
        SafeMoveWindow(m_hXSlider, left, top, right, bottom, bRedraw);
    }
}

void CHXWinSite::_ShowYSlider(BOOL bShow)
{
    if (m_hYSlider)
    {
        SafeShowWindow(m_hYSlider, bShow? SW_SHOW : SW_HIDE);
    }
}

void CHXWinSite::_MoveYSlider(INT32 left, INT32 top, INT32 right, INT32 bottom, BOOL bRedraw)
{
    if (m_hYSlider)
    {
        SafeMoveWindow(m_hYSlider, left, top, right, bottom, bRedraw);
    }
}

BOOL CHXWinSite::_DoesXSliderExist()
{
    return m_hXSlider ? TRUE : FALSE;
}

void CHXWinSite::_GetCursorPos(HXxPoint* ptMouse)
{
    POINT pt;
    GetCursorPos(&pt);
    ptMouse->x = pt.x;
    ptMouse->y = pt.y;
}

void* CHXWinSite::_GetWindowWithCursor()
{
    HXxPoint pt;
    _GetCursorPos(&pt);
    return (void*)WindowFromPoint(WINPOINT(pt));
}

void CHXWinSite::_MapPointToOSWindow(HXxPoint* pPt, void** pWindowHandle)
{
    //    pWindowHandle = (void*) WindowFromPoint(WINPOINT(*pPt));
}

void CHXWinSite::SetCaptureMessage(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HXxEvent theEvent;

    if (m_pTopLevelSite->m_bSetCaptureOn)
    {
        /*
         *  XXXAH I have to figure out if I have to translate the x and y coords to
         *        some other origin when I find a renderer that exercises this code.
         */

        theEvent.event  = message;
        theEvent.window = (void*)hWnd;
        theEvent.param1 = (void*)wParam;
        theEvent.param2 = (void*)lParam;
        theEvent.result = 0;
        theEvent.handled = FALSE;

        if( m_pTopLevelSite->m_pCaptureUser )
            m_pTopLevelSite->m_pCaptureUser->HandleEvent(&theEvent);
    }
}

void CHXWinSite::_ReInitPrimarySurface()
{
    WINDRAW* pWindraw = ((CWinBaseRootSurface*)m_pRootSurface)->GetWinDraw();
    WinDraw2_RestorePrimarySurface(pWindraw);
}

void* CHXWinSite::_GetContainingWindow()
{
    return m_pContainingWindow->GetWindow();
}




/************************************************************************
 *  Class: CHXWinFullScreenWindow
 *
 *  The window used to contain the full screen windows.
 */


UINT32  CHXWinFullScreenWindow::zm_nInstanceCount           = 0;
char*   CHXWinFullScreenWindow::zm_pszWindowClassName       = "HXFullScreenWindowClass";
char*   CHXWinFullScreenWindow::zm_pszWindowName            = "HXFullScreenWindow";
BOOL    CHXWinFullScreenWindow::zm_bHideFullScreenWindow    = FALSE;

#define FULL_SCREEN_WINDOW_CLASSNAME

CHXWinFullScreenWindow::CHXWinFullScreenWindow(CHXWinSite* pSite) :
    m_hWnd(0)
                                                                  ,       m_pWindowless(pSite)
                                                                  ,       m_bIsVisible(FALSE)
{
}

CHXWinFullScreenWindow::~CHXWinFullScreenWindow()
{
    Destroy();
}

void
CHXWinFullScreenWindow::RegisterClass()
{
    if (0 == zm_nInstanceCount)
    {
        WNDCLASS wndClass;
        ATOM result;

        wndClass.style = CS_HREDRAW | CS_VREDRAW;
        wndClass.lpfnWndProc = CHXWinFullScreenWindow::WindowProc;
        wndClass.cbClsExtra = 0;
        wndClass.cbWndExtra = sizeof(this);
        wndClass.hInstance = GetModuleHandle(NULL);
        wndClass.hIcon = NULL;
        wndClass.hCursor = NULL;
        wndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
        wndClass.lpszMenuName = NULL;
        wndClass.lpszClassName = zm_pszWindowClassName;

        result = ::RegisterClass(&wndClass);
        HX_ASSERT(result);
    }
    zm_nInstanceCount++;
}

void
CHXWinFullScreenWindow::UnRegisterClass()
{
    HX_ASSERT(zm_nInstanceCount > 0);

    if (zm_nInstanceCount > 0)
    {
        zm_nInstanceCount--;
    }

    if (0 == zm_nInstanceCount)
    {
        BOOL result = ::UnregisterClass(zm_pszWindowClassName,GetModuleHandle(NULL));
        HX_ASSERT(result);
    }
}

HX_RESULT CHXWinFullScreenWindow::Create()
{
/*
 * Make sure the window class is registered.
 */

    RegisterClass();

    HXxWindow* ptempWindow = m_pWindowless->GetWindow();

    HWND hwnd = (HWND) ptempWindow->window;
    HWND oldHwnd = hwnd;

    while(hwnd)
    {
        hwnd = ::GetParent(hwnd);
        if (hwnd)
            oldHwnd = hwnd;
    }


    HWND parentWindow = GetParent((HWND)ptempWindow->window);

    m_hWnd = CreateWindowEx(
        NULL,
        zm_pszWindowClassName,
        zm_pszWindowName,
        WS_POPUP,
        0,
        0,
        100,
        100,
        oldHwnd,
        NULL,
        GetModuleHandle(NULL),
        NULL);

    if (!m_hWnd)
        return HXR_FAIL;

    SetWindowLong( m_hWnd, GWL_USERDATA, (long) this );

    return HXR_OK;
}

HX_RESULT CHXWinFullScreenWindow::Destroy()
{
    if (m_hWnd)
    {
        BOOL bDidDestroy = ::DestroyWindow(m_hWnd);
#ifdef _DEBUGGING_DESTROY_WINDOWS
        HX_ASSERT(bDidDestroy);
#endif
        m_hWnd = 0;
        UnRegisterClass();
        return HXR_OK;
    }

    return HXR_FAIL;
}


HX_RESULT CHXWinFullScreenWindow::Show()
{
    if (m_hWnd)
    {
        // resize the window the full screen
        int temp_sx = GetSystemMetrics(SM_CXSCREEN);
        int temp_sy = GetSystemMetrics(SM_CYSCREEN);

        // when we exit full screen mode via F1 the
        // full screen window gets minimized.

        ::ShowWindow(m_hWnd, SW_RESTORE);
#ifdef _HAMEL
        ::MoveWindow(m_hWnd, 0, 0, temp_sx, temp_sy, TRUE);
#else
        ::SetWindowPos(m_hWnd, HWND_TOPMOST, 0, 0, temp_sx, temp_sy, NULL);
#endif

        ::ShowWindow(m_hWnd, SW_SHOW);

        m_bIsVisible = TRUE;
        m_hOldForegroudWindow = GetForegroundWindow();

        // from HXGui ...
        DWORD   dwLockTimeout = 0;

        // These are new flags that work on Win98 and WinNT5 ONLY.  First get the current foreground lock timeout and save
        // it off and then set it to 0.
        ::SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT,0,&dwLockTimeout,0);
        ::SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,0,0,0);

        // We should actually be able to become the foreground window now
        SetForegroundWindow(m_hWnd);

        // Restore the old foreground lock timeout
        ::SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,0,(PVOID)dwLockTimeout,0);

        m_hOldFocus = SetFocus(m_hWnd);
        ::SetActiveWindow(m_hWnd);

        return HXR_OK;
    }
    return HXR_FAIL;
}

HX_RESULT CHXWinFullScreenWindow::Hide()
{
    if (m_hWnd)
    {
        m_bIsVisible = FALSE;
#ifdef _ALAINDEBUG
        ::MoveWindow(m_hWnd, 0, 0, 100, 100, FALSE);
#else
        ::SetWindowPos(m_hWnd, HWND_NOTOPMOST , 0, 0, 100, 100, NULL);
#endif
        ::ShowWindow(m_hWnd, SW_HIDE);

        DWORD   dwLockTimeout = 0;

        // These are new flags that work on Win98 and WinNT5 ONLY.  First get the current foreground lock timeout and save
        // it off and then set it to 0.
        ::SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT,0,&dwLockTimeout,0);
        ::SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,0,0,0);

        // We should actually be able to become the foreground window now
        SetForegroundWindow(m_hOldForegroudWindow);

        // Restore the old foreground lock timeout
        ::SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,0,(PVOID)dwLockTimeout,0);

        ::SetFocus(m_hOldFocus);
        return HXR_OK;
    }
    return HXR_FAIL;
}

/************************************************************************
 *  Method:
 *    CHXWinFullScreenWindow::WindowProc
 *
 */
LRESULT HXEXPORT
CHXWinFullScreenWindow::WindowProc
(
    HWND    hWnd,
    UINT    message,
    WPARAM  wParam,
    LPARAM  lParam
    )
{
    CHXWinFullScreenWindow* pThis = NULL;

    pThis = (CHXWinFullScreenWindow*)GetWindowLong( hWnd, GWL_USERDATA );

    if (pThis != NULL)
    {
        switch( message )
        {
#ifndef _HAMEL
           case WM_ACTIVATE:
           {
               BOOL bIsActive = (BOOL)wParam;

               if (bIsActive==WA_INACTIVE && pThis->m_bIsVisible)
               {
                   pThis->ForceExitFullScreen(WM_CHAR, VK_ESCAPE, 0);
               }
           }
           break;
           case WM_ACTIVATEAPP:
           {
               BOOL    fActive = (BOOL) wParam;        // activation flag

               if (!fActive && pThis->m_bIsVisible)
               {
                   pThis->ForceExitFullScreen(WM_CHAR, VK_ESCAPE, 0);
               }
           }
           break;
           case WM_SYSKEYUP:
           {
               if (wParam == VK_TAB && pThis->m_bIsVisible)
               {
                   pThis->ForceExitFullScreen(WM_CHAR, VK_ESCAPE, 0);
               }
           }
           break;
#endif
           case WM_CLOSE:
           {
               pThis->ForceExitFullScreen(WM_CHAR, VK_ESCAPE, 0);
               return 0;
           }
           case WM_SYSCOMMAND:
           {
               int uCmdType = wParam;

               if (wParam == SC_SCREENSAVE)
               {
                   return 1;
               }
               else
               {
                   return DefWindowProc(hWnd, message, wParam, lParam);
               }
           }

        }
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
}

void CHXWinFullScreenWindow::ForceExitFullScreen(UINT message, WPARAM  wParam, LPARAM  lParam)
{
    IHXSiteUser* pUser = NULL;

    if (m_pWindowless->GetUser(pUser) == HXR_OK && pUser)
    {
        HXxWindow* pwin = m_pWindowless->GetWindow();

        HXxEvent event = {message, (void*)pwin->window, (void*)wParam, (void*)lParam, 0, 0};
        pUser->HandleEvent(&event);
        HX_RELEASE(pUser);
    }
}

// crap from windowless here


void CHXWinSite::_SetFocus(void* pWindow)
{
    HX_ASSERT( pWindow );
    HWND hTmp = ::GetForegroundWindow();
    if( ::IsChild(hTmp, (HWND)GetWindow()->window ))
    {
        ::SetFocus((HWND)pWindow);
    }
}

BOOL CHXWinSite::_SetWindowRgn(void* hWnd, HXREGION* hRgn, BOOL bRedraw)
{
    HX_ASSERT( hWnd );

    HRGN rgn = CreateRectRgn(0,0,0,0);
    for(int i = 0; i< hRgn->numRects; i++)
    {
        HRGN tempRgn = CreateRectRgn(   hRgn->rects[i].x1 - m_topleft.x,
                                        hRgn->rects[i].y1 - m_topleft.y,
                                        hRgn->rects[i].x2 - m_topleft.x,
                                        hRgn->rects[i].y2 - m_topleft.y);
        CombineRgn(rgn, tempRgn, rgn, RGN_OR);
        DeleteObject(tempRgn);
    }

    int returnVal = ::SetWindowRgn((HWND)hWnd,rgn,bRedraw);

    //    DeleteObject(rgn);  OMG. What a messed up API.
    return returnVal;
}


BOOL CHXWinSite::_SetWindowPos(void* hWnd,
                               void* hWndInsertAfter,
                               INT32 X,
                               INT32 Y,
                               INT32 cx,
                               INT32 cy,
                               INT32 uFlags)
{
    // XXXSMJ As far as I can tell this is only a Windows thing and there aren't any
    // RMA flags.  This gets called from SafeSetWindowPos which in turn is only
    // called from WinSite.
    HX_ASSERT( GetWindow() );
    return ::SetWindowPos((HWND)hWnd,(HWND)hWndInsertAfter,X,Y,cx,cy,uFlags);
}

BOOL CHXWinSite::_MoveWindow( void* win,
                              INT32 X,
                              INT32 Y,
                              INT32 nWidth,
                              INT32 nHeight,
                              BOOL bRepaint)
{
    HX_ASSERT( GetWindow() );
    return ::MoveWindow((HWND)win,X,Y,nWidth,nHeight,bRepaint);
}

BOOL CHXWinSite::_ShowWindow(void* hWnd, INT32 nCmdShow)
{
    HX_ASSERT( GetWindow() );
    HX_ASSERT( nCmdShow==HX_SHOW_WINDOW || nCmdShow==HX_HIDE_WINDOW);

    int flags = (nCmdShow & HX_SHOW_WINDOW) ? SW_SHOW : SW_HIDE;
    ::ShowWindow((HWND)hWnd, flags);
    return TRUE;
}

BOOL CHXWinSite::_UpdateWindow(void* hWnd)
{
    return ::UpdateWindow((HWND)hWnd);
}

void CHXWinSite::_GetWindowRect(HXxRect* destRect)
{
    HX_ASSERT( GetWindow() );
    ::GetWindowRect((HWND)GetWindow()->window,(RECT*)destRect);
}

HX_RESULT CHXWinSite::_EventOccurred(HXxEvent* pEvent)
{
    return HXR_OK;
}

void CHXWinSite::_DamageRegion(HXxRegion pRegion)
{
    HXREGION* reg = (HXREGION*)pRegion;
    HXxRect rect;

    rect.left   = reg->extents.x1;
    rect.top    = reg->extents.y1;
    rect.right  = reg->extents.x2;
    rect.bottom = reg->extents.y2;

    _DamageRect(rect);
}

BOOL CHXWinSite::_ConvertToHXEvent(HXxEvent* pEvent)
{
    switch( pEvent->event )
    {
       case WM_KEYUP:
           pEvent->event = HX_KEY_UP;
           break;
       case WM_KEYDOWN:
           pEvent->event = HX_KEY_DOWN;
           break;
       case WM_CHAR:
           pEvent->event = HX_CHAR;
           break;
       case WM_LBUTTONUP:
           pEvent->event = HX_PRIMARY_BUTTON_UP;
           break;
       case WM_LBUTTONDOWN:
           pEvent->event = HX_PRIMARY_BUTTON_DOWN;
           break;
       case WM_RBUTTONUP:
           pEvent->event = HX_CONTEXT_BUTTON_UP;
           break;
       case WM_RBUTTONDOWN:
           pEvent->event = HX_CONTEXT_BUTTON_DOWN;
           break;
       case WM_MOUSEMOVE:
           pEvent->event = HX_MOUSE_MOVE;
           break;
       case WM_SETFOCUS:
           pEvent->event = HX_SET_FOCUS;
           break;
       case WM_KILLFOCUS:
           pEvent->event = HX_LOSE_FOCUS;
           break;
       case WM_LBUTTONDBLCLK:
           pEvent->event = HX_PRIMARY_DBLCLK;
           break;
       case WM_RBUTTONDBLCLK:
           pEvent->event = HX_CONTEXT_DBLCLK;
           break;
       default:
           HX_ASSERT("unkown event type...." );
    }

    return pEvent->handled;
}

void CHXWinSite::_DrawFocusRect(UCHAR* pImage,
                                HXBitmapInfoHeader* pImageInfo,
                                HXxRect* pImageSize,
                                void* pOsSpecificData)
{
#if 1
    CHXBaseSite::_DrawFocusRect(pImage,
                                pImageInfo,
                                pImageSize,
                                pOsSpecificData);
    return;
#else

    // Do we have an active rect
    if (!m_rcFocusRect.bRectActive)
        return;

    // Only support rgb for now
    if (IsYUV(GETBITMAPCOLOR(pImageInfo)))
        return;

    if (!pOsSpecificData)
        return;

    HDC hdc = *((HDC*)pOsSpecificData);

    // Create the proper pen style and color
    UINT32  ulPenStyle = PS_SOLID;

    if (m_rcFocusRect.ulLineStyle == HX_DASHED_LINE)
        ulPenStyle = PS_DASH;
    else if (m_rcFocusRect.ulLineStyle == HX_DOTTED_LINE)
        ulPenStyle = PS_DOT;

    HPEN hPen = CreatePen(ulPenStyle,
                          m_rcFocusRect.ulLineWidth,
                          RGB(m_rcFocusRect.red,
                              m_rcFocusRect.green,
                              m_rcFocusRect.blue));

    HGDIOBJ hOldPen = SelectObject(hdc, hPen);

    POINT p;
    if (m_rcFocusRect.ulShape & DRAW_RECT)
    {
        // Draw the rect
        MoveToEx(hdc, m_rcFocusRect.rcFocus.left, m_rcFocusRect.rcFocus.bottom, &p);

        LineTo(hdc, m_rcFocusRect.rcFocus.left, m_rcFocusRect.rcFocus.top);
        LineTo(hdc, m_rcFocusRect.rcFocus.right, m_rcFocusRect.rcFocus.top);
        LineTo(hdc, m_rcFocusRect.rcFocus.right, m_rcFocusRect.rcFocus.bottom);
        LineTo(hdc, m_rcFocusRect.rcFocus.left, m_rcFocusRect.rcFocus.bottom);
    }
    else if (m_rcFocusRect.ulShape & DRAW_ELLIPSE)
    {
        // Draw the ellipse
        MoveToEx(hdc,
                 m_rcFocusRect.rcFocus.left,
                 (m_rcFocusRect.rcFocus.bottom-m_rcFocusRect.rcFocus.top)/2,
                 &p);

        ArcTo(hdc,
              m_rcFocusRect.rcFocus.left, m_rcFocusRect.rcFocus.top,
              m_rcFocusRect.rcFocus.right, m_rcFocusRect.rcFocus.bottom,
              m_rcFocusRect.rcFocus.left,
              (m_rcFocusRect.rcFocus.bottom-m_rcFocusRect.rcFocus.top)/2,
              m_rcFocusRect.rcFocus.left,
              (m_rcFocusRect.rcFocus.bottom-m_rcFocusRect.rcFocus.top)/2);
    }
    else if (m_rcFocusRect.ulShape & DRAW_POLYGON)
    {
        // Draw the polygon
        MoveToEx(hdc,
                 m_rcFocusRect.polygon.pFocusPoints[m_rcFocusRect.polygon.ulFocusPoints-1].x,
                 m_rcFocusRect.polygon.pFocusPoints[m_rcFocusRect.polygon.ulFocusPoints-1].y,
                 &p);

        PolylineTo(hdc, (CONST POINT*)(m_rcFocusRect.polygon.pFocusPoints), m_rcFocusRect.polygon.ulFocusPoints);
    }

    // Resotre old pen
    SelectObject(hdc, hOldPen);
    DeleteObject(hPen);
#endif
}

void CHXWinSite::CheckCapture()
{

    HWND                captureHwnd = GetCapture();
    CHXWinSite*  pTempThis   = NULL;

    if (m_pTopLevelSite && !m_pTopLevelSite->m_bSetCaptureOn)
    {
        if (CHXWinSite::zm_SubclassedWnds.Lookup((void*)captureHwnd,(void*&)pTempThis))
        {
            m_pTopLevelSite->m_bSetCaptureOn = TRUE;
            m_pTopLevelSite->m_pCaptureUser = m_pTopLevelSite->m_pLastUser;
        }
    }
}

void CHXWinSite::ReHookParents()
{
    //Remove all hooks.
    HWND hWnd;
    CHXSimpleList* pChildrenList;
    POSITION pos = CHXWinSite::zm_ParentWnds.GetStartPosition();
    while(pos)
    {
        zm_ParentWnds.GetNextAssoc(pos, (void*&) hWnd, (void*&) pChildrenList);
        pChildrenList->RemoveAll();
        HX_DELETE(pChildrenList);
    }
    CHXWinSite::zm_ParentWnds.RemoveAll();
    CHXMapPtrToPtr::Iterator i = m_ChildrenMap.Begin();
    for ( ; i != m_ChildrenMap.End(); ++i)
    {
        CHXBaseSite* pSite = (CHXBaseSite*) *i;
        HWND hWnd = (HWND)(pSite->GetWindow()->window);
        HX_ASSERT( hWnd );

        while (hWnd)
        {
            CHXSimpleList* pChildrenList;
            if (!CHXWinSite::zm_ParentWnds.Lookup((void*)hWnd,(void*&) pChildrenList))
            {
                pChildrenList = new CHXSimpleList;
                CHXWinSite::zm_ParentWnds.SetAt((void*)hWnd, (void*)pChildrenList);
            }

            LISTPOSITION pos = pChildrenList->Find(pSite);
            HX_ASSERT(pos == NULL);
            if (!pos)
            {
                pChildrenList->AddTail(pSite);
            }
            hWnd = GetParent(hWnd);
        }
    }
}
