/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: unixsite.cpp,v 1.4.4.8 2004/07/22 23:25:26 nhart 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):
 *                 Phil Dibowitz
 * 
 * ***** END LICENSE BLOCK ***** */

#ifndef _UNIX
#error This is the UNIX platform specific implementation.
#endif

//
// System includes...
//
#include <stdio.h>
#include "hlxclib/string.h"
#include <X11/Intrinsic.h>
#include <X11/Shell.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/Xos.h>
#include <X11/cursorfont.h>
#include <X11/extensions/XShm.h>


//
// RMA includes...
//
#include "hxcom.h"
#include "hxcore.h"
#include "hxevent.h"
#include "hxwintyp.h"
#include "hxwin.h"
#include "hxsite2.h"
#include "hxtypes.h"
#include "unixsite.h"
#include "unixcmap.h"
#include "visuals.h"
#include "region.h"
#include "basesurf.h"
#include "unixroot.h"
#include "hxthread.h"
#include "hxtick.h"
#include "sitetext.h"

#include "unixsurf.h"

#include "hxprefs.h"

//
// Global & Static global/member data....
//
Display *CHXUnixSite::zm_display = NULL;
static CHXMapPtrToPtr z_mapSiteToWindow;

//
// Scroll bar support
//
#define SCROLL_BAR_WIDTH 13        //Width of scroll bar.
//#define _ARROWS_SIDE_BY_SIDE 1   //Regular or side by side arrows?




//
// CHXUnixSite only Methods...
//
CHXUnixSite::CHXUnixSite( IUnknown* pContext, IUnknown* pUnkOuter, INT32 lInitialZorder)
   : CHXBaseSite( pContext, pUnkOuter, lInitialZorder )
   , m_pUnixEventHandler(NULL)
   , m_ScrollHorizButtonL(0)
   , m_ScrollHorizButtonR(0)
   , m_ScrollVertButtonT(0)
   , m_ScrollVertButtonB(0)
   , m_winFullScreenWindow(0)
   , m_winOldParent(0)
   , m_bScrollingInProgress(FALSE)
   , m_nScrollDir(0)
   , m_bLastPointInSite(FALSE)
   , m_bDamaged(FALSE)
   , m_bIgnoreFocusOutInFS(FALSE)
{
   m_ptScrollVertPosT.x   = m_ptScrollVertPosT.y   = 0;
   m_ptScrollVertPosB.x   = m_ptScrollVertPosB.y   = 0;
   m_ptScrollHorizPosR.x  = m_ptScrollHorizPosR.y  = 0;
   m_ptScrollHorizPosL.x  = m_ptScrollHorizPosL.y  = 0;
   m_ptFullScreenOffset.x = m_ptFullScreenOffset.y = 0;
   memset( &m_PreFullScreenSize, 0, sizeof( m_PreFullScreenSize ) );
   
   HX_ASSERT( m_pContext );
   IHXPreferences* pPreferences = NULL;   
   if( m_pContext && HXR_OK == m_pContext->QueryInterface( IID_IHXPreferences, (void **) &pPreferences))
   { 
       IHXBuffer *pBuffer = NULL;
       pPreferences->ReadPref("IgnoreFocusOutInFS", pBuffer);
       if(pBuffer)
       {
           m_bIgnoreFocusOutInFS = (::atoi((const char*)pBuffer->GetBuffer()) == 1);
           HX_RELEASE(pBuffer);
       }
   }
}

CHXUnixSite::~CHXUnixSite()
{   
   void* pDummy; 
   if (z_mapSiteToWindow.Lookup((void*)this, pDummy))
   {
      z_mapSiteToWindow.RemoveKey((void*)this);
   }

   if( m_pUnixEventHandler )
   {
      m_pUnixEventHandler->CancelCallback();
      HX_RELEASE(m_pUnixEventHandler);
   }
}

HX_RESULT CHXUnixSite::_OpenXDisplay(char* pszDisplayString)
{
   HX_RESULT retVal = HXR_OK;
    
   //Is the connection open already?
   if( NULL==zm_display )
   {
      zm_display = XOpenDisplay(pszDisplayString);
      
      //If you can't open the display your done.
      if(NULL == zm_display )
      {
         HX_ASSERT("Can't open X Display..."==NULL);
         retVal = HXR_FAIL;
      }
      else
      {
         HX_ASSERT(m_pScheduler);
         if( m_pScheduler )
         {
            //UnixEventHandler scheduls itself for init callback
            //in the ctor.
            m_pUnixEventHandler = new UnixEventHandler(this);
            m_pUnixEventHandler->AddRef();
         }
      }
   }
   return retVal;
}

Window CHXUnixSite::CreateXWindow( Window win )
{
   Window     parentWindow;
   HXxWindow* pWindow = NULL;
   //If parentWin is NULL then we belong to the root window.    
   if( win )
   {
      parentWindow = win;
   }
   else
   {
      HX_ASSERT(zm_display);
      XLockDisplay(zm_display);
      parentWindow = RootWindow(zm_display, DefaultScreen(zm_display));
      XUnlockDisplay(zm_display);      
   }
    
   //Find the best visual to use on this display.
   Visual* visual = GetBestVisual(zm_display);

   //Get the visual info.
   int         nNotUsed=0;
   XVisualInfo stVisInfo;
    
   memset(&stVisInfo, 0, sizeof(XVisualInfo));
   stVisInfo.visualid = XVisualIDFromVisual(visual);
   XLockDisplay(zm_display);
   XVisualInfo* pVisual = XGetVisualInfo( zm_display,
                                          VisualIDMask,
                                          &stVisInfo,
                                          &nNotUsed );
   XUnlockDisplay(zm_display);

   // Set up attributes of the window.
   int                  attrMask = CWBackPixel | CWBorderPixel;
   XSetWindowAttributes attr;
    
   memset(&attr, 0, sizeof(XSetWindowAttributes));
   XLockDisplay(zm_display);
   attr.background_pixel = BlackPixel(zm_display, DefaultScreen(zm_display));
   attr.border_pixel     = BlackPixel(zm_display, DefaultScreen(zm_display));
   XUnlockDisplay(zm_display);
   
   //See if the default visaul of hte screen is the same one we Want
   //to use. If not, create a new one and install it.
   Colormap cmap;
   XLockDisplay(zm_display);
   Visual*  defVisual = DefaultVisual(zm_display, DefaultScreen(zm_display));
   XUnlockDisplay(zm_display);
   if( defVisual->visualid != stVisInfo.visualid )
   {
      //XXXgfw Are we leaking this colormap????
      XLockDisplay(zm_display);
      cmap = XCreateColormap(zm_display, parentWindow, visual, AllocNone);
      XUnlockDisplay(zm_display);
      attr.colormap = cmap;
      attrMask |= CWColormap;
   }

   // Set the size/position of the window before creating.
   XSizeHints size_hints;

   size_hints.flags  = PPosition | PSize;
   size_hints.x      = m_position.x;
   size_hints.y      = m_position.y;
   size_hints.width  = 1;
   size_hints.height = 1;

   //Create it.
   XLockDisplay(zm_display);
   Window window = XCreateWindow(zm_display, 
                                 parentWindow,
                                 size_hints.x,
                                 size_hints.y,
                                 size_hints.width,
                                 size_hints.height, 
                                 0,
                                 pVisual->depth,
                                 InputOutput,
                                 visual,
                                 attrMask,
                                 &attr);
   XUnlockDisplay(zm_display);
   XFree(pVisual);

   //Tell the WM about this window.
#if 0
   XSetStandardProperties( zm_display,
                           window,
                           "CHXUnixSite",
                           "CHXUnixSite",
                           None,
                           NULL, 0,
                           &size_hints
                           );
#endif

   //Select all input events on the window since the other platforms
   //we work with have no concept of event masks
   XLockDisplay(zm_display);   
   int result = XSelectInput( zm_display, window,
                              ButtonPressMask   | ButtonReleaseMask | KeyPressMask    |
                              KeyReleaseMask    | EnterWindowMask   | LeaveWindowMask |
                              PointerMotionMask | ButtonMotionMask  | KeymapStateMask |
                              ExposureMask      | StructureNotifyMask | FocusChangeMask
                              );
   XUnlockDisplay(zm_display);
   if( BadWindow == result )
   {
#ifdef _DEBUG
      fprintf( stderr, "Can select events.\n" );
#endif      
   }
   
   //Map the window.
   XLockDisplay(zm_display);
   XMapWindow(zm_display, window);

   //Flush event queue.
   XFlush(zm_display);
   XUnlockDisplay(zm_display);


   return window;
}

void CHXUnixSite::_MapHorzScroll()
{
   if( GetWindow() && GetWindow()->display && m_ScrollHorizButtonL)
   {
      Display* pDis = (Display*)GetWindow()->display;
      XLockDisplay(pDis);
      XMapWindow( pDis, m_ScrollHorizButtonL );
      XMapWindow( pDis, m_ScrollHorizButtonR ); 
      XUnlockDisplay(pDis);
   }
   _DrawArrows();
}

void CHXUnixSite::_MapVertScroll()
{
   if( GetWindow() && GetWindow()->display && m_ScrollVertButtonT)
   {
      Display* pDis = (Display*)GetWindow()->display;
      XLockDisplay(pDis);
      XMapWindow( pDis, m_ScrollVertButtonT );
      XMapWindow( pDis, m_ScrollVertButtonB );
      XUnlockDisplay(pDis);
   }
   _DrawArrows();
}

void CHXUnixSite::_MapScrollButtons()
{
   _MapHorzScroll();
   _MapVertScroll();
}

void CHXUnixSite::_UnmapHorzScroll()
{
   HX_ASSERT( GetWindow() );
   if( m_ScrollHorizButtonL && GetWindow()->display )
   {
      Display* pDis = (Display*)GetWindow()->display;
      XLockDisplay(pDis);
      XUnmapWindow( pDis, m_ScrollHorizButtonL );
      XUnmapWindow( pDis, m_ScrollHorizButtonR );
      XUnlockDisplay(pDis);
   }
}
void CHXUnixSite::_UnmapVertScroll()
{
   HX_ASSERT( GetWindow() );
   if( m_ScrollVertButtonT && GetWindow()->display )
   {
      Display* pDis = (Display*)GetWindow()->display;
      XLockDisplay(pDis);
      XUnmapWindow( pDis, m_ScrollVertButtonT );
      XUnmapWindow( pDis, m_ScrollVertButtonB ); 
      XUnlockDisplay(pDis);
   }
}

void CHXUnixSite::_UnmapScrollButtons()
{
   if( GetWindow() )
   {
      _UnmapVertScroll();
      _UnmapHorzScroll();
   }
}

void CHXUnixSite::_DestroyScrollButtons()
{
    if (GetWindow())
    {
	Display* pDis = (Display*)GetWindow()->display;
	if( m_ScrollHorizButtonL && pDis )
	{
	    XLockDisplay(pDis);
	    XDestroyWindow( pDis, m_ScrollHorizButtonL );
	    m_ScrollHorizButtonL = 0;
	    XDestroyWindow( pDis, m_ScrollHorizButtonR );
	    XUnlockDisplay(pDis);
	    m_ScrollHorizButtonR = 0;
	}
	if( m_ScrollVertButtonT && pDis)
	{
	    XLockDisplay(pDis);
	    XDestroyWindow( pDis, m_ScrollVertButtonT );
	    m_ScrollVertButtonT = 0;
	    XDestroyWindow( pDis, m_ScrollVertButtonB );
	    XUnlockDisplay(pDis);
	    m_ScrollVertButtonB = 0;
	}

	m_ptScrollVertPosT.x = m_ptScrollVertPosT.y = 0;
	m_ptScrollVertPosB.x = m_ptScrollVertPosB.y = 0;
	m_ptScrollHorizPosR.x = m_ptScrollHorizPosR.y = 0;
	m_ptScrollHorizPosL.x = m_ptScrollHorizPosL.y = 0;
    }
}

void CHXUnixSite::_DrawArrows()
{
   //only do the work if our site is visible.
   if( !IsSiteVisible() )
      return;
    
    //Draw an arrow on this window.
   XPoint points[4];
   int offset = SCROLL_BAR_WIDTH/10;
   GC tmpGC;
   XGCValues values;
   Display* dis = (Display*)GetWindow()->display;

   if( m_ScrollVertButtonB )
   {
      XLockDisplay(dis);
      tmpGC = XCreateGC( dis, m_ScrollVertButtonB, 0, &values );
      XUnlockDisplay(dis);
   }
   else if( m_ScrollHorizButtonL )
   {
      XLockDisplay(dis);
      tmpGC = XCreateGC( dis, m_ScrollHorizButtonL, 0, &values );
      XUnlockDisplay(dis);
   }
   else
   {
      //We don't have any scroll bars to draw....
      return;
   }
   

   XLockDisplay(dis);
   XSetForeground( dis, tmpGC, WhitePixel(dis, 0 ));
   XSetBackground( dis, tmpGC, BlackPixel(dis, 0 ));
   XUnlockDisplay(dis);
   Colormap cmap = HXGetXColormap((Display*)GetWindow()->display,
                                   (Window)GetWindow()->window);
   XColor color;
    
   memset(&color, 0, sizeof(XColor));
   XLockDisplay(dis);
   XParseColor(dis, cmap, "blue", &color);
   XUnlockDisplay(dis);
   HXFindBestXColor(dis, cmap, &color);
   XLockDisplay(dis);
   XSetForeground( dis, tmpGC, color.pixel);
   XSetLineAttributes(dis, tmpGC, 1, LineSolid, CapRound, JoinRound );
   XUnlockDisplay(dis);


   //Draw up Vertical arrow.
   if( m_ScrollVertButtonT )
   {
      points[0].x = offset;
      points[0].y = SCROLL_BAR_WIDTH-offset;
      points[1].x = SCROLL_BAR_WIDTH/2;
      points[1].y = offset;
      points[2].x = SCROLL_BAR_WIDTH-offset;
      points[2].y = SCROLL_BAR_WIDTH-offset;
      points[3].x = points[0].x;
      points[3].y = points[0].y;
      XLockDisplay(dis);
      XFillPolygon( dis, m_ScrollVertButtonT, tmpGC, points, 4, Convex, CoordModeOrigin);
      XUnlockDisplay(dis);
   }
    
   //Draw down Vertical arrow.
   if( m_ScrollVertButtonB )
   {
      points[0].x = offset;
      points[0].y = offset;
      points[1].x = SCROLL_BAR_WIDTH-offset;
      points[1].y = offset;
      points[2].x = SCROLL_BAR_WIDTH/2;
      points[2].y = SCROLL_BAR_WIDTH-offset;
      points[3].x = points[0].x;
      points[3].y = points[0].y;
      XLockDisplay(dis);
      XFillPolygon( dis, m_ScrollVertButtonB, tmpGC, points, 4, Convex, CoordModeOrigin);
      XUnlockDisplay(dis);
   }
    
   //Draw Left Horizontal arrow.
   if( m_ScrollHorizButtonL )
   {
      points[0].x = SCROLL_BAR_WIDTH-offset;
      points[0].y = offset;
      points[1].x = SCROLL_BAR_WIDTH-offset;
      points[1].y = SCROLL_BAR_WIDTH-offset;
      points[2].x = offset;
      points[2].y = SCROLL_BAR_WIDTH/2;
      points[3].x = points[0].x;
      points[3].y = points[0].y;
      XLockDisplay(dis);
      XFillPolygon( dis, m_ScrollHorizButtonL, tmpGC, points, 4, Convex, CoordModeOrigin);
      XUnlockDisplay(dis);
   }
    
   //Draw Right Horizontal arrow.
   if( m_ScrollHorizButtonR )
   {
      points[0].x = offset;
      points[0].y = SCROLL_BAR_WIDTH-offset;
      points[1].x = offset;
      points[1].y = offset;
      points[2].x = SCROLL_BAR_WIDTH-offset;
      points[2].y = SCROLL_BAR_WIDTH/2;
      points[3].x = points[0].x;
      points[3].y = points[0].y;
      XLockDisplay(dis);
      XFillPolygon( dis, m_ScrollHorizButtonR, tmpGC, points, 4, Convex, CoordModeOrigin);
      XUnlockDisplay(dis);
   }
    
   //Free the GC and go.
   XLockDisplay(dis);
   XFreeGC( dis, tmpGC );
   XUnlockDisplay(dis);
}

BOOL CHXUnixSite::_InButton( HXxPoint& pt, int x, int y )
{
   BOOL retVal =FALSE;
   if( x>= pt.x && x< pt.x+SCROLL_BAR_WIDTH && y>=pt.y && y<pt.y+SCROLL_BAR_WIDTH )
      retVal=TRUE;
   else
      retVal=FALSE;

   return retVal;
}

void CHXUnixSite::_CreateHorizScrollBar()
{
   HX_ASSERT( m_ScrollHorizButtonL == 0 );
   HX_ASSERT( m_ScrollHorizButtonR == 0 );
    
   HXxSize  mySize;

   HXxWindow* pParentWindow = NULL;
   if(GetParentSite())
   {
      pParentWindow = GetParentSite()->GetWindow();
   }
   if(pParentWindow)
   {
      GetParentSite()->GetSize(mySize);
   }

   HX_ASSERT( pParentWindow );
   HX_ASSERT( pParentWindow->window != 0 );
    
   if( m_ScrollVertButtonB )
   {
      // if the other bar already exists, don't overlap it!
      mySize.cx -= SCROLL_BAR_WIDTH;
   }

   m_ptScrollHorizPosL.x = m_topleft.x;
   m_ptScrollHorizPosL.y = m_topleft.y+mySize.cy-SCROLL_BAR_WIDTH;

#ifndef _ARROWS_SIDE_BY_SIDE    
   m_ptScrollHorizPosR.x = m_topleft.x+mySize.cx-SCROLL_BAR_WIDTH;
#else    
   m_ptScrollHorizPosR.x = m_topleft.x+SCROLL_BAR_WIDTH;
#endif
   m_ptScrollHorizPosR.y = m_topleft.y+mySize.cy-SCROLL_BAR_WIDTH;

   Display* dis     = (Display*)GetWindow()->display;
   XLockDisplay(dis);
   Pixel blackPixel = BlackPixel( dis, DefaultScreen(dis) );
   XUnlockDisplay(dis);
   Pixel greyPixel  = blackPixel;

   Colormap cmap = HXGetXColormap(dis, (Window)GetWindow()->window);
   XColor color;
    
   XLockDisplay(dis);
   XParseColor(dis, cmap, "gray", &color);
   XUnlockDisplay(dis);
   HXFindBestXColor(dis, cmap, &color);
   greyPixel = color.pixel;

   XLockDisplay(dis);
   m_ScrollHorizButtonL = XCreateSimpleWindow( dis,
                                               (Window)pParentWindow->window,
                                               m_ptScrollHorizPosL.x, m_ptScrollHorizPosL.y,
                                               SCROLL_BAR_WIDTH, SCROLL_BAR_WIDTH,
                                               1,
                                               blackPixel,
                                               greyPixel
                                               );
   m_ScrollHorizButtonR = XCreateSimpleWindow( dis,
                                               (Window)pParentWindow->window,
                                               m_ptScrollHorizPosR.x, m_ptScrollHorizPosR.y,
                                               SCROLL_BAR_WIDTH, SCROLL_BAR_WIDTH,
                                               1,
                                               blackPixel,
                                               greyPixel
                                               );
   XUnlockDisplay(dis);
   HX_ASSERT( m_ScrollHorizButtonR && m_ScrollHorizButtonL );
    
}

void CHXUnixSite::_CreateVertScrollBar()
{
   HX_ASSERT( m_ScrollVertButtonB == 0 );
   HX_ASSERT( m_ScrollVertButtonT == 0 );
    
   HXxSize  mySize;

   HXxWindow* pParentWindow = NULL;
   if(GetParentSite())
   {
      pParentWindow = GetParentSite()->GetWindow();
   }
   if(pParentWindow)
   {
      GetParentSite()->GetSize(mySize);
   }

   HX_ASSERT( pParentWindow );
   HX_ASSERT( pParentWindow->window != 0 );
    
   if( m_ScrollHorizButtonR )
   {
      // if the other bar already exists, don't overlap it!
      mySize.cy -= SCROLL_BAR_WIDTH;
   }
    
    
   m_ptScrollVertPosT.x = m_topleft.x+mySize.cx-SCROLL_BAR_WIDTH;
   m_ptScrollVertPosT.y = m_topleft.y;

   m_ptScrollVertPosB.x = m_topleft.x+mySize.cx-SCROLL_BAR_WIDTH;
#ifndef _ARROWS_SIDE_BY_SIDE    
   m_ptScrollVertPosB.y = m_topleft.y+mySize.cy-SCROLL_BAR_WIDTH;
#else
   m_ptScrollVertPosB.y = m_topleft.y+SCROLL_BAR_WIDTH;
#endif    

   Display* dis     = (Display*)GetWindow()->display;
   XLockDisplay(dis);
   Pixel blackPixel = BlackPixel( dis, DefaultScreen(dis) );
   XUnlockDisplay(dis);
   Pixel greyPixel  = blackPixel;
   Colormap cmap = HXGetXColormap((Display*)GetWindow()->display,
                                   (Window)GetWindow()->window);
   XColor color;
   XLockDisplay(dis);
   XParseColor(dis, cmap, "gray", &color);
   XUnlockDisplay(dis);
   HXFindBestXColor(dis, cmap, &color);
   greyPixel = color.pixel;
    
   HX_ASSERT( GetWindow() );
   XLockDisplay(dis);
   m_ScrollVertButtonT = XCreateSimpleWindow( dis,
                                              (Window)pParentWindow->window,
                                              m_ptScrollVertPosT.x, m_ptScrollVertPosT.y,
                                              SCROLL_BAR_WIDTH, SCROLL_BAR_WIDTH,
                                              1,
                                              blackPixel,
                                              greyPixel
                                              );
   m_ScrollVertButtonB = XCreateSimpleWindow( dis,
                                              (Window)pParentWindow->window,
                                              m_ptScrollVertPosB.x, m_ptScrollVertPosB.y,
                                              SCROLL_BAR_WIDTH, SCROLL_BAR_WIDTH,
                                              1,
                                              blackPixel,
                                              greyPixel
                                              );
   XUnlockDisplay(dis);

   HX_ASSERT( m_ScrollVertButtonB && m_ScrollVertButtonT );

}

//
// Inherited CHXBaseSite methods.
//
void CHXUnixSite::_NeedWindowedSite()
{
#ifdef _DEBUG   
   fprintf( stderr, "CHXUnixSite::_NeedWindowedSite do something here....\n" );
#endif   
   //Nothing to do on unix....
}

void CHXUnixSite::_AttachWindow()
{
   void* pDummy=NULL; 
   if(!z_mapSiteToWindow.Lookup((void*)this, pDummy))
   {
      z_mapSiteToWindow.SetAt((void*)this, (void*)m_pWindow);
   }

   //Set the display variable.
   if( m_pWindow->display == NULL )
   {
      HX_ASSERT(zm_display);
      m_pWindow->display = zm_display;
   }
   
   //Now that we have a window be sure to init the CUnixRootSurf.
   //this lets it set up the display, colormap, etc.
   ((CUnixRootSurf*)m_pRootSurface)->Init();
}

void CHXUnixSite::_DetachWindow()
{
   void* pDummy; 

   if (z_mapSiteToWindow.Lookup((void*)this, pDummy))
   {
      z_mapSiteToWindow.RemoveKey((void*)this);
   }
}

void* CHXUnixSite::_Create(void* pParentWindow, UINT32 style)
{
   HRESULT result = HXR_OK;
   if( m_pWindow && m_pWindow->window )
   {
      HX_ASSERT( "We already have created a window"==NULL);
      return NULL;
   }

   if (pParentWindow==NULL || style)
   {
      m_bIsChildWindow = FALSE;
   }
   else
   {
      m_bIsChildWindow = TRUE;
   }

   if( _OpenXDisplay(NULL) != HXR_OK )
   {
      return NULL;
   }
   return (void*)CreateXWindow((Window)pParentWindow);
}


void CHXUnixSite::_Destroy(HXxWindow* pWindow)
{
    _DestroySliders();
    if (GetWindow())
    {
	Display* pDis = (Display*)GetWindow()->display;
	XLockDisplay(pDis);
	XDestroyWindow( pDis, (Window)pWindow->window );
	XUnlockDisplay(pDis);
    }
}

void CHXUnixSite::_SetSize(HXxSize size)
{
   HX_ASSERT( m_pWindow && m_pWindow->display && m_pWindow->window);
   //The scroll bars get resized also...
   _DestroySliders();
   Display* pDis = (Display*)GetWindow()->display;
   XLockDisplay(pDis);
   XResizeWindow(pDis,
                 (Window) m_pWindow->window,
                 size.cx,
                 size.cy);
   XUnlockDisplay(pDis);
}

void CHXUnixSite::_SetPosition(HXxPoint position)
{
   HX_ASSERT( m_pWindow && m_pWindow->display && m_pWindow->window);
   _DestroyScrollButtons();
   XLockDisplay((Display*) m_pWindow->display);
   XMoveWindow((Display*)m_pWindow->display,
               (Window)m_pWindow->window,
               position.x,
               position.y);
   XUnlockDisplay((Display*) m_pWindow->display);
}

void CHXUnixSite::_DamageRect(HXxRect rect)
{
   if(GetWindow())
   {    
      m_bDamaged = TRUE;
   }
   return;
}

void CHXUnixSite::_DamageRegion(HXxRegion rect)
{
   if(GetWindow())
   {    
      m_bDamaged = TRUE;
   }
   return;
}

void CHXUnixSite::_SendOSUpdateMessage()
{
   //We need to redraw our window here, m_pWindow.
}

void CHXUnixSite::_ShowSite(BOOL bShow)
{
   if( bShow )
   {
      _MapScrollButtons();
   }
   else
   {
      _UnmapScrollButtons();
   }
   //do nothing....
}

BOOL CHXUnixSite::_AtSystemTime()
{
   return TRUE;
}

void CHXUnixSite::_GetDeviceCaps( void* hdc,
                                  UINT16& uBitsPerPixel,
                                  UINT16& uHorzRes,
                                  UINT16& uVertRes )
{
   Screen* pScreen = NULL;
   HXxWindow* pWin = GetWindow();
   HX_ASSERT( pWin );
   if( pWin )
   {
       Display* dis = (Display*)pWin->display;
       HX_ASSERT( dis );
       if( dis )
       {
	   Display* pDisp = (Display*)GetWindow()->display;
	   XLockDisplay(pDisp);
           pScreen = DefaultScreenOfDisplay(pDisp);    
	   XUnlockDisplay(pDisp);
           
           uBitsPerPixel = pScreen->root_depth;
           uHorzRes      = pScreen->width;
           uVertRes      = pScreen->height;   
       }
   }
}

void CHXUnixSite::_GetWindowRect(HXxRect* destRect)
{
   HX_ASSERT( "Doesn't seem to be used anywhere"==NULL );
}

void CHXUnixSite::_DestroySliders()
{
   _DestroyScrollButtons();
}

void CHXUnixSite::_ForwardUpdateEvent(HXxEvent* pEvent)
{
   GC gc = NULL;
   AddRef();

   HX_ASSERT(GetWindow()->window);
   HX_ASSERT(m_pUser);
   if(m_bIsChildWindow)
   {
      //Create a clip region that excludes our higher z-order
      //siblings and is clipped to our parent.
      if( !m_bRegionIsValid )
      {
         RecomputeClip();
      }

      // The problem is that regions are locked to the origin so we
      // will need to reverse shift the region before we set the
      // origin of the graph port! get the GC from the video surface
      gc = ((CUnixRootSurf*)m_pRootSurface)->GetGC();
      HX_ASSERT( gc );
        
      //Actually setup our clip region
      Display* pDis = (Display*)GetWindow()->display;
      XLockDisplay(pDis);
      XSetRegion( pDis, gc, (Region) m_Region );
      XUnlockDisplay(pDis);
   }

   XEvent* pXEvent = (XEvent*) pEvent->param2; 
   XExposeEvent* exposeEvent = (XExposeEvent*) pXEvent;
   
   // get the rect for this site with respect to our parent
   HXRECTANGLE exposedRect = { exposeEvent->x,
                             exposeEvent->y,
                             exposeEvent->width,
                             exposeEvent->height };
   HXREGION* exposedRegion = HXCreateRegion();
   HXUnionRectWithRegion(&exposedRect, exposedRegion,  exposedRegion);
   
   // does the site intersect the current clipping region?
   HXREGION* resultRegion = HXCreateRegion();
   HXIntersectRegion(exposedRegion, m_Region, resultRegion);
   BOOL bSiteIntersectsExposed = (HXEmptyRegion(resultRegion)==FALSE);
   
   HXDestroyRegion(resultRegion);
   HXDestroyRegion(exposedRegion);
   
   // if the exposed region intersects the sites clipping region
   if(bSiteIntersectsExposed)
   {
      m_pUser->HandleEvent(pEvent);
   }
   
   //If the user doesn't handle the standard update event then send
   //them the cross platform HX_SURFACE_UPDATE event don't damage the
   //original event structure
   if(!pEvent->handled && m_pUser )
   {
      HX_ASSERT(GetWindow());
      HXxEvent event;
      event.event   = HX_SURFACE_UPDATE;
      event.window  = GetWindow()->window;
      event.param1  = m_pVideoSurface;
      event.param2  = GetWindow();
      event.result  = 0;
      event.handled = FALSE;
      m_pUser->HandleEvent(&event);
      pEvent->handled = event.handled;
   }
   

   //reset the gc to use no region
   if(m_bIsChildWindow && gc)
   {
      Display* pDisp = (Display*)GetWindow()->display;
      XLockDisplay(pDisp);
      XSetClipMask(pDisp, gc, None);
      XUnlockDisplay(pDisp);
   }

   //Handle the drawing of our arrows...
   _DrawArrows();

   //Now do all our children.... 
   CHXMapPtrToPtr::Iterator i = m_ChildrenMap.Begin();
   for(;i!=m_ChildrenMap.End();++i)
   {
      CHXUnixSite* pSite = (CHXUnixSite*) *i;
      pSite->_ForwardUpdateEvent(pEvent);
   }
   
   Release();
}

UINT32 CHXUnixSite::_MapKeySymToHXVK(KeySym sym, UINT32& uFlags )
{
   //XXXgfw if we add the extended flag in the HX_KEYBOARD event
   //structure then we can modify the flags here to show that these
   //keys are 'extended' in the windows sense.
   UINT32 ulRet = 0;
   switch( sym )
   {
      case XK_Shift_R:
         ulRet = XK_Shift_L;
         break;
      case XK_Alt_R:
         ulRet = XK_Alt_L;
         break;
      case XK_KP_Home:
         ulRet = XK_Home;
         break;
      case XK_KP_Next:
         ulRet = XK_Next;
         break;
      case XK_KP_Prior:
         ulRet = XK_Prior;
         break;
      case XK_KP_Enter:
         ulRet = XK_Return;
         break;
      case XK_KP_End:
         ulRet = XK_End;
         break;
      case XK_KP_Begin:
         ulRet = XK_Begin;
         break;
      case XK_KP_Left:
         ulRet = XK_Left;
         break;
      case XK_KP_Up:
         ulRet = XK_Up;
         break;
      case XK_Control_R:
         ulRet = XK_Control_L;
         break;
      case XK_KP_Right:
         ulRet = XK_Right;
         break;
      case XK_KP_Down:
         ulRet = XK_Down;
         break;
      case XK_KP_Insert:
         ulRet = XK_Insert;
         break;
      case XK_KP_Delete:
         ulRet = XK_Delete;
         break;
      default:
         ulRet = sym;
         break;
   }
   if( ulRet != sym )
   {
      //We have mapped a key from Right hand side, keypad, arrows
      //or other parts of an extended keyboard. Set the flag.
      uFlags |= HX_EXTENDED_KEY_MASK;
   }
   return ulRet;
}


BOOL CHXUnixSite::_ConvertToHXEvent(HXxEvent* pEvent )
{
   // get original events info from pEvent
   XEvent* pXEvent = (XEvent*) pEvent->param2;
   XButtonEvent* buttonEvent = (XButtonEvent*) pXEvent;

   
   //===============================================================
   //   Convert all other event to RMA generic events and pass back.
   //===============================================================
   if( ((pEvent->event == ButtonPress)   ||
        (pEvent->event == ButtonRelease) ||
        (pEvent->event == MotionNotify ) ||
        (pEvent->event == EnterNotify)   ||
        (pEvent->event == FocusIn)       ||
        (pEvent->event == FocusOut)      ||
        (pEvent->event == KeyPress)      ||
        (pEvent->event == KeyRelease)    ||
        (pEvent->event == LeaveNotify))
       )
   {
      // set modifier flags for all events....
      UINT32 flags = 0;

      // create new HXxEvent
      HXxEvent theEvent;

      //XXXgfw ouch....
      static HXxPoint realPt = {0,0};

      //Init certain members. 
      memset(&theEvent, 0, sizeof(HXxEvent));
      theEvent.window  = pEvent->window;
      theEvent.handled = FALSE;

      //
      // NOTE:
      //
      // theEvent must be filled in by *ALL* event types.
      // theEvent will be memcopied into the pEvent passed
      // back to the basesite at the end of the method.
      // 

      //==================================================
      // LEAVE NOTIFY EVENT
      //==================================================            
      if( pEvent->event==LeaveNotify)
      {
         if( m_pTopLevelSite->m_pMouseInSite )
         {
            HXxPoint oobPoint;
            oobPoint.x = -1;
            oobPoint.y = -1;
            HXxEvent Outevent = { HX_MOUSE_LEAVE,
                                  m_pWindow->window,
                                  (void*)&oobPoint,
                                  0, 0,
                                  FALSE };
            m_pTopLevelSite->m_pMouseInSite->EventOccurred(&Outevent);
            m_pTopLevelSite->m_pMouseInSite = NULL;
         }
         pEvent->handled=TRUE;
         return TRUE;
      }

      //==================================================
      // ENTER NOTIFY EVENT
      //==================================================
      if( pEvent->event==EnterNotify)
      {
         pEvent->handled=TRUE;
         return TRUE;
      }

      //==================================================
      // KEY PRESS/RELEASE EVENT
      //==================================================
      if ( pEvent->event == KeyPress || pEvent->event==KeyRelease )
      {
         XKeyEvent* pKeyEvent = (XKeyEvent*)pEvent->param2;

         //
         //Set the event type
         //
         theEvent.event = pEvent->event==KeyPress?HX_KEY_DOWN:HX_KEY_UP;

         //
         // Fill in the scan/key code.
         //
         flags =  pKeyEvent->keycode;
         flags &= 0x000000ff; //the scan code only gets bits 0-7
               
         //
         // build key modifier list...
         //
         if( pKeyEvent->state & ShiftMask )
            flags |= HX_SHIFT_MASK;
               
         if( pKeyEvent->state & ControlMask )
            flags |= HX_CTRL_MASK;
               
         if( pKeyEvent->state & LockMask )
            flags |= HX_CAPS_LOCK_MASK;

         if( pKeyEvent->state & Mod1Mask)
            flags |= HX_ALT_MASK;
                  
         if( pKeyEvent->state & Mod2Mask)
            flags |= HX_NUM_LOCK_MASK;
                  
         if( pKeyEvent->state & Mod5Mask)
            flags |= HX_SCROLL_LOCK_MASK;

         //
         //Store the char pressed.
         //
         KeySym sym;
         char   szBuf[10]; /* Flawfinder: ignore */
         int    nNum;
                  
         //Save the state of the keys...
         unsigned int unSave = pKeyEvent->state;
         pKeyEvent->state=0;

         //Lookup the key without any state.
         nNum = XLookupString( pKeyEvent, szBuf, 10, &sym, NULL );
         if( nNum > 0 )
         {
            theEvent.param1 = (void*)*szBuf;
         }
         else
         {
            theEvent.param1 = (void*)_MapKeySymToHXVK(sym, flags);
            flags |= HX_VIRTUAL_KEY_MASK;
         }
         //restore the state of the event
         pKeyEvent->state = unSave;
               
         //Set the flags...
         theEvent.param2 = (void*)flags;

         //Check for HX_CHAR needed or not.
         if( theEvent.event == HX_KEY_DOWN )
         {
            //We have to send an extra HX_CHAR event
            HXxEvent extraEvent;
            memcpy( &extraEvent, &theEvent, sizeof( extraEvent ) ); /* Flawfinder: ignore */

            //Change the type.
            extraEvent.event = HX_CHAR;
                  
            //
            //Change the keycode to an translated ascii char.
            //
            KeySym sym;
            char   szBuf[10]; /* Flawfinder: ignore */
            int    nNum;
                  
            nNum = XLookupString( pKeyEvent, szBuf, 10, &sym, NULL );
                  
            if( nNum > 0 )
            {
               extraEvent.param1 = (void*)*szBuf;
            }
            else
            {
               extraEvent.param1 = (void*)_MapKeySymToHXVK(sym, flags);
               flags |= HX_VIRTUAL_KEY_MASK;
            }
            extraEvent.param2 = (void*)flags;

            //
            // Now send the extra event....
            //
            CHXBaseSite::EventOccurred(&extraEvent);
         }
      }
            
      //==================================================
      // FOCUS OUT EVENT
      //==================================================            
      if ( pEvent->event == FocusOut )
      {
         theEvent.event = HX_LOSE_FOCUS;
      }

      if ( pEvent->event == FocusIn )
      {
         theEvent.event = HX_SET_FOCUS;
      }

      //==================================================
      // MOUSE MOVE EVENT
      //==================================================            
      if( pEvent->event == MotionNotify )
      {
         XMotionEvent* pp = (XMotionEvent*)pEvent->param2;
         theEvent.event = HX_MOUSE_MOVE; 
               
         if( pp->state&Button1Mask )
            flags |= HX_PRIMARY_BUTTON;
               
         if( pp->state&Button2Mask )
            flags |= HX_CONTEXT_BUTTON;
               
         if( pp->state&Button3Mask )
            flags |= HX_THIRD_BUTTON;
               
         if(pp->state & ShiftMask)
            flags |= HX_SHIFT_KEY;
               
         if(pp->state & ControlMask)
            flags |= HX_CTRL_KEY;
               
         if(pp->state & Mod1Mask)
            flags |= HX_ALT_COMMAND_KEY;
               
         theEvent.param2 = (void*) flags;
               
         //Grab the X and Y.
         theEvent.param1 = (void*) &realPt;
         realPt.x = pp->x;
         realPt.y = pp->y;
      }
            
      //==================================================
      // BUTTON PRESS/RELEASE EVENT
      //==================================================            
      if((pEvent->event == ButtonPress) || (pEvent->event == ButtonRelease))
      {
         // remap event
         if (pEvent->event == ButtonPress)
         {
            if (buttonEvent->button == Button3)
               theEvent.event = HX_CONTEXT_BUTTON_DOWN;
            else
               theEvent.event = HX_PRIMARY_BUTTON_DOWN;
         }
         else if (pEvent->event == ButtonRelease)
         {
            if (buttonEvent->button == Button3)
               theEvent.event = HX_CONTEXT_BUTTON_UP;
            else
               theEvent.event = HX_PRIMARY_BUTTON_UP;
         }
            
         if(buttonEvent->state & ShiftMask)
            flags |= HX_SHIFT_KEY;
               
         if(buttonEvent->state & ControlMask)
            flags |= HX_CTRL_KEY;
               
         theEvent.param2 = (void*) flags;
               
         //Grab the X and Y.
         theEvent.param1 = (void*) &realPt;
         realPt.x = buttonEvent->x;
         realPt.y = buttonEvent->y;
      }
            
      //Copy the new event back into the passed in one for
      //all events that fall through here...
      memcpy( pEvent, &theEvent, sizeof(HXxEvent) ); /* Flawfinder: ignore */

#if defined(_DEBUG)
      //If the users presses control-primary button
      //dump info on all sites. If shift-context, then
      //just this site.
      if( (buttonEvent->state&ControlMask)&&
          (theEvent.event==HX_PRIMARY_BUTTON_DOWN))
      {
         DisplayAllSiteData();
      }
      if( (buttonEvent->state&ShiftMask)&&
          (theEvent.event==HX_PRIMARY_BUTTON_DOWN))
      {
         DisplaySiteData("");
      }
#endif            
   }
   return pEvent->handled;
}


void CHXUnixSite::CheckColorSettings()
{
#if !defined(HELIX_FEATURE_HARDWARE_COLOR_CONTROLS)
    CHXBaseSite::CheckColorSettings();
#else

    CUnixSurf* pSurf = (CUnixSurf*)m_pVideoSurface;
    if( !pSurf->HasHWColorConrols() )
    {
        CHXBaseSite::CheckColorSettings();
    }
    else
    {
        if (m_pParentSite)
        {
            m_pParentSite->CheckColorSettings();
        }
        else
        {
            pSurf->SetHWColorControls();

            //We do all color stuff except sharpmess in hardware.
            float   fCurrentSharpness; 
            INT16   bInterpolate;
            zm_pColorAcc->GetSharpnessAdjustments(&fCurrentSharpness, &bInterpolate);

            if (fCurrentSharpness != m_fSharpness)
            {
                zm_pColorAcc->SetSharpnessAdjustments(m_fSharpness, FALSE);
            }
        }
    }
#endif
}

//
// OK, here it is. Take care of any OS specific duties, like scrollbar
// stuff and expose events. Then, if the event isn't handled, convert
// to an RMA event and return.
BOOL CHXUnixSite::_HandleOSEvents(HXxEvent* pEvent)
{
   HXxPoint position = {0, 0};
   HXxPoint point;

   if( NULL==pEvent )
   {
      return FALSE;
   }
   
#if defined(_DEBUG) && 0
//   fprintf( stderr, "this: %p m_pUser: %p ", this, m_pUser );
   switch( pEvent->event )
   {
      case HX_MOUSE_LEAVE:
         fprintf( stderr, "HX_MOUSE_LEAVE\n" );
         break;
//        case HX_MOUSE_MOVE:
//           point.x = ((HXxPoint*)pEvent->param1)->x;
//           point.y = ((HXxPoint*)pEvent->param1)->y;
//           fprintf( stderr, "HX_MOUSE_MOVE: %d %d\n", point.x, point.y );
//           break;
      case HX_MOUSE_ENTER:
         fprintf( stderr, "HX_MOUSE_ENTER\n" );
         break;
//        case MotionNotify:
//           point.x = ((XMotionEvent*)pEvent->param2)->x;
//           point.y = ((XMotionEvent*)pEvent->param2)->y;
//           fprintf( stderr, "MotionNotify: %d %d\n", point.x, point.y );
//           break;
      case Expose:
         fprintf( stderr, "Expose\n" );
         break;
      case EnterNotify :
         fprintf( stderr, "EnterNotify\n" );
         break;
      case LeaveNotify:
         fprintf( stderr, "LeaveNotify\n" );
         break;
      case KeyPress:
         fprintf( stderr, "this: %p m_pUser: %p ", this, m_pUser );
         fprintf( stderr, "Keypress\n\n" );
         break;
      case KeyRelease:
         fprintf( stderr, "this: %p m_pUser: %p ", this, m_pUser );
         fprintf( stderr, "KeyRelease\n" );
         break;
      default:
         fprintf( stderr, "Other\n" );         
         break;
   }
#endif

   //Find the ConfigureNotify events so we can drop to RGB from
   //overlay while we move....
//     if( pEvent->event == ConfigureNotify && this==m_pTopLevelSite )
//     {
//        XConfigureEvent* pev = (XConfigureEvent*)pEvent->param2;
//        if( m_pWindow && pev->window == (Window)m_pWindow->window )
//        {
//           HXxPoint p;
//           _GetPositionRelativeToActualWindow( p );
//  //           fprintf( stderr, "wint %p  -- x,y width, height: %d %d %d %d \n",
//  //                    pev->window,
//  //                    pev->x, pev->y, pev->width, pev->height);
//  //           fprintf( stderr, "size of site: %d %d\n", m_size.cx, m_size.cy); 
//  //           fprintf( stderr, "pos of site: %d %d\n", m_topleft.x, m_topleft.y); 
//           m_pTopLevelSite->m_pMutex->Lock();
//           m_pTopLevelSite->SiteMoving(0, 0);	
//           m_pTopLevelSite->m_nLastMoveTime = HX_GET_TICKCOUNT();
//           m_pTopLevelSite->ScheduleCallback(MOUSE, 100);
//           m_pTopLevelSite->m_pMutex->Unlock();
//        }
//     }

   //See if we should drop out of full screen
   if( pEvent->event == FocusOut && IsFullScreen() && !m_bIgnoreFocusOutInFS )
   {
//         fprintf( stderr, "_HandleOSEvents: focus out: " );
//         XEvent* pXEvent = (XEvent*) pEvent->param2;
//         XFocusChangeEvent* event = (XFocusChangeEvent*) pXEvent;
//         switch( event->mode )
//         {
//            case NotifyAncestor:
//                fprintf( stderr, "NotifyAncestor\n" );
//                break;
//            case NotifyVirtual:
//                fprintf( stderr, "NotifyVirtual\n" );
//                break;
//            case NotifyInferior:
//                fprintf( stderr, "NotifyInferior\n" );
//                break;
//            case NotifyNonlinear:
//                fprintf( stderr, "NotifyNonlinear\n" );
//                break;
//            case NotifyNonlinearVirtual:
//                fprintf( stderr, "NotifyNonlinearVirtual\n" );
//                break;
//            case NotifyPointer:
//                fprintf( stderr, "NotifyPointer\n" );
//                break;
//            case NotifyPointerRoot:
//                fprintf( stderr, "NotifyPointerRoot\n" );
//                break;
//            case NotifyDetailNone:
//                fprintf( stderr, "NotifyDetailNone\n" );
//                break;
//            default:
//                fprintf( stderr, "screwed.....\n" ); 
//         }
       ExitFullScreen();
   }


#if defined(_DEBUG) && defined(TEST_FULL_SCREEN)
   if( pEvent->event == KeyPress )
   {
      KeySym sym;
      char   szBuf[10]; /* Flawfinder: ignore */
      int    nNum;
      
      //Lookup the key without any state.
      nNum = XLookupString( (XKeyEvent*)(pEvent->param2), szBuf, 10, &sym, NULL );
      if( nNum > 0 )
      {
         if( 'f' == szBuf[0] && IsFullScreen() )
         {
            //Exit full screen if 'f' is pressed.....
            m_pTopLevelSite->ExitFullScreen();
         }
         else if( 'f' == szBuf[0] && !IsFullScreen() )
         {
            //Enter full screen if 'f' is pressed.....
            m_pTopLevelSite->EnterFullScreen();
         }
         
      }
      
   }
#endif

#if defined(_DEBUG) && defined(_TEST_COLOR_CONTROLS)
   if( pEvent->event == KeyPress )
   {
      KeySym sym;
      char   szBuf[10]; /* Flawfinder: ignore */
      int    nNum;
      
      //Lookup the key without any state.
      nNum = XLookupString( (XKeyEvent*)(pEvent->param2), szBuf, 10, &sym, NULL );
      if( nNum > 0 )
      {
          if( 'b' == szBuf[0] )
          {
              SetBrightness( GetBrightness()-.05);
          }
          if( 'B' == szBuf[0] )
          {
              SetBrightness( GetBrightness()+.05);
          }

          if( 'c' == szBuf[0] )
          {
              SetContrast( GetContrast()-.05);
          }
          if( 'C' == szBuf[0] )
          {
              SetContrast( GetContrast()+.05);
          }

          if( 'h' == szBuf[0] )
          {
              SetHue( GetHue()-.05);
          }
          if( 'H' == szBuf[0] )
          {
              SetHue( GetHue()+.05 ); 
          }
          
          if( 's' == szBuf[0] )
          {
              SetSaturation( GetSaturation()-.05);
          }
          if( 'S' == szBuf[0] ) 
          {
              SetSaturation( GetSaturation()+.05);
          }
          fprintf( stderr, "colors %f %f %f %f\n",
                   GetBrightness(),
                   GetContrast(),
                   GetSaturation(),
                   GetHue()); 
      } 
      
   }
#endif

   //Exit full screen on ESC pressed......
   if( pEvent->event == KeyPress )
   {
      KeySym sym; 
      char   szBuf[10]; /* Flawfinder: ignore */
      int    nNum;
      
      //Lookup the key without any state.
      nNum = XLookupString( (XKeyEvent*)(pEvent->param2), szBuf, 10, &sym, NULL );
      if( nNum > 0 )
      {
         if( 27 == (int)szBuf[0] && IsFullScreen() )
         {
            //Exit full screen if esc is pressed.....
            m_pTopLevelSite->ExitFullScreen();
         }
      }
   }
   
   //Find out if this is an event we are interested in.  Make sure we
   //are visible, it isn't a button, expose or FocusIn event and also
   //make sure it is headed for our window.
   if (!_ShouldProcess(pEvent))
   {
      return FALSE;
   }

   
   if(m_pUser && GetWindow() && GetWindow()->window)
   {
      //Do not send an update event to a hidden site.
      if( pEvent->event == Expose ||
          pEvent->event == FocusIn  ||
          pEvent->event == HX_SURFACE_UPDATE )
      {
         if( (m_ScrollVertButtonT || m_ScrollHorizButtonR) && IsSiteVisible() )
         {
            _DrawArrows();
         }
         _ForwardUpdateEvent(pEvent);
         return TRUE;
      }
      else
      {
         // get original events info from pEvent
         XEvent* pXEvent = (XEvent*) pEvent->param2;
         XButtonEvent* buttonEvent = (XButtonEvent*) pXEvent;
         

         //XXXgfw all this code sucks! It really need to be written
         //for just native events or RMA events. With the change to a
         //common site it is all screwed up. I am leaving it for now
         //so we can get on with transparancy but get back to it!

         //If the user clicks MB1 on a scroll button, handle it here and
         //don't pass it up or let the user handle the event.
         //Hit detection here.

         ////////////////////////////////////////////////////////
         // BEGIN SCROLLING GARBAGE
         ////////////////////////////////////////////////////////
         if(
            ((pEvent->event==ButtonPress || pEvent->event==ButtonRelease) &&
             buttonEvent->button==Button1) &&
            (m_ScrollHorizButtonL || m_ScrollVertButtonB )
             )
         {
            int buttonX=0;
            int buttonY=0;

            if( pEvent->event==ButtonRelease )
            {
               if( m_bScrollingInProgress )
               {
                  m_bScrollingInProgress = FALSE;
                  m_nScrollDir = 0;
                  return TRUE ;
               }
            }
            else
            {
                buttonX = buttonEvent->x;
                buttonY = buttonEvent->y;
               
               BOOL bPointInSite = FALSE;
               if( m_Region )
                   bPointInSite = HXPointInRegion(m_Region, buttonX, buttonY);
                    
               if( bPointInSite )
               {
                  if( m_ScrollHorizButtonL )
                  {
                     if( _InButton( m_ptScrollHorizPosL, buttonX, buttonY ))
                     {
                        m_bScrollingInProgress = TRUE;
                        m_nScrollDir = 1;
                     }
                     if( _InButton( m_ptScrollHorizPosR, buttonX, buttonY ))
                     {
                        m_bScrollingInProgress = TRUE;
                        m_nScrollDir = 2;
                     }
                  }
                  if( m_ScrollVertButtonT )
                  {
                     if( _InButton( m_ptScrollVertPosT, buttonX, buttonY ))
                     {
                        m_bScrollingInProgress = TRUE;
                        m_nScrollDir = 3;
                     }
                     if( _InButton( m_ptScrollVertPosB, buttonX, buttonY ))
                     {
                        m_bScrollingInProgress = TRUE;
                        m_nScrollDir = 4;
                     }                        
                  }
               }
            }

            if( (m_ScrollHorizButtonL||m_ScrollVertButtonT) && m_bScrollingInProgress)
            {
               int xx=0;
               int yy=0;
               HXxWindow* pParentWindow = GetParentSite()->GetWindow();
               //Make it scroll 10% of the parent window each click.
               HXxSize sizeTmp;
               GetParentSite()->GetSize(sizeTmp);

               //Set it to a percentage of the slider range.
               int incX = sizeTmp.cx/10;
               int incY = sizeTmp.cy/10;
                
               HX_ASSERT( pParentWindow );
                
               xx = m_XSliderPos;
               yy = m_YSliderPos;

               if( m_nScrollDir == 1 )
                  xx-=incX;
               if( m_nScrollDir == 2 )
                  xx+=incX;
               if( m_nScrollDir == 3 )
                  yy-=incY;
               if( m_nScrollDir == 4 )
                  yy+=incY;
               
               if( xx > m_size.cx-sizeTmp.cx )
                  xx = m_size.cx-sizeTmp.cx;
               if( yy > m_size.cy-sizeTmp.cy)
                  yy = m_size.cy-sizeTmp.cy;
               
               if( xx < 0 )
                  xx = 0;
               if( yy < 0 )
                  yy = 0;

               m_XSliderPos = xx;
               m_YSliderPos = yy;
               
               HXxRect rect;
               DamageRect(rect);
               
               InternalForceRedraw();
            }
            //Only throw away the event if it had something to do with
            //scolling.
            if( m_bScrollingInProgress )
            {
                m_bScrollingInProgress = FALSE;
                m_nScrollDir = 0;
               return TRUE;
            }
         }
         ////////////////////////////////////////////////////////
         // END SCROLLING GARBAGE
         ////////////////////////////////////////////////////////
         point.x = -1;
         point.y = -1;

         if( pEvent->event == MotionNotify)
         {
            point.x = ((XMotionEvent*)pXEvent)->x;
            point.y = ((XMotionEvent*)pXEvent)->y;
         }
         else if( pEvent->event == ButtonPress )
         {
            point.x = ((XMotionEvent*)pXEvent)->x;
            point.y = ((XMotionEvent*)pXEvent)->y;
         }

         //
         //Give the user a chance at the native event.
         //
         if( m_RegionWithoutChildren && HXPointInRegion(m_RegionWithoutChildren, point.x, point.y ))
         {
            if( m_Region && HXPointInRegion(m_Region, point.x, point.y) )
            {
                if (m_pUser)
                    m_pUser->HandleEvent(pEvent);
            }
            else
            {
               INT32 handledCount = 0;
               INT32 mapCount     = 0;
               
               //try send this to all of our children
              _unixsitecpp1: 
               mapCount = m_ChildrenMap.GetCount();
               CHXMapPtrToPtr::Iterator i;
               for(i=m_ChildrenMap.Begin() ; i!=m_ChildrenMap.End() ; ++i)
               {
                  CHXBaseSite* pSite = (CHXBaseSite*) *i;
                  pSite->_HandleOSEvents(pEvent);
                  if (pEvent->handled)
                  {                      
                     break;
                  }
                  handledCount+=pEvent->handled;
                  pEvent->handled=0;
                  
                  if (m_ChildrenMap.GetCount() != mapCount)
                  {
                     goto _unixsitecpp1;
                  }
               }
               if (handledCount)
               {
                  pEvent->handled = 1;
               }
               HX_ASSERT(handledCount<2);
            }
         }
         pEvent->handled=FALSE;
      }
   }
   
   return FALSE;
}

void CHXUnixSite::_GenerateOSEvent(HXxEvent* pEvent, HXxEvent* pEvent2)
{
   //XXXgfw Not needed on UNIX I guess???
}

void CHXUnixSite::_GenerateSetCursorEvent()
{
#ifdef _DEBUG   
   fprintf( stderr, "CHXUnixSite::_GenerateSetCursorEvent\n" );
#endif   
   //XXXgfw do we need this??
}

void CHXUnixSite::_TryCreateXSlider()
{
   if( !m_ScrollHorizButtonL && IsSiteVisible() )
      _CreateHorizScrollBar();
}

void CHXUnixSite::_SetXSliderValues(INT32 range, INT32 pageSize)
{
   //XXXgfw this is a do nothing as long as we only have
   //scroll buttons on unix and not real scroll bars.
}

void CHXUnixSite::_TryCreateYSlider()
{
   if( !m_ScrollVertButtonT && IsSiteVisible() )
      _CreateVertScrollBar();
}

void CHXUnixSite::_SetYSliderValues(INT32 range, INT32 pageSize)
{
   //XXXgfw this is a do nothing as long as we only have
   //scroll buttons on unix and not real scroll bars.
}

void CHXUnixSite::_GetSystemSizeOfSliders(INT32* pWidth, INT32* pHeight)
{
   *pWidth = *pHeight = SCROLL_BAR_WIDTH;
}

BOOL CHXUnixSite::_IsWindowVisible()
{
   HX_RESULT retVal = FALSE;
   //XXXgfw do this for now...
   retVal = IsSiteVisible();
   return retVal;
}

void CHXUnixSite::_ShowXSlider(BOOL bShow)
{
   if( GetWindow() )
   {
      if( bShow )
         _MapHorzScroll();
      else
         _UnmapHorzScroll();
   }
}

void CHXUnixSite::_MoveXSlider( INT32 left,
                                INT32 top,
                                INT32 right,
                                INT32 bottom,
                                BOOL bRedraw )
{
   //Do nothing right now....
}

void CHXUnixSite::_ShowYSlider(BOOL bShow)
{
   if( GetWindow() )
   {
      if( bShow )
         _MapVertScroll();
      else
         _UnmapVertScroll();
   }
}

void CHXUnixSite::_MoveYSlider( INT32 left,
                                INT32 top,
                                INT32 right,
                                INT32 bottom,
                                BOOL bRedraw)
{
   //do nothing right now...
}

BOOL CHXUnixSite::_DoesXSliderExist()
{
   return (m_ScrollHorizButtonL!=0);
}

void* CHXUnixSite::_GetContainingWindow()
{
   //XXXgfw Do we need this???
   return NULL;
}

void CHXUnixSite::_GetCursorPos(HXxPoint* pPoint)
{
   //Return the cursor pos in screen coords.
   Window rootWin;
   Window childWin;
   int rootX=0;
   int rootY=0;
   int childX=0;
   int childY=0;
   unsigned int mask=0;
   Bool ret=FALSE;
   
   HX_ASSERT(GetWindow());
   Display* pDis = (Display*)GetWindow()->display;
   XLockDisplay(pDis);
   ret = XQueryPointer(pDis,
                       (Window)GetWindow()->window,
                       &rootWin,
                       &childWin,
                       &rootX, &rootY,
                       &childX, &childY,
                       &mask);
   XUnlockDisplay(pDis);

   if(ret)
   {
      pPoint->x = rootX;
      pPoint->y = rootY;
   }
}
void* CHXUnixSite::_GetWindowWithCursor()
{
   //Return the cursor pos in screen coords.
   void*        pRet  = NULL;
   int          rootX = 0;
   int          rootY = 0;
   int          childX= 0;
   int          childY= 0;
   unsigned int mask  = 0;
   Bool         ret   = FALSE;
   Window       rootWin;
   Window       childWin;
   
   HX_ASSERT(GetWindow());
   Display* pDis = (Display*)GetWindow()->display;
   XLockDisplay(pDis);
   ret = XQueryPointer(pDis,
                       (Window)GetWindow()->window,
                       &rootWin,
                       &childWin,
                       &rootX, &rootY,
                       &childX, &childY,
                       &mask);
   XUnlockDisplay(pDis);

   if(ret)
   {
      pRet = (void*)childWin;
   }
   return pRet;
}

void CHXUnixSite::_MapPointToOSWindow(HXxPoint* pPt, void** pWindowHandle)
{
   //XXXgfw we could query the window tree and traverse down but that
   //is really slow and this isn't used right now.
   HX_ASSERT( "Not implemented..." == NULL );
}

void CHXUnixSite::_ReInitPrimarySurface()
{
   //Nothing to do in unix here right?
}

BOOL CHXUnixSite::_MoveWindow( void* win,
                               INT32 X,
                               INT32 Y,
                               INT32 nWidth,
                               INT32 nHeight,
                               BOOL bRepaint)
{
   //XXXgfw we still have to do bRepaint....
   HX_ASSERT( m_pWindow && m_pWindow->window && m_pWindow->display);
   _DestroyScrollButtons();
   XLockDisplay((Display*) m_pWindow->display);
   XMoveResizeWindow( (Display*)m_pWindow->display,
                      (Window)m_pWindow->window,
                      X,
                      Y,
                      nWidth,
                      nHeight
                      );
   XUnlockDisplay((Display*) m_pWindow->display);
   return TRUE;
}

BOOL CHXUnixSite::_UpdateWindow(void* hWnd)
{
   //We need to generate a repaint here of the window....
   return TRUE;
}

BOOL CHXUnixSite::_ShowWindow(void* hWnd, INT32 nCmdShow)
{
   HX_ASSERT( nCmdShow==HX_SHOW_WINDOW || nCmdShow==HX_HIDE_WINDOW);
   if( !m_pWindow || !m_pWindow->window || !m_pWindow->display )
      return FALSE;

   if( nCmdShow == HX_SHOW_WINDOW )
   {
      _MapScrollButtons();
      XLockDisplay((Display*) m_pWindow->display);
      XMapWindow( (Display*)m_pWindow->display, (Window)m_pWindow->window );
      XUnlockDisplay((Display*) m_pWindow->display);
   }
   else
   {
      _UnmapScrollButtons();
      XLockDisplay((Display*) m_pWindow->display);
      XUnmapWindow( (Display*)m_pWindow->display, (Window)m_pWindow->window );
      XUnlockDisplay((Display*) m_pWindow->display);
   }
   return TRUE;
}

BOOL CHXUnixSite::_SetWindowPos(void* hWnd,
                                void* hWndInsertAfter,
                                INT32 X,
                                INT32 Y,
                                INT32 cx,
                                INT32 cy,
                                INT32 uFlags)
{
#ifdef _DEBUG
   fprintf( stderr, "Now what on earth is this suppose to do??\n" );
#endif
   return TRUE;
}

BOOL CHXUnixSite::_SetWindowRgn(void* hWnd, HXREGION* hRgn, BOOL bRedraw)
{
   HX_ASSERT( GetWindow() );
   Display* pDis = (Display*)GetWindow()->display;
   XLockDisplay(pDis);
   XSetRegion( pDis,
               (GC)m_pVideoSurface->_GetDC(NULL),
               (Region)hRgn
               );
   XUnlockDisplay(pDis);
   if( bRedraw )
   {
      HX_ASSERT("Redraw asked for here"==NULL );
   }
   
   return TRUE;
}

void CHXUnixSite::_SetFocus(void* pWindow)
{
   XWindowAttributes attr;
   HXxWindow*        pWin = GetWindow();
   
   HX_ASSERT(pWin);
   HX_ASSERT(pWindow);
  
   XLockDisplay((Display*) pWin->display);
   XGetWindowAttributes((Display*)pWin->display, (Window)pWindow, &attr);
   XUnlockDisplay((Display*) pWin->display);
   if( attr.map_state == IsViewable )
   {
      XLockDisplay((Display*) pWin->display);
      XSetInputFocus( (Display*)pWin->display,
                      (Window)pWindow,
                      RevertToParent,
                      CurrentTime
                      );
      XUnlockDisplay((Display*) pWin->display);
   }
   
   return;
}

HX_RESULT CHXUnixSite::_EnterFullScreen()
{
   HXxWindow* pWin = GetWindow();
   HX_ASSERT( pWin && pWin->display && pWin->display);
   HX_ASSERT( this == m_pTopLevelSite );

   if( 0 != m_winFullScreenWindow || IsFullScreen() )
   {
      //We are already in full screen
      return HXR_FAIL;
   }
   
   //Create a override redirect window to fill the root.
   XSizeHints           size_hints;
   XLockDisplay((Display*) pWin->display);
   Screen*              pScreen = XDefaultScreenOfDisplay((Display*)pWin->display);
   XUnlockDisplay((Display*) pWin->display);
   UINT16               uHorzRes = WidthOfScreen(pScreen);
   UINT16               uVertRes = HeightOfScreen(pScreen);
   int                  attrMask = 0;
   XSetWindowAttributes attr;
    
   memset(&attr, 0, sizeof(XSetWindowAttributes));
   attrMask = CWOverrideRedirect | CWBorderPixel |
      CWBackPixel | CWCursor;
   attr.cursor = None;
   attr.override_redirect = True;
   XLockDisplay((Display*)pWin->display);
   attr.background_pixel = BlackPixel((Display*)pWin->display,
                                      DefaultScreen((Display*)pWin->display));
   attr.border_pixel     = BlackPixel((Display*)pWin->display,
                                      DefaultScreen((Display*)pWin->display));
   XUnlockDisplay((Display*)pWin->display);

   size_hints.flags  = PPosition | PSize;
   size_hints.x      = 0;
   size_hints.y      = 0;
   size_hints.width  = uHorzRes;
   size_hints.height = uVertRes;

   //Create it.
   XLockDisplay((Display*) pWin->display);
   Window window = XCreateWindow((Display*)pWin->display, 
                                 DefaultRootWindow((Display*)pWin->display),
                                 size_hints.x,
                                 size_hints.y,
                                 size_hints.width,
                                 size_hints.height, 
                                 0,
                                 CopyFromParent,
                                 InputOutput,
                                 CopyFromParent,
                                 attrMask,
                                 &attr);
   
   //Tell the WM about this window.
   XSetStandardProperties( (Display*)pWin->display,
                           window,
                           "unixfullscreen",
                           "unixfullscreen",
                           None,
                           NULL, 0,
                           &size_hints
                           );
   
   int result = XSelectInput( zm_display, window,
                              ButtonPressMask   | ButtonReleaseMask | KeyPressMask    |
                              KeyReleaseMask    | EnterWindowMask   | LeaveWindowMask |
                              PointerMotionMask | ButtonMotionMask  | KeymapStateMask |
                              ExposureMask      | StructureNotifyMask | FocusChangeMask
                              );

   //Map the window.
   XMapWindow((Display*)pWin->display, window);
   XUnlockDisplay((Display*) pWin->display);


   //Get ready to resize the presentation....
   m_pTopLevelSite->m_bDisableForceRedraw = TRUE;

   //Maintain aspect ratio and Scale it.
   float fXScale   = (float)uHorzRes/(float)(m_size.cx);
   float fYScale   = (float)uVertRes/(float)(m_size.cy);
   float fScale    = (fXScale<fYScale) ? fXScale : fYScale;
   int nWidth      = (int)(fScale*m_size.cx+.5);
   int nHeight     = (int)(fScale*m_size.cy+.5);

   //Center the presentation and save the old size
   memcpy( &m_PreFullScreenSize, &m_size, sizeof( HXxSize) ); /* Flawfinder: ignore */
   HXxSize size = {nWidth, nHeight};
   
   if( nWidth<uHorzRes )
      m_ptFullScreenOffset.x = (uHorzRes-nWidth)/2;
   
   if( nHeight<uVertRes )
      m_ptFullScreenOffset.y = (uVertRes-nHeight)/2;

   //Reparent our main window.......
   Window       winRootParent = 0;
   Window       winParent     = 0;
   Window*      pwinChildren  = NULL;
   unsigned int nNumChildren  = 0;
   XLockDisplay((Display*) pWin->display);
   XQueryTree( (Display*)pWin->display,
               (Window)pWin->window,
               &winRootParent,
               &winParent,
               &pwinChildren,
               &nNumChildren
               );
   //Free unused children list.
   XFree( pwinChildren );
   XUnlockDisplay((Display*) pWin->display);

   HX_ASSERT( winParent );
   m_winOldParent = winParent;
   XLockDisplay((Display*) pWin->display);
   XReparentWindow( (Display*)pWin->display,
                    (Window)pWin->window,
                    window,
                    m_ptFullScreenOffset.x,
                    m_ptFullScreenOffset.y
                    );
   
   //Flush event queue.
   XSync((Display*)pWin->display, False);
   XUnlockDisplay((Display*) pWin->display);



   //Save it
   m_winFullScreenWindow = window;
   m_bInFullScreen = TRUE;

      //Now resize it...
   SetSize(m_size);
   //Redraw the presentation....
   m_pTopLevelSite->m_bDisableForceRedraw = FALSE;
   _ForceRedrawAll();

   //Give it focus....
   _SetFocus( (void*)pWin->window );
   
   // now eat all the focusouts that came as a result of this reparent...
   XEvent event;
   XLockDisplay((Display*) pWin->display);
   BOOL status   =  XCheckTypedWindowEvent((Display*)pWin->display, (Window)pWin->window,
		  	   FocusOut, &event);
   XUnlockDisplay((Display*) pWin->display);
   while (m_bWindowCreatedByCreate && status)
   {
       // just discarding these
      XLockDisplay((Display*) pWin->display);
      status   =  XCheckTypedWindowEvent((Display*)pWin->display, (Window)pWin->window,
		                              FocusOut, &event);
      XUnlockDisplay((Display*) pWin->display);
   }


   //Update the status text...
   if(m_pStatusText)
   {
      m_pStatusText->ParentChangedSize();
      m_pStatusText->Show();
   }

   return HXR_OK;
}

HX_RESULT CHXUnixSite::_ExitFullScreen()
{
   HX_ASSERT( this == m_pTopLevelSite );

   HXxWindow* pWin = GetWindow();

   HX_ASSERT( pWin && pWin->display && pWin->window );

   //Give the window back to the TLC.

   XLockDisplay((Display*) pWin->display);
   XReparentWindow( (Display*)pWin->display,
                    (Window)pWin->window,
                    m_winOldParent,
                    m_position.x, m_position.y
                    );
   XUnlockDisplay((Display*) pWin->display);

   //Just kill our window and take us out of full screen....
   if( 0 != m_winFullScreenWindow )
   {
      XLockDisplay((Display*) pWin->display);
      XDestroyWindow( (Display*)pWin->display, m_winFullScreenWindow );
      XUnlockDisplay((Display*) pWin->display);
      m_winFullScreenWindow = 0;
   }

   m_bDisableForceRedraw = TRUE;

   m_bInFullScreen = FALSE;
   HXxSize size = {0,0};
   memcpy( &size, &m_PreFullScreenSize, sizeof(HXxSize) ); /* Flawfinder: ignore */
   m_PreFullScreenSize.cx = m_PreFullScreenSize.cy = 0;

   SetSize(size);
   _SetFocus( (void*)pWin->window );
   m_ptFullScreenOffset.x = 0;
   m_ptFullScreenOffset.y = 0;
   

   m_bDisableForceRedraw = FALSE;
   _ForceRedrawAll();
   
   if(m_pStatusText)
   {
      m_pStatusText->ParentChangedSize();
      m_pStatusText->Hide();
   }

   //move the site back to where it was.
   if( m_pTopLevelSite )
   {
       m_pTopLevelSite->_SetPosition(m_CreateWindowPos);
   }
   
   return HXR_OK;
}

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

HX_RESULT CHXUnixSite::_TestFullScreen( void* hTestBitmap,
                                        const char* pszStatusText )
{
#ifdef _DEBUG   
   fprintf( stderr, "Going to test full screen....\n" );
#endif   
   return HXR_OK;
}

void CHXUnixSite::ProcessEvent(HXxEvent* pEvent)
{
   if(pEvent)
   {
       //Expose event compression. Combine all outstanding expose events
       //into one big region.
       if(Expose==pEvent->event)
       {  
           _CollapseExposeEvents((XEvent*)pEvent->param2);
       }
   }

   //Send the event to each registered UnixSite.
   void* pSite   = NULL; 
   void* pWindow = NULL;
   POSITION  pos = z_mapSiteToWindow.GetStartPosition();
   while( pos )
   {
      z_mapSiteToWindow.GetNextAssoc(pos, pSite, pWindow);
      CHXUnixSite* pSiteWindowed = (CHXUnixSite*)pSite;
      CHXUnixSite* pTopLevel = NULL;
      HX_ASSERT(pSiteWindowed);
      pSiteWindowed->AddRef();
      pTopLevel = (CHXUnixSite*)pSiteWindowed->GetTopLevelSite();
      
      if(pEvent)
      {
          //Call back into the basesite's event loop.
          pTopLevel->EventOccurred(pEvent);
      }

      //XXXgfw As a workaround for the overlay not moving while the
      //player is paused, we will check it here and update it if needed.

      //XXXRGG We might be able to use X's ConfigureNotify messages instead
      //of doing a refresh every 50 ms.
      pTopLevel->_UpdateOverlayIfNeeded();

      pSiteWindowed->Release();
   }
}

void CHXUnixSite::_CollapseExposeEvents(XEvent* xevent)
{
   Display*      display = xevent->xany.display;
   Window        window  = xevent->xany.window;
   XExposeEvent* expose_event = (XExposeEvent*)xevent;
   XEvent        new_event;
   XExposeEvent* new_expose_event = (XExposeEvent*)&new_event;
   ushort        x1;
   ushort        y1;
   ushort        x2;
   ushort        y2;
   ushort        x3;
   ushort        y3;

   x1 = expose_event->x;
   y1 = expose_event->y;
   x2 = x1 + expose_event->width;
   y2 = y1 + expose_event->height;
   XLockDisplay(display);
   BOOL status = XCheckWindowEvent(display, window, ExposureMask, &new_event);
   XUnlockDisplay(display);   
   while( status)
   { 
      if (new_expose_event->x < x1)
         x1 = new_expose_event->x;
        
      if (new_expose_event->y < y1)
         y1 = new_expose_event->y;
                
      x3 = new_expose_event->x + new_expose_event->width;
      if (x3 > x2)
         x2 = x3;
                
      y3 = new_expose_event->y + new_expose_event->height;
      if (y3 > y2)
         y2 = y3;
      XLockDisplay(display);
      status = XCheckWindowEvent(display, window, ExposureMask, &new_event);
      XUnlockDisplay(display);

   }
            
   expose_event->x = x1;
   expose_event->y = y1;
   expose_event->width = x2 - x1;
   expose_event->height = y2 - y1;
   expose_event->count = new_expose_event->count;
}


BOOL CHXUnixSite::_ShouldProcess(HXxEvent* pEvent)
{
   BOOL bShouldProcessThisEvent = TRUE;

   
   if( !IsSiteVisible() )
   {
      switch (pEvent->event)
      {
         case ButtonPress:
         case ButtonRelease:
         case Expose:
         case FocusIn:
            bShouldProcessThisEvent = FALSE;
            break;
         default:
            break;
      }
   }

   if(m_pWindow && m_pWindow->window!=pEvent->window)
   {
      bShouldProcessThisEvent = FALSE;
   }
   return bShouldProcessThisEvent;
}


///////////////////////////////////////////////////////
//
// UnixEventHandler methods...
//
CHXUnixSite::UnixEventHandler::UnixEventHandler(CHXUnixSite* pParent)
   : m_pParent(pParent),
     m_lRefCount(0),
     m_cbHandle(0)
{
   HX_ASSERT(m_pParent);
   HX_ASSERT(m_pParent->m_pScheduler);
   m_cbHandle = m_pParent->m_pScheduler->RelativeEnter((IHXCallback*)this, 30);
}

CHXUnixSite::UnixEventHandler::~UnixEventHandler()
{
    CancelCallback();
}

void
CHXUnixSite::UnixEventHandler::CancelCallback()
{
   if( m_cbHandle && m_pParent && m_pParent->m_pScheduler )
   {
      UINT32 tempHandle = m_cbHandle;
      m_cbHandle = 0;
      m_pParent->m_pScheduler->Remove(tempHandle);
   }
}
    
HX_RESULT CHXUnixSite::UnixEventHandler::QueryInterface(REFIID riid, void** ppvObj)
{
   if (IsEqualIID(riid, IID_IHXCallback))
   {
      AddRef();
      *ppvObj = (IHXCallback*)this;
      return HXR_OK;
   }
   else if (IsEqualIID(riid, IID_IUnknown))
   {
      AddRef();
      *ppvObj = this;
      return HXR_OK;
   }
    
   *ppvObj = NULL;
   return HXR_NOINTERFACE;
}

ULONG32 CHXUnixSite::UnixEventHandler::AddRef()
{
   return InterlockedIncrement(&m_lRefCount);
}

ULONG32 CHXUnixSite::UnixEventHandler::Release()
{
   HX_ASSERT(m_lRefCount>0);
   if( InterlockedDecrement(&m_lRefCount)>0 )
   {
      return m_lRefCount;
   }
   delete this;
   return 0;
}

//IHXCallback methods
HX_RESULT CHXUnixSite::UnixEventHandler::Func()
{
    XEvent xevent;
    static HXxEvent pnevent;
    
    m_cbHandle = 0;
    XLockDisplay(m_pParent->zm_display);
    int status = XPending(m_pParent->zm_display);
    XUnlockDisplay(m_pParent->zm_display);
    while(status)
    {
	XLockDisplay(m_pParent->zm_display);
        XNextEvent(m_pParent->zm_display, &xevent);
	XUnlockDisplay(m_pParent->zm_display);
        
        // package native event in HXxEvent and send to dispatcher
        pnevent.event = xevent.type;
        pnevent.window = (void *)xevent.xany.window;
        pnevent.param1 = xevent.xany.display;
        pnevent.param2 = &xevent;

        m_pParent->ProcessEvent(&pnevent);
	XLockDisplay(m_pParent->zm_display);
	status = XPending(m_pParent->zm_display);
	XUnlockDisplay(m_pParent->zm_display);
    }
    
    if (m_pParent && m_pParent->m_pScheduler)
    {
        m_cbHandle = m_pParent->m_pScheduler->RelativeEnter((IHXCallback*)this, 30);
    }
    return HXR_OK;
}

void CHXUnixSite::_UpdateOverlayIfNeeded()
{
    if( m_pVideoSurface )
    {
        if( m_pVideoSurface->m_nBltMode == HX_OVERLAY_BLT )
        {
            ULONG32 ulNow = HX_GET_BETTERTICKCOUNT();
            CUnixSurf* pSurf = (CUnixSurf*)m_pVideoSurface;
            if( ulNow- pSurf->m_ulLastOverlayUpdateTime > 50 )
            {
                SiteMoving(0,0);
            }
        }
    }
    LISTPOSITION pos = m_ChildrenInZOrder.GetHeadPosition();
    while(pos)
    {
        CHXUnixSite* pSite = (CHXUnixSite*)m_ChildrenInZOrder.GetNext(pos);
        pSite->_UpdateOverlayIfNeeded();
    }
}


BOOL  CHXUnixSite::_ShouldEnterForceRedraw()
{
   if( !m_bDamaged || !m_pUser || !IsSiteVisible() )
   {
      return FALSE;
   }

   if(InterlockedIncrement(&m_lBltEntryCount)>1)
   {
      InterlockedDecrement(&m_lBltEntryCount);
      return FALSE;
   }
         
   return TRUE;
}

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




/////////////////////////////////////////////////////////
//
// CHXSiteEventHandler
//
/////////////////////////////////////////////////////////
CHXSiteEventHandler::CHXSiteEventHandler(IUnknown* pContext)
   : m_lRefCount(0)
   , m_pContext(NULL)
{
   if (pContext)
   {
      m_pContext = pContext;
      m_pContext->AddRef();
   }
} 

CHXSiteEventHandler::~CHXSiteEventHandler()
{
   HX_RELEASE(m_pContext);
}

HX_RESULT CHXSiteEventHandler::QueryInterface(REFIID riid, void** ppvObj)
{
   if (IsEqualIID(riid, IID_IUnknown))
   {
      AddRef();
      *ppvObj = (IUnknown*)(IHXSiteEventHandler*)this;
      return HXR_OK;
   }
   else if (IsEqualIID(riid, IID_IHXSiteEventHandler))
   {
      AddRef();
      *ppvObj = (IHXSiteEventHandler*)this;
      return HXR_OK;
   }

   *ppvObj = NULL;
   return HXR_NOINTERFACE;
}


ULONG32 CHXSiteEventHandler::AddRef()
{
   return InterlockedIncrement(&m_lRefCount);
}

ULONG32 CHXSiteEventHandler::Release()
{
   if (InterlockedDecrement(&m_lRefCount) > 0)
   {
      return m_lRefCount;
   }

   delete this;
   return 0;
}

HX_RESULT CHXSiteEventHandler::EventOccurred(HXxEvent* pEvent)
{
   CHXUnixSite::ProcessEvent(pEvent);
   return HXR_OK;
}
