xref: /core/vcl/win/window/salframe.cxx (revision 34e017c4)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
21 #include <com/sun/star/container/XIndexAccess.hpp>
22 #include <com/sun/star/beans/XPropertySet.hpp>
23 #include <com/sun/star/awt/Rectangle.hpp>
24 
25 #include <officecfg/Office/Common.hxx>
26 
27 #include <memory>
28 #include <string.h>
29 #include <limits.h>
30 
31 #include <svsys.h>
32 
33 #include <comphelper/windowserrorstring.hxx>
34 
35 #include <fstream>
36 #include <boost/property_tree/ptree.hpp>
37 #include <boost/property_tree/ini_parser.hpp>
38 #include <osl/file.hxx>
39 #include <osl/process.h>
40 
41 #include <rtl/character.hxx>
42 #include <rtl/string.h>
43 #include <rtl/ustring.h>
44 #include <sal/log.hxx>
45 
46 #include <osl/module.h>
47 #include <comphelper/scopeguard.hxx>
48 #include <tools/debug.hxx>
49 #include <o3tl/enumarray.hxx>
50 #include <o3tl/char16_t2wchar_t.hxx>
51 
52 #include <vcl/event.hxx>
53 #include <vcl/sysdata.hxx>
54 #include <vcl/timer.hxx>
55 #include <vcl/settings.hxx>
56 #include <vcl/keycodes.hxx>
57 #include <vcl/window.hxx>
58 #include <vcl/wrkwin.hxx>
59 #include <vcl/svapp.hxx>
60 #include <vcl/ptrstyle.hxx>
61 
62 #include <win/wincomp.hxx>
63 #include <win/salids.hrc>
64 #include <win/saldata.hxx>
65 #include <win/salinst.h>
66 #include <win/salbmp.h>
67 #include <win/salgdi.h>
68 #include <win/salsys.h>
69 #include <win/salframe.h>
70 #include <win/salvd.h>
71 #include <win/salmenu.h>
72 #include <win/salobj.h>
73 #include <win/saltimer.h>
74 
75 #include <helpwin.hxx>
76 #include <window.h>
77 #include <sallayout.hxx>
78 
79 #define COMPILE_MULTIMON_STUBS
80 #pragma warning(push)
81 #pragma warning(disable:4996) // 'GetVersionExA': was declared deprecated
82 #include <multimon.h>
83 #pragma warning(pop)
84 #include <vector>
85 
86 #include <com/sun/star/uno/Exception.hpp>
87 
88 #include <oleacc.h>
89 #include <com/sun/star/accessibility/XMSAAService.hpp>
90 
91 #include <time.h>
92 
93 #if !defined WIN32_LEAN_AND_MEAN
94 # define WIN32_LEAN_AND_MEAN
95 #endif
96 #include <windows.h>
97 #include <dwmapi.h>
98 #include <shobjidl.h>
99 #include <propkey.h>
100 #include <propvarutil.h>
101 #include <shellapi.h>
102 #include <uxtheme.h>
103 #include <Vssym32.h>
104 
105 using namespace ::com::sun::star;
106 using namespace ::com::sun::star::uno;
107 using namespace ::com::sun::star::lang;
108 using namespace ::com::sun::star::container;
109 using namespace ::com::sun::star::beans;
110 
111 #ifndef SPI_GETWHEELSCROLLCHARS
112 # define SPI_GETWHEELSCROLLCHARS   0x006C
113 #endif
114 #ifndef SPI_SETWHEELSCROLLCHARS
115 # define SPI_SETWHEELSCROLLCHARS   0x006D
116 #endif
117 #ifndef WM_MOUSEHWHEEL
118 # define WM_MOUSEHWHEEL 0x020E
119 #endif
120 #ifndef IDC_PEN
121 # define IDC_PEN MAKEINTRESOURCE(32631)
122 #endif
123 
124 const unsigned int WM_USER_SYSTEM_WINDOW_ACTIVATED = RegisterWindowMessageW(L"SYSTEM_WINDOW_ACTIVATED");
125 
126 bool WinSalFrame::mbInReparent = false;
127 
128 // Macros for support of WM_UNICHAR & Keyman 6.0
129 #define Uni_SupplementaryPlanesStart    0x10000
130 
131 static void UpdateFrameGeometry(WinSalFrame* pFrame);
132 static void SetMaximizedFrameGeometry( HWND hWnd, WinSalFrame* pFrame, RECT* pParentRect = nullptr );
133 
134 static void SetGeometrySize(vcl::WindowPosSize& rWinPosSize, const Size& rSize)
135 {
136     rWinPosSize.setWidth(rSize.Width() < 0 ? 0 : rSize.Width());
137     rWinPosSize.setHeight(rSize.Height() < 0 ? 0 : rSize.Height());
138 }
139 
140 // If called with UpdateFrameGeometry, it must be called after it, as UpdateFrameGeometry
141 // updates the geometry depending on the old state!
142 void WinSalFrame::UpdateFrameState()
143 {
144     // don't overwrite restore state in fullscreen mode
145     if (isFullScreen())
146         return;
147 
148     const bool bVisible = (GetWindowStyle(mhWnd) & WS_VISIBLE);
149     if (IsIconic(mhWnd))
150     {
151         m_eState &= ~vcl::WindowState(vcl::WindowState::Normal | vcl::WindowState::Maximized);
152         m_eState |= vcl::WindowState::Minimized;
153         if (bVisible)
154             mnShowState = SW_SHOWMINIMIZED;
155     }
156     else if (IsZoomed(mhWnd))
157     {
158         m_eState &= ~vcl::WindowState(vcl::WindowState::Minimized | vcl::WindowState::Normal);
159         m_eState |= vcl::WindowState::Maximized;
160         if (bVisible)
161             mnShowState = SW_SHOWMAXIMIZED;
162         mbRestoreMaximize = true;
163     }
164     else
165     {
166         m_eState &= ~vcl::WindowState(vcl::WindowState::Minimized | vcl::WindowState::Maximized);
167         m_eState |= vcl::WindowState::Normal;
168         if (bVisible)
169             mnShowState = SW_SHOWNORMAL;
170         mbRestoreMaximize = false;
171     }
172 }
173 
174 // if pParentRect is set, the workarea of the monitor that contains pParentRect is returned
175 void ImplSalGetWorkArea( HWND hWnd, RECT *pRect, const RECT *pParentRect )
176 {
177     if (Application::IsHeadlessModeEnabled()) {
178         pRect->left = 0;
179         pRect->top = 0;
180         pRect->right = VIRTUAL_DESKTOP_WIDTH;
181         pRect->bottom = VIRTUAL_DESKTOP_HEIGHT;
182         return;
183     }
184     // check if we or our parent is fullscreen, then the taskbar should be ignored
185     bool bIgnoreTaskbar = false;
186     WinSalFrame* pFrame = GetWindowPtr( hWnd );
187     if( pFrame )
188     {
189         vcl::Window *pWin = pFrame->GetWindow();
190         while( pWin )
191         {
192             WorkWindow *pWorkWin = (pWin->GetType() == WindowType::WORKWINDOW) ? static_cast<WorkWindow *>(pWin) : nullptr;
193             if( pWorkWin && pWorkWin->ImplGetWindowImpl()->mbReallyVisible && pWorkWin->IsFullScreenMode() )
194             {
195                 bIgnoreTaskbar = true;
196                 break;
197             }
198             else
199                 pWin = pWin->ImplGetWindowImpl()->mpParent;
200         }
201     }
202 
203     // calculates the work area taking multiple monitors into account
204     static int nMonitors = GetSystemMetrics( SM_CMONITORS );
205     if( nMonitors == 1 )
206     {
207         if( bIgnoreTaskbar )
208         {
209             pRect->left = pRect->top = 0;
210             pRect->right   = GetSystemMetrics( SM_CXSCREEN );
211             pRect->bottom  = GetSystemMetrics( SM_CYSCREEN );
212         }
213         else
214             SystemParametersInfoW( SPI_GETWORKAREA, 0, pRect, 0 );
215     }
216     else
217     {
218         if( pParentRect != nullptr )
219         {
220             // return the size of the monitor where pParentRect lives
221             HMONITOR hMonitor;
222             MONITORINFO mi;
223 
224             // get the nearest monitor to the passed rect.
225             hMonitor = MonitorFromRect(pParentRect, MONITOR_DEFAULTTONEAREST);
226 
227             // get the work area or entire monitor rect.
228             mi.cbSize = sizeof(mi);
229             GetMonitorInfo(hMonitor, &mi);
230             if( !bIgnoreTaskbar )
231                 *pRect = mi.rcWork;
232             else
233                 *pRect = mi.rcMonitor;
234         }
235         else
236         {
237             // return the union of all monitors
238             pRect->left = GetSystemMetrics( SM_XVIRTUALSCREEN );
239             pRect->top = GetSystemMetrics( SM_YVIRTUALSCREEN );
240             pRect->right = pRect->left + GetSystemMetrics( SM_CXVIRTUALSCREEN );
241             pRect->bottom = pRect->top + GetSystemMetrics( SM_CYVIRTUALSCREEN );
242 
243             // virtualscreen does not take taskbar into account, so use the corresponding
244             // diffs between screen and workarea from the default screen
245             // however, this is still not perfect: the taskbar might not be on the primary screen
246             if( !bIgnoreTaskbar )
247             {
248                 RECT wRect, scrRect;
249                 SystemParametersInfoW( SPI_GETWORKAREA, 0, &wRect, 0 );
250                 scrRect.left = 0;
251                 scrRect.top = 0;
252                 scrRect.right = GetSystemMetrics( SM_CXSCREEN );
253                 scrRect.bottom = GetSystemMetrics( SM_CYSCREEN );
254 
255                 pRect->left += wRect.left;
256                 pRect->top += wRect.top;
257                 pRect->right -= scrRect.right - wRect.right;
258                 pRect->bottom -= scrRect.bottom - wRect.bottom;
259             }
260         }
261     }
262 }
263 
264 static void UpdateDarkMode(HWND hWnd)
265 {
266     static bool bOSSupportsDarkMode = OSSupportsDarkMode();
267     if (!bOSSupportsDarkMode)
268         return;
269 
270     HINSTANCE hUxthemeLib = LoadLibraryExW(L"uxtheme.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
271     if (!hUxthemeLib)
272         return;
273 
274     typedef void(WINAPI* AllowDarkModeForWindow_t)(HWND, BOOL);
275     if (auto AllowDarkModeForWindow = reinterpret_cast<AllowDarkModeForWindow_t>(GetProcAddress(hUxthemeLib, MAKEINTRESOURCEA(133))))
276         AllowDarkModeForWindow(hWnd, TRUE);
277 
278     typedef bool(WINAPI* ShouldAppsUseDarkMode_t)();
279     if (auto ShouldAppsUseDarkMode = reinterpret_cast<ShouldAppsUseDarkMode_t>(GetProcAddress(hUxthemeLib, MAKEINTRESOURCEA(132))))
280     {
281         BOOL bDarkMode = ShouldAppsUseDarkMode();
282         DwmSetWindowAttribute(hWnd, 20, &bDarkMode, sizeof(bDarkMode));
283     }
284 
285     FreeLibrary(hUxthemeLib);
286 }
287 
288 SalFrame* ImplSalCreateFrame( WinSalInstance* pInst,
289                               HWND hWndParent, SalFrameStyleFlags nSalFrameStyle )
290 {
291     WinSalFrame*   pFrame = new WinSalFrame;
292     HWND        hWnd;
293     DWORD       nSysStyle = 0;
294     DWORD       nExSysStyle = 0;
295     bool        bSubFrame = false;
296 
297     static const char* pEnvSynchronize = getenv("SAL_SYNCHRONIZE");
298     if ( pEnvSynchronize )   // no buffering of drawing commands
299         GdiSetBatchLimit( 1 );
300 
301     static const char* pEnvTransparentFloats = getenv("SAL_TRANSPARENT_FLOATS" );
302 
303     // determine creation data
304     if ( nSalFrameStyle & (SalFrameStyleFlags::PLUG | SalFrameStyleFlags::SYSTEMCHILD) )
305     {
306         nSysStyle |= WS_CHILD;
307         if( nSalFrameStyle & SalFrameStyleFlags::SYSTEMCHILD )
308             nSysStyle |= WS_CLIPSIBLINGS;
309     }
310     else
311     {
312         // #i87402# commenting out WS_CLIPCHILDREN
313         // this breaks SalFrameStyleFlags::SYSTEMCHILD handling, which is not
314         // used currently. Probably SalFrameStyleFlags::SYSTEMCHILD should be
315         // removed again.
316 
317         // nSysStyle  |= WS_CLIPCHILDREN;
318         if ( hWndParent )
319         {
320             nSysStyle |= WS_POPUP;
321             bSubFrame = true;
322             pFrame->mbNoIcon = true;
323         }
324         else
325         {
326             // Only with WS_OVERLAPPED we get a useful default position/size
327             if ( (nSalFrameStyle & (SalFrameStyleFlags::SIZEABLE | SalFrameStyleFlags::MOVEABLE)) ==
328                  (SalFrameStyleFlags::SIZEABLE | SalFrameStyleFlags::MOVEABLE) )
329                 nSysStyle |= WS_OVERLAPPED;
330             else
331             {
332                 nSysStyle |= WS_POPUP;
333                 if ( !(nSalFrameStyle & SalFrameStyleFlags::MOVEABLE) )
334                     nExSysStyle |= WS_EX_TOOLWINDOW;    // avoid taskbar appearance, for eg splash screen
335             }
336         }
337 
338         if ( nSalFrameStyle & SalFrameStyleFlags::MOVEABLE )
339         {
340             pFrame->mbCaption = true;
341             nSysStyle |= WS_SYSMENU | WS_CAPTION;
342             if ( !hWndParent )
343                 nSysStyle |= WS_SYSMENU | WS_MINIMIZEBOX;
344             else
345                 nExSysStyle |= WS_EX_DLGMODALFRAME;
346 
347             if ( nSalFrameStyle & SalFrameStyleFlags::SIZEABLE )
348             {
349                 pFrame->mbSizeBorder = true;
350                 nSysStyle |= WS_THICKFRAME;
351                 if ( !hWndParent )
352                     nSysStyle |= WS_MAXIMIZEBOX;
353             }
354             else
355                 pFrame->mbFixBorder = true;
356 
357             if ( nSalFrameStyle & SalFrameStyleFlags::DEFAULT )
358                 nExSysStyle |= WS_EX_APPWINDOW;
359         }
360         if( nSalFrameStyle & SalFrameStyleFlags::TOOLWINDOW
361             // #100656# toolwindows lead to bad alt-tab behaviour, if they have the focus
362             // you must press it twice to leave the application
363             // so toolwindows are only used for non sizeable windows
364             // which are typically small, so a small caption makes sense
365 
366             // #103578# looked too bad - above changes reverted
367             /* && !(nSalFrameStyle & SalFrameStyleFlags::SIZEABLE) */ )
368         {
369             pFrame->mbNoIcon = true;
370             nExSysStyle |= WS_EX_TOOLWINDOW;
371             if ( pEnvTransparentFloats /*&& !(nSalFrameStyle & SalFrameStyleFlags::MOVEABLE) */)
372                 nExSysStyle |= WS_EX_LAYERED;
373         }
374     }
375     if ( nSalFrameStyle & SalFrameStyleFlags::FLOAT )
376     {
377         nExSysStyle |= WS_EX_TOOLWINDOW;
378         pFrame->mbFloatWin = true;
379 
380         if (pEnvTransparentFloats)
381             nExSysStyle |= WS_EX_LAYERED;
382 
383     }
384     if (nSalFrameStyle & SalFrameStyleFlags::TOOLTIP)
385         nExSysStyle |= WS_EX_TOPMOST;
386 
387     // init frame data
388     pFrame->mnStyle = nSalFrameStyle;
389 
390     // determine show style
391     pFrame->mnShowState = SW_SHOWNORMAL;
392     if ( (nSysStyle & (WS_POPUP | WS_MAXIMIZEBOX | WS_THICKFRAME)) == (WS_MAXIMIZEBOX | WS_THICKFRAME) )
393     {
394         if ( GetSystemMetrics( SM_CXSCREEN ) <= 1024 )
395             pFrame->mnShowState = SW_SHOWMAXIMIZED;
396         else
397         {
398             if ( nSalFrameStyle & SalFrameStyleFlags::DEFAULT )
399             {
400                 SalData* pSalData = GetSalData();
401                 pFrame->mnShowState = pSalData->mnCmdShow;
402                 if ( (pFrame->mnShowState != SW_SHOWMINIMIZED) &&
403                      (pFrame->mnShowState != SW_MINIMIZE) &&
404                      (pFrame->mnShowState != SW_SHOWMINNOACTIVE) )
405                 {
406                     if ( (pFrame->mnShowState == SW_SHOWMAXIMIZED) ||
407                          (pFrame->mnShowState == SW_MAXIMIZE) )
408                         pFrame->mbOverwriteState = false;
409                     pFrame->mnShowState = SW_SHOWMAXIMIZED;
410                 }
411                 else
412                     pFrame->mbOverwriteState = false;
413             }
414             else
415             {
416                 // Document Windows are also maximized, if the current Document Window
417                 // is also maximized
418                 HWND hWnd2 = GetForegroundWindow();
419                 if ( hWnd2 && IsMaximized( hWnd2 ) &&
420                      (GetWindowInstance( hWnd2 ) == pInst->mhInst) &&
421                      ((GetWindowStyle( hWnd2 ) & (WS_POPUP | WS_MAXIMIZEBOX | WS_THICKFRAME)) == (WS_MAXIMIZEBOX | WS_THICKFRAME)) )
422                     pFrame->mnShowState = SW_SHOWMAXIMIZED;
423             }
424         }
425     }
426 
427     // create frame
428     LPCWSTR pClassName;
429     if ( bSubFrame )
430     {
431         if ( nSalFrameStyle & (SalFrameStyleFlags::MOVEABLE|SalFrameStyleFlags::NOSHADOW) ) // check if shadow not wanted
432             pClassName = SAL_SUBFRAME_CLASSNAMEW;
433         else
434             pClassName = SAL_TMPSUBFRAME_CLASSNAMEW;    // undecorated floaters will get shadow on XP
435     }
436     else
437     {
438         if ( nSalFrameStyle & SalFrameStyleFlags::MOVEABLE )
439             pClassName = SAL_FRAME_CLASSNAMEW;
440         else
441             pClassName = SAL_TMPSUBFRAME_CLASSNAMEW;
442     }
443     hWnd = CreateWindowExW( nExSysStyle, pClassName, L"", nSysStyle,
444                             CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
445                             hWndParent, nullptr, pInst->mhInst, pFrame );
446     SAL_WARN_IF(!hWnd, "vcl", "CreateWindowExW failed: " << WindowsErrorString(GetLastError()));
447 
448 #if OSL_DEBUG_LEVEL > 1
449     // set transparency value
450     if( GetWindowExStyle( hWnd ) & WS_EX_LAYERED )
451         SetLayeredWindowAttributes( hWnd, 0, 230, 0x00000002 /*LWA_ALPHA*/ );
452 #endif
453     if ( !hWnd )
454     {
455         delete pFrame;
456         return nullptr;
457     }
458 
459     // If we have a Window with a Caption Bar and without
460     // a MaximizeBox, we change the SystemMenu
461     if ( (nSysStyle & (WS_CAPTION | WS_MAXIMIZEBOX)) == (WS_CAPTION) )
462     {
463         HMENU hSysMenu = GetSystemMenu( hWnd, FALSE );
464         if ( hSysMenu )
465         {
466             if ( !(nSysStyle & (WS_MINIMIZEBOX | WS_MAXIMIZEBOX)) )
467                 DeleteMenu( hSysMenu, SC_RESTORE, MF_BYCOMMAND );
468             else
469                 EnableMenuItem( hSysMenu, SC_RESTORE, MF_BYCOMMAND | MF_GRAYED | MF_DISABLED );
470             if ( !(nSysStyle & WS_MINIMIZEBOX) )
471                 DeleteMenu( hSysMenu, SC_MINIMIZE, MF_BYCOMMAND );
472             if ( !(nSysStyle & WS_MAXIMIZEBOX) )
473                 DeleteMenu( hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND );
474             if ( !(nSysStyle & WS_THICKFRAME) )
475                 DeleteMenu( hSysMenu, SC_SIZE, MF_BYCOMMAND );
476         }
477     }
478     if ( (nSysStyle & WS_SYSMENU) && !(nSalFrameStyle & SalFrameStyleFlags::CLOSEABLE) )
479     {
480         HMENU hSysMenu = GetSystemMenu( hWnd, FALSE );
481         if ( hSysMenu )
482             EnableMenuItem( hSysMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED | MF_DISABLED );
483     }
484 
485     // reset input context
486     pFrame->mhDefIMEContext = ImmAssociateContext( hWnd, nullptr );
487 
488     // determine output size and state
489     RECT aRect;
490     GetClientRect( hWnd, &aRect );
491     pFrame->mbDefPos = true;
492 
493     UpdateFrameGeometry(pFrame);
494     pFrame->UpdateFrameState();
495 
496     if( pFrame->mnShowState == SW_SHOWMAXIMIZED )
497     {
498         // #96084 set a useful internal window size because
499         // the window will not be maximized (and the size updated) before show()
500 
501         SetMaximizedFrameGeometry( hWnd, pFrame );
502     }
503 
504     return pFrame;
505 }
506 
507 // helper that only creates the HWND
508 // to allow for easy reparenting of system windows, (i.e. destroy and create new)
509 HWND ImplSalReCreateHWND( HWND hWndParent, HWND oldhWnd, bool bAsChild )
510 {
511     HINSTANCE hInstance = GetSalData()->mhInst;
512     sal_uLong nSysStyle     = GetWindowLongW( oldhWnd, GWL_STYLE );
513     sal_uLong nExSysStyle   = GetWindowLongW( oldhWnd, GWL_EXSTYLE );
514 
515     if( bAsChild )
516     {
517         nSysStyle = WS_CHILD;
518         nExSysStyle = 0;
519     }
520 
521     LPCWSTR pClassName = SAL_SUBFRAME_CLASSNAMEW;
522     return CreateWindowExW( nExSysStyle, pClassName, L"", nSysStyle,
523                             CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
524                             hWndParent, nullptr, hInstance, GetWindowPtr( oldhWnd ) );
525 }
526 
527 // translation table from System keycodes into StartView keycodes
528 #define KEY_TAB_SIZE     146
529 
530 const sal_uInt16 aImplTranslateKeyTab[KEY_TAB_SIZE] =
531 {
532     // StarView-Code      System-Code                         Index
533     0,                    //                                  0
534     0,                    // VK_LBUTTON                       1
535     0,                    // VK_RBUTTON                       2
536     0,                    // VK_CANCEL                        3
537     0,                    // VK_MBUTTON                       4
538     0,                    //                                  5
539     0,                    //                                  6
540     0,                    //                                  7
541     KEY_BACKSPACE,        // VK_BACK                          8
542     KEY_TAB,              // VK_TAB                           9
543     0,                    //                                  10
544     0,                    //                                  11
545     0,                    // VK_CLEAR                         12
546     KEY_RETURN,           // VK_RETURN                        13
547     0,                    //                                  14
548     0,                    //                                  15
549     0,                    // VK_SHIFT                         16
550     0,                    // VK_CONTROL                       17
551     0,                    // VK_MENU                          18
552     0,                    // VK_PAUSE                         19
553     0,                    // VK_CAPITAL                       20
554     0,                    // VK_HANGUL                        21
555     0,                    //                                  22
556     0,                    //                                  23
557     0,                    //                                  24
558     KEY_HANGUL_HANJA,     // VK_HANJA                         25
559     0,                    //                                  26
560     KEY_ESCAPE,           // VK_ESCAPE                        27
561     0,                    //                                  28
562     0,                    //                                  29
563     0,                    //                                  30
564     0,                    //                                  31
565     KEY_SPACE,            // VK_SPACE                         32
566     KEY_PAGEUP,           // VK_PRIOR                         33
567     KEY_PAGEDOWN,         // VK_NEXT                          34
568     KEY_END,              // VK_END                           35
569     KEY_HOME,             // VK_HOME                          36
570     KEY_LEFT,             // VK_LEFT                          37
571     KEY_UP,               // VK_UP                            38
572     KEY_RIGHT,            // VK_RIGHT                         39
573     KEY_DOWN,             // VK_DOWN                          40
574     0,                    // VK_SELECT                        41
575     0,                    // VK_PRINT                         42
576     0,                    // VK_EXECUTE                       43
577     0,                    // VK_SNAPSHOT                      44
578     KEY_INSERT,           // VK_INSERT                        45
579     KEY_DELETE,           // VK_DELETE                        46
580     KEY_HELP,             // VK_HELP                          47
581     KEY_0,                //                                  48
582     KEY_1,                //                                  49
583     KEY_2,                //                                  50
584     KEY_3,                //                                  51
585     KEY_4,                //                                  52
586     KEY_5,                //                                  53
587     KEY_6,                //                                  54
588     KEY_7,                //                                  55
589     KEY_8,                //                                  56
590     KEY_9,                //                                  57
591     0,                    //                                  58
592     0,                    //                                  59
593     0,                    //                                  60
594     0,                    //                                  61
595     0,                    //                                  62
596     0,                    //                                  63
597     0,                    //                                  64
598     KEY_A,                //                                  65
599     KEY_B,                //                                  66
600     KEY_C,                //                                  67
601     KEY_D,                //                                  68
602     KEY_E,                //                                  69
603     KEY_F,                //                                  70
604     KEY_G,                //                                  71
605     KEY_H,                //                                  72
606     KEY_I,                //                                  73
607     KEY_J,                //                                  74
608     KEY_K,                //                                  75
609     KEY_L,                //                                  76
610     KEY_M,                //                                  77
611     KEY_N,                //                                  78
612     KEY_O,                //                                  79
613     KEY_P,                //                                  80
614     KEY_Q,                //                                  81
615     KEY_R,                //                                  82
616     KEY_S,                //                                  83
617     KEY_T,                //                                  84
618     KEY_U,                //                                  85
619     KEY_V,                //                                  86
620     KEY_W,                //                                  87
621     KEY_X,                //                                  88
622     KEY_Y,                //                                  89
623     KEY_Z,                //                                  90
624     0,                    // VK_LWIN                          91
625     0,                    // VK_RWIN                          92
626     KEY_CONTEXTMENU,      // VK_APPS                          93
627     0,                    //                                  94
628     0,                    //                                  95
629     KEY_0,                // VK_NUMPAD0                       96
630     KEY_1,                // VK_NUMPAD1                       97
631     KEY_2,                // VK_NUMPAD2                       98
632     KEY_3,                // VK_NUMPAD3                       99
633     KEY_4,                // VK_NUMPAD4                      100
634     KEY_5,                // VK_NUMPAD5                      101
635     KEY_6,                // VK_NUMPAD6                      102
636     KEY_7,                // VK_NUMPAD7                      103
637     KEY_8,                // VK_NUMPAD8                      104
638     KEY_9,                // VK_NUMPAD9                      105
639     KEY_MULTIPLY,         // VK_MULTIPLY                     106
640     KEY_ADD,              // VK_ADD                          107
641     KEY_DECIMAL,          // VK_SEPARATOR                    108
642     KEY_SUBTRACT,         // VK_SUBTRACT                     109
643     KEY_DECIMAL,          // VK_DECIMAL                      110
644     KEY_DIVIDE,           // VK_DIVIDE                       111
645     KEY_F1,               // VK_F1                           112
646     KEY_F2,               // VK_F2                           113
647     KEY_F3,               // VK_F3                           114
648     KEY_F4,               // VK_F4                           115
649     KEY_F5,               // VK_F5                           116
650     KEY_F6,               // VK_F6                           117
651     KEY_F7,               // VK_F7                           118
652     KEY_F8,               // VK_F8                           119
653     KEY_F9,               // VK_F9                           120
654     KEY_F10,              // VK_F10                          121
655     KEY_F11,              // VK_F11                          122
656     KEY_F12,              // VK_F12                          123
657     KEY_F13,              // VK_F13                          124
658     KEY_F14,              // VK_F14                          125
659     KEY_F15,              // VK_F15                          126
660     KEY_F16,              // VK_F16                          127
661     KEY_F17,              // VK_F17                          128
662     KEY_F18,              // VK_F18                          129
663     KEY_F19,              // VK_F19                          130
664     KEY_F20,              // VK_F20                          131
665     KEY_F21,              // VK_F21                          132
666     KEY_F22,              // VK_F22                          133
667     KEY_F23,              // VK_F23                          134
668     KEY_F24,              // VK_F24                          135
669     0,                    //                                 136
670     0,                    //                                 137
671     0,                    //                                 138
672     0,                    //                                 139
673     0,                    //                                 140
674     0,                    //                                 141
675     0,                    //                                 142
676     0,                    //                                 143
677     0,                    // NUMLOCK                         144
678     0                     // SCROLLLOCK                      145
679 };
680 
681 static UINT ImplSalGetWheelScrollLines()
682 {
683     UINT nScrLines = 0;
684     HWND hWndMsWheel = FindWindowW( MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE );
685     if ( hWndMsWheel )
686     {
687         UINT nGetScrollLinesMsgId = RegisterWindowMessageW( MSH_SCROLL_LINES );
688         nScrLines = static_cast<UINT>(SendMessageW( hWndMsWheel, nGetScrollLinesMsgId, 0, 0 ));
689     }
690 
691     if ( !nScrLines )
692         if( !SystemParametersInfoW( SPI_GETWHEELSCROLLLINES, 0, &nScrLines, 0 ) )
693             nScrLines = 0 ;
694 
695     if ( !nScrLines )
696         nScrLines = 3;
697 
698     return nScrLines;
699 }
700 
701 static UINT ImplSalGetWheelScrollChars()
702 {
703     UINT nScrChars = 0;
704     if( !SystemParametersInfoW( SPI_GETWHEELSCROLLCHARS, 0, &nScrChars, 0 ) )
705     {
706         return 3;
707     }
708 
709     // system settings successfully read
710     return nScrChars;
711 }
712 
713 static void ImplSalAddBorder( const WinSalFrame* pFrame, int& width, int& height )
714 {
715     // transform client size into window size
716     RECT    aWinRect;
717     aWinRect.left   = 0;
718     aWinRect.right  = width-1;
719     aWinRect.top    = 0;
720     aWinRect.bottom = height-1;
721     AdjustWindowRectEx( &aWinRect, GetWindowStyle( pFrame->mhWnd ),
722                         FALSE,     GetWindowExStyle( pFrame->mhWnd ) );
723     width  = aWinRect.right - aWinRect.left + 1;
724     height = aWinRect.bottom - aWinRect.top + 1;
725 }
726 
727 static void ImplSalCalcFullScreenSize( const WinSalFrame* pFrame,
728                                        int& rX, int& rY, int& rDX, int& rDY )
729 {
730     // set window to screen size
731     int nFrameX;
732     int nFrameY;
733     int nCaptionY;
734     int nScreenX = 0;
735     int nScreenY = 0;
736     int nScreenDX = 0;
737     int nScreenDY = 0;
738 
739     if ( pFrame->mbSizeBorder )
740     {
741         nFrameX = GetSystemMetrics( SM_CXSIZEFRAME );
742         nFrameY = GetSystemMetrics( SM_CYSIZEFRAME );
743     }
744     else if ( pFrame->mbFixBorder )
745     {
746         nFrameX = GetSystemMetrics( SM_CXFIXEDFRAME );
747         nFrameY = GetSystemMetrics( SM_CYFIXEDFRAME );
748     }
749     else if ( pFrame->mbBorder )
750     {
751         nFrameX = GetSystemMetrics( SM_CXBORDER );
752         nFrameY = GetSystemMetrics( SM_CYBORDER );
753     }
754     else
755     {
756         nFrameX = 0;
757         nFrameY = 0;
758     }
759     if ( pFrame->mbCaption )
760         nCaptionY = GetSystemMetrics( SM_CYCAPTION );
761     else
762         nCaptionY = 0;
763 
764     try
765     {
766         tools::Rectangle aRect;
767         sal_Int32 nMonitors = Application::GetScreenCount();
768         if( (pFrame->mnDisplay >= 0) && (pFrame->mnDisplay < nMonitors) )
769         {
770             aRect = Application::GetScreenPosSizePixel(pFrame->mnDisplay);
771         }
772         else
773         {
774             for (sal_Int32 i = 0; i < nMonitors; i++)
775                 aRect.Union(Application::GetScreenPosSizePixel(i));
776         }
777         nScreenX = aRect.Left();
778         nScreenY = aRect.Top();
779         nScreenDX = aRect.GetWidth();
780         nScreenDY = aRect.GetHeight();
781     }
782     catch( Exception& )
783     {
784     }
785 
786     if( !nScreenDX || !nScreenDY )
787     {
788         nScreenDX   = GetSystemMetrics( SM_CXSCREEN );
789         nScreenDY   = GetSystemMetrics( SM_CYSCREEN );
790     }
791 
792     rX  = nScreenX -nFrameX;
793     rY  = nScreenY -(nFrameY+nCaptionY);
794     rDX = nScreenDX+(nFrameX*2);
795     rDY = nScreenDY+(nFrameY*2)+nCaptionY;
796 }
797 
798 static void ImplSalFrameFullScreenPos( WinSalFrame* pFrame, bool bAlways = false )
799 {
800     if ( bAlways || !IsIconic( pFrame->mhWnd ) )
801     {
802         // set window to screen size
803         int nX;
804         int nY;
805         int nWidth;
806         int nHeight;
807         ImplSalCalcFullScreenSize( pFrame, nX, nY, nWidth, nHeight );
808         SetWindowPos( pFrame->mhWnd, nullptr,
809                       nX, nY, nWidth, nHeight,
810                       SWP_NOZORDER | SWP_NOACTIVATE );
811     }
812 }
813 
814 namespace {
815 
816 void SetForegroundWindow_Impl(HWND hwnd)
817 {
818     if (!Application::IsHeadlessModeEnabled())
819         SetForegroundWindow(hwnd);
820 }
821 
822 }
823 
824 WinSalFrame::WinSalFrame()
825 {
826     SalData* pSalData = GetSalData();
827 
828     mhWnd               = nullptr;
829     mhCursor            = LoadCursor( nullptr, IDC_ARROW );
830     mhDefIMEContext     = nullptr;
831     mpLocalGraphics     = nullptr;
832     mpThreadGraphics    = nullptr;
833     m_eState = vcl::WindowState::Normal;
834     mnShowState         = SW_SHOWNORMAL;
835     mnMinWidth          = 0;
836     mnMinHeight         = 0;
837     mnMaxWidth          = SHRT_MAX;
838     mnMaxHeight         = SHRT_MAX;
839     mnInputLang         = 0;
840     mnInputCodePage     = 0;
841     mbGraphics          = false;
842     mbCaption           = false;
843     mbBorder            = false;
844     mbFixBorder         = false;
845     mbSizeBorder        = false;
846     mbFullScreenCaption = false;
847     mbPresentation      = false;
848     mbInShow            = false;
849     mbRestoreMaximize   = false;
850     mbInMoveMsg         = false;
851     mbInSizeMsg         = false;
852     mbFullScreenToolWin = false;
853     mbDefPos            = true;
854     mbOverwriteState    = true;
855     mbIME               = false;
856     mbHandleIME         = false;
857     mbSpezIME           = false;
858     mbAtCursorIME       = false;
859     mbCandidateMode     = false;
860     mbFloatWin          = false;
861     mbNoIcon            = false;
862     mSelectedhMenu      = nullptr;
863     mLastActivatedhMenu = nullptr;
864     mpClipRgnData       = nullptr;
865     mbFirstClipRect     = true;
866     mpNextClipRect      = nullptr;
867     mnDisplay           = 0;
868     mbPropertiesStored  = false;
869 
870     // get data, when making 1st frame
871     if ( !pSalData->mpFirstFrame )
872     {
873         if ( !aSalShlData.mnWheelScrollLines )
874             aSalShlData.mnWheelScrollLines = ImplSalGetWheelScrollLines();
875         if ( !aSalShlData.mnWheelScrollChars )
876             aSalShlData.mnWheelScrollChars = ImplSalGetWheelScrollChars();
877     }
878 
879     // insert frame in framelist
880     mpNextFrame = pSalData->mpFirstFrame;
881     pSalData->mpFirstFrame = this;
882 }
883 
884 void WinSalFrame::updateScreenNumber()
885 {
886     if( mnDisplay == -1 ) // spans all monitors
887         return;
888     WinSalSystem* pSys = static_cast<WinSalSystem*>(ImplGetSalSystem());
889     if( pSys )
890     {
891         const std::vector<WinSalSystem::DisplayMonitor>& rMonitors =
892             pSys->getMonitors();
893         Point aPoint(maGeometry.pos());
894         size_t nMon = rMonitors.size();
895         for( size_t i = 0; i < nMon; i++ )
896         {
897             if( rMonitors[i].m_aArea.Contains( aPoint ) )
898             {
899                 mnDisplay = static_cast<sal_Int32>(i);
900                 maGeometry.setScreen(static_cast<unsigned int>(i));
901             }
902         }
903     }
904 }
905 
906 bool WinSalFrame::ReleaseFrameGraphicsDC( WinSalGraphics* pGraphics )
907 {
908     assert( pGraphics );
909     SalData* pSalData = GetSalData();
910     HDC hDC = pGraphics->getHDC();
911     if ( !hDC )
912         return false;
913     pGraphics->setHDC(nullptr);
914     SendMessageW( pSalData->mpInstance->mhComWnd, SAL_MSG_RELEASEDC,
915         reinterpret_cast<WPARAM>(mhWnd), reinterpret_cast<LPARAM>(hDC) );
916     if ( pGraphics == mpThreadGraphics )
917         pSalData->mnCacheDCInUse--;
918     return true;
919 }
920 
921 WinSalFrame::~WinSalFrame()
922 {
923     SalData* pSalData = GetSalData();
924 
925     if( mpClipRgnData )
926         delete [] reinterpret_cast<BYTE*>(mpClipRgnData);
927 
928     // remove frame from framelist
929     WinSalFrame** ppFrame = &pSalData->mpFirstFrame;
930     for(; (*ppFrame != this) && *ppFrame; ppFrame = &(*ppFrame)->mpNextFrame );
931     if( *ppFrame )
932         *ppFrame = mpNextFrame;
933     mpNextFrame = nullptr;
934 
935     // destroy the thread SalGraphics
936     if ( mpThreadGraphics )
937     {
938         ReleaseFrameGraphicsDC( mpThreadGraphics );
939         delete mpThreadGraphics;
940         mpThreadGraphics = nullptr;
941     }
942 
943     // destroy the local SalGraphics
944     if ( mpLocalGraphics )
945     {
946         ReleaseFrameGraphicsDC( mpLocalGraphics );
947         delete mpLocalGraphics;
948         mpLocalGraphics = nullptr;
949     }
950 
951     if ( mhWnd )
952     {
953         // reset mouse leave data
954         if ( pSalData->mhWantLeaveMsg == mhWnd )
955         {
956             pSalData->mhWantLeaveMsg = nullptr;
957             if ( pSalData->mpMouseLeaveTimer )
958             {
959                 delete pSalData->mpMouseLeaveTimer;
960                 pSalData->mpMouseLeaveTimer = nullptr;
961             }
962         }
963 
964         // remove windows properties
965         if ( mbPropertiesStored )
966             SetApplicationID( OUString() );
967 
968         // destroy system frame
969         if ( !DestroyWindow( mhWnd ) )
970             SetWindowPtr( mhWnd, nullptr );
971 
972         mhWnd = nullptr;
973     }
974 }
975 
976 bool WinSalFrame::InitFrameGraphicsDC( WinSalGraphics *pGraphics, HDC hDC, HWND hWnd )
977 {
978     SalData* pSalData = GetSalData();
979     assert( pGraphics );
980     pGraphics->setHWND( hWnd );
981 
982     HDC hCurrentDC = pGraphics->getHDC();
983     assert( !hCurrentDC || (hCurrentDC == hDC) );
984     if ( hCurrentDC )
985         return true;
986     pGraphics->setHDC( hDC );
987 
988     if ( !hDC )
989         return false;
990 
991     if ( pSalData->mhDitherPal )
992         pGraphics->setPalette(pSalData->mhDitherPal);
993 
994     if ( pGraphics == mpThreadGraphics )
995         pSalData->mnCacheDCInUse++;
996     return true;
997 }
998 
999 SalGraphics* WinSalFrame::AcquireGraphics()
1000 {
1001     if ( mbGraphics || !mhWnd )
1002         return nullptr;
1003 
1004     SalData* pSalData = GetSalData();
1005     WinSalGraphics *pGraphics = nullptr;
1006     HDC hDC = nullptr;
1007 
1008     // Other threads get an own DC, because Windows modify in the
1009     // other case our DC (changing clip region), when they send a
1010     // WM_ERASEBACKGROUND message
1011     if ( !pSalData->mpInstance->IsMainThread() )
1012     {
1013         // We use only three CacheDC's for all threads, because W9x is limited
1014         // to max. 5 Cache DC's per thread
1015         if ( pSalData->mnCacheDCInUse >= 3 )
1016             return nullptr;
1017 
1018         if ( !mpThreadGraphics )
1019             mpThreadGraphics = new WinSalGraphics(WinSalGraphics::WINDOW, true, mhWnd, this);
1020         pGraphics = mpThreadGraphics;
1021         assert( !pGraphics->getHDC() );
1022         hDC = reinterpret_cast<HDC>(static_cast<sal_IntPtr>(SendMessageW( pSalData->mpInstance->mhComWnd,
1023                                     SAL_MSG_GETCACHEDDC, reinterpret_cast<WPARAM>(mhWnd), 0 )));
1024     }
1025     else
1026     {
1027         if ( !mpLocalGraphics )
1028             mpLocalGraphics = new WinSalGraphics(WinSalGraphics::WINDOW, true, mhWnd, this);
1029         pGraphics = mpLocalGraphics;
1030         hDC = pGraphics->getHDC();
1031         if ( !hDC )
1032             hDC = GetDC( mhWnd );
1033     }
1034 
1035     mbGraphics = InitFrameGraphicsDC( pGraphics, hDC, mhWnd );
1036     return mbGraphics ? pGraphics : nullptr;
1037 }
1038 
1039 void WinSalFrame::ReleaseGraphics( SalGraphics* pGraphics )
1040 {
1041     if ( mpThreadGraphics == pGraphics )
1042         ReleaseFrameGraphicsDC( mpThreadGraphics );
1043     mbGraphics = false;
1044 }
1045 
1046 bool WinSalFrame::PostEvent(std::unique_ptr<ImplSVEvent> pData)
1047 {
1048     bool const ret = PostMessageW(mhWnd, SAL_MSG_USEREVENT, 0, reinterpret_cast<LPARAM>(pData.get()));
1049     SAL_WARN_IF(!ret, "vcl", "ERROR: PostMessage() failed!");
1050     if (ret)
1051         pData.release();
1052     return ret;
1053 }
1054 
1055 void WinSalFrame::SetTitle( const OUString& rTitle )
1056 {
1057     static_assert( sizeof( WCHAR ) == sizeof( sal_Unicode ), "must be the same size" );
1058 
1059     SetWindowTextW( mhWnd, o3tl::toW(rTitle.getStr()) );
1060 }
1061 
1062 void WinSalFrame::SetIcon( sal_uInt16 nIcon )
1063 {
1064     // If we have a window without an Icon (for example a dialog), ignore this call
1065     if ( mbNoIcon )
1066         return;
1067 
1068     // 0 means default (class) icon
1069     HICON hIcon = nullptr, hSmIcon = nullptr;
1070     if ( !nIcon )
1071         nIcon = 1;
1072 
1073     ImplLoadSalIcon( nIcon, hIcon, hSmIcon );
1074 
1075     SAL_WARN_IF( !hIcon , "vcl",   "WinSalFrame::SetIcon(): Could not load large icon !" );
1076     SAL_WARN_IF( !hSmIcon , "vcl", "WinSalFrame::SetIcon(): Could not load small icon !" );
1077 
1078     SendMessageW( mhWnd, WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(hIcon) );
1079     SendMessageW( mhWnd, WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>(hSmIcon) );
1080 }
1081 
1082 void WinSalFrame::SetMenu( SalMenu* pSalMenu )
1083 {
1084     WinSalMenu* pWMenu = static_cast<WinSalMenu*>(pSalMenu);
1085     if( pSalMenu && pWMenu->mbMenuBar )
1086         ::SetMenu( mhWnd, pWMenu->mhMenu );
1087 }
1088 
1089 static HWND ImplGetParentHwnd( HWND hWnd )
1090 {
1091     WinSalFrame* pFrame = GetWindowPtr( hWnd );
1092     if( !pFrame || !pFrame->GetWindow())
1093         return ::GetParent( hWnd );
1094     vcl::Window *pRealParent = pFrame->GetWindow()->ImplGetWindowImpl()->mpRealParent;
1095     if( pRealParent )
1096         return static_cast<WinSalFrame*>(pRealParent->ImplGetWindowImpl()->mpFrame)->mhWnd;
1097     else
1098         return ::GetParent( hWnd );
1099 
1100 }
1101 
1102 SalFrame* WinSalFrame::GetParent() const
1103 {
1104     return GetWindowPtr( ImplGetParentHwnd( mhWnd ) );
1105 }
1106 
1107 static void ImplSalShow( HWND hWnd, bool bVisible, bool bNoActivate )
1108 {
1109     WinSalFrame* pFrame = GetWindowPtr( hWnd );
1110     if ( !pFrame )
1111         return;
1112 
1113     if ( bVisible )
1114     {
1115         pFrame->mbDefPos = false;
1116         pFrame->mbOverwriteState = true;
1117         pFrame->mbInShow = true;
1118 
1119         // #i4715, save position
1120         RECT aRectPreMatrox, aRectPostMatrox;
1121         GetWindowRect( hWnd, &aRectPreMatrox );
1122 
1123         vcl::DeletionListener aDogTag( pFrame );
1124         if( bNoActivate )
1125             ShowWindow( hWnd, SW_SHOWNOACTIVATE );
1126         else
1127             ShowWindow( hWnd, pFrame->mnShowState );
1128         if( aDogTag.isDeleted() )
1129             return;
1130 
1131         if (pFrame->mbFloatWin && !(pFrame->mnStyle & SalFrameStyleFlags::NOSHADOW))
1132         {
1133             // erase the window immediately to improve XP shadow effect
1134             // otherwise the shadow may appears long time before the rest of the window
1135             // especially when accessibility is on
1136             HDC dc = GetDC( hWnd );
1137             RECT aRect;
1138             GetClientRect( hWnd, &aRect );
1139             FillRect( dc, &aRect, reinterpret_cast<HBRUSH>(COLOR_MENU+1) ); // choose the menucolor, because its mostly noticeable for menus
1140             ReleaseDC( hWnd, dc );
1141         }
1142 
1143         // #i4715, matrox centerpopup might have changed our position
1144         // reposition popups without caption (menus, dropdowns, tooltips)
1145         GetWindowRect( hWnd, &aRectPostMatrox );
1146         if( (GetWindowStyle( hWnd ) & WS_POPUP) &&
1147             !pFrame->mbCaption &&
1148             (aRectPreMatrox.left != aRectPostMatrox.left || aRectPreMatrox.top != aRectPostMatrox.top) )
1149             SetWindowPos( hWnd, nullptr, aRectPreMatrox.left, aRectPreMatrox.top, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE  );
1150 
1151         if( aDogTag.isDeleted() )
1152             return;
1153         vcl::Window *pClientWin = pFrame->GetWindow()->ImplGetClientWindow();
1154         if ( pFrame->mbFloatWin || ( pClientWin && (pClientWin->GetStyle() & WB_SYSTEMFLOATWIN) ) )
1155             pFrame->mnShowState = SW_SHOWNOACTIVATE;
1156         else
1157             pFrame->mnShowState = SW_SHOW;
1158         // hide toolbar for W98
1159         if ( pFrame->mbPresentation )
1160         {
1161             HWND hWndParent = ::GetParent( hWnd );
1162             if ( hWndParent )
1163                 SetForegroundWindow_Impl( hWndParent );
1164             SetForegroundWindow_Impl( hWnd );
1165         }
1166 
1167         pFrame->mbInShow = false;
1168         pFrame->updateScreenNumber();
1169 
1170         // Direct Paint only, if we get the SolarMutex
1171         if ( ImplSalYieldMutexTryToAcquire() )
1172         {
1173             UpdateWindow( hWnd );
1174             ImplSalYieldMutexRelease();
1175         }
1176     }
1177     else
1178     {
1179         ShowWindow( hWnd, SW_HIDE );
1180     }
1181 }
1182 
1183 void WinSalFrame::SetExtendedFrameStyle( SalExtStyle )
1184 {
1185 }
1186 
1187 void WinSalFrame::Show( bool bVisible, bool bNoActivate )
1188 {
1189     // Post this Message to the window, because this only works
1190     // in the thread of the window, which has create this window.
1191     // We post this message to avoid deadlocks
1192     if ( GetSalData()->mnAppThreadId != GetCurrentThreadId() )
1193     {
1194         bool const ret = PostMessageW(mhWnd, SAL_MSG_SHOW, WPARAM(bVisible), LPARAM(bNoActivate));
1195         SAL_WARN_IF(!ret, "vcl", "ERROR: PostMessage() failed!");
1196     }
1197     else
1198         ImplSalShow( mhWnd, bVisible, bNoActivate );
1199 }
1200 
1201 void WinSalFrame::SetMinClientSize( tools::Long nWidth, tools::Long nHeight )
1202 {
1203     mnMinWidth  = nWidth;
1204     mnMinHeight = nHeight;
1205 }
1206 
1207 void WinSalFrame::SetMaxClientSize( tools::Long nWidth, tools::Long nHeight )
1208 {
1209     mnMaxWidth  = nWidth;
1210     mnMaxHeight = nHeight;
1211 }
1212 
1213 void WinSalFrame::SetPosSize( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight,
1214                                                    sal_uInt16 nFlags )
1215 {
1216     bool bVisible = (GetWindowStyle( mhWnd ) & WS_VISIBLE) != 0;
1217     if ( !bVisible )
1218     {
1219         vcl::Window *pClientWin = GetWindow()->ImplGetClientWindow();
1220         if ( mbFloatWin || ( pClientWin && (pClientWin->GetStyle() & WB_SYSTEMFLOATWIN) ) )
1221                 mnShowState = SW_SHOWNOACTIVATE;
1222         else
1223                 mnShowState = SW_SHOWNORMAL;
1224     }
1225     else
1226     {
1227         if ( IsIconic( mhWnd ) || IsZoomed( mhWnd ) )
1228                 ShowWindow( mhWnd, SW_RESTORE );
1229     }
1230 
1231     SalEvent nEvent = SalEvent::NONE;
1232     UINT    nPosSize = 0;
1233     RECT    aClientRect, aWindowRect;
1234     GetClientRect( mhWnd, &aClientRect );   // x,y always 0,0, but width and height without border
1235     GetWindowRect( mhWnd, &aWindowRect );   // x,y in screen coordinates, width and height with border
1236 
1237     if ( !(nFlags & (SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y)) )
1238         nPosSize |= SWP_NOMOVE;
1239     else
1240     {
1241         //SAL_WARN_IF( !nX || !nY, "vcl", " Windowposition of (0,0) requested!" );
1242         nEvent = SalEvent::Move;
1243     }
1244     if ( !(nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT)) )
1245         nPosSize |= SWP_NOSIZE;
1246     else
1247         nEvent = (nEvent == SalEvent::Move) ? SalEvent::MoveResize : SalEvent::Resize;
1248 
1249     if ( !(nFlags & SAL_FRAME_POSSIZE_X) )
1250         nX = aWindowRect.left;
1251     if ( !(nFlags & SAL_FRAME_POSSIZE_Y) )
1252         nY = aWindowRect.top;
1253     if ( !(nFlags & SAL_FRAME_POSSIZE_WIDTH) )
1254         nWidth = aClientRect.right-aClientRect.left;
1255     if ( !(nFlags & SAL_FRAME_POSSIZE_HEIGHT) )
1256         nHeight = aClientRect.bottom-aClientRect.top;
1257 
1258     // Calculate window size including the border
1259     RECT    aWinRect;
1260     aWinRect.left   = 0;
1261     aWinRect.right  = static_cast<int>(nWidth)-1;
1262     aWinRect.top    = 0;
1263     aWinRect.bottom = static_cast<int>(nHeight)-1;
1264     AdjustWindowRectEx( &aWinRect, GetWindowStyle( mhWnd ),
1265                         FALSE,     GetWindowExStyle( mhWnd ) );
1266     nWidth  = aWinRect.right - aWinRect.left + 1;
1267     nHeight = aWinRect.bottom - aWinRect.top + 1;
1268 
1269     HWND hWndParent = ImplGetParentHwnd(mhWnd);
1270     // For dialogs (WS_POPUP && WS_DLGFRAME), we need to find the "real" parent,
1271     // in case multiple dialogs are stacked on each other
1272     // (we don't want to position the second dialog relative to the first one, but relative to the main window)
1273     if ( (GetWindowStyle( mhWnd ) & WS_POPUP) &&  (GetWindowStyle( mhWnd ) & WS_DLGFRAME) ) // mhWnd is a dialog
1274     {
1275         while ( hWndParent && (GetWindowStyle( hWndParent ) & WS_POPUP) &&  (GetWindowStyle( hWndParent ) & WS_DLGFRAME) )
1276         {
1277             hWndParent = ::ImplGetParentHwnd( hWndParent );
1278         }
1279     }
1280 
1281     if ( !(nPosSize & SWP_NOMOVE) && hWndParent )
1282     {
1283             RECT aParentRect;
1284             GetClientRect( hWndParent, &aParentRect );
1285             if( AllSettings::GetLayoutRTL() )
1286                 nX = (aParentRect.right - aParentRect.left) - nWidth-1 - nX;
1287 
1288             //#110386#, do not transform coordinates for system child windows
1289             if( !(GetWindowStyle( mhWnd ) & WS_CHILD) )
1290             {
1291                 POINT aPt;
1292                 aPt.x = nX;
1293                 aPt.y = nY;
1294 
1295                 WinSalFrame* pParentFrame = GetWindowPtr( hWndParent );
1296                 if ( pParentFrame && pParentFrame->mnShowState == SW_SHOWMAXIMIZED )
1297                 {
1298                     // #i42485#: parent will be shown maximized in which case
1299                     // a ClientToScreen uses the wrong coordinates (i.e. those from the restore pos)
1300                     // so use the (already updated) frame geometry for the transformation
1301                     aPt.x +=  pParentFrame->maGeometry.x();
1302                     aPt.y +=  pParentFrame->maGeometry.y();
1303                 }
1304                 else
1305                     ClientToScreen( hWndParent, &aPt );
1306 
1307                 nX = aPt.x;
1308                 nY = aPt.y;
1309 
1310                 // the position is set
1311                 mbDefPos = false;
1312             }
1313     }
1314 
1315     // #i3338# to be conformant to UNIX we must position the client window, ie without the decoration
1316     // #i43250# if the position was read from the system (GetWindowRect(), see above), it must not be modified
1317     if ( nFlags & SAL_FRAME_POSSIZE_X )
1318         nX += aWinRect.left;
1319     if ( nFlags & SAL_FRAME_POSSIZE_Y )
1320         nY += aWinRect.top;
1321 
1322     int     nScreenX;
1323     int     nScreenY;
1324     int     nScreenWidth;
1325     int     nScreenHeight;
1326 
1327     RECT aRect;
1328     ImplSalGetWorkArea( mhWnd, &aRect, nullptr );
1329     nScreenX        = aRect.left;
1330     nScreenY        = aRect.top;
1331     nScreenWidth    = aRect.right-aRect.left;
1332     nScreenHeight   = aRect.bottom-aRect.top;
1333 
1334     if ( mbDefPos && (nPosSize & SWP_NOMOVE)) // we got no positioning request, so choose default position
1335     {
1336         // center window
1337 
1338         HWND hWndParent2 = ::GetParent( mhWnd );
1339         // Search for TopLevel Frame
1340         while ( hWndParent2 && (GetWindowStyle( hWndParent2 ) & WS_CHILD) )
1341             hWndParent2 = ::GetParent( hWndParent2 );
1342         // if the Window has a Parent, then center the window to
1343         // the parent, in the other case to the screen
1344         if ( hWndParent2 && !IsIconic( hWndParent2 ) &&
1345              (GetWindowStyle( hWndParent2 ) & WS_VISIBLE) )
1346         {
1347             RECT aParentRect;
1348             GetWindowRect( hWndParent2, &aParentRect );
1349             int nParentWidth    = aParentRect.right-aParentRect.left;
1350             int nParentHeight   = aParentRect.bottom-aParentRect.top;
1351 
1352             // We don't center, when Parent is smaller than our window
1353             if ( (nParentWidth-GetSystemMetrics( SM_CXFIXEDFRAME ) <= nWidth) &&
1354                  (nParentHeight-GetSystemMetrics( SM_CYFIXEDFRAME ) <= nHeight) )
1355             {
1356                 int nOff = GetSystemMetrics( SM_CYSIZEFRAME ) + GetSystemMetrics( SM_CYCAPTION );
1357                 nX = aParentRect.left+nOff;
1358                 nY = aParentRect.top+nOff;
1359             }
1360             else
1361             {
1362                 nX = (nParentWidth-nWidth)/2 + aParentRect.left;
1363                 nY = (nParentHeight-nHeight)/2 + aParentRect.top;
1364             }
1365         }
1366         else
1367         {
1368             POINT pt;
1369             GetCursorPos( &pt );
1370             RECT aRect2;
1371             aRect2.left = pt.x;
1372             aRect2.top = pt.y;
1373             aRect2.right = pt.x+2;
1374             aRect2.bottom = pt.y+2;
1375 
1376             // dualmonitor support:
1377             // Get screensize of the monitor with the mouse pointer
1378             ImplSalGetWorkArea( mhWnd, &aRect2, &aRect2 );
1379 
1380             nX = ((aRect2.right-aRect2.left)-nWidth)/2 + aRect2.left;
1381             nY = ((aRect2.bottom-aRect2.top)-nHeight)/2 + aRect2.top;
1382         }
1383 
1384         //if ( bVisible )
1385         //    mbDefPos = FALSE;
1386 
1387         mbDefPos = false;   // center only once
1388         nPosSize &= ~SWP_NOMOVE;        // activate positioning
1389         nEvent = SalEvent::MoveResize;
1390     }
1391 
1392     // Adjust Window in the screen
1393     bool bCheckOffScreen = true;
1394 
1395     // but don't do this for floaters or ownerdraw windows that are currently moved interactively
1396     if( (mnStyle & SalFrameStyleFlags::FLOAT) && !(mnStyle & SalFrameStyleFlags::OWNERDRAWDECORATION) )
1397         bCheckOffScreen = false;
1398 
1399     if( mnStyle & SalFrameStyleFlags::OWNERDRAWDECORATION )
1400     {
1401         // may be the window is currently being moved (mouse is captured), then no check is required
1402         if( mhWnd == ::GetCapture() )
1403             bCheckOffScreen = false;
1404         else
1405             bCheckOffScreen = true;
1406     }
1407 
1408     if( bCheckOffScreen )
1409     {
1410         if ( nX+nWidth > nScreenX+nScreenWidth )
1411             nX = (nScreenX+nScreenWidth) - nWidth;
1412         if ( nY+nHeight > nScreenY+nScreenHeight )
1413             nY = (nScreenY+nScreenHeight) - nHeight;
1414         if ( nX < nScreenX )
1415             nX = nScreenX;
1416         if ( nY < nScreenY )
1417             nY = nScreenY;
1418     }
1419 
1420     UINT nPosFlags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | nPosSize;
1421     // bring floating windows always to top
1422     if( !(mnStyle & SalFrameStyleFlags::FLOAT) )
1423         nPosFlags |= SWP_NOZORDER; // do not change z-order
1424 
1425     SetWindowPos( mhWnd, HWND_TOP, nX, nY, static_cast<int>(nWidth), static_cast<int>(nHeight), nPosFlags  );
1426 
1427     UpdateFrameGeometry(this);
1428 
1429     // Notification -- really ???
1430     if( nEvent != SalEvent::NONE )
1431         CallCallback( nEvent, nullptr );
1432 }
1433 
1434 void WinSalFrame::ImplSetParentFrame( HWND hNewParentWnd, bool bAsChild )
1435 {
1436     // save hwnd, will be overwritten in WM_CREATE during createwindow
1437     HWND hWndOld = mhWnd;
1438     HWND hWndOldParent = ::GetParent( hWndOld );
1439     SalData* pSalData = GetSalData();
1440 
1441     if( hNewParentWnd == hWndOldParent )
1442         return;
1443 
1444     ::std::vector< WinSalFrame* > children;
1445     ::std::vector< WinSalObject* > systemChildren;
1446 
1447     // search child windows
1448     WinSalFrame *pFrame = pSalData->mpFirstFrame;
1449     while( pFrame )
1450     {
1451         HWND hWndParent = ::GetParent( pFrame->mhWnd );
1452         if( mhWnd == hWndParent )
1453             children.push_back( pFrame );
1454         pFrame = pFrame->mpNextFrame;
1455     }
1456 
1457     // search system child windows (plugins etc.)
1458     WinSalObject *pObject = pSalData->mpFirstObject;
1459     while( pObject )
1460     {
1461         HWND hWndParent = ::GetParent( pObject->mhWnd );
1462         if( mhWnd == hWndParent )
1463             systemChildren.push_back( pObject );
1464         pObject = pObject->mpNextObject;
1465     }
1466 
1467     // to recreate the DCs, if they were destroyed
1468     bool bHadLocalGraphics = false, bHadThreadGraphics = false;
1469 
1470     HFONT   hFont   = nullptr;
1471     HPEN    hPen    = nullptr;
1472     HBRUSH  hBrush  = nullptr;
1473 
1474     int oldCount = pSalData->mnCacheDCInUse;
1475 
1476     // release the thread DC
1477     if ( mpThreadGraphics )
1478     {
1479         // save current gdi objects before hdc is gone
1480         HDC hDC = mpThreadGraphics->getHDC();
1481         if ( hDC )
1482         {
1483             hFont  = static_cast<HFONT>(GetCurrentObject( hDC, OBJ_FONT ));
1484             hPen   = static_cast<HPEN>(GetCurrentObject( hDC, OBJ_PEN ));
1485             hBrush = static_cast<HBRUSH>(GetCurrentObject( hDC, OBJ_BRUSH ));
1486         }
1487 
1488         bHadThreadGraphics = ReleaseFrameGraphicsDC( mpThreadGraphics );
1489         assert( (bHadThreadGraphics && hDC) || (!bHadThreadGraphics && !hDC) );
1490     }
1491 
1492     // release the local DC
1493     if ( mpLocalGraphics )
1494         bHadLocalGraphics = ReleaseFrameGraphicsDC( mpLocalGraphics );
1495 
1496     // create a new hwnd with the same styles
1497     HWND hWndParent = hNewParentWnd;
1498     // forward to main thread
1499     HWND hWnd = reinterpret_cast<HWND>(static_cast<sal_IntPtr>(SendMessageW( pSalData->mpInstance->mhComWnd,
1500                                         bAsChild ? SAL_MSG_RECREATECHILDHWND : SAL_MSG_RECREATEHWND,
1501                                         reinterpret_cast<WPARAM>(hWndParent), reinterpret_cast<LPARAM>(mhWnd) )));
1502 
1503     // succeeded ?
1504     SAL_WARN_IF( !IsWindow( hWnd ), "vcl", "WinSalFrame::SetParent not successful");
1505 
1506     // re-create thread DC
1507     if( bHadThreadGraphics )
1508     {
1509         HDC hDC = reinterpret_cast<HDC>(static_cast<sal_IntPtr>(
1510                     SendMessageW( pSalData->mpInstance->mhComWnd,
1511                         SAL_MSG_GETCACHEDDC, reinterpret_cast<WPARAM>(hWnd), 0 )));
1512         InitFrameGraphicsDC( mpThreadGraphics, hDC, hWnd );
1513         if ( hDC )
1514         {
1515             // re-select saved gdi objects
1516             if( hFont )
1517                 SelectObject( hDC, hFont );
1518             if( hPen )
1519                 SelectObject( hDC, hPen );
1520             if( hBrush )
1521                 SelectObject( hDC, hBrush );
1522 
1523             SAL_WARN_IF( oldCount != pSalData->mnCacheDCInUse, "vcl", "WinSalFrame::SetParent() hDC count corrupted");
1524         }
1525     }
1526 
1527     // re-create local DC
1528     if( bHadLocalGraphics )
1529         InitFrameGraphicsDC( mpLocalGraphics, GetDC( hWnd ), hWnd );
1530 
1531     // TODO: add SetParent() call for SalObjects
1532     SAL_WARN_IF( !systemChildren.empty(), "vcl", "WinSalFrame::SetParent() parent of living system child window will be destroyed!");
1533 
1534     // reparent children before old parent is destroyed
1535     for (auto & child : children)
1536         child->ImplSetParentFrame( hWnd, false );
1537 
1538     children.clear();
1539     systemChildren.clear();
1540 
1541     // Now destroy original HWND in the thread where it was created.
1542     SendMessageW( GetSalData()->mpInstance->mhComWnd,
1543                      SAL_MSG_DESTROYHWND, WPARAM(0), reinterpret_cast<LPARAM>(hWndOld));
1544 }
1545 
1546 void WinSalFrame::SetParent( SalFrame* pNewParent )
1547 {
1548     WinSalFrame::mbInReparent = true;
1549     ImplSetParentFrame( static_cast<WinSalFrame*>(pNewParent)->mhWnd, false );
1550     WinSalFrame::mbInReparent = false;
1551 }
1552 
1553 void WinSalFrame::SetPluginParent( SystemParentData* pNewParent )
1554 {
1555     if ( pNewParent->hWnd == nullptr )
1556     {
1557         pNewParent->hWnd = GetDesktopWindow();
1558     }
1559 
1560     WinSalFrame::mbInReparent = true;
1561     ImplSetParentFrame( pNewParent->hWnd, true );
1562     WinSalFrame::mbInReparent = false;
1563 }
1564 
1565 void WinSalFrame::GetWorkArea( tools::Rectangle &rRect )
1566 {
1567     RECT aRect;
1568     ImplSalGetWorkArea( mhWnd, &aRect, nullptr );
1569     rRect.SetLeft( aRect.left );
1570     rRect.SetRight( aRect.right-1 );
1571     rRect.SetTop( aRect.top );
1572     rRect.SetBottom( aRect.bottom-1 );
1573 }
1574 
1575 void WinSalFrame::GetClientSize( tools::Long& rWidth, tools::Long& rHeight )
1576 {
1577     rWidth  = maGeometry.width();
1578     rHeight = maGeometry.height();
1579 }
1580 
1581 void WinSalFrame::SetWindowState(const vcl::WindowData* pState)
1582 {
1583     // Check if the window fits into the screen, in case the screen
1584     // resolution changed
1585     int     nX;
1586     int     nY;
1587     int     nWidth;
1588     int     nHeight;
1589     int     nScreenX;
1590     int     nScreenY;
1591     int     nScreenWidth;
1592     int     nScreenHeight;
1593 
1594     RECT aRect;
1595     ImplSalGetWorkArea( mhWnd, &aRect, nullptr );
1596     // #102500# allow some overlap, the window could have been made a little larger than the physical screen
1597     nScreenX        = aRect.left-10;
1598     nScreenY        = aRect.top-10;
1599     nScreenWidth    = aRect.right-aRect.left+20;
1600     nScreenHeight   = aRect.bottom-aRect.top+20;
1601 
1602     UINT    nPosSize    = 0;
1603     RECT    aWinRect;
1604     GetWindowRect( mhWnd, &aWinRect );
1605 
1606     // to be consistent with Unix, the frame state is without(!) decoration
1607     // ->add the decoration
1608     RECT aRect2 = aWinRect;
1609     AdjustWindowRectEx( &aRect2, GetWindowStyle( mhWnd ),
1610                     FALSE,     GetWindowExStyle( mhWnd ) );
1611     tools::Long nTopDeco = abs( aWinRect.top - aRect2.top );
1612     tools::Long nLeftDeco = abs( aWinRect.left - aRect2.left );
1613     tools::Long nBottomDeco = abs( aWinRect.bottom - aRect2.bottom );
1614     tools::Long nRightDeco = abs( aWinRect.right - aRect2.right );
1615 
1616     // adjust window position/size to fit the screen
1617     if ( !(pState->mask() & vcl::WindowDataMask::Pos) )
1618         nPosSize |= SWP_NOMOVE;
1619     if ( !(pState->mask() & vcl::WindowDataMask::Size) )
1620         nPosSize |= SWP_NOSIZE;
1621     if ( pState->mask() & vcl::WindowDataMask::X )
1622         nX = static_cast<int>(pState->x()) - nLeftDeco;
1623     else
1624         nX = aWinRect.left;
1625     if ( pState->mask() & vcl::WindowDataMask::Y )
1626         nY = static_cast<int>(pState->y()) - nTopDeco;
1627     else
1628         nY = aWinRect.top;
1629     if ( pState->mask() & vcl::WindowDataMask::Width )
1630         nWidth = static_cast<int>(pState->width()) + nLeftDeco + nRightDeco;
1631     else
1632         nWidth = aWinRect.right-aWinRect.left;
1633     if ( pState->mask() & vcl::WindowDataMask::Height )
1634         nHeight = static_cast<int>(pState->height()) + nTopDeco + nBottomDeco;
1635     else
1636         nHeight = aWinRect.bottom-aWinRect.top;
1637 
1638     // Adjust Window in the screen:
1639     // if it does not fit into the screen do nothing, ie default pos/size will be used
1640     // if there is an overlap with the screen border move the window while keeping its size
1641 
1642     if( nWidth > nScreenWidth || nHeight > nScreenHeight )
1643         nPosSize |= (SWP_NOMOVE | SWP_NOSIZE);
1644 
1645     if ( nX+nWidth > nScreenX+nScreenWidth )
1646         nX = (nScreenX+nScreenWidth) - nWidth;
1647     if ( nY+nHeight > nScreenY+nScreenHeight )
1648         nY = (nScreenY+nScreenHeight) - nHeight;
1649     if ( nX < nScreenX )
1650         nX = nScreenX;
1651     if ( nY < nScreenY )
1652         nY = nScreenY;
1653 
1654     // set Restore-Position
1655     WINDOWPLACEMENT aPlacement;
1656     aPlacement.length = sizeof( aPlacement );
1657     GetWindowPlacement( mhWnd, &aPlacement );
1658 
1659     // set State
1660     const bool bIsMinimized = IsIconic(mhWnd);
1661     const bool bIsMaximized = IsZoomed(mhWnd);
1662     const bool bVisible = (GetWindowStyle(mhWnd) & WS_VISIBLE);
1663     bool bUpdateHiddenFramePos = false;
1664     if ( !bVisible )
1665     {
1666         aPlacement.showCmd = SW_HIDE;
1667 
1668         if (mbOverwriteState && (pState->mask() & vcl::WindowDataMask::State))
1669         {
1670             if (pState->state() & vcl::WindowState::Minimized)
1671                 mnShowState = SW_SHOWMINIMIZED;
1672             else if (pState->state() & vcl::WindowState::Maximized)
1673             {
1674                 mnShowState = SW_SHOWMAXIMIZED;
1675                 bUpdateHiddenFramePos = true;
1676             }
1677             else if (pState->state() & vcl::WindowState::Normal)
1678                 mnShowState = SW_SHOWNORMAL;
1679         }
1680     }
1681     else
1682     {
1683         if ( pState->mask() & vcl::WindowDataMask::State )
1684         {
1685             if ( pState->state() & vcl::WindowState::Minimized )
1686             {
1687                 if ( pState->state() & vcl::WindowState::Maximized )
1688                     aPlacement.flags |= WPF_RESTORETOMAXIMIZED;
1689                 aPlacement.showCmd = SW_SHOWMINIMIZED;
1690             }
1691             else if ( pState->state() & vcl::WindowState::Maximized )
1692                 aPlacement.showCmd = SW_SHOWMAXIMIZED;
1693             else if ( pState->state() & vcl::WindowState::Normal )
1694                 aPlacement.showCmd = SW_RESTORE;
1695         }
1696     }
1697 
1698     // if a window is neither minimized nor maximized or need not be
1699     // positioned visibly (that is in visible state), do not use
1700     // SetWindowPlacement since it calculates including the TaskBar
1701     if (!bIsMinimized && !bIsMaximized && (!bVisible || (aPlacement.showCmd == SW_RESTORE)))
1702     {
1703         if( bUpdateHiddenFramePos )
1704         {
1705             RECT aStateRect;
1706             aStateRect.left   = nX;
1707             aStateRect.top    = nY;
1708             aStateRect.right  = nX+nWidth;
1709             aStateRect.bottom = nY+nHeight;
1710             // #96084 set a useful internal window size because
1711             // the window will not be maximized (and the size updated) before show()
1712             SetMaximizedFrameGeometry( mhWnd, this, &aStateRect );
1713             SetWindowPos( mhWnd, nullptr,
1714                           maGeometry.x(), maGeometry.y(), maGeometry.width(), maGeometry.height(),
1715                           SWP_NOZORDER | SWP_NOACTIVATE | nPosSize );
1716         }
1717         else
1718             SetWindowPos( mhWnd, nullptr,
1719                       nX, nY, nWidth, nHeight,
1720                       SWP_NOZORDER | SWP_NOACTIVATE | nPosSize );
1721     }
1722     else
1723     {
1724         if( !(nPosSize & (SWP_NOMOVE|SWP_NOSIZE)) )
1725         {
1726             aPlacement.rcNormalPosition.left    = nX-nScreenX;
1727             aPlacement.rcNormalPosition.top     = nY-nScreenY;
1728             aPlacement.rcNormalPosition.right   = nX+nWidth-nScreenX;
1729             aPlacement.rcNormalPosition.bottom  = nY+nHeight-nScreenY;
1730         }
1731         SetWindowPlacement( mhWnd, &aPlacement );
1732     }
1733 
1734     if( !(nPosSize & SWP_NOMOVE) )
1735         mbDefPos = false; // window was positioned
1736 }
1737 
1738 bool WinSalFrame::GetWindowState(vcl::WindowData* pState)
1739 {
1740     pState->setPosSize(maGeometry.posSize());
1741     pState->setState(m_eState);
1742     pState->setMask(vcl::WindowDataMask::PosSizeState);
1743     return true;
1744 }
1745 
1746 void WinSalFrame::SetScreenNumber( unsigned int nNewScreen )
1747 {
1748     WinSalSystem* pSys = static_cast<WinSalSystem*>(ImplGetSalSystem());
1749     if( pSys )
1750     {
1751         const std::vector<WinSalSystem::DisplayMonitor>& rMonitors =
1752             pSys->getMonitors();
1753         size_t nMon = rMonitors.size();
1754         if( nNewScreen < nMon )
1755         {
1756             Point aOldMonPos, aNewMonPos( rMonitors[nNewScreen].m_aArea.TopLeft() );
1757             Point aCurPos(maGeometry.pos());
1758             for( size_t i = 0; i < nMon; i++ )
1759             {
1760                 if( rMonitors[i].m_aArea.Contains( aCurPos ) )
1761                 {
1762                     aOldMonPos = rMonitors[i].m_aArea.TopLeft();
1763                     break;
1764                 }
1765             }
1766             mnDisplay = nNewScreen;
1767             maGeometry.setScreen(nNewScreen);
1768             SetPosSize( aNewMonPos.X() + (maGeometry.x() - aOldMonPos.X()),
1769                         aNewMonPos.Y() + (maGeometry.y() - aOldMonPos.Y()),
1770                         0, 0,
1771                         SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
1772         }
1773     }
1774 }
1775 
1776 void WinSalFrame::SetApplicationID( const OUString &rApplicationID )
1777 {
1778     // http://msdn.microsoft.com/en-us/library/windows/desktop/dd378430(v=vs.85).aspx
1779     // A window's properties must be removed before the window is closed.
1780 
1781     IPropertyStore *pps;
1782     HRESULT hr = SHGetPropertyStoreForWindow(mhWnd, IID_PPV_ARGS(&pps));
1783     if (SUCCEEDED(hr))
1784     {
1785         PROPVARIANT pv;
1786         if (!rApplicationID.isEmpty())
1787         {
1788             hr = InitPropVariantFromString(o3tl::toW(rApplicationID.getStr()), &pv);
1789             mbPropertiesStored = true;
1790         }
1791         else
1792             // if rApplicationID we remove the property from the window, if present
1793             PropVariantInit(&pv);
1794 
1795         if (SUCCEEDED(hr))
1796         {
1797             hr = pps->SetValue(PKEY_AppUserModel_ID, pv);
1798             PropVariantClear(&pv);
1799         }
1800         pps->Release();
1801     }
1802 }
1803 
1804 void WinSalFrame::ShowFullScreen(const bool bFullScreen, const sal_Int32 nDisplay)
1805 {
1806     if ((isFullScreen() == bFullScreen) && (!bFullScreen || (mnDisplay == nDisplay)))
1807         return;
1808 
1809     mnDisplay = nDisplay;
1810 
1811     if ( bFullScreen )
1812     {
1813         m_eState |= vcl::WindowState::FullScreen;
1814         // to hide the Windows taskbar
1815         DWORD nExStyle = GetWindowExStyle( mhWnd );
1816         if ( nExStyle & WS_EX_TOOLWINDOW )
1817         {
1818             mbFullScreenToolWin = true;
1819             nExStyle &= ~WS_EX_TOOLWINDOW;
1820             SetWindowExStyle( mhWnd, nExStyle );
1821         }
1822         // save old position
1823         GetWindowRect( mhWnd, &maFullScreenRect );
1824 
1825         // save show state
1826         mnFullScreenShowState = mnShowState;
1827         if ( !(GetWindowStyle( mhWnd ) & WS_VISIBLE) )
1828             mnShowState = SW_SHOW;
1829 
1830         // Save caption state.
1831         mbFullScreenCaption = mbCaption;
1832         if (mbCaption)
1833         {
1834             DWORD nStyle = GetWindowStyle(mhWnd);
1835             SetWindowStyle(mhWnd, nStyle & ~WS_CAPTION);
1836             mbCaption = false;
1837         }
1838 
1839         // set window to screen size
1840         ImplSalFrameFullScreenPos( this, true );
1841     }
1842     else
1843     {
1844         m_eState &= ~vcl::WindowState::FullScreen;
1845         // when the ShowState has to be reset, hide the window first to
1846         // reduce flicker
1847         bool bVisible = (GetWindowStyle( mhWnd ) & WS_VISIBLE) != 0;
1848         if ( bVisible && (mnShowState != mnFullScreenShowState) )
1849             ShowWindow( mhWnd, SW_HIDE );
1850 
1851         if ( mbFullScreenToolWin )
1852             SetWindowExStyle( mhWnd, GetWindowExStyle( mhWnd ) | WS_EX_TOOLWINDOW );
1853         mbFullScreenToolWin = false;
1854 
1855         // Restore caption state.
1856         if (mbFullScreenCaption)
1857         {
1858             DWORD nStyle = GetWindowStyle(mhWnd);
1859             SetWindowStyle(mhWnd, nStyle | WS_CAPTION);
1860         }
1861         mbCaption = mbFullScreenCaption;
1862 
1863         SetWindowPos( mhWnd, nullptr,
1864                       maFullScreenRect.left,
1865                       maFullScreenRect.top,
1866                       maFullScreenRect.right-maFullScreenRect.left,
1867                       maFullScreenRect.bottom-maFullScreenRect.top,
1868                       SWP_NOZORDER | SWP_NOACTIVATE );
1869 
1870         // restore show state
1871         if ( mnShowState != mnFullScreenShowState )
1872         {
1873             mnShowState = mnFullScreenShowState;
1874             if ( bVisible )
1875             {
1876                 mbInShow = true;
1877                 ShowWindow( mhWnd, mnShowState );
1878                 mbInShow = false;
1879                 UpdateWindow( mhWnd );
1880             }
1881         }
1882     }
1883 }
1884 
1885 void WinSalFrame::StartPresentation( bool bStart )
1886 {
1887     if ( mbPresentation == bStart )
1888         return;
1889 
1890     mbPresentation = bStart;
1891 
1892     if ( bStart )
1893     {
1894         // turn off screen-saver / power saving when in Presentation mode
1895         SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);
1896     }
1897     else
1898     {
1899         // turn on screen-saver / power saving back
1900         SetThreadExecutionState(ES_CONTINUOUS);
1901     }
1902 }
1903 
1904 void WinSalFrame::SetAlwaysOnTop( bool bOnTop )
1905 {
1906     HWND hWnd;
1907     if ( bOnTop )
1908         hWnd = HWND_TOPMOST;
1909     else
1910         hWnd = HWND_NOTOPMOST;
1911     SetWindowPos( mhWnd, hWnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
1912 }
1913 
1914 static bool EnableAttachThreadInputHack()
1915 {
1916     OUString aBootstrapUri;
1917     if (osl_getProcessWorkingDir(&aBootstrapUri.pData) != osl_Process_E_None)
1918         return false;
1919     aBootstrapUri += "/bootstrap.ini";
1920 
1921     OUString aSystemFileName;
1922     if (osl::FileBase::getSystemPathFromFileURL(aBootstrapUri, aSystemFileName) != osl::FileBase::E_None)
1923         return false;
1924     if (aSystemFileName.getLength() > MAX_PATH)
1925         return false;
1926 
1927     // this uses the Boost ini parser, instead of tools::Config, as we already use it to read other
1928     // values from bootstrap.ini in desktop/win32/source/loader.cxx, because that watchdog process
1929     // can't access LO libs. This way the handling is consistent.
1930     try
1931     {
1932         boost::property_tree::ptree pt;
1933         std::ifstream aFile(o3tl::toW(aSystemFileName.getStr()));
1934         boost::property_tree::ini_parser::read_ini(aFile, pt);
1935         const bool bEnabled = pt.get("Win32.EnableAttachThreadInputHack", false);
1936         SAL_WARN_IF(bEnabled, "vcl", "AttachThreadInput hack is enabled. Watch out for deadlocks!");
1937         return bEnabled;
1938     }
1939     catch (...)
1940     {
1941         return false;
1942     }
1943 }
1944 
1945 static void ImplSalToTop( HWND hWnd, SalFrameToTop nFlags )
1946 {
1947     static const bool bEnableAttachThreadInputHack = EnableAttachThreadInputHack();
1948 
1949     WinSalFrame* pToTopFrame = GetWindowPtr( hWnd );
1950     if( pToTopFrame && (pToTopFrame->mnStyle & SalFrameStyleFlags::SYSTEMCHILD) )
1951         BringWindowToTop( hWnd );
1952 
1953     if ( nFlags & SalFrameToTop::ForegroundTask )
1954     {
1955         // LO used to always call AttachThreadInput here, which resulted in deadlocks
1956         // in some installations for unknown reasons!
1957         if (bEnableAttachThreadInputHack)
1958         {
1959             // This magic code is necessary to connect the input focus of the
1960             // current window thread and the thread which owns the window that
1961             // should be the new foreground window.
1962             HWND hCurrWnd = GetForegroundWindow();
1963             DWORD myThreadID = GetCurrentThreadId();
1964             DWORD currThreadID = GetWindowThreadProcessId(hCurrWnd,nullptr);
1965             AttachThreadInput(myThreadID, currThreadID, TRUE);
1966             SetForegroundWindow_Impl(hWnd);
1967             AttachThreadInput(myThreadID, currThreadID, FALSE);
1968         }
1969         else
1970             SetForegroundWindow_Impl(hWnd);
1971     }
1972 
1973     if ( nFlags & SalFrameToTop::RestoreWhenMin )
1974     {
1975         HWND hIconicWnd = hWnd;
1976         while ( hIconicWnd )
1977         {
1978             if ( IsIconic( hIconicWnd ) )
1979             {
1980                 WinSalFrame* pFrame = GetWindowPtr( hIconicWnd );
1981                 if ( pFrame )
1982                 {
1983                     if ( GetWindowPtr( hWnd )->mbRestoreMaximize )
1984                         ShowWindow( hIconicWnd, SW_MAXIMIZE );
1985                     else
1986                         ShowWindow( hIconicWnd, SW_RESTORE );
1987                 }
1988                 else
1989                     ShowWindow( hIconicWnd, SW_RESTORE );
1990             }
1991 
1992             hIconicWnd = ::GetParent( hIconicWnd );
1993         }
1994     }
1995 
1996     if ( !IsIconic( hWnd ) && IsWindowVisible( hWnd ) )
1997     {
1998         SetFocus( hWnd );
1999 
2000         // Windows sometimes incorrectly reports to have the focus;
2001         // thus make sure to really get the focus
2002         if ( ::GetFocus() == hWnd )
2003             SetForegroundWindow_Impl( hWnd );
2004     }
2005 }
2006 
2007 void WinSalFrame::ToTop( SalFrameToTop nFlags )
2008 {
2009     nFlags &= ~SalFrameToTop::GrabFocus;   // this flag is not needed on win32
2010     // Post this Message to the window, because this only works
2011     // in the thread of the window, which has create this window.
2012     // We post this message to avoid deadlocks
2013     if ( GetSalData()->mnAppThreadId != GetCurrentThreadId() )
2014     {
2015         bool const ret = PostMessageW( mhWnd, SAL_MSG_TOTOP, static_cast<WPARAM>(nFlags), 0 );
2016         SAL_WARN_IF(!ret, "vcl", "ERROR: PostMessage() failed!");
2017     }
2018     else
2019         ImplSalToTop( mhWnd, nFlags );
2020 }
2021 
2022 void WinSalFrame::SetPointer( PointerStyle ePointerStyle )
2023 {
2024     struct ImplPtrData
2025     {
2026         HCURSOR         mhCursor;
2027         LPCTSTR         mnSysId;
2028         UINT            mnOwnId;
2029     };
2030 
2031     static o3tl::enumarray<PointerStyle, ImplPtrData> aImplPtrTab =
2032     {
2033     // [-loplugin:redundantfcast]:
2034     ImplPtrData{ nullptr, IDC_ARROW, 0 },                       // POINTER_ARROW
2035     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_NULL },    // POINTER_NULL
2036     ImplPtrData{ nullptr, IDC_WAIT, 0 },                        // POINTER_WAIT
2037     ImplPtrData{ nullptr, IDC_IBEAM, 0 },                       // POINTER_TEXT
2038     ImplPtrData{ nullptr, IDC_HELP, 0 },                        // POINTER_HELP
2039     ImplPtrData{ nullptr, IDC_CROSS, 0 },                       // POINTER_CROSS
2040     ImplPtrData{ nullptr, IDC_SIZEALL, 0 },                     // POINTER_MOVE
2041     ImplPtrData{ nullptr, IDC_SIZENS, 0 },                      // POINTER_NSIZE
2042     ImplPtrData{ nullptr, IDC_SIZENS, 0 },                      // POINTER_SSIZE
2043     ImplPtrData{ nullptr, IDC_SIZEWE, 0 },                      // POINTER_WSIZE
2044     ImplPtrData{ nullptr, IDC_SIZEWE, 0 },                      // POINTER_ESIZE
2045     ImplPtrData{ nullptr, IDC_SIZENWSE, 0 },                    // POINTER_NWSIZE
2046     ImplPtrData{ nullptr, IDC_SIZENESW, 0 },                    // POINTER_NESIZE
2047     ImplPtrData{ nullptr, IDC_SIZENESW, 0 },                    // POINTER_SWSIZE
2048     ImplPtrData{ nullptr, IDC_SIZENWSE, 0 },                    // POINTER_SESIZE
2049     ImplPtrData{ nullptr, IDC_SIZENS, 0 },                      // POINTER_WINDOW_NSIZE
2050     ImplPtrData{ nullptr, IDC_SIZENS, 0 },                      // POINTER_WINDOW_SSIZE
2051     ImplPtrData{ nullptr, IDC_SIZEWE, 0 },                      // POINTER_WINDOW_WSIZE
2052     ImplPtrData{ nullptr, IDC_SIZEWE, 0 },                      // POINTER_WINDOW_ESIZE
2053     ImplPtrData{ nullptr, IDC_SIZENWSE, 0 },                    // POINTER_WINDOW_NWSIZE
2054     ImplPtrData{ nullptr, IDC_SIZENESW, 0 },                    // POINTER_WINDOW_NESIZE
2055     ImplPtrData{ nullptr, IDC_SIZENESW, 0 },                    // POINTER_WINDOW_SWSIZE
2056     ImplPtrData{ nullptr, IDC_SIZENWSE, 0 },                    // POINTER_WINDOW_SESIZE
2057     ImplPtrData{ nullptr, IDC_SIZEWE, 0 },                      // POINTER_HSPLIT
2058     ImplPtrData{ nullptr, IDC_SIZENS, 0 },                      // POINTER_VSPLIT
2059     ImplPtrData{ nullptr, IDC_SIZEWE, 0 },                      // POINTER_HSIZEBAR
2060     ImplPtrData{ nullptr, IDC_SIZENS, 0 },                      // POINTER_VSIZEBAR
2061     ImplPtrData{ nullptr, IDC_HAND, 0 },                        // POINTER_HAND
2062     ImplPtrData{ nullptr, IDC_HAND, 0 },                        // POINTER_REFHAND
2063     ImplPtrData{ nullptr, IDC_PEN, 0 },                         // POINTER_PEN
2064     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_MAGNIFY }, // POINTER_MAGNIFY
2065     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_FILL },    // POINTER_FILL
2066     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_ROTATE },  // POINTER_ROTATE
2067     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_HSHEAR },  // POINTER_HSHEAR
2068     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_VSHEAR },  // POINTER_VSHEAR
2069     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_MIRROR },  // POINTER_MIRROR
2070     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_CROOK },   // POINTER_CROOK
2071     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_CROP },    // POINTER_CROP
2072     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_MOVEPOINT }, // POINTER_MOVEPOINT
2073     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_MOVEBEZIERWEIGHT }, // POINTER_MOVEBEZIERWEIGHT
2074     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_MOVEDATA }, // POINTER_MOVEDATA
2075     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_COPYDATA }, // POINTER_COPYDATA
2076     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_LINKDATA }, // POINTER_LINKDATA
2077     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_MOVEDATALINK }, // POINTER_MOVEDATALINK
2078     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_COPYDATALINK }, // POINTER_COPYDATALINK
2079     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_MOVEFILE }, // POINTER_MOVEFILE
2080     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_COPYFILE }, // POINTER_COPYFILE
2081     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_LINKFILE }, // POINTER_LINKFILE
2082     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_MOVEFILELINK }, // POINTER_MOVEFILELINK
2083     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_COPYFILELINK }, // POINTER_COPYFILELINK
2084     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_MOVEFILES }, // POINTER_MOVEFILES
2085     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_COPYFILES }, // POINTER_COPYFILES
2086     ImplPtrData{ nullptr, IDC_NO, 0 },                          // POINTER_NOTALLOWED
2087     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DRAW_LINE }, // POINTER_DRAW_LINE
2088     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DRAW_RECT }, // POINTER_DRAW_RECT
2089     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DRAW_POLYGON }, // POINTER_DRAW_POLYGON
2090     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DRAW_BEZIER }, // POINTER_DRAW_BEZIER
2091     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DRAW_ARC }, // POINTER_DRAW_ARC
2092     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DRAW_PIE }, // POINTER_DRAW_PIE
2093     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DRAW_CIRCLECUT }, // POINTER_DRAW_CIRCLECUT
2094     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DRAW_ELLIPSE }, // POINTER_DRAW_ELLIPSE
2095     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DRAW_FREEHAND }, // POINTER_DRAW_FREEHAND
2096     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DRAW_CONNECT }, // POINTER_DRAW_CONNECT
2097     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DRAW_TEXT }, // POINTER_DRAW_TEXT
2098     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DRAW_CAPTION }, // POINTER_DRAW_CAPTION
2099     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_CHART },   // POINTER_CHART
2100     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DETECTIVE }, // POINTER_DETECTIVE
2101     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_PIVOT_COL }, // POINTER_PIVOT_COL
2102     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_PIVOT_ROW }, // POINTER_PIVOT_ROW
2103     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_PIVOT_FIELD }, // POINTER_PIVOT_FIELD
2104     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_CHAIN },   // POINTER_CHAIN
2105     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_CHAIN_NOTALLOWED }, // POINTER_CHAIN_NOTALLOWED
2106     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_N }, // POINTER_AUTOSCROLL_N
2107     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_S }, // POINTER_AUTOSCROLL_S
2108     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_W }, // POINTER_AUTOSCROLL_W
2109     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_E }, // POINTER_AUTOSCROLL_E
2110     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_NW }, // POINTER_AUTOSCROLL_NW
2111     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_NE }, // POINTER_AUTOSCROLL_NE
2112     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_SW }, // POINTER_AUTOSCROLL_SW
2113     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_SE }, // POINTER_AUTOSCROLL_SE
2114     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_NS }, // POINTER_AUTOSCROLL_NS
2115     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_WE }, // POINTER_AUTOSCROLL_WE
2116     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_NSWE }, // POINTER_AUTOSCROLL_NSWE
2117     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_TEXT_VERTICAL }, // POINTER_TEXT_VERTICAL
2118     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_PIVOT_DELETE }, // POINTER_PIVOT_DELETE
2119 
2120      // #i32329#
2121     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_TAB_SELECT_S }, // POINTER_TAB_SELECT_S
2122     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_TAB_SELECT_E }, // POINTER_TAB_SELECT_E
2123     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_TAB_SELECT_SE }, // POINTER_TAB_SELECT_SE
2124     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_TAB_SELECT_W }, // POINTER_TAB_SELECT_W
2125     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_TAB_SELECT_SW }, // POINTER_TAB_SELECT_SW
2126 
2127     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_HIDEWHITESPACE }, // POINTER_HIDEWHITESPACE
2128     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_SHOWWHITESPACE }, // POINTER_UNHIDEWHITESPACE
2129 
2130     ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_FATCROSS } // POINTER_FATCROSS
2131     };
2132 
2133     // Mousepointer loaded ?
2134     if ( !aImplPtrTab[ePointerStyle].mhCursor )
2135     {
2136         if ( aImplPtrTab[ePointerStyle].mnOwnId )
2137             aImplPtrTab[ePointerStyle].mhCursor = ImplLoadSalCursor( aImplPtrTab[ePointerStyle].mnOwnId );
2138         else
2139             aImplPtrTab[ePointerStyle].mhCursor = LoadCursor( nullptr, aImplPtrTab[ePointerStyle].mnSysId );
2140     }
2141 
2142     // change the mouse pointer if different
2143     if ( mhCursor != aImplPtrTab[ePointerStyle].mhCursor )
2144     {
2145         mhCursor = aImplPtrTab[ePointerStyle].mhCursor;
2146         SetCursor( mhCursor );
2147     }
2148 }
2149 
2150 void WinSalFrame::CaptureMouse( bool bCapture )
2151 {
2152     // Send this Message to the window, because CaptureMouse() only work
2153     // in the thread of the window, which has create this window
2154     int nMsg;
2155     if ( bCapture )
2156         nMsg = SAL_MSG_CAPTUREMOUSE;
2157     else
2158         nMsg = SAL_MSG_RELEASEMOUSE;
2159     SendMessageW( mhWnd, nMsg, 0, 0 );
2160 }
2161 
2162 void WinSalFrame::SetPointerPos( tools::Long nX, tools::Long nY )
2163 {
2164     POINT aPt;
2165     aPt.x = static_cast<int>(nX);
2166     aPt.y = static_cast<int>(nY);
2167     ClientToScreen( mhWnd, &aPt );
2168     SetCursorPos( aPt.x, aPt.y );
2169 }
2170 
2171 void WinSalFrame::Flush()
2172 {
2173     if(mpLocalGraphics)
2174         mpLocalGraphics->Flush();
2175     if(mpThreadGraphics)
2176         mpThreadGraphics->Flush();
2177     GdiFlush();
2178 }
2179 
2180 static void ImplSalFrameSetInputContext( HWND hWnd, const SalInputContext* pContext )
2181 {
2182     WinSalFrame*   pFrame = GetWindowPtr( hWnd );
2183     bool           bIME(pContext->mnOptions & InputContextFlags::Text);
2184     if ( bIME )
2185     {
2186         if ( !pFrame->mbIME )
2187         {
2188             pFrame->mbIME = true;
2189 
2190             if ( pFrame->mhDefIMEContext )
2191             {
2192                 ImmAssociateContext( pFrame->mhWnd, pFrame->mhDefIMEContext );
2193                 UINT nImeProps = ImmGetProperty( GetKeyboardLayout( 0 ), IGP_PROPERTY );
2194                 pFrame->mbSpezIME = (nImeProps & IME_PROP_SPECIAL_UI) != 0;
2195                 pFrame->mbAtCursorIME = (nImeProps & IME_PROP_AT_CARET) != 0;
2196                 pFrame->mbHandleIME = !pFrame->mbSpezIME;
2197             }
2198         }
2199 
2200         // When the application can't handle IME messages, then the
2201         // System should handle the IME handling
2202         if ( !(pContext->mnOptions & InputContextFlags::ExtText) )
2203             pFrame->mbHandleIME = false;
2204 
2205         // Set the Font for IME Handling
2206         if ( pContext->mpFont )
2207         {
2208             HIMC hIMC = ImmGetContext( pFrame->mhWnd );
2209             if ( hIMC )
2210             {
2211                 LOGFONTW aLogFont;
2212                 ImplGetLogFontFromFontSelect(pContext->mpFont->GetFontSelectPattern(),
2213                                              nullptr, aLogFont);
2214                 ImmSetCompositionFontW( hIMC, &aLogFont );
2215                 ImmReleaseContext( pFrame->mhWnd, hIMC );
2216             }
2217         }
2218     }
2219     else
2220     {
2221         if ( pFrame->mbIME )
2222         {
2223             pFrame->mbIME = false;
2224             pFrame->mbHandleIME = false;
2225             ImmAssociateContext( pFrame->mhWnd, nullptr );
2226         }
2227     }
2228 }
2229 
2230 void WinSalFrame::SetInputContext( SalInputContext* pContext )
2231 {
2232     // Must be called in the main thread!
2233     SendMessageW( mhWnd, SAL_MSG_SETINPUTCONTEXT, 0, reinterpret_cast<LPARAM>(pContext) );
2234 }
2235 
2236 static void ImplSalFrameEndExtTextInput( HWND hWnd, EndExtTextInputFlags nFlags )
2237 {
2238     HIMC hIMC = ImmGetContext( hWnd );
2239     if ( hIMC )
2240     {
2241         DWORD nIndex;
2242         if ( nFlags & EndExtTextInputFlags::Complete )
2243             nIndex = CPS_COMPLETE;
2244         else
2245             nIndex = CPS_CANCEL;
2246 
2247         ImmNotifyIME( hIMC, NI_COMPOSITIONSTR, nIndex, 0 );
2248         ImmReleaseContext( hWnd, hIMC );
2249     }
2250 }
2251 
2252 void WinSalFrame::EndExtTextInput( EndExtTextInputFlags nFlags )
2253 {
2254     // Must be called in the main thread!
2255     SendMessageW( mhWnd, SAL_MSG_ENDEXTTEXTINPUT, static_cast<WPARAM>(nFlags), 0 );
2256 }
2257 
2258 static void ImplGetKeyNameText( LONG lParam, sal_Unicode* pBuf,
2259                                 UINT& rCount, UINT nMaxSize,
2260                                 const char* pReplace )
2261 {
2262     static_assert( sizeof( WCHAR ) == sizeof( sal_Unicode ), "must be the same size" );
2263 
2264     static const int nMaxKeyLen = 350;
2265     WCHAR aKeyBuf[ nMaxKeyLen ];
2266     int nKeyLen = 0;
2267     if ( lParam )
2268     {
2269         OUString aLang = Application::GetSettings().GetUILanguageTag().getLanguage();
2270         OUString aRet;
2271 
2272         aRet = ::vcl_sal::getKeysReplacementName( aLang, lParam );
2273         if( aRet.isEmpty() )
2274         {
2275             nKeyLen = GetKeyNameTextW( lParam, aKeyBuf, nMaxKeyLen );
2276             SAL_WARN_IF( nKeyLen > nMaxKeyLen, "vcl", "Invalid key name length!" );
2277             if( nKeyLen > nMaxKeyLen )
2278                 nKeyLen = 0;
2279             else if( nKeyLen > 0 )
2280             {
2281                 // Capitalize just the first letter of key names
2282                 CharLowerBuffW( aKeyBuf, nKeyLen );
2283 
2284                 bool bUpper = true;
2285                 for( WCHAR *pW=aKeyBuf, *pE=pW+nKeyLen; pW < pE; ++pW )
2286                 {
2287                     if( bUpper )
2288                         CharUpperBuffW( pW, 1 );
2289                     bUpper = (*pW=='+') || (*pW=='-') || (*pW==' ') || (*pW=='.');
2290                 }
2291             }
2292         }
2293         else
2294         {
2295             nKeyLen = aRet.getLength();
2296             wcscpy( aKeyBuf, o3tl::toW( aRet.getStr() ));
2297         }
2298     }
2299 
2300     if ( (nKeyLen > 0) || pReplace )
2301     {
2302         if( (rCount > 0) && (rCount < nMaxSize) )
2303         {
2304             pBuf[rCount] = '+';
2305             rCount++;
2306         }
2307 
2308         if( nKeyLen > 0 )
2309         {
2310             WCHAR *pW = aKeyBuf, *pE = aKeyBuf + nKeyLen;
2311             while ((pW < pE) && *pW && (rCount < nMaxSize))
2312                 pBuf[rCount++] = *pW++;
2313         }
2314         else // fall back to provided default name
2315         {
2316             while( *pReplace && (rCount < nMaxSize) )
2317             {
2318                 pBuf[rCount] = *pReplace;
2319                 rCount++;
2320                 pReplace++;
2321             }
2322         }
2323     }
2324     else
2325         rCount = 0;
2326 }
2327 
2328 OUString WinSalFrame::GetKeyName( sal_uInt16 nKeyCode )
2329 {
2330     static const UINT nMaxKeyLen = 350;
2331     sal_Unicode aKeyBuf[ nMaxKeyLen ];
2332     UINT        nKeyBufLen = 0;
2333     UINT        nSysCode = 0;
2334 
2335     if ( nKeyCode & KEY_MOD1 )
2336     {
2337         nSysCode = MapVirtualKeyW( VK_CONTROL, 0 );
2338         nSysCode = (nSysCode << 16) | ((sal_uLong(1)) << 25);
2339         ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, "Ctrl" );
2340     }
2341 
2342     if ( nKeyCode & KEY_MOD2 )
2343     {
2344         nSysCode = MapVirtualKeyW( VK_MENU, 0 );
2345         nSysCode = (nSysCode << 16) | ((sal_uLong(1)) << 25);
2346         ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, "Alt" );
2347     }
2348 
2349     if ( nKeyCode & KEY_SHIFT )
2350     {
2351         nSysCode = MapVirtualKeyW( VK_SHIFT, 0 );
2352         nSysCode = (nSysCode << 16) | ((sal_uLong(1)) << 25);
2353         ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, "Shift" );
2354     }
2355 
2356     sal_uInt16      nCode = nKeyCode & 0x0FFF;
2357     sal_uLong       nSysCode2 = 0;
2358     const char*   pReplace = nullptr;
2359     sal_Unicode cSVCode = 0;
2360     char    aFBuf[4];
2361     nSysCode = 0;
2362 
2363     if ( (nCode >= KEY_0) && (nCode <= KEY_9) )
2364         cSVCode = '0' + (nCode - KEY_0);
2365     else if ( (nCode >= KEY_A) && (nCode <= KEY_Z) )
2366         cSVCode = 'A' + (nCode - KEY_A);
2367     else if ( (nCode >= KEY_F1) && (nCode <= KEY_F26) )
2368     {
2369         nSysCode = VK_F1 + (nCode - KEY_F1);
2370         aFBuf[0] = 'F';
2371         if (nCode <= KEY_F9)
2372         {
2373             aFBuf[1] = sal::static_int_cast<char>('1' + (nCode - KEY_F1));
2374             aFBuf[2] = 0;
2375         }
2376         else if (nCode <= KEY_F19)
2377         {
2378             aFBuf[1] = '1';
2379             aFBuf[2] = sal::static_int_cast<char>('0' + (nCode - KEY_F10));
2380             aFBuf[3] = 0;
2381         }
2382         else
2383         {
2384             aFBuf[1] = '2';
2385             aFBuf[2] = sal::static_int_cast<char>('0' + (nCode - KEY_F20));
2386             aFBuf[3] = 0;
2387         }
2388         pReplace = aFBuf;
2389     }
2390     else
2391     {
2392         switch ( nCode )
2393         {
2394             case KEY_DOWN:
2395                 nSysCode = VK_DOWN;
2396                 nSysCode2 = ((sal_uLong(1)) << 24);
2397                 pReplace = "Down";
2398                 break;
2399             case KEY_UP:
2400                 nSysCode = VK_UP;
2401                 nSysCode2 = ((sal_uLong(1)) << 24);
2402                 pReplace = "Up";
2403                 break;
2404             case KEY_LEFT:
2405                 nSysCode = VK_LEFT;
2406                 nSysCode2 = ((sal_uLong(1)) << 24);
2407                 pReplace = "Left";
2408                 break;
2409             case KEY_RIGHT:
2410                 nSysCode = VK_RIGHT;
2411                 nSysCode2 = ((sal_uLong(1)) << 24);
2412                 pReplace = "Right";
2413                 break;
2414             case KEY_HOME:
2415                 nSysCode = VK_HOME;
2416                 nSysCode2 = ((sal_uLong(1)) << 24);
2417                 pReplace = "Home";
2418                 break;
2419             case KEY_END:
2420                 nSysCode = VK_END;
2421                 nSysCode2 = ((sal_uLong(1)) << 24);
2422                 pReplace = "End";
2423                 break;
2424             case KEY_PAGEUP:
2425                 nSysCode = VK_PRIOR;
2426                 nSysCode2 = ((sal_uLong(1)) << 24);
2427                 pReplace = "Page Up";
2428                 break;
2429             case KEY_PAGEDOWN:
2430                 nSysCode = VK_NEXT;
2431                 nSysCode2 = ((sal_uLong(1)) << 24);
2432                 pReplace = "Page Down";
2433                 break;
2434             case KEY_RETURN:
2435                 nSysCode = VK_RETURN;
2436                 pReplace = "Enter";
2437                 break;
2438             case KEY_ESCAPE:
2439                 nSysCode = VK_ESCAPE;
2440                 pReplace = "Escape";
2441                 break;
2442             case KEY_TAB:
2443                 nSysCode = VK_TAB;
2444                 pReplace = "Tab";
2445                 break;
2446             case KEY_BACKSPACE:
2447                 nSysCode = VK_BACK;
2448                 pReplace = "Backspace";
2449                 break;
2450             case KEY_SPACE:
2451                 nSysCode = VK_SPACE;
2452                 pReplace = "Space";
2453                 break;
2454             case KEY_INSERT:
2455                 nSysCode = VK_INSERT;
2456                 nSysCode2 = ((sal_uLong(1)) << 24);
2457                 pReplace = "Insert";
2458                 break;
2459             case KEY_DELETE:
2460                 nSysCode = VK_DELETE;
2461                 nSysCode2 = ((sal_uLong(1)) << 24);
2462                 pReplace = "Delete";
2463                 break;
2464 
2465             case KEY_ADD:
2466                 cSVCode  = '+';
2467                 break;
2468             case KEY_SUBTRACT:
2469                 cSVCode  = '-';
2470                 break;
2471             case KEY_MULTIPLY:
2472                 cSVCode  = '*';
2473                 break;
2474             case KEY_DIVIDE:
2475                 cSVCode  = '/';
2476                 break;
2477             case KEY_POINT:
2478                 cSVCode  = '.';
2479                 break;
2480             case KEY_COMMA:
2481                 cSVCode  = ',';
2482                 break;
2483             case KEY_LESS:
2484                 cSVCode  = '<';
2485                 break;
2486             case KEY_GREATER:
2487                 cSVCode  = '>';
2488                 break;
2489             case KEY_EQUAL:
2490                 cSVCode  = '=';
2491                 break;
2492             case KEY_SEMICOLON:
2493                 cSVCode = ';';
2494                 break;
2495             case KEY_QUOTERIGHT:
2496                 cSVCode = '\'';
2497                 break;
2498             case KEY_BRACKETLEFT:
2499                 cSVCode = '[';
2500                 break;
2501             case KEY_BRACKETRIGHT:
2502                 cSVCode = ']';
2503                 break;
2504             case KEY_QUOTELEFT:
2505                 cSVCode = '`';
2506                 break;
2507             case KEY_RIGHTCURLYBRACKET:
2508                 cSVCode = '}';
2509                 break;
2510         }
2511     }
2512 
2513     if ( nSysCode )
2514     {
2515         nSysCode = MapVirtualKeyW( nSysCode, 0 );
2516         if ( nSysCode )
2517             nSysCode = (nSysCode << 16) | nSysCode2;
2518         ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, pReplace );
2519     }
2520     else
2521     {
2522         if ( cSVCode )
2523         {
2524             if ( nKeyBufLen > 0 )
2525                 aKeyBuf[ nKeyBufLen++ ] = '+';
2526             if( nKeyBufLen < nMaxKeyLen )
2527                 aKeyBuf[ nKeyBufLen++ ] = cSVCode;
2528         }
2529     }
2530 
2531     if( !nKeyBufLen )
2532         return OUString();
2533 
2534     return OUString( aKeyBuf, sal::static_int_cast< sal_uInt16 >(nKeyBufLen) );
2535 }
2536 
2537 static Color ImplWinColorToSal( COLORREF nColor )
2538 {
2539     return Color( GetRValue( nColor ), GetGValue( nColor ), GetBValue( nColor ) );
2540 }
2541 
2542 static void ImplSalUpdateStyleFontW( HDC hDC, const LOGFONTW& rLogFont, vcl::Font& rFont )
2543 {
2544     ImplSalLogFontToFontW( hDC, rLogFont, rFont );
2545 
2546     // On Windows 9x, Windows NT we get sometimes very small sizes
2547     // (for example for the small Caption height).
2548     // So if it is MS Sans Serif, a none scalable font we use
2549     // 8 Point as the minimum control height, in all other cases
2550     // 6 Point is the smallest one
2551     if ( rFont.GetFontHeight() < 8 )
2552     {
2553         if ( rtl_ustr_compareIgnoreAsciiCase( o3tl::toU(rLogFont.lfFaceName), o3tl::toU(L"MS Sans Serif") ) == 0 )
2554             rFont.SetFontHeight( 8 );
2555         else if ( rFont.GetFontHeight() < 6 )
2556             rFont.SetFontHeight( 6 );
2557     }
2558 }
2559 
2560 static tools::Long ImplW2I( const wchar_t* pStr )
2561 {
2562     tools::Long n = 0;
2563     int     nSign = 1;
2564 
2565     if ( *pStr == '-' )
2566     {
2567         nSign = -1;
2568         pStr++;
2569     }
2570 
2571     while( (*pStr >= 48) && (*pStr <= 57) )
2572     {
2573         n *= 10;
2574         n += ((*pStr) - 48);
2575         pStr++;
2576     }
2577 
2578     n *= nSign;
2579 
2580     return n;
2581 }
2582 
2583 void WinSalFrame::UpdateSettings( AllSettings& rSettings )
2584 {
2585     MouseSettings aMouseSettings = rSettings.GetMouseSettings();
2586     aMouseSettings.SetDoubleClickTime( GetDoubleClickTime() );
2587     aMouseSettings.SetDoubleClickWidth( GetSystemMetrics( SM_CXDOUBLECLK ) );
2588     aMouseSettings.SetDoubleClickHeight( GetSystemMetrics( SM_CYDOUBLECLK ) );
2589     tools::Long nDragWidth = GetSystemMetrics( SM_CXDRAG );
2590     tools::Long nDragHeight = GetSystemMetrics( SM_CYDRAG );
2591     if ( nDragWidth )
2592         aMouseSettings.SetStartDragWidth( nDragWidth );
2593     if ( nDragHeight )
2594         aMouseSettings.SetStartDragHeight( nDragHeight );
2595     HKEY hRegKey;
2596     if ( RegOpenKeyW( HKEY_CURRENT_USER,
2597                       L"Control Panel\\Desktop",
2598                       &hRegKey ) == ERROR_SUCCESS )
2599     {
2600         wchar_t aValueBuf[10];
2601         DWORD   nValueSize = sizeof( aValueBuf );
2602         DWORD   nType;
2603         if ( RegQueryValueExW( hRegKey, L"MenuShowDelay", nullptr,
2604                                &nType, reinterpret_cast<LPBYTE>(aValueBuf), &nValueSize ) == ERROR_SUCCESS )
2605         {
2606             if ( nType == REG_SZ )
2607                 aMouseSettings.SetMenuDelay( static_cast<sal_uLong>(ImplW2I( aValueBuf )) );
2608         }
2609 
2610         RegCloseKey( hRegKey );
2611     }
2612 
2613     StyleSettings aStyleSettings = rSettings.GetStyleSettings();
2614 
2615     // High contrast
2616     HIGHCONTRAST hc;
2617     hc.cbSize = sizeof( HIGHCONTRAST );
2618     if( SystemParametersInfoW( SPI_GETHIGHCONTRAST, hc.cbSize, &hc, 0 )
2619             && (hc.dwFlags & HCF_HIGHCONTRASTON) )
2620         aStyleSettings.SetHighContrastMode( true );
2621     else
2622         aStyleSettings.SetHighContrastMode( false );
2623 
2624     aStyleSettings.SetScrollBarSize( GetSystemMetrics( SM_CXVSCROLL ) );
2625     aStyleSettings.SetSpinSize( GetSystemMetrics( SM_CXVSCROLL ) );
2626     UINT blinkTime = GetCaretBlinkTime();
2627     aStyleSettings.SetCursorBlinkTime(
2628         blinkTime == 0 || blinkTime == INFINITE // 0 indicates error
2629         ? STYLE_CURSOR_NOBLINKTIME : blinkTime );
2630     aStyleSettings.SetFloatTitleHeight( GetSystemMetrics( SM_CYSMCAPTION ) );
2631     aStyleSettings.SetTitleHeight( GetSystemMetrics( SM_CYCAPTION ) );
2632     aStyleSettings.SetActiveBorderColor( ImplWinColorToSal( GetSysColor( COLOR_ACTIVEBORDER ) ) );
2633     aStyleSettings.SetDeactiveBorderColor( ImplWinColorToSal( GetSysColor( COLOR_INACTIVEBORDER ) ) );
2634     aStyleSettings.SetDeactiveColor( ImplWinColorToSal( GetSysColor( COLOR_GRADIENTINACTIVECAPTION ) ) );
2635 
2636     Color aControlTextColor;
2637     Color aMenuBarTextColor;
2638     Color aMenuBarRolloverTextColor;
2639     Color aHighlightTextColor = ImplWinColorToSal(GetSysColor(COLOR_HIGHLIGHTTEXT));
2640 
2641     const bool bUseDarkMode(UseDarkMode());
2642 
2643     OUString sThemeName(!bUseDarkMode ? u"colibre" : u"colibre_dark");
2644     aStyleSettings.SetPreferredIconTheme(sThemeName, bUseDarkMode);
2645 
2646     if (bUseDarkMode)
2647     {
2648         SetWindowTheme(mhWnd, L"Explorer", nullptr);
2649 
2650         HTHEME hTheme = OpenThemeData(nullptr, L"ItemsView");
2651         COLORREF color;
2652         GetThemeColor(hTheme, 0, 0, TMT_FILLCOLOR, &color);
2653         aStyleSettings.SetFaceColor( ImplWinColorToSal( color ) );
2654         aStyleSettings.SetWindowColor( ImplWinColorToSal( color ) );
2655         GetThemeColor(hTheme, 0, 0, TMT_TEXTCOLOR, &color);
2656         aStyleSettings.SetWindowTextColor( ImplWinColorToSal( color ) );
2657         aStyleSettings.SetToolTextColor( ImplWinColorToSal( color ) );
2658         GetThemeColor(hTheme, 0, 0, TMT_SHADOWCOLOR, &color);
2659         aStyleSettings.SetShadowColor( ImplWinColorToSal( color ) );
2660         GetThemeColor(hTheme, 0, 0, TMT_DKSHADOW3D, &color);
2661         aStyleSettings.SetDarkShadowColor( ImplWinColorToSal( color ) );
2662         CloseThemeData(hTheme);
2663 
2664         hTheme = OpenThemeData(mhWnd, L"Button");
2665         GetThemeColor(hTheme, BP_PUSHBUTTON, PBS_NORMAL, TMT_TEXTCOLOR, &color);
2666         aControlTextColor = ImplWinColorToSal(color);
2667         GetThemeColor(hTheme, BP_CHECKBOX, PBS_NORMAL, TMT_TEXTCOLOR, &color);
2668         aStyleSettings.SetRadioCheckTextColor( ImplWinColorToSal( color ) );
2669         CloseThemeData(hTheme);
2670 
2671         SetWindowTheme(mhWnd, nullptr, nullptr);
2672 
2673         hTheme = OpenThemeData(mhWnd, L"Menu");
2674         GetThemeColor(hTheme, MENU_POPUPITEM, MBI_NORMAL, TMT_TEXTCOLOR, &color);
2675         aStyleSettings.SetMenuTextColor( ImplWinColorToSal( color ) );
2676         aMenuBarTextColor = ImplWinColorToSal( color );
2677         aMenuBarRolloverTextColor = ImplWinColorToSal( color );
2678         CloseThemeData(hTheme);
2679 
2680         aStyleSettings.SetActiveTabColor( aStyleSettings.GetWindowColor() );
2681         hTheme = OpenThemeData(mhWnd, L"Toolbar");
2682         GetThemeColor(hTheme, 0, 0, TMT_FILLCOLOR, &color);
2683         aStyleSettings.SetInactiveTabColor( ImplWinColorToSal( color ) );
2684         CloseThemeData(hTheme);
2685 
2686         // tdf#148448 pick a warning color more likely to be readable as a
2687         // background in a dark theme
2688         aStyleSettings.SetWarningColor(Color(0xf5, 0x79, 0x00));
2689     }
2690     else
2691     {
2692         aStyleSettings.SetFaceColor( ImplWinColorToSal( GetSysColor( COLOR_3DFACE ) ) );
2693         aStyleSettings.SetWindowColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOW ) ) );
2694         aStyleSettings.SetWindowTextColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOWTEXT ) ) );
2695         aStyleSettings.SetToolTextColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOWTEXT ) ) );
2696         aStyleSettings.SetShadowColor( ImplWinColorToSal( GetSysColor( COLOR_3DSHADOW ) ) );
2697         aStyleSettings.SetDarkShadowColor( ImplWinColorToSal( GetSysColor( COLOR_3DDKSHADOW ) ) );
2698         aControlTextColor = ImplWinColorToSal(GetSysColor(COLOR_BTNTEXT));
2699         aStyleSettings.SetRadioCheckTextColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOWTEXT ) ) );
2700         aStyleSettings.SetMenuTextColor( ImplWinColorToSal( GetSysColor( COLOR_MENUTEXT ) ) );
2701         aMenuBarTextColor = ImplWinColorToSal( GetSysColor( COLOR_MENUTEXT ) );
2702         aMenuBarRolloverTextColor = aHighlightTextColor;
2703         aStyleSettings.SetActiveTabColor( aStyleSettings.GetWindowColor() );
2704         aStyleSettings.SetInactiveTabColor( aStyleSettings.GetFaceColor() );
2705     }
2706 
2707     if ( std::optional<Color> aColor = aStyleSettings.GetPersonaMenuBarTextColor() )
2708     {
2709         aMenuBarTextColor = *aColor;
2710         aMenuBarRolloverTextColor = *aColor;
2711     }
2712 
2713     aStyleSettings.SetMenuBarTextColor( aMenuBarTextColor );
2714     aStyleSettings.SetMenuBarRolloverTextColor( aMenuBarRolloverTextColor );
2715 
2716     aStyleSettings.SetLightColor( ImplWinColorToSal( GetSysColor( COLOR_3DHILIGHT ) ) );
2717     aStyleSettings.SetLightBorderColor( ImplWinColorToSal( GetSysColor( COLOR_3DLIGHT ) ) );
2718     aStyleSettings.SetHelpColor( ImplWinColorToSal( GetSysColor( COLOR_INFOBK ) ) );
2719     aStyleSettings.SetHelpTextColor( ImplWinColorToSal( GetSysColor( COLOR_INFOTEXT ) ) );
2720 
2721     aStyleSettings.SetWorkspaceColor(aStyleSettings.GetFaceColor());
2722     aStyleSettings.SetDialogColor(aStyleSettings.GetFaceColor());
2723     aStyleSettings.SetDialogTextColor(aControlTextColor);
2724 
2725     Color aHighlightButtonTextColor = aStyleSettings.GetHighContrastMode() ?
2726         aHighlightTextColor : aControlTextColor;
2727 
2728     if (aStyleSettings.GetHighContrastMode())
2729     {
2730         Color aLinkColor(ImplWinColorToSal(GetSysColor(COLOR_HOTLIGHT)));
2731         aStyleSettings.SetLinkColor(aLinkColor);
2732         aStyleSettings.SetVisitedLinkColor(aLinkColor);
2733     }
2734 
2735     aStyleSettings.SetDefaultButtonTextColor(aHighlightButtonTextColor);
2736     aStyleSettings.SetButtonTextColor(aControlTextColor);
2737     aStyleSettings.SetDefaultActionButtonTextColor(aHighlightButtonTextColor);
2738     aStyleSettings.SetActionButtonTextColor(aControlTextColor);
2739     aStyleSettings.SetFlatButtonTextColor(aControlTextColor);
2740     aStyleSettings.SetDefaultButtonRolloverTextColor(aHighlightButtonTextColor);
2741     aStyleSettings.SetButtonRolloverTextColor(aHighlightButtonTextColor);
2742     aStyleSettings.SetDefaultActionButtonRolloverTextColor(aHighlightButtonTextColor);
2743     aStyleSettings.SetActionButtonRolloverTextColor(aHighlightButtonTextColor);
2744     aStyleSettings.SetFlatButtonRolloverTextColor(aHighlightButtonTextColor);
2745     aStyleSettings.SetDefaultButtonPressedRolloverTextColor(aControlTextColor);
2746     aStyleSettings.SetButtonPressedRolloverTextColor(aControlTextColor);
2747     aStyleSettings.SetDefaultActionButtonPressedRolloverTextColor(aControlTextColor);
2748     aStyleSettings.SetActionButtonPressedRolloverTextColor(aControlTextColor);
2749     aStyleSettings.SetFlatButtonPressedRolloverTextColor(aControlTextColor);
2750 
2751     aStyleSettings.SetTabTextColor(aControlTextColor);
2752     aStyleSettings.SetTabRolloverTextColor(aControlTextColor);
2753     aStyleSettings.SetTabHighlightTextColor(aControlTextColor);
2754 
2755     aStyleSettings.SetGroupTextColor( aStyleSettings.GetRadioCheckTextColor() );
2756     aStyleSettings.SetLabelTextColor( aStyleSettings.GetRadioCheckTextColor() );
2757     aStyleSettings.SetFieldColor( aStyleSettings.GetWindowColor() );
2758     aStyleSettings.SetListBoxWindowBackgroundColor( aStyleSettings.GetWindowColor() );
2759     aStyleSettings.SetFieldTextColor( aStyleSettings.GetWindowTextColor() );
2760     aStyleSettings.SetFieldRolloverTextColor( aStyleSettings.GetFieldTextColor() );
2761     aStyleSettings.SetListBoxWindowTextColor( aStyleSettings.GetFieldTextColor() );
2762     aStyleSettings.SetHighlightColor( ImplWinColorToSal( GetSysColor( COLOR_HIGHLIGHT ) ) );
2763     aStyleSettings.SetHighlightTextColor(aHighlightTextColor);
2764     aStyleSettings.SetListBoxWindowHighlightColor( aStyleSettings.GetHighlightColor() );
2765     aStyleSettings.SetListBoxWindowHighlightTextColor( aStyleSettings.GetHighlightTextColor() );
2766     aStyleSettings.SetMenuHighlightColor( aStyleSettings.GetHighlightColor() );
2767     aStyleSettings.SetMenuHighlightTextColor( aStyleSettings.GetHighlightTextColor() );
2768 
2769     ImplSVData* pSVData = ImplGetSVData();
2770     pSVData->maNWFData.mnMenuFormatBorderX = 0;
2771     pSVData->maNWFData.mnMenuFormatBorderY = 0;
2772     pSVData->maNWFData.maMenuBarHighlightTextColor = COL_TRANSPARENT;
2773     GetSalData()->mbThemeMenuSupport = false;
2774     aStyleSettings.SetMenuColor( ImplWinColorToSal( GetSysColor( COLOR_MENU ) ) );
2775     aStyleSettings.SetMenuBarColor( aStyleSettings.GetMenuColor() );
2776     aStyleSettings.SetMenuBarRolloverColor( aStyleSettings.GetHighlightColor() );
2777     aStyleSettings.SetMenuBorderColor( aStyleSettings.GetLightBorderColor() ); // overridden below for flat menus
2778     aStyleSettings.SetUseFlatBorders( false );
2779     aStyleSettings.SetUseFlatMenus( false );
2780     aStyleSettings.SetMenuBarHighlightTextColor(aStyleSettings.GetMenuHighlightTextColor());
2781     aStyleSettings.SetActiveColor( ImplWinColorToSal( GetSysColor( COLOR_ACTIVECAPTION ) ) );
2782     aStyleSettings.SetActiveTextColor( ImplWinColorToSal( GetSysColor( COLOR_CAPTIONTEXT ) ) );
2783     aStyleSettings.SetDeactiveColor( ImplWinColorToSal( GetSysColor( COLOR_INACTIVECAPTION ) ) );
2784     aStyleSettings.SetDeactiveTextColor( ImplWinColorToSal( GetSysColor( COLOR_INACTIVECAPTIONTEXT ) ) );
2785     BOOL bFlatMenus = FALSE;
2786     SystemParametersInfoW( SPI_GETFLATMENU, 0, &bFlatMenus, 0);
2787     if( bFlatMenus )
2788     {
2789         aStyleSettings.SetUseFlatMenus( true );
2790         aStyleSettings.SetMenuBarColor( ImplWinColorToSal( GetSysColor( COLOR_MENUBAR ) ) );
2791         aStyleSettings.SetMenuHighlightColor( ImplWinColorToSal( GetSysColor( COLOR_MENUHILIGHT ) ) );
2792         aStyleSettings.SetMenuBarRolloverColor( ImplWinColorToSal( GetSysColor( COLOR_MENUHILIGHT ) ) );
2793         aStyleSettings.SetMenuBorderColor( ImplWinColorToSal( GetSysColor( COLOR_3DSHADOW ) ) );
2794 
2795         // flat borders for our controls etc. as well in this mode (ie, no 3d borders)
2796         // this is not active in the classic style appearance
2797         aStyleSettings.SetUseFlatBorders( true );
2798     }
2799     aStyleSettings.SetCheckedColorSpecialCase( );
2800 
2801     // caret width
2802     DWORD nCaretWidth = 2;
2803     if( SystemParametersInfoW( SPI_GETCARETWIDTH, 0, &nCaretWidth, 0 ) )
2804         aStyleSettings.SetCursorSize( nCaretWidth );
2805 
2806     // Query Fonts
2807     vcl::Font    aMenuFont = aStyleSettings.GetMenuFont();
2808     vcl::Font    aTitleFont = aStyleSettings.GetTitleFont();
2809     vcl::Font    aFloatTitleFont = aStyleSettings.GetFloatTitleFont();
2810     vcl::Font    aHelpFont = aStyleSettings.GetHelpFont();
2811     vcl::Font    aAppFont = aStyleSettings.GetAppFont();
2812     vcl::Font    aIconFont = aStyleSettings.GetIconFont();
2813     HDC     hDC = GetDC( nullptr );
2814     NONCLIENTMETRICSW aNonClientMetrics;
2815     aNonClientMetrics.cbSize = sizeof( aNonClientMetrics );
2816     if ( SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, sizeof( aNonClientMetrics ), &aNonClientMetrics, 0 ) )
2817     {
2818         ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfMenuFont, aMenuFont );
2819         ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfCaptionFont, aTitleFont );
2820         ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfSmCaptionFont, aFloatTitleFont );
2821         ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfStatusFont, aHelpFont );
2822         ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfMessageFont, aAppFont );
2823 
2824         LOGFONTW aLogFont;
2825         if ( SystemParametersInfoW( SPI_GETICONTITLELOGFONT, 0, &aLogFont, 0 ) )
2826             ImplSalUpdateStyleFontW( hDC, aLogFont, aIconFont );
2827     }
2828 
2829     ReleaseDC( nullptr, hDC );
2830 
2831     aStyleSettings.SetToolbarIconSize(ToolbarIconSize::Large);
2832 
2833     aStyleSettings.BatchSetFonts( aAppFont, aAppFont );
2834 
2835     aStyleSettings.SetMenuFont( aMenuFont );
2836     aStyleSettings.SetTitleFont( aTitleFont );
2837     aStyleSettings.SetFloatTitleFont( aFloatTitleFont );
2838     aStyleSettings.SetHelpFont( aHelpFont );
2839     aStyleSettings.SetIconFont( aIconFont );
2840 
2841     if ( aAppFont.GetWeight() > WEIGHT_NORMAL )
2842         aAppFont.SetWeight( WEIGHT_NORMAL );
2843     aStyleSettings.SetToolFont( aAppFont );
2844     aStyleSettings.SetTabFont( aAppFont );
2845 
2846     BOOL bDragFull;
2847     if ( SystemParametersInfoW( SPI_GETDRAGFULLWINDOWS, 0, &bDragFull, 0 ) )
2848     {
2849         DragFullOptions nDragFullOptions = aStyleSettings.GetDragFullOptions();
2850         if ( bDragFull )
2851             nDragFullOptions |= DragFullOptions::WindowMove | DragFullOptions::WindowSize | DragFullOptions::Docking | DragFullOptions::Split;
2852         else
2853             nDragFullOptions &= ~DragFullOptions(DragFullOptions::WindowMove | DragFullOptions::WindowSize | DragFullOptions::Docking | DragFullOptions::Split);
2854         aStyleSettings.SetDragFullOptions( nDragFullOptions );
2855     }
2856 
2857     if ( RegOpenKeyW( HKEY_CURRENT_USER,
2858                       L"Control Panel\\International\\Calendars\\TwoDigitYearMax",
2859                       &hRegKey ) == ERROR_SUCCESS )
2860     {
2861         wchar_t aValueBuf[10];
2862         DWORD   nValue;
2863         DWORD   nValueSize = sizeof( aValueBuf );
2864         DWORD   nType;
2865         if ( RegQueryValueExW( hRegKey, L"1", nullptr,
2866                                &nType, reinterpret_cast<LPBYTE>(aValueBuf), &nValueSize ) == ERROR_SUCCESS )
2867         {
2868             if ( nType == REG_SZ )
2869             {
2870                 nValue = static_cast<sal_uLong>(ImplW2I( aValueBuf ));
2871                 if ( (nValue > 1000) && (nValue < 10000) )
2872                 {
2873                     std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
2874                     officecfg::Office::Common::DateFormat::TwoDigitYear::set(static_cast<sal_Int32>(nValue-99), batch);
2875                     batch->commit();
2876                 }
2877             }
2878         }
2879 
2880         RegCloseKey( hRegKey );
2881     }
2882 
2883     rSettings.SetMouseSettings( aMouseSettings );
2884     rSettings.SetStyleSettings( aStyleSettings );
2885 
2886     // now apply the values from theming, if available
2887     WinSalGraphics::updateSettingsNative( rSettings );
2888 }
2889 
2890 const SystemEnvData* WinSalFrame::GetSystemData() const
2891 {
2892     return &maSysData;
2893 }
2894 
2895 void WinSalFrame::Beep()
2896 {
2897     // a simple beep
2898     MessageBeep( 0 );
2899 }
2900 
2901 SalFrame::SalPointerState WinSalFrame::GetPointerState()
2902 {
2903     SalPointerState aState;
2904     aState.mnState = 0;
2905 
2906     if ( GetKeyState( VK_LBUTTON ) & 0x8000 )
2907         aState.mnState |= MOUSE_LEFT;
2908     if ( GetKeyState( VK_MBUTTON ) & 0x8000 )
2909         aState.mnState |= MOUSE_MIDDLE;
2910     if ( GetKeyState( VK_RBUTTON ) & 0x8000 )
2911         aState.mnState |= MOUSE_RIGHT;
2912     if ( GetKeyState( VK_SHIFT ) & 0x8000 )
2913         aState.mnState |= KEY_SHIFT;
2914     if ( GetKeyState( VK_CONTROL ) & 0x8000 )
2915         aState.mnState |= KEY_MOD1;
2916     if ( GetKeyState( VK_MENU ) & 0x8000 )
2917         aState.mnState |= KEY_MOD2;
2918 
2919     POINT pt;
2920     GetCursorPos( &pt );
2921 
2922     aState.maPos = Point(pt.x - maGeometry.x(), pt.y - maGeometry.y());
2923     return aState;
2924 }
2925 
2926 KeyIndicatorState WinSalFrame::GetIndicatorState()
2927 {
2928     KeyIndicatorState aState = KeyIndicatorState::NONE;
2929     if (::GetKeyState(VK_CAPITAL))
2930         aState |= KeyIndicatorState::CAPSLOCK;
2931 
2932     if (::GetKeyState(VK_NUMLOCK))
2933         aState |= KeyIndicatorState::NUMLOCK;
2934 
2935     if (::GetKeyState(VK_SCROLL))
2936         aState |= KeyIndicatorState::SCROLLLOCK;
2937 
2938     return aState;
2939 }
2940 
2941 void WinSalFrame::SimulateKeyPress( sal_uInt16 nKeyCode )
2942 {
2943     BYTE nVKey = 0;
2944     switch (nKeyCode)
2945     {
2946         case KEY_CAPSLOCK:
2947             nVKey = VK_CAPITAL;
2948         break;
2949     }
2950 
2951     if (nVKey > 0 && nVKey < 255)
2952     {
2953         ::keybd_event(nVKey, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
2954         ::keybd_event(nVKey, 0x45, KEYEVENTF_EXTENDEDKEY|KEYEVENTF_KEYUP, 0);
2955     }
2956 }
2957 
2958 void WinSalFrame::ResetClipRegion()
2959 {
2960     SetWindowRgn( mhWnd, nullptr, TRUE );
2961 }
2962 
2963 void WinSalFrame::BeginSetClipRegion( sal_uInt32 nRects )
2964 {
2965     if( mpClipRgnData )
2966         delete [] reinterpret_cast<BYTE*>(mpClipRgnData);
2967     sal_uLong nRectBufSize = sizeof(RECT)*nRects;
2968     mpClipRgnData = reinterpret_cast<RGNDATA*>(new BYTE[sizeof(RGNDATA)-1+nRectBufSize]);
2969     mpClipRgnData->rdh.dwSize     = sizeof( RGNDATAHEADER );
2970     mpClipRgnData->rdh.iType      = RDH_RECTANGLES;
2971     mpClipRgnData->rdh.nCount     = nRects;
2972     mpClipRgnData->rdh.nRgnSize  = nRectBufSize;
2973     SetRectEmpty( &(mpClipRgnData->rdh.rcBound) );
2974     mpNextClipRect        = reinterpret_cast<RECT*>(&(mpClipRgnData->Buffer));
2975     mbFirstClipRect       = true;
2976 }
2977 
2978 void WinSalFrame::UnionClipRegion( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight )
2979 {
2980     if( ! mpClipRgnData )
2981         return;
2982 
2983     RECT*       pRect = mpNextClipRect;
2984     RECT*       pBoundRect = &(mpClipRgnData->rdh.rcBound);
2985     tools::Long        nRight = nX + nWidth;
2986     tools::Long        nBottom = nY + nHeight;
2987 
2988     if ( mbFirstClipRect )
2989     {
2990         pBoundRect->left    = nX;
2991         pBoundRect->top     = nY;
2992         pBoundRect->right   = nRight;
2993         pBoundRect->bottom  = nBottom;
2994         mbFirstClipRect = false;
2995     }
2996     else
2997     {
2998         if ( nX < pBoundRect->left )
2999             pBoundRect->left = static_cast<int>(nX);
3000 
3001         if ( nY < pBoundRect->top )
3002             pBoundRect->top = static_cast<int>(nY);
3003 
3004         if ( nRight > pBoundRect->right )
3005             pBoundRect->right = static_cast<int>(nRight);
3006 
3007         if ( nBottom > pBoundRect->bottom )
3008             pBoundRect->bottom = static_cast<int>(nBottom);
3009     }
3010 
3011     pRect->left     = static_cast<int>(nX);
3012     pRect->top      = static_cast<int>(nY);
3013     pRect->right    = static_cast<int>(nRight);
3014     pRect->bottom   = static_cast<int>(nBottom);
3015     if( (mpNextClipRect  - reinterpret_cast<RECT*>(&mpClipRgnData->Buffer)) < static_cast<int>(mpClipRgnData->rdh.nCount) )
3016         mpNextClipRect++;
3017 }
3018 
3019 void WinSalFrame::EndSetClipRegion()
3020 {
3021     if( ! mpClipRgnData )
3022         return;
3023 
3024     HRGN hRegion;
3025 
3026     // create region from accumulated rectangles
3027     if ( mpClipRgnData->rdh.nCount == 1 )
3028     {
3029         RECT* pRect = &(mpClipRgnData->rdh.rcBound);
3030         hRegion = CreateRectRgn( pRect->left, pRect->top,
3031                                  pRect->right, pRect->bottom );
3032     }
3033     else
3034     {
3035         sal_uLong nSize = mpClipRgnData->rdh.nRgnSize+sizeof(RGNDATAHEADER);
3036         hRegion = ExtCreateRegion( nullptr, nSize, mpClipRgnData );
3037     }
3038     delete [] reinterpret_cast<BYTE*>(mpClipRgnData);
3039     mpClipRgnData = nullptr;
3040 
3041     SAL_WARN_IF( !hRegion, "vcl", "WinSalFrame::EndSetClipRegion() - Can't create ClipRegion" );
3042     if( hRegion )
3043     {
3044         RECT aWindowRect;
3045         GetWindowRect( mhWnd, &aWindowRect );
3046         POINT aPt;
3047         aPt.x=0;
3048         aPt.y=0;
3049         ClientToScreen( mhWnd, &aPt );
3050         OffsetRgn( hRegion, aPt.x - aWindowRect.left, aPt.y - aWindowRect.top );
3051 
3052         if( SetWindowRgn( mhWnd, hRegion, TRUE ) == 0 )
3053             DeleteObject( hRegion );
3054     }
3055 }
3056 
3057 static bool ImplHandleMouseMsg( HWND hWnd, UINT nMsg,
3058                                 WPARAM wParam, LPARAM lParam )
3059 {
3060     WinSalFrame* pFrame = GetWindowPtr( hWnd );
3061     if ( !pFrame )
3062         return false;
3063 
3064     if( nMsg == WM_LBUTTONDOWN || nMsg == WM_MBUTTONDOWN || nMsg == WM_RBUTTONDOWN )
3065     {
3066         // #103168# post again if async focus has not arrived yet
3067         // hopefully we will not receive the corresponding button up before this
3068         // button down arrives again
3069         vcl::Window *pWin = pFrame->GetWindow();
3070         if( pWin && pWin->ImplGetWindowImpl()->mpFrameData->mnFocusId )
3071         {
3072             bool const ret = PostMessageW( hWnd, nMsg, wParam, lParam );
3073             SAL_WARN_IF(!ret, "vcl", "ERROR: PostMessage() failed!");
3074             return true;
3075         }
3076     }
3077     SalMouseEvent   aMouseEvt;
3078     bool            nRet;
3079     SalEvent        nEvent = SalEvent::NONE;
3080     bool            bCall = true;
3081 
3082     aMouseEvt.mnX       = static_cast<short>(LOWORD( lParam ));
3083     aMouseEvt.mnY       = static_cast<short>(HIWORD( lParam ));
3084     aMouseEvt.mnCode    = 0;
3085     aMouseEvt.mnTime    = GetMessageTime();
3086 
3087     // Use GetKeyState(), as some Logitech mouse drivers do not check
3088     // KeyState when simulating double-click with center mouse button
3089 
3090     if ( GetKeyState( VK_LBUTTON ) & 0x8000 )
3091         aMouseEvt.mnCode |= MOUSE_LEFT;
3092     if ( GetKeyState( VK_MBUTTON ) & 0x8000 )
3093         aMouseEvt.mnCode |= MOUSE_MIDDLE;
3094     if ( GetKeyState( VK_RBUTTON ) & 0x8000 )
3095         aMouseEvt.mnCode |= MOUSE_RIGHT;
3096     if ( GetKeyState( VK_SHIFT ) & 0x8000 )
3097         aMouseEvt.mnCode |= KEY_SHIFT;
3098     if ( GetKeyState( VK_CONTROL ) & 0x8000 )
3099         aMouseEvt.mnCode |= KEY_MOD1;
3100     if ( GetKeyState( VK_MENU ) & 0x8000 )
3101         aMouseEvt.mnCode |= KEY_MOD2;
3102 
3103     switch ( nMsg )
3104     {
3105         case WM_MOUSEMOVE:
3106             {
3107             // As the mouse events are not collected correctly when
3108             // pressing modifier keys (as interrupted by KeyEvents)
3109             // we do this here ourselves
3110             if ( aMouseEvt.mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2) )
3111             {
3112                 MSG aTempMsg;
3113                 if ( PeekMessageW( &aTempMsg, hWnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE | PM_NOYIELD ) )
3114                 {
3115                     if ( (aTempMsg.message == WM_MOUSEMOVE) &&
3116                          (aTempMsg.wParam == wParam) )
3117                         return true;
3118                 }
3119             }
3120 
3121             SalData* pSalData = GetSalData();
3122             // Test for MouseLeave
3123             if ( pSalData->mhWantLeaveMsg && (pSalData->mhWantLeaveMsg != hWnd) )
3124                 SendMessageW( pSalData->mhWantLeaveMsg, SAL_MSG_MOUSELEAVE, 0, GetMessagePos() );
3125 
3126             pSalData->mhWantLeaveMsg = hWnd;
3127             // Start MouseLeave-Timer
3128             if ( !pSalData->mpMouseLeaveTimer )
3129             {
3130                 pSalData->mpMouseLeaveTimer = new AutoTimer( "ImplHandleMouseMsg SalData::mpMouseLeaveTimer" );
3131                 pSalData->mpMouseLeaveTimer->SetTimeout( SAL_MOUSELEAVE_TIMEOUT );
3132                 pSalData->mpMouseLeaveTimer->Start();
3133                 // We don't need to set a timeout handler, because we test
3134                 // for mouseleave in the timeout callback
3135             }
3136             aMouseEvt.mnButton = 0;
3137             nEvent = SalEvent::MouseMove;
3138             }
3139             break;
3140 
3141         case WM_NCMOUSEMOVE:
3142         case SAL_MSG_MOUSELEAVE:
3143             {
3144             SalData* pSalData = GetSalData();
3145             if ( pSalData->mhWantLeaveMsg == hWnd )
3146             {
3147                 // Mouse-Coordinates are relative to the screen
3148                 POINT aPt;
3149                 aPt.x = static_cast<short>(LOWORD(lParam));
3150                 aPt.y = static_cast<short>(HIWORD(lParam));
3151                 ScreenToClient(hWnd, &aPt);
3152                 if (const auto& pHelpWin = ImplGetSVHelpData().mpHelpWin)
3153                 {
3154                     const tools::Rectangle& rHelpRect = pHelpWin->GetHelpArea();
3155                     if (rHelpRect.Contains(Point(aPt.x, aPt.y)))
3156                     {
3157                         // We have entered a tooltip (help window). Don't call the handler here; it
3158                         // would launch the sequence "Mouse leaves the Control->Control redraws->
3159                         // Help window gets destroyed->Mouse enters the Control->Control redraws",
3160                         // which takes CPU and may flicker. Just destroy the help window and pretend
3161                         // we are still over the original window.
3162                         ImplDestroyHelpWindow(true);
3163                         bCall = false;
3164                         break;
3165                     }
3166                 }
3167                 pSalData->mhWantLeaveMsg = nullptr;
3168                 if ( pSalData->mpMouseLeaveTimer )
3169                 {
3170                     delete pSalData->mpMouseLeaveTimer;
3171                     pSalData->mpMouseLeaveTimer = nullptr;
3172                 }
3173                 aMouseEvt.mnX = aPt.x;
3174                 aMouseEvt.mnY = aPt.y;
3175                 aMouseEvt.mnButton = 0;
3176                 nEvent = SalEvent::MouseLeave;
3177             }
3178             else
3179                 bCall = false;
3180             }
3181             break;
3182 
3183         case WM_LBUTTONDOWN:
3184             aMouseEvt.mnButton = MOUSE_LEFT;
3185             nEvent = SalEvent::MouseButtonDown;
3186             break;
3187 
3188         case WM_MBUTTONDOWN:
3189             aMouseEvt.mnButton = MOUSE_MIDDLE;
3190             nEvent = SalEvent::MouseButtonDown;
3191             break;
3192 
3193         case WM_RBUTTONDOWN:
3194             aMouseEvt.mnButton = MOUSE_RIGHT;
3195             nEvent = SalEvent::MouseButtonDown;
3196             break;
3197 
3198         case WM_LBUTTONUP:
3199             aMouseEvt.mnButton = MOUSE_LEFT;
3200             nEvent = SalEvent::MouseButtonUp;
3201             break;
3202 
3203         case WM_MBUTTONUP:
3204             aMouseEvt.mnButton = MOUSE_MIDDLE;
3205             nEvent = SalEvent::MouseButtonUp;
3206             break;
3207 
3208         case WM_RBUTTONUP:
3209             aMouseEvt.mnButton = MOUSE_RIGHT;
3210             nEvent = SalEvent::MouseButtonUp;
3211             break;
3212     }
3213 
3214     // check if this window was destroyed - this might happen if we are the help window
3215     // and sent a mouse leave message to the application which killed the help window, ie ourselves
3216     if( !IsWindow( hWnd ) )
3217         return false;
3218 
3219     if ( bCall )
3220     {
3221         if ( nEvent == SalEvent::MouseButtonDown )
3222             UpdateWindow( hWnd );
3223 
3224         if( AllSettings::GetLayoutRTL() )
3225             aMouseEvt.mnX = pFrame->maGeometry.width() - 1 - aMouseEvt.mnX;
3226 
3227         nRet = pFrame->CallCallback( nEvent, &aMouseEvt );
3228         if ( nMsg == WM_MOUSEMOVE )
3229             SetCursor( pFrame->mhCursor );
3230     }
3231     else
3232         nRet = false;
3233 
3234     return nRet;
3235 }
3236 
3237 static bool ImplHandleMouseActivateMsg( HWND hWnd )
3238 {
3239     WinSalFrame* pFrame = GetWindowPtr( hWnd );
3240     if ( !pFrame )
3241         return false;
3242 
3243     if ( pFrame->mbFloatWin )
3244         return true;
3245 
3246     return pFrame->CallCallback( SalEvent::MouseActivate, nullptr );
3247 }
3248 
3249 static bool ImplHandleWheelMsg( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
3250 {
3251     DBG_ASSERT( nMsg == WM_MOUSEWHEEL ||
3252                 nMsg == WM_MOUSEHWHEEL,
3253                 "ImplHandleWheelMsg() called with no wheel mouse event" );
3254 
3255     ImplSalYieldMutexAcquireWithWait();
3256 
3257     bool nRet = false;
3258     WinSalFrame*   pFrame = GetWindowPtr( hWnd );
3259     if ( pFrame )
3260     {
3261         WORD    nWinModCode = LOWORD( wParam );
3262         POINT   aWinPt;
3263         aWinPt.x    = static_cast<short>(LOWORD( lParam ));
3264         aWinPt.y    = static_cast<short>(HIWORD( lParam ));
3265         ScreenToClient( hWnd, &aWinPt );
3266 
3267         SalWheelMouseEvent aWheelEvt;
3268         aWheelEvt.mnTime        = GetMessageTime();
3269         aWheelEvt.mnX           = aWinPt.x;
3270         aWheelEvt.mnY           = aWinPt.y;
3271         aWheelEvt.mnCode        = 0;
3272         aWheelEvt.mnDelta       = static_cast<short>(HIWORD( wParam ));
3273         aWheelEvt.mnNotchDelta  = aWheelEvt.mnDelta/WHEEL_DELTA;
3274         if( aWheelEvt.mnNotchDelta == 0 )
3275         {
3276             if( aWheelEvt.mnDelta > 0 )
3277                 aWheelEvt.mnNotchDelta = 1;
3278             else if( aWheelEvt.mnDelta < 0 )
3279                 aWheelEvt.mnNotchDelta = -1;
3280         }
3281 
3282         if( nMsg == WM_MOUSEWHEEL )
3283         {
3284             if ( aSalShlData.mnWheelScrollLines == WHEEL_PAGESCROLL )
3285                 aWheelEvt.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
3286             else
3287                 aWheelEvt.mnScrollLines = aSalShlData.mnWheelScrollLines;
3288             aWheelEvt.mbHorz        = false;
3289         }
3290         else
3291         {
3292             aWheelEvt.mnScrollLines = aSalShlData.mnWheelScrollChars;
3293             aWheelEvt.mbHorz        = true;
3294 
3295             // fdo#36380 - seems horiz scrolling has swapped direction
3296             aWheelEvt.mnDelta *= -1;
3297             aWheelEvt.mnNotchDelta *= -1;
3298         }
3299 
3300         if ( nWinModCode & MK_SHIFT )
3301             aWheelEvt.mnCode |= KEY_SHIFT;
3302         if ( nWinModCode & MK_CONTROL )
3303             aWheelEvt.mnCode |= KEY_MOD1;
3304         if ( GetKeyState( VK_MENU ) & 0x8000 )
3305             aWheelEvt.mnCode |= KEY_MOD2;
3306 
3307         if( AllSettings::GetLayoutRTL() )
3308             aWheelEvt.mnX = pFrame->maGeometry.width() - 1 - aWheelEvt.mnX;
3309 
3310         nRet = pFrame->CallCallback( SalEvent::WheelMouse, &aWheelEvt );
3311     }
3312 
3313     ImplSalYieldMutexRelease();
3314 
3315     return nRet;
3316 }
3317 
3318 static sal_uInt16 ImplSalGetKeyCode( WPARAM wParam )
3319 {
3320     sal_uInt16 nKeyCode;
3321 
3322     // convert KeyCode
3323     if ( wParam < KEY_TAB_SIZE )
3324         nKeyCode = aImplTranslateKeyTab[wParam];
3325     else
3326     {
3327         SalData* pSalData = GetSalData();
3328         std::map< UINT, sal_uInt16 >::const_iterator it = pSalData->maVKMap.find( static_cast<UINT>(wParam) );
3329         if( it != pSalData->maVKMap.end() )
3330             nKeyCode = it->second;
3331         else
3332             nKeyCode = 0;
3333     }
3334 
3335     return nKeyCode;
3336 }
3337 
3338 static void ImplUpdateInputLang( WinSalFrame* pFrame )
3339 {
3340     UINT nLang = LOWORD( GetKeyboardLayout( 0 ) );
3341     if ( nLang && nLang != pFrame->mnInputLang )
3342     {
3343         // keep input lang up-to-date
3344         pFrame->mnInputLang = nLang;
3345     }
3346 
3347     // We are on Windows NT so we use Unicode FrameProcs and get
3348     // Unicode charcodes directly from Windows no need to set up a
3349     // code page
3350     return;
3351 }
3352 
3353 static sal_Unicode ImplGetCharCode( WinSalFrame* pFrame, WPARAM nCharCode )
3354 {
3355     ImplUpdateInputLang( pFrame );
3356 
3357     // We are on Windows NT so we use Unicode FrameProcs and we
3358     // get Unicode charcodes directly from Windows
3359     return static_cast<sal_Unicode>(nCharCode);
3360 }
3361 
3362 LanguageType WinSalFrame::GetInputLanguage()
3363 {
3364     if( !mnInputLang )
3365         ImplUpdateInputLang( this );
3366 
3367     if( !mnInputLang )
3368         return LANGUAGE_DONTKNOW;
3369     else
3370         return LanguageType(mnInputLang);
3371 }
3372 
3373 bool WinSalFrame::MapUnicodeToKeyCode( sal_Unicode aUnicode, LanguageType aLangType, vcl::KeyCode& rKeyCode )
3374 {
3375     bool bRet = false;
3376     sal_IntPtr nLangType = static_cast<sal_uInt16>(aLangType);
3377     // just use the passed language identifier, do not try to load additional keyboard support
3378     HKL hkl = reinterpret_cast<HKL>(nLangType);
3379 
3380     if( hkl )
3381     {
3382         SHORT scan = VkKeyScanExW( aUnicode, hkl );
3383         if( LOWORD(scan) == 0xFFFF )
3384             // keyboard not loaded or key cannot be mapped
3385             bRet = false;
3386         else
3387         {
3388             BYTE vkeycode   = LOBYTE(scan);
3389             BYTE shiftstate = HIBYTE(scan);
3390 
3391             // Last argument is set to false, because there's no decision made
3392             // yet which key should be assigned to MOD3 modifier on Windows.
3393             // Windows key - user's can be confused, because it should display
3394             //               Windows menu (applies to both left/right key)
3395             // Menu key    - this key is used to display context menu
3396             // AltGr key   - probably it has no sense
3397             rKeyCode = vcl::KeyCode( ImplSalGetKeyCode( vkeycode ),
3398                 (shiftstate & 0x01) != 0,     // shift
3399                 (shiftstate & 0x02) != 0,     // ctrl
3400                 (shiftstate & 0x04) != 0,     // alt
3401                 false );
3402             bRet = true;
3403         }
3404     }
3405 
3406     return bRet;
3407 }
3408 
3409 static void UnsetAltIfAltGr(SalKeyEvent& rKeyEvt, sal_uInt16 nModCode)
3410 {
3411     if ((nModCode & (KEY_MOD1 | KEY_MOD2)) == (KEY_MOD1 | KEY_MOD2) &&
3412         rKeyEvt.mnCharCode)
3413     {
3414         // this is actually AltGr and should not be handled as Alt
3415         rKeyEvt.mnCode &= ~(KEY_MOD1 | KEY_MOD2);
3416     }
3417 }
3418 
3419 static bool ImplHandleKeyMsg( HWND hWnd, UINT nMsg,
3420                               WPARAM wParam, LPARAM lParam, LRESULT& rResult )
3421 {
3422     static bool         bIgnoreCharMsg  = false;
3423     static WPARAM       nDeadChar       = 0;
3424     static WPARAM       nLastVKChar     = 0;
3425     static sal_uInt16   nLastChar       = 0;
3426     static ModKeyFlags  nLastModKeyCode = ModKeyFlags::NONE;
3427     static bool         bWaitForModKeyRelease = false;
3428     sal_uInt16          nRepeat         = LOWORD( lParam )-1;
3429     sal_uInt16          nModCode        = 0;
3430 
3431     // this key might have been relayed by SysChild and thus
3432     // may not be processed twice
3433     GetSalData()->mnSalObjWantKeyEvt = 0;
3434 
3435     if ( nMsg == WM_DEADCHAR )
3436     {
3437         nDeadChar = wParam;
3438         return false;
3439     }
3440 
3441     WinSalFrame* pFrame = GetWindowPtr( hWnd );
3442     if ( !pFrame )
3443         return false;
3444 
3445     // reset the background mode for each text input,
3446     // as some tools such as RichWin may have changed it
3447     if ( pFrame->mpLocalGraphics &&
3448          pFrame->mpLocalGraphics->getHDC() )
3449         SetBkMode( pFrame->mpLocalGraphics->getHDC(), TRANSPARENT );
3450 
3451     // determine modifiers
3452     if ( GetKeyState( VK_SHIFT ) & 0x8000 )
3453         nModCode |= KEY_SHIFT;
3454     if ( GetKeyState( VK_CONTROL ) & 0x8000 )
3455         nModCode |= KEY_MOD1;
3456     if (GetKeyState(VK_MENU) & 0x8000)
3457         nModCode |= KEY_MOD2;
3458 
3459     if ( (nMsg == WM_CHAR) || (nMsg == WM_SYSCHAR) )
3460     {
3461         nDeadChar = 0;
3462 
3463         if ( bIgnoreCharMsg )
3464         {
3465             bIgnoreCharMsg = false;
3466             // #101635# if zero is returned here for WM_SYSCHAR (ALT+<key>) Windows will beep
3467             // because this 'hotkey' was not processed -> better return 1
3468             // except for Alt-SPACE which should always open the sysmenu (#104616#)
3469 
3470             // also return zero if a system menubar is available that might process this hotkey
3471             // this also applies to the OLE inplace embedding where we are a child window
3472             if( (GetWindowStyle( hWnd ) & WS_CHILD) || GetMenu( hWnd ) || (wParam == 0x20) )
3473                 return false;
3474             else
3475                 return true;
3476         }
3477 
3478         // ignore backspace as a single key, so that
3479         // we do not get problems for combinations w/ a DeadKey
3480         if ( wParam == 0x08 )    // BACKSPACE
3481             return false;
3482 
3483         // only "free flying" WM_CHAR messages arrive here, that are
3484         // created by typing an ALT-NUMPAD combination
3485         SalKeyEvent aKeyEvt;
3486 
3487         if ( (wParam >= '0') && (wParam <= '9') )
3488             aKeyEvt.mnCode = sal::static_int_cast<sal_uInt16>(KEYGROUP_NUM + wParam - '0');
3489         else if ( (wParam >= 'A') && (wParam <= 'Z') )
3490             aKeyEvt.mnCode = sal::static_int_cast<sal_uInt16>(KEYGROUP_ALPHA + wParam - 'A');
3491         else if ( (wParam >= 'a') && (wParam <= 'z') )
3492             aKeyEvt.mnCode = sal::static_int_cast<sal_uInt16>(KEYGROUP_ALPHA + wParam - 'a');
3493         else if ( wParam == 0x0D )    // RETURN
3494             aKeyEvt.mnCode = KEY_RETURN;
3495         else if ( wParam == 0x1B )    // ESCAPE
3496             aKeyEvt.mnCode = KEY_ESCAPE;
3497         else if ( wParam == 0x09 )    // TAB
3498             aKeyEvt.mnCode = KEY_TAB;
3499         else if ( wParam == 0x20 )    // SPACE
3500             aKeyEvt.mnCode = KEY_SPACE;
3501         else
3502             aKeyEvt.mnCode = 0;
3503 
3504         aKeyEvt.mnCode     |= nModCode;
3505         aKeyEvt.mnCharCode  = ImplGetCharCode( pFrame, wParam );
3506         aKeyEvt.mnRepeat    = nRepeat;
3507 
3508         UnsetAltIfAltGr(aKeyEvt, nModCode);
3509 
3510         nLastChar = 0;
3511         nLastVKChar = 0;
3512 
3513         bool nRet = pFrame->CallCallback( SalEvent::KeyInput, &aKeyEvt );
3514         pFrame->CallCallback( SalEvent::KeyUp, &aKeyEvt );
3515         return nRet;
3516     }
3517     // #i11583#, MCD, 2003-01-13, Support for WM_UNICHAR & Keyman 6.0; addition begins
3518     else if( nMsg == WM_UNICHAR )
3519     {
3520         // If Windows is asking if we accept WM_UNICHAR, return TRUE
3521         if(wParam == UNICODE_NOCHAR)
3522         {
3523             rResult = TRUE; // ssa: this will actually return TRUE to windows
3524             return true;    // ...but this will only avoid calling the defwindowproc
3525         }
3526 
3527         SalKeyEvent aKeyEvt;
3528         aKeyEvt.mnCode     = nModCode; // Or should it be 0? - as this is always a character returned
3529         aKeyEvt.mnRepeat   = 0;
3530 
3531         if( wParam >= Uni_SupplementaryPlanesStart )
3532         {
3533             // character is supplementary char in UTF-32 format - must be converted to UTF-16 supplementary pair
3534             // sal_Unicode ch = (sal_Unicode) Uni_UTF32ToSurrogate1(wParam);
3535              nLastChar = 0;
3536              nLastVKChar = 0;
3537              pFrame->CallCallback( SalEvent::KeyInput, &aKeyEvt );
3538              pFrame->CallCallback( SalEvent::KeyUp, &aKeyEvt );
3539              wParam = rtl::getLowSurrogate( wParam );
3540         }
3541 
3542         aKeyEvt.mnCharCode = static_cast<sal_Unicode>(wParam);
3543 
3544         nLastChar = 0;
3545         nLastVKChar = 0;
3546         bool nRet = pFrame->CallCallback( SalEvent::KeyInput, &aKeyEvt );
3547         pFrame->CallCallback( SalEvent::KeyUp, &aKeyEvt );
3548 
3549         return nRet;
3550     }
3551     // MCD, 2003-01-13, Support for WM_UNICHAR & Keyman 6.0; addition ends
3552     else
3553     {
3554         // for shift, control and menu we issue a KeyModChange event
3555         if ( (wParam == VK_SHIFT) || (wParam == VK_CONTROL) || (wParam == VK_MENU) )
3556         {
3557             SalKeyModEvent aModEvt;
3558             aModEvt.mbDown = false; // auto-accelerator feature not supported here.
3559             aModEvt.mnCode = nModCode;
3560             aModEvt.mnModKeyCode = ModKeyFlags::NONE;   // no command events will be sent if this member is 0
3561 
3562             ModKeyFlags tmpCode = ModKeyFlags::NONE;
3563             if( GetKeyState( VK_LSHIFT )  & 0x8000 )
3564                 tmpCode |= ModKeyFlags::LeftShift;
3565             if( GetKeyState( VK_RSHIFT )  & 0x8000 )
3566                 tmpCode |= ModKeyFlags::RightShift;
3567             if( GetKeyState( VK_LCONTROL ) & 0x8000 )
3568                 tmpCode |= ModKeyFlags::LeftMod1;
3569             if( GetKeyState( VK_RCONTROL ) & 0x8000 )
3570                 tmpCode |= ModKeyFlags::RightMod1;
3571             if( GetKeyState( VK_LMENU )  & 0x8000 )
3572                 tmpCode |= ModKeyFlags::LeftMod2;
3573             if( GetKeyState( VK_RMENU )  & 0x8000 )
3574                 tmpCode |= ModKeyFlags::RightMod2;
3575 
3576             if( tmpCode < nLastModKeyCode )
3577             {
3578                 aModEvt.mnModKeyCode = nLastModKeyCode;
3579                 nLastModKeyCode = ModKeyFlags::NONE;
3580                 bWaitForModKeyRelease = true;
3581             }
3582             else
3583             {
3584                 if( !bWaitForModKeyRelease )
3585                     nLastModKeyCode = tmpCode;
3586             }
3587 
3588             if( tmpCode == ModKeyFlags::NONE )
3589                 bWaitForModKeyRelease = false;
3590 
3591             return pFrame->CallCallback( SalEvent::KeyModChange, &aModEvt );
3592         }
3593         else
3594         {
3595             SalKeyEvent     aKeyEvt;
3596             SalEvent        nEvent;
3597             MSG             aCharMsg;
3598             bool            bCharPeek = false;
3599             UINT            nCharMsg = WM_CHAR;
3600             bool            bKeyUp = (nMsg == WM_KEYUP) || (nMsg == WM_SYSKEYUP);
3601 
3602             nLastModKeyCode = ModKeyFlags::NONE; // make sure no modkey messages are sent if they belong to a hotkey (see above)
3603             aKeyEvt.mnCharCode = 0;
3604             aKeyEvt.mnCode = ImplSalGetKeyCode( wParam );
3605             if ( !bKeyUp )
3606             {
3607                 // check for charcode
3608                 // Get the related WM_CHAR message using PeekMessage, if available.
3609                 // The WM_CHAR message is always at the beginning of the
3610                 // message queue. Also it is made certain that there is always only
3611                 // one WM_CHAR message in the queue.
3612                 bCharPeek = PeekMessageW( &aCharMsg, hWnd,
3613                                              WM_CHAR, WM_CHAR, PM_NOREMOVE | PM_NOYIELD );
3614                 if ( bCharPeek && (nDeadChar == aCharMsg.wParam) )
3615                 {
3616                     bCharPeek = false;
3617                     nDeadChar = 0;
3618 
3619                     if ( wParam == VK_BACK )
3620                     {
3621                         PeekMessageW( &aCharMsg, hWnd,
3622                                          nCharMsg, nCharMsg, PM_REMOVE | PM_NOYIELD );
3623                         return false;
3624                     }
3625                 }
3626                 else
3627                 {
3628                     if ( !bCharPeek )
3629                     {
3630                         bCharPeek = PeekMessageW( &aCharMsg, hWnd,
3631                                                     WM_SYSCHAR, WM_SYSCHAR, PM_NOREMOVE | PM_NOYIELD );
3632                         nCharMsg = WM_SYSCHAR;
3633                     }
3634                 }
3635                 if ( bCharPeek )
3636                     aKeyEvt.mnCharCode = ImplGetCharCode( pFrame, aCharMsg.wParam );
3637                 else
3638                     aKeyEvt.mnCharCode = 0;
3639 
3640                 nLastChar = aKeyEvt.mnCharCode;
3641                 nLastVKChar = wParam;
3642             }
3643             else
3644             {
3645                 if ( wParam == nLastVKChar )
3646                 {
3647                     aKeyEvt.mnCharCode = nLastChar;
3648                     nLastChar = 0;
3649                     nLastVKChar = 0;
3650                 }
3651             }
3652 
3653             if ( aKeyEvt.mnCode || aKeyEvt.mnCharCode )
3654             {
3655                 if ( bKeyUp )
3656                     nEvent = SalEvent::KeyUp;
3657                 else
3658                     nEvent = SalEvent::KeyInput;
3659 
3660                 aKeyEvt.mnCode     |= nModCode;
3661                 aKeyEvt.mnRepeat    = nRepeat;
3662 
3663                 UnsetAltIfAltGr(aKeyEvt, nModCode);
3664 
3665                 bIgnoreCharMsg = bCharPeek;
3666                 bool nRet = pFrame->CallCallback( nEvent, &aKeyEvt );
3667                 // independent part only reacts on keyup but Windows does not send
3668                 // keyup for VK_HANJA
3669                 if( aKeyEvt.mnCode == KEY_HANGUL_HANJA )
3670                     nRet = pFrame->CallCallback( SalEvent::KeyUp, &aKeyEvt );
3671 
3672                 bIgnoreCharMsg = false;
3673 
3674                 // char-message, then remove or ignore
3675                 if ( bCharPeek )
3676                 {
3677                     nDeadChar = 0;
3678                     if ( nRet )
3679                     {
3680                         PeekMessageW( &aCharMsg, hWnd,
3681                                          nCharMsg, nCharMsg, PM_REMOVE | PM_NOYIELD );
3682                     }
3683                     else
3684                         bIgnoreCharMsg = true;
3685                 }
3686 
3687                 return nRet;
3688             }
3689             else
3690                 return false;
3691         }
3692     }
3693 }
3694 
3695 bool ImplHandleSalObjKeyMsg( HWND hWnd, UINT nMsg,
3696                              WPARAM wParam, LPARAM lParam )
3697 {
3698     if ( (nMsg == WM_KEYDOWN) || (nMsg == WM_KEYUP) )
3699     {
3700         WinSalFrame* pFrame = GetWindowPtr( hWnd );
3701         if ( !pFrame )
3702             return false;
3703 
3704         sal_uInt16  nRepeat     = LOWORD( lParam )-1;
3705         sal_uInt16  nModCode    = 0;
3706 
3707         // determine modifiers
3708         if ( GetKeyState( VK_SHIFT ) & 0x8000 )
3709             nModCode |= KEY_SHIFT;
3710         if ( GetKeyState( VK_CONTROL ) & 0x8000 )
3711             nModCode |= KEY_MOD1;
3712         if ( GetKeyState( VK_MENU ) & 0x8000 )
3713             nModCode |= KEY_MOD2;
3714 
3715         if ( (wParam != VK_SHIFT) && (wParam != VK_CONTROL) && (wParam != VK_MENU) )
3716         {
3717             SalKeyEvent     aKeyEvt;
3718             SalEvent        nEvent;
3719 
3720             // convert KeyCode
3721             aKeyEvt.mnCode      = ImplSalGetKeyCode( wParam );
3722             aKeyEvt.mnCharCode  = 0;
3723 
3724             if ( aKeyEvt.mnCode )
3725             {
3726                 if (nMsg == WM_KEYUP)
3727                     nEvent = SalEvent::KeyUp;
3728                 else
3729                     nEvent = SalEvent::KeyInput;
3730 
3731                 aKeyEvt.mnCode     |= nModCode;
3732                 aKeyEvt.mnRepeat    = nRepeat;
3733                 bool nRet = pFrame->CallCallback( nEvent, &aKeyEvt );
3734                 return nRet;
3735             }
3736             else
3737                 return false;
3738         }
3739     }
3740 
3741     return false;
3742 }
3743 
3744 bool ImplHandleSalObjSysCharMsg( HWND hWnd, WPARAM wParam, LPARAM lParam )
3745 {
3746     WinSalFrame* pFrame = GetWindowPtr( hWnd );
3747     if ( !pFrame )
3748         return false;
3749 
3750     sal_uInt16  nRepeat     = LOWORD( lParam )-1;
3751     sal_uInt16  nModCode    = 0;
3752     sal_uInt16  cKeyCode    = static_cast<sal_uInt16>(wParam);
3753 
3754     // determine modifiers
3755     if ( GetKeyState( VK_SHIFT ) & 0x8000 )
3756         nModCode |= KEY_SHIFT;
3757     if ( GetKeyState( VK_CONTROL ) & 0x8000 )
3758         nModCode |= KEY_MOD1;
3759     nModCode |= KEY_MOD2;
3760 
3761     // assemble KeyEvent
3762     SalKeyEvent aKeyEvt;
3763     if ( (cKeyCode >= 48) && (cKeyCode <= 57) )
3764         aKeyEvt.mnCode = KEY_0+(cKeyCode-48);
3765     else if ( (cKeyCode >= 65) && (cKeyCode <= 90) )
3766         aKeyEvt.mnCode = KEY_A+(cKeyCode-65);
3767     else  if ( (cKeyCode >= 97) && (cKeyCode <= 122) )
3768         aKeyEvt.mnCode = KEY_A+(cKeyCode-97);
3769     else
3770         aKeyEvt.mnCode = 0;
3771     aKeyEvt.mnCode     |= nModCode;
3772     aKeyEvt.mnCharCode  = ImplGetCharCode( pFrame, cKeyCode );
3773     aKeyEvt.mnRepeat    = nRepeat;
3774     bool nRet = pFrame->CallCallback( SalEvent::KeyInput, &aKeyEvt );
3775     pFrame->CallCallback( SalEvent::KeyUp, &aKeyEvt );
3776     return nRet;
3777 }
3778 
3779 namespace {
3780 
3781 enum class DeferPolicy
3782 {
3783     Blocked,
3784     Allowed
3785 };
3786 
3787 }
3788 
3789 // Remember to release the solar mutex on success!
3790 static WinSalFrame* ProcessOrDeferMessage( HWND hWnd, INT nMsg, WPARAM pWParam = 0,
3791                                                   DeferPolicy eCanDefer = DeferPolicy::Allowed )
3792 {
3793     bool bFailedCondition = false, bGotMutex = false;
3794     WinSalFrame* pFrame = nullptr;
3795 
3796     if ( DeferPolicy::Blocked == eCanDefer )
3797         assert( (DeferPolicy::Blocked == eCanDefer) && (nMsg == 0) && (pWParam == 0) );
3798     else
3799         assert( (DeferPolicy::Allowed == eCanDefer) && (nMsg != 0) );
3800 
3801     if ( DeferPolicy::Blocked == eCanDefer )
3802     {
3803         ImplSalYieldMutexAcquireWithWait();
3804         bGotMutex = true;
3805     }
3806     else if ( !(bGotMutex = ImplSalYieldMutexTryToAcquire()) )
3807         bFailedCondition = true;
3808 
3809     if ( !bFailedCondition )
3810     {
3811         pFrame = GetWindowPtr( hWnd );
3812         bFailedCondition = pFrame == nullptr;
3813     }
3814 
3815     if ( bFailedCondition )
3816     {
3817         if ( bGotMutex )
3818             ImplSalYieldMutexRelease();
3819         if ( DeferPolicy::Allowed == eCanDefer )
3820         {
3821             bool const ret = PostMessageW(hWnd, nMsg, pWParam, 0);
3822             SAL_WARN_IF(!ret, "vcl", "ERROR: PostMessage() failed!");
3823         }
3824     }
3825 
3826     return pFrame;
3827 }
3828 
3829 namespace {
3830 
3831 enum class PostedState
3832 {
3833     IsPosted,
3834     IsInitial
3835 };
3836 
3837 }
3838 
3839 static bool ImplHandlePostPaintMsg( HWND hWnd, RECT* pRect,
3840                                     PostedState eProcessed = PostedState::IsPosted )
3841 {
3842     RECT* pMsgRect;
3843     if ( PostedState::IsInitial == eProcessed )
3844     {
3845         pMsgRect = new RECT;
3846         CopyRect( pMsgRect, pRect );
3847     }
3848     else
3849         pMsgRect = pRect;
3850 
3851     WinSalFrame* pFrame = ProcessOrDeferMessage( hWnd, SAL_MSG_POSTPAINT,
3852                                                  reinterpret_cast<WPARAM>(pMsgRect) );
3853     if ( pFrame )
3854     {
3855         SalPaintEvent aPEvt( pRect->left, pRect->top, pRect->right-pRect->left, pRect->bottom-pRect->top );
3856         pFrame->CallCallback( SalEvent::Paint, &aPEvt );
3857         ImplSalYieldMutexRelease();
3858         if ( PostedState::IsPosted == eProcessed )
3859             delete pRect;
3860     }
3861 
3862     return (pFrame != nullptr);
3863 }
3864 
3865 static bool ImplHandlePaintMsg( HWND hWnd )
3866 {
3867     bool bPaintSuccessful = false;
3868 
3869     // even without the Yield mutex, we can still change the clip region,
3870     // because other threads don't use the Yield mutex
3871     // --> see AcquireGraphics()
3872 
3873     WinSalFrame* pFrame = GetWindowPtr( hWnd );
3874     if ( pFrame )
3875     {
3876         // clip region must be set, as we don't get a proper
3877         // bounding rectangle otherwise
3878         WinSalGraphics *pGraphics = pFrame->mpLocalGraphics;
3879         bool bHasClipRegion = pGraphics &&
3880             pGraphics->getHDC() && pGraphics->getRegion();
3881         if ( bHasClipRegion )
3882             SelectClipRgn( pGraphics->getHDC(), nullptr );
3883 
3884         // according to Windows documentation one shall check first if
3885         // there really is a paint-region
3886         RECT aUpdateRect;
3887         PAINTSTRUCT aPs;
3888         bool bHasPaintRegion = GetUpdateRect( hWnd, nullptr, FALSE );
3889         if ( bHasPaintRegion )
3890         {
3891             // call BeginPaint/EndPaint to query the paint rect and use
3892             // this information in the (deferred) paint
3893             BeginPaint( hWnd, &aPs );
3894             CopyRect( &aUpdateRect, &aPs.rcPaint );
3895         }
3896 
3897         // reset clip region
3898         if ( bHasClipRegion )
3899             SelectClipRgn( pGraphics->getHDC(), pGraphics->getRegion() );
3900 
3901         // try painting
3902         if ( bHasPaintRegion )
3903         {
3904             bPaintSuccessful = ImplHandlePostPaintMsg(
3905                 hWnd, &aUpdateRect, PostedState::IsInitial );
3906             EndPaint( hWnd, &aPs );
3907         }
3908         else // if there is nothing to paint, the paint is successful
3909             bPaintSuccessful = true;
3910     }
3911 
3912     return bPaintSuccessful;
3913 }
3914 
3915 static void SetMaximizedFrameGeometry( HWND hWnd, WinSalFrame* pFrame, RECT* pParentRect )
3916 {
3917     // calculate and set frame geometry of a maximized window - useful if the window is still hidden
3918 
3919     // dualmonitor support:
3920     // Get screensize of the monitor with the mouse pointer
3921 
3922     RECT aRectMouse;
3923     if( ! pParentRect )
3924     {
3925         POINT pt;
3926         GetCursorPos( &pt );
3927         aRectMouse.left = pt.x;
3928         aRectMouse.top = pt.y;
3929         aRectMouse.right = pt.x+2;
3930         aRectMouse.bottom = pt.y+2;
3931         pParentRect = &aRectMouse;
3932     }
3933 
3934     RECT aRect;
3935     ImplSalGetWorkArea( hWnd, &aRect, pParentRect );
3936 
3937     // a maximized window has no other borders than the caption
3938     pFrame->maGeometry.setDecorations(0, pFrame->mbCaption ? GetSystemMetrics(SM_CYCAPTION) : 0, 0, 0);
3939 
3940     aRect.top += pFrame->maGeometry.topDecoration();
3941     pFrame->maGeometry.setPos({ aRect.left, aRect.top });
3942     SetGeometrySize(pFrame->maGeometry, { aRect.right - aRect.left, aRect.bottom - aRect.top });
3943 }
3944 
3945 static void UpdateFrameGeometry(WinSalFrame* pFrame)
3946 {
3947     if( !pFrame )
3948         return;
3949     const HWND hWnd = pFrame->mhWnd;
3950 
3951     RECT aRect;
3952     GetWindowRect( hWnd, &aRect );
3953     pFrame->maGeometry.setPosSize({ 0, 0 }, { 0, 0 });
3954     pFrame->maGeometry.setDecorations(0, 0, 0, 0);
3955     pFrame->maGeometry.setScreen(0);
3956 
3957     if ( IsIconic( hWnd ) )
3958         return;
3959 
3960     POINT aPt;
3961     aPt.x=0;
3962     aPt.y=0;
3963     ClientToScreen(hWnd, &aPt);
3964     int cx = aPt.x - aRect.left;
3965 
3966     pFrame->maGeometry.setDecorations(cx, aPt.y - aRect.top, cx, 0);
3967     pFrame->maGeometry.setPos({ aPt.x, aPt.y });
3968 
3969     RECT aInnerRect;
3970     GetClientRect( hWnd, &aInnerRect );
3971     if( aInnerRect.right )
3972     {
3973         // improve right decoration
3974         aPt.x=aInnerRect.right;
3975         aPt.y=aInnerRect.top;
3976         ClientToScreen(hWnd, &aPt);
3977         pFrame->maGeometry.setRightDecoration(aRect.right - aPt.x);
3978     }
3979     if( aInnerRect.bottom ) // may be zero if window was not shown yet
3980         pFrame->maGeometry.setBottomDecoration(aRect.bottom - aPt.y - aInnerRect.bottom);
3981     else
3982         // bottom border is typically the same as left/right
3983         pFrame->maGeometry.setBottomDecoration(pFrame->maGeometry.leftDecoration());
3984 
3985     int nWidth  = aRect.right - aRect.left
3986         - pFrame->maGeometry.rightDecoration() - pFrame->maGeometry.leftDecoration();
3987     int nHeight = aRect.bottom - aRect.top
3988         - pFrame->maGeometry.bottomDecoration() - pFrame->maGeometry.topDecoration();
3989     SetGeometrySize(pFrame->maGeometry, { nWidth, nHeight });
3990     pFrame->updateScreenNumber();
3991 }
3992 
3993 static void ImplCallClosePopupsHdl( HWND hWnd )
3994 {
3995     WinSalFrame* pFrame = GetWindowPtr( hWnd );
3996     if ( pFrame )
3997     {
3998         pFrame->CallCallback( SalEvent::ClosePopups, nullptr );
3999     }
4000 }
4001 
4002 static void ImplCallMoveHdl(HWND hWnd)
4003 {
4004     WinSalFrame* pFrame = ProcessOrDeferMessage(hWnd, SAL_MSG_POSTMOVE);
4005     if (!pFrame)
4006         return;
4007 
4008     pFrame->CallCallback(SalEvent::Move, nullptr);
4009 
4010     ImplSalYieldMutexRelease();
4011 }
4012 
4013 static void ImplHandleMoveMsg(HWND hWnd, LPARAM lParam)
4014 {
4015     WinSalFrame* pFrame = GetWindowPtr( hWnd );
4016     if (!pFrame)
4017         return;
4018 
4019     UpdateFrameGeometry(pFrame);
4020 
4021 #ifdef NDEBUG
4022     (void) lParam;
4023 #endif
4024     assert(IsIconic(hWnd) || (pFrame->maGeometry.x() == static_cast<sal_Int16>(LOWORD(lParam))));
4025     assert(IsIconic(hWnd) || (pFrame->maGeometry.y() == static_cast<sal_Int16>(HIWORD(lParam))));
4026 
4027     if (GetWindowStyle(hWnd) & WS_VISIBLE)
4028         pFrame->mbDefPos = false;
4029 
4030     // protect against recursion
4031     if (!pFrame->mbInMoveMsg)
4032     {
4033         // adjust window again for FullScreenMode
4034         pFrame->mbInMoveMsg = true;
4035         if (pFrame->isFullScreen())
4036             ImplSalFrameFullScreenPos(pFrame);
4037         pFrame->mbInMoveMsg = false;
4038     }
4039 
4040     pFrame->UpdateFrameState();
4041 
4042     ImplCallMoveHdl(hWnd);
4043 }
4044 
4045 static void ImplCallSizeHdl( HWND hWnd )
4046 {
4047     WinSalFrame* pFrame = ProcessOrDeferMessage( hWnd, SAL_MSG_POSTCALLSIZE );
4048     if (!pFrame)
4049         return;
4050 
4051     pFrame->CallCallback(SalEvent::Resize, nullptr);
4052     // to avoid double Paints by VCL and SAL
4053     if (IsWindowVisible(hWnd) && !pFrame->mbInShow)
4054         UpdateWindow(hWnd);
4055 
4056     ImplSalYieldMutexRelease();
4057 }
4058 
4059 static void ImplHandleSizeMsg(HWND hWnd, WPARAM wParam, LPARAM lParam)
4060 {
4061     if ((wParam == SIZE_MAXSHOW) || (wParam == SIZE_MAXHIDE))
4062         return;
4063 
4064     WinSalFrame* pFrame = GetWindowPtr(hWnd);
4065     if (!pFrame)
4066         return;
4067 
4068     UpdateFrameGeometry(pFrame);
4069 
4070 #ifdef NDEBUG
4071     (void) lParam;
4072 #endif
4073     assert(pFrame->maGeometry.width() == static_cast<sal_Int16>(LOWORD(lParam)));
4074     assert(pFrame->maGeometry.height() == static_cast<sal_Int16>(HIWORD(lParam)));
4075 
4076     pFrame->UpdateFrameState();
4077 
4078     ImplCallSizeHdl(hWnd);
4079 
4080     WinSalTimer* pTimer = static_cast<WinSalTimer*>(ImplGetSVData()->maSchedCtx.mpSalTimer);
4081     if (pTimer)
4082         pTimer->SetForceRealTimer(true);
4083 }
4084 
4085 static void ImplHandleFocusMsg( HWND hWnd )
4086 {
4087     WinSalFrame* pFrame = ProcessOrDeferMessage( hWnd, SAL_MSG_POSTFOCUS );
4088     if (!pFrame)
4089         return;
4090     const ::comphelper::ScopeGuard aScopeGuard([](){ ImplSalYieldMutexRelease(); });
4091 
4092     if (WinSalFrame::mbInReparent)
4093         return;
4094 
4095     const bool bGotFocus = ::GetFocus() == hWnd;
4096     if (bGotFocus)
4097     {
4098         if (IsWindowVisible(hWnd) && !pFrame->mbInShow)
4099             UpdateWindow(hWnd);
4100 
4101         // do we support IME?
4102         if (pFrame->mbIME && pFrame->mhDefIMEContext)
4103         {
4104             UINT nImeProps = ImmGetProperty(GetKeyboardLayout(0), IGP_PROPERTY);
4105             pFrame->mbSpezIME = (nImeProps & IME_PROP_SPECIAL_UI) != 0;
4106             pFrame->mbAtCursorIME = (nImeProps & IME_PROP_AT_CARET) != 0;
4107             pFrame->mbHandleIME = !pFrame->mbSpezIME;
4108         }
4109     }
4110 
4111     pFrame->CallCallback(bGotFocus ? SalEvent::GetFocus : SalEvent::LoseFocus, nullptr);
4112 }
4113 
4114 static void ImplHandleCloseMsg( HWND hWnd )
4115 {
4116     WinSalFrame* pFrame = ProcessOrDeferMessage( hWnd, WM_CLOSE );
4117     if ( pFrame )
4118     {
4119         pFrame->CallCallback( SalEvent::Close, nullptr );
4120         ImplSalYieldMutexRelease();
4121     }
4122 }
4123 
4124 static bool ImplHandleShutDownMsg( HWND hWnd )
4125 {
4126     bool nRet = false;
4127     WinSalFrame* pFrame = ProcessOrDeferMessage( hWnd, 0, 0, DeferPolicy::Blocked );
4128     if ( pFrame )
4129     {
4130         nRet = pFrame->CallCallback( SalEvent::Shutdown, nullptr );
4131         ImplSalYieldMutexRelease();
4132     }
4133     return nRet;
4134 }
4135 
4136 static void ImplHandleSettingsChangeMsg( HWND hWnd, UINT nMsg,
4137                                          WPARAM wParam, LPARAM lParam )
4138 {
4139     SalEvent nSalEvent = SalEvent::SettingsChanged;
4140 
4141     if ( nMsg == WM_DEVMODECHANGE )
4142         nSalEvent = SalEvent::PrinterChanged;
4143     else if ( nMsg == WM_DISPLAYCHANGE )
4144         nSalEvent = SalEvent::DisplayChanged;
4145     else if ( nMsg == WM_FONTCHANGE )
4146         nSalEvent = SalEvent::FontChanged;
4147     else if ( nMsg == WM_WININICHANGE )
4148     {
4149         if ( lParam )
4150         {
4151             if ( ImplSalWICompareAscii( reinterpret_cast<const wchar_t*>(lParam), "devices" ) == 0 )
4152                 nSalEvent = SalEvent::PrinterChanged;
4153         }
4154     }
4155 
4156     if ( nMsg == WM_SETTINGCHANGE )
4157     {
4158         if ( wParam == SPI_SETWHEELSCROLLLINES )
4159             aSalShlData.mnWheelScrollLines = ImplSalGetWheelScrollLines();
4160         else if( wParam == SPI_SETWHEELSCROLLCHARS )
4161             aSalShlData.mnWheelScrollChars = ImplSalGetWheelScrollChars();
4162         UpdateDarkMode(hWnd);
4163         GetSalData()->mbThemeChanged = true;
4164     }
4165 
4166     if ( WM_SYSCOLORCHANGE == nMsg && GetSalData()->mhDitherPal )
4167         ImplUpdateSysColorEntries();
4168 
4169     WinSalFrame* pFrame = ProcessOrDeferMessage( hWnd, 0, 0, DeferPolicy::Blocked );
4170     if (!pFrame)
4171         return;
4172 
4173     if (((nMsg == WM_DISPLAYCHANGE) || (nMsg == WM_WININICHANGE)) && pFrame->isFullScreen())
4174         ImplSalFrameFullScreenPos(pFrame);
4175 
4176     pFrame->CallCallback(nSalEvent, nullptr);
4177 
4178     ImplSalYieldMutexRelease();
4179 }
4180 
4181 static void ImplHandleUserEvent( HWND hWnd, LPARAM lParam )
4182 {
4183     WinSalFrame* pFrame = ProcessOrDeferMessage( hWnd, 0, 0, DeferPolicy::Blocked );
4184     if ( pFrame )
4185     {
4186         pFrame->CallCallback( SalEvent::UserEvent, reinterpret_cast<void*>(lParam) );
4187         ImplSalYieldMutexRelease();
4188     }
4189 }
4190 
4191 static void ImplHandleForcePalette( HWND hWnd )
4192 {
4193     SalData*    pSalData = GetSalData();
4194     HPALETTE    hPal = pSalData->mhDitherPal;
4195     if (!hPal)
4196         return;
4197 
4198     WinSalFrame* pFrame = ProcessOrDeferMessage(hWnd, SAL_MSG_FORCEPALETTE);
4199     if (!pFrame)
4200         return;
4201     const ::comphelper::ScopeGuard aScopeGuard([](){ ImplSalYieldMutexRelease(); });
4202 
4203     WinSalGraphics* pGraphics = pFrame->mpLocalGraphics;
4204     if (!pGraphics || !pGraphics->getHDC() || !pGraphics->getDefPal()
4205             || (pGraphics->setPalette(hPal, FALSE) == GDI_ERROR))
4206         return;
4207 
4208     InvalidateRect(hWnd, nullptr, FALSE);
4209     UpdateWindow(hWnd);
4210     pFrame->CallCallback(SalEvent::DisplayChanged, nullptr);
4211 }
4212 
4213 static LRESULT ImplHandlePalette( bool bFrame, HWND hWnd, UINT nMsg,
4214                                   WPARAM wParam, LPARAM lParam, bool& rDef )
4215 {
4216     SalData*    pSalData = GetSalData();
4217     HPALETTE    hPal = pSalData->mhDitherPal;
4218     if ( !hPal )
4219         return 0;
4220 
4221     rDef = false;
4222     if ( pSalData->mbInPalChange )
4223         return 0;
4224 
4225     if ( (nMsg == WM_PALETTECHANGED) || (nMsg == SAL_MSG_POSTPALCHANGED) )
4226     {
4227         if ( reinterpret_cast<HWND>(wParam) == hWnd )
4228             return 0;
4229     }
4230 
4231     bool bReleaseMutex = false;
4232     if ( (nMsg == WM_QUERYNEWPALETTE) || (nMsg == WM_PALETTECHANGED) )
4233     {
4234         // as Windows can send these messages also, we have to use
4235         // the Solar semaphore
4236         if ( ImplSalYieldMutexTryToAcquire() )
4237             bReleaseMutex = true;
4238         else if ( nMsg == WM_QUERYNEWPALETTE )
4239         {
4240             bool const ret = PostMessageW(hWnd, SAL_MSG_POSTQUERYNEWPAL, wParam, lParam);
4241             SAL_WARN_IF(!ret, "vcl", "ERROR: PostMessage() failed!");
4242         }
4243         else /* ( nMsg == WM_PALETTECHANGED ) */
4244         {
4245             bool const ret = PostMessageW(hWnd, SAL_MSG_POSTPALCHANGED, wParam, lParam);
4246             SAL_WARN_IF(!ret, "vcl", "ERROR: PostMessage() failed!");
4247         }
4248     }
4249 
4250     WinSalVirtualDevice*pTempVD;
4251     WinSalFrame*        pTempFrame;
4252     WinSalGraphics*     pGraphics;
4253     HDC                 hDC;
4254     HPALETTE hOldPal = nullptr;
4255     UINT nCols = GDI_ERROR;
4256     bool                bUpdate;
4257 
4258     pSalData->mbInPalChange = true;
4259 
4260     // reset all palettes in VirDevs and Frames
4261     pTempVD = pSalData->mpFirstVD;
4262     while ( pTempVD )
4263     {
4264         pGraphics = pTempVD->getGraphics();
4265         pGraphics->setPalette(nullptr);
4266         pTempVD = pTempVD->getNext();
4267     }
4268     pTempFrame = pSalData->mpFirstFrame;
4269     while ( pTempFrame )
4270     {
4271         pGraphics = pTempFrame->mpLocalGraphics;
4272         pGraphics->setPalette(nullptr);
4273         pTempFrame = pTempFrame->mpNextFrame;
4274     }
4275 
4276     // re-initialize palette
4277     WinSalFrame* pFrame = nullptr;
4278     if ( bFrame )
4279         pFrame = GetWindowPtr( hWnd );
4280 
4281     UnrealizeObject(hPal);
4282     const bool bStdDC = pFrame && pFrame->mpLocalGraphics && pFrame->mpLocalGraphics->getHDC();
4283     if (!bStdDC)
4284     {
4285         hDC = GetDC(hWnd);
4286         hOldPal = SelectPalette(hDC, hPal, TRUE);
4287         if (hOldPal)
4288             nCols = RealizePalette(hDC);
4289     }
4290     else
4291     {
4292         hDC = pFrame->mpLocalGraphics->getHDC();
4293         nCols = pFrame->mpLocalGraphics->setPalette(hPal);
4294     }
4295 
4296     bUpdate = nCols != 0 && nCols != GDI_ERROR;
4297 
4298     if ( !bStdDC )
4299     {
4300         if (hOldPal)
4301             SelectPalette(hDC, hOldPal, TRUE);
4302         ReleaseDC( hWnd, hDC );
4303     }
4304 
4305     // reset all palettes in VirDevs and Frames
4306     pTempVD = pSalData->mpFirstVD;
4307     while ( pTempVD )
4308     {
4309         pGraphics = pTempVD->getGraphics();
4310         if ( pGraphics->getDefPal() )
4311             pGraphics->setPalette(hPal);
4312         pTempVD = pTempVD->getNext();
4313     }
4314 
4315     pTempFrame = pSalData->mpFirstFrame;
4316     while ( pTempFrame )
4317     {
4318         if ( pTempFrame != pFrame )
4319         {
4320             pGraphics = pTempFrame->mpLocalGraphics;
4321             if (pGraphics && pGraphics->getDefPal())
4322             {
4323                 UINT nRes = pGraphics->setPalette(hPal);
4324                 if (nRes != 0 && nRes != GDI_ERROR)
4325                     bUpdate = true;
4326             }
4327         }
4328         pTempFrame = pTempFrame->mpNextFrame;
4329     }
4330 
4331     // if colors changed, update the window
4332     if ( bUpdate )
4333     {
4334         pTempFrame = pSalData->mpFirstFrame;
4335         while ( pTempFrame )
4336         {
4337             pGraphics = pTempFrame->mpLocalGraphics;
4338             if (pGraphics && pGraphics->getDefPal())
4339             {
4340                 InvalidateRect( pTempFrame->mhWnd, nullptr, FALSE );
4341                 UpdateWindow( pTempFrame->mhWnd );
4342                 pTempFrame->CallCallback( SalEvent::DisplayChanged, nullptr );
4343             }
4344             pTempFrame = pTempFrame->mpNextFrame;
4345         }
4346     }
4347 
4348     pSalData->mbInPalChange = false;
4349 
4350     if ( bReleaseMutex )
4351         ImplSalYieldMutexRelease();
4352 
4353     if ( nMsg == WM_PALETTECHANGED )
4354         return 0;
4355     else
4356         return nCols;
4357 }
4358 
4359 static bool ImplHandleMinMax( HWND hWnd, LPARAM lParam )
4360 {
4361     bool bRet = false;
4362 
4363     if ( ImplSalYieldMutexTryToAcquire() )
4364     {
4365         WinSalFrame* pFrame = GetWindowPtr( hWnd );
4366         if ( pFrame )
4367         {
4368             MINMAXINFO* pMinMax = reinterpret_cast<MINMAXINFO*>(lParam);
4369 
4370             if (pFrame->isFullScreen())
4371             {
4372                 int         nX;
4373                 int         nY;
4374                 int         nDX;
4375                 int         nDY;
4376                 ImplSalCalcFullScreenSize( pFrame, nX, nY, nDX, nDY );
4377 
4378                 if ( pMinMax->ptMaxPosition.x > nX )
4379                     pMinMax->ptMaxPosition.x = nX;
4380                 if ( pMinMax->ptMaxPosition.y > nY )
4381                     pMinMax->ptMaxPosition.y = nY;
4382 
4383                 if ( pMinMax->ptMaxSize.x < nDX )
4384                     pMinMax->ptMaxSize.x = nDX;
4385                 if ( pMinMax->ptMaxSize.y < nDY )
4386                     pMinMax->ptMaxSize.y = nDY;
4387                 if ( pMinMax->ptMaxTrackSize.x < nDX )
4388                     pMinMax->ptMaxTrackSize.x = nDX;
4389                 if ( pMinMax->ptMaxTrackSize.y < nDY )
4390                     pMinMax->ptMaxTrackSize.y = nDY;
4391 
4392                 pMinMax->ptMinTrackSize.x = nDX;
4393                 pMinMax->ptMinTrackSize.y = nDY;
4394 
4395                 bRet = true;
4396             }
4397 
4398             if ( pFrame->mnMinWidth || pFrame->mnMinHeight )
4399             {
4400                 int nWidth   = pFrame->mnMinWidth;
4401                 int nHeight  = pFrame->mnMinHeight;
4402 
4403                 ImplSalAddBorder( pFrame, nWidth, nHeight );
4404 
4405                 if ( pMinMax->ptMinTrackSize.x < nWidth )
4406                      pMinMax->ptMinTrackSize.x = nWidth;
4407                 if ( pMinMax->ptMinTrackSize.y < nHeight )
4408                      pMinMax->ptMinTrackSize.y = nHeight;
4409             }
4410 
4411             if ( pFrame->mnMaxWidth || pFrame->mnMaxHeight )
4412             {
4413                 int nWidth   = pFrame->mnMaxWidth;
4414                 int nHeight  = pFrame->mnMaxHeight;
4415 
4416                 ImplSalAddBorder( pFrame, nWidth, nHeight );
4417 
4418                 if( nWidth > 0 && nHeight > 0 ) // protect against int overflow due to INT_MAX initialisation
4419                 {
4420                     if ( pMinMax->ptMaxTrackSize.x > nWidth )
4421                         pMinMax->ptMaxTrackSize.x = nWidth;
4422                     if ( pMinMax->ptMaxTrackSize.y > nHeight )
4423                         pMinMax->ptMaxTrackSize.y = nHeight;
4424                 }
4425             }
4426         }
4427 
4428         ImplSalYieldMutexRelease();
4429     }
4430 
4431     return bRet;
4432 }
4433 
4434 // retrieves the SalMenuItem pointer from a hMenu
4435 // the pointer is stored in every item, so if no position
4436 // is specified we just use the first item (ie, pos=0)
4437 // if bByPosition is false then nPos denotes a menu id instead of a position
4438 static WinSalMenuItem* ImplGetSalMenuItem( HMENU hMenu, UINT nPos, bool bByPosition=true )
4439 {
4440     MENUITEMINFOW mi = {};
4441     mi.cbSize = sizeof( mi );
4442     mi.fMask = MIIM_DATA;
4443     if( !GetMenuItemInfoW( hMenu, nPos, bByPosition, &mi) )
4444         SAL_WARN("vcl", "GetMenuItemInfoW failed: " << WindowsErrorString(GetLastError()));
4445 
4446     return reinterpret_cast<WinSalMenuItem *>(mi.dwItemData);
4447 }
4448 
4449 // returns the index of the currently selected item if any or -1
4450 static int ImplGetSelectedIndex( HMENU hMenu )
4451 {
4452     MENUITEMINFOW mi = {};
4453     mi.cbSize = sizeof( mi );
4454     mi.fMask = MIIM_STATE;
4455     int n = GetMenuItemCount( hMenu );
4456     if( n != -1 )
4457     {
4458         for(int i=0; i<n; i++ )
4459         {
4460             if( !GetMenuItemInfoW( hMenu, i, TRUE, &mi) )
4461                 SAL_WARN( "vcl", "GetMenuItemInfoW failed: " << WindowsErrorString( GetLastError() ) );
4462             else
4463             {
4464                 if( mi.fState & MFS_HILITE )
4465                     return i;
4466             }
4467         }
4468     }
4469     return -1;
4470 }
4471 
4472 static LRESULT ImplMenuChar( HWND, WPARAM wParam, LPARAM lParam )
4473 {
4474     LRESULT nRet = MNC_IGNORE;
4475     HMENU hMenu = reinterpret_cast<HMENU>(lParam);
4476     OUString aMnemonic( "&" + OUStringChar(static_cast<sal_Unicode>(LOWORD(wParam))) );
4477     aMnemonic = aMnemonic.toAsciiLowerCase();   // we only have ascii mnemonics
4478 
4479     // search the mnemonic in the current menu
4480     int nItemCount = GetMenuItemCount( hMenu );
4481     int nFound = 0;
4482     int idxFound = -1;
4483     int idxSelected = ImplGetSelectedIndex( hMenu );
4484     int idx = idxSelected != -1 ? idxSelected+1 : 0;    // if duplicate mnemonics cycle through menu
4485     for( int i=0; i< nItemCount; i++, idx++ )
4486     {
4487         WinSalMenuItem* pSalMenuItem = ImplGetSalMenuItem( hMenu, idx % nItemCount );
4488         if( !pSalMenuItem )
4489             continue;
4490         OUString aStr = pSalMenuItem->mText;
4491         aStr = aStr.toAsciiLowerCase();
4492         if( aStr.indexOf( aMnemonic ) != -1 )
4493         {
4494             if( idxFound == -1 )
4495                 idxFound = idx % nItemCount;
4496             if( nFound++ )
4497                 break;  // duplicate found
4498         }
4499     }
4500     if( nFound == 1 )
4501         nRet = MAKELRESULT( idxFound, MNC_EXECUTE );
4502     else
4503         // duplicate mnemonics, just select the next occurrence
4504         nRet = MAKELRESULT( idxFound, MNC_SELECT );
4505 
4506     return nRet;
4507 }
4508 
4509 static LRESULT ImplMeasureItem( HWND hWnd, WPARAM wParam, LPARAM lParam )
4510 {
4511     LRESULT nRet = 0;
4512     if( !wParam )
4513     {
4514         // request was sent by a menu
4515         nRet = 1;
4516         MEASUREITEMSTRUCT *pMI = reinterpret_cast<LPMEASUREITEMSTRUCT>(lParam);
4517         if( pMI->CtlType != ODT_MENU )
4518             return 0;
4519 
4520         WinSalMenuItem *pSalMenuItem = reinterpret_cast<WinSalMenuItem *>(pMI->itemData);
4521         if( !pSalMenuItem )
4522             return 0;
4523 
4524         HDC hdc = GetDC( hWnd );
4525         SIZE strSize;
4526 
4527         NONCLIENTMETRICSW ncm = {};
4528         ncm.cbSize = sizeof( ncm );
4529         SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4530 
4531         // Assume every menu item can be default and printed bold
4532         //ncm.lfMenuFont.lfWeight = FW_BOLD;
4533 
4534         HFONT hfntOld = static_cast<HFONT>(SelectObject(hdc, CreateFontIndirectW( &ncm.lfMenuFont )));
4535 
4536         // menu text and accelerator
4537         OUString aStr(pSalMenuItem->mText);
4538         if( pSalMenuItem->mAccelText.getLength() )
4539         {
4540             aStr += " " + pSalMenuItem->mAccelText;
4541         }
4542         GetTextExtentPoint32W( hdc, o3tl::toW(aStr.getStr()),
4543                                 aStr.getLength(), &strSize );
4544 
4545         // image
4546         Size bmpSize( 16, 16 );
4547         //if( pSalMenuItem->maBitmap )
4548         //    bmpSize = pSalMenuItem->maBitmap.GetSizePixel();
4549 
4550         // checkmark
4551         Size checkSize( GetSystemMetrics( SM_CXMENUCHECK ), GetSystemMetrics( SM_CYMENUCHECK ) );
4552 
4553         pMI->itemWidth = checkSize.Width() + 3 + bmpSize.Width() + 3 + strSize.cx;
4554         pMI->itemHeight = std::max( std::max( checkSize.Height(), bmpSize.Height() ), tools::Long(strSize.cy) );
4555         pMI->itemHeight += 4;
4556 
4557         DeleteObject( SelectObject(hdc, hfntOld) );
4558         ReleaseDC( hWnd, hdc );
4559     }
4560 
4561     return nRet;
4562 }
4563 
4564 static LRESULT ImplDrawItem(HWND, WPARAM wParam, LPARAM lParam )
4565 {
4566     LRESULT nRet = 0;
4567     if( !wParam )
4568     {
4569         // request was sent by a menu
4570         nRet = 1;
4571         DRAWITEMSTRUCT *pDI = reinterpret_cast<LPDRAWITEMSTRUCT>(lParam);
4572         if( pDI->CtlType != ODT_MENU )
4573             return 0;
4574 
4575         WinSalMenuItem *pSalMenuItem = reinterpret_cast<WinSalMenuItem *>(pDI->itemData);
4576         if( !pSalMenuItem )
4577             return 0;
4578 
4579         COLORREF clrPrevText, clrPrevBkgnd;
4580         HFONT hfntOld;
4581         HBRUSH hbrOld;
4582         bool    fChecked = (pDI->itemState & ODS_CHECKED);
4583         bool    fSelected = (pDI->itemState & ODS_SELECTED);
4584         bool    fDisabled = (pDI->itemState & (ODS_DISABLED | ODS_GRAYED));
4585 
4586         // Set the appropriate foreground and background colors.
4587         RECT aRect = pDI->rcItem;
4588 
4589         if ( fDisabled )
4590             clrPrevText = SetTextColor( pDI->hDC, GetSysColor( COLOR_GRAYTEXT ) );
4591         else
4592             clrPrevText = SetTextColor( pDI->hDC, GetSysColor( fSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT ) );
4593 
4594         DWORD colBackground = GetSysColor( fSelected ? COLOR_HIGHLIGHT : COLOR_MENU );
4595         clrPrevBkgnd = SetBkColor( pDI->hDC, colBackground );
4596 
4597         hbrOld = static_cast<HBRUSH>(SelectObject( pDI->hDC, CreateSolidBrush( GetBkColor( pDI->hDC ) ) ));
4598 
4599         // Fill background
4600         if(!PatBlt( pDI->hDC, aRect.left, aRect.top, aRect.right-aRect.left, aRect.bottom-aRect.top, PATCOPY ))
4601             SAL_WARN("vcl", "PatBlt failed: " << WindowsErrorString(GetLastError()));
4602 
4603         int lineHeight = aRect.bottom-aRect.top;
4604 
4605         int x = aRect.left;
4606         int y = aRect.top;
4607 
4608         int checkWidth  = GetSystemMetrics( SM_CXMENUCHECK );
4609         int checkHeight = GetSystemMetrics( SM_CYMENUCHECK );
4610         if( fChecked )
4611         {
4612             RECT r;
4613             r.left = 0;
4614             r.top = 0;
4615             r.right = checkWidth;
4616             r.bottom = checkWidth;
4617             HDC memDC = CreateCompatibleDC( pDI->hDC );
4618             HBITMAP memBmp = CreateCompatibleBitmap( pDI->hDC, checkWidth, checkHeight );
4619             HBITMAP hOldBmp = static_cast<HBITMAP>(SelectObject( memDC, memBmp ));
4620             DrawFrameControl( memDC, &r, DFC_MENU, DFCS_MENUCHECK );
4621             BitBlt( pDI->hDC, x, y+(lineHeight-checkHeight)/2, checkWidth, checkHeight, memDC, 0, 0, SRCAND );
4622             DeleteObject( SelectObject( memDC, hOldBmp ) );
4623             DeleteDC( memDC );
4624         }
4625         x += checkWidth+3;
4626 
4627         //Size bmpSize = aBitmap.GetSizePixel();
4628         Size bmpSize(16, 16);
4629         if( !pSalMenuItem->maBitmap.IsEmpty() )
4630         {
4631             Bitmap aBitmap( pSalMenuItem->maBitmap );
4632 
4633             // set transparent pixels to background color
4634             if( fDisabled )
4635                 colBackground = RGB(255,255,255);
4636             aBitmap.Replace( COL_LIGHTMAGENTA,
4637                 Color( GetRValue(colBackground),GetGValue(colBackground),GetBValue(colBackground) ));
4638 
4639             WinSalBitmap* pSalBmp = static_cast<WinSalBitmap*>(aBitmap.ImplGetSalBitmap().get());
4640             HGLOBAL hDrawDIB = pSalBmp->ImplGethDIB();
4641 
4642             if( hDrawDIB )
4643             {
4644                 PBITMAPINFO         pBI = static_cast<PBITMAPINFO>(GlobalLock( hDrawDIB ));
4645                 PBYTE               pBits = reinterpret_cast<PBYTE>(pBI) + pBI->bmiHeader.biSize +
4646                                             WinSalBitmap::ImplGetDIBColorCount( hDrawDIB ) * sizeof( RGBQUAD );
4647 
4648                 HBITMAP hBmp = CreateDIBitmap( pDI->hDC, &pBI->bmiHeader, CBM_INIT, pBits, pBI, DIB_RGB_COLORS );
4649                 GlobalUnlock( hDrawDIB );
4650 
4651                 HBRUSH hbrIcon = CreateSolidBrush( GetSysColor( COLOR_GRAYTEXT ) );
4652                 DrawStateW( pDI->hDC, hbrIcon, nullptr, reinterpret_cast<LPARAM>(hBmp), WPARAM(0),
4653                     x, y+(lineHeight-bmpSize.Height())/2, bmpSize.Width(), bmpSize.Height(),
4654                      DST_BITMAP | (fDisabled ? (fSelected ? DSS_MONO : DSS_DISABLED) : DSS_NORMAL) );
4655 
4656                 DeleteObject( hbrIcon );
4657                 DeleteObject( hBmp );
4658             }
4659 
4660         }
4661         x += bmpSize.Width() + 3;
4662         aRect.left = x;
4663 
4664         NONCLIENTMETRICSW ncm = {};
4665         ncm.cbSize = sizeof( ncm );
4666         SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4667 
4668         // Print default menu entry with bold font
4669         //if ( pDI->itemState & ODS_DEFAULT )
4670         //    ncm.lfMenuFont.lfWeight = FW_BOLD;
4671 
4672         hfntOld = static_cast<HFONT>(SelectObject(pDI->hDC, CreateFontIndirectW( &ncm.lfMenuFont )));
4673 
4674         SIZE strSize;
4675         OUString aStr( pSalMenuItem->mText );
4676         GetTextExtentPoint32W( pDI->hDC, o3tl::toW(aStr.getStr()),
4677                                 aStr.getLength(), &strSize );
4678 
4679         if(!DrawStateW( pDI->hDC, nullptr, nullptr,
4680             reinterpret_cast<LPARAM>(aStr.getStr()),
4681             WPARAM(0), aRect.left, aRect.top + (lineHeight - strSize.cy)/2, 0, 0,
4682             DST_PREFIXTEXT | (fDisabled && !fSelected ? DSS_DISABLED : DSS_NORMAL) ) )
4683             SAL_WARN("vcl", "DrawStateW failed: " << WindowsErrorString(GetLastError()));
4684 
4685         if( pSalMenuItem->mAccelText.getLength() )
4686         {
4687             SIZE strSizeA;
4688             aStr = pSalMenuItem->mAccelText;
4689             GetTextExtentPoint32W( pDI->hDC, o3tl::toW(aStr.getStr()),
4690                                     aStr.getLength(), &strSizeA );
4691             TEXTMETRICW tm;
4692             GetTextMetricsW( pDI->hDC, &tm );
4693 
4694             // position the accelerator string to the right but leave space for the
4695             // (potential) submenu arrow (tm.tmMaxCharWidth)
4696             if(!DrawStateW( pDI->hDC, nullptr, nullptr,
4697                 reinterpret_cast<LPARAM>(aStr.getStr()),
4698                 WPARAM(0), aRect.right-strSizeA.cx-tm.tmMaxCharWidth, aRect.top + (lineHeight - strSizeA.cy)/2, 0, 0,
4699                 DST_TEXT | (fDisabled && !fSelected ? DSS_DISABLED : DSS_NORMAL) ) )
4700                 SAL_WARN("vcl", "DrawStateW failed: " << WindowsErrorString(GetLastError()));
4701         }
4702 
4703         // Restore the original font and colors.
4704         DeleteObject( SelectObject( pDI->hDC, hbrOld ) );
4705         DeleteObject( SelectObject( pDI->hDC, hfntOld) );
4706         SetTextColor(pDI->hDC, clrPrevText);
4707         SetBkColor(pDI->hDC, clrPrevBkgnd);
4708     }
4709     return nRet;
4710 }
4711 
4712 static bool ImplHandleMenuActivate( HWND hWnd, WPARAM wParam, LPARAM )
4713 {
4714     // Menu activation
4715     WinSalFrame* pFrame = GetWindowPtr( hWnd );
4716     if ( !pFrame )
4717         return false;
4718 
4719     HMENU hMenu = reinterpret_cast<HMENU>(wParam);
4720     // WORD nPos = LOWORD (lParam);
4721     // bool bWindowMenu = (bool) HIWORD(lParam);
4722 
4723     // Send activate and deactivate together, so we have not keep track of opened menus
4724     // this will be enough to have the menus updated correctly
4725     SalMenuEvent aMenuEvt;
4726     WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( hMenu, 0 );
4727     if( pSalMenuItem )
4728         aMenuEvt.mpMenu = pSalMenuItem->mpMenu;
4729     else
4730         aMenuEvt.mpMenu = nullptr;
4731 
4732     bool nRet = pFrame->CallCallback( SalEvent::MenuActivate, &aMenuEvt );
4733     if( nRet )
4734         nRet = pFrame->CallCallback( SalEvent::MenuDeactivate, &aMenuEvt );
4735     if( nRet )
4736         pFrame->mLastActivatedhMenu = hMenu;
4737 
4738     return nRet;
4739 }
4740 
4741 static bool ImplHandleMenuSelect( HWND hWnd, WPARAM wParam, LPARAM lParam )
4742 {
4743     // Menu selection
4744     WinSalFrame* pFrame = GetWindowPtr( hWnd );
4745     if ( !pFrame )
4746         return false;
4747 
4748     WORD nId = LOWORD(wParam);      // menu item or submenu index
4749     WORD nFlags = HIWORD(wParam);
4750     HMENU hMenu = reinterpret_cast<HMENU>(lParam);
4751 
4752     // check if we have to process the message
4753     if( !GetSalData()->IsKnownMenuHandle( hMenu ) )
4754         return false;
4755 
4756     bool bByPosition = false;
4757     if( nFlags & MF_POPUP )
4758         bByPosition = true;
4759 
4760     bool nRet = false;
4761     if ( hMenu && !pFrame->mLastActivatedhMenu )
4762     {
4763         // we never activated a menu (ie, no WM_INITMENUPOPUP has occurred yet)
4764         // which means this must be the menubar -> send activation/deactivation
4765         SalMenuEvent aMenuEvt;
4766         WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( hMenu, nId, bByPosition );
4767         if( pSalMenuItem )
4768             aMenuEvt.mpMenu = pSalMenuItem->mpMenu;
4769         else
4770             aMenuEvt.mpMenu = nullptr;
4771 
4772         nRet = pFrame->CallCallback( SalEvent::MenuActivate, &aMenuEvt );
4773         if( nRet )
4774             nRet = pFrame->CallCallback( SalEvent::MenuDeactivate, &aMenuEvt );
4775         if( nRet )
4776             pFrame->mLastActivatedhMenu = hMenu;
4777     }
4778 
4779     if( !hMenu && nFlags == 0xFFFF )
4780     {
4781         // all menus are closed, reset activation logic
4782         pFrame->mLastActivatedhMenu = nullptr;
4783     }
4784 
4785     if( hMenu )
4786     {
4787         // hMenu must be saved, as it is not passed in WM_COMMAND which always occurs after a selection
4788         // if a menu is closed due to a command selection then hMenu is NULL, but WM_COMMAND comes later
4789         // so we must not overwrite it in this case
4790         pFrame->mSelectedhMenu = hMenu;
4791 
4792         // send highlight event
4793         if( nFlags & MF_POPUP )
4794         {
4795             // submenu selected
4796             // wParam now carries an index instead of an id -> retrieve id
4797             MENUITEMINFOW mi = {};
4798             mi.cbSize = sizeof( mi );
4799             mi.fMask = MIIM_ID;
4800             if( GetMenuItemInfoW( hMenu, LOWORD(wParam), TRUE, &mi) )
4801                 nId = sal::static_int_cast<WORD>(mi.wID);
4802         }
4803 
4804         SalMenuEvent aMenuEvt;
4805         aMenuEvt.mnId   = nId;
4806         WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( hMenu, nId, false );
4807         if( pSalMenuItem )
4808             aMenuEvt.mpMenu = pSalMenuItem->mpMenu;
4809         else
4810             aMenuEvt.mpMenu = nullptr;
4811 
4812         nRet = pFrame->CallCallback( SalEvent::MenuHighlight, &aMenuEvt );
4813     }
4814 
4815     return nRet;
4816 }
4817 
4818 static bool ImplHandleCommand( HWND hWnd, WPARAM wParam, LPARAM )
4819 {
4820     WinSalFrame* pFrame = GetWindowPtr( hWnd );
4821     if ( !pFrame )
4822         return false;
4823 
4824     bool nRet = false;
4825     if( !HIWORD(wParam) )
4826     {
4827         // Menu command
4828         WORD nId = LOWORD(wParam);
4829         if( nId )   // zero for separators
4830         {
4831             SalMenuEvent aMenuEvt;
4832             aMenuEvt.mnId   = nId;
4833             WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( pFrame->mSelectedhMenu, nId, false );
4834             if( pSalMenuItem )
4835                 aMenuEvt.mpMenu = pSalMenuItem->mpMenu;
4836             else
4837                 aMenuEvt.mpMenu = nullptr;
4838 
4839             nRet = pFrame->CallCallback( SalEvent::MenuCommand, &aMenuEvt );
4840         }
4841     }
4842     return nRet;
4843 }
4844 
4845 static bool ImplHandleSysCommand( HWND hWnd, WPARAM wParam, LPARAM lParam )
4846 {
4847     WinSalFrame* pFrame = GetWindowPtr( hWnd );
4848     if ( !pFrame )
4849         return false;
4850 
4851     WPARAM nCommand = wParam & 0xFFF0;
4852 
4853     if (pFrame->isFullScreen())
4854     {
4855         bool    bMaximize = IsZoomed( pFrame->mhWnd );
4856         bool    bMinimize = IsIconic( pFrame->mhWnd );
4857         if ( (nCommand == SC_SIZE) ||
4858              (!bMinimize && (nCommand == SC_MOVE)) ||
4859              (!bMaximize && (nCommand == SC_MAXIMIZE)) ||
4860              (bMaximize && (nCommand == SC_RESTORE)) )
4861         {
4862             return true;
4863         }
4864     }
4865 
4866     if ( nCommand == SC_MOVE )
4867     {
4868         WinSalTimer* pTimer = static_cast<WinSalTimer*>( ImplGetSVData()->maSchedCtx.mpSalTimer );
4869         if ( pTimer )
4870             pTimer->SetForceRealTimer( true );
4871     }
4872 
4873     if ( nCommand == SC_KEYMENU )
4874     {
4875         // do not process SC_KEYMENU if we have a native menu
4876         // Windows should handle this
4877         if( GetMenu( hWnd ) )
4878             return false;
4879 
4880         // Process here KeyMenu events only for Alt to activate the MenuBar,
4881         // or if a SysChild window is in focus, as Alt-key-combinations are
4882         // only processed via this event
4883         if ( !LOWORD( lParam ) )
4884         {
4885             // Only trigger if no other key is pressed.
4886             // Contrary to Docu the CharCode is delivered with the x-coordinate
4887             // that is pressed in addition.
4888             // Also 32 for space, 99 for c, 100 for d, ...
4889             // As this is not documented, we check the state of the space-bar
4890             if ( GetKeyState( VK_SPACE ) & 0x8000 )
4891                 return false;
4892 
4893             // to avoid activating the MenuBar for Alt+MouseKey
4894             if ( (GetKeyState( VK_LBUTTON ) & 0x8000) ||
4895                  (GetKeyState( VK_RBUTTON ) & 0x8000) ||
4896                  (GetKeyState( VK_MBUTTON ) & 0x8000) ||
4897                  (GetKeyState( VK_SHIFT )   & 0x8000) )
4898                 return true;
4899 
4900             SalKeyEvent aKeyEvt;
4901             aKeyEvt.mnCode      = KEY_MENU;
4902             aKeyEvt.mnCharCode  = 0;
4903             aKeyEvt.mnRepeat    = 0;
4904             bool nRet = pFrame->CallCallback( SalEvent::KeyInput, &aKeyEvt );
4905             pFrame->CallCallback( SalEvent::KeyUp, &aKeyEvt );
4906             return nRet;
4907         }
4908         else
4909         {
4910             // check if a SysChild is in focus
4911             HWND hFocusWnd = ::GetFocus();
4912             if ( hFocusWnd && ImplFindSalObject( hFocusWnd ) )
4913             {
4914                 char cKeyCode = static_cast<char>(static_cast<unsigned char>(LOWORD( lParam )));
4915                 // LowerCase
4916                 if ( (cKeyCode >= 65) && (cKeyCode <= 90) )
4917                     cKeyCode += 32;
4918                 // We only accept 0-9 and A-Z; all other keys have to be
4919                 // processed by the SalObj hook
4920                 if ( ((cKeyCode >= 48) && (cKeyCode <= 57)) ||
4921                      ((cKeyCode >= 97) && (cKeyCode <= 122)) )
4922                 {
4923                     sal_uInt16 nModCode = 0;
4924                     if ( GetKeyState( VK_SHIFT ) & 0x8000 )
4925                         nModCode |= KEY_SHIFT;
4926                     if ( GetKeyState( VK_CONTROL ) & 0x8000 )
4927                         nModCode |= KEY_MOD1;
4928                     nModCode |= KEY_MOD2;
4929 
4930                     SalKeyEvent aKeyEvt;
4931                     if ( (cKeyCode >= 48) && (cKeyCode <= 57) )
4932                         aKeyEvt.mnCode = KEY_0+(cKeyCode-48);
4933                     else
4934                         aKeyEvt.mnCode = KEY_A+(cKeyCode-97);
4935                     aKeyEvt.mnCode     |= nModCode;
4936                     aKeyEvt.mnCharCode  = cKeyCode;
4937                     aKeyEvt.mnRepeat    = 0;
4938                     bool nRet = pFrame->CallCallback( SalEvent::KeyInput, &aKeyEvt );
4939                     pFrame->CallCallback( SalEvent::KeyUp, &aKeyEvt );
4940                     return nRet;
4941                 }
4942             }
4943         }
4944     }
4945 
4946     return false;
4947 }
4948 
4949 static void ImplHandleInputLangChange( HWND hWnd, WPARAM, LPARAM lParam )
4950 {
4951     ImplSalYieldMutexAcquireWithWait();
4952 
4953     // check if we support IME
4954     WinSalFrame* pFrame = GetWindowPtr( hWnd );
4955 
4956     if ( !pFrame )
4957         return;
4958 
4959     if ( pFrame->mbIME && pFrame->mhDefIMEContext )
4960     {
4961         HKL     hKL = reinterpret_cast<HKL>(lParam);
4962         UINT    nImeProps = ImmGetProperty( hKL, IGP_PROPERTY );
4963 
4964         pFrame->mbSpezIME = (nImeProps & IME_PROP_SPECIAL_UI) != 0;
4965         pFrame->mbAtCursorIME = (nImeProps & IME_PROP_AT_CARET) != 0;
4966         pFrame->mbHandleIME = !pFrame->mbSpezIME;
4967     }
4968 
4969     // trigger input language and codepage update
4970     UINT nLang = pFrame->mnInputLang;
4971     ImplUpdateInputLang( pFrame );
4972 
4973     // notify change
4974     if( nLang != pFrame->mnInputLang )
4975         pFrame->CallCallback( SalEvent::InputLanguageChange, nullptr );
4976 
4977     // reinit spec. keys
4978     GetSalData()->initKeyCodeMap();
4979 
4980     ImplSalYieldMutexRelease();
4981 }
4982 
4983 static void ImplUpdateIMECursorPos( WinSalFrame* pFrame, HIMC hIMC )
4984 {
4985     COMPOSITIONFORM aForm = {};
4986 
4987     // get cursor position and from it calculate default position
4988     // for the composition window
4989     SalExtTextInputPosEvent aPosEvt;
4990     pFrame->CallCallback( SalEvent::ExtTextInputPos, &aPosEvt );
4991     if ( (aPosEvt.mnX == -1) && (aPosEvt.mnY == -1) )
4992         aForm.dwStyle |= CFS_DEFAULT;
4993     else
4994     {
4995         aForm.dwStyle          |= CFS_POINT;
4996         aForm.ptCurrentPos.x    = aPosEvt.mnX;
4997         aForm.ptCurrentPos.y    = aPosEvt.mnY;
4998     }
4999     ImmSetCompositionWindow( hIMC, &aForm );
5000 
5001     // Because not all IME's use this values, we create
5002     // a Windows caret to force the Position from the IME
5003     if ( GetFocus() == pFrame->mhWnd )
5004     {
5005         CreateCaret( pFrame->mhWnd, nullptr,
5006                      aPosEvt.mnWidth, aPosEvt.mnHeight );
5007         SetCaretPos( aPosEvt.mnX, aPosEvt.mnY );
5008     }
5009 }
5010 
5011 static bool ImplHandleIMEStartComposition( HWND hWnd )
5012 {
5013     bool bDef = true;
5014 
5015     ImplSalYieldMutexAcquireWithWait();
5016 
5017     WinSalFrame* pFrame = GetWindowPtr( hWnd );
5018     if ( pFrame )
5019     {
5020         HIMC hIMC = ImmGetContext( hWnd );
5021         if ( hIMC )
5022         {
5023             ImplUpdateIMECursorPos( pFrame, hIMC );
5024             ImmReleaseContext( hWnd, hIMC );
5025         }
5026 
5027         if ( pFrame->mbHandleIME )
5028         {
5029             if ( pFrame->mbAtCursorIME )
5030                 bDef = false;
5031         }
5032     }
5033 
5034     ImplSalYieldMutexRelease();
5035 
5036     return bDef;
5037 }
5038 
5039 static bool ImplHandleIMECompositionInput( WinSalFrame* pFrame,
5040                                                HIMC hIMC, LPARAM lParam )
5041 {
5042     bool bDef = true;
5043 
5044     // Init Event
5045     SalExtTextInputEvent    aEvt;
5046     aEvt.mpTextAttr         = nullptr;
5047     aEvt.mnCursorPos        = 0;
5048     aEvt.mnCursorFlags      = 0;
5049 
5050     // If we get a result string, then we handle this input
5051     if ( lParam & GCS_RESULTSTR )
5052     {
5053         bDef = false;
5054 
5055         LONG nTextLen = ImmGetCompositionStringW( hIMC, GCS_RESULTSTR, nullptr, 0 ) / sizeof( WCHAR );
5056         if ( nTextLen >= 0 )
5057         {
5058             auto pTextBuf = std::make_unique<WCHAR[]>(nTextLen);
5059             ImmGetCompositionStringW( hIMC, GCS_RESULTSTR, pTextBuf.get(), nTextLen*sizeof( WCHAR ) );
5060             aEvt.maText = OUString( o3tl::toU(pTextBuf.get()), static_cast<sal_Int32>(nTextLen) );
5061         }
5062 
5063         aEvt.mnCursorPos = aEvt.maText.getLength();
5064         pFrame->CallCallback( SalEvent::ExtTextInput, &aEvt );
5065         pFrame->CallCallback( SalEvent::EndExtTextInput, nullptr );
5066         ImplUpdateIMECursorPos( pFrame, hIMC );
5067     }
5068 
5069     // If the IME doesn't support OnSpot input, then there is nothing to do
5070     if ( !pFrame->mbAtCursorIME )
5071         return !bDef;
5072 
5073     // If we get new Composition data, then we handle this new input
5074     if ( (lParam & (GCS_COMPSTR | GCS_COMPATTR)) ||
5075          ((lParam & GCS_CURSORPOS) && !(lParam & GCS_RESULTSTR)) )
5076     {
5077         bDef = false;
5078 
5079         std::unique_ptr<ExtTextInputAttr[]> pSalAttrAry;
5080         LONG    nTextLen = ImmGetCompositionStringW( hIMC, GCS_COMPSTR, nullptr, 0 ) / sizeof( WCHAR );
5081         if ( nTextLen > 0 )
5082         {
5083             {
5084                 auto pTextBuf = std::make_unique<WCHAR[]>(nTextLen);
5085                 ImmGetCompositionStringW( hIMC, GCS_COMPSTR, pTextBuf.get(), nTextLen*sizeof( WCHAR ) );
5086                 aEvt.maText = OUString( o3tl::toU(pTextBuf.get()), static_cast<sal_Int32>(nTextLen) );
5087             }
5088 
5089             std::unique_ptr<BYTE[]> pAttrBuf;
5090             LONG        nAttrLen = ImmGetCompositionStringW( hIMC, GCS_COMPATTR, nullptr, 0 );
5091             if ( nAttrLen > 0 )
5092             {
5093                 pAttrBuf.reset(new BYTE[nAttrLen]);
5094                 ImmGetCompositionStringW( hIMC, GCS_COMPATTR, pAttrBuf.get(), nAttrLen );
5095             }
5096 
5097             if ( pAttrBuf )
5098             {
5099                 sal_Int32 nTextLen2 = aEvt.maText.getLength();
5100                 pSalAttrAry.reset(new ExtTextInputAttr[nTextLen2]);
5101                 memset( pSalAttrAry.get(), 0, nTextLen2*sizeof( sal_uInt16 ) );
5102                 for( sal_Int32 i = 0; (i < nTextLen2) && (i < nAttrLen); i++ )
5103                 {
5104                     BYTE nWinAttr = pAttrBuf.get()[i];
5105                     ExtTextInputAttr   nSalAttr;
5106                     if ( nWinAttr == ATTR_TARGET_CONVERTED )
5107                     {
5108                         nSalAttr = ExtTextInputAttr::BoldUnderline;
5109                         aEvt.mnCursorFlags |= EXTTEXTINPUT_CURSOR_INVISIBLE;
5110                     }
5111                     else if ( nWinAttr == ATTR_CONVERTED )
5112                         nSalAttr = ExtTextInputAttr::DashDotUnderline;
5113                     else if ( nWinAttr == ATTR_TARGET_NOTCONVERTED )
5114                         nSalAttr = ExtTextInputAttr::Highlight;
5115                     else if ( nWinAttr == ATTR_INPUT_ERROR )
5116                         nSalAttr = ExtTextInputAttr::RedText | ExtTextInputAttr::DottedUnderline;
5117                     else /* ( nWinAttr == ATTR_INPUT ) */
5118                         nSalAttr = ExtTextInputAttr::DottedUnderline;
5119                     pSalAttrAry[i] = nSalAttr;
5120                 }
5121 
5122                 aEvt.mpTextAttr = pSalAttrAry.get();
5123             }
5124         }
5125 
5126         // Only when we get new composition data, we must send this event
5127         if ( (nTextLen > 0) || !(lParam & GCS_RESULTSTR) )
5128         {
5129             // End the mode, if the last character is deleted
5130             if ( !nTextLen )
5131             {
5132                 pFrame->CallCallback( SalEvent::ExtTextInput, &aEvt );
5133                 pFrame->CallCallback( SalEvent::EndExtTextInput, nullptr );
5134             }
5135             else
5136             {
5137                 // Because Cursor-Position and DeltaStart never updated
5138                 // from the korean input engine, we must handle this here
5139                 if ( lParam & CS_INSERTCHAR )
5140                 {
5141                     aEvt.mnCursorPos = nTextLen;
5142                     if ( aEvt.mnCursorPos && (lParam & CS_NOMOVECARET) )
5143                         aEvt.mnCursorPos--;
5144                 }
5145                 else
5146                     aEvt.mnCursorPos = LOWORD( ImmGetCompositionStringW( hIMC, GCS_CURSORPOS, nullptr, 0 ) );
5147 
5148                 if ( pFrame->mbCandidateMode )
5149                     aEvt.mnCursorFlags |= EXTTEXTINPUT_CURSOR_INVISIBLE;
5150                 if ( lParam & CS_NOMOVECARET )
5151                     aEvt.mnCursorFlags |= EXTTEXTINPUT_CURSOR_OVERWRITE;
5152 
5153                 pFrame->CallCallback( SalEvent::ExtTextInput, &aEvt );
5154             }
5155             ImplUpdateIMECursorPos( pFrame, hIMC );
5156         }
5157     }
5158 
5159     return !bDef;
5160 }
5161 
5162 static bool ImplHandleIMEComposition( HWND hWnd, LPARAM lParam )
5163 {
5164     bool bDef = true;
5165     ImplSalYieldMutexAcquireWithWait();
5166 
5167     WinSalFrame* pFrame = GetWindowPtr( hWnd );
5168     if ( pFrame && (!lParam || (lParam & GCS_RESULTSTR)) )
5169     {
5170         // reset the background mode for each text input,
5171         // as some tools such as RichWin may have changed it
5172         if ( pFrame->mpLocalGraphics &&
5173              pFrame->mpLocalGraphics->getHDC() )
5174             SetBkMode( pFrame->mpLocalGraphics->getHDC(), TRANSPARENT );
5175     }
5176 
5177     if ( pFrame && pFrame->mbHandleIME )
5178     {
5179         if ( !lParam )
5180         {
5181             SalExtTextInputEvent aEvt;
5182             aEvt.mpTextAttr         = nullptr;
5183             aEvt.mnCursorPos        = 0;
5184             aEvt.mnCursorFlags      = 0;
5185             pFrame->CallCallback( SalEvent::ExtTextInput, &aEvt );
5186             pFrame->CallCallback( SalEvent::EndExtTextInput, nullptr );
5187         }
5188         else if ( lParam & (GCS_RESULTSTR | GCS_COMPSTR | GCS_COMPATTR | GCS_CURSORPOS) )
5189         {
5190             HIMC hIMC = ImmGetContext( hWnd );
5191             if ( hIMC )
5192             {
5193                 if ( ImplHandleIMECompositionInput( pFrame, hIMC, lParam ) )
5194                     bDef = false;
5195 
5196                 ImmReleaseContext( hWnd, hIMC );
5197             }
5198         }
5199     }
5200 
5201     ImplSalYieldMutexRelease();
5202     return bDef;
5203 }
5204 
5205 static bool ImplHandleIMEEndComposition( HWND hWnd )
5206 {
5207     bool bDef = true;
5208 
5209     ImplSalYieldMutexAcquireWithWait();
5210 
5211     WinSalFrame* pFrame = GetWindowPtr( hWnd );
5212     if ( pFrame && pFrame->mbHandleIME )
5213     {
5214         if ( pFrame->mbAtCursorIME )
5215         {
5216             pFrame->mbCandidateMode = false;
5217             bDef = false;
5218         }
5219     }
5220 
5221     ImplSalYieldMutexRelease();
5222 
5223     return bDef;
5224 }
5225 
5226 static bool ImplHandleAppCommand( HWND hWnd, LPARAM lParam, LRESULT & nRet )
5227 {
5228     MediaCommand nCommand;
5229     switch( GET_APPCOMMAND_LPARAM(lParam) )
5230     {
5231     case APPCOMMAND_MEDIA_CHANNEL_DOWN:         nCommand = MediaCommand::ChannelDown; break;
5232     case APPCOMMAND_MEDIA_CHANNEL_UP:           nCommand = MediaCommand::ChannelUp; break;
5233     case APPCOMMAND_MEDIA_NEXTTRACK:            nCommand = MediaCommand::NextTrack; break;
5234     case APPCOMMAND_MEDIA_PAUSE:                nCommand = MediaCommand::Pause; break;
5235     case APPCOMMAND_MEDIA_PLAY:                 nCommand = MediaCommand::Play; break;
5236     case APPCOMMAND_MEDIA_PLAY_PAUSE:           nCommand = MediaCommand::PlayPause; break;
5237     case APPCOMMAND_MEDIA_PREVIOUSTRACK:        nCommand = MediaCommand::PreviousTrack; break;
5238     case APPCOMMAND_MEDIA_RECORD:               nCommand = MediaCommand::Record; break;
5239     case APPCOMMAND_MEDIA_REWIND:               nCommand = MediaCommand::Rewind; break;
5240     case APPCOMMAND_MEDIA_STOP:                 nCommand = MediaCommand::Stop; break;
5241     case APPCOMMAND_MIC_ON_OFF_TOGGLE:          nCommand = MediaCommand::MicOnOffToggle; break;
5242     case APPCOMMAND_MICROPHONE_VOLUME_DOWN:     nCommand = MediaCommand::MicrophoneVolumeDown; break;
5243     case APPCOMMAND_MICROPHONE_VOLUME_MUTE:     nCommand = MediaCommand::MicrophoneVolumeMute; break;
5244     case APPCOMMAND_MICROPHONE_VOLUME_UP:       nCommand = MediaCommand::MicrophoneVolumeUp; break;
5245     case APPCOMMAND_VOLUME_DOWN:                nCommand = MediaCommand::VolumeDown; break;
5246     case APPCOMMAND_VOLUME_MUTE:                nCommand = MediaCommand::VolumeMute; break;
5247     case APPCOMMAND_VOLUME_UP:                  nCommand = MediaCommand::VolumeUp; break;
5248     default:
5249         return false;
5250     }
5251 
5252     WinSalFrame* pFrame = GetWindowPtr( hWnd );
5253     vcl::Window *pWindow = pFrame ? pFrame->GetWindow() : nullptr;
5254 
5255     if( pWindow )
5256     {
5257         const Point aPoint;
5258         CommandMediaData aMediaData(nCommand);
5259         CommandEvent aCEvt( aPoint, CommandEventId::Media, false, &aMediaData );
5260         NotifyEvent aNCmdEvt( NotifyEventType::COMMAND, pWindow, &aCEvt );
5261 
5262         if ( !ImplCallPreNotify( aNCmdEvt ) )
5263         {
5264             pWindow->Command( aCEvt );
5265             nRet = 1;
5266             return !aMediaData.GetPassThroughToOS();
5267         }
5268     }
5269 
5270     return false;
5271 }
5272 
5273 static void ImplHandleIMENotify( HWND hWnd, WPARAM wParam )
5274 {
5275     if ( wParam == WPARAM(IMN_OPENCANDIDATE) )
5276     {
5277         ImplSalYieldMutexAcquireWithWait();
5278 
5279         WinSalFrame* pFrame = GetWindowPtr( hWnd );
5280         if ( pFrame && pFrame->mbHandleIME &&
5281              pFrame->mbAtCursorIME )
5282         {
5283             // we want to hide the cursor
5284             pFrame->mbCandidateMode = true;
5285             ImplHandleIMEComposition( hWnd, GCS_CURSORPOS );
5286 
5287             HWND hWnd2 = pFrame->mhWnd;
5288             HIMC hIMC = ImmGetContext( hWnd2 );
5289             if ( hIMC )
5290             {
5291                 LONG nBufLen = ImmGetCompositionStringW( hIMC, GCS_COMPSTR, nullptr, 0 );
5292                 if ( nBufLen >= 1 )
5293                 {
5294                     SalExtTextInputPosEvent aPosEvt;
5295                     pFrame->CallCallback( SalEvent::ExtTextInputPos, &aPosEvt );
5296 
5297                     // Vertical !!!
5298                     CANDIDATEFORM aForm;
5299                     aForm.dwIndex           = 0;
5300                     aForm.dwStyle           = CFS_EXCLUDE;
5301                     aForm.ptCurrentPos.x    = aPosEvt.mnX;
5302                     aForm.ptCurrentPos.y    = aPosEvt.mnY+1;
5303                     aForm.rcArea.left       = aPosEvt.mnX;
5304                     aForm.rcArea.top        = aPosEvt.mnY;
5305                     aForm.rcArea.right      = aForm.rcArea.left+aPosEvt.mnExtWidth+1;
5306                     aForm.rcArea.bottom     = aForm.rcArea.top+aPosEvt.mnHeight+1;
5307                     ImmSetCandidateWindow( hIMC, &aForm );
5308                 }
5309 
5310                 ImmReleaseContext( hWnd2, hIMC );
5311             }
5312         }
5313 
5314         ImplSalYieldMutexRelease();
5315     }
5316     else if ( wParam == WPARAM(IMN_CLOSECANDIDATE) )
5317     {
5318         ImplSalYieldMutexAcquireWithWait();
5319         WinSalFrame* pFrame = GetWindowPtr( hWnd );
5320         if ( pFrame )
5321             pFrame->mbCandidateMode = false;
5322         ImplSalYieldMutexRelease();
5323     }
5324 }
5325 
5326 static bool
5327 ImplHandleGetObject(HWND hWnd, LPARAM lParam, WPARAM wParam, LRESULT & nRet)
5328 {
5329     if (!Application::GetSettings().GetMiscSettings().GetEnableATToolSupport())
5330     {
5331         // IA2 should be enabled automatically
5332         AllSettings aSettings = Application::GetSettings();
5333         MiscSettings aMisc = aSettings.GetMiscSettings();
5334         aMisc.SetEnableATToolSupport(true);
5335         // The above is enough, since aMisc changes the same shared ImplMiscData as used in global
5336         // settings, so no need to call aSettings.SetMiscSettings and Application::SetSettings
5337 
5338         if (!Application::GetSettings().GetMiscSettings().GetEnableATToolSupport())
5339             return false; // locked down somehow ?
5340     }
5341 
5342     ImplSVData* pSVData = ImplGetSVData();
5343 
5344     // Make sure to launch Accessibility only the following criteria are satisfied
5345     // to avoid RFT interrupts regular accessibility processing
5346     if ( !pSVData->mxAccessBridge.is() )
5347     {
5348         if( !InitAccessBridge() )
5349             return false;
5350     }
5351 
5352     uno::Reference< accessibility::XMSAAService > xMSAA( pSVData->mxAccessBridge, uno::UNO_QUERY );
5353     if ( xMSAA.is() )
5354     {
5355         sal_Int32 lParam32 = static_cast<sal_Int32>(lParam);
5356         sal_uInt32 wParam32 = static_cast<sal_uInt32>(wParam);
5357 
5358         // mhOnSetTitleWnd not set to reasonable value anywhere...
5359         if ( lParam32 == OBJID_CLIENT )
5360         {
5361             nRet = xMSAA->getAccObjectPtr(
5362                     reinterpret_cast<sal_Int64>(hWnd), lParam32, wParam32);
5363             if (nRet != 0)
5364                 return true;
5365         }
5366     }
5367     return false;
5368 }
5369 
5370 static LRESULT ImplHandleIMEReconvertString( HWND hWnd, LPARAM lParam )
5371 {
5372     WinSalFrame* pFrame = GetWindowPtr( hWnd );
5373     LPRECONVERTSTRING pReconvertString = reinterpret_cast<LPRECONVERTSTRING>(lParam);
5374     LRESULT nRet = 0;
5375     SalSurroundingTextRequestEvent aEvt;
5376     aEvt.maText.clear();
5377     aEvt.mnStart = aEvt.mnEnd = 0;
5378 
5379     UINT nImeProps = ImmGetProperty( GetKeyboardLayout( 0 ), IGP_SETCOMPSTR );
5380     if( (nImeProps & SCS_CAP_SETRECONVERTSTRING) == 0 )
5381     {
5382         // This IME does not support reconversion.
5383         return 0;
5384     }
5385 
5386     if( !pReconvertString )
5387     {
5388         // The first call for reconversion.
5389         pFrame->CallCallback( SalEvent::StartReconversion, nullptr );
5390 
5391         // Retrieve the surrounding text from the focused control.
5392         pFrame->CallCallback( SalEvent::SurroundingTextRequest, &aEvt );
5393 
5394         if( aEvt.maText.isEmpty())
5395         {
5396             return 0;
5397         }
5398 
5399         nRet = sizeof(RECONVERTSTRING) + (aEvt.maText.getLength() + 1) * sizeof(WCHAR);
5400     }
5401     else
5402     {
5403         // The second call for reconversion.
5404 
5405         // Retrieve the surrounding text from the focused control.
5406         pFrame->CallCallback( SalEvent::SurroundingTextRequest, &aEvt );
5407         nRet = sizeof(RECONVERTSTRING) + (aEvt.maText.getLength() + 1) * sizeof(WCHAR);
5408 
5409         pReconvertString->dwStrOffset = sizeof(RECONVERTSTRING);
5410         pReconvertString->dwStrLen = aEvt.maText.getLength();
5411         pReconvertString->dwCompStrOffset = aEvt.mnStart * sizeof(WCHAR);
5412         pReconvertString->dwCompStrLen = aEvt.mnEnd - aEvt.mnStart;
5413         pReconvertString->dwTargetStrOffset = pReconvertString->dwCompStrOffset;
5414         pReconvertString->dwTargetStrLen = pReconvertString->dwCompStrLen;
5415 
5416         memcpy( pReconvertString + 1, aEvt.maText.getStr(), (aEvt.maText.getLength() + 1) * sizeof(WCHAR) );
5417     }
5418 
5419     // just return the required size of buffer to reconvert.
5420     return nRet;
5421 }
5422 
5423 static LRESULT ImplHandleIMEConfirmReconvertString( HWND hWnd, LPARAM lParam )
5424 {
5425     WinSalFrame* pFrame = GetWindowPtr( hWnd );
5426     LPRECONVERTSTRING pReconvertString = reinterpret_cast<LPRECONVERTSTRING>(lParam);
5427     SalSurroundingTextRequestEvent aEvt;
5428     aEvt.maText.clear();
5429     aEvt.mnStart = aEvt.mnEnd = 0;
5430 
5431     pFrame->CallCallback( SalEvent::SurroundingTextRequest, &aEvt );
5432 
5433     sal_uLong nTmpStart = pReconvertString->dwCompStrOffset / sizeof(WCHAR);
5434     sal_uLong nTmpEnd = nTmpStart + pReconvertString->dwCompStrLen;
5435 
5436     if( nTmpStart != aEvt.mnStart || nTmpEnd != aEvt.mnEnd )
5437     {
5438         SalSurroundingTextSelectionChangeEvent aSelEvt { nTmpStart, nTmpEnd };
5439         pFrame->CallCallback( SalEvent::SurroundingTextSelectionChange, &aSelEvt );
5440     }
5441 
5442     return TRUE;
5443 }
5444 
5445 static LRESULT ImplHandleIMEQueryCharPosition( HWND hWnd, LPARAM lParam ) {
5446     WinSalFrame* pFrame = GetWindowPtr( hWnd );
5447     PIMECHARPOSITION pQueryCharPosition = reinterpret_cast<PIMECHARPOSITION>(lParam);
5448     if ( pQueryCharPosition->dwSize < sizeof(IMECHARPOSITION) )
5449         return FALSE;
5450 
5451     SalQueryCharPositionEvent aEvt;
5452     aEvt.mbValid = false;
5453     aEvt.mnCharPos = pQueryCharPosition->dwCharPos;
5454 
5455     pFrame->CallCallback( SalEvent::QueryCharPosition, &aEvt );
5456 
5457     if ( !aEvt.mbValid )
5458         return FALSE;
5459 
5460     if ( aEvt.mbVertical )
5461     {
5462         // For vertical writing, the base line is left edge of the rectangle
5463         // and the target position is top-right corner.
5464         pQueryCharPosition->pt.x = aEvt.mnCursorBoundX + aEvt.mnCursorBoundWidth;
5465         pQueryCharPosition->pt.y = aEvt.mnCursorBoundY;
5466         pQueryCharPosition->cLineHeight = aEvt.mnCursorBoundWidth;
5467     }
5468     else
5469     {
5470         // For horizontal writing, the base line is the bottom edge of the rectangle.
5471         // and the target position is top-left corner.
5472         pQueryCharPosition->pt.x = aEvt.mnCursorBoundX;
5473         pQueryCharPosition->pt.y = aEvt.mnCursorBoundY;
5474         pQueryCharPosition->cLineHeight = aEvt.mnCursorBoundHeight;
5475     }
5476 
5477     // Currently not supported but many IMEs usually ignore them.
5478     pQueryCharPosition->rcDocument.left = 0;
5479     pQueryCharPosition->rcDocument.top = 0;
5480     pQueryCharPosition->rcDocument.right = 0;
5481     pQueryCharPosition->rcDocument.bottom = 0;
5482 
5483     return TRUE;
5484 }
5485 
5486 void SalTestMouseLeave()
5487 {
5488     SalData* pSalData = GetSalData();
5489 
5490     if ( pSalData->mhWantLeaveMsg && !::GetCapture() )
5491     {
5492         POINT aPt;
5493         GetCursorPos( &aPt );
5494 
5495         // a one item cache, because this function is sometimes hot - if the cursor has not moved, then
5496         // no need to call WindowFromPoint
5497         static POINT cachedPoint;
5498         if (cachedPoint.x == aPt.x && cachedPoint.y == aPt.y)
5499             return;
5500         cachedPoint = aPt;
5501 
5502         if ( pSalData->mhWantLeaveMsg != WindowFromPoint( aPt ) )
5503             SendMessageW( pSalData->mhWantLeaveMsg, SAL_MSG_MOUSELEAVE, 0, MAKELPARAM( aPt.x, aPt.y ) );
5504     }
5505 }
5506 
5507 static bool ImplSalWheelMousePos( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ,
5508                                  LRESULT& rResult )
5509 {
5510     POINT aPt;
5511     POINT aScreenPt;
5512     aScreenPt.x = static_cast<short>(LOWORD( lParam ));
5513     aScreenPt.y = static_cast<short>(HIWORD( lParam ));
5514     // find child window that is at this position
5515     HWND hChildWnd;
5516     HWND hWheelWnd = hWnd;
5517     do
5518     {
5519         hChildWnd = hWheelWnd;
5520         aPt = aScreenPt;
5521         ScreenToClient( hChildWnd, &aPt );
5522         hWheelWnd = ChildWindowFromPointEx( hChildWnd, aPt, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT );
5523     }
5524     while ( hWheelWnd && (hWheelWnd != hChildWnd) );
5525     if ( hWheelWnd && (hWheelWnd != hWnd) &&
5526          (hWheelWnd != ::GetFocus()) && IsWindowEnabled( hWheelWnd ) )
5527     {
5528         rResult = SendMessageW( hWheelWnd, nMsg, wParam, lParam );
5529         return false;
5530     }
5531 
5532     return true;
5533 }
5534 
5535 static LRESULT CALLBACK SalFrameWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, bool& rDef )
5536 {
5537     LRESULT     nRet = 0;
5538     static bool  bInWheelMsg = false;
5539     static bool  bInQueryEnd = false;
5540 
5541     SAL_INFO("vcl.gdi.wndproc", "SalFrameWndProc(nMsg=" << nMsg << ", wParam=" << wParam << ", lParam=" << lParam << ")");
5542 
5543     // By WM_CREATE we connect the frame with the window handle
5544     if ( nMsg == WM_CREATE )
5545     {
5546         // Save Window-Instance in Windowhandle
5547         // Can also be used for the A-Version, because the struct
5548         // to access lpCreateParams is the same structure
5549         CREATESTRUCTW* pStruct = reinterpret_cast<CREATESTRUCTW*>(lParam);
5550         WinSalFrame* pFrame = static_cast<WinSalFrame*>(pStruct->lpCreateParams);
5551         if ( pFrame != nullptr )
5552         {
5553             SetWindowPtr( hWnd, pFrame );
5554 
5555             UpdateDarkMode(hWnd);
5556 
5557             // Set HWND already here, as data might be used already
5558             // when messages are being sent by CreateWindow()
5559             pFrame->mhWnd = hWnd;
5560             pFrame->maSysData.hWnd = hWnd;
5561         }
5562         return 0;
5563     }
5564 
5565     ImplSVData* pSVData = ImplGetSVData();
5566     // #i72707# TODO: the mbDeInit check will not be needed
5567     // once all windows that are not properly closed on exit got fixed
5568     if( pSVData->mbDeInit )
5569         return 0;
5570 
5571     if ( WM_USER_SYSTEM_WINDOW_ACTIVATED == nMsg )
5572     {
5573         ImplHideSplash();
5574         return 0;
5575     }
5576 
5577     switch( nMsg )
5578     {
5579         case WM_MOUSEMOVE:
5580         case WM_LBUTTONDOWN:
5581         case WM_MBUTTONDOWN:
5582         case WM_RBUTTONDOWN:
5583         case WM_LBUTTONUP:
5584         case WM_MBUTTONUP:
5585         case WM_RBUTTONUP:
5586         case WM_NCMOUSEMOVE:
5587         case SAL_MSG_MOUSELEAVE:
5588             ImplSalYieldMutexAcquireWithWait();
5589             rDef = !ImplHandleMouseMsg( hWnd, nMsg, wParam, lParam );
5590             ImplSalYieldMutexRelease();
5591             break;
5592 
5593         case WM_NCLBUTTONDOWN:
5594         case WM_NCMBUTTONDOWN:
5595         case WM_NCRBUTTONDOWN:
5596             ImplSalYieldMutexAcquireWithWait();
5597             ImplCallClosePopupsHdl( hWnd );   // close popups...
5598             ImplSalYieldMutexRelease();
5599             break;
5600 
5601         case WM_MOUSEACTIVATE:
5602             if ( LOWORD( lParam ) == HTCLIENT )
5603             {
5604                 ImplSalYieldMutexAcquireWithWait();
5605                 nRet = LRESULT(ImplHandleMouseActivateMsg( hWnd ));
5606                 ImplSalYieldMutexRelease();
5607                 if ( nRet )
5608                 {
5609                     nRet = MA_NOACTIVATE;
5610                     rDef = false;
5611                 }
5612             }
5613             break;
5614 
5615         case WM_KEYDOWN:
5616         case WM_KEYUP:
5617         case WM_DEADCHAR:
5618         case WM_CHAR:
5619         case WM_UNICHAR:    // MCD, 2003-01-13, Support for WM_UNICHAR & Keyman 6.0
5620         case WM_SYSKEYDOWN:
5621         case WM_SYSKEYUP:
5622         case WM_SYSCHAR:
5623             ImplSalYieldMutexAcquireWithWait();
5624             rDef = !ImplHandleKeyMsg( hWnd, nMsg, wParam, lParam, nRet );
5625             ImplSalYieldMutexRelease();
5626             break;
5627 
5628         case WM_MOUSEWHEEL:
5629         case WM_MOUSEHWHEEL:
5630             // protect against recursion, in case the message is returned
5631             // by IE or the external window
5632             if ( !bInWheelMsg )
5633             {
5634                 bInWheelMsg = true;
5635                 rDef = !ImplHandleWheelMsg( hWnd, nMsg, wParam, lParam );
5636                 // If we did not process the message, re-check if here is a
5637                 // connected (?) window that we have to notify.
5638                 if ( rDef )
5639                     rDef = ImplSalWheelMousePos( hWnd, nMsg, wParam, lParam, nRet );
5640                 bInWheelMsg = false;
5641             }
5642             break;
5643 
5644         case WM_COMMAND:
5645             ImplSalYieldMutexAcquireWithWait();
5646             rDef = !ImplHandleCommand( hWnd, wParam, lParam );
5647             ImplSalYieldMutexRelease();
5648             break;
5649 
5650         case WM_INITMENUPOPUP:
5651             ImplSalYieldMutexAcquireWithWait();
5652             rDef = !ImplHandleMenuActivate( hWnd, wParam, lParam );
5653             ImplSalYieldMutexRelease();
5654             break;
5655 
5656         case WM_MENUSELECT:
5657             ImplSalYieldMutexAcquireWithWait();
5658             rDef = !ImplHandleMenuSelect( hWnd, wParam, lParam );
5659             ImplSalYieldMutexRelease();
5660             break;
5661 
5662         case WM_SYSCOMMAND:
5663             ImplSalYieldMutexAcquireWithWait();
5664             nRet = LRESULT(ImplHandleSysCommand( hWnd, wParam, lParam ));
5665             ImplSalYieldMutexRelease();
5666             if ( nRet )
5667                 rDef = false;
5668             break;
5669 
5670         case WM_MENUCHAR:
5671             nRet = ImplMenuChar( hWnd, wParam, lParam );
5672             if( nRet )
5673                 rDef = false;
5674             break;
5675 
5676         case WM_MEASUREITEM:
5677             nRet = ImplMeasureItem(hWnd, wParam, lParam);
5678             if( nRet )
5679                 rDef = false;
5680             break;
5681 
5682         case WM_DRAWITEM:
5683             nRet = ImplDrawItem(hWnd, wParam, lParam);
5684             if( nRet )
5685                 rDef = false;
5686             break;
5687 
5688         case WM_MOVE:
5689             ImplHandleMoveMsg(hWnd, lParam);
5690             rDef = false;
5691             break;
5692         case SAL_MSG_POSTMOVE:
5693             ImplCallMoveHdl(hWnd);
5694             rDef = false;
5695             break;
5696         case WM_SIZE:
5697             ImplHandleSizeMsg(hWnd, wParam, lParam);
5698             rDef = false;
5699             break;
5700         case SAL_MSG_POSTCALLSIZE:
5701             ImplCallSizeHdl( hWnd );
5702             rDef = false;
5703             break;
5704 
5705         case WM_GETMINMAXINFO:
5706             if ( ImplHandleMinMax( hWnd, lParam ) )
5707                 rDef = false;
5708             break;
5709 
5710         case WM_ERASEBKGND:
5711             nRet = 1;
5712             rDef = false;
5713             break;
5714         case WM_PAINT:
5715             ImplHandlePaintMsg( hWnd );
5716             rDef = false;
5717             break;
5718         case SAL_MSG_POSTPAINT:
5719             ImplHandlePostPaintMsg( hWnd, reinterpret_cast<RECT*>(wParam) );
5720             rDef = false;
5721             break;
5722 
5723         case SAL_MSG_FORCEPALETTE:
5724             ImplHandleForcePalette( hWnd );
5725             rDef = false;
5726             break;
5727 
5728         case WM_QUERYNEWPALETTE:
5729         case SAL_MSG_POSTQUERYNEWPAL:
5730             nRet = ImplHandlePalette( true, hWnd, nMsg, wParam, lParam, rDef );
5731             break;
5732 
5733         case WM_ACTIVATE:
5734             // Getting activated, we also want to set our palette.
5735             // We do this in Activate, so that other external child windows
5736             // can overwrite our palette. Thus our palette is set only once
5737             // and not recursively, as at all other places it is set only as
5738             // the background palette.
5739             if ( LOWORD( wParam ) != WA_INACTIVE )
5740                 SendMessageW( hWnd, SAL_MSG_FORCEPALETTE, 0, 0 );
5741             break;
5742 
5743         case WM_ENABLE:
5744             // #95133# a system dialog is opened/closed, using our app window as parent
5745             {
5746                 WinSalFrame* pFrame = GetWindowPtr( hWnd );
5747                 vcl::Window *pWin = nullptr;
5748                 if( pFrame )
5749                     pWin = pFrame->GetWindow();
5750 
5751                 if( !wParam )
5752                 {
5753                     pSVData->maAppData.mnModalMode++;
5754 
5755                     ImplHideSplash();
5756                     if( pWin )
5757                     {
5758                         pWin->EnableInput( false, nullptr );
5759                         pWin->IncModalCount();  // #106303# support frame based modal count
5760                     }
5761                 }
5762                 else
5763                 {
5764                     ImplGetSVData()->maAppData.mnModalMode--;
5765                     if( pWin )
5766                     {
5767                         pWin->EnableInput( true, nullptr );
5768                         pWin->DecModalCount();  // #106303# support frame based modal count
5769                     }
5770                 }
5771             }
5772             break;
5773 
5774         case WM_KILLFOCUS:
5775             DestroyCaret();
5776             [[fallthrough]];
5777         case WM_SETFOCUS:
5778         case SAL_MSG_POSTFOCUS:
5779             ImplHandleFocusMsg( hWnd );
5780             rDef = false;
5781             break;
5782 
5783         case WM_CLOSE:
5784             ImplHandleCloseMsg( hWnd );
5785             rDef = false;
5786             break;
5787 
5788         case WM_QUERYENDSESSION:
5789             if( !bInQueryEnd )
5790             {
5791                 // handle queryendsession only once
5792                 bInQueryEnd = true;
5793                 nRet = LRESULT(!ImplHandleShutDownMsg( hWnd ));
5794                 rDef = false;
5795 
5796                 // Issue #16314#: ImplHandleShutDownMsg causes a PostMessage in case of allowing shutdown.
5797                 // This posted message was never processed and cause Windows XP to hang after log off
5798                 // if there are multiple sessions and the current session wasn't the first one started.
5799                 // So if shutdown is allowed we assume that a post message was done and retrieve all
5800                 // messages in the message queue and dispatch them before we return control to the system.
5801 
5802                 if ( nRet )
5803                 {
5804                     SolarMutexGuard aGuard;
5805                     while ( Application::Reschedule( true ) );
5806                 }
5807             }
5808             else
5809             {
5810                 ImplSalYieldMutexAcquireWithWait();
5811                 ImplSalYieldMutexRelease();
5812                 rDef = true;
5813             }
5814             break;
5815 
5816         case WM_ENDSESSION:
5817             if( !wParam )
5818                 bInQueryEnd = false; // no shutdown: allow query again
5819             nRet = FALSE;
5820             rDef = false;
5821             break;
5822 
5823         case WM_DISPLAYCHANGE:
5824         case WM_SETTINGCHANGE:
5825         case WM_DEVMODECHANGE:
5826         case WM_FONTCHANGE:
5827         case WM_SYSCOLORCHANGE:
5828         case WM_TIMECHANGE:
5829             ImplHandleSettingsChangeMsg( hWnd, nMsg, wParam, lParam );
5830             break;
5831 
5832         case WM_THEMECHANGED:
5833             GetSalData()->mbThemeChanged = true;
5834             break;
5835 
5836         case SAL_MSG_USEREVENT:
5837             ImplHandleUserEvent( hWnd, lParam );
5838             rDef = false;
5839             break;
5840 
5841         case SAL_MSG_CAPTUREMOUSE:
5842             SetCapture( hWnd );
5843             rDef = false;
5844             break;
5845         case SAL_MSG_RELEASEMOUSE:
5846             if ( ::GetCapture() == hWnd )
5847                 ReleaseCapture();
5848             rDef = false;
5849             break;
5850         case SAL_MSG_TOTOP:
5851             ImplSalToTop( hWnd, static_cast<SalFrameToTop>(wParam) );
5852             rDef = false;
5853             break;
5854         case SAL_MSG_SHOW:
5855             ImplSalShow( hWnd, static_cast<bool>(wParam), static_cast<bool>(lParam) );
5856             rDef = false;
5857             break;
5858         case SAL_MSG_SETINPUTCONTEXT:
5859             ImplSalFrameSetInputContext( hWnd, reinterpret_cast<const SalInputContext*>(lParam) );
5860             rDef = false;
5861             break;
5862         case SAL_MSG_ENDEXTTEXTINPUT:
5863             ImplSalFrameEndExtTextInput( hWnd, static_cast<EndExtTextInputFlags>(wParam) );
5864             rDef = false;
5865             break;
5866 
5867         case WM_INPUTLANGCHANGE:
5868             ImplHandleInputLangChange( hWnd, wParam, lParam );
5869             break;
5870 
5871         case WM_IME_CHAR:
5872             // #103487#, some IMEs (eg, those that do not work onspot)
5873             //           may send WM_IME_CHAR instead of WM_IME_COMPOSITION
5874             // we just handle it like a WM_CHAR message - seems to work fine
5875             ImplSalYieldMutexAcquireWithWait();
5876             rDef = !ImplHandleKeyMsg( hWnd, WM_CHAR, wParam, lParam, nRet );
5877             ImplSalYieldMutexRelease();
5878             break;
5879 
5880          case WM_IME_STARTCOMPOSITION:
5881             rDef = ImplHandleIMEStartComposition( hWnd );
5882             break;
5883 
5884         case WM_IME_COMPOSITION:
5885             rDef = ImplHandleIMEComposition( hWnd, lParam );
5886             break;
5887 
5888         case WM_IME_ENDCOMPOSITION:
5889             rDef = ImplHandleIMEEndComposition( hWnd );
5890             break;
5891 
5892         case WM_IME_NOTIFY:
5893             ImplHandleIMENotify( hWnd, wParam );
5894             break;
5895 
5896         case WM_GETOBJECT:
5897             ImplSalYieldMutexAcquireWithWait();
5898             if ( ImplHandleGetObject( hWnd, lParam, wParam, nRet ) )
5899             {
5900                 rDef = false;
5901             }
5902             ImplSalYieldMutexRelease();
5903             break;
5904 
5905         case WM_APPCOMMAND:
5906             if( ImplHandleAppCommand( hWnd, lParam, nRet ) )
5907             {
5908                 rDef = false;
5909             }
5910             break;
5911         case WM_IME_REQUEST:
5912             if ( static_cast<sal_uIntPtr>(wParam) == IMR_RECONVERTSTRING )
5913             {
5914                 nRet = ImplHandleIMEReconvertString( hWnd, lParam );
5915                 rDef = false;
5916             }
5917             else if( static_cast<sal_uIntPtr>(wParam) == IMR_CONFIRMRECONVERTSTRING )
5918             {
5919                 nRet = ImplHandleIMEConfirmReconvertString( hWnd, lParam );
5920                 rDef = false;
5921             }
5922             else if ( static_cast<sal_uIntPtr>(wParam) == IMR_QUERYCHARPOSITION )
5923             {
5924                 if ( ImplSalYieldMutexTryToAcquire() )
5925                 {
5926                     nRet = ImplHandleIMEQueryCharPosition( hWnd, lParam );
5927                     ImplSalYieldMutexRelease();
5928                 }
5929                 else
5930                     nRet = FALSE;
5931                 rDef = false;
5932             }
5933             break;
5934     }
5935 
5936     return nRet;
5937 }
5938 
5939 LRESULT CALLBACK SalFrameWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
5940 {
5941     bool bDef = true;
5942     LRESULT nRet = 0;
5943     __try
5944     {
5945         nRet = SalFrameWndProc( hWnd, nMsg, wParam, lParam, bDef );
5946     }
5947     __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))
5948     {
5949     }
5950 
5951     if ( bDef )
5952         nRet = DefWindowProcW( hWnd, nMsg, wParam, lParam );
5953     return nRet;
5954 }
5955 
5956 bool ImplHandleGlobalMsg( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, LRESULT& rlResult )
5957 {
5958     // handle all messages concerning all frames so they get processed only once
5959     // Must work for Unicode and none Unicode
5960     bool bResult = false;
5961     if ( (nMsg == WM_PALETTECHANGED) || (nMsg == SAL_MSG_POSTPALCHANGED) )
5962     {
5963         bResult = true;
5964         rlResult = ImplHandlePalette( false, hWnd, nMsg, wParam, lParam, bResult );
5965     }
5966     else if( nMsg == WM_DISPLAYCHANGE )
5967     {
5968         WinSalSystem* pSys = static_cast<WinSalSystem*>(ImplGetSalSystem());
5969         if( pSys )
5970             pSys->clearMonitors();
5971         bResult = (pSys != nullptr);
5972     }
5973     return bResult;
5974 }
5975 
5976 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
5977