/************************************************************** * * 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 #include #include #define _SV_SALINST_CXX #ifndef _VOS_MUTEX_HXX #include #endif #include #ifndef _SV_SALIDS_HRC #include #endif #include #include #include #include #include #include #include #include #include #include // ======================================================================= 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 received 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(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; }