Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / win / source / app / salinst.cxx
blob1c212467b286820334a163c9388838cac4bede05
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <string.h>
21 #include <svsys.h>
22 #include <process.h>
24 #include <osl/file.hxx>
25 #include <comphelper/solarmutex.hxx>
27 #include <tools/solarmutex.hxx>
29 #include <vcl/apptypes.hxx>
30 #include <vcl/opengl/OpenGLHelper.hxx>
31 #include <vcl/opengl/OpenGLContext.hxx>
32 #include <vcl/timer.hxx>
34 #include <opengl/salbmp.hxx>
35 #include <win/wincomp.hxx>
36 #include <win/salids.hrc>
37 #include <win/saldata.hxx>
38 #include <win/salinst.h>
39 #include <win/salframe.h>
40 #include <win/salobj.h>
41 #include <win/saltimer.h>
42 #include <win/salbmp.h>
44 #include <salimestatus.hxx>
45 #include <salsys.hxx>
47 #if defined _MSC_VER
48 #ifndef min
49 #define min(a,b) (((a) < (b)) ? (a) : (b))
50 #endif
51 #ifndef max
52 #define max(a,b) (((a) > (b)) ? (a) : (b))
53 #endif
54 #endif
56 #if defined _MSC_VER
57 #pragma warning(push, 1)
58 #pragma warning( disable: 4917 )
59 #endif
61 #ifdef __MINGW32__
62 #ifdef GetObject
63 #undef GetObject
64 #endif
65 #define GetObject GetObjectA
66 #endif
68 #include <gdiplus.h>
69 #include <gdiplusenums.h>
70 #include <gdipluscolor.h>
71 #include <shlobj.h>
73 #ifdef _WIN32_WINNT_WINBLUE
74 #include <VersionHelpers.h>
75 #endif
77 #ifdef __MINGW32__
78 #ifdef GetObject
79 #undef GetObject
80 #endif
81 #endif
83 #if defined _MSC_VER
84 #pragma warning(pop)
85 #endif
87 #ifdef __MINGW32__
88 #include <sehandler.hxx>
89 #endif
91 void SalAbort( const OUString& rErrorText, bool )
93 ImplFreeSalGDI();
95 if ( rErrorText.isEmpty() )
97 // make sure crash reporter is triggered
98 RaiseException( 0, EXCEPTION_NONCONTINUABLE, 0, NULL );
99 FatalAppExitW( 0, L"Application Error" );
101 else
103 // make sure crash reporter is triggered
104 RaiseException( 0, EXCEPTION_NONCONTINUABLE, 0, NULL );
105 FatalAppExitW( 0, reinterpret_cast<LPCWSTR>(rErrorText.getStr()) );
109 LRESULT CALLBACK SalComWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam );
111 class SalYieldMutex : public comphelper::SolarMutex
113 osl::Mutex m_mutex;
115 public: // for ImplSalYield()
116 WinSalInstance* mpInstData;
117 sal_uLong mnCount;
118 DWORD mnThreadId;
120 public:
121 SalYieldMutex( WinSalInstance* pInstData );
123 virtual void acquire();
124 virtual void release();
125 virtual bool tryToAcquire();
127 sal_uLong GetAcquireCount( sal_uLong nThreadId );
130 SalYieldMutex::SalYieldMutex( WinSalInstance* pInstData )
132 mpInstData = pInstData;
133 mnCount = 0;
134 mnThreadId = 0;
137 void SalYieldMutex::acquire()
139 m_mutex.acquire();
140 mnCount++;
141 mnThreadId = GetCurrentThreadId();
144 void SalYieldMutex::release()
146 DWORD nThreadId = GetCurrentThreadId();
147 if ( mnThreadId != nThreadId )
148 m_mutex.release();
149 else
151 SalData* pSalData = GetSalData();
152 if ( pSalData->mnAppThreadId != nThreadId )
154 if ( mnCount == 1 )
156 OpenGLContext::prepareForYield();
158 // If we don't call these message, the Output from the
159 // Java clients doesn't come in the right order
160 GdiFlush();
162 mpInstData->mpSalWaitMutex->acquire();
163 if ( mpInstData->mnYieldWaitCount )
164 PostMessageW( mpInstData->mhComWnd, SAL_MSG_RELEASEWAITYIELD, 0, 0 );
165 mnThreadId = 0;
166 mnCount--;
167 m_mutex.release();
168 mpInstData->mpSalWaitMutex->release();
170 else
172 mnCount--;
173 m_mutex.release();
176 else
178 if ( mnCount == 1 )
180 mnThreadId = 0;
181 OpenGLContext::prepareForYield();
183 mnCount--;
184 m_mutex.release();
189 bool SalYieldMutex::tryToAcquire()
191 if( m_mutex.tryToAcquire() )
193 mnCount++;
194 mnThreadId = GetCurrentThreadId();
195 return true;
197 else
198 return false;
201 sal_uLong SalYieldMutex::GetAcquireCount( sal_uLong nThreadId )
203 if ( nThreadId == mnThreadId )
204 return mnCount;
205 else
206 return 0;
209 void ImplSalYieldMutexAcquireWithWait()
211 WinSalInstance* pInst = GetSalData()->mpFirstInstance;
212 if ( !pInst )
213 return;
215 // If we are the main thread, then we must wait with wait, because
216 // in if we don't reschedule, then we create deadlocks if a Windows
217 // Function is called from another thread. If we aren't the main thread,
218 // than we call acquire directly.
219 DWORD nThreadId = GetCurrentThreadId();
220 SalData* pSalData = GetSalData();
221 if ( pSalData->mnAppThreadId == nThreadId )
223 // wait till we get the Mutex
224 bool bAcquire = FALSE;
227 if ( pInst->mpSalYieldMutex->tryToAcquire() )
228 bAcquire = TRUE;
229 else
231 pInst->mpSalWaitMutex->acquire();
232 if ( pInst->mpSalYieldMutex->tryToAcquire() )
234 bAcquire = TRUE;
235 pInst->mpSalWaitMutex->release();
237 else
239 pInst->mnYieldWaitCount++;
240 pInst->mpSalWaitMutex->release();
241 MSG aTmpMsg;
242 GetMessageW( &aTmpMsg, pInst->mhComWnd, SAL_MSG_RELEASEWAITYIELD, SAL_MSG_RELEASEWAITYIELD );
243 pInst->mnYieldWaitCount--;
244 if ( pInst->mnYieldWaitCount )
245 PostMessageW( pInst->mhComWnd, SAL_MSG_RELEASEWAITYIELD, 0, 0 );
249 while ( !bAcquire );
251 else
252 pInst->mpSalYieldMutex->acquire();
255 bool ImplSalYieldMutexTryToAcquire()
257 WinSalInstance* pInst = GetSalData()->mpFirstInstance;
258 if ( pInst )
259 return pInst->mpSalYieldMutex->tryToAcquire();
260 else
261 return FALSE;
264 void ImplSalYieldMutexRelease()
266 WinSalInstance* pInst = GetSalData()->mpFirstInstance;
267 if ( pInst )
269 GdiFlush();
270 pInst->mpSalYieldMutex->release();
274 sal_uLong ImplSalReleaseYieldMutex()
276 WinSalInstance* pInst = GetSalData()->mpFirstInstance;
277 if ( !pInst )
278 return 0;
280 SalYieldMutex* pYieldMutex = pInst->mpSalYieldMutex;
281 sal_uLong nCount = pYieldMutex->GetAcquireCount( GetCurrentThreadId() );
282 sal_uLong n = nCount;
283 while ( n )
285 pYieldMutex->release();
286 n--;
289 return nCount;
292 void ImplSalAcquireYieldMutex( sal_uLong nCount )
294 WinSalInstance* pInst = GetSalData()->mpFirstInstance;
295 if ( !pInst )
296 return;
298 SalYieldMutex* pYieldMutex = pInst->mpSalYieldMutex;
299 while ( nCount )
301 pYieldMutex->acquire();
302 nCount--;
306 bool WinSalInstance::CheckYieldMutex()
308 SalData* pSalData = GetSalData();
309 if ( pSalData->mpFirstInstance )
311 SalYieldMutex* pYieldMutex = pSalData->mpFirstInstance->mpSalYieldMutex;
312 return (pYieldMutex->mnThreadId == (GetCurrentThreadId()));
314 return true;
317 void SalData::initKeyCodeMap()
319 UINT nKey = 0xffffffff;
320 #define initKey( a, b )\
321 nKey = LOWORD( VkKeyScan( a ) );\
322 if( nKey < 0xffff )\
323 maVKMap[ nKey ] = b;
325 initKey( '+', KEY_ADD );
326 initKey( '-', KEY_SUBTRACT );
327 initKey( '*', KEY_MULTIPLY );
328 initKey( '/', KEY_DIVIDE );
329 initKey( '.', KEY_POINT );
330 initKey( ',', KEY_COMMA );
331 initKey( '<', KEY_LESS );
332 initKey( '>', KEY_GREATER );
333 initKey( '=', KEY_EQUAL );
334 initKey( '~', KEY_TILDE );
335 initKey( '`', KEY_QUOTELEFT );
336 initKey( '[', KEY_BRACKETLEFT );
337 initKey( ']', KEY_BRACKETRIGHT );
338 initKey( ';', KEY_SEMICOLON );
339 initKey( '\'', KEY_QUOTERIGHT );
342 // SalData
344 SalData::SalData()
346 mhInst = 0; // default instance handle
347 mnCmdShow = 0; // default frame show style
348 mhDitherPal = 0; // dither palette
349 mhDitherDIB = 0; // dither memory handle
350 mpDitherDIB = 0; // dither memory
351 mpDitherDIBData = 0; // beginning of DIB data
352 mpDitherDiff = 0; // Dither mapping table
353 mpDitherLow = 0; // Dither mapping table
354 mpDitherHigh = 0; // Dither mapping table
355 mnTimerMS = 0; // Current Time (in MS) of the Timer
356 mnTimerOrgMS = 0; // Current Original Time (in MS)
357 mnNextTimerTime = 0;
358 mnLastEventTime = 0;
359 mnTimerId = 0; // windows timer id
360 mhSalObjMsgHook = 0; // hook to get interesting msg for SalObject
361 mhWantLeaveMsg = 0; // window handle, that want a MOUSELEAVE message
362 mpMouseLeaveTimer = 0; // Timer for MouseLeave Test
363 mpFirstInstance = 0; // pointer of first instance
364 mpFirstFrame = 0; // pointer of first frame
365 mpFirstObject = 0; // pointer of first object window
366 mpFirstVD = 0; // first VirDev
367 mpFirstPrinter = 0; // first printing printer
368 mpHDCCache = 0; // Cache for three DC's
369 mh50Bmp = 0; // 50% Bitmap
370 mh50Brush = 0; // 50% Brush
371 int i;
372 for(i=0; i<MAX_STOCKPEN; i++)
374 maStockPenColorAry[i] = 0;
375 mhStockPenAry[i] = 0;
377 for(i=0; i<MAX_STOCKBRUSH; i++)
379 maStockBrushColorAry[i] = 0;
380 mhStockBrushAry[i] = 0;
382 mnStockPenCount = 0; // count of static pens
383 mnStockBrushCount = 0; // count of static brushes
384 mnSalObjWantKeyEvt = 0; // KeyEvent for the SalObj hook
385 mnCacheDCInUse = 0; // count of CacheDC in use
386 mbObjClassInit = FALSE; // is SALOBJECTCLASS initialised
387 mbInPalChange = FALSE; // is in WM_QUERYNEWPALETTE
388 mnAppThreadId = 0; // Id from Applikation-Thread
389 mbScrSvrEnabled = FALSE; // ScreenSaver enabled
390 mnSageStatus = 0; // status of Sage-DLL (DISABLE_AGENT == not available)
391 mpSageEnableProc = 0; // funktion to deactivate the system agent
392 mpFirstIcon = 0; // icon cache, points to first icon, NULL if none
393 mpTempFontItem = 0;
394 mbThemeChanged = FALSE; // true if visual theme was changed: throw away theme handles
395 mbThemeMenuSupport = FALSE;
397 // init with NULL
398 gdiplusToken = 0;
399 maDwmLib = 0;
400 mpDwmIsCompositionEnabled = 0;
402 initKeyCodeMap();
404 SetSalData( this );
405 initNWF();
408 SalData::~SalData()
410 deInitNWF();
411 SetSalData( NULL );
414 void InitSalData()
416 SalData* pSalData = new SalData;
417 CoInitialize(0); // put main thread in Single Threaded Apartment (STA)
419 // init GDIPlus
420 static Gdiplus::GdiplusStartupInput gdiplusStartupInput;
421 Gdiplus::GdiplusStartup(&pSalData->gdiplusToken, &gdiplusStartupInput, NULL);
424 void DeInitSalData()
426 CoUninitialize();
427 SalData* pSalData = GetSalData();
429 // deinit GDIPlus
430 if(pSalData)
432 Gdiplus::GdiplusShutdown(pSalData->gdiplusToken);
435 delete pSalData;
438 void InitSalMain()
440 // remember data, copied from WinMain
441 SalData* pData = GetSalData();
442 if ( pData ) // Im AppServer NULL
444 STARTUPINFO aSI;
445 aSI.cb = sizeof( aSI );
446 GetStartupInfo( &aSI );
447 pData->mhInst = GetModuleHandle( NULL );
448 pData->mnCmdShow = aSI.wShowWindow;
452 SalInstance* CreateSalInstance()
454 SalData* pSalData = GetSalData();
456 // determine the windows version
457 aSalShlData.mbWXP = 0;
458 aSalShlData.mbWVista = 0;
459 aSalShlData.mbW7 = 0;
460 // the Win32 SDK 8.1 deprecates GetVersionEx()
461 #ifdef _WIN32_WINNT_WINBLUE
462 aSalShlData.mbWXP = IsWindowsXPOrGreater() ? 1 : 0;
463 aSalShlData.mbWVista = IsWindowsVistaOrGreater() ? 1 : 0;
464 aSalShlData.mbW7 = IsWindows7OrGreater() ? 1 : 0;
465 #else
466 OSVERSIONINFO aVersionInfo;
467 memset( &aVersionInfo, 0, sizeof(aVersionInfo) );
468 aVersionInfo.dwOSVersionInfoSize = sizeof( aVersionInfo );
469 if (GetVersionEx( &aVersionInfo ))
471 // Windows XP ?
472 if (aVersionInfo.dwMajorVersion > 5 ||
473 (aVersionInfo.dwMajorVersion == 5 && aVersionInfo.dwMinorVersion >= 1))
474 aSalShlData.mbWXP = 1;
475 // Windows Vista ?
476 if (aVersionInfo.dwMajorVersion >= 6)
477 aSalShlData.mbWVista = 1;
478 // Windows 7 ?
479 if (aVersionInfo.dwMajorVersion > 6 ||
480 (aVersionInfo.dwMajorVersion == 6 && aVersionInfo.dwMinorVersion >= 1))
481 aSalShlData.mbW7 = 1;
483 #endif
485 pSalData->mnAppThreadId = GetCurrentThreadId();
487 // register frame class
488 WNDCLASSEXW aWndClassEx;
489 aWndClassEx.cbSize = sizeof( aWndClassEx );
490 aWndClassEx.style = CS_OWNDC;
491 aWndClassEx.lpfnWndProc = SalFrameWndProcW;
492 aWndClassEx.cbClsExtra = 0;
493 aWndClassEx.cbWndExtra = SAL_FRAME_WNDEXTRA;
494 aWndClassEx.hInstance = pSalData->mhInst;
495 aWndClassEx.hCursor = 0;
496 aWndClassEx.hbrBackground = 0;
497 aWndClassEx.lpszMenuName = 0;
498 aWndClassEx.lpszClassName = SAL_FRAME_CLASSNAMEW;
499 ImplLoadSalIcon( SAL_RESID_ICON_DEFAULT, aWndClassEx.hIcon, aWndClassEx.hIconSm );
500 if ( !RegisterClassExW( &aWndClassEx ) )
501 return NULL;
503 aWndClassEx.hIcon = 0;
504 aWndClassEx.hIconSm = 0;
505 aWndClassEx.style |= CS_SAVEBITS;
506 aWndClassEx.lpszClassName = SAL_SUBFRAME_CLASSNAMEW;
507 if ( !RegisterClassExW( &aWndClassEx ) )
508 return NULL;
510 // shadow effect for popups on XP
511 if( aSalShlData.mbWXP )
512 aWndClassEx.style |= CS_DROPSHADOW;
513 aWndClassEx.lpszClassName = SAL_TMPSUBFRAME_CLASSNAMEW;
514 if ( !RegisterClassExW( &aWndClassEx ) )
515 return NULL;
517 aWndClassEx.style = 0;
518 aWndClassEx.lpfnWndProc = SalComWndProcW;
519 aWndClassEx.cbWndExtra = 0;
520 aWndClassEx.lpszClassName = SAL_COM_CLASSNAMEW;
521 if ( !RegisterClassExW( &aWndClassEx ) )
522 return NULL;
524 HWND hComWnd = CreateWindowExW( WS_EX_TOOLWINDOW, SAL_COM_CLASSNAMEW,
525 L"", WS_POPUP, 0, 0, 0, 0, 0, 0,
526 pSalData->mhInst, NULL );
527 if ( !hComWnd )
528 return NULL;
530 WinSalInstance* pInst = new WinSalInstance;
532 // init instance (only one instance in this version !!!)
533 pSalData->mpFirstInstance = pInst;
534 pInst->mhInst = pSalData->mhInst;
535 pInst->mhComWnd = hComWnd;
537 // init static GDI Data
538 ImplInitSalGDI();
540 return pInst;
543 void DestroySalInstance( SalInstance* pInst )
545 SalData* pSalData = GetSalData();
547 // (only one instance in this version !!!)
549 ImplFreeSalGDI();
551 // reset instance
552 if ( pSalData->mpFirstInstance == pInst )
553 pSalData->mpFirstInstance = NULL;
555 delete pInst;
558 WinSalInstance::WinSalInstance()
560 mhComWnd = 0;
561 mpSalYieldMutex = new SalYieldMutex( this );
562 mpSalWaitMutex = new osl::Mutex;
563 mnYieldWaitCount = 0;
564 mpSalYieldMutex->acquire();
565 ::tools::SolarMutex::SetSolarMutex( mpSalYieldMutex );
568 WinSalInstance::~WinSalInstance()
570 ::tools::SolarMutex::SetSolarMutex( 0 );
571 mpSalYieldMutex->release();
572 delete mpSalYieldMutex;
573 delete mpSalWaitMutex;
574 DestroyWindow( mhComWnd );
577 comphelper::SolarMutex* WinSalInstance::GetYieldMutex()
579 return mpSalYieldMutex;
582 sal_uLong WinSalInstance::ReleaseYieldMutex()
584 return ImplSalReleaseYieldMutex();
587 void WinSalInstance::AcquireYieldMutex( sal_uLong nCount )
589 ImplSalAcquireYieldMutex( nCount );
592 static void ImplSalDispatchMessage( MSG* pMsg )
594 SalData* pSalData = GetSalData();
595 if ( pSalData->mpFirstObject )
597 if ( ImplSalPreDispatchMsg( pMsg ) )
598 return;
600 LRESULT lResult = DispatchMessageW( pMsg );
601 if ( pSalData->mpFirstObject )
602 ImplSalPostDispatchMsg( pMsg, lResult );
605 void ImplSalYield( bool bWait, bool bHandleAllCurrentEvents )
607 MSG aMsg;
608 bool bWasMsg = false, bOneEvent = false;
610 int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1;
613 if ( PeekMessageW( &aMsg, 0, 0, 0, PM_REMOVE ) )
615 TranslateMessage( &aMsg );
616 ImplSalDispatchMessage( &aMsg );
618 bOneEvent = bWasMsg = true;
620 else
621 bOneEvent = false;
622 } while( --nMaxEvents && bOneEvent );
624 if ( bWait && ! bWasMsg )
626 if ( GetMessageW( &aMsg, 0, 0, 0 ) )
628 TranslateMessage( &aMsg );
629 ImplSalDispatchMessage( &aMsg );
634 void WinSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
636 SalYieldMutex* pYieldMutex = mpSalYieldMutex;
637 SalData* pSalData = GetSalData();
638 DWORD nCurThreadId = GetCurrentThreadId();
639 sal_uLong nCount = pYieldMutex->GetAcquireCount( nCurThreadId );
640 sal_uLong n = nCount;
641 while ( n )
643 pYieldMutex->release();
644 n--;
646 if ( pSalData->mnAppThreadId != nCurThreadId )
648 // #97739# A SendMessage call blocks until the called thread (here: the main thread)
649 // returns. During a yield however, messages are processed in the main thread that might
650 // result in a new message loop due to opening a dialog. Thus, SendMessage would not
651 // return which will block this thread!
652 // Solution: just give up the time slice and hope that messages are processed
653 // by the main thread anyway (where all windows are created)
654 // If the mainthread is not currently handling messages, then our SendMessage would
655 // also do nothing, so this seems to be reasonable.
657 // #i18883# only sleep if potential deadlock scenario, ie, when a dialog is open
658 if( ImplGetSVData()->maAppData.mnModalMode )
659 Sleep(1);
660 else
661 SendMessageW( mhComWnd, SAL_MSG_THREADYIELD, (WPARAM)bWait, (LPARAM)bHandleAllCurrentEvents );
663 n = nCount;
664 while ( n )
666 pYieldMutex->acquire();
667 n--;
670 else
672 ImplSalYield( bWait, bHandleAllCurrentEvents );
674 n = nCount;
675 while ( n )
677 ImplSalYieldMutexAcquireWithWait();
678 n--;
683 LRESULT CALLBACK SalComWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, int& rDef )
685 LRESULT nRet = 0;
687 switch ( nMsg )
689 case SAL_MSG_PRINTABORTJOB:
690 ImplSalPrinterAbortJobAsync( (HDC)wParam );
691 rDef = FALSE;
692 break;
693 case SAL_MSG_THREADYIELD:
694 ImplSalYield( (bool)wParam, (bool)lParam );
695 rDef = FALSE;
696 break;
697 // If we get this message, because another GetMessage() call
698 // has received this message, we must post this message to
699 // us again, because in the other case we wait forever.
700 case SAL_MSG_RELEASEWAITYIELD:
702 WinSalInstance* pInst = GetSalData()->mpFirstInstance;
703 if ( pInst && pInst->mnYieldWaitCount )
704 PostMessageW( hWnd, SAL_MSG_RELEASEWAITYIELD, wParam, lParam );
706 rDef = FALSE;
707 break;
708 case SAL_MSG_STARTTIMER:
709 ImplSalStartTimer( (sal_uLong) lParam, FALSE );
710 rDef = FALSE;
711 break;
712 case SAL_MSG_CREATEFRAME:
713 nRet = (LRESULT)ImplSalCreateFrame( GetSalData()->mpFirstInstance, (HWND)lParam, (sal_uLong)wParam );
714 rDef = FALSE;
715 break;
716 case SAL_MSG_RECREATEHWND:
717 nRet = (LRESULT)ImplSalReCreateHWND( (HWND)wParam, (HWND)lParam, FALSE );
718 rDef = FALSE;
719 break;
720 case SAL_MSG_RECREATECHILDHWND:
721 nRet = (LRESULT)ImplSalReCreateHWND( (HWND)wParam, (HWND)lParam, TRUE );
722 rDef = FALSE;
723 break;
724 case SAL_MSG_DESTROYFRAME:
725 delete (SalFrame*)lParam;
726 rDef = FALSE;
727 break;
728 case SAL_MSG_DESTROYHWND:
729 //We only destroy the native window here. We do NOT destroy the SalFrame contained
730 //in the structure (GetWindowPtr()).
731 if (DestroyWindow((HWND)lParam) == 0)
733 OSL_FAIL("DestroyWindow failed!");
734 //Failure: We remove the SalFrame from the window structure. So we avoid that
735 // the window structure may contain an invalid pointer, once the SalFrame is deleted.
736 SetWindowPtr((HWND)lParam, 0);
738 rDef = FALSE;
739 break;
740 case SAL_MSG_CREATEOBJECT:
741 nRet = (LRESULT)ImplSalCreateObject( GetSalData()->mpFirstInstance, (WinSalFrame*)lParam );
742 rDef = FALSE;
743 break;
744 case SAL_MSG_DESTROYOBJECT:
745 delete (SalObject*)lParam;
746 rDef = FALSE;
747 break;
748 case SAL_MSG_GETDC:
749 nRet = (LRESULT)GetDCEx( (HWND)wParam, 0, DCX_CACHE );
750 rDef = FALSE;
751 break;
752 case SAL_MSG_RELEASEDC:
753 ReleaseDC( (HWND)wParam, (HDC)lParam );
754 rDef = FALSE;
755 break;
756 case SAL_MSG_POSTTIMER:
757 EmitTimerCallback();
758 break;
759 case SAL_MSG_TIMER_CALLBACK:
760 EmitTimerCallback();
761 MSG aMsg;
762 while (PeekMessageW(&aMsg, 0, SAL_MSG_TIMER_CALLBACK, SAL_MSG_TIMER_CALLBACK, PM_REMOVE))
764 // nothing; just remove all the SAL_MSG_TIMER_CALLBACKs that
765 // accumulated in the queue during the EmitTimerCallback(),
766 // otherwise it happens with short timeouts and long callbacks
767 // that no other events will ever be processed, as the queue
768 // is full of SAL_MSG_TIMER_CALLBACKs.
769 // It is impossible to limit the amount of them being emitted
770 // in the first place, as they are emitted asynchronously, but
771 // here we are already fully synchronized.
773 break;
776 return nRet;
779 LRESULT CALLBACK SalComWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
781 int bDef = TRUE;
782 LRESULT nRet = 0;
783 #if defined ( __MINGW32__ ) && !defined ( _WIN64 )
784 jmp_buf jmpbuf;
785 __SEHandler han;
786 if (__builtin_setjmp(jmpbuf) == 0)
788 han.Set(jmpbuf, NULL, (__SEHandler::PF)EXCEPTION_EXECUTE_HANDLER);
789 #else
790 __try
792 #endif
793 nRet = SalComWndProc( hWnd, nMsg, wParam, lParam, bDef );
795 #if defined ( __MINGW32__ ) && !defined ( _WIN64 )
796 han.Reset();
797 #else
798 __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))
801 #endif
802 if ( bDef )
804 if ( !ImplHandleGlobalMsg( hWnd, nMsg, wParam, lParam, nRet ) )
805 nRet = DefWindowProcW( hWnd, nMsg, wParam, lParam );
807 return nRet;
810 bool WinSalInstance::AnyInput( VclInputFlags nType )
812 MSG aMsg;
814 if ( (nType & VCL_INPUT_ANY) == VCL_INPUT_ANY )
816 // revert bugfix for #108919# which never reported timeouts when called from the timer handler
817 // which made the application completely unresponsive during background formatting
818 if ( PeekMessageW( &aMsg, 0, 0, 0, PM_NOREMOVE | PM_NOYIELD ) )
819 return true;
821 else
823 if ( nType & VclInputFlags::MOUSE )
825 // Test for mouse input
826 if ( PeekMessageW( &aMsg, 0, WM_MOUSEFIRST, WM_MOUSELAST,
827 PM_NOREMOVE | PM_NOYIELD ) )
828 return true;
831 if ( nType & VclInputFlags::KEYBOARD )
833 // Test for key input
834 if ( PeekMessageW( &aMsg, 0, WM_KEYDOWN, WM_KEYDOWN,
835 PM_NOREMOVE | PM_NOYIELD ) )
837 if ( (aMsg.wParam == VK_SHIFT) ||
838 (aMsg.wParam == VK_CONTROL) ||
839 (aMsg.wParam == VK_MENU) )
840 return false;
841 else
842 return true;
846 if ( nType & VclInputFlags::PAINT )
848 // Test for paint input
849 if ( PeekMessageW( &aMsg, 0, WM_PAINT, WM_PAINT,
850 PM_NOREMOVE | PM_NOYIELD ) )
851 return true;
853 if ( PeekMessageW( &aMsg, 0, WM_SIZE, WM_SIZE,
854 PM_NOREMOVE | PM_NOYIELD ) )
855 return true;
857 if ( PeekMessageW( &aMsg, 0, SAL_MSG_POSTCALLSIZE, SAL_MSG_POSTCALLSIZE,
858 PM_NOREMOVE | PM_NOYIELD ) )
859 return true;
861 if ( PeekMessageW( &aMsg, 0, WM_MOVE, WM_MOVE,
862 PM_NOREMOVE | PM_NOYIELD ) )
863 return true;
865 if ( PeekMessageW( &aMsg, 0, SAL_MSG_POSTMOVE, SAL_MSG_POSTMOVE,
866 PM_NOREMOVE | PM_NOYIELD ) )
867 return true;
870 if ( nType & VclInputFlags::TIMER )
872 // Test for timer input
873 if ( PeekMessageW( &aMsg, 0, WM_TIMER, WM_TIMER,
874 PM_NOREMOVE | PM_NOYIELD ) )
875 return true;
879 if ( nType & VclInputFlags::OTHER )
881 // Test for any input
882 if ( PeekMessageW( &aMsg, 0, 0, 0, PM_NOREMOVE | PM_NOYIELD ) )
883 return true;
887 return FALSE;
890 void SalTimer::Start( sal_uLong nMS )
892 // to switch to Main-Thread
893 SalData* pSalData = GetSalData();
894 if ( pSalData->mpFirstInstance )
896 if ( pSalData->mnAppThreadId != GetCurrentThreadId() )
897 PostMessageW( pSalData->mpFirstInstance->mhComWnd, SAL_MSG_STARTTIMER, 0, (LPARAM)nMS );
898 else
899 SendMessageW( pSalData->mpFirstInstance->mhComWnd, SAL_MSG_STARTTIMER, 0, (LPARAM)nMS );
901 else
902 ImplSalStartTimer( nMS, FALSE );
905 SalFrame* WinSalInstance::CreateChildFrame( SystemParentData* pSystemParentData, sal_uLong nSalFrameStyle )
907 // to switch to Main-Thread
908 return (SalFrame*)(sal_IntPtr)SendMessageW( mhComWnd, SAL_MSG_CREATEFRAME, nSalFrameStyle, (LPARAM)pSystemParentData->hWnd );
911 SalFrame* WinSalInstance::CreateFrame( SalFrame* pParent, sal_uLong nSalFrameStyle )
913 // to switch to Main-Thread
914 HWND hWndParent;
915 if ( pParent )
916 hWndParent = static_cast<WinSalFrame*>(pParent)->mhWnd;
917 else
918 hWndParent = 0;
919 return (SalFrame*)(sal_IntPtr)SendMessageW( mhComWnd, SAL_MSG_CREATEFRAME, nSalFrameStyle, (LPARAM)hWndParent );
922 void WinSalInstance::DestroyFrame( SalFrame* pFrame )
924 OpenGLContext::prepareForYield();
925 SendMessageW( mhComWnd, SAL_MSG_DESTROYFRAME, 0, (LPARAM)pFrame );
928 SalObject* WinSalInstance::CreateObject( SalFrame* pParent,
929 SystemWindowData* /*pWindowData*/, // SystemWindowData meaningless on Windows
930 bool /*bShow*/ )
932 // to switch to Main-Thread
933 return (SalObject*)(sal_IntPtr)SendMessageW( mhComWnd, SAL_MSG_CREATEOBJECT, 0, (LPARAM)static_cast<WinSalFrame*>(pParent) );
936 void WinSalInstance::DestroyObject( SalObject* pObject )
938 SendMessageW( mhComWnd, SAL_MSG_DESTROYOBJECT, 0, (LPARAM)pObject );
941 void* WinSalInstance::GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes )
943 rReturnedBytes = 1;
944 rReturnedType = AsciiCString;
945 return const_cast<char *>("");
948 /** Add a file to the system shells recent document list if there is any.
949 This function may have no effect under Unix because there is no
950 standard API among the different desktop managers.
952 @param aFileUrl
953 The file url of the document.
955 void WinSalInstance::AddToRecentDocumentList(const OUString& rFileUrl, const OUString& /*rMimeType*/, const OUString& rDocumentService)
957 OUString system_path;
958 osl::FileBase::RC rc = osl::FileBase::getSystemPathFromFileURL(rFileUrl, system_path);
960 OSL_ENSURE(osl::FileBase::E_None == rc, "Invalid file url");
962 if (osl::FileBase::E_None == rc)
964 if ( aSalShlData.mbW7 )
966 typedef HRESULT ( WINAPI *SHCREATEITEMFROMPARSINGNAME )( PCWSTR, IBindCtx*, REFIID, void **ppv );
967 SHCREATEITEMFROMPARSINGNAME pSHCreateItemFromParsingName =
968 ( SHCREATEITEMFROMPARSINGNAME )GetProcAddress(
969 GetModuleHandleW (L"shell32.dll"), "SHCreateItemFromParsingName" );
971 if( pSHCreateItemFromParsingName )
973 IShellItem* pShellItem = NULL;
975 HRESULT hr = pSHCreateItemFromParsingName ( (PCWSTR) system_path.getStr(), NULL, IID_PPV_ARGS(&pShellItem) );
977 if ( SUCCEEDED(hr) && pShellItem )
979 OUString sApplicationName;
981 if ( rDocumentService == "com.sun.star.text.TextDocument" ||
982 rDocumentService == "com.sun.star.text.GlobalDocument" ||
983 rDocumentService == "com.sun.star.text.WebDocument" ||
984 rDocumentService == "com.sun.star.xforms.XMLFormDocument" )
985 sApplicationName = "Writer";
986 else if ( rDocumentService == "com.sun.star.sheet.SpreadsheetDocument" ||
987 rDocumentService == "com.sun.star.chart2.ChartDocument" )
988 sApplicationName = "Calc";
989 else if ( rDocumentService == "com.sun.star.presentation.PresentationDocument" )
990 sApplicationName = "Impress";
991 else if ( rDocumentService == "com.sun.star.drawing.DrawingDocument" )
992 sApplicationName = "Draw";
993 else if ( rDocumentService == "com.sun.star.formula.FormulaProperties" )
994 sApplicationName = "Math";
995 else if ( rDocumentService == "com.sun.star.sdb.DatabaseDocument" ||
996 rDocumentService == "com.sun.star.sdb.OfficeDatabaseDocument" ||
997 rDocumentService == "com.sun.star.sdb.RelationDesign" ||
998 rDocumentService == "com.sun.star.sdb.QueryDesign" ||
999 rDocumentService == "com.sun.star.sdb.TableDesign" ||
1000 rDocumentService == "com.sun.star.sdb.DataSourceBrowser" )
1001 sApplicationName = "Base";
1003 if ( !sApplicationName.isEmpty() )
1005 OUString sApplicationID("TheDocumentFoundation.LibreOffice.");
1006 sApplicationID += sApplicationName;
1008 #if _WIN32_WINNT < _WIN32_WINNT_WIN7
1009 // just define Windows 7 only constant locally...
1010 #define SHARD_APPIDINFO 0x00000004
1011 #endif
1013 typedef struct {
1014 IShellItem *psi;
1015 PCWSTR pszAppID;
1016 } DummyShardAppIDInfo;
1018 DummyShardAppIDInfo info;
1019 info.psi = pShellItem;
1020 info.pszAppID = (PCWSTR) sApplicationID.getStr();
1022 SHAddToRecentDocs ( SHARD_APPIDINFO, &info );
1023 return;
1028 // For whatever reason, we could not use the SHARD_APPIDINFO semantics
1029 SHAddToRecentDocs(SHARD_PATHW, (PCWSTR) system_path.getStr());
1033 SalTimer* WinSalInstance::CreateSalTimer()
1035 return new WinSalTimer();
1038 SalBitmap* WinSalInstance::CreateSalBitmap()
1040 if (OpenGLHelper::isVCLOpenGLEnabled())
1041 return new OpenGLSalBitmap();
1042 else
1043 return new WinSalBitmap();
1046 class WinImeStatus : public SalI18NImeStatus
1048 public:
1049 WinImeStatus() {}
1050 virtual ~WinImeStatus() {}
1052 // asks whether there is a status window available
1053 // to toggle into menubar
1054 virtual bool canToggle() { return false; }
1055 virtual void toggle() {}
1058 SalI18NImeStatus* WinSalInstance::CreateI18NImeStatus()
1060 return new WinImeStatus();
1063 const OUString& SalGetDesktopEnvironment()
1065 static OUString aDesktopEnvironment( "Windows" );
1066 return aDesktopEnvironment;
1069 SalSession* WinSalInstance::CreateSalSession()
1071 return NULL;
1074 #if !defined ( __MINGW32__ ) || defined ( _WIN64 )
1076 int WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(int, LPEXCEPTION_POINTERS pExceptionInfo)
1078 // Decide if an exception is a c++ (mostly UNO) exception or a process violation.
1079 // Depending on this information we pass process violations directly to our signal handler ...
1080 // and c++ (UNO) exceptions are sended to the following code on the current stack.
1081 // Problem behind: user32.dll sometime consumes exceptions/process violations .-)
1082 // see also #112221#
1084 static DWORD EXCEPTION_MSC_CPP_EXCEPTION = 0xE06D7363;
1086 if (pExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_MSC_CPP_EXCEPTION)
1087 return EXCEPTION_CONTINUE_SEARCH;
1089 return UnhandledExceptionFilter( pExceptionInfo );
1091 #endif
1093 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */