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