/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"

#include <string.h>

#include <tools/debug.hxx>
#include <tools/svwin.h>

#include <vcl/svapp.hxx>

#include <win/wincomp.hxx>
#include <win/saldata.hxx>
#include <win/salinst.h>
#include <win/salframe.h>
#include <win/salobj.h>

// =======================================================================

static sal_Bool ImplIsSysWindowOrChild( HWND hWndParent, HWND hWndChild )
{
	if ( hWndParent == hWndChild )
		return TRUE;

	HWND hTempWnd = ::GetParent( hWndChild );
	while ( hTempWnd )
	{
		// Ab nicht Child-Fenstern hoeren wir auf zu suchen
		if ( !(GetWindowStyle( hTempWnd ) & WS_CHILD) )
			return FALSE;
		if ( hTempWnd == hWndParent )
			return TRUE;
		hTempWnd = ::GetParent( hTempWnd );
	}

	return FALSE;
}

// -----------------------------------------------------------------------

WinSalObject* ImplFindSalObject( HWND hWndChild )
{
	SalData*        pSalData = GetSalData();
	WinSalObject*	pObject = pSalData->mpFirstObject;
	while ( pObject )
	{
		if ( ImplIsSysWindowOrChild( pObject->mhWndChild, hWndChild ) )
			return pObject;

		pObject = pObject->mpNextObject;
	}

	return NULL;
}

// -----------------------------------------------------------------------

WinSalFrame* ImplFindSalObjectFrame( HWND hWnd )
{
	WinSalFrame* pFrame = NULL;
	WinSalObject* pObject = ImplFindSalObject( hWnd );
	if ( pObject )
	{
		// Dazugehoerenden Frame suchen
		HWND hWnd = ::GetParent( pObject->mhWnd );
		pFrame = GetSalData()->mpFirstFrame;
		while ( pFrame )
		{
			if ( pFrame->mhWnd == hWnd )
				break;

			pFrame = pFrame->mpNextFrame;
		}
	}

	return pFrame;
}

// -----------------------------------------------------------------------

sal_Bool ImplInterceptChildWindowKeyDown( MSG& rMsg )
{
    sal_Bool bResult = sal_False;
    if ( rMsg.message == WM_KEYDOWN )
    {
        wchar_t pClassName[10];
        sal_Int32 nLen = GetClassNameW( rMsg.hwnd, pClassName, 10 );
        if ( !( nLen == 9 && wcsncmp( pClassName, SAL_OBJECT_CLASSNAMEW, nLen ) == 0 ) )
        {
            // look for the first SalObject in the parent hierarchy
            HWND hWin = rMsg.hwnd;
            HWND hLastOLEWindow = hWin;
            WinSalObject* pSalObj = NULL;
            do
            {
                hLastOLEWindow = hWin;
                hWin = ::GetParent( hWin );
                if ( hWin )
                {
                    nLen = GetClassNameW( hWin, pClassName, 10 );
                    if ( nLen == 9 && wcsncmp( pClassName, SAL_OBJECT_CLASSNAMEW, nLen ) == 0 )
                        pSalObj = GetSalObjWindowPtr( hWin );
                }
            } while( hWin && !pSalObj );

            if ( pSalObj && pSalObj->mbInterceptChildWindowKeyDown && pSalObj->maSysData.hWnd )
            {
                bResult = ( 1 == ImplSendMessage( pSalObj->maSysData.hWnd, rMsg.message, rMsg.wParam, rMsg.lParam ) );
            }
        }
    }

    return bResult;
}

// -----------------------------------------------------------------------


// -----------------------------------------------------------------------

LRESULT CALLBACK SalSysMsgProc( int nCode, WPARAM wParam, LPARAM lParam )
{
	// Used for Unicode and none Unicode
	SalData* pSalData = GetSalData();

	if ( (nCode >= 0) && lParam )
	{
		CWPSTRUCT* pData = (CWPSTRUCT*)lParam;
		if ( (pData->message != WM_KEYDOWN) &&
			 (pData->message != WM_KEYUP) )
			pSalData->mnSalObjWantKeyEvt = 0;

		// Testen, ob wir Daten fuer ein SalObject-Fenster behandeln
		// muessen
		WinSalObject* pObject;
		if ( pData->message == WM_SETFOCUS )
		{
			pObject = ImplFindSalObject( pData->hwnd );
			if ( pObject )
			{
				pObject->mhLastFocusWnd = pData->hwnd;
				if ( ImplSalYieldMutexTryToAcquire() )
				{
					pObject->CallCallback( SALOBJ_EVENT_GETFOCUS, 0 );
					ImplSalYieldMutexRelease();
				}
				else
					ImplPostMessage( pObject->mhWnd, SALOBJ_MSG_POSTFOCUS, 0, 0 );
			}
		}
		else if ( pData->message == WM_KILLFOCUS )
		{
			pObject = ImplFindSalObject( pData->hwnd );
			if ( pObject && !ImplFindSalObject( (HWND)pData->wParam ) )
			{
				// LoseFocus nur rufen, wenn wirklich kein ChildFenster
				// den Focus bekommt
				if ( !pData->wParam || !ImplFindSalObject( (HWND)pData->wParam ) )
				{
					if ( ImplSalYieldMutexTryToAcquire() )
					{
						pObject->CallCallback( SALOBJ_EVENT_LOSEFOCUS, 0 );
						ImplSalYieldMutexRelease();
					}
					else
						ImplPostMessage( pObject->mhWnd, SALOBJ_MSG_POSTFOCUS, 0, 0 );
				}
				else
					pObject->mhLastFocusWnd = (HWND)pData->wParam;
			}
		}
	}

	return CallNextHookEx( pSalData->mhSalObjMsgHook, nCode, wParam, lParam );
}

// -----------------------------------------------------------------------

sal_Bool ImplSalPreDispatchMsg( MSG* pMsg )
{
	// Used for Unicode and none Unicode
	SalData*	    pSalData = GetSalData();
	WinSalObject*	pObject;

	if ( (pMsg->message == WM_LBUTTONDOWN) ||
		 (pMsg->message == WM_RBUTTONDOWN) ||
		 (pMsg->message == WM_MBUTTONDOWN) )
	{
		ImplSalYieldMutexAcquireWithWait();
		pObject = ImplFindSalObject( pMsg->hwnd );
		if ( pObject && !pObject->IsMouseTransparent() )
		    ImplPostMessage( pObject->mhWnd, SALOBJ_MSG_TOTOP, 0, 0 );
		ImplSalYieldMutexRelease();
	}

	if ( (pMsg->message == WM_KEYDOWN) ||
		 (pMsg->message == WM_KEYUP) )
	{
		// KeyEvents wollen wir nach Moeglichkeit auch abarbeiten,
		// wenn das Control diese nicht selber auswertet
		// SysKeys werden als WM_SYSCOMMAND verarbeitet
		// Char-Events verarbeiten wir nicht, da wir nur
		// Accelerator relevante Keys verarbeiten wollen
		sal_Bool bWantedKeyCode = FALSE;
		// A-Z, 0-9 nur in Verbindung mit Control-Taste
		if ( ((pMsg->wParam >= 65) && (pMsg->wParam <= 90)) ||
			 ((pMsg->wParam >= 48) && (pMsg->wParam <= 57)) )
		{
			if ( GetKeyState( VK_CONTROL ) & 0x8000 )
				bWantedKeyCode = TRUE;
		}
		else if ( ((pMsg->wParam >= VK_F1) && (pMsg->wParam <= VK_F24)) ||
				  ((pMsg->wParam >= VK_SPACE) && (pMsg->wParam <= VK_HELP)) ||
				  (pMsg->wParam == VK_BACK) || (pMsg->wParam == VK_TAB) ||
				  (pMsg->wParam == VK_CLEAR) || (pMsg->wParam == VK_RETURN) ||
				  (pMsg->wParam == VK_ESCAPE) )
			bWantedKeyCode = TRUE;
		if ( bWantedKeyCode )
		{
			ImplSalYieldMutexAcquireWithWait();
			pObject = ImplFindSalObject( pMsg->hwnd );
			if ( pObject )
				pSalData->mnSalObjWantKeyEvt = pMsg->wParam;
			ImplSalYieldMutexRelease();
		}
	}
	// Hier WM_SYSCHAR abfangen, um mit Alt+Taste evtl. Menu zu aktivieren
	else if ( pMsg->message == WM_SYSCHAR )
	{
		pSalData->mnSalObjWantKeyEvt = 0;

		sal_uInt16 nKeyCode = LOWORD( pMsg->wParam );
		// Nur 0-9 und A-Z
		if ( ((nKeyCode >= 48) && (nKeyCode <= 57)) ||
			 ((nKeyCode >= 65) && (nKeyCode <= 90)) ||
			 ((nKeyCode >= 97) && (nKeyCode <= 122)) )
		{
			sal_Bool bRet = FALSE;
			ImplSalYieldMutexAcquireWithWait();
			pObject = ImplFindSalObject( pMsg->hwnd );
			if ( pObject )
			{
				if ( pMsg->hwnd == ::GetFocus() )
				{
					WinSalFrame* pFrame = ImplFindSalObjectFrame( pMsg->hwnd );
					if ( pFrame )
					{
						if ( ImplHandleSalObjSysCharMsg( pFrame->mhWnd, pMsg->wParam, pMsg->lParam ) )
							bRet = TRUE;
					}
				}
			}
			ImplSalYieldMutexRelease();
			if ( bRet )
				return TRUE;
		}
	}
	else
		pSalData->mnSalObjWantKeyEvt = 0;

	return FALSE;
}

// -----------------------------------------------------------------------

void ImplSalPostDispatchMsg( MSG* pMsg, LRESULT /* nDispatchResult */ )
{
	// Used for Unicode and none Unicode
	SalData*	    pSalData = GetSalData();
	WinSalFrame*	pFrame;

	if ( (pMsg->message == WM_KEYDOWN) || (pMsg->message == WM_KEYUP) )
	{
		if ( pSalData->mnSalObjWantKeyEvt == pMsg->wParam )
		{
			pSalData->mnSalObjWantKeyEvt = 0;
			if ( pMsg->hwnd == ::GetFocus() )
			{
				ImplSalYieldMutexAcquireWithWait();
				pFrame = ImplFindSalObjectFrame( pMsg->hwnd );
				if ( pFrame )
					ImplHandleSalObjKeyMsg( pFrame->mhWnd, pMsg->message, pMsg->wParam, pMsg->lParam );
				ImplSalYieldMutexRelease();
			}
		}
	}

	pSalData->mnSalObjWantKeyEvt = 0;
}

// =======================================================================

LRESULT CALLBACK SalSysObjWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, int& rDef )
{
	WinSalObject*	pSysObj;
	LRESULT      	nRet = 0;

	switch( nMsg )
	{
		case WM_ERASEBKGND:
			nRet = 1;
			rDef = FALSE;
			break;
		case WM_PAINT:
			{
			PAINTSTRUCT aPs;
			BeginPaint( hWnd, &aPs );
			EndPaint( hWnd, &aPs );
			rDef = FALSE;
			}
			break;

		case WM_PARENTNOTIFY:
			{
			UINT nNotifyMsg = LOWORD( wParam );
			if ( (nNotifyMsg == WM_LBUTTONDOWN) ||
				 (nNotifyMsg == WM_RBUTTONDOWN) ||
				 (nNotifyMsg == WM_MBUTTONDOWN) )
			{
				ImplSalYieldMutexAcquireWithWait();
				pSysObj = GetSalObjWindowPtr( hWnd );
				if ( pSysObj && !pSysObj->IsMouseTransparent() )
				    pSysObj->CallCallback( SALOBJ_EVENT_TOTOP, 0 );
				ImplSalYieldMutexRelease();
			}
			}
			break;

		case WM_MOUSEACTIVATE:
            {
			ImplSalYieldMutexAcquireWithWait();
			pSysObj = GetSalObjWindowPtr( hWnd );
			if ( pSysObj && !pSysObj->IsMouseTransparent() )
			    ImplPostMessage( hWnd, SALOBJ_MSG_TOTOP, 0, 0 );
		    ImplSalYieldMutexRelease();
            }
			break;

		case SALOBJ_MSG_TOTOP:
			if ( ImplSalYieldMutexTryToAcquire() )
			{
				pSysObj = GetSalObjWindowPtr( hWnd );
				pSysObj->CallCallback( SALOBJ_EVENT_TOTOP, 0 );
				ImplSalYieldMutexRelease();
				rDef = FALSE;
			}
			else
				ImplPostMessage( hWnd, SALOBJ_MSG_TOTOP, 0, 0 );
			break;

		case SALOBJ_MSG_POSTFOCUS:
			if ( ImplSalYieldMutexTryToAcquire() )
			{
				pSysObj = GetSalObjWindowPtr( hWnd );
				HWND	hFocusWnd = ::GetFocus();
				sal_uInt16 nEvent;
				if ( hFocusWnd && ImplIsSysWindowOrChild( hWnd, hFocusWnd ) )
					nEvent = SALOBJ_EVENT_GETFOCUS;
				else
					nEvent = SALOBJ_EVENT_LOSEFOCUS;
				pSysObj->CallCallback( nEvent, 0 );
				ImplSalYieldMutexRelease();
			}
			else
				ImplPostMessage( hWnd, SALOBJ_MSG_POSTFOCUS, 0, 0 );
			rDef = FALSE;
			break;

		case WM_SIZE:
			{
			HWND hWndChild = GetWindow( hWnd, GW_CHILD );
			if ( hWndChild )
			{
				SetWindowPos( hWndChild,
							  0, 0,  0, (int)LOWORD( lParam ), (int)HIWORD( lParam ),
							  SWP_NOZORDER | SWP_NOACTIVATE );
			}
			}
			rDef = FALSE;
			break;

		case WM_CREATE:
			{
			// Window-Instanz am Windowhandle speichern
			// Can also be used for the W-Version, because the struct
			// to access lpCreateParams is the same structure
			CREATESTRUCTA* pStruct = (CREATESTRUCTA*)lParam;
			pSysObj = (WinSalObject*)pStruct->lpCreateParams;
			SetSalObjWindowPtr( hWnd, pSysObj );
			// HWND schon hier setzen, da schon auf den Instanzdaten
			// gearbeitet werden kann, wenn Messages waehrend
			// CreateWindow() gesendet werden
			pSysObj->mhWnd = hWnd;
			rDef = FALSE;
			}
			break;
	}

	return nRet;
}

LRESULT CALLBACK SalSysObjWndProcA( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
{
	int bDef = TRUE;
	LRESULT nRet = SalSysObjWndProc( hWnd, nMsg, wParam, lParam, bDef );
	if ( bDef )
		nRet = DefWindowProcA( hWnd, nMsg, wParam, lParam );
	return nRet;
}

LRESULT CALLBACK SalSysObjWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
{
	int bDef = TRUE;
	LRESULT nRet = SalSysObjWndProc( hWnd, nMsg, wParam, lParam, bDef );
	if ( bDef )
		nRet = DefWindowProcW( hWnd, nMsg, wParam, lParam );
	return nRet;
}

// -----------------------------------------------------------------------

LRESULT CALLBACK SalSysObjChildWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, int& rDef )
{
	LRESULT nRet = 0;

	switch( nMsg )
	{
		// Wegen PlugIn's loeschen wir erstmal den Hintergrund
		case WM_ERASEBKGND:
            {
	            WinSalObject* pSysObj = GetSalObjWindowPtr( ::GetParent( hWnd ) );

                if( pSysObj && !pSysObj->IsEraseBackgroundEnabled() )
                {
                    // do not erase background
			        nRet = 1;
			        rDef = FALSE;
                }
            }
			break;

		case WM_PAINT:
			{
			PAINTSTRUCT aPs;
			BeginPaint( hWnd, &aPs );
			EndPaint( hWnd, &aPs );
			rDef = FALSE;
			}
			break;

        case WM_MOUSEMOVE:
        case WM_LBUTTONDOWN:
        case WM_MBUTTONDOWN:
        case WM_RBUTTONDOWN:
        case WM_LBUTTONUP:
        case WM_MBUTTONUP:
        case WM_RBUTTONUP:
            {
	            WinSalObject* pSysObj;
                pSysObj = GetSalObjWindowPtr( ::GetParent( hWnd ) );

                if( pSysObj && pSysObj->IsMouseTransparent() )
                {
                    // forward mouse events to parent frame
                    HWND hWndParent = ::GetParent( pSysObj->mhWnd );

                    // transform coordinates
                    POINT pt;
                    pt.x = (long) LOWORD( lParam );
                    pt.y = (long) HIWORD( lParam );
                    MapWindowPoints( hWnd, hWndParent, &pt, 1 );
                    lParam = MAKELPARAM( (WORD) pt.x, (WORD) pt.y );

		            nRet = ImplSendMessage( hWndParent, nMsg, wParam, lParam );
                    rDef = FALSE;
                }
            }
            break;
	}

	return nRet;
}

LRESULT CALLBACK SalSysObjChildWndProcA( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
{
	int bDef = TRUE;
	LRESULT nRet = SalSysObjChildWndProc( hWnd, nMsg, wParam, lParam, bDef );
	if ( bDef )
		nRet = DefWindowProcA( hWnd, nMsg, wParam, lParam );
	return nRet;
}

LRESULT CALLBACK SalSysObjChildWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
{
	int bDef = TRUE;
	LRESULT nRet = SalSysObjChildWndProc( hWnd, nMsg, wParam, lParam, bDef );
	if ( bDef )
		nRet = DefWindowProcW( hWnd, nMsg, wParam, lParam );
	return nRet;
}

// =======================================================================

SalObject* ImplSalCreateObject( WinSalInstance* pInst, WinSalFrame* pParent )
{
	SalData* pSalData = GetSalData();

	// Hook installieren, wenn es das erste SalObject ist
	if ( !pSalData->mpFirstObject )
	{
		pSalData->mhSalObjMsgHook = SetWindowsHookExW( WH_CALLWNDPROC,
														   SalSysMsgProc,
														   pSalData->mhInst,
														   pSalData->mnAppThreadId );
	}

	if ( !pSalData->mbObjClassInit )
	{
        // #95301# shockwave plugin has bug; expects ASCII functions to be used
		if ( false )//aSalShlData.mbWNT )
		{
			WNDCLASSEXW aWndClassEx;
			aWndClassEx.cbSize			= sizeof( aWndClassEx );
			aWndClassEx.style			= 0;
			aWndClassEx.lpfnWndProc 	= SalSysObjWndProcW;
			aWndClassEx.cbClsExtra		= 0;
			aWndClassEx.cbWndExtra		= SAL_OBJECT_WNDEXTRA;
			aWndClassEx.hInstance		= pSalData->mhInst;
			aWndClassEx.hIcon			= 0;
			aWndClassEx.hIconSm 		= 0;
			aWndClassEx.hCursor 		= LoadCursor( 0, IDC_ARROW );
			aWndClassEx.hbrBackground	= 0;
			aWndClassEx.lpszMenuName	= 0;
			aWndClassEx.lpszClassName	= SAL_OBJECT_CLASSNAMEW;
			if ( RegisterClassExW( &aWndClassEx ) )
			{
				// Wegen PlugIn's loeschen wir erstmal den Hintergrund
				aWndClassEx.cbWndExtra		= 0;
				aWndClassEx.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
				aWndClassEx.lpfnWndProc 	= SalSysObjChildWndProcW;
				aWndClassEx.lpszClassName	= SAL_OBJECT_CHILDCLASSNAMEW;
				if ( RegisterClassExW( &aWndClassEx ) )
					pSalData->mbObjClassInit = TRUE;
			}
		}
		else
		{
			WNDCLASSEXA aWndClassEx;
			aWndClassEx.cbSize			= sizeof( aWndClassEx );
			aWndClassEx.style			= 0;
			aWndClassEx.lpfnWndProc 	= SalSysObjWndProcA;
			aWndClassEx.cbClsExtra		= 0;
			aWndClassEx.cbWndExtra		= SAL_OBJECT_WNDEXTRA;
			aWndClassEx.hInstance		= pSalData->mhInst;
			aWndClassEx.hIcon			= 0;
			aWndClassEx.hIconSm 		= 0;
			aWndClassEx.hCursor 		= LoadCursor( 0, IDC_ARROW );
			aWndClassEx.hbrBackground	= 0;
			aWndClassEx.lpszMenuName	= 0;
			aWndClassEx.lpszClassName	= SAL_OBJECT_CLASSNAMEA;
			if ( RegisterClassExA( &aWndClassEx ) )
			{
				// Wegen PlugIn's loeschen wir erstmal den Hintergrund
				aWndClassEx.cbWndExtra		= 0;
				aWndClassEx.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
				aWndClassEx.lpfnWndProc 	= SalSysObjChildWndProcA;
				aWndClassEx.lpszClassName	= SAL_OBJECT_CHILDCLASSNAMEA;
				if ( RegisterClassExA( &aWndClassEx ) )
					pSalData->mbObjClassInit = TRUE;
			}
		}
	}

	if ( pSalData->mbObjClassInit )
	{
		WinSalObject* pObject = new WinSalObject;
        
        // #135235# Clip siblings of this
        // SystemChildWindow. Otherwise, DXCanvas (using a hidden
        // SystemChildWindow) clobbers applets/plugins during
        // animations .
        HWND hWnd = CreateWindowExA( 0, SAL_OBJECT_CLASSNAMEA, "",
                                     WS_CHILD | WS_CLIPSIBLINGS, 0, 0, 0, 0,
                                     pParent->mhWnd, 0,
                                     pInst->mhInst, (void*)pObject );

		HWND hWndChild = 0;
        if ( hWnd )
        {
            // #135235# Explicitely stack SystemChildWindows in
            // the order they're created - since there's no notion
            // of zorder.
            SetWindowPos(hWnd,HWND_TOP,0,0,0,0,
                         SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOSIZE);
            hWndChild = CreateWindowExA( 0, SAL_OBJECT_CHILDCLASSNAMEA, "",
                                         WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE,
                                         0, 0, 0, 0,
                                         hWnd, 0,
                                         pInst->mhInst, NULL );
        }

		if ( !hWndChild )
		{
			delete pObject;
			return NULL;
		}

		if ( hWnd )
		{
			pObject->mhWnd 			= hWnd;
			pObject->mhWndChild		= hWndChild;
			pObject->maSysData.hWnd	= hWndChild;
			return pObject;
		}
	}

	return NULL;
}

// =======================================================================

WinSalObject::WinSalObject()
{
	SalData* pSalData = GetSalData();

	mhWnd			= 0;
	mhWndChild 		= 0;
	mhLastFocusWnd 	= 0;
	maSysData.nSize	= sizeof( SystemEnvData );
	mpStdClipRgnData	= NULL;
    mbInterceptChildWindowKeyDown = sal_False;

	// Insert object in objectlist
	mpNextObject = pSalData->mpFirstObject;
	pSalData->mpFirstObject = this;
}

// -----------------------------------------------------------------------

WinSalObject::~WinSalObject()
{
	SalData* pSalData = GetSalData();

	// remove frame from framelist
	if ( this == pSalData->mpFirstObject )
	{
		pSalData->mpFirstObject = mpNextObject;

		// Wenn letztes SalObject, dann Hook wieder entfernen
		if ( !pSalData->mpFirstObject )
			UnhookWindowsHookEx( pSalData->mhSalObjMsgHook );
	}
	else
	{
		WinSalObject* pTempObject = pSalData->mpFirstObject;
		while ( pTempObject->mpNextObject != this )
			pTempObject = pTempObject->mpNextObject;

		pTempObject->mpNextObject = mpNextObject;
	}

	// Cache-Daten zerstoeren
	if ( mpStdClipRgnData )
		delete mpStdClipRgnData;

	HWND hWndParent = ::GetParent( mhWnd );

	if ( mhWndChild )
		DestroyWindow( mhWndChild );
	if ( mhWnd )
		DestroyWindow( mhWnd );

	// Palette wieder zuruecksetzen, wenn kein externes Child-Fenster
	// mehr vorhanden ist, da diese unsere Palette ueberschrieben haben
	// koennen
	if ( hWndParent &&
		 ::GetActiveWindow() == hWndParent &&
		 !GetWindow( hWndParent, GW_CHILD ) )
		ImplSendMessage( hWndParent, SAL_MSG_FORCEPALETTE, 0, 0 );
}

// -----------------------------------------------------------------------

void WinSalObject::ResetClipRegion()
{
	SetWindowRgn( mhWnd, 0, TRUE );
}

// -----------------------------------------------------------------------

sal_uInt16 WinSalObject::GetClipRegionType()
{
	return SAL_OBJECT_CLIP_INCLUDERECTS;
}

// -----------------------------------------------------------------------

void WinSalObject::BeginSetClipRegion( sal_uLong nRectCount )
{
	sal_uLong nRectBufSize = sizeof(RECT)*nRectCount;
	if ( nRectCount < SAL_CLIPRECT_COUNT )
	{
		if ( !mpStdClipRgnData )
			mpStdClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+(SAL_CLIPRECT_COUNT*sizeof(RECT))];
		mpClipRgnData = mpStdClipRgnData;
	}
	else
		mpClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+nRectBufSize];
	mpClipRgnData->rdh.dwSize	  = sizeof( RGNDATAHEADER );
	mpClipRgnData->rdh.iType	  = RDH_RECTANGLES;
	mpClipRgnData->rdh.nCount	  = nRectCount;
	mpClipRgnData->rdh.nRgnSize  = nRectBufSize;
	SetRectEmpty( &(mpClipRgnData->rdh.rcBound) );
	mpNextClipRect 		  = (RECT*)(&(mpClipRgnData->Buffer));
	mbFirstClipRect		  = TRUE;
}

// -----------------------------------------------------------------------

void WinSalObject::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
{
	RECT*		pRect = mpNextClipRect;
	RECT*		pBoundRect = &(mpClipRgnData->rdh.rcBound);
	long		nRight = nX + nWidth;
	long		nBottom = nY + nHeight;

	if ( mbFirstClipRect )
	{
		pBoundRect->left	= nX;
		pBoundRect->top 	= nY;
		pBoundRect->right	= nRight;
		pBoundRect->bottom	= nBottom;
		mbFirstClipRect = FALSE;
	}
	else
	{
		if ( nX < pBoundRect->left )
			pBoundRect->left = (int)nX;

		if ( nY < pBoundRect->top )
			pBoundRect->top = (int)nY;

		if ( nRight > pBoundRect->right )
			pBoundRect->right = (int)nRight;

		if ( nBottom > pBoundRect->bottom )
			pBoundRect->bottom = (int)nBottom;
	}

	pRect->left 	= (int)nX;
	pRect->top		= (int)nY;
	pRect->right	= (int)nRight;
	pRect->bottom	= (int)nBottom;
	mpNextClipRect++;
}

// -----------------------------------------------------------------------

void WinSalObject::EndSetClipRegion()
{
	HRGN hRegion;

	// Aus den Region-Daten muessen wir jetzt eine ClipRegion erzeugen
	if ( mpClipRgnData->rdh.nCount == 1 )
	{
		RECT* pRect = &(mpClipRgnData->rdh.rcBound);
		hRegion = CreateRectRgn( pRect->left, pRect->top,
								 pRect->right, pRect->bottom );
	}
	else
	{
		sal_uLong nSize = mpClipRgnData->rdh.nRgnSize+sizeof(RGNDATAHEADER);
		hRegion = ExtCreateRegion( NULL, nSize, mpClipRgnData );
		if ( mpClipRgnData != mpStdClipRgnData )
			delete [] (BYTE*)mpClipRgnData;
	}

	DBG_ASSERT( hRegion, "SalObject::EndSetClipRegion() - Can't create ClipRegion" );
	SetWindowRgn( mhWnd, hRegion, TRUE );
}

// -----------------------------------------------------------------------

void WinSalObject::SetPosSize( long nX, long nY, long nWidth, long nHeight )
{
	sal_uLong nStyle = 0;
	sal_Bool bVisible = (GetWindowStyle( mhWnd ) & WS_VISIBLE) != 0;
	if ( bVisible )
	{
		ShowWindow( mhWnd, SW_HIDE );
		nStyle |= SWP_SHOWWINDOW;
	}
	SetWindowPos( mhWnd, 0,
				  (int)nX, (int)nY, (int)nWidth, (int)nHeight,
				  SWP_NOZORDER | SWP_NOACTIVATE | nStyle );
}

// -----------------------------------------------------------------------

void WinSalObject::Show( sal_Bool bVisible )
{
	if ( bVisible )
		ShowWindow( mhWnd, SW_SHOWNORMAL );
	else
		ShowWindow( mhWnd, SW_HIDE );
}

// -----------------------------------------------------------------------

void WinSalObject::Enable( sal_Bool bEnable )
{
	EnableWindow( mhWnd, bEnable );
}

// -----------------------------------------------------------------------

void WinSalObject::GrabFocus()
{
	if ( mhLastFocusWnd &&
		 IsWindow( mhLastFocusWnd ) &&
		 ImplIsSysWindowOrChild( mhWndChild, mhLastFocusWnd ) )
		::SetFocus( mhLastFocusWnd );
	else
		::SetFocus( mhWndChild );
}

// -----------------------------------------------------------------------

void WinSalObject::SetBackground()
{
}

// -----------------------------------------------------------------------

void WinSalObject::SetBackground( SalColor )
{
}

// -----------------------------------------------------------------------

const SystemEnvData* WinSalObject::GetSystemData() const
{
	return &maSysData;
}

// -----------------------------------------------------------------------

void WinSalObject::InterceptChildWindowKeyDown( sal_Bool bIntercept )
{
    mbInterceptChildWindowKeyDown = bIntercept;
}

