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 <tools/time.hxx>
27 #include <comphelper/solarmutex.hxx>
28 #include <o3tl/char16_t2wchar_t.hxx>
30 #include <vcl/inputtypes.hxx>
31 #include <vcl/opengl/OpenGLHelper.hxx>
32 #include <vcl/opengl/OpenGLContext.hxx>
33 #include <vcl/timer.hxx>
35 #include <opengl/salbmp.hxx>
36 #include <opengl/win/gdiimpl.hxx>
37 #include <win/wincomp.hxx>
38 #include <win/salids.hrc>
39 #include <win/saldata.hxx>
40 #include <win/salinst.h>
41 #include <win/salframe.h>
42 #include <win/salobj.h>
43 #include <win/saltimer.h>
44 #include <win/salbmp.h>
45 #include <win/winlayout.hxx>
47 #include <salimestatus.hxx>
50 #include <desktop/crashreport.hxx>
54 #define min(a,b) (((a) < (b)) ? (a) : (b))
57 #define max(a,b) (((a) > (b)) ? (a) : (b))
68 void SalAbort( const OUString
& rErrorText
, bool )
72 if ( rErrorText
.isEmpty() )
74 // make sure crash reporter is triggered
75 RaiseException( 0, EXCEPTION_NONCONTINUABLE
, 0, nullptr );
76 FatalAppExitW( 0, L
"Application Error" );
80 CrashReporter::AddKeyValue("AbortMessage", rErrorText
);
81 // make sure crash reporter is triggered
82 RaiseException( 0, EXCEPTION_NONCONTINUABLE
, 0, nullptr );
83 FatalAppExitW( 0, o3tl::toW(rErrorText
.getStr()) );
87 LRESULT CALLBACK
SalComWndProcW( HWND hWnd
, UINT nMsg
, WPARAM wParam
, LPARAM lParam
);
89 class SalYieldMutex
: public comphelper::GenericSolarMutex
91 public: // for ImplSalYield() and ImplSalYieldMutexAcquireWithWait()
92 osl::Condition m_condition
; /// for MsgWaitForMultipleObjects()
95 virtual void doAcquire( sal_uInt32 nLockCount
) override
;
96 virtual sal_uInt32
doRelease( bool bUnlockAll
) override
;
98 static void BeforeReleaseHandler();
101 explicit SalYieldMutex();
103 virtual bool IsCurrentThread() const override
;
104 virtual bool tryToAcquire() override
;
107 SalYieldMutex::SalYieldMutex()
109 SetBeforeReleaseHandler( &SalYieldMutex::BeforeReleaseHandler
);
112 void SalYieldMutex::BeforeReleaseHandler()
114 OpenGLContext::prepareForYield();
116 if ( GetSalData()->mnAppThreadId
!= GetCurrentThreadId() )
118 // If we don't call these message, the Output from the
119 // Java clients doesn't come in the right order
124 /// note: while VCL is fully up and running (other threads started and
125 /// before shutdown), the main thread must acquire SolarMutex only via
126 /// this function to avoid deadlock
127 void SalYieldMutex::doAcquire( sal_uInt32 nLockCount
)
129 WinSalInstance
* pInst
= GetSalData()->mpInstance
;
130 if ( pInst
&& pInst
->IsMainThread() )
132 if ( pInst
->m_nNoYieldLock
)
134 // tdf#96887 If this is the main thread, then we must wait for two things:
135 // - the mpSalYieldMutex being freed
136 // - SendMessage() being triggered
137 // This can nicely be done using MsgWaitForMultipleObjects. The 2nd one is
138 // needed because if we don't reschedule, then we create deadlocks if a
139 // Window's create/destroy is called via SendMessage() from another thread.
140 // Have a look at the osl_waitCondition implementation for more info.
142 // reset condition *before* acquiring!
144 if (m_aMutex
.tryToAcquire())
146 // wait for SalYieldMutex::release() to set the condition
147 osl::Condition::Result res
= m_condition
.wait();
148 assert(osl::Condition::Result::result_ok
== res
);
157 comphelper::GenericSolarMutex::doAcquire( nLockCount
);
160 sal_uInt32
SalYieldMutex::doRelease( const bool bUnlockAll
)
162 WinSalInstance
* pInst
= GetSalData()->mpInstance
;
163 if ( pInst
&& pInst
->m_nNoYieldLock
&& pInst
->IsMainThread() )
166 sal_uInt32 nCount
= comphelper::GenericSolarMutex::doRelease( bUnlockAll
);
167 // wake up ImplSalYieldMutexAcquireWithWait() after release
173 bool SalYieldMutex::tryToAcquire()
175 WinSalInstance
* pInst
= GetSalData()->mpInstance
;
178 if ( pInst
->m_nNoYieldLock
&& pInst
->IsMainThread() )
181 return comphelper::GenericSolarMutex::tryToAcquire();
187 void ImplSalYieldMutexAcquireWithWait( sal_uInt32 nCount
)
189 WinSalInstance
* pInst
= GetSalData()->mpInstance
;
191 pInst
->mpSalYieldMutex
->acquire( nCount
);
194 bool ImplSalYieldMutexTryToAcquire()
196 WinSalInstance
* pInst
= GetSalData()->mpInstance
;
197 return pInst
&& pInst
->mpSalYieldMutex
->tryToAcquire();
200 void ImplSalYieldMutexRelease()
202 WinSalInstance
* pInst
= GetSalData()->mpInstance
;
206 pInst
->mpSalYieldMutex
->release();
210 bool SalYieldMutex::IsCurrentThread() const
212 if ( !GetSalData()->mpInstance
->m_nNoYieldLock
)
213 // For the Windows backend, the LO identifier is the system thread ID
214 return m_nThreadId
== GetCurrentThreadId();
216 return GetSalData()->mpInstance
->IsMainThread();
219 void SalData::initKeyCodeMap()
222 #define initKey( a, b )\
223 nKey = LOWORD( VkKeyScanW( a ) );\
229 initKey( L
'+', KEY_ADD
);
230 initKey( L
'-', KEY_SUBTRACT
);
231 initKey( L
'*', KEY_MULTIPLY
);
232 initKey( L
'/', KEY_DIVIDE
);
233 initKey( L
'.', KEY_POINT
);
234 initKey( L
',', KEY_COMMA
);
235 initKey( L
'<', KEY_LESS
);
236 initKey( L
'>', KEY_GREATER
);
237 initKey( L
'=', KEY_EQUAL
);
238 initKey( L
'~', KEY_TILDE
);
239 initKey( L
'`', KEY_QUOTELEFT
);
240 initKey( L
'[', KEY_BRACKETLEFT
);
241 initKey( L
']', KEY_BRACKETRIGHT
);
242 initKey( L
';', KEY_SEMICOLON
);
243 initKey( L
'\'', KEY_QUOTERIGHT
);
250 mhInst
= nullptr; // default instance handle
251 mnCmdShow
= 0; // default frame show style
252 mhDitherPal
= nullptr; // dither palette
253 mhDitherDIB
= nullptr; // dither memory handle
254 mpDitherDIB
= nullptr; // dither memory
255 mpDitherDIBData
= nullptr; // beginning of DIB data
256 mpDitherDiff
= nullptr; // Dither mapping table
257 mpDitherLow
= nullptr; // Dither mapping table
258 mpDitherHigh
= nullptr; // Dither mapping table
259 mhSalObjMsgHook
= nullptr; // hook to get interesting msg for SalObject
260 mhWantLeaveMsg
= nullptr; // window handle, that want a MOUSELEAVE message
261 mpMouseLeaveTimer
= nullptr; // Timer for MouseLeave Test
262 mpInstance
= nullptr; // pointer of first instance
263 mpFirstFrame
= nullptr; // pointer of first frame
264 mpFirstObject
= nullptr; // pointer of first object window
265 mpFirstVD
= nullptr; // first VirDev
266 mpFirstPrinter
= nullptr; // first printing printer
267 mpHDCCache
= nullptr; // Cache for three DC's
268 mh50Bmp
= nullptr; // 50% Bitmap
269 mh50Brush
= nullptr; // 50% Brush
271 for(i
=0; i
<MAX_STOCKPEN
; i
++)
273 maStockPenColorAry
[i
] = 0;
274 mhStockPenAry
[i
] = nullptr;
276 for(i
=0; i
<MAX_STOCKBRUSH
; i
++)
278 maStockBrushColorAry
[i
] = 0;
279 mhStockBrushAry
[i
] = nullptr;
281 mnStockPenCount
= 0; // count of static pens
282 mnStockBrushCount
= 0; // count of static brushes
283 mnSalObjWantKeyEvt
= 0; // KeyEvent for the SalObj hook
284 mnCacheDCInUse
= 0; // count of CacheDC in use
285 mbObjClassInit
= false; // is SALOBJECTCLASS initialised
286 mbInPalChange
= false; // is in WM_QUERYNEWPALETTE
287 mnAppThreadId
= 0; // Id from Application-Thread
288 mbScrSvrEnabled
= FALSE
; // ScreenSaver enabled
289 mpFirstIcon
= nullptr; // icon cache, points to first icon, NULL if none
290 mpTempFontItem
= nullptr;
291 mbThemeChanged
= false; // true if visual theme was changed: throw away theme handles
292 mbThemeMenuSupport
= false;
306 SetSalData( nullptr );
311 SalData
* pSalData
= new SalData
;
312 CoInitialize(nullptr); // put main thread in Single Threaded Apartment (STA)
315 static Gdiplus::GdiplusStartupInput gdiplusStartupInput
;
316 Gdiplus::GdiplusStartup(&pSalData
->gdiplusToken
, &gdiplusStartupInput
, nullptr);
322 SalData
* pSalData
= GetSalData();
327 Gdiplus::GdiplusShutdown(pSalData
->gdiplusToken
);
335 // remember data, copied from WinMain
336 SalData
* pData
= GetSalData();
337 if ( pData
) // Im AppServer NULL
340 aSI
.cb
= sizeof( aSI
);
341 GetStartupInfoW( &aSI
);
342 pData
->mhInst
= GetModuleHandleW( nullptr );
343 pData
->mnCmdShow
= aSI
.wShowWindow
;
347 SalInstance
* CreateSalInstance()
349 SalData
* pSalData
= GetSalData();
351 pSalData
->mnAppThreadId
= GetCurrentThreadId();
353 // register frame class
354 WNDCLASSEXW aWndClassEx
;
355 aWndClassEx
.cbSize
= sizeof( aWndClassEx
);
356 aWndClassEx
.style
= CS_OWNDC
;
357 aWndClassEx
.lpfnWndProc
= SalFrameWndProcW
;
358 aWndClassEx
.cbClsExtra
= 0;
359 aWndClassEx
.cbWndExtra
= SAL_FRAME_WNDEXTRA
;
360 aWndClassEx
.hInstance
= pSalData
->mhInst
;
361 aWndClassEx
.hCursor
= nullptr;
362 aWndClassEx
.hbrBackground
= nullptr;
363 aWndClassEx
.lpszMenuName
= nullptr;
364 aWndClassEx
.lpszClassName
= SAL_FRAME_CLASSNAMEW
;
365 ImplLoadSalIcon( SAL_RESID_ICON_DEFAULT
, aWndClassEx
.hIcon
, aWndClassEx
.hIconSm
);
366 if ( !RegisterClassExW( &aWndClassEx
) )
369 aWndClassEx
.hIcon
= nullptr;
370 aWndClassEx
.hIconSm
= nullptr;
371 aWndClassEx
.style
|= CS_SAVEBITS
;
372 aWndClassEx
.lpszClassName
= SAL_SUBFRAME_CLASSNAMEW
;
373 if ( !RegisterClassExW( &aWndClassEx
) )
376 // shadow effect for popups on XP
377 aWndClassEx
.style
|= CS_DROPSHADOW
;
378 aWndClassEx
.lpszClassName
= SAL_TMPSUBFRAME_CLASSNAMEW
;
379 if ( !RegisterClassExW( &aWndClassEx
) )
382 aWndClassEx
.style
= 0;
383 aWndClassEx
.lpfnWndProc
= SalComWndProcW
;
384 aWndClassEx
.cbWndExtra
= 0;
385 aWndClassEx
.lpszClassName
= SAL_COM_CLASSNAMEW
;
386 if ( !RegisterClassExW( &aWndClassEx
) )
389 HWND hComWnd
= CreateWindowExW( WS_EX_TOOLWINDOW
, SAL_COM_CLASSNAMEW
,
390 L
"", WS_POPUP
, 0, 0, 0, 0, nullptr, nullptr,
391 pSalData
->mhInst
, nullptr );
395 WinSalInstance
* pInst
= new WinSalInstance
;
397 // init instance (only one instance in this version !!!)
398 pSalData
->mpInstance
= pInst
;
399 pInst
->mhInst
= pSalData
->mhInst
;
400 pInst
->mhComWnd
= hComWnd
;
402 // init static GDI Data
408 void DestroySalInstance( SalInstance
* pInst
)
410 SalData
* pSalData
= GetSalData();
412 // (only one instance in this version !!!)
417 if ( pSalData
->mpInstance
== pInst
)
418 pSalData
->mpInstance
= nullptr;
423 WinSalInstance::WinSalInstance()
424 : mhComWnd( nullptr )
425 , m_nNoYieldLock( 0 )
427 mpSalYieldMutex
= new SalYieldMutex();
428 mpSalYieldMutex
->acquire();
431 WinSalInstance::~WinSalInstance()
433 mpSalYieldMutex
->release();
434 delete mpSalYieldMutex
;
435 DestroyWindow( mhComWnd
);
438 comphelper::SolarMutex
* WinSalInstance::GetYieldMutex()
440 return mpSalYieldMutex
;
443 sal_uInt32
WinSalInstance::ReleaseYieldMutexAll()
445 return mpSalYieldMutex
->release( true/*bUnlockAll*/ );
448 void WinSalInstance::AcquireYieldMutex( sal_uInt32 nCount
)
450 mpSalYieldMutex
->acquire( nCount
);
453 static LRESULT
ImplSalDispatchMessage( const MSG
* pMsg
)
455 SalData
* pSalData
= GetSalData();
456 if ( pSalData
->mpFirstObject
&& ImplSalPreDispatchMsg( pMsg
) )
458 LRESULT lResult
= DispatchMessageW( pMsg
);
459 if ( pSalData
->mpFirstObject
)
460 ImplSalPostDispatchMsg( pMsg
);
464 bool ImplSalYield( bool bWait
, bool bHandleAllCurrentEvents
)
466 static sal_uInt32 nLastTicks
= 0;
468 bool bWasMsg
= false, bOneEvent
= false, bWasTimeoutMsg
= false;
469 ImplSVData
*const pSVData
= ImplGetSVData();
470 WinSalTimer
* pTimer
= static_cast<WinSalTimer
*>( pSVData
->maSchedCtx
.mpSalTimer
);
471 const bool bNoYieldLock
= (GetSalData()->mpInstance
->m_nNoYieldLock
> 0);
473 assert( !bNoYieldLock
);
477 sal_uInt32 nCurTicks
= 0;
478 if ( bHandleAllCurrentEvents
)
479 nCurTicks
= GetTickCount();
481 bool bHadNewerEvent
= false;
484 bOneEvent
= PeekMessageW( &aMsg
, nullptr, 0, 0, PM_REMOVE
);
488 TranslateMessage( &aMsg
);
489 LRESULT nRet
= ImplSalDispatchMessage( &aMsg
);
491 if ( !bWasTimeoutMsg
)
492 bWasTimeoutMsg
= (SAL_MSG_TIMER_CALLBACK
== aMsg
.message
)
493 && static_cast<bool>( nRet
);
495 if ( bHandleAllCurrentEvents
496 && !bHadNewerEvent
&& aMsg
.time
> nCurTicks
497 && (nLastTicks
<= nCurTicks
|| aMsg
.time
< nLastTicks
) )
498 bHadNewerEvent
= true;
499 bOneEvent
= !bHadNewerEvent
;
502 if ( !(bHandleAllCurrentEvents
&& bOneEvent
) )
507 // 0ms timeouts are handled out-of-bounds to prevent busy-locking the
508 // event loop with timeout messages.
509 // We ensure we never handle more then one timeout per call.
510 // This way we'll always process a normal system message.
511 if ( !bWasTimeoutMsg
&& pTimer
&& pTimer
->IsDirectTimeout() )
513 pTimer
->ImplHandleElapsedTimer();
517 if ( bHandleAllCurrentEvents
)
518 nLastTicks
= nCurTicks
;
520 if ( bWait
&& !bWasMsg
)
522 if ( GetMessageW( &aMsg
, nullptr, 0, 0 ) )
525 TranslateMessage( &aMsg
);
526 ImplSalDispatchMessage( &aMsg
);
530 // we're back in the main loop after resize or move
532 pTimer
->SetForceRealTimer( false );
537 bool WinSalInstance::IsMainThread() const
539 const SalData
* pSalData
= GetSalData();
540 return pSalData
->mnAppThreadId
== GetCurrentThreadId();
543 bool WinSalInstance::DoYield(bool bWait
, bool bHandleAllCurrentEvents
)
545 bool bDidWork
= false;
546 SolarMutexReleaser aReleaser
;
547 if ( !IsMainThread() )
549 bDidWork
= SendMessageW( mhComWnd
, SAL_MSG_THREADYIELD
,
550 WPARAM(false), static_cast<LPARAM
>(bHandleAllCurrentEvents
) );
551 if ( !bDidWork
&& bWait
)
553 maWaitingYieldCond
.reset();
554 maWaitingYieldCond
.wait();
560 bDidWork
= ImplSalYield( bWait
, bHandleAllCurrentEvents
);
562 maWaitingYieldCond
.set();
568 #define CASE_NOYIELDLOCK( salmsg, function ) \
570 if (bIsOtherThreadMessage) \
572 ++pInst->m_nNoYieldLock; \
574 --pInst->m_nNoYieldLock; \
578 DBG_TESTSOLARMUTEX(); \
583 #define CASE_NOYIELDLOCK_RESULT( salmsg, function ) \
585 if (bIsOtherThreadMessage) \
587 ++pInst->m_nNoYieldLock; \
588 nRet = reinterpret_cast<LRESULT>( function ); \
589 --pInst->m_nNoYieldLock; \
593 DBG_TESTSOLARMUTEX(); \
594 nRet = reinterpret_cast<LRESULT>( function ); \
598 LRESULT CALLBACK
SalComWndProc( HWND
, UINT nMsg
, WPARAM wParam
, LPARAM lParam
, bool& rDef
)
600 const BOOL bIsOtherThreadMessage
= InSendMessage();
602 WinSalInstance
*pInst
= GetSalData()->mpInstance
;
603 WinSalTimer
*const pTimer
= static_cast<WinSalTimer
*>( ImplGetSVData()->maSchedCtx
.mpSalTimer
);
605 SAL_INFO("vcl.gdi.wndproc", "SalComWndProc(nMsg=" << nMsg
<< ", wParam=" << wParam
606 << ", lParam=" << lParam
<< "); inSendMsg: " << bIsOtherThreadMessage
);
610 case SAL_MSG_THREADYIELD
:
611 assert( !static_cast<bool>(wParam
) );
612 nRet
= static_cast<LRESULT
>(ImplSalYield(
613 false, static_cast<bool>( lParam
) ));
616 case SAL_MSG_STARTTIMER
:
618 sal_uInt64 nTime
= tools::Time::GetSystemTicks();
619 if ( nTime
< static_cast<sal_uInt64
>( lParam
) )
620 nTime
= static_cast<sal_uInt64
>( lParam
) - nTime
;
623 assert( pTimer
!= nullptr );
624 pTimer
->ImplStart( nTime
);
628 case SAL_MSG_STOPTIMER
:
629 assert( pTimer
!= nullptr );
633 CASE_NOYIELDLOCK_RESULT( SAL_MSG_CREATEFRAME
, ImplSalCreateFrame( GetSalData()->mpInstance
,
634 reinterpret_cast<HWND
>(lParam
), static_cast<SalFrameStyleFlags
>(wParam
)) )
635 CASE_NOYIELDLOCK_RESULT( SAL_MSG_RECREATEHWND
, ImplSalReCreateHWND(
636 reinterpret_cast<HWND
>(wParam
), reinterpret_cast<HWND
>(lParam
), false) )
637 CASE_NOYIELDLOCK_RESULT( SAL_MSG_RECREATECHILDHWND
, ImplSalReCreateHWND(
638 reinterpret_cast<HWND
>(wParam
), reinterpret_cast<HWND
>(lParam
), true) )
639 CASE_NOYIELDLOCK( SAL_MSG_DESTROYFRAME
, delete reinterpret_cast<SalFrame
*>(lParam
) )
641 case SAL_MSG_DESTROYHWND
:
642 // We only destroy the native window here. We do NOT destroy the SalFrame contained
643 // in the structure (GetWindowPtr()).
644 if (DestroyWindow(reinterpret_cast<HWND
>(lParam
)) == 0)
646 OSL_FAIL("DestroyWindow failed!");
647 // Failure: We remove the SalFrame from the window structure. So we avoid that
648 // the window structure may contain an invalid pointer, once the SalFrame is deleted.
649 SetWindowPtr(reinterpret_cast<HWND
>(lParam
), nullptr);
653 CASE_NOYIELDLOCK_RESULT( SAL_MSG_CREATEOBJECT
, ImplSalCreateObject(
654 GetSalData()->mpInstance
, reinterpret_cast<WinSalFrame
*>(lParam
)) )
655 CASE_NOYIELDLOCK( SAL_MSG_DESTROYOBJECT
, delete reinterpret_cast<SalObject
*>(lParam
) )
656 CASE_NOYIELDLOCK_RESULT( SAL_MSG_GETCACHEDDC
, GetDCEx(
657 reinterpret_cast<HWND
>(wParam
), nullptr, DCX_CACHE
) )
658 CASE_NOYIELDLOCK( SAL_MSG_RELEASEDC
, ReleaseDC(
659 reinterpret_cast<HWND
>(wParam
), reinterpret_cast<HDC
>(lParam
)) )
661 case SAL_MSG_TIMER_CALLBACK
:
662 assert( pTimer
!= nullptr );
663 nRet
= static_cast<LRESULT
>( pTimer
->ImplHandleTimerEvent( wParam
) );
667 assert( pTimer
!= nullptr );
668 nRet
= static_cast<LRESULT
>( pTimer
->ImplHandle_WM_TIMER( wParam
) );
682 #undef CASE_NOYIELDLOCK
683 #undef CASE_NOYIELDLOCK_RESULT
685 LRESULT CALLBACK
SalComWndProcW( HWND hWnd
, UINT nMsg
, WPARAM wParam
, LPARAM lParam
)
691 nRet
= SalComWndProc( hWnd
, nMsg
, wParam
, lParam
, bDef
);
693 __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))
698 if ( !ImplHandleGlobalMsg( hWnd
, nMsg
, wParam
, lParam
, nRet
) )
699 nRet
= DefWindowProcW( hWnd
, nMsg
, wParam
, lParam
);
710 static std::vector
<MsgRange
> GetOtherRanges( VclInputFlags nType
)
712 assert( nType
!= VCL_INPUT_ANY
);
714 // this array must be kept sorted!
715 const UINT nExcludeMsgIds
[] =
725 WM_MOUSEFIRST
, // 512
736 SAL_MSG_POSTMOVE
, // WM_USER+136
737 SAL_MSG_POSTCALLSIZE
, // WM_USER+137
739 SAL_MSG_TIMER_CALLBACK
, // WM_USER+162
743 const unsigned MAX_EXCL
= SAL_N_ELEMENTS( nExcludeMsgIds
);
745 bool aExcludeMsgList
[ MAX_EXCL
] = { false, };
746 std::vector
<MsgRange
> aResult
;
748 // set the excluded values
749 if ( !(nType
& VclInputFlags::MOUSE
) )
751 for ( unsigned i
= 0; nExcludeMsgIds
[ 6 + i
] <= WM_MOUSELAST
; ++i
)
752 aExcludeMsgList
[ 6 + i
] = true;
755 if ( !(nType
& VclInputFlags::KEYBOARD
) )
756 aExcludeMsgList
[ 4 ] = true;
758 if ( !(nType
& VclInputFlags::PAINT
) )
760 aExcludeMsgList
[ 1 ] = true;
761 aExcludeMsgList
[ 2 ] = true;
762 aExcludeMsgList
[ 3 ] = true;
763 aExcludeMsgList
[ 16 ] = true;
764 aExcludeMsgList
[ 17 ] = true;
767 if ( !(nType
& VclInputFlags::TIMER
) )
769 aExcludeMsgList
[ 5 ] = true;
770 aExcludeMsgList
[ 18 ] = true;
773 // build the message ranges to check
774 MsgRange aRange
= { 0, 0 };
776 for ( unsigned i
= 1; i
< MAX_EXCL
; ++i
)
778 if ( aExcludeMsgList
[ i
] )
782 if ( nExcludeMsgIds
[ i
] == aRange
.nStart
)
789 aRange
.nEnd
= nExcludeMsgIds
[ i
] - 1;
790 aResult
.push_back( aRange
);
792 aRange
.nStart
= aRange
.nEnd
+ 2;
797 if ( aRange
.nStart
!= UINT_MAX
)
799 aRange
.nEnd
= UINT_MAX
;
800 aResult
.push_back( aRange
);
806 bool WinSalInstance::AnyInput( VclInputFlags nType
)
810 if ( nType
& VclInputFlags::TIMER
)
812 const WinSalTimer
* pTimer
= static_cast<WinSalTimer
*>( ImplGetSVData()->maSchedCtx
.mpSalTimer
);
813 if ( pTimer
&& pTimer
->HasTimerElapsed() )
817 if ( (nType
& VCL_INPUT_ANY
) == VCL_INPUT_ANY
)
819 // revert bugfix for #108919# which never reported timeouts when called from the timer handler
820 // which made the application completely unresponsive during background formatting
821 if ( PeekMessageW( &aMsg
, nullptr, 0, 0, PM_NOREMOVE
| PM_NOYIELD
) )
826 const bool bCheck_KEYBOARD (nType
& VclInputFlags::KEYBOARD
);
827 const bool bCheck_OTHER (nType
& VclInputFlags::OTHER
);
829 // If there is a modifier key event, it counts as OTHER
830 // Previously we were simply ignoring these events...
831 if ( bCheck_KEYBOARD
|| bCheck_OTHER
)
833 if ( PeekMessageW( &aMsg
, nullptr, WM_KEYDOWN
, WM_KEYDOWN
,
834 PM_NOREMOVE
| PM_NOYIELD
) )
836 const bool bIsModifier
= ( (aMsg
.wParam
== VK_SHIFT
) ||
837 (aMsg
.wParam
== VK_CONTROL
) || (aMsg
.wParam
== VK_MENU
) );
838 if ( bCheck_KEYBOARD
&& !bIsModifier
)
840 if ( bCheck_OTHER
&& bIsModifier
)
845 // Other checks for all messages not excluded.
846 // The less we exclude, the less ranges have to be checked!
849 // TIMER and KEYBOARD are already handled, so always exclude them!
850 VclInputFlags nOtherType
= nType
&
851 ~VclInputFlags(VclInputFlags::KEYBOARD
| VclInputFlags::TIMER
);
853 std::vector
<MsgRange
> aMsgRangeList( GetOtherRanges( nOtherType
) );
854 for ( MsgRange
const & aRange
: aMsgRangeList
)
855 if ( PeekMessageW( &aMsg
, nullptr, aRange
.nStart
,
856 aRange
.nEnd
, PM_NOREMOVE
| PM_NOYIELD
) )
859 // MOUSE and PAINT already handled, so skip further checks
863 if ( nType
& VclInputFlags::MOUSE
)
865 if ( PeekMessageW( &aMsg
, nullptr, WM_MOUSEFIRST
, WM_MOUSELAST
,
866 PM_NOREMOVE
| PM_NOYIELD
) )
870 if ( nType
& VclInputFlags::PAINT
)
872 if ( PeekMessageW( &aMsg
, nullptr, WM_PAINT
, WM_PAINT
,
873 PM_NOREMOVE
| PM_NOYIELD
) )
876 if ( PeekMessageW( &aMsg
, nullptr, WM_SIZE
, WM_SIZE
,
877 PM_NOREMOVE
| PM_NOYIELD
) )
880 if ( PeekMessageW( &aMsg
, nullptr, SAL_MSG_POSTCALLSIZE
, SAL_MSG_POSTCALLSIZE
,
881 PM_NOREMOVE
| PM_NOYIELD
) )
884 if ( PeekMessageW( &aMsg
, nullptr, WM_MOVE
, WM_MOVE
,
885 PM_NOREMOVE
| PM_NOYIELD
) )
888 if ( PeekMessageW( &aMsg
, nullptr, SAL_MSG_POSTMOVE
, SAL_MSG_POSTMOVE
,
889 PM_NOREMOVE
| PM_NOYIELD
) )
897 SalFrame
* WinSalInstance::CreateChildFrame( SystemParentData
* pSystemParentData
, SalFrameStyleFlags nSalFrameStyle
)
899 // to switch to Main-Thread
900 return reinterpret_cast<SalFrame
*>(static_cast<sal_IntPtr
>(SendMessageW( mhComWnd
, SAL_MSG_CREATEFRAME
, static_cast<WPARAM
>(nSalFrameStyle
), reinterpret_cast<LPARAM
>(pSystemParentData
->hWnd
) )));
903 SalFrame
* WinSalInstance::CreateFrame( SalFrame
* pParent
, SalFrameStyleFlags nSalFrameStyle
)
905 // to switch to Main-Thread
908 hWndParent
= static_cast<WinSalFrame
*>(pParent
)->mhWnd
;
910 hWndParent
= nullptr;
911 return reinterpret_cast<SalFrame
*>(static_cast<sal_IntPtr
>(SendMessageW( mhComWnd
, SAL_MSG_CREATEFRAME
, static_cast<WPARAM
>(nSalFrameStyle
), reinterpret_cast<LPARAM
>(hWndParent
) )));
914 void WinSalInstance::DestroyFrame( SalFrame
* pFrame
)
916 OpenGLContext::prepareForYield();
917 SendMessageW( mhComWnd
, SAL_MSG_DESTROYFRAME
, 0, reinterpret_cast<LPARAM
>(pFrame
) );
920 SalObject
* WinSalInstance::CreateObject( SalFrame
* pParent
,
921 SystemWindowData
* /*pWindowData*/, // SystemWindowData meaningless on Windows
924 // to switch to Main-Thread
925 return reinterpret_cast<SalObject
*>(static_cast<sal_IntPtr
>(SendMessageW( mhComWnd
, SAL_MSG_CREATEOBJECT
, 0, reinterpret_cast<LPARAM
>(static_cast<WinSalFrame
*>(pParent
)) )));
928 void WinSalInstance::DestroyObject( SalObject
* pObject
)
930 SendMessageW( mhComWnd
, SAL_MSG_DESTROYOBJECT
, 0, reinterpret_cast<LPARAM
>(pObject
) );
933 OUString
WinSalInstance::GetConnectionIdentifier()
938 /** Add a file to the system shells recent document list if there is any.
939 This function may have no effect under Unix because there is no
940 standard API among the different desktop managers.
943 The file url of the document.
945 void WinSalInstance::AddToRecentDocumentList(const OUString
& rFileUrl
, const OUString
& /*rMimeType*/, const OUString
& rDocumentService
)
947 if (Application::IsHeadlessModeEnabled())
950 OUString system_path
;
951 osl::FileBase::RC rc
= osl::FileBase::getSystemPathFromFileURL(rFileUrl
, system_path
);
953 OSL_ENSURE(osl::FileBase::E_None
== rc
, "Invalid file url");
955 if (osl::FileBase::E_None
== rc
)
957 IShellItem
* pShellItem
= nullptr;
959 HRESULT hr
= SHCreateItemFromParsingName(o3tl::toW(system_path
.getStr()), nullptr, IID_PPV_ARGS(&pShellItem
));
961 if ( SUCCEEDED(hr
) && pShellItem
)
963 OUString sApplicationName
;
965 if ( rDocumentService
== "com.sun.star.text.TextDocument" ||
966 rDocumentService
== "com.sun.star.text.GlobalDocument" ||
967 rDocumentService
== "com.sun.star.text.WebDocument" ||
968 rDocumentService
== "com.sun.star.xforms.XMLFormDocument" )
969 sApplicationName
= "Writer";
970 else if ( rDocumentService
== "com.sun.star.sheet.SpreadsheetDocument" ||
971 rDocumentService
== "com.sun.star.chart2.ChartDocument" )
972 sApplicationName
= "Calc";
973 else if ( rDocumentService
== "com.sun.star.presentation.PresentationDocument" )
974 sApplicationName
= "Impress";
975 else if ( rDocumentService
== "com.sun.star.drawing.DrawingDocument" )
976 sApplicationName
= "Draw";
977 else if ( rDocumentService
== "com.sun.star.formula.FormulaProperties" )
978 sApplicationName
= "Math";
979 else if ( rDocumentService
== "com.sun.star.sdb.DatabaseDocument" ||
980 rDocumentService
== "com.sun.star.sdb.OfficeDatabaseDocument" ||
981 rDocumentService
== "com.sun.star.sdb.RelationDesign" ||
982 rDocumentService
== "com.sun.star.sdb.QueryDesign" ||
983 rDocumentService
== "com.sun.star.sdb.TableDesign" ||
984 rDocumentService
== "com.sun.star.sdb.DataSourceBrowser" )
985 sApplicationName
= "Base";
987 if ( !sApplicationName
.isEmpty() )
989 OUString
sApplicationID("TheDocumentFoundation.LibreOffice.");
990 sApplicationID
+= sApplicationName
;
993 info
.psi
= pShellItem
;
994 info
.pszAppID
= o3tl::toW(sApplicationID
.getStr());
996 SHAddToRecentDocs ( SHARD_APPIDINFO
, &info
);
1000 // For whatever reason, we could not use the SHARD_APPIDINFO semantics
1001 SHAddToRecentDocs(SHARD_PATHW
, system_path
.getStr());
1005 SalTimer
* WinSalInstance::CreateSalTimer()
1007 return new WinSalTimer();
1010 SalBitmap
* WinSalInstance::CreateSalBitmap()
1012 if (OpenGLHelper::isVCLOpenGLEnabled())
1013 return new OpenGLSalBitmap();
1015 return new WinSalBitmap();
1018 const OUString
& SalGetDesktopEnvironment()
1020 static OUString
aDesktopEnvironment( "Windows" );
1021 return aDesktopEnvironment
;
1024 SalSession
* WinSalInstance::CreateSalSession()
1029 int WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(int, LPEXCEPTION_POINTERS pExceptionInfo
)
1031 // Decide if an exception is a c++ (mostly UNO) exception or a process violation.
1032 // Depending on this information we pass process violations directly to our signal handler ...
1033 // and c++ (UNO) exceptions are sended to the following code on the current stack.
1034 // Problem behind: user32.dll sometime consumes exceptions/process violations .-)
1035 // see also #112221#
1037 static const DWORD EXCEPTION_MSC_CPP_EXCEPTION
= 0xE06D7363;
1039 if (pExceptionInfo
->ExceptionRecord
->ExceptionCode
== EXCEPTION_MSC_CPP_EXCEPTION
)
1040 return EXCEPTION_CONTINUE_SEARCH
;
1042 return UnhandledExceptionFilter( pExceptionInfo
);
1045 OUString
WinSalInstance::getOSVersion()
1047 // GetVersion(Ex) and VersionHelpers (based on VerifyVersionInfo) API are
1048 // subject to manifest-based behavior since Windows 8.1, so give wrong results.
1049 // Another approach would be to use NetWkstaGetInfo, but that has some small
1050 // reported delays (some milliseconds), and might get slower in domains with
1051 // poor network connections.
1052 // So go with a solution described at https://msdn.microsoft.com/en-us/library/ms724429
1053 HINSTANCE hLibrary
= LoadLibraryW(L
"kernel32.dll");
1054 if (hLibrary
!= nullptr)
1056 wchar_t szPath
[MAX_PATH
];
1057 DWORD dwCount
= GetModuleFileNameW(hLibrary
, szPath
, SAL_N_ELEMENTS(szPath
));
1058 FreeLibrary(hLibrary
);
1059 if (dwCount
!= 0 && dwCount
< SAL_N_ELEMENTS(szPath
))
1061 dwCount
= GetFileVersionInfoSizeW(szPath
, nullptr);
1064 std::unique_ptr
<char> ver(new char[dwCount
]);
1065 if (GetFileVersionInfoW(szPath
, 0, dwCount
, ver
.get()) != FALSE
)
1067 void* pBlock
= nullptr;
1069 if (VerQueryValueW(ver
.get(), L
"\\", &pBlock
, &dwBlockSz
) != FALSE
&& dwBlockSz
>= sizeof(VS_FIXEDFILEINFO
))
1071 VS_FIXEDFILEINFO
*vinfo
= static_cast<VS_FIXEDFILEINFO
*>(pBlock
);
1072 OUStringBuffer aVer
;
1073 aVer
.append("Windows ");
1074 aVer
.append(static_cast<sal_Int32
>(HIWORD(vinfo
->dwProductVersionMS
)));
1076 aVer
.append(static_cast<sal_Int32
>(LOWORD(vinfo
->dwProductVersionMS
)));
1077 return aVer
.makeStringAndClear();
1086 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */