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