/**************************************************************
 * 
 * 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.
 * 
 *************************************************************/



#define INCL_DOSMISC
#define INCL_DOSMODULEMGR
#define INCL_DOSPROCESS

#include <string.h>
#include <svpm.h>
#include <process.h>

#define _SV_SALINST_CXX

#ifndef _VOS_MUTEX_HXX
#include <vos/mutex.hxx>
#endif
#include <tools/debug.hxx>

#ifndef _SV_SALIDS_HRC
#include <os2/salids.hrc>
#endif
#include <vcl/apptypes.hxx>
#include <os2/saldata.hxx>
#include <os2/salinst.h>
#include <os2/salframe.h>
#include <os2/salobj.h>
#include <os2/saltimer.h>
#include <os2/salbmp.h>
#include <salimestatus.hxx>
#include <vcl/timer.hxx>
#include <tools/solarmutex.hxx>

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

void SalAbort( const XubString& rErrorText )
{
	ImplFreeSalGDI();

	if( !rErrorText.Len() )
		fprintf( stderr, "Application Error " );
	else
		fprintf( stderr, "%s ",
			ByteString( rErrorText, gsl_getSystemTextEncoding() ).GetBuffer() );
	abort();
}

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

ULONG GetCurrentThreadId()
{
	PTIB pptib = NULL;
	PPIB pppib = NULL;

	DosGetInfoBlocks( &pptib, &pppib );
	return pptib->tib_ptib2->tib2_ultid;
}

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

MRESULT EXPENTRY SalComWndProc( HWND hWnd, ULONG nMsg, MPARAM nMP1, MPARAM nMP2 );

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

class SalYieldMutex : public vos::OMutex
{
public:
	Os2SalInstance*			mpInstData;
	ULONG					mnCount;
	ULONG					mnThreadId;

public:
							SalYieldMutex( Os2SalInstance* pInstData );

	virtual void SAL_CALL       acquire();
	virtual void SAL_CALL       release();
	virtual sal_Bool SAL_CALL   tryToAcquire();

	ULONG					GetAcquireCount( ULONG nThreadId );
};

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

SalYieldMutex::SalYieldMutex( Os2SalInstance* pInstData )
{
	mpInstData	= pInstData;
	mnCount 	= 0;
	mnThreadId	= 0;
}

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

void SalYieldMutex::acquire()
{
	OMutex::acquire();
	mnCount++;
	mnThreadId = GetCurrentThreadId();
}

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

void SalYieldMutex::release()
{
	ULONG nThreadId = GetCurrentThreadId();
	if ( mnThreadId != nThreadId )
		OMutex::release();
	else
	{
		SalData* pSalData = GetSalData();
		if ( pSalData->mnAppThreadId != nThreadId )
		{
			if ( mnCount == 1 )
			{
                mpInstData->mpSalWaitMutex->acquire();
				if ( mpInstData->mnYieldWaitCount )
					WinPostMsg( mpInstData->mhComWnd, SAL_MSG_RELEASEWAITYIELD, 0, 0 );
				mnThreadId = 0;
                mnCount--;
                OMutex::release();
                mpInstData->mpSalWaitMutex->release();
            }
            else
            {
                mnCount--;
                OMutex::release();
            }
		}
		else
		{
			if ( mnCount == 1 )
				mnThreadId = 0;
			mnCount--;
			OMutex::release();
		}
	}
}

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

sal_Bool SalYieldMutex::tryToAcquire()
{
	if ( OMutex::tryToAcquire() )
	{
		mnCount++;
		mnThreadId = GetCurrentThreadId();
		return sal_True;
	}
	else
		return sal_False;
}

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

ULONG SalYieldMutex::GetAcquireCount( ULONG nThreadId )
{
	if ( nThreadId == mnThreadId )
		return mnCount;
	else
		return 0;
}

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

void ImplSalYieldMutexAcquireWithWait()
{
    Os2SalInstance* pInst = GetSalData()->mpFirstInstance;
    if ( !pInst )
        return;

    // If we are the main thread, then we must wait with wait, because
    // in if we don't reschedule, then we create deadlocks if a Windows
    // Function is called from another thread. If we arn't the main thread,
    // than we call qcquire directly.
    ULONG nThreadId = GetCurrentThreadId();
    SalData* pSalData = GetSalData();
    if ( pSalData->mnAppThreadId == nThreadId )
    {
        // Wenn wir den Mutex nicht bekommen, muessen wir solange
        // warten, bis wir Ihn bekommen
        sal_Bool bAcquire = FALSE;
        do
        {
            if ( pInst->mpSalYieldMutex->tryToAcquire() )
                bAcquire = TRUE;
            else
            {
                pInst->mpSalWaitMutex->acquire();
                if ( pInst->mpSalYieldMutex->tryToAcquire() )
                {
                    bAcquire = TRUE;
                    pInst->mpSalWaitMutex->release();
                }
                else
                {
                    pInst->mnYieldWaitCount++;
                    pInst->mpSalWaitMutex->release();
					QMSG aTmpMsg;
					WinGetMsg( pSalData->mhAB, &aTmpMsg, pInst->mhComWnd, SAL_MSG_RELEASEWAITYIELD, SAL_MSG_RELEASEWAITYIELD );
                    pInst->mnYieldWaitCount--;
                    if ( pInst->mnYieldWaitCount )
						WinPostMsg( pInst->mhComWnd, SAL_MSG_RELEASEWAITYIELD, 0 , 0 );
                }
            }
        }
        while ( !bAcquire );
    }
    else
        pInst->mpSalYieldMutex->acquire();
}

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

sal_Bool ImplSalYieldMutexTryToAcquire()
{
    Os2SalInstance* pInst = GetSalData()->mpFirstInstance;
    if ( pInst )
        return pInst->mpSalYieldMutex->tryToAcquire();
    else
        return FALSE;
}

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

void ImplSalYieldMutexAcquire()
{
    Os2SalInstance* pInst = GetSalData()->mpFirstInstance;
    if ( pInst )
        pInst->mpSalYieldMutex->acquire();
}

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

void ImplSalYieldMutexRelease()
{
    Os2SalInstance* pInst = GetSalData()->mpFirstInstance;
    if ( pInst )
        pInst->mpSalYieldMutex->release();
}

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

ULONG ImplSalReleaseYieldMutex()
{
    Os2SalInstance* pInst = GetSalData()->mpFirstInstance;
    if ( !pInst )
        return 0;

    SalYieldMutex*  pYieldMutex = pInst->mpSalYieldMutex;
    ULONG           nCount = pYieldMutex->GetAcquireCount( GetCurrentThreadId() );
    ULONG           n = nCount;
    while ( n )
    {
        pYieldMutex->release();
        n--;
    }

    return nCount;
}

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

void ImplSalAcquireYieldMutex( ULONG nCount )
{
    Os2SalInstance* pInst = GetSalData()->mpFirstInstance;
    if ( !pInst )
        return;

    SalYieldMutex*  pYieldMutex = pInst->mpSalYieldMutex;
    while ( nCount )
    {
        pYieldMutex->acquire();
        nCount--;
    }
}

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

bool Os2SalInstance::CheckYieldMutex()
{
    bool bRet = true;
	SalData*	pSalData = GetSalData();
	ULONG		nCurThreadId = GetCurrentThreadId();
	if ( pSalData->mnAppThreadId != nCurThreadId )
	{
		if ( pSalData->mpFirstInstance )
		{
            SalYieldMutex* pYieldMutex = pSalData->mpFirstInstance->mpSalYieldMutex;
			if ( pYieldMutex->mnThreadId != nCurThreadId )
			{
				bRet = false;
			}
		}
	}
	else
	{
		if ( pSalData->mpFirstInstance )
		{
            SalYieldMutex* pYieldMutex = pSalData->mpFirstInstance->mpSalYieldMutex;
			if ( pYieldMutex->mnThreadId != nCurThreadId )
			{
				bRet = false;
			}
		}
	}
	return bRet;
}

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

void InitSalData()
{
	SalData* pSalData = new SalData;
	memset( pSalData, 0, sizeof( SalData ) );
	SetSalData( pSalData );
}

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

void DeInitSalData()
{
	SalData* pSalData = GetSalData();
	if ( pSalData->mpFontMetrics )
		delete pSalData->mpFontMetrics;
	delete pSalData;
	SetSalData( NULL );
}

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

void InitSalMain()
{
	PPIB pib;
	PTIB tib;
	HAB hAB;
	HMQ hMQ;
	SalData* pData = GetAppSalData();
#if OSL_DEBUG_LEVEL>0
	debug_printf("InitSalMain\n");
#endif

	// morph application to PM
	DosGetInfoBlocks(&tib, &pib);
	// Change flag from VIO to PM:
	if (pib->pib_ultype==2) pib->pib_ultype = 3;

	// create anchor block
	hAB = WinInitialize( 0 );
	if ( !hAB )
		return;

	// create message queue
	hMQ = WinCreateMsgQueue( hAB, 60 );
	if ( !hMQ )
	{
		WinTerminate( hAB );
		return;
	}

	if ( pData ) // Im AppServer NULL
	{
		// Ankerblock und Messagequeue merken
		pData->mhAB = hAB;
		pData->mhMQ = hMQ;
	}

}

void DeInitSalMain()
{
#if OSL_DEBUG_LEVEL>0
printf("DeInitSalMain\n");
#endif

	SalData* pData = GetAppSalData();
	// destroy message queue and anchor block
	WinDestroyMsgQueue( pData->mhMQ );
	WinTerminate( pData->mhAB );

}

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

SalInstance* CreateSalInstance()
{
	SalData*		pSalData = GetSalData();

	// determine the os2 version
	ULONG nMayor;
	ULONG nMinor;
	DosQuerySysInfo( QSV_VERSION_MAJOR, QSV_VERSION_MAJOR, &nMayor, sizeof( nMayor ) );
	DosQuerySysInfo( QSV_VERSION_MINOR, QSV_VERSION_MINOR, &nMinor, sizeof( nMinor ) );
	aSalShlData.mnVersion = (USHORT)(nMayor*10 + nMinor);

	pSalData->mnAppThreadId = GetCurrentThreadId();

	// register frame class
	if ( !WinRegisterClass( pSalData->mhAB, (PSZ)SAL_FRAME_CLASSNAME,
							(PFNWP)SalFrameWndProc, CS_MOVENOTIFY /* 17/08 CS_HITTEST | CS_MOVENOTIFY */,
							SAL_FRAME_WNDEXTRA ) )
	{
		return NULL;
	}
	// register subframe class
	if ( !WinRegisterClass( pSalData->mhAB, (PSZ)SAL_SUBFRAME_CLASSNAME,
							(PFNWP)SalFrameWndProc, CS_SAVEBITS| CS_MOVENOTIFY,
							SAL_FRAME_WNDEXTRA ) )
	{
		return NULL;
	}
	// register object class
	if ( !WinRegisterClass( pSalData->mhAB, (PSZ)SAL_COM_CLASSNAME,
							(PFNWP)SalComWndProc, 0, 0 ))
	{
		return NULL;
	}

	HWND hComWnd = WinCreateWindow( HWND_OBJECT, (PCSZ)SAL_COM_CLASSNAME,
									(PCSZ)"", 0, 0, 0, 0, 0,
									HWND_OBJECT, HWND_TOP,
									222, NULL, NULL);
    if ( !hComWnd )
        return NULL;

#if OSL_DEBUG_LEVEL>0
	debug_printf("CreateSalInstance hComWnd %x\n", hComWnd);
#endif
    Os2SalInstance* pInst = new Os2SalInstance;

	// init instance (only one instance in this version !!!)
	pSalData->mpFirstInstance	= pInst;
	pInst->mhAB		= pSalData->mhAB;
	pInst->mhMQ		= pSalData->mhMQ;
	pInst->mnArgc	= pSalData->mnArgc;
	pInst->mpArgv	= pSalData->mpArgv;
	pInst->mhComWnd	= hComWnd;

	// AppIcon ermitteln
	ImplLoadSalIcon( SAL_RESID_ICON_DEFAULT, pInst->mhAppIcon);

	// init static GDI Data
	ImplInitSalGDI();

	return pInst;
}

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

void DestroySalInstance( SalInstance* pInst )
{
	SalData* pSalData = GetSalData();

	//	(only one instance in this version !!!)
	ImplFreeSalGDI();

#ifdef ENABLE_IME
	// IME-Daten freigeben
	if ( pSalData->mpIMEData )
		ImplReleaseSALIMEData();
#endif

	// reset instance
	if ( pSalData->mpFirstInstance == pInst )
		pSalData->mpFirstInstance = NULL;

	delete pInst;
}

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

Os2SalInstance::Os2SalInstance()
{
	mhComWnd				= 0;
	mpSalYieldMutex			= new SalYieldMutex( this );
	mpSalWaitMutex			= new vos::OMutex;
    mnYieldWaitCount         = 0;
	mpSalYieldMutex->acquire();
	::tools::SolarMutex::SetSolarMutex( mpSalYieldMutex );
}

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

Os2SalInstance::~Os2SalInstance()
{
	::tools::SolarMutex::SetSolarMutex( 0 );
	mpSalYieldMutex->release();
	delete mpSalYieldMutex;
	delete mpSalWaitMutex;
	WinDestroyWindow( mhComWnd);
}

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

vos::IMutex* Os2SalInstance::GetYieldMutex()
{
    return mpSalYieldMutex;
}
// -----------------------------------------------------------------------

ULONG Os2SalInstance::ReleaseYieldMutex()
{
    return ImplSalReleaseYieldMutex();
}

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

void Os2SalInstance::AcquireYieldMutex( ULONG nCount )
{
    ImplSalAcquireYieldMutex( nCount );
}

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

static void ImplSalYield( sal_Bool bWait, sal_Bool bHandleAllCurrentEvents )
{
	QMSG			aMsg;
	bool bWasMsg = false, bOneEvent = false;
	bool bQuit = false;

    Os2SalInstance* pInst = GetSalData()->mpFirstInstance;
    int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1;
    do
    {
        if ( WinPeekMsg( pInst->mhAB, &aMsg, 0, 0, 0, PM_REMOVE ) )
        {
			WinDispatchMsg( pInst->mhAB, &aMsg );
			bOneEvent = bWasMsg = true;
			if (aMsg.msg == WM_QUIT)
				bQuit = true;
        }
        else
            bOneEvent = false;
    } while( --nMaxEvents && bOneEvent );

	if ( bWait && ! bWasMsg )
	{
		if ( WinGetMsg( pInst->mhAB, &aMsg, 0, 0, 0 ) )
			WinDispatchMsg( pInst->mhAB, &aMsg );
		else
			bQuit = true;
	}
	
	if (bQuit)
	{
		ImplSalYieldMutexAcquireWithWait();
		Os2SalFrame*   pFrame = GetSalData()->mpFirstFrame;
		if ( pFrame )
		{
			if (pFrame->CallCallback( SALEVENT_SHUTDOWN, 0 ))
				WinCancelShutdown( pFrame->mhAB, FALSE );
		}
		ImplSalYieldMutexRelease();
	}

}

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

void Os2SalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
{
	SalYieldMutex*	pYieldMutex = mpSalYieldMutex;
	SalData*		pSalData = GetSalData();
	ULONG			nCurThreadId = GetCurrentThreadId();
	ULONG			nCount = pYieldMutex->GetAcquireCount( nCurThreadId );
	ULONG			n = nCount;
	while ( n )
	{
		pYieldMutex->release();
		n--;
	}
	if ( pSalData->mnAppThreadId != nCurThreadId )
	{
		// #97739# A SendMessage call blocks until the called thread (here: the main thread) 
		// returns. During a yield however, messages are processed in the main thread that might
		// result in a new message loop due to opening a dialog. Thus, SendMessage would not
		// return which will block this thread!
		// Solution: just give up the time slice and hope that messages are processed
		// by the main thread anyway (where all windows are created)
		// If the mainthread is not currently handling messages, then our SendMessage would
		// also do nothing, so this seems to be reasonable.

        // #i18883# only sleep if potential deadlock scenario, ie, when a dialog is open
        if( ImplGetSVData()->maAppData.mnModalMode )
            DosSleep(1);
        else
			WinSendMsg( mhComWnd, SAL_MSG_THREADYIELD, (MPARAM)bWait, (MPARAM)bHandleAllCurrentEvents );

		n = nCount;
		while ( n )
		{
			pYieldMutex->acquire();
			n--;
		}
	}
	else
	{
		ImplSalYield( bWait, bHandleAllCurrentEvents );

		n = nCount;
		while ( n )
		{
            ImplSalYieldMutexAcquireWithWait();
            n--;
		}
	}
}

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

MRESULT EXPENTRY SalComWndProc( HWND hWnd, ULONG nMsg,
								MPARAM nMP1, MPARAM nMP2 )
{
	//debug_printf( "SalComWndProc hWnd 0x%x nMsg %d\n", hWnd, nMsg);

	switch ( nMsg )
	{
        case SAL_MSG_PRINTABORTJOB:
            //ImplSalPrinterAbortJobAsync( (HDC)wParam );
            break;
		case SAL_MSG_THREADYIELD:
			ImplSalYield( (bool)nMP1, (bool) nMP2);
			return 0;
        // If we get this message, because another GetMessage() call
        // has recieved this message, we must post this message to
        // us again, because in the other case we wait forever.
        case SAL_MSG_RELEASEWAITYIELD:
            {
            Os2SalInstance* pInst = GetSalData()->mpFirstInstance;
            if ( pInst && pInst->mnYieldWaitCount )
                WinPostMsg( hWnd, SAL_MSG_RELEASEWAITYIELD, nMP1, nMP2 );
            }
            return 0;
		case SAL_MSG_STARTTIMER:
			ImplSalStartTimer( (ULONG)nMP2, FALSE);
			return 0;
		case SAL_MSG_CREATEFRAME:
			return (MRESULT)ImplSalCreateFrame( GetSalData()->mpFirstInstance, (HWND)nMP2, (ULONG)nMP1 );
        case SAL_MSG_DESTROYFRAME:
            delete (SalFrame*)nMP2;
            return 0;
        case SAL_MSG_DESTROYHWND:
            //We only destroy the native window here. We do NOT destroy the SalFrame contained
			//in the structure (GetWindowPtr()). 
			if (WinDestroyWindow((HWND)nMP2) == 0)
			{
				OSL_ENSURE(0, "DestroyWindow failed!");
				//Failure: We remove the SalFrame from the window structure. So we avoid that
				// the window structure may contain an invalid pointer, once the SalFrame is deleted.
	           SetWindowPtr((HWND)nMP2, 0);
			}
			return 0;
		case SAL_MSG_CREATEOBJECT:
			return (MRESULT)ImplSalCreateObject( GetSalData()->mpFirstInstance, (Os2SalFrame*)(ULONG)nMP2 );
        case SAL_MSG_DESTROYOBJECT:
            delete (SalObject*)nMP2;
			return 0;
        case SAL_MSG_CREATESOUND:
            //return (MRESULT)((Os2SalSound*)nMP2)->ImplCreate();
			return 0;
        case SAL_MSG_DESTROYSOUND:
            //((Os2SalSound*)nMP2)->ImplDestroy();
			return 0;
        case SAL_MSG_POSTTIMER:
			SalTimerProc( 0, 0, SALTIMERPROC_RECURSIVE, (ULONG)nMP2 );
			break;
        case WM_TIMER:
			SalTimerProc( hWnd, 0, 0, 0 );
            break;
	}

	return WinDefWindowProc( hWnd, nMsg, nMP1, nMP2 );
}

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

bool Os2SalInstance::AnyInput( USHORT nType )
{
	SalData* pSalData = GetSalData();
	QMSG	aQMSG;

	if ( (nType & (INPUT_ANY)) == INPUT_ANY )
	{
		// Any Input
		if ( WinPeekMsg( pSalData->mhAB, &aQMSG, 0, 0, 0, PM_NOREMOVE ) )
			return TRUE;
	}
	else
	{
		if ( nType & INPUT_MOUSE )
		{
			// Test auf Mouseinput
			if ( WinPeekMsg( pSalData->mhAB, &aQMSG, 0,
							 WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE ) )
				return TRUE;
		}

		if ( nType & INPUT_KEYBOARD )
		{
			// Test auf Keyinput
			if ( WinPeekMsg( pSalData->mhAB, &aQMSG, 0,
							 WM_CHAR, WM_CHAR, PM_NOREMOVE ) )
				return !(SHORT1FROMMP( aQMSG.mp1 ) & KC_KEYUP);
		}

		if ( nType & INPUT_PAINT )
		{
			// Test auf Paintinput
			if ( WinPeekMsg( pSalData->mhAB, &aQMSG, 0,
							 WM_PAINT, WM_PAINT, PM_NOREMOVE ) )
				return TRUE;
		}

		if ( nType & INPUT_TIMER )
		{
			// Test auf Timerinput
			if ( WinPeekMsg( pSalData->mhAB, &aQMSG, 0,
							 WM_TIMER, WM_TIMER, PM_NOREMOVE ) )
				return TRUE;
		}

		if ( nType & INPUT_OTHER )
		{
			// Test auf sonstigen Input
			if ( WinPeekMsg( pSalData->mhAB, &aQMSG, 0, 0, 0, PM_NOREMOVE ) )
				return TRUE;
		}
	}

	return FALSE;
}

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

SalFrame* Os2SalInstance::CreateChildFrame( SystemParentData* pSystemParentData, ULONG nSalFrameStyle )
{
    // Um auf Main-Thread umzuschalten
    return (SalFrame*)WinSendMsg( mhComWnd, SAL_MSG_CREATEFRAME, (MPARAM)nSalFrameStyle, (MPARAM)pSystemParentData->hWnd );
}

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

SalFrame* Os2SalInstance::CreateFrame( SalFrame* pParent, ULONG nSalFrameStyle )
{
    // Um auf Main-Thread umzuschalten
    HWND mhWndClient;
//31/05/06 YD use client as owner(parent) so positioning will not need to
// take care of borders and captions
    if ( pParent )
        mhWndClient = static_cast<Os2SalFrame*>(pParent)->mhWndClient;
    else
        mhWndClient = 0;
    return (SalFrame*)WinSendMsg( mhComWnd, SAL_MSG_CREATEFRAME, (MPARAM)nSalFrameStyle, (MPARAM)mhWndClient );
}


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

void Os2SalInstance::DestroyFrame( SalFrame* pFrame )
{
    WinSendMsg( mhComWnd, SAL_MSG_DESTROYFRAME, 0, (MPARAM)pFrame );
}

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

SalObject* Os2SalInstance::CreateObject( SalFrame* pParent,
                                         SystemWindowData* /*pWindowData*/, // SystemWindowData meaningless on Windows
                                         sal_Bool /*bShow*/ ) 
{
	// Um auf Main-Thread umzuschalten
	return (SalObject*)WinSendMsg( mhComWnd, SAL_MSG_CREATEOBJECT, 0, (MPARAM)pParent );
}


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

void Os2SalInstance::DestroyObject( SalObject* pObject )
{
    WinSendMsg( mhComWnd, SAL_MSG_DESTROYOBJECT, 0, (MPARAM)pObject );
}

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

void* Os2SalInstance::GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes )
{
	rReturnedBytes	= 1;
	rReturnedType	= AsciiCString;
	return (void*) "";
}

void Os2SalInstance::AddToRecentDocumentList(const rtl::OUString& /*rFileUrl*/, const rtl::OUString& /*rMimeType*/)
{
}

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

SalTimer* Os2SalInstance::CreateSalTimer()
{
    return new Os2SalTimer();
}

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

SalBitmap* Os2SalInstance::CreateSalBitmap()
{
    return new Os2SalBitmap();
}

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

class Os2ImeStatus : public SalI18NImeStatus
{
  public:
    Os2ImeStatus() {}
    virtual ~Os2ImeStatus() {}
    
    // asks whether there is a status window available
    // to toggle into menubar
    virtual bool canToggle() { return false; }
    virtual void toggle() {}
};

SalI18NImeStatus* Os2SalInstance::CreateI18NImeStatus()
{
    return new Os2ImeStatus();
}

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

const ::rtl::OUString& SalGetDesktopEnvironment()
{
    static ::rtl::OUString aDesktopEnvironment( RTL_CONSTASCII_USTRINGPARAM( "OS/2" ) );
    return aDesktopEnvironment;
}

SalSession* Os2SalInstance::CreateSalSession()
{
    return NULL;
}
