| /************************************************************** |
| * |
| * 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/svwin.h> |
| #ifdef WNT |
| #include <process.h> |
| #endif |
| #ifdef __MINGW32__ |
| #include <excpt.h> |
| #endif |
| |
| #include <osl/file.hxx> |
| |
| #include <vos/mutex.hxx> |
| |
| #include <tools/solarmutex.hxx> |
| #include <tools/debug.hxx> |
| |
| #include <vcl/timer.hxx> |
| #include <vcl/apptypes.hxx> |
| |
| #include <win/wincomp.hxx> |
| #include <win/salids.hrc> |
| #include <win/saldata.hxx> |
| #include <win/salinst.h> |
| #include <win/salframe.h> |
| #include <win/salobj.h> |
| #include <win/saltimer.h> |
| #include <win/salbmp.h> |
| |
| #include <salimestatus.hxx> |
| #include <salsys.hxx> |
| |
| #ifndef min |
| #define min(a,b) (((a) < (b)) ? (a) : (b)) |
| #endif |
| #ifndef max |
| #define max(a,b) (((a) > (b)) ? (a) : (b)) |
| #endif |
| |
| #if defined _MSC_VER |
| #pragma warning(push, 1) |
| #pragma warning( disable: 4917 ) |
| #endif |
| |
| #include <GdiPlus.h> |
| #include <GdiPlusEnums.h> |
| #include <GdiPlusColor.h> |
| #include <Shlobj.h> |
| |
| #if defined _MSC_VER |
| #pragma warning(pop) |
| #endif |
| |
| // ======================================================================= |
| |
| void SalAbort( const XubString& rErrorText ) |
| { |
| ImplFreeSalGDI(); |
| |
| if ( !rErrorText.Len() ) |
| { |
| // #112255# make sure crash reporter is triggered |
| RaiseException( 0, EXCEPTION_NONCONTINUABLE, 0, NULL ); |
| FatalAppExit( 0, "Application Error" ); |
| } |
| else |
| { |
| // #112255# make sure crash reporter is triggered |
| RaiseException( 0, EXCEPTION_NONCONTINUABLE, 0, NULL ); |
| ByteString aErrorText( ImplSalGetWinAnsiString( rErrorText ) ); |
| FatalAppExit( 0, aErrorText.GetBuffer() ); |
| } |
| } |
| |
| // ======================================================================= |
| |
| LRESULT CALLBACK SalComWndProcA( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ); |
| LRESULT CALLBACK SalComWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ); |
| |
| // ======================================================================= |
| |
| class SalYieldMutex : public vos::OMutex |
| { |
| public: // for ImplSalYield() |
| WinSalInstance* mpInstData; |
| sal_uLong mnCount; |
| DWORD mnThreadId; |
| |
| public: |
| SalYieldMutex( WinSalInstance* pInstData ); |
| |
| virtual void SAL_CALL acquire(); |
| virtual void SAL_CALL release(); |
| virtual sal_Bool SAL_CALL tryToAcquire(); |
| |
| sal_uLong GetAcquireCount( sal_uLong nThreadId ); |
| }; |
| |
| // ----------------------------------------------------------------------- |
| |
| SalYieldMutex::SalYieldMutex( WinSalInstance* pInstData ) |
| { |
| mpInstData = pInstData; |
| mnCount = 0; |
| mnThreadId = 0; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void SAL_CALL SalYieldMutex::acquire() |
| { |
| OMutex::acquire(); |
| mnCount++; |
| mnThreadId = GetCurrentThreadId(); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void SAL_CALL SalYieldMutex::release() |
| { |
| DWORD nThreadId = GetCurrentThreadId(); |
| if ( mnThreadId != nThreadId ) |
| OMutex::release(); |
| else |
| { |
| SalData* pSalData = GetSalData(); |
| if ( pSalData->mnAppThreadId != nThreadId ) |
| { |
| if ( mnCount == 1 ) |
| { |
| // If we don't call these message, the Output from the |
| // Java clients doesn't come in the right order |
| GdiFlush(); |
| |
| mpInstData->mpSalWaitMutex->acquire(); |
| if ( mpInstData->mnYieldWaitCount ) |
| ImplPostMessage( 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 SAL_CALL SalYieldMutex::tryToAcquire() |
| { |
| if( OMutex::tryToAcquire() ) |
| { |
| mnCount++; |
| mnThreadId = GetCurrentThreadId(); |
| return sal_True; |
| } |
| else |
| return sal_False; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| sal_uLong SalYieldMutex::GetAcquireCount( sal_uLong nThreadId ) |
| { |
| if ( nThreadId == mnThreadId ) |
| return mnCount; |
| else |
| return 0; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void ImplSalYieldMutexAcquireWithWait() |
| { |
| WinSalInstance* 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. |
| DWORD 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(); |
| MSG aTmpMsg; |
| ImplGetMessage( &aTmpMsg, pInst->mhComWnd, SAL_MSG_RELEASEWAITYIELD, SAL_MSG_RELEASEWAITYIELD ); |
| pInst->mnYieldWaitCount--; |
| if ( pInst->mnYieldWaitCount ) |
| ImplPostMessage( pInst->mhComWnd, SAL_MSG_RELEASEWAITYIELD, 0, 0 ); |
| } |
| } |
| } |
| while ( !bAcquire ); |
| } |
| else |
| pInst->mpSalYieldMutex->acquire(); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| sal_Bool ImplSalYieldMutexTryToAcquire() |
| { |
| WinSalInstance* pInst = GetSalData()->mpFirstInstance; |
| if ( pInst ) |
| return pInst->mpSalYieldMutex->tryToAcquire(); |
| else |
| return FALSE; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void ImplSalYieldMutexAcquire() |
| { |
| WinSalInstance* pInst = GetSalData()->mpFirstInstance; |
| if ( pInst ) |
| pInst->mpSalYieldMutex->acquire(); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void ImplSalYieldMutexRelease() |
| { |
| WinSalInstance* pInst = GetSalData()->mpFirstInstance; |
| if ( pInst ) |
| { |
| GdiFlush(); |
| pInst->mpSalYieldMutex->release(); |
| } |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| sal_uLong ImplSalReleaseYieldMutex() |
| { |
| WinSalInstance* pInst = GetSalData()->mpFirstInstance; |
| if ( !pInst ) |
| return 0; |
| |
| SalYieldMutex* pYieldMutex = pInst->mpSalYieldMutex; |
| sal_uLong nCount = pYieldMutex->GetAcquireCount( GetCurrentThreadId() ); |
| sal_uLong n = nCount; |
| while ( n ) |
| { |
| pYieldMutex->release(); |
| n--; |
| } |
| |
| return nCount; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void ImplSalAcquireYieldMutex( sal_uLong nCount ) |
| { |
| WinSalInstance* pInst = GetSalData()->mpFirstInstance; |
| if ( !pInst ) |
| return; |
| |
| SalYieldMutex* pYieldMutex = pInst->mpSalYieldMutex; |
| while ( nCount ) |
| { |
| pYieldMutex->acquire(); |
| nCount--; |
| } |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| bool WinSalInstance::CheckYieldMutex() |
| { |
| bool bRet = true; |
| SalData* pSalData = GetSalData(); |
| DWORD 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 SalData::initKeyCodeMap() |
| { |
| UINT nKey = 0xffffffff; |
| #define initKey( a, b )\ |
| nKey = LOWORD( VkKeyScan( a ) );\ |
| if( nKey < 0xffff )\ |
| maVKMap[ nKey ] = b; |
| |
| initKey( '+', KEY_ADD ); |
| initKey( '-', KEY_SUBTRACT ); |
| initKey( '*', KEY_MULTIPLY ); |
| initKey( '/', KEY_DIVIDE ); |
| initKey( '.', KEY_POINT ); |
| initKey( ',', KEY_COMMA ); |
| initKey( '<', KEY_LESS ); |
| initKey( '>', KEY_GREATER ); |
| initKey( '=', KEY_EQUAL ); |
| initKey( '~', KEY_TILDE ); |
| initKey( '`', KEY_QUOTELEFT ); |
| } |
| |
| // ======================================================================= |
| // ------- |
| // SalData |
| // ------- |
| |
| SalData::SalData() |
| { |
| mhInst = 0; // default instance handle |
| mhPrevInst = 0; // previous instance handle |
| mnCmdShow = 0; // default frame show style |
| mhDitherPal = 0; // dither palette |
| mhDitherDIB = 0; // dither memory handle |
| mpDitherDIB = 0; // dither memory |
| mpDitherDIBData = 0; // beginning of DIB data |
| mpDitherDiff = 0; // Dither mapping table |
| mpDitherLow = 0; // Dither mapping table |
| mpDitherHigh = 0; // Dither mapping table |
| mnTimerMS = 0; // Current Time (in MS) of the Timer |
| mnTimerOrgMS = 0; // Current Original Time (in MS) |
| mnNextTimerTime = 0; |
| mnLastEventTime = 0; |
| mnTimerId = 0; // windows timer id |
| mbInTimerProc = FALSE; // timer event is currently being dispatched |
| mhSalObjMsgHook = 0; // hook to get interesting msg for SalObject |
| mhWantLeaveMsg = 0; // window handle, that want a MOUSELEAVE message |
| mpMouseLeaveTimer = 0; // Timer for MouseLeave Test |
| mpFirstInstance = 0; // pointer of first instance |
| mpFirstFrame = 0; // pointer of first frame |
| mpFirstObject = 0; // pointer of first object window |
| mpFirstVD = 0; // first VirDev |
| mpFirstPrinter = 0; // first printing printer |
| mpHDCCache = 0; // Cache for three DC's |
| mh50Bmp = 0; // 50% Bitmap |
| mh50Brush = 0; // 50% Brush |
| int i; |
| for(i=0; i<MAX_STOCKPEN; i++) |
| { |
| maStockPenColorAry[i] = 0; |
| mhStockPenAry[i] = 0; |
| } |
| for(i=0; i<MAX_STOCKBRUSH; i++) |
| { |
| maStockBrushColorAry[i] = 0; |
| mhStockBrushAry[i] = 0; |
| } |
| mnStockPenCount = 0; // count of static pens |
| mnStockBrushCount = 0; // count of static brushes |
| mnSalObjWantKeyEvt = 0; // KeyEvent, welcher vom SalObj-Hook verarbeitet werden soll |
| mnCacheDCInUse = 0; // count of CacheDC in use |
| mbObjClassInit = FALSE; // is SALOBJECTCLASS initialised |
| mbInPalChange = FALSE; // is in WM_QUERYNEWPALETTE |
| mnAppThreadId = 0; // Id from Applikation-Thread |
| mbScrSvrEnabled = FALSE; // ScreenSaver enabled |
| mnSageStatus = 0; // status of Sage-DLL (DISABLE_AGENT == nicht vorhanden) |
| mpSageEnableProc = 0; // funktion to deactivate the system agent |
| mpFirstIcon = 0; // icon cache, points to first icon, NULL if none |
| mpTempFontItem = 0; |
| mbThemeChanged = FALSE; // true if visual theme was changed: throw away theme handles |
| mbThemeMenuSupport = FALSE; |
| |
| // init with NULL |
| gdiplusToken = 0; |
| maDwmLib = 0; |
| mpDwmIsCompositionEnabled = 0; |
| |
| initKeyCodeMap(); |
| |
| SetSalData( this ); |
| initNWF(); |
| } |
| |
| SalData::~SalData() |
| { |
| deInitNWF(); |
| SetSalData( NULL ); |
| } |
| |
| void InitSalData() |
| { |
| SalData* pSalData = new SalData; |
| CoInitialize(0); |
| |
| // init GDIPlus |
| static Gdiplus::GdiplusStartupInput gdiplusStartupInput; |
| Gdiplus::GdiplusStartup(&pSalData->gdiplusToken, &gdiplusStartupInput, NULL); |
| } |
| |
| |
| void DeInitSalData() |
| { |
| CoUninitialize(); |
| SalData* pSalData = GetSalData(); |
| |
| // deinit GDIPlus |
| if(pSalData) |
| { |
| Gdiplus::GdiplusShutdown(pSalData->gdiplusToken); |
| } |
| |
| delete pSalData; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void InitSalMain() |
| { |
| // remember data, copied from WinMain |
| SalData* pData = GetAppSalData(); |
| if ( pData ) // Im AppServer NULL |
| { |
| STARTUPINFO aSI; |
| aSI.cb = sizeof( aSI ); |
| GetStartupInfo( &aSI ); |
| pData->mhInst = GetModuleHandle( NULL ); |
| pData->mhPrevInst = NULL; |
| pData->mnCmdShow = aSI.wShowWindow; |
| } |
| } |
| |
| void DeInitSalMain() |
| { |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| SalInstance* CreateSalInstance() |
| { |
| SalData* pSalData = GetSalData(); |
| |
| // determine the windows version |
| aSalShlData.mbWXP = 0; |
| aSalShlData.mbWPrinter = 0; |
| WORD nVer = (WORD)GetVersion(); |
| aSalShlData.mnVersion = (((WORD)LOBYTE(nVer)) * 100) + HIBYTE(nVer); |
| if ( aSalShlData.mnVersion >= 400 ) |
| aSalShlData.mbW40 = 1; |
| rtl_zeroMemory( &aSalShlData.maVersionInfo, sizeof(aSalShlData.maVersionInfo) ); |
| aSalShlData.maVersionInfo.dwOSVersionInfoSize = sizeof( aSalShlData.maVersionInfo ); |
| if ( GetVersionEx( &aSalShlData.maVersionInfo ) ) |
| { |
| if ( aSalShlData.maVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ) |
| { |
| // Windows XP ? |
| if ( aSalShlData.maVersionInfo.dwMajorVersion > 5 || |
| ( aSalShlData.maVersionInfo.dwMajorVersion == 5 && aSalShlData.maVersionInfo.dwMinorVersion >= 1 ) ) |
| aSalShlData.mbWXP = 1; |
| if( aSalShlData.maVersionInfo.dwMajorVersion >= 5 ) |
| aSalShlData.mbWPrinter = 1; |
| } |
| } |
| |
| pSalData->mnAppThreadId = GetCurrentThreadId(); |
| |
| // register frame class |
| if ( !pSalData->mhPrevInst ) |
| { |
| WNDCLASSEXW aWndClassEx; |
| aWndClassEx.cbSize = sizeof( aWndClassEx ); |
| aWndClassEx.style = CS_OWNDC; |
| aWndClassEx.lpfnWndProc = SalFrameWndProcW; |
| aWndClassEx.cbClsExtra = 0; |
| aWndClassEx.cbWndExtra = SAL_FRAME_WNDEXTRA; |
| aWndClassEx.hInstance = pSalData->mhInst; |
| aWndClassEx.hCursor = 0; |
| aWndClassEx.hbrBackground = 0; |
| aWndClassEx.lpszMenuName = 0; |
| aWndClassEx.lpszClassName = SAL_FRAME_CLASSNAMEW; |
| ImplLoadSalIcon( SAL_RESID_ICON_DEFAULT, aWndClassEx.hIcon, aWndClassEx.hIconSm ); |
| if ( !RegisterClassExW( &aWndClassEx ) ) |
| return NULL; |
| |
| aWndClassEx.hIcon = 0; |
| aWndClassEx.hIconSm = 0; |
| aWndClassEx.style |= CS_SAVEBITS; |
| aWndClassEx.lpszClassName = SAL_SUBFRAME_CLASSNAMEW; |
| if ( !RegisterClassExW( &aWndClassEx ) ) |
| return NULL; |
| |
| // shadow effect for popups on XP |
| if( aSalShlData.mbWXP ) |
| aWndClassEx.style |= CS_DROPSHADOW; |
| aWndClassEx.lpszClassName = SAL_TMPSUBFRAME_CLASSNAMEW; |
| if ( !RegisterClassExW( &aWndClassEx ) ) |
| return NULL; |
| |
| aWndClassEx.style = 0; |
| aWndClassEx.lpfnWndProc = SalComWndProcW; |
| aWndClassEx.cbWndExtra = 0; |
| aWndClassEx.lpszClassName = SAL_COM_CLASSNAMEW; |
| if ( !RegisterClassExW( &aWndClassEx ) ) |
| return NULL; |
| } |
| |
| HWND hComWnd = CreateWindowExW( WS_EX_TOOLWINDOW, SAL_COM_CLASSNAMEW, |
| L"", WS_POPUP, 0, 0, 0, 0, 0, 0, |
| pSalData->mhInst, NULL ); |
| if ( !hComWnd ) |
| return NULL; |
| |
| WinSalInstance* pInst = new WinSalInstance; |
| |
| // init instance (only one instance in this version !!!) |
| pSalData->mpFirstInstance = pInst; |
| pInst->mhInst = pSalData->mhInst; |
| pInst->mhComWnd = hComWnd; |
| |
| // init static GDI Data |
| ImplInitSalGDI(); |
| |
| return pInst; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void DestroySalInstance( SalInstance* pInst ) |
| { |
| SalData* pSalData = GetSalData(); |
| |
| // (only one instance in this version !!!) |
| |
| ImplFreeSalGDI(); |
| |
| // reset instance |
| if ( pSalData->mpFirstInstance == pInst ) |
| pSalData->mpFirstInstance = NULL; |
| |
| delete pInst; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| WinSalInstance::WinSalInstance() |
| { |
| mhComWnd = 0; |
| mpSalYieldMutex = new SalYieldMutex( this ); |
| mpSalWaitMutex = new vos::OMutex; |
| mnYieldWaitCount = 0; |
| mpSalYieldMutex->acquire(); |
| ::tools::SolarMutex::SetSolarMutex( mpSalYieldMutex ); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| WinSalInstance::~WinSalInstance() |
| { |
| ::tools::SolarMutex::SetSolarMutex( 0 ); |
| mpSalYieldMutex->release(); |
| delete mpSalYieldMutex; |
| delete mpSalWaitMutex; |
| DestroyWindow( mhComWnd ); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| vos::IMutex* WinSalInstance::GetYieldMutex() |
| { |
| return mpSalYieldMutex; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| sal_uLong WinSalInstance::ReleaseYieldMutex() |
| { |
| return ImplSalReleaseYieldMutex(); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void WinSalInstance::AcquireYieldMutex( sal_uLong nCount ) |
| { |
| ImplSalAcquireYieldMutex( nCount ); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| static void ImplSalDispatchMessage( MSG* pMsg ) |
| { |
| SalData* pSalData = GetSalData(); |
| if ( pSalData->mpFirstObject ) |
| { |
| if ( ImplSalPreDispatchMsg( pMsg ) ) |
| return; |
| } |
| LRESULT lResult = ImplDispatchMessage( pMsg ); |
| if ( pSalData->mpFirstObject ) |
| ImplSalPostDispatchMsg( pMsg, lResult ); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void ImplSalYield( sal_Bool bWait, sal_Bool bHandleAllCurrentEvents ) |
| { |
| MSG aMsg; |
| bool bWasMsg = false, bOneEvent = false; |
| |
| int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1; |
| do |
| { |
| if ( ImplPeekMessage( &aMsg, 0, 0, 0, PM_REMOVE ) ) |
| { |
| if ( !ImplInterceptChildWindowKeyDown( aMsg ) ) |
| { |
| TranslateMessage( &aMsg ); |
| ImplSalDispatchMessage( &aMsg ); |
| } |
| |
| bOneEvent = bWasMsg = true; |
| } |
| else |
| bOneEvent = false; |
| } while( --nMaxEvents && bOneEvent ); |
| |
| if ( bWait && ! bWasMsg ) |
| { |
| if ( ImplGetMessage( &aMsg, 0, 0, 0 ) ) |
| { |
| if ( !ImplInterceptChildWindowKeyDown( aMsg ) ) |
| { |
| TranslateMessage( &aMsg ); |
| ImplSalDispatchMessage( &aMsg ); |
| } |
| } |
| } |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void WinSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents ) |
| { |
| SalYieldMutex* pYieldMutex = mpSalYieldMutex; |
| SalData* pSalData = GetSalData(); |
| DWORD nCurThreadId = GetCurrentThreadId(); |
| sal_uLong nCount = pYieldMutex->GetAcquireCount( nCurThreadId ); |
| sal_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 ) |
| Sleep(1); |
| else |
| ImplSendMessage( mhComWnd, SAL_MSG_THREADYIELD, (WPARAM)bWait, (LPARAM)bHandleAllCurrentEvents ); |
| |
| n = nCount; |
| while ( n ) |
| { |
| pYieldMutex->acquire(); |
| n--; |
| } |
| } |
| else |
| { |
| ImplSalYield( bWait, bHandleAllCurrentEvents ); |
| |
| n = nCount; |
| while ( n ) |
| { |
| ImplSalYieldMutexAcquireWithWait(); |
| n--; |
| } |
| } |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| LRESULT CALLBACK SalComWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, int& rDef ) |
| { |
| LRESULT nRet = 0; |
| |
| |
| switch ( nMsg ) |
| { |
| case SAL_MSG_PRINTABORTJOB: |
| ImplSalPrinterAbortJobAsync( (HDC)wParam ); |
| rDef = FALSE; |
| break; |
| case SAL_MSG_THREADYIELD: |
| ImplSalYield( (sal_Bool)wParam, (sal_Bool)lParam ); |
| rDef = FALSE; |
| break; |
| // 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: |
| { |
| WinSalInstance* pInst = GetSalData()->mpFirstInstance; |
| if ( pInst && pInst->mnYieldWaitCount ) |
| ImplPostMessage( hWnd, SAL_MSG_RELEASEWAITYIELD, wParam, lParam ); |
| } |
| rDef = FALSE; |
| break; |
| case SAL_MSG_STARTTIMER: |
| ImplSalStartTimer( (sal_uLong) lParam, FALSE ); |
| rDef = FALSE; |
| break; |
| case SAL_MSG_CREATEFRAME: |
| nRet = (LRESULT)ImplSalCreateFrame( GetSalData()->mpFirstInstance, (HWND)lParam, (sal_uLong)wParam ); |
| rDef = FALSE; |
| break; |
| case SAL_MSG_RECREATEHWND: |
| nRet = (LRESULT)ImplSalReCreateHWND( (HWND)wParam, (HWND)lParam, FALSE ); |
| rDef = FALSE; |
| break; |
| case SAL_MSG_RECREATECHILDHWND: |
| nRet = (LRESULT)ImplSalReCreateHWND( (HWND)wParam, (HWND)lParam, TRUE ); |
| rDef = FALSE; |
| break; |
| case SAL_MSG_DESTROYFRAME: |
| delete (SalFrame*)lParam; |
| rDef = FALSE; |
| break; |
| case SAL_MSG_DESTROYHWND: |
| //We only destroy the native window here. We do NOT destroy the SalFrame contained |
| //in the structure (GetWindowPtr()). |
| if (DestroyWindow((HWND)lParam) == 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)lParam, 0); |
| } |
| rDef = FALSE; |
| break; |
| case SAL_MSG_CREATEOBJECT: |
| nRet = (LRESULT)ImplSalCreateObject( GetSalData()->mpFirstInstance, (WinSalFrame*)lParam ); |
| rDef = FALSE; |
| break; |
| case SAL_MSG_DESTROYOBJECT: |
| delete (SalObject*)lParam; |
| rDef = FALSE; |
| break; |
| case SAL_MSG_GETDC: |
| nRet = (LRESULT)GetDCEx( (HWND)wParam, 0, DCX_CACHE ); |
| rDef = FALSE; |
| break; |
| case SAL_MSG_RELEASEDC: |
| ReleaseDC( (HWND)wParam, (HDC)lParam ); |
| rDef = FALSE; |
| break; |
| case SAL_MSG_POSTTIMER: |
| SalTimerProc( 0, 0, SALTIMERPROC_RECURSIVE, lParam ); |
| break; |
| } |
| |
| return nRet; |
| } |
| |
| LRESULT CALLBACK SalComWndProcA( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ) |
| { |
| int bDef = TRUE; |
| LRESULT nRet = 0; |
| #ifdef __MINGW32__ |
| jmp_buf jmpbuf; |
| __SEHandler han; |
| if (__builtin_setjmp(jmpbuf) == 0) |
| { |
| han.Set(jmpbuf, NULL, (__SEHandler::PF)EXCEPTION_EXECUTE_HANDLER); |
| #else |
| __try |
| { |
| #endif |
| nRet = SalComWndProc( hWnd, nMsg, wParam, lParam, bDef ); |
| } |
| #ifdef __MINGW32__ |
| han.Reset(); |
| #else |
| __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation())) |
| { |
| } |
| #endif |
| if ( bDef ) |
| { |
| if ( !ImplHandleGlobalMsg( hWnd, nMsg, wParam, lParam, nRet ) ) |
| nRet = DefWindowProcA( hWnd, nMsg, wParam, lParam ); |
| } |
| return nRet; |
| } |
| |
| LRESULT CALLBACK SalComWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ) |
| { |
| int bDef = TRUE; |
| LRESULT nRet = 0; |
| #ifdef __MINGW32__ |
| jmp_buf jmpbuf; |
| __SEHandler han; |
| if (__builtin_setjmp(jmpbuf) == 0) |
| { |
| han.Set(jmpbuf, NULL, (__SEHandler::PF)EXCEPTION_EXECUTE_HANDLER); |
| #else |
| __try |
| { |
| #endif |
| nRet = SalComWndProc( hWnd, nMsg, wParam, lParam, bDef ); |
| } |
| #ifdef __MINGW32__ |
| han.Reset(); |
| #else |
| __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation())) |
| { |
| } |
| #endif |
| if ( bDef ) |
| { |
| if ( !ImplHandleGlobalMsg( hWnd, nMsg, wParam, lParam, nRet ) ) |
| nRet = DefWindowProcW( hWnd, nMsg, wParam, lParam ); |
| } |
| return nRet; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| bool WinSalInstance::AnyInput( sal_uInt16 nType ) |
| { |
| MSG aMsg; |
| |
| if ( (nType & (INPUT_ANY)) == (INPUT_ANY) ) |
| { |
| // revert bugfix for #108919# which never reported timeouts when called from the timer handler |
| // which made the application completely unresponsive during background formatting |
| if ( ImplPeekMessage( &aMsg, 0, 0, 0, PM_NOREMOVE | PM_NOYIELD ) ) |
| return true; |
| } |
| else |
| { |
| if ( nType & INPUT_MOUSE ) |
| { |
| // Test for mouse input |
| if ( ImplPeekMessage( &aMsg, 0, WM_MOUSEFIRST, WM_MOUSELAST, |
| PM_NOREMOVE | PM_NOYIELD ) ) |
| return true; |
| } |
| |
| if ( nType & INPUT_KEYBOARD ) |
| { |
| // Test for key input |
| if ( ImplPeekMessage( &aMsg, 0, WM_KEYDOWN, WM_KEYDOWN, |
| PM_NOREMOVE | PM_NOYIELD ) ) |
| { |
| if ( (aMsg.wParam == VK_SHIFT) || |
| (aMsg.wParam == VK_CONTROL) || |
| (aMsg.wParam == VK_MENU) ) |
| return false; |
| else |
| return true; |
| } |
| } |
| |
| if ( nType & INPUT_PAINT ) |
| { |
| // Test for paint input |
| if ( ImplPeekMessage( &aMsg, 0, WM_PAINT, WM_PAINT, |
| PM_NOREMOVE | PM_NOYIELD ) ) |
| return true; |
| |
| if ( ImplPeekMessage( &aMsg, 0, WM_SIZE, WM_SIZE, |
| PM_NOREMOVE | PM_NOYIELD ) ) |
| return true; |
| |
| if ( ImplPeekMessage( &aMsg, 0, SAL_MSG_POSTCALLSIZE, SAL_MSG_POSTCALLSIZE, |
| PM_NOREMOVE | PM_NOYIELD ) ) |
| return true; |
| |
| if ( ImplPeekMessage( &aMsg, 0, WM_MOVE, WM_MOVE, |
| PM_NOREMOVE | PM_NOYIELD ) ) |
| return true; |
| |
| if ( ImplPeekMessage( &aMsg, 0, SAL_MSG_POSTMOVE, SAL_MSG_POSTMOVE, |
| PM_NOREMOVE | PM_NOYIELD ) ) |
| return true; |
| } |
| |
| if ( nType & INPUT_TIMER ) |
| { |
| // Test for timer input |
| if ( ImplPeekMessage( &aMsg, 0, WM_TIMER, WM_TIMER, |
| PM_NOREMOVE | PM_NOYIELD ) ) |
| return true; |
| |
| } |
| |
| if ( nType & INPUT_OTHER ) |
| { |
| // Test for any input |
| if ( ImplPeekMessage( &aMsg, 0, 0, 0, PM_NOREMOVE | PM_NOYIELD ) ) |
| return true; |
| } |
| } |
| |
| return FALSE; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void SalTimer::Start( sal_uLong nMS ) |
| { |
| // Um auf Main-Thread umzuschalten |
| SalData* pSalData = GetSalData(); |
| if ( pSalData->mpFirstInstance ) |
| { |
| if ( pSalData->mnAppThreadId != GetCurrentThreadId() ) |
| ImplPostMessage( pSalData->mpFirstInstance->mhComWnd, SAL_MSG_STARTTIMER, 0, (LPARAM)nMS ); |
| else |
| ImplSendMessage( pSalData->mpFirstInstance->mhComWnd, SAL_MSG_STARTTIMER, 0, (LPARAM)nMS ); |
| } |
| else |
| ImplSalStartTimer( nMS, FALSE ); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| SalFrame* WinSalInstance::CreateChildFrame( SystemParentData* pSystemParentData, sal_uLong nSalFrameStyle ) |
| { |
| // Um auf Main-Thread umzuschalten |
| return (SalFrame*)ImplSendMessage( mhComWnd, SAL_MSG_CREATEFRAME, nSalFrameStyle, (LPARAM)pSystemParentData->hWnd ); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| SalFrame* WinSalInstance::CreateFrame( SalFrame* pParent, sal_uLong nSalFrameStyle ) |
| { |
| // Um auf Main-Thread umzuschalten |
| HWND hWndParent; |
| if ( pParent ) |
| hWndParent = static_cast<WinSalFrame*>(pParent)->mhWnd; |
| else |
| hWndParent = 0; |
| return (SalFrame*)ImplSendMessage( mhComWnd, SAL_MSG_CREATEFRAME, nSalFrameStyle, (LPARAM)hWndParent ); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void WinSalInstance::DestroyFrame( SalFrame* pFrame ) |
| { |
| ImplSendMessage( mhComWnd, SAL_MSG_DESTROYFRAME, 0, (LPARAM)pFrame ); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| SalObject* WinSalInstance::CreateObject( SalFrame* pParent, |
| SystemWindowData* /*pWindowData*/, // SystemWindowData meaningless on Windows |
| sal_Bool /*bShow*/ ) |
| { |
| // Um auf Main-Thread umzuschalten |
| return (SalObject*)ImplSendMessage( mhComWnd, SAL_MSG_CREATEOBJECT, 0, (LPARAM)static_cast<WinSalFrame*>(pParent) ); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void WinSalInstance::DestroyObject( SalObject* pObject ) |
| { |
| ImplSendMessage( mhComWnd, SAL_MSG_DESTROYOBJECT, 0, (LPARAM)pObject ); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void* WinSalInstance::GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes ) |
| { |
| rReturnedBytes = 1; |
| rReturnedType = AsciiCString; |
| return const_cast<char *>(""); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| /** Add a file to the system shells recent document list if there is any. |
| This function may have no effect under Unix because there is no |
| standard API among the different desktop managers. |
| |
| @param aFileUrl |
| The file url of the document. |
| */ |
| void WinSalInstance::AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& /*rMimeType*/) |
| { |
| rtl::OUString system_path; |
| osl::FileBase::RC rc = osl::FileBase::getSystemPathFromFileURL(rFileUrl, system_path); |
| |
| OSL_ENSURE(osl::FileBase::E_None == rc, "Invalid file url"); |
| |
| if (osl::FileBase::E_None == rc) |
| SHAddToRecentDocs(SHARD_PATHW, system_path.getStr()); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| SalTimer* WinSalInstance::CreateSalTimer() |
| { |
| return new WinSalTimer(); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| SalBitmap* WinSalInstance::CreateSalBitmap() |
| { |
| return new WinSalBitmap(); |
| } |
| |
| class WinImeStatus : public SalI18NImeStatus |
| { |
| public: |
| WinImeStatus() {} |
| virtual ~WinImeStatus() {} |
| |
| // asks whether there is a status window available |
| // to toggle into menubar |
| virtual bool canToggle() { return false; } |
| virtual void toggle() {} |
| }; |
| |
| SalI18NImeStatus* WinSalInstance::CreateI18NImeStatus() |
| { |
| return new WinImeStatus(); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| const ::rtl::OUString& SalGetDesktopEnvironment() |
| { |
| static ::rtl::OUString aDesktopEnvironment( RTL_CONSTASCII_USTRINGPARAM( "Windows" ) ); |
| return aDesktopEnvironment; |
| } |
| |
| SalSession* WinSalInstance::CreateSalSession() |
| { |
| return NULL; |
| } |
| |
| #ifndef __MINGW32__ |
| // ----------------------------------------------------------------------- |
| int WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(int, LPEXCEPTION_POINTERS pExceptionInfo) |
| { |
| // Decide if an exception is a c++ (mostly UNO) exception or a process violation. |
| // Depending on this information we pass process violations directly to our signal handler ... |
| // and c++ (UNO) exceptions are sended to the following code on the current stack. |
| // Problem behind: user32.dll sometime consumes exceptions/process violations .-) |
| // see also #112221# |
| |
| static DWORD EXCEPTION_MSC_CPP_EXCEPTION = 0xE06D7363; |
| |
| if (pExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_MSC_CPP_EXCEPTION) |
| return EXCEPTION_CONTINUE_SEARCH; |
| |
| return UnhandledExceptionFilter( pExceptionInfo ); |
| } |
| #endif |