1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
24 #include <osl/conditn.hxx>
25 #include <osl/file.hxx>
26 #include <rtl/ustrbuf.hxx>
27 #include <sal/log.hxx>
28 #include <tools/debug.hxx>
29 #include <tools/time.hxx>
30 #include <comphelper/solarmutex.hxx>
31 #include <o3tl/char16_t2wchar_t.hxx>
33 #include <vcl/inputtypes.hxx>
34 #include <vcl/opengl/OpenGLHelper.hxx>
35 #include <vcl/opengl/OpenGLContext.hxx>
36 #include <vcl/timer.hxx>
37 #include <vclpluginapi.h>
39 #include <opengl/salbmp.hxx>
40 #include <opengl/win/gdiimpl.hxx>
41 #include <win/wincomp.hxx>
42 #include <win/salids.hrc>
43 #include <win/saldata.hxx>
44 #include <win/salinst.h>
45 #include <win/salframe.h>
46 #include <win/salobj.h>
47 #include <win/saltimer.h>
48 #include <win/salbmp.h>
49 #include <win/winlayout.hxx>
51 #include <config_features.h>
52 #include <vcl/skia/SkiaHelper.hxx>
54 #include <config_skia.h>
55 #include <skia/salbmp.hxx>
56 #include <skia/win/gdiimpl.hxx>
61 #include <desktop/crashreport.hxx>
65 #define min(a,b) (((a) < (b)) ? (a) : (b))
68 #define max(a,b) (((a) > (b)) ? (a) : (b))
79 void SalAbort( const OUString
& rErrorText
, bool )
83 if ( rErrorText
.isEmpty() )
85 // make sure crash reporter is triggered
86 RaiseException( 0, EXCEPTION_NONCONTINUABLE
, 0, nullptr );
87 FatalAppExitW( 0, L
"Application Error" );
91 CrashReporter::addKeyValue("AbortMessage", rErrorText
, CrashReporter::Write
);
92 // make sure crash reporter is triggered
93 RaiseException( 0, EXCEPTION_NONCONTINUABLE
, 0, nullptr );
94 FatalAppExitW( 0, o3tl::toW(rErrorText
.getStr()) );
98 static LRESULT CALLBACK
SalComWndProcW( HWND hWnd
, UINT nMsg
, WPARAM wParam
, LPARAM lParam
);
100 class SalYieldMutex
: public comphelper::SolarMutex
102 public: // for ImplSalYield() and ImplSalYieldMutexAcquireWithWait()
103 osl::Condition m_condition
; /// for MsgWaitForMultipleObjects()
106 virtual void doAcquire( sal_uInt32 nLockCount
) override
;
107 virtual sal_uInt32
doRelease( bool bUnlockAll
) override
;
109 static void BeforeReleaseHandler();
112 explicit SalYieldMutex();
114 virtual bool IsCurrentThread() const override
;
115 virtual bool tryToAcquire() override
;
118 SalYieldMutex::SalYieldMutex()
120 SetBeforeReleaseHandler( &SalYieldMutex::BeforeReleaseHandler
);
123 void SalYieldMutex::BeforeReleaseHandler()
125 OpenGLContext::prepareForYield();
127 if ( GetSalData()->mnAppThreadId
!= GetCurrentThreadId() )
129 // If we don't call these message, the Output from the
130 // Java clients doesn't come in the right order
135 /// note: while VCL is fully up and running (other threads started and
136 /// before shutdown), the main thread must acquire SolarMutex only via
137 /// this function to avoid deadlock
138 void SalYieldMutex::doAcquire( sal_uInt32 nLockCount
)
140 WinSalInstance
* pInst
= GetSalData()->mpInstance
;
141 if ( pInst
&& pInst
->IsMainThread() )
143 if ( pInst
->m_nNoYieldLock
)
145 // tdf#96887 If this is the main thread, then we must wait for two things:
146 // - the yield mutex being unlocked
147 // - SendMessage() being triggered
148 // This can nicely be done using MsgWaitForMultipleObjects, which is called in
149 // m_condition.wait(). The 2nd one is
150 // needed because if we don't reschedule, then we create deadlocks if a
151 // Window's create/destroy is called via SendMessage() from another thread.
152 // Have a look at the osl_waitCondition implementation for more info.
154 // reset condition *before* acquiring!
156 if (m_aMutex
.tryToAcquire())
158 // wait for SalYieldMutex::release() to set the condition
159 osl::Condition::Result res
= m_condition
.wait();
160 assert(osl::Condition::Result::result_ok
== res
);
169 comphelper::SolarMutex::doAcquire( nLockCount
);
172 sal_uInt32
SalYieldMutex::doRelease( const bool bUnlockAll
)
174 WinSalInstance
* pInst
= GetSalData()->mpInstance
;
175 if ( pInst
&& pInst
->m_nNoYieldLock
&& pInst
->IsMainThread() )
178 sal_uInt32 nCount
= comphelper::SolarMutex::doRelease( bUnlockAll
);
179 // wake up ImplSalYieldMutexAcquireWithWait() after release
185 bool SalYieldMutex::tryToAcquire()
187 WinSalInstance
* pInst
= GetSalData()->mpInstance
;
190 if ( pInst
->m_nNoYieldLock
&& pInst
->IsMainThread() )
193 return comphelper::SolarMutex::tryToAcquire();
199 void ImplSalYieldMutexAcquireWithWait( sal_uInt32 nCount
)
201 WinSalInstance
* pInst
= GetSalData()->mpInstance
;
203 pInst
->GetYieldMutex()->acquire( nCount
);
206 bool ImplSalYieldMutexTryToAcquire()
208 WinSalInstance
* pInst
= GetSalData()->mpInstance
;
209 return pInst
&& pInst
->GetYieldMutex()->tryToAcquire();
212 void ImplSalYieldMutexRelease()
214 WinSalInstance
* pInst
= GetSalData()->mpInstance
;
218 pInst
->GetYieldMutex()->release();
222 bool SalYieldMutex::IsCurrentThread() const
224 if ( !GetSalData()->mpInstance
->m_nNoYieldLock
)
225 return SolarMutex::IsCurrentThread();
227 return GetSalData()->mpInstance
->IsMainThread();
230 void SalData::initKeyCodeMap()
233 #define initKey( a, b )\
234 nKey = LOWORD( VkKeyScanW( a ) );\
240 initKey( L
'+', KEY_ADD
);
241 initKey( L
'-', KEY_SUBTRACT
);
242 initKey( L
'*', KEY_MULTIPLY
);
243 initKey( L
'/', KEY_DIVIDE
);
244 initKey( L
'.', KEY_POINT
);
245 initKey( L
',', KEY_COMMA
);
246 initKey( L
'<', KEY_LESS
);
247 initKey( L
'>', KEY_GREATER
);
248 initKey( L
'=', KEY_EQUAL
);
249 initKey( L
'~', KEY_TILDE
);
250 initKey( L
'`', KEY_QUOTELEFT
);
251 initKey( L
'[', KEY_BRACKETLEFT
);
252 initKey( L
']', KEY_BRACKETRIGHT
);
253 initKey( L
';', KEY_SEMICOLON
);
254 initKey( L
'\'', KEY_QUOTERIGHT
);
261 mhInst
= nullptr; // default instance handle
262 mnCmdShow
= 0; // default frame show style
263 mhDitherPal
= nullptr; // dither palette
264 mhDitherDIB
= nullptr; // dither memory handle
265 mpDitherDIB
= nullptr; // dither memory
266 mpDitherDIBData
= nullptr; // beginning of DIB data
267 mpDitherDiff
= nullptr; // Dither mapping table
268 mpDitherLow
= nullptr; // Dither mapping table
269 mpDitherHigh
= nullptr; // Dither mapping table
270 mhSalObjMsgHook
= nullptr; // hook to get interesting msg for SalObject
271 mhWantLeaveMsg
= nullptr; // window handle, that want a MOUSELEAVE message
272 mpMouseLeaveTimer
= nullptr; // Timer for MouseLeave Test
273 mpInstance
= nullptr; // pointer of first instance
274 mpFirstFrame
= nullptr; // pointer of first frame
275 mpFirstObject
= nullptr; // pointer of first object window
276 mpFirstVD
= nullptr; // first VirDev
277 mpFirstPrinter
= nullptr; // first printing printer
278 mpHDCCache
= nullptr; // Cache for three DC's
279 mh50Bmp
= nullptr; // 50% Bitmap
280 mh50Brush
= nullptr; // 50% Brush
282 for(i
=0; i
<MAX_STOCKPEN
; i
++)
284 maStockPenColorAry
[i
] = 0;
285 mhStockPenAry
[i
] = nullptr;
287 for(i
=0; i
<MAX_STOCKBRUSH
; i
++)
289 maStockBrushColorAry
[i
] = 0;
290 mhStockBrushAry
[i
] = nullptr;
292 mnStockPenCount
= 0; // count of static pens
293 mnStockBrushCount
= 0; // count of static brushes
294 mnSalObjWantKeyEvt
= 0; // KeyEvent for the SalObj hook
295 mnCacheDCInUse
= 0; // count of CacheDC in use
296 mbObjClassInit
= false; // is SALOBJECTCLASS initialised
297 mbInPalChange
= false; // is in WM_QUERYNEWPALETTE
298 mnAppThreadId
= 0; // Id from Application-Thread
299 mbScrSvrEnabled
= FALSE
; // ScreenSaver enabled
300 mpFirstIcon
= nullptr; // icon cache, points to first icon, NULL if none
301 mpSharedTempFontItem
= nullptr;
302 mpOtherTempFontItem
= nullptr;
303 mbThemeChanged
= false; // true if visual theme was changed: throw away theme handles
304 mbThemeMenuSupport
= false;
314 CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED
); // put main thread in Single Threaded Apartment (STA)
315 static Gdiplus::GdiplusStartupInput gdiplusStartupInput
;
316 Gdiplus::GdiplusStartup(&gdiplusToken
, &gdiplusStartupInput
, nullptr);
322 SetSalData( nullptr );
327 Gdiplus::GdiplusShutdown(gdiplusToken
);
331 VCLPLUG_WIN_PUBLIC SalInstance
* create_SalInstance()
333 SalData
* pSalData
= new SalData();
336 aSI
.cb
= sizeof( aSI
);
337 GetStartupInfoW( &aSI
);
338 pSalData
->mhInst
= GetModuleHandleW( nullptr );
339 pSalData
->mnCmdShow
= aSI
.wShowWindow
;
341 pSalData
->mnAppThreadId
= GetCurrentThreadId();
343 // register frame class
344 WNDCLASSEXW aWndClassEx
;
345 aWndClassEx
.cbSize
= sizeof( aWndClassEx
);
346 aWndClassEx
.style
= CS_OWNDC
;
347 aWndClassEx
.lpfnWndProc
= SalFrameWndProcW
;
348 aWndClassEx
.cbClsExtra
= 0;
349 aWndClassEx
.cbWndExtra
= SAL_FRAME_WNDEXTRA
;
350 aWndClassEx
.hInstance
= pSalData
->mhInst
;
351 aWndClassEx
.hCursor
= nullptr;
352 aWndClassEx
.hbrBackground
= nullptr;
353 aWndClassEx
.lpszMenuName
= nullptr;
354 aWndClassEx
.lpszClassName
= SAL_FRAME_CLASSNAMEW
;
355 ImplLoadSalIcon( SAL_RESID_ICON_DEFAULT
, aWndClassEx
.hIcon
, aWndClassEx
.hIconSm
);
356 if ( !RegisterClassExW( &aWndClassEx
) )
359 aWndClassEx
.hIcon
= nullptr;
360 aWndClassEx
.hIconSm
= nullptr;
361 aWndClassEx
.style
|= CS_SAVEBITS
;
362 aWndClassEx
.lpszClassName
= SAL_SUBFRAME_CLASSNAMEW
;
363 if ( !RegisterClassExW( &aWndClassEx
) )
366 // shadow effect for popups on XP
367 aWndClassEx
.style
|= CS_DROPSHADOW
;
368 aWndClassEx
.lpszClassName
= SAL_TMPSUBFRAME_CLASSNAMEW
;
369 if ( !RegisterClassExW( &aWndClassEx
) )
372 aWndClassEx
.style
= 0;
373 aWndClassEx
.lpfnWndProc
= SalComWndProcW
;
374 aWndClassEx
.cbWndExtra
= 0;
375 aWndClassEx
.lpszClassName
= SAL_COM_CLASSNAMEW
;
376 if ( !RegisterClassExW( &aWndClassEx
) )
379 HWND hComWnd
= CreateWindowExW( WS_EX_TOOLWINDOW
, SAL_COM_CLASSNAMEW
,
380 L
"", WS_POPUP
, 0, 0, 0, 0, nullptr, nullptr,
381 pSalData
->mhInst
, nullptr );
385 WinSalInstance
* pInst
= new WinSalInstance
;
387 // init instance (only one instance in this version !!!)
388 pSalData
->mpInstance
= pInst
;
389 pInst
->mhInst
= pSalData
->mhInst
;
390 pInst
->mhComWnd
= hComWnd
;
392 // init static GDI Data
399 WinSalInstance::WinSalInstance()
400 : SalInstance(std::make_unique
<SalYieldMutex
>())
402 , mhComWnd( nullptr )
403 , m_nNoYieldLock( 0 )
405 ImplSVData
* pSVData
= ImplGetSVData();
406 pSVData
->maAppData
.mxToolkitName
= OUString("win");
407 #if HAVE_FEATURE_SKIA
408 WinSkiaSalGraphicsImpl::prepareSkia();
412 WinSalInstance::~WinSalInstance()
415 DestroyWindow( mhComWnd
);
416 #if HAVE_FEATURE_SKIA
417 SkiaHelper::cleanup();
421 static LRESULT
ImplSalDispatchMessage( const MSG
* pMsg
)
423 SalData
* pSalData
= GetSalData();
424 if ( pSalData
->mpFirstObject
&& ImplSalPreDispatchMsg( pMsg
) )
426 LRESULT lResult
= DispatchMessageW( pMsg
);
427 if ( pSalData
->mpFirstObject
)
428 ImplSalPostDispatchMsg( pMsg
);
432 bool ImplSalYield( bool bWait
, bool bHandleAllCurrentEvents
)
434 static sal_uInt32 nLastTicks
= 0;
436 bool bWasMsg
= false, bOneEvent
= false, bWasTimeoutMsg
= false;
437 ImplSVData
*const pSVData
= ImplGetSVData();
438 WinSalTimer
* pTimer
= static_cast<WinSalTimer
*>( pSVData
->maSchedCtx
.mpSalTimer
);
439 const bool bNoYieldLock
= (GetSalData()->mpInstance
->m_nNoYieldLock
> 0);
441 assert( !bNoYieldLock
);
445 sal_uInt32 nCurTicks
= 0;
446 if ( bHandleAllCurrentEvents
)
447 nCurTicks
= GetTickCount();
449 bool bHadNewerEvent
= false;
452 bOneEvent
= PeekMessageW( &aMsg
, nullptr, 0, 0, PM_REMOVE
);
456 TranslateMessage( &aMsg
);
457 LRESULT nRet
= ImplSalDispatchMessage( &aMsg
);
459 if ( !bWasTimeoutMsg
)
460 bWasTimeoutMsg
= (SAL_MSG_TIMER_CALLBACK
== aMsg
.message
)
461 && static_cast<bool>( nRet
);
463 if ( bHandleAllCurrentEvents
464 && !bHadNewerEvent
&& aMsg
.time
> nCurTicks
465 && (nLastTicks
<= nCurTicks
|| aMsg
.time
< nLastTicks
) )
466 bHadNewerEvent
= true;
467 bOneEvent
= !bHadNewerEvent
;
470 if ( !(bHandleAllCurrentEvents
&& bOneEvent
) )
475 // 0ms timeouts are handled out-of-bounds to prevent busy-locking the
476 // event loop with timeout messages.
477 // We ensure we never handle more than one timeout per call.
478 // This way we'll always process a normal system message.
479 if ( !bWasTimeoutMsg
&& pTimer
&& pTimer
->IsDirectTimeout() )
481 pTimer
->ImplHandleElapsedTimer();
485 if ( bHandleAllCurrentEvents
)
486 nLastTicks
= nCurTicks
;
488 if ( bWait
&& !bWasMsg
)
490 if ( GetMessageW( &aMsg
, nullptr, 0, 0 ) )
493 TranslateMessage( &aMsg
);
494 ImplSalDispatchMessage( &aMsg
);
498 // we're back in the main loop after resize or move
500 pTimer
->SetForceRealTimer( false );
505 bool WinSalInstance::IsMainThread() const
507 const SalData
* pSalData
= GetSalData();
508 return pSalData
->mnAppThreadId
== GetCurrentThreadId();
511 bool WinSalInstance::DoYield(bool bWait
, bool bHandleAllCurrentEvents
)
513 bool bDidWork
= false;
514 SolarMutexReleaser aReleaser
;
515 if ( !IsMainThread() )
517 bDidWork
= SendMessageW( mhComWnd
, SAL_MSG_THREADYIELD
,
518 WPARAM(false), static_cast<LPARAM
>(bHandleAllCurrentEvents
) );
519 if ( !bDidWork
&& bWait
)
521 maWaitingYieldCond
.reset();
522 maWaitingYieldCond
.wait();
528 bDidWork
= ImplSalYield( bWait
, bHandleAllCurrentEvents
);
530 maWaitingYieldCond
.set();
536 #define CASE_NOYIELDLOCK( salmsg, function ) \
538 if (bIsOtherThreadMessage) \
540 ++pInst->m_nNoYieldLock; \
542 --pInst->m_nNoYieldLock; \
546 DBG_TESTSOLARMUTEX(); \
551 #define CASE_NOYIELDLOCK_RESULT( salmsg, function ) \
553 if (bIsOtherThreadMessage) \
555 ++pInst->m_nNoYieldLock; \
556 nRet = reinterpret_cast<LRESULT>( function ); \
557 --pInst->m_nNoYieldLock; \
561 DBG_TESTSOLARMUTEX(); \
562 nRet = reinterpret_cast<LRESULT>( function ); \
566 LRESULT CALLBACK
SalComWndProc( HWND
, UINT nMsg
, WPARAM wParam
, LPARAM lParam
, bool& rDef
)
568 const bool bIsOtherThreadMessage
= InSendMessage();
570 WinSalInstance
*pInst
= GetSalData()->mpInstance
;
571 WinSalTimer
*const pTimer
= static_cast<WinSalTimer
*>( ImplGetSVData()->maSchedCtx
.mpSalTimer
);
573 SAL_INFO("vcl.gdi.wndproc", "SalComWndProc(nMsg=" << nMsg
<< ", wParam=" << wParam
574 << ", lParam=" << lParam
<< "); inSendMsg: " << bIsOtherThreadMessage
);
576 if (ImplGetSVData()->mbDeInit
)
578 SAL_WARN("vcl.gdi.wndproc", "ignoring timer event because we are shutting down");
584 case SAL_MSG_THREADYIELD
:
585 assert( !static_cast<bool>(wParam
) );
586 nRet
= static_cast<LRESULT
>(ImplSalYield(
587 false, static_cast<bool>( lParam
) ));
590 case SAL_MSG_STARTTIMER
:
592 auto const nParam
= static_cast<sal_uInt64
>( lParam
);
593 sal_uInt64 nTime
= tools::Time::GetSystemTicks();
594 if ( nTime
< nParam
)
595 nTime
= nParam
- nTime
;
598 assert( pTimer
!= nullptr );
599 pTimer
->ImplStart( nTime
);
603 case SAL_MSG_STOPTIMER
:
604 assert( pTimer
!= nullptr );
608 CASE_NOYIELDLOCK_RESULT( SAL_MSG_CREATEFRAME
, ImplSalCreateFrame( GetSalData()->mpInstance
,
609 reinterpret_cast<HWND
>(lParam
), static_cast<SalFrameStyleFlags
>(wParam
)) )
610 CASE_NOYIELDLOCK_RESULT( SAL_MSG_RECREATEHWND
, ImplSalReCreateHWND(
611 reinterpret_cast<HWND
>(wParam
), reinterpret_cast<HWND
>(lParam
), false) )
612 CASE_NOYIELDLOCK_RESULT( SAL_MSG_RECREATECHILDHWND
, ImplSalReCreateHWND(
613 reinterpret_cast<HWND
>(wParam
), reinterpret_cast<HWND
>(lParam
), true) )
614 CASE_NOYIELDLOCK( SAL_MSG_DESTROYFRAME
, delete reinterpret_cast<SalFrame
*>(lParam
) )
616 case SAL_MSG_DESTROYHWND
:
617 // We only destroy the native window here. We do NOT destroy the SalFrame contained
618 // in the structure (GetWindowPtr()).
619 if (DestroyWindow(reinterpret_cast<HWND
>(lParam
)) == 0)
621 OSL_FAIL("DestroyWindow failed!");
622 // Failure: We remove the SalFrame from the window structure. So we avoid that
623 // the window structure may contain an invalid pointer, once the SalFrame is deleted.
624 SetWindowPtr(reinterpret_cast<HWND
>(lParam
), nullptr);
628 CASE_NOYIELDLOCK_RESULT( SAL_MSG_CREATEOBJECT
, ImplSalCreateObject(
629 GetSalData()->mpInstance
, reinterpret_cast<WinSalFrame
*>(lParam
)) )
630 CASE_NOYIELDLOCK( SAL_MSG_DESTROYOBJECT
, delete reinterpret_cast<SalObject
*>(lParam
) )
631 CASE_NOYIELDLOCK_RESULT( SAL_MSG_GETCACHEDDC
, GetDCEx(
632 reinterpret_cast<HWND
>(wParam
), nullptr, DCX_CACHE
) )
633 CASE_NOYIELDLOCK( SAL_MSG_RELEASEDC
, ReleaseDC(
634 reinterpret_cast<HWND
>(wParam
), reinterpret_cast<HDC
>(lParam
)) )
636 case SAL_MSG_TIMER_CALLBACK
:
637 assert( pTimer
!= nullptr );
638 pTimer
->ImplHandleTimerEvent( wParam
);
642 assert( pTimer
!= nullptr );
643 pTimer
->ImplHandle_WM_TIMER( wParam
);
646 case SAL_MSG_FORCE_REAL_TIMER
:
647 assert(pTimer
!= nullptr);
648 pTimer
->SetForceRealTimer(true);
662 #undef CASE_NOYIELDLOCK
663 #undef CASE_NOYIELDLOCK_RESULT
665 LRESULT CALLBACK
SalComWndProcW( HWND hWnd
, UINT nMsg
, WPARAM wParam
, LPARAM lParam
)
671 nRet
= SalComWndProc( hWnd
, nMsg
, wParam
, lParam
, bDef
);
673 __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))
678 if ( !ImplHandleGlobalMsg( hWnd
, nMsg
, wParam
, lParam
, nRet
) )
679 nRet
= DefWindowProcW( hWnd
, nMsg
, wParam
, lParam
);
694 static std::vector
<MsgRange
> GetOtherRanges( VclInputFlags nType
)
696 assert( nType
!= VCL_INPUT_ANY
);
698 // this array must be kept sorted!
699 const UINT nExcludeMsgIds
[] =
709 WM_MOUSEFIRST
, // 512
720 SAL_MSG_POSTMOVE
, // WM_USER+136
721 SAL_MSG_POSTCALLSIZE
, // WM_USER+137
723 SAL_MSG_TIMER_CALLBACK
, // WM_USER+162
727 const unsigned MAX_EXCL
= SAL_N_ELEMENTS( nExcludeMsgIds
);
729 bool aExcludeMsgList
[ MAX_EXCL
] = { false, };
730 std::vector
<MsgRange
> aResult
;
732 // set the excluded values
733 if ( !(nType
& VclInputFlags::MOUSE
) )
735 for ( unsigned i
= 0; nExcludeMsgIds
[ 6 + i
] <= WM_MOUSELAST
; ++i
)
736 aExcludeMsgList
[ 6 + i
] = true;
739 if ( !(nType
& VclInputFlags::KEYBOARD
) )
740 aExcludeMsgList
[ 4 ] = true;
742 if ( !(nType
& VclInputFlags::PAINT
) )
744 aExcludeMsgList
[ 1 ] = true;
745 aExcludeMsgList
[ 2 ] = true;
746 aExcludeMsgList
[ 3 ] = true;
747 aExcludeMsgList
[ 16 ] = true;
748 aExcludeMsgList
[ 17 ] = true;
751 if ( !(nType
& VclInputFlags::TIMER
) )
753 aExcludeMsgList
[ 5 ] = true;
754 aExcludeMsgList
[ 18 ] = true;
757 // build the message ranges to check
758 MsgRange aRange
= { 0, 0 };
760 for ( unsigned i
= 1; i
< MAX_EXCL
; ++i
)
762 if ( aExcludeMsgList
[ i
] )
766 if ( nExcludeMsgIds
[ i
] == aRange
.nStart
)
773 aRange
.nEnd
= nExcludeMsgIds
[ i
] - 1;
774 aResult
.push_back( aRange
);
776 aRange
.nStart
= aRange
.nEnd
+ 2;
781 if ( aRange
.nStart
!= UINT_MAX
)
783 aRange
.nEnd
= UINT_MAX
;
784 aResult
.push_back( aRange
);
790 bool WinSalInstance::AnyInput( VclInputFlags nType
)
794 if ( nType
& VclInputFlags::TIMER
)
796 const WinSalTimer
* pTimer
= static_cast<WinSalTimer
*>( ImplGetSVData()->maSchedCtx
.mpSalTimer
);
797 if ( pTimer
&& pTimer
->HasTimerElapsed() )
801 if ( (nType
& VCL_INPUT_ANY
) == VCL_INPUT_ANY
)
803 // revert bugfix for #108919# which never reported timeouts when called from the timer handler
804 // which made the application completely unresponsive during background formatting
805 if ( PeekMessageW( &aMsg
, nullptr, 0, 0, PM_NOREMOVE
| PM_NOYIELD
) )
810 const bool bCheck_KEYBOARD (nType
& VclInputFlags::KEYBOARD
);
811 const bool bCheck_OTHER (nType
& VclInputFlags::OTHER
);
813 // If there is a modifier key event, it counts as OTHER
814 // Previously we were simply ignoring these events...
815 if ( bCheck_KEYBOARD
|| bCheck_OTHER
)
817 if ( PeekMessageW( &aMsg
, nullptr, WM_KEYDOWN
, WM_KEYDOWN
,
818 PM_NOREMOVE
| PM_NOYIELD
) )
820 const bool bIsModifier
= ( (aMsg
.wParam
== VK_SHIFT
) ||
821 (aMsg
.wParam
== VK_CONTROL
) || (aMsg
.wParam
== VK_MENU
) );
822 if ( bCheck_KEYBOARD
&& !bIsModifier
)
824 if ( bCheck_OTHER
&& bIsModifier
)
829 // Other checks for all messages not excluded.
830 // The less we exclude, the less ranges have to be checked!
833 // TIMER and KEYBOARD are already handled, so always exclude them!
834 VclInputFlags nOtherType
= nType
&
835 ~VclInputFlags(VclInputFlags::KEYBOARD
| VclInputFlags::TIMER
);
837 std::vector
<MsgRange
> aMsgRangeList( GetOtherRanges( nOtherType
) );
838 for ( MsgRange
const & aRange
: aMsgRangeList
)
839 if ( PeekMessageW( &aMsg
, nullptr, aRange
.nStart
,
840 aRange
.nEnd
, PM_NOREMOVE
| PM_NOYIELD
) )
843 // MOUSE and PAINT already handled, so skip further checks
847 if ( nType
& VclInputFlags::MOUSE
)
849 if ( PeekMessageW( &aMsg
, nullptr, WM_MOUSEFIRST
, WM_MOUSELAST
,
850 PM_NOREMOVE
| PM_NOYIELD
) )
854 if ( nType
& VclInputFlags::PAINT
)
856 if ( PeekMessageW( &aMsg
, nullptr, WM_PAINT
, WM_PAINT
,
857 PM_NOREMOVE
| PM_NOYIELD
) )
860 if ( PeekMessageW( &aMsg
, nullptr, WM_SIZE
, WM_SIZE
,
861 PM_NOREMOVE
| PM_NOYIELD
) )
864 if ( PeekMessageW( &aMsg
, nullptr, SAL_MSG_POSTCALLSIZE
, SAL_MSG_POSTCALLSIZE
,
865 PM_NOREMOVE
| PM_NOYIELD
) )
868 if ( PeekMessageW( &aMsg
, nullptr, WM_MOVE
, WM_MOVE
,
869 PM_NOREMOVE
| PM_NOYIELD
) )
872 if ( PeekMessageW( &aMsg
, nullptr, SAL_MSG_POSTMOVE
, SAL_MSG_POSTMOVE
,
873 PM_NOREMOVE
| PM_NOYIELD
) )
881 SalFrame
* WinSalInstance::CreateChildFrame( SystemParentData
* pSystemParentData
, SalFrameStyleFlags nSalFrameStyle
)
883 // to switch to Main-Thread
884 return reinterpret_cast<SalFrame
*>(static_cast<sal_IntPtr
>(SendMessageW( mhComWnd
, SAL_MSG_CREATEFRAME
, static_cast<WPARAM
>(nSalFrameStyle
), reinterpret_cast<LPARAM
>(pSystemParentData
->hWnd
) )));
887 SalFrame
* WinSalInstance::CreateFrame( SalFrame
* pParent
, SalFrameStyleFlags nSalFrameStyle
)
889 // to switch to Main-Thread
892 hWndParent
= static_cast<WinSalFrame
*>(pParent
)->mhWnd
;
894 hWndParent
= nullptr;
895 return reinterpret_cast<SalFrame
*>(static_cast<sal_IntPtr
>(SendMessageW( mhComWnd
, SAL_MSG_CREATEFRAME
, static_cast<WPARAM
>(nSalFrameStyle
), reinterpret_cast<LPARAM
>(hWndParent
) )));
898 void WinSalInstance::DestroyFrame( SalFrame
* pFrame
)
900 OpenGLContext::prepareForYield();
901 SendMessageW( mhComWnd
, SAL_MSG_DESTROYFRAME
, 0, reinterpret_cast<LPARAM
>(pFrame
) );
904 SalObject
* WinSalInstance::CreateObject( SalFrame
* pParent
,
905 SystemWindowData
* /*pWindowData*/, // SystemWindowData meaningless on Windows
908 // to switch to Main-Thread
909 return reinterpret_cast<SalObject
*>(static_cast<sal_IntPtr
>(SendMessageW( mhComWnd
, SAL_MSG_CREATEOBJECT
, 0, reinterpret_cast<LPARAM
>(static_cast<WinSalFrame
*>(pParent
)) )));
912 void WinSalInstance::DestroyObject( SalObject
* pObject
)
914 SendMessageW( mhComWnd
, SAL_MSG_DESTROYOBJECT
, 0, reinterpret_cast<LPARAM
>(pObject
) );
917 OUString
WinSalInstance::GetConnectionIdentifier()
922 /** Add a file to the system shells recent document list if there is any.
923 This function may have no effect under Unix because there is no
924 standard API among the different desktop managers.
927 The file url of the document.
929 void WinSalInstance::AddToRecentDocumentList(const OUString
& rFileUrl
, const OUString
& /*rMimeType*/, const OUString
& rDocumentService
)
931 if (Application::IsHeadlessModeEnabled())
934 OUString system_path
;
935 osl::FileBase::RC rc
= osl::FileBase::getSystemPathFromFileURL(rFileUrl
, system_path
);
937 OSL_ENSURE(osl::FileBase::E_None
== rc
, "Invalid file url");
939 if (osl::FileBase::E_None
== rc
)
941 IShellItem
* pShellItem
= nullptr;
943 HRESULT hr
= SHCreateItemFromParsingName(o3tl::toW(system_path
.getStr()), nullptr, IID_PPV_ARGS(&pShellItem
));
945 if ( SUCCEEDED(hr
) && pShellItem
)
947 OUString sApplicationName
;
949 if ( rDocumentService
== "com.sun.star.text.TextDocument" ||
950 rDocumentService
== "com.sun.star.text.GlobalDocument" ||
951 rDocumentService
== "com.sun.star.text.WebDocument" ||
952 rDocumentService
== "com.sun.star.xforms.XMLFormDocument" )
953 sApplicationName
= "Writer";
954 else if ( rDocumentService
== "com.sun.star.sheet.SpreadsheetDocument" ||
955 rDocumentService
== "com.sun.star.chart2.ChartDocument" )
956 sApplicationName
= "Calc";
957 else if ( rDocumentService
== "com.sun.star.presentation.PresentationDocument" )
958 sApplicationName
= "Impress";
959 else if ( rDocumentService
== "com.sun.star.drawing.DrawingDocument" )
960 sApplicationName
= "Draw";
961 else if ( rDocumentService
== "com.sun.star.formula.FormulaProperties" )
962 sApplicationName
= "Math";
963 else if ( rDocumentService
== "com.sun.star.sdb.DatabaseDocument" ||
964 rDocumentService
== "com.sun.star.sdb.OfficeDatabaseDocument" ||
965 rDocumentService
== "com.sun.star.sdb.RelationDesign" ||
966 rDocumentService
== "com.sun.star.sdb.QueryDesign" ||
967 rDocumentService
== "com.sun.star.sdb.TableDesign" ||
968 rDocumentService
== "com.sun.star.sdb.DataSourceBrowser" )
969 sApplicationName
= "Base";
971 if ( !sApplicationName
.isEmpty() )
973 OUString
sApplicationID("TheDocumentFoundation.LibreOffice." + sApplicationName
);
976 info
.psi
= pShellItem
;
977 info
.pszAppID
= o3tl::toW(sApplicationID
.getStr());
979 SHAddToRecentDocs ( SHARD_APPIDINFO
, &info
);
983 // For whatever reason, we could not use the SHARD_APPIDINFO semantics
984 SHAddToRecentDocs(SHARD_PATHW
, system_path
.getStr());
988 SalTimer
* WinSalInstance::CreateSalTimer()
990 return new WinSalTimer();
993 std::shared_ptr
<SalBitmap
> WinSalInstance::CreateSalBitmap()
995 #if HAVE_FEATURE_SKIA
996 if (SkiaHelper::isVCLSkiaEnabled())
997 return std::make_shared
<SkiaSalBitmap
>();
1000 if (OpenGLHelper::isVCLOpenGLEnabled())
1001 return std::make_shared
<OpenGLSalBitmap
>();
1003 return std::make_shared
<WinSalBitmap
>();
1006 int WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(int, LPEXCEPTION_POINTERS pExceptionInfo
)
1008 // Decide if an exception is a c++ (mostly UNO) exception or a process violation.
1009 // Depending on this information we pass process violations directly to our signal handler ...
1010 // and c++ (UNO) exceptions are sended to the following code on the current stack.
1011 // Problem behind: user32.dll sometime consumes exceptions/process violations .-)
1012 // see also #112221#
1014 static const DWORD EXCEPTION_MSC_CPP_EXCEPTION
= 0xE06D7363;
1016 if (pExceptionInfo
->ExceptionRecord
->ExceptionCode
== EXCEPTION_MSC_CPP_EXCEPTION
)
1017 return EXCEPTION_CONTINUE_SEARCH
;
1019 return UnhandledExceptionFilter( pExceptionInfo
);
1022 typedef LONG NTSTATUS
;
1023 typedef NTSTATUS(WINAPI
* RtlGetVersion_t
)(PRTL_OSVERSIONINFOW
);
1024 constexpr NTSTATUS STATUS_SUCCESS
= 0x00000000;
1026 OUString
WinSalInstance::getOSVersion()
1028 OUStringBuffer
aVer(50); // capacity for string like "Windows 6.1 Service Pack 1 build 7601"
1029 aVer
.append("Windows ");
1030 // GetVersion(Ex) and VersionHelpers (based on VerifyVersionInfo) API are
1031 // subject to manifest-based behavior since Windows 8.1, so give wrong results.
1032 // Another approach would be to use NetWkstaGetInfo, but that has some small
1033 // reported delays (some milliseconds), and might get slower in domains with
1034 // poor network connections.
1035 // So go with a solution described at https://msdn.microsoft.com/en-us/library/ms724429
1036 bool bHaveVerFromKernel32
= false;
1037 if (HMODULE h_kernel32
= GetModuleHandleW(L
"kernel32.dll"))
1039 wchar_t szPath
[MAX_PATH
];
1040 DWORD dwCount
= GetModuleFileNameW(h_kernel32
, szPath
, SAL_N_ELEMENTS(szPath
));
1041 if (dwCount
!= 0 && dwCount
< SAL_N_ELEMENTS(szPath
))
1043 dwCount
= GetFileVersionInfoSizeW(szPath
, nullptr);
1046 std::unique_ptr
<char[]> ver(new char[dwCount
]);
1047 if (GetFileVersionInfoW(szPath
, 0, dwCount
, ver
.get()) != FALSE
)
1049 void* pBlock
= nullptr;
1051 if (VerQueryValueW(ver
.get(), L
"\\", &pBlock
, &dwBlockSz
) != FALSE
&& dwBlockSz
>= sizeof(VS_FIXEDFILEINFO
))
1053 VS_FIXEDFILEINFO
* vi1
= static_cast<VS_FIXEDFILEINFO
*>(pBlock
);
1054 aVer
.append(OUString::number(HIWORD(vi1
->dwProductVersionMS
)) + "."
1055 + OUString::number(LOWORD(vi1
->dwProductVersionMS
)));
1056 bHaveVerFromKernel32
= true;
1062 // Now use RtlGetVersion (which is not subject to deprecation for GetVersion(Ex) API)
1063 // to get build number and SP info
1064 bool bHaveVerFromRtlGetVersion
= false;
1065 if (HMODULE h_ntdll
= GetModuleHandleW(L
"ntdll.dll"))
1067 if (auto RtlGetVersion
1068 = reinterpret_cast<RtlGetVersion_t
>(GetProcAddress(h_ntdll
, "RtlGetVersion")))
1070 RTL_OSVERSIONINFOW vi2
{}; // initialize with zeroes - a better alternative to memset
1071 vi2
.dwOSVersionInfoSize
= sizeof(vi2
);
1072 if (STATUS_SUCCESS
== RtlGetVersion(&vi2
))
1074 if (!bHaveVerFromKernel32
) // we failed above; let's hope this would be useful
1075 aVer
.append(OUString::number(vi2
.dwMajorVersion
) + "."
1076 + OUString::number(vi2
.dwMinorVersion
));
1078 if (vi2
.szCSDVersion
[0])
1079 aVer
.append(o3tl::toU(vi2
.szCSDVersion
)).append(" ");
1080 aVer
.append("Build " + OUString::number(vi2
.dwBuildNumber
));
1081 bHaveVerFromRtlGetVersion
= true;
1085 if (!bHaveVerFromKernel32
&& !bHaveVerFromRtlGetVersion
)
1086 aVer
.append("unknown");
1087 return aVer
.makeStringAndClear();
1090 std::shared_ptr
<vcl::BackendCapabilities
> WinSalInstance::GetBackendCapabilities()
1092 auto pBackendCapabilities
= SalInstance::GetBackendCapabilities();
1093 #if HAVE_FEATURE_SKIA
1094 #if SKIA_USE_BITMAP32
1095 if( SkiaHelper::isVCLSkiaEnabled())
1096 pBackendCapabilities
->mbSupportsBitmap32
= true;
1099 return pBackendCapabilities
;
1102 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */