diff options
Diffstat (limited to 'vcl/win/source/app/salinst.cxx')
-rw-r--r-- | vcl/win/source/app/salinst.cxx | 1173 |
1 files changed, 1173 insertions, 0 deletions
diff --git a/vcl/win/source/app/salinst.cxx b/vcl/win/source/app/salinst.cxx new file mode 100644 index 000000000000..97dbb5285cca --- /dev/null +++ b/vcl/win/source/app/salinst.cxx @@ -0,0 +1,1173 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 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/debug.hxx> +#include <wincomp.hxx> +#include <salids.hrc> +#include <saldata.hxx> +#include <salinst.h> +#include <salframe.h> +#include <salobj.h> +#include <vcl/salsys.hxx> +#include <saltimer.h> +#include <vcl/salatype.hxx> +#include <salbmp.h> +#include <vcl/salimestatus.hxx> +#include <vcl/timer.hxx> +#include <wincomp.hxx> // CS_DROPSHADOW +#include <tools/solarmutex.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; + ULONG mnCount; + DWORD mnThreadId; + +public: + SalYieldMutex( WinSalInstance* pInstData ); + + virtual void SAL_CALL acquire(); + virtual void SAL_CALL release(); + virtual sal_Bool SAL_CALL tryToAcquire(); + + ULONG GetAcquireCount( 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; +} + +// ----------------------------------------------------------------------- + +ULONG SalYieldMutex::GetAcquireCount( 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 + 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(); +} + +// ----------------------------------------------------------------------- + +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(); + } +} + +// ----------------------------------------------------------------------- + +ULONG ImplSalReleaseYieldMutex() +{ + WinSalInstance* 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 ) +{ + WinSalInstance* pInst = GetSalData()->mpFirstInstance; + if ( !pInst ) + return; + + SalYieldMutex* pYieldMutex = pInst->mpSalYieldMutex; + while ( nCount ) + { + pYieldMutex->acquire(); + nCount--; + } +} + +// ----------------------------------------------------------------------- + +#ifdef DBG_UTIL + +void ImplDbgTestSolarMutex() +{ + SalData* pSalData = GetSalData(); + DWORD nCurThreadId = GetCurrentThreadId(); + if ( pSalData->mnAppThreadId != nCurThreadId ) + { + if ( pSalData->mpFirstInstance ) + { + SalYieldMutex* pYieldMutex = pSalData->mpFirstInstance->mpSalYieldMutex; + if ( pYieldMutex->mnThreadId != nCurThreadId ) + { + DBG_ERROR( "SolarMutex not locked, and not thread save code in VCL is called from outside of the main thread" ); + } + } + } + else + { + if ( pSalData->mpFirstInstance ) + { + SalYieldMutex* pYieldMutex = pSalData->mpFirstInstance->mpSalYieldMutex; + if ( pYieldMutex->mnThreadId != nCurThreadId ) + { + DBG_ERROR( "SolarMutex not locked in the main thread" ); + } + } + } +} + +#endif + +// ======================================================================= + +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 + + // init with NULL + gdiplusToken = 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.mbWNT = 0; + 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 ) + { + aSalShlData.mbWNT = 1; + // 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 ) + { + if ( aSalShlData.mbWNT ) + { + 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; + } + else + { + WNDCLASSEXA aWndClassEx; + aWndClassEx.cbSize = sizeof( aWndClassEx ); + aWndClassEx.style = CS_OWNDC; + aWndClassEx.lpfnWndProc = SalFrameWndProcA; + 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_CLASSNAMEA; + ImplLoadSalIcon( SAL_RESID_ICON_DEFAULT, aWndClassEx.hIcon, aWndClassEx.hIconSm ); + if ( !RegisterClassExA( &aWndClassEx ) ) + return NULL; + + aWndClassEx.hIcon = 0; + aWndClassEx.hIconSm = 0; + aWndClassEx.style |= CS_SAVEBITS; + aWndClassEx.lpszClassName = SAL_SUBFRAME_CLASSNAMEA; + if ( !RegisterClassExA( &aWndClassEx ) ) + return NULL; + + aWndClassEx.style = 0; + aWndClassEx.lpfnWndProc = SalComWndProcA; + aWndClassEx.cbWndExtra = 0; + aWndClassEx.lpszClassName = SAL_COM_CLASSNAMEA; + if ( !RegisterClassExA( &aWndClassEx ) ) + return NULL; + } + } + + HWND hComWnd; + if ( aSalShlData.mbWNT ) + { + hComWnd = CreateWindowExW( WS_EX_TOOLWINDOW, SAL_COM_CLASSNAMEW, + L"", WS_POPUP, 0, 0, 0, 0, 0, 0, + pSalData->mhInst, NULL ); + } + else + { + hComWnd = CreateWindowExA( WS_EX_TOOLWINDOW, SAL_COM_CLASSNAMEA, + "", 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; +} + +// ----------------------------------------------------------------------- + +ULONG WinSalInstance::ReleaseYieldMutex() +{ + return ImplSalReleaseYieldMutex(); +} + +// ----------------------------------------------------------------------- + +void WinSalInstance::AcquireYieldMutex( 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( BOOL bWait, BOOL bHandleAllCurrentEvents ) +{ + MSG aMsg; + bool bWasMsg = false, bOneEvent = false; + + int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1; + do + { + if ( ImplPeekMessage( &aMsg, 0, 0, 0, PM_REMOVE ) ) + { + TranslateMessage( &aMsg ); + ImplSalDispatchMessage( &aMsg ); + bOneEvent = bWasMsg = true; + } + else + bOneEvent = false; + } while( --nMaxEvents && bOneEvent ); + + if ( bWait && ! bWasMsg ) + { + if ( ImplGetMessage( &aMsg, 0, 0, 0 ) ) + { + TranslateMessage( &aMsg ); + ImplSalDispatchMessage( &aMsg ); + } + } +} + +// ----------------------------------------------------------------------- + +void WinSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents ) +{ + SalYieldMutex* pYieldMutex = mpSalYieldMutex; + SalData* pSalData = GetSalData(); + DWORD 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 ) + 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( (BOOL)wParam, (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( (ULONG) lParam, FALSE ); + rDef = FALSE; + break; + case SAL_MSG_CREATEFRAME: + nRet = (LRESULT)ImplSalCreateFrame( GetSalData()->mpFirstInstance, (HWND)lParam, (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( USHORT 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( 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, ULONG nSalFrameStyle ) +{ + // Um auf Main-Thread umzuschalten + return (SalFrame*)ImplSendMessage( mhComWnd, SAL_MSG_CREATEFRAME, nSalFrameStyle, (LPARAM)pSystemParentData->hWnd ); +} + +// ----------------------------------------------------------------------- + +SalFrame* WinSalInstance::CreateFrame( SalFrame* pParent, 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 + 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 |