Avoid potential negative array index access to cached text.
[LibreOffice.git] / vcl / win / window / salframe.cxx
blobbd93ad6bf4325cc561410641773fd90414e9c481
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <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>
25 #include <officecfg/Office/Common.hxx>
27 #include <memory>
28 #include <string.h>
29 #include <limits.h>
31 #include <svsys.h>
33 #include <comphelper/windowserrorstring.hxx>
35 #include <fstream>
36 #include <boost/property_tree/ptree.hpp>
37 #include <boost/property_tree/ini_parser.hpp>
38 #include <osl/file.hxx>
39 #include <osl/process.h>
41 #include <rtl/character.hxx>
42 #include <rtl/string.h>
43 #include <rtl/ustring.h>
44 #include <sal/log.hxx>
46 #include <osl/module.h>
47 #include <comphelper/scopeguard.hxx>
48 #include <tools/debug.hxx>
49 #include <o3tl/enumarray.hxx>
50 #include <o3tl/char16_t2wchar_t.hxx>
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>
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>
75 #include <helpwin.hxx>
76 #include <window.h>
77 #include <sallayout.hxx>
79 #include <vector>
81 #include <com/sun/star/uno/Exception.hpp>
83 #include <oleacc.h>
84 #include <com/sun/star/accessibility/XMSAAService.hpp>
86 #include <time.h>
88 #if !defined WIN32_LEAN_AND_MEAN
89 # define WIN32_LEAN_AND_MEAN
90 #endif
91 #include <windows.h>
92 #include <dwmapi.h>
93 #include <shobjidl.h>
94 #include <propkey.h>
95 #include <propvarutil.h>
96 #include <shellapi.h>
97 #include <uxtheme.h>
98 #include <Vssym32.h>
100 using namespace ::com::sun::star;
101 using namespace ::com::sun::star::uno;
102 using namespace ::com::sun::star::lang;
103 using namespace ::com::sun::star::container;
104 using namespace ::com::sun::star::beans;
106 #ifndef IDC_PEN
107 # define IDC_PEN MAKEINTRESOURCE(32631)
108 #endif
110 const unsigned int WM_USER_SYSTEM_WINDOW_ACTIVATED = RegisterWindowMessageW(L"SYSTEM_WINDOW_ACTIVATED");
112 bool WinSalFrame::mbInReparent = false;
114 // Macros for support of WM_UNICHAR & Keyman 6.0
115 #define Uni_SupplementaryPlanesStart 0x10000
117 static void UpdateFrameGeometry(WinSalFrame* pFrame);
118 static void SetMaximizedFrameGeometry( HWND hWnd, WinSalFrame* pFrame, RECT* pParentRect = nullptr );
120 static void SetGeometrySize(vcl::WindowPosSize& rWinPosSize, const Size& rSize)
122 rWinPosSize.setWidth(rSize.Width() < 0 ? 0 : rSize.Width());
123 rWinPosSize.setHeight(rSize.Height() < 0 ? 0 : rSize.Height());
126 // If called with UpdateFrameGeometry, it must be called after it, as UpdateFrameGeometry
127 // updates the geometry depending on the old state!
128 void WinSalFrame::UpdateFrameState()
130 // don't overwrite restore state in fullscreen mode
131 if (isFullScreen())
132 return;
134 const bool bVisible = (GetWindowStyle(mhWnd) & WS_VISIBLE);
135 if (IsIconic(mhWnd))
137 m_eState &= ~vcl::WindowState(vcl::WindowState::Normal | vcl::WindowState::Maximized);
138 m_eState |= vcl::WindowState::Minimized;
139 if (bVisible)
140 mnShowState = SW_SHOWMINIMIZED;
142 else if (IsZoomed(mhWnd))
144 m_eState &= ~vcl::WindowState(vcl::WindowState::Minimized | vcl::WindowState::Normal);
145 m_eState |= vcl::WindowState::Maximized;
146 if (bVisible)
147 mnShowState = SW_SHOWMAXIMIZED;
148 mbRestoreMaximize = true;
150 else
152 m_eState &= ~vcl::WindowState(vcl::WindowState::Minimized | vcl::WindowState::Maximized);
153 m_eState |= vcl::WindowState::Normal;
154 if (bVisible)
155 mnShowState = SW_SHOWNORMAL;
156 mbRestoreMaximize = false;
160 // if pParentRect is set, the workarea of the monitor that contains pParentRect is returned
161 void ImplSalGetWorkArea( HWND hWnd, RECT *pRect, const RECT *pParentRect )
163 if (Application::IsHeadlessModeEnabled()) {
164 pRect->left = 0;
165 pRect->top = 0;
166 pRect->right = VIRTUAL_DESKTOP_WIDTH;
167 pRect->bottom = VIRTUAL_DESKTOP_HEIGHT;
168 return;
170 // check if we or our parent is fullscreen, then the taskbar should be ignored
171 bool bIgnoreTaskbar = false;
172 WinSalFrame* pFrame = GetWindowPtr( hWnd );
173 if( pFrame )
175 vcl::Window *pWin = pFrame->GetWindow();
176 while( pWin )
178 WorkWindow *pWorkWin = (pWin->GetType() == WindowType::WORKWINDOW) ? static_cast<WorkWindow *>(pWin) : nullptr;
179 if( pWorkWin && pWorkWin->ImplGetWindowImpl()->mbReallyVisible && pWorkWin->IsFullScreenMode() )
181 bIgnoreTaskbar = true;
182 break;
184 else
185 pWin = pWin->ImplGetWindowImpl()->mpParent;
189 // calculates the work area taking multiple monitors into account
190 static int nMonitors = GetSystemMetrics( SM_CMONITORS );
191 if( nMonitors == 1 )
193 if( bIgnoreTaskbar )
195 pRect->left = pRect->top = 0;
196 pRect->right = GetSystemMetrics( SM_CXSCREEN );
197 pRect->bottom = GetSystemMetrics( SM_CYSCREEN );
199 else
200 SystemParametersInfoW( SPI_GETWORKAREA, 0, pRect, 0 );
202 else
204 if( pParentRect != nullptr )
206 // return the size of the monitor where pParentRect lives
207 HMONITOR hMonitor;
208 MONITORINFO mi;
210 // get the nearest monitor to the passed rect.
211 hMonitor = MonitorFromRect(pParentRect, MONITOR_DEFAULTTONEAREST);
213 // get the work area or entire monitor rect.
214 mi.cbSize = sizeof(mi);
215 GetMonitorInfo(hMonitor, &mi);
216 if( !bIgnoreTaskbar )
217 *pRect = mi.rcWork;
218 else
219 *pRect = mi.rcMonitor;
221 else
223 // return the union of all monitors
224 pRect->left = GetSystemMetrics( SM_XVIRTUALSCREEN );
225 pRect->top = GetSystemMetrics( SM_YVIRTUALSCREEN );
226 pRect->right = pRect->left + GetSystemMetrics( SM_CXVIRTUALSCREEN );
227 pRect->bottom = pRect->top + GetSystemMetrics( SM_CYVIRTUALSCREEN );
229 // virtualscreen does not take taskbar into account, so use the corresponding
230 // diffs between screen and workarea from the default screen
231 // however, this is still not perfect: the taskbar might not be on the primary screen
232 if( !bIgnoreTaskbar )
234 RECT wRect, scrRect;
235 SystemParametersInfoW( SPI_GETWORKAREA, 0, &wRect, 0 );
236 scrRect.left = 0;
237 scrRect.top = 0;
238 scrRect.right = GetSystemMetrics( SM_CXSCREEN );
239 scrRect.bottom = GetSystemMetrics( SM_CYSCREEN );
241 pRect->left += wRect.left;
242 pRect->top += wRect.top;
243 pRect->right -= scrRect.right - wRect.right;
244 pRect->bottom -= scrRect.bottom - wRect.bottom;
250 namespace {
252 enum PreferredAppMode
254 AllowDark = 1,
255 ForceDark = 2,
256 ForceLight = 3
261 static void UpdateDarkMode(HWND hWnd)
263 static bool bOSSupportsDarkMode = OSSupportsDarkMode();
264 if (!bOSSupportsDarkMode)
265 return;
267 HINSTANCE hUxthemeLib = LoadLibraryExW(L"uxtheme.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
268 if (!hUxthemeLib)
269 return;
271 typedef PreferredAppMode(WINAPI* SetPreferredAppMode_t)(PreferredAppMode);
272 auto SetPreferredAppMode = reinterpret_cast<SetPreferredAppMode_t>(GetProcAddress(hUxthemeLib, MAKEINTRESOURCEA(135)));
273 if (SetPreferredAppMode)
275 switch (MiscSettings::GetDarkMode())
277 case 0:
278 SetPreferredAppMode(AllowDark);
279 break;
280 case 1:
281 SetPreferredAppMode(ForceLight);
282 break;
283 case 2:
284 SetPreferredAppMode(ForceDark);
285 break;
289 BOOL bDarkMode = UseDarkMode();
291 typedef void(WINAPI* AllowDarkModeForWindow_t)(HWND, BOOL);
292 auto AllowDarkModeForWindow = reinterpret_cast<AllowDarkModeForWindow_t>(GetProcAddress(hUxthemeLib, MAKEINTRESOURCEA(133)));
293 if (AllowDarkModeForWindow)
294 AllowDarkModeForWindow(hWnd, bDarkMode);
296 FreeLibrary(hUxthemeLib);
298 if (!AllowDarkModeForWindow)
299 return;
301 DwmSetWindowAttribute(hWnd, 20, &bDarkMode, sizeof(bDarkMode));
304 SalFrame* ImplSalCreateFrame( WinSalInstance* pInst,
305 HWND hWndParent, SalFrameStyleFlags nSalFrameStyle )
307 WinSalFrame* pFrame = new WinSalFrame;
308 HWND hWnd;
309 DWORD nSysStyle = 0;
310 DWORD nExSysStyle = 0;
311 bool bSubFrame = false;
313 static const char* pEnvSynchronize = getenv("SAL_SYNCHRONIZE");
314 if ( pEnvSynchronize ) // no buffering of drawing commands
315 GdiSetBatchLimit( 1 );
317 static const char* pEnvTransparentFloats = getenv("SAL_TRANSPARENT_FLOATS" );
319 // determine creation data
320 if ( nSalFrameStyle & (SalFrameStyleFlags::PLUG | SalFrameStyleFlags::SYSTEMCHILD) )
322 nSysStyle |= WS_CHILD;
323 if( nSalFrameStyle & SalFrameStyleFlags::SYSTEMCHILD )
324 nSysStyle |= WS_CLIPSIBLINGS;
326 else
328 // #i87402# commenting out WS_CLIPCHILDREN
329 // this breaks SalFrameStyleFlags::SYSTEMCHILD handling, which is not
330 // used currently. Probably SalFrameStyleFlags::SYSTEMCHILD should be
331 // removed again.
333 // nSysStyle |= WS_CLIPCHILDREN;
334 if ( hWndParent )
336 nSysStyle |= WS_POPUP;
337 bSubFrame = true;
338 pFrame->mbNoIcon = true;
340 else
342 // Only with WS_OVERLAPPED we get a useful default position/size
343 if ( (nSalFrameStyle & (SalFrameStyleFlags::SIZEABLE | SalFrameStyleFlags::MOVEABLE)) ==
344 (SalFrameStyleFlags::SIZEABLE | SalFrameStyleFlags::MOVEABLE) )
345 nSysStyle |= WS_OVERLAPPED;
346 else
348 nSysStyle |= WS_POPUP;
349 if ( !(nSalFrameStyle & SalFrameStyleFlags::MOVEABLE) )
350 nExSysStyle |= WS_EX_TOOLWINDOW; // avoid taskbar appearance, for eg splash screen
354 if ( nSalFrameStyle & SalFrameStyleFlags::MOVEABLE )
356 pFrame->mbCaption = true;
357 nSysStyle |= WS_SYSMENU | WS_CAPTION;
358 if ( !hWndParent )
359 nSysStyle |= WS_SYSMENU | WS_MINIMIZEBOX;
360 else
361 nExSysStyle |= WS_EX_DLGMODALFRAME;
363 if ( nSalFrameStyle & SalFrameStyleFlags::SIZEABLE )
365 pFrame->mbSizeBorder = true;
366 nSysStyle |= WS_THICKFRAME;
367 if ( !hWndParent )
368 nSysStyle |= WS_MAXIMIZEBOX;
370 else
371 pFrame->mbFixBorder = true;
373 if ( nSalFrameStyle & SalFrameStyleFlags::DEFAULT )
374 nExSysStyle |= WS_EX_APPWINDOW;
376 if( nSalFrameStyle & SalFrameStyleFlags::TOOLWINDOW
377 // #100656# toolwindows lead to bad alt-tab behaviour, if they have the focus
378 // you must press it twice to leave the application
379 // so toolwindows are only used for non sizeable windows
380 // which are typically small, so a small caption makes sense
382 // #103578# looked too bad - above changes reverted
383 /* && !(nSalFrameStyle & SalFrameStyleFlags::SIZEABLE) */ )
385 pFrame->mbNoIcon = true;
386 nExSysStyle |= WS_EX_TOOLWINDOW;
387 if ( pEnvTransparentFloats /*&& !(nSalFrameStyle & SalFrameStyleFlags::MOVEABLE) */)
388 nExSysStyle |= WS_EX_LAYERED;
391 if ( nSalFrameStyle & SalFrameStyleFlags::FLOAT )
393 nExSysStyle |= WS_EX_TOOLWINDOW;
394 pFrame->mbFloatWin = true;
396 if (pEnvTransparentFloats)
397 nExSysStyle |= WS_EX_LAYERED;
400 if (nSalFrameStyle & SalFrameStyleFlags::TOOLTIP)
401 nExSysStyle |= WS_EX_TOPMOST;
403 // init frame data
404 pFrame->mnStyle = nSalFrameStyle;
406 // determine show style
407 pFrame->mnShowState = SW_SHOWNORMAL;
408 if ( (nSysStyle & (WS_POPUP | WS_MAXIMIZEBOX | WS_THICKFRAME)) == (WS_MAXIMIZEBOX | WS_THICKFRAME) )
410 if ( GetSystemMetrics( SM_CXSCREEN ) <= 1024 )
411 pFrame->mnShowState = SW_SHOWMAXIMIZED;
412 else
414 if ( nSalFrameStyle & SalFrameStyleFlags::DEFAULT )
416 SalData* pSalData = GetSalData();
417 pFrame->mnShowState = pSalData->mnCmdShow;
418 if ( (pFrame->mnShowState != SW_SHOWMINIMIZED) &&
419 (pFrame->mnShowState != SW_MINIMIZE) &&
420 (pFrame->mnShowState != SW_SHOWMINNOACTIVE) )
422 if ( (pFrame->mnShowState == SW_SHOWMAXIMIZED) ||
423 (pFrame->mnShowState == SW_MAXIMIZE) )
424 pFrame->mbOverwriteState = false;
425 pFrame->mnShowState = SW_SHOWMAXIMIZED;
427 else
428 pFrame->mbOverwriteState = false;
430 else
432 // Document Windows are also maximized, if the current Document Window
433 // is also maximized
434 HWND hWnd2 = GetForegroundWindow();
435 if ( hWnd2 && IsMaximized( hWnd2 ) &&
436 (GetWindowInstance( hWnd2 ) == pInst->mhInst) &&
437 ((GetWindowStyle( hWnd2 ) & (WS_POPUP | WS_MAXIMIZEBOX | WS_THICKFRAME)) == (WS_MAXIMIZEBOX | WS_THICKFRAME)) )
438 pFrame->mnShowState = SW_SHOWMAXIMIZED;
443 // create frame
444 LPCWSTR pClassName;
445 if ( bSubFrame )
447 if ( nSalFrameStyle & (SalFrameStyleFlags::MOVEABLE|SalFrameStyleFlags::NOSHADOW) ) // check if shadow not wanted
448 pClassName = SAL_SUBFRAME_CLASSNAMEW;
449 else
450 pClassName = SAL_TMPSUBFRAME_CLASSNAMEW; // undecorated floaters will get shadow on XP
452 else
454 if ( nSalFrameStyle & SalFrameStyleFlags::MOVEABLE )
455 pClassName = SAL_FRAME_CLASSNAMEW;
456 else
457 pClassName = SAL_TMPSUBFRAME_CLASSNAMEW;
459 hWnd = CreateWindowExW( nExSysStyle, pClassName, L"", nSysStyle,
460 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
461 hWndParent, nullptr, pInst->mhInst, pFrame );
462 SAL_WARN_IF(!hWnd, "vcl", "CreateWindowExW failed: " << WindowsErrorString(GetLastError()));
464 #if OSL_DEBUG_LEVEL > 1
465 // set transparency value
466 if( GetWindowExStyle( hWnd ) & WS_EX_LAYERED )
467 SetLayeredWindowAttributes( hWnd, 0, 230, 0x00000002 /*LWA_ALPHA*/ );
468 #endif
469 if ( !hWnd )
471 delete pFrame;
472 return nullptr;
475 // If we have a Window with a Caption Bar and without
476 // a MaximizeBox, we change the SystemMenu
477 if ( (nSysStyle & (WS_CAPTION | WS_MAXIMIZEBOX)) == (WS_CAPTION) )
479 HMENU hSysMenu = GetSystemMenu( hWnd, FALSE );
480 if ( hSysMenu )
482 if ( !(nSysStyle & (WS_MINIMIZEBOX | WS_MAXIMIZEBOX)) )
483 DeleteMenu( hSysMenu, SC_RESTORE, MF_BYCOMMAND );
484 else
485 EnableMenuItem( hSysMenu, SC_RESTORE, MF_BYCOMMAND | MF_GRAYED | MF_DISABLED );
486 if ( !(nSysStyle & WS_MINIMIZEBOX) )
487 DeleteMenu( hSysMenu, SC_MINIMIZE, MF_BYCOMMAND );
488 if ( !(nSysStyle & WS_MAXIMIZEBOX) )
489 DeleteMenu( hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND );
490 if ( !(nSysStyle & WS_THICKFRAME) )
491 DeleteMenu( hSysMenu, SC_SIZE, MF_BYCOMMAND );
494 if ( (nSysStyle & WS_SYSMENU) && !(nSalFrameStyle & SalFrameStyleFlags::CLOSEABLE) )
496 HMENU hSysMenu = GetSystemMenu( hWnd, FALSE );
497 if ( hSysMenu )
498 EnableMenuItem( hSysMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED | MF_DISABLED );
501 // reset input context
502 pFrame->mhDefIMEContext = ImmAssociateContext( hWnd, nullptr );
504 // determine output size and state
505 RECT aRect;
506 GetClientRect( hWnd, &aRect );
507 pFrame->mbDefPos = true;
509 UpdateFrameGeometry(pFrame);
510 pFrame->UpdateFrameState();
512 if( pFrame->mnShowState == SW_SHOWMAXIMIZED )
514 // #96084 set a useful internal window size because
515 // the window will not be maximized (and the size updated) before show()
517 SetMaximizedFrameGeometry( hWnd, pFrame );
520 return pFrame;
523 // helper that only creates the HWND
524 // to allow for easy reparenting of system windows, (i.e. destroy and create new)
525 HWND ImplSalReCreateHWND( HWND hWndParent, HWND oldhWnd, bool bAsChild )
527 HINSTANCE hInstance = GetSalData()->mhInst;
528 sal_uLong nSysStyle = GetWindowLongW( oldhWnd, GWL_STYLE );
529 sal_uLong nExSysStyle = GetWindowLongW( oldhWnd, GWL_EXSTYLE );
531 if( bAsChild )
533 nSysStyle = WS_CHILD;
534 nExSysStyle = 0;
537 LPCWSTR pClassName = SAL_SUBFRAME_CLASSNAMEW;
538 return CreateWindowExW( nExSysStyle, pClassName, L"", nSysStyle,
539 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
540 hWndParent, nullptr, hInstance, GetWindowPtr( oldhWnd ) );
543 // translation table from System keycodes into StartView keycodes
544 #define KEY_TAB_SIZE 168
546 const sal_uInt16 aImplTranslateKeyTab[KEY_TAB_SIZE] =
548 // StarView-Code System-Code Index
549 0, // 0
550 0, // VK_LBUTTON 1
551 0, // VK_RBUTTON 2
552 0, // VK_CANCEL 3
553 0, // VK_MBUTTON 4
554 0, // 5
555 0, // 6
556 0, // 7
557 KEY_BACKSPACE, // VK_BACK 8
558 KEY_TAB, // VK_TAB 9
559 0, // 10
560 0, // 11
561 0, // VK_CLEAR 12
562 KEY_RETURN, // VK_RETURN 13
563 0, // 14
564 0, // 15
565 0, // VK_SHIFT 16
566 0, // VK_CONTROL 17
567 0, // VK_MENU 18
568 0, // VK_PAUSE 19
569 0, // VK_CAPITAL 20
570 0, // VK_HANGUL 21
571 0, // 22
572 0, // 23
573 0, // 24
574 KEY_HANGUL_HANJA, // VK_HANJA 25
575 0, // 26
576 KEY_ESCAPE, // VK_ESCAPE 27
577 0, // 28
578 0, // 29
579 0, // 30
580 0, // 31
581 KEY_SPACE, // VK_SPACE 32
582 KEY_PAGEUP, // VK_PRIOR 33
583 KEY_PAGEDOWN, // VK_NEXT 34
584 KEY_END, // VK_END 35
585 KEY_HOME, // VK_HOME 36
586 KEY_LEFT, // VK_LEFT 37
587 KEY_UP, // VK_UP 38
588 KEY_RIGHT, // VK_RIGHT 39
589 KEY_DOWN, // VK_DOWN 40
590 0, // VK_SELECT 41
591 0, // VK_PRINT 42
592 0, // VK_EXECUTE 43
593 0, // VK_SNAPSHOT 44
594 KEY_INSERT, // VK_INSERT 45
595 KEY_DELETE, // VK_DELETE 46
596 KEY_HELP, // VK_HELP 47
597 KEY_0, // 48
598 KEY_1, // 49
599 KEY_2, // 50
600 KEY_3, // 51
601 KEY_4, // 52
602 KEY_5, // 53
603 KEY_6, // 54
604 KEY_7, // 55
605 KEY_8, // 56
606 KEY_9, // 57
607 0, // 58
608 0, // 59
609 0, // 60
610 0, // 61
611 0, // 62
612 0, // 63
613 0, // 64
614 KEY_A, // 65
615 KEY_B, // 66
616 KEY_C, // 67
617 KEY_D, // 68
618 KEY_E, // 69
619 KEY_F, // 70
620 KEY_G, // 71
621 KEY_H, // 72
622 KEY_I, // 73
623 KEY_J, // 74
624 KEY_K, // 75
625 KEY_L, // 76
626 KEY_M, // 77
627 KEY_N, // 78
628 KEY_O, // 79
629 KEY_P, // 80
630 KEY_Q, // 81
631 KEY_R, // 82
632 KEY_S, // 83
633 KEY_T, // 84
634 KEY_U, // 85
635 KEY_V, // 86
636 KEY_W, // 87
637 KEY_X, // 88
638 KEY_Y, // 89
639 KEY_Z, // 90
640 0, // VK_LWIN 91
641 0, // VK_RWIN 92
642 KEY_CONTEXTMENU, // VK_APPS 93
643 0, // 94
644 0, // 95
645 KEY_0, // VK_NUMPAD0 96
646 KEY_1, // VK_NUMPAD1 97
647 KEY_2, // VK_NUMPAD2 98
648 KEY_3, // VK_NUMPAD3 99
649 KEY_4, // VK_NUMPAD4 100
650 KEY_5, // VK_NUMPAD5 101
651 KEY_6, // VK_NUMPAD6 102
652 KEY_7, // VK_NUMPAD7 103
653 KEY_8, // VK_NUMPAD8 104
654 KEY_9, // VK_NUMPAD9 105
655 KEY_MULTIPLY, // VK_MULTIPLY 106
656 KEY_ADD, // VK_ADD 107
657 KEY_DECIMAL, // VK_SEPARATOR 108
658 KEY_SUBTRACT, // VK_SUBTRACT 109
659 KEY_DECIMAL, // VK_DECIMAL 110
660 KEY_DIVIDE, // VK_DIVIDE 111
661 KEY_F1, // VK_F1 112
662 KEY_F2, // VK_F2 113
663 KEY_F3, // VK_F3 114
664 KEY_F4, // VK_F4 115
665 KEY_F5, // VK_F5 116
666 KEY_F6, // VK_F6 117
667 KEY_F7, // VK_F7 118
668 KEY_F8, // VK_F8 119
669 KEY_F9, // VK_F9 120
670 KEY_F10, // VK_F10 121
671 KEY_F11, // VK_F11 122
672 KEY_F12, // VK_F12 123
673 KEY_F13, // VK_F13 124
674 KEY_F14, // VK_F14 125
675 KEY_F15, // VK_F15 126
676 KEY_F16, // VK_F16 127
677 KEY_F17, // VK_F17 128
678 KEY_F18, // VK_F18 129
679 KEY_F19, // VK_F19 130
680 KEY_F20, // VK_F20 131
681 KEY_F21, // VK_F21 132
682 KEY_F22, // VK_F22 133
683 KEY_F23, // VK_F23 134
684 KEY_F24, // VK_F24 135
685 0, // 136
686 0, // 137
687 0, // 138
688 0, // 139
689 0, // 140
690 0, // 141
691 0, // 142
692 0, // 143
693 0, // NUMLOCK 144
694 0, // SCROLLLOCK 145
695 0, // 146
696 0, // 147
697 0, // 148
698 0, // 149
699 0, // 150
700 0, // 151
701 0, // 152
702 0, // 153
703 0, // 154
704 0, // 155
705 0, // 156
706 0, // 157
707 0, // 158
708 0, // 159
709 0, // 160
710 0, // 161
711 0, // 162
712 0, // 163
713 0, // 164
714 0, // 165
715 KEY_XF86BACK, // VK_BROWSER_BACK 166
716 KEY_XF86FORWARD // VK_BROWSER_FORWARD 167
719 static UINT ImplSalGetWheelScrollLines()
721 UINT nScrLines = 0;
722 HWND hWndMsWheel = FindWindowW( MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE );
723 if ( hWndMsWheel )
725 UINT nGetScrollLinesMsgId = RegisterWindowMessageW( MSH_SCROLL_LINES );
726 nScrLines = static_cast<UINT>(SendMessageW( hWndMsWheel, nGetScrollLinesMsgId, 0, 0 ));
729 if ( !nScrLines )
730 if( !SystemParametersInfoW( SPI_GETWHEELSCROLLLINES, 0, &nScrLines, 0 ) )
731 nScrLines = 0 ;
733 if ( !nScrLines )
734 nScrLines = 3;
736 return nScrLines;
739 static UINT ImplSalGetWheelScrollChars()
741 UINT nScrChars = 0;
742 if( !SystemParametersInfoW( SPI_GETWHEELSCROLLCHARS, 0, &nScrChars, 0 ) )
744 return 3;
747 // system settings successfully read
748 return nScrChars;
751 static void ImplSalAddBorder( const WinSalFrame* pFrame, int& width, int& height )
753 // transform client size into window size
754 RECT aWinRect;
755 aWinRect.left = 0;
756 aWinRect.right = width-1;
757 aWinRect.top = 0;
758 aWinRect.bottom = height-1;
759 AdjustWindowRectEx( &aWinRect, GetWindowStyle( pFrame->mhWnd ),
760 FALSE, GetWindowExStyle( pFrame->mhWnd ) );
761 width = aWinRect.right - aWinRect.left + 1;
762 height = aWinRect.bottom - aWinRect.top + 1;
765 static void ImplSalCalcFullScreenSize( const WinSalFrame* pFrame,
766 int& rX, int& rY, int& rDX, int& rDY )
768 // set window to screen size
769 int nFrameX;
770 int nFrameY;
771 int nCaptionY;
772 int nScreenX = 0;
773 int nScreenY = 0;
774 int nScreenDX = 0;
775 int nScreenDY = 0;
777 if ( pFrame->mbSizeBorder )
779 nFrameX = GetSystemMetrics( SM_CXSIZEFRAME );
780 nFrameY = GetSystemMetrics( SM_CYSIZEFRAME );
782 else if ( pFrame->mbFixBorder )
784 nFrameX = GetSystemMetrics( SM_CXFIXEDFRAME );
785 nFrameY = GetSystemMetrics( SM_CYFIXEDFRAME );
787 else if ( pFrame->mbBorder )
789 nFrameX = GetSystemMetrics( SM_CXBORDER );
790 nFrameY = GetSystemMetrics( SM_CYBORDER );
792 else
794 nFrameX = 0;
795 nFrameY = 0;
797 if ( pFrame->mbCaption )
798 nCaptionY = GetSystemMetrics( SM_CYCAPTION );
799 else
800 nCaptionY = 0;
804 AbsoluteScreenPixelRectangle aRect;
805 sal_Int32 nMonitors = Application::GetScreenCount();
806 if( (pFrame->mnDisplay >= 0) && (pFrame->mnDisplay < nMonitors) )
808 aRect = Application::GetScreenPosSizePixel(pFrame->mnDisplay);
810 else
812 for (sal_Int32 i = 0; i < nMonitors; i++)
813 aRect.Union(Application::GetScreenPosSizePixel(i));
815 nScreenX = aRect.Left();
816 nScreenY = aRect.Top();
817 nScreenDX = aRect.GetWidth();
818 nScreenDY = aRect.GetHeight();
820 catch( Exception& )
824 if( !nScreenDX || !nScreenDY )
826 nScreenDX = GetSystemMetrics( SM_CXSCREEN );
827 nScreenDY = GetSystemMetrics( SM_CYSCREEN );
830 rX = nScreenX -nFrameX;
831 rY = nScreenY -(nFrameY+nCaptionY);
832 rDX = nScreenDX+(nFrameX*2);
833 rDY = nScreenDY+(nFrameY*2)+nCaptionY;
836 static void ImplSalFrameFullScreenPos( WinSalFrame* pFrame, bool bAlways = false )
838 if ( bAlways || !IsIconic( pFrame->mhWnd ) )
840 // set window to screen size
841 int nX;
842 int nY;
843 int nWidth;
844 int nHeight;
845 ImplSalCalcFullScreenSize( pFrame, nX, nY, nWidth, nHeight );
846 SetWindowPos( pFrame->mhWnd, nullptr,
847 nX, nY, nWidth, nHeight,
848 SWP_NOZORDER | SWP_NOACTIVATE );
852 namespace {
854 void SetForegroundWindow_Impl(HWND hwnd)
856 if (!Application::IsHeadlessModeEnabled())
857 SetForegroundWindow(hwnd);
862 WinSalFrame::WinSalFrame()
864 SalData* pSalData = GetSalData();
866 mhWnd = nullptr;
867 mhCursor = LoadCursor( nullptr, IDC_ARROW );
868 mhDefIMEContext = nullptr;
869 mpLocalGraphics = nullptr;
870 mpThreadGraphics = nullptr;
871 m_eState = vcl::WindowState::Normal;
872 mnShowState = SW_SHOWNORMAL;
873 mnMinWidth = 0;
874 mnMinHeight = 0;
875 mnMaxWidth = SHRT_MAX;
876 mnMaxHeight = SHRT_MAX;
877 mnInputLang = 0;
878 mnInputCodePage = 0;
879 mbGraphics = false;
880 mbCaption = false;
881 mbBorder = false;
882 mbFixBorder = false;
883 mbSizeBorder = false;
884 mbFullScreenCaption = false;
885 mbPresentation = false;
886 mbInShow = false;
887 mbRestoreMaximize = false;
888 mbInMoveMsg = false;
889 mbInSizeMsg = false;
890 mbFullScreenToolWin = false;
891 mbDefPos = true;
892 mbOverwriteState = true;
893 mbIME = false;
894 mbHandleIME = false;
895 mbSpezIME = false;
896 mbAtCursorIME = false;
897 mbCandidateMode = false;
898 mbFloatWin = false;
899 mbNoIcon = false;
900 mSelectedhMenu = nullptr;
901 mLastActivatedhMenu = nullptr;
902 mpClipRgnData = nullptr;
903 mbFirstClipRect = true;
904 mpNextClipRect = nullptr;
905 mnDisplay = 0;
906 mbPropertiesStored = false;
908 // get data, when making 1st frame
909 if ( !pSalData->mpFirstFrame )
911 if ( !aSalShlData.mnWheelScrollLines )
912 aSalShlData.mnWheelScrollLines = ImplSalGetWheelScrollLines();
913 if ( !aSalShlData.mnWheelScrollChars )
914 aSalShlData.mnWheelScrollChars = ImplSalGetWheelScrollChars();
917 // insert frame in framelist
918 mpNextFrame = pSalData->mpFirstFrame;
919 pSalData->mpFirstFrame = this;
922 void WinSalFrame::updateScreenNumber()
924 if( mnDisplay == -1 ) // spans all monitors
925 return;
926 WinSalSystem* pSys = static_cast<WinSalSystem*>(ImplGetSalSystem());
927 if( pSys )
929 const std::vector<WinSalSystem::DisplayMonitor>& rMonitors =
930 pSys->getMonitors();
931 AbsoluteScreenPixelPoint aPoint(maGeometry.pos());
932 size_t nMon = rMonitors.size();
933 for( size_t i = 0; i < nMon; i++ )
935 if( rMonitors[i].m_aArea.Contains( aPoint ) )
937 mnDisplay = static_cast<sal_Int32>(i);
938 maGeometry.setScreen(static_cast<unsigned int>(i));
944 bool WinSalFrame::ReleaseFrameGraphicsDC( WinSalGraphics* pGraphics )
946 assert( pGraphics );
947 SalData* pSalData = GetSalData();
948 HDC hDC = pGraphics->getHDC();
949 if ( !hDC )
950 return false;
951 pGraphics->setHDC(nullptr);
952 SendMessageW( pSalData->mpInstance->mhComWnd, SAL_MSG_RELEASEDC,
953 reinterpret_cast<WPARAM>(mhWnd), reinterpret_cast<LPARAM>(hDC) );
954 if ( pGraphics == mpThreadGraphics )
955 pSalData->mnCacheDCInUse--;
956 return true;
959 WinSalFrame::~WinSalFrame()
961 SalData* pSalData = GetSalData();
963 if( mpClipRgnData )
964 delete [] reinterpret_cast<BYTE*>(mpClipRgnData);
966 // remove frame from framelist
967 WinSalFrame** ppFrame = &pSalData->mpFirstFrame;
968 for(; (*ppFrame != this) && *ppFrame; ppFrame = &(*ppFrame)->mpNextFrame );
969 if( *ppFrame )
970 *ppFrame = mpNextFrame;
971 mpNextFrame = nullptr;
973 // destroy the thread SalGraphics
974 if ( mpThreadGraphics )
976 ReleaseFrameGraphicsDC( mpThreadGraphics );
977 delete mpThreadGraphics;
978 mpThreadGraphics = nullptr;
981 // destroy the local SalGraphics
982 if ( mpLocalGraphics )
984 ReleaseFrameGraphicsDC( mpLocalGraphics );
985 delete mpLocalGraphics;
986 mpLocalGraphics = nullptr;
989 if ( mhWnd )
991 // reset mouse leave data
992 if ( pSalData->mhWantLeaveMsg == mhWnd )
994 pSalData->mhWantLeaveMsg = nullptr;
997 // remove windows properties
998 if ( mbPropertiesStored )
999 SetApplicationID( OUString() );
1001 // destroy system frame
1002 if ( !DestroyWindow( mhWnd ) )
1003 SetWindowPtr( mhWnd, nullptr );
1005 mhWnd = nullptr;
1009 bool WinSalFrame::InitFrameGraphicsDC( WinSalGraphics *pGraphics, HDC hDC, HWND hWnd )
1011 SalData* pSalData = GetSalData();
1012 assert( pGraphics );
1013 pGraphics->setHWND( hWnd );
1015 HDC hCurrentDC = pGraphics->getHDC();
1016 assert( !hCurrentDC || (hCurrentDC == hDC) );
1017 if ( hCurrentDC )
1018 return true;
1019 pGraphics->setHDC( hDC );
1021 if ( !hDC )
1022 return false;
1024 if ( pSalData->mhDitherPal )
1025 pGraphics->setPalette(pSalData->mhDitherPal);
1027 if ( pGraphics == mpThreadGraphics )
1028 pSalData->mnCacheDCInUse++;
1029 return true;
1032 SalGraphics* WinSalFrame::AcquireGraphics()
1034 if ( mbGraphics || !mhWnd )
1035 return nullptr;
1037 SalData* pSalData = GetSalData();
1038 WinSalGraphics *pGraphics = nullptr;
1039 HDC hDC = nullptr;
1041 // Other threads get an own DC, because Windows modify in the
1042 // other case our DC (changing clip region), when they send a
1043 // WM_ERASEBACKGROUND message
1044 if ( !pSalData->mpInstance->IsMainThread() )
1046 // We use only three CacheDC's for all threads, because W9x is limited
1047 // to max. 5 Cache DC's per thread
1048 if ( pSalData->mnCacheDCInUse >= 3 )
1049 return nullptr;
1051 if ( !mpThreadGraphics )
1052 mpThreadGraphics = new WinSalGraphics(WinSalGraphics::WINDOW, true, mhWnd, this);
1053 pGraphics = mpThreadGraphics;
1054 assert( !pGraphics->getHDC() );
1055 hDC = reinterpret_cast<HDC>(static_cast<sal_IntPtr>(SendMessageW( pSalData->mpInstance->mhComWnd,
1056 SAL_MSG_GETCACHEDDC, reinterpret_cast<WPARAM>(mhWnd), 0 )));
1058 else
1060 if ( !mpLocalGraphics )
1061 mpLocalGraphics = new WinSalGraphics(WinSalGraphics::WINDOW, true, mhWnd, this);
1062 pGraphics = mpLocalGraphics;
1063 hDC = pGraphics->getHDC();
1064 if ( !hDC )
1065 hDC = GetDC( mhWnd );
1068 mbGraphics = InitFrameGraphicsDC( pGraphics, hDC, mhWnd );
1069 return mbGraphics ? pGraphics : nullptr;
1072 void WinSalFrame::ReleaseGraphics( SalGraphics* pGraphics )
1074 if ( mpThreadGraphics == pGraphics )
1075 ReleaseFrameGraphicsDC( mpThreadGraphics );
1076 mbGraphics = false;
1079 bool WinSalFrame::PostEvent(std::unique_ptr<ImplSVEvent> pData)
1081 bool const ret = PostMessageW(mhWnd, SAL_MSG_USEREVENT, 0, reinterpret_cast<LPARAM>(pData.get()));
1082 SAL_WARN_IF(!ret, "vcl", "ERROR: PostMessage() failed!");
1083 if (ret)
1084 pData.release();
1085 return ret;
1088 void WinSalFrame::SetTitle( const OUString& rTitle )
1090 static_assert( sizeof( WCHAR ) == sizeof( sal_Unicode ), "must be the same size" );
1092 SetWindowTextW( mhWnd, o3tl::toW(rTitle.getStr()) );
1095 void WinSalFrame::SetIcon( sal_uInt16 nIcon )
1097 // If we have a window without an Icon (for example a dialog), ignore this call
1098 if ( mbNoIcon )
1099 return;
1101 // 0 means default (class) icon
1102 HICON hIcon = nullptr, hSmIcon = nullptr;
1103 if ( !nIcon )
1104 nIcon = 1;
1106 ImplLoadSalIcon( nIcon, hIcon, hSmIcon );
1108 SAL_WARN_IF( !hIcon , "vcl", "WinSalFrame::SetIcon(): Could not load large icon !" );
1109 SAL_WARN_IF( !hSmIcon , "vcl", "WinSalFrame::SetIcon(): Could not load small icon !" );
1111 SendMessageW( mhWnd, WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(hIcon) );
1112 SendMessageW( mhWnd, WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>(hSmIcon) );
1115 void WinSalFrame::SetMenu( SalMenu* pSalMenu )
1117 WinSalMenu* pWMenu = static_cast<WinSalMenu*>(pSalMenu);
1118 if( pSalMenu && pWMenu->mbMenuBar )
1119 ::SetMenu( mhWnd, pWMenu->mhMenu );
1122 static HWND ImplGetParentHwnd( HWND hWnd )
1124 WinSalFrame* pFrame = GetWindowPtr( hWnd );
1125 if( !pFrame || !pFrame->GetWindow())
1126 return ::GetParent( hWnd );
1127 vcl::Window *pRealParent = pFrame->GetWindow()->ImplGetWindowImpl()->mpRealParent;
1128 if( pRealParent )
1129 return static_cast<WinSalFrame*>(pRealParent->ImplGetWindowImpl()->mpFrame)->mhWnd;
1130 else
1131 return ::GetParent( hWnd );
1135 SalFrame* WinSalFrame::GetParent() const
1137 return GetWindowPtr( ImplGetParentHwnd( mhWnd ) );
1140 static void ImplSalShow( HWND hWnd, bool bVisible, bool bNoActivate )
1142 WinSalFrame* pFrame = GetWindowPtr( hWnd );
1143 if ( !pFrame )
1144 return;
1146 if ( bVisible )
1148 pFrame->mbDefPos = false;
1149 pFrame->mbOverwriteState = true;
1150 pFrame->mbInShow = true;
1152 // #i4715, save position
1153 RECT aRectPreMatrox, aRectPostMatrox;
1154 GetWindowRect( hWnd, &aRectPreMatrox );
1156 vcl::DeletionListener aDogTag( pFrame );
1157 if( bNoActivate )
1158 ShowWindow( hWnd, SW_SHOWNOACTIVATE );
1159 else
1160 ShowWindow( hWnd, pFrame->mnShowState );
1161 if( aDogTag.isDeleted() )
1162 return;
1164 if (pFrame->mbFloatWin && !(pFrame->mnStyle & SalFrameStyleFlags::NOSHADOW))
1166 // erase the window immediately to improve XP shadow effect
1167 // otherwise the shadow may appears long time before the rest of the window
1168 // especially when accessibility is on
1169 HDC dc = GetDC( hWnd );
1170 RECT aRect;
1171 GetClientRect( hWnd, &aRect );
1172 FillRect( dc, &aRect, reinterpret_cast<HBRUSH>(COLOR_MENU+1) ); // choose the menucolor, because its mostly noticeable for menus
1173 ReleaseDC( hWnd, dc );
1176 // #i4715, matrox centerpopup might have changed our position
1177 // reposition popups without caption (menus, dropdowns, tooltips)
1178 GetWindowRect( hWnd, &aRectPostMatrox );
1179 if( (GetWindowStyle( hWnd ) & WS_POPUP) &&
1180 !pFrame->mbCaption &&
1181 (aRectPreMatrox.left != aRectPostMatrox.left || aRectPreMatrox.top != aRectPostMatrox.top) )
1182 SetWindowPos( hWnd, nullptr, aRectPreMatrox.left, aRectPreMatrox.top, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE );
1184 if( aDogTag.isDeleted() )
1185 return;
1186 vcl::Window *pClientWin = pFrame->GetWindow()->ImplGetClientWindow();
1187 if ( pFrame->mbFloatWin || ( pClientWin && (pClientWin->GetStyle() & WB_SYSTEMFLOATWIN) ) )
1188 pFrame->mnShowState = SW_SHOWNOACTIVATE;
1189 else
1190 pFrame->mnShowState = SW_SHOW;
1191 // hide toolbar for W98
1192 if ( pFrame->mbPresentation )
1194 HWND hWndParent = ::GetParent( hWnd );
1195 if ( hWndParent )
1196 SetForegroundWindow_Impl( hWndParent );
1197 SetForegroundWindow_Impl( hWnd );
1200 pFrame->mbInShow = false;
1201 pFrame->updateScreenNumber();
1203 // Direct Paint only, if we get the SolarMutex
1204 if ( ImplSalYieldMutexTryToAcquire() )
1206 UpdateWindow( hWnd );
1207 ImplSalYieldMutexRelease();
1210 else
1212 ShowWindow( hWnd, SW_HIDE );
1216 void WinSalFrame::SetExtendedFrameStyle( SalExtStyle )
1220 void WinSalFrame::Show( bool bVisible, bool bNoActivate )
1222 // Post this Message to the window, because this only works
1223 // in the thread of the window, which has create this window.
1224 // We post this message to avoid deadlocks
1225 if ( GetSalData()->mnAppThreadId != GetCurrentThreadId() )
1227 bool const ret = PostMessageW(mhWnd, SAL_MSG_SHOW, WPARAM(bVisible), LPARAM(bNoActivate));
1228 SAL_WARN_IF(!ret, "vcl", "ERROR: PostMessage() failed!");
1230 else
1231 ImplSalShow( mhWnd, bVisible, bNoActivate );
1234 void WinSalFrame::SetMinClientSize( tools::Long nWidth, tools::Long nHeight )
1236 mnMinWidth = nWidth;
1237 mnMinHeight = nHeight;
1240 void WinSalFrame::SetMaxClientSize( tools::Long nWidth, tools::Long nHeight )
1242 mnMaxWidth = nWidth;
1243 mnMaxHeight = nHeight;
1246 void WinSalFrame::SetPosSize( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight,
1247 sal_uInt16 nFlags )
1249 bool bVisible = (GetWindowStyle( mhWnd ) & WS_VISIBLE) != 0;
1250 if ( !bVisible )
1252 vcl::Window *pClientWin = GetWindow()->ImplGetClientWindow();
1253 if ( mbFloatWin || ( pClientWin && (pClientWin->GetStyle() & WB_SYSTEMFLOATWIN) ) )
1254 mnShowState = SW_SHOWNOACTIVATE;
1255 else
1256 mnShowState = SW_SHOWNORMAL;
1258 else
1260 if ( IsIconic( mhWnd ) || IsZoomed( mhWnd ) )
1261 ShowWindow( mhWnd, SW_RESTORE );
1264 SalEvent nEvent = SalEvent::NONE;
1265 UINT nPosSize = 0;
1266 RECT aClientRect, aWindowRect;
1267 GetClientRect( mhWnd, &aClientRect ); // x,y always 0,0, but width and height without border
1268 GetWindowRect( mhWnd, &aWindowRect ); // x,y in screen coordinates, width and height with border
1270 if ( !(nFlags & (SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y)) )
1271 nPosSize |= SWP_NOMOVE;
1272 else
1274 //SAL_WARN_IF( !nX || !nY, "vcl", " Windowposition of (0,0) requested!" );
1275 nEvent = SalEvent::Move;
1277 if ( !(nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT)) )
1278 nPosSize |= SWP_NOSIZE;
1279 else
1280 nEvent = (nEvent == SalEvent::Move) ? SalEvent::MoveResize : SalEvent::Resize;
1282 if ( !(nFlags & SAL_FRAME_POSSIZE_X) )
1283 nX = aWindowRect.left;
1284 if ( !(nFlags & SAL_FRAME_POSSIZE_Y) )
1285 nY = aWindowRect.top;
1286 if ( !(nFlags & SAL_FRAME_POSSIZE_WIDTH) )
1287 nWidth = aClientRect.right-aClientRect.left;
1288 if ( !(nFlags & SAL_FRAME_POSSIZE_HEIGHT) )
1289 nHeight = aClientRect.bottom-aClientRect.top;
1291 // Calculate window size including the border
1292 RECT aWinRect;
1293 aWinRect.left = 0;
1294 aWinRect.right = static_cast<int>(nWidth)-1;
1295 aWinRect.top = 0;
1296 aWinRect.bottom = static_cast<int>(nHeight)-1;
1297 AdjustWindowRectEx( &aWinRect, GetWindowStyle( mhWnd ),
1298 FALSE, GetWindowExStyle( mhWnd ) );
1299 nWidth = aWinRect.right - aWinRect.left + 1;
1300 nHeight = aWinRect.bottom - aWinRect.top + 1;
1302 HWND hWndParent = ImplGetParentHwnd(mhWnd);
1303 // For dialogs (WS_POPUP && WS_DLGFRAME), we need to find the "real" parent,
1304 // in case multiple dialogs are stacked on each other
1305 // (we don't want to position the second dialog relative to the first one, but relative to the main window)
1306 if ( (GetWindowStyle( mhWnd ) & WS_POPUP) && (GetWindowStyle( mhWnd ) & WS_DLGFRAME) ) // mhWnd is a dialog
1308 while ( hWndParent && (GetWindowStyle( hWndParent ) & WS_POPUP) && (GetWindowStyle( hWndParent ) & WS_DLGFRAME) )
1310 hWndParent = ::ImplGetParentHwnd( hWndParent );
1314 if ( !(nPosSize & SWP_NOMOVE) && hWndParent )
1316 RECT aParentRect;
1317 GetClientRect( hWndParent, &aParentRect );
1318 if( AllSettings::GetLayoutRTL() )
1319 nX = (aParentRect.right - aParentRect.left) - nWidth-1 - nX;
1321 //#110386#, do not transform coordinates for system child windows
1322 if( !(GetWindowStyle( mhWnd ) & WS_CHILD) )
1324 POINT aPt;
1325 aPt.x = nX;
1326 aPt.y = nY;
1328 WinSalFrame* pParentFrame = GetWindowPtr( hWndParent );
1329 if ( pParentFrame && pParentFrame->mnShowState == SW_SHOWMAXIMIZED )
1331 // #i42485#: parent will be shown maximized in which case
1332 // a ClientToScreen uses the wrong coordinates (i.e. those from the restore pos)
1333 // so use the (already updated) frame geometry for the transformation
1334 aPt.x += pParentFrame->maGeometry.x();
1335 aPt.y += pParentFrame->maGeometry.y();
1337 else
1338 ClientToScreen( hWndParent, &aPt );
1340 nX = aPt.x;
1341 nY = aPt.y;
1343 // the position is set
1344 mbDefPos = false;
1348 // #i3338# to be conformant to UNIX we must position the client window, ie without the decoration
1349 // #i43250# if the position was read from the system (GetWindowRect(), see above), it must not be modified
1350 if ( nFlags & SAL_FRAME_POSSIZE_X )
1351 nX += aWinRect.left;
1352 if ( nFlags & SAL_FRAME_POSSIZE_Y )
1353 nY += aWinRect.top;
1355 int nScreenX;
1356 int nScreenY;
1357 int nScreenWidth;
1358 int nScreenHeight;
1360 RECT aRect;
1361 ImplSalGetWorkArea( mhWnd, &aRect, nullptr );
1362 nScreenX = aRect.left;
1363 nScreenY = aRect.top;
1364 nScreenWidth = aRect.right-aRect.left;
1365 nScreenHeight = aRect.bottom-aRect.top;
1367 if ( mbDefPos && (nPosSize & SWP_NOMOVE)) // we got no positioning request, so choose default position
1369 // center window
1371 HWND hWndParent2 = ::GetParent( mhWnd );
1372 // Search for TopLevel Frame
1373 while ( hWndParent2 && (GetWindowStyle( hWndParent2 ) & WS_CHILD) )
1374 hWndParent2 = ::GetParent( hWndParent2 );
1375 // if the Window has a Parent, then center the window to
1376 // the parent, in the other case to the screen
1377 if ( hWndParent2 && !IsIconic( hWndParent2 ) &&
1378 (GetWindowStyle( hWndParent2 ) & WS_VISIBLE) )
1380 RECT aParentRect;
1381 GetWindowRect( hWndParent2, &aParentRect );
1382 int nParentWidth = aParentRect.right-aParentRect.left;
1383 int nParentHeight = aParentRect.bottom-aParentRect.top;
1385 // We don't center, when Parent is smaller than our window
1386 if ( (nParentWidth-GetSystemMetrics( SM_CXFIXEDFRAME ) <= nWidth) &&
1387 (nParentHeight-GetSystemMetrics( SM_CYFIXEDFRAME ) <= nHeight) )
1389 int nOff = GetSystemMetrics( SM_CYSIZEFRAME ) + GetSystemMetrics( SM_CYCAPTION );
1390 nX = aParentRect.left+nOff;
1391 nY = aParentRect.top+nOff;
1393 else
1395 nX = (nParentWidth-nWidth)/2 + aParentRect.left;
1396 nY = (nParentHeight-nHeight)/2 + aParentRect.top;
1399 else
1401 POINT pt;
1402 GetCursorPos( &pt );
1403 RECT aRect2;
1404 aRect2.left = pt.x;
1405 aRect2.top = pt.y;
1406 aRect2.right = pt.x+2;
1407 aRect2.bottom = pt.y+2;
1409 // dualmonitor support:
1410 // Get screensize of the monitor with the mouse pointer
1411 ImplSalGetWorkArea( mhWnd, &aRect2, &aRect2 );
1413 nX = ((aRect2.right-aRect2.left)-nWidth)/2 + aRect2.left;
1414 nY = ((aRect2.bottom-aRect2.top)-nHeight)/2 + aRect2.top;
1417 //if ( bVisible )
1418 // mbDefPos = FALSE;
1420 mbDefPos = false; // center only once
1421 nPosSize &= ~SWP_NOMOVE; // activate positioning
1422 nEvent = SalEvent::MoveResize;
1425 // Adjust Window in the screen
1426 bool bCheckOffScreen = true;
1428 // but don't do this for floaters or ownerdraw windows that are currently moved interactively
1429 if( (mnStyle & SalFrameStyleFlags::FLOAT) && !(mnStyle & SalFrameStyleFlags::OWNERDRAWDECORATION) )
1430 bCheckOffScreen = false;
1432 if( mnStyle & SalFrameStyleFlags::OWNERDRAWDECORATION )
1434 // may be the window is currently being moved (mouse is captured), then no check is required
1435 if( mhWnd == ::GetCapture() )
1436 bCheckOffScreen = false;
1437 else
1438 bCheckOffScreen = true;
1441 if( bCheckOffScreen )
1443 if ( nX+nWidth > nScreenX+nScreenWidth )
1444 nX = (nScreenX+nScreenWidth) - nWidth;
1445 if ( nY+nHeight > nScreenY+nScreenHeight )
1446 nY = (nScreenY+nScreenHeight) - nHeight;
1447 if ( nX < nScreenX )
1448 nX = nScreenX;
1449 if ( nY < nScreenY )
1450 nY = nScreenY;
1453 UINT nPosFlags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | nPosSize;
1454 // bring floating windows always to top
1455 if( !(mnStyle & SalFrameStyleFlags::FLOAT) )
1456 nPosFlags |= SWP_NOZORDER; // do not change z-order
1458 SetWindowPos( mhWnd, HWND_TOP, nX, nY, static_cast<int>(nWidth), static_cast<int>(nHeight), nPosFlags );
1460 UpdateFrameGeometry(this);
1462 // Notification -- really ???
1463 if( nEvent != SalEvent::NONE )
1464 CallCallback( nEvent, nullptr );
1467 void WinSalFrame::ImplSetParentFrame( HWND hNewParentWnd, bool bAsChild )
1469 // save hwnd, will be overwritten in WM_CREATE during createwindow
1470 HWND hWndOld = mhWnd;
1471 HWND hWndOldParent = ::GetParent( hWndOld );
1472 SalData* pSalData = GetSalData();
1474 if( hNewParentWnd == hWndOldParent )
1475 return;
1477 ::std::vector< WinSalFrame* > children;
1478 ::std::vector< WinSalObject* > systemChildren;
1480 // search child windows
1481 WinSalFrame *pFrame = pSalData->mpFirstFrame;
1482 while( pFrame )
1484 HWND hWndParent = ::GetParent( pFrame->mhWnd );
1485 if( mhWnd == hWndParent )
1486 children.push_back( pFrame );
1487 pFrame = pFrame->mpNextFrame;
1490 // search system child windows (plugins etc.)
1491 WinSalObject *pObject = pSalData->mpFirstObject;
1492 while( pObject )
1494 HWND hWndParent = ::GetParent( pObject->mhWnd );
1495 if( mhWnd == hWndParent )
1496 systemChildren.push_back( pObject );
1497 pObject = pObject->mpNextObject;
1500 // to recreate the DCs, if they were destroyed
1501 bool bHadLocalGraphics = false, bHadThreadGraphics = false;
1503 HFONT hFont = nullptr;
1504 HPEN hPen = nullptr;
1505 HBRUSH hBrush = nullptr;
1507 int oldCount = pSalData->mnCacheDCInUse;
1509 // release the thread DC
1510 if ( mpThreadGraphics )
1512 // save current gdi objects before hdc is gone
1513 HDC hDC = mpThreadGraphics->getHDC();
1514 if ( hDC )
1516 hFont = static_cast<HFONT>(GetCurrentObject( hDC, OBJ_FONT ));
1517 hPen = static_cast<HPEN>(GetCurrentObject( hDC, OBJ_PEN ));
1518 hBrush = static_cast<HBRUSH>(GetCurrentObject( hDC, OBJ_BRUSH ));
1521 bHadThreadGraphics = ReleaseFrameGraphicsDC( mpThreadGraphics );
1522 assert( (bHadThreadGraphics && hDC) || (!bHadThreadGraphics && !hDC) );
1525 // release the local DC
1526 if ( mpLocalGraphics )
1527 bHadLocalGraphics = ReleaseFrameGraphicsDC( mpLocalGraphics );
1529 // create a new hwnd with the same styles
1530 HWND hWndParent = hNewParentWnd;
1531 // forward to main thread
1532 HWND hWnd = reinterpret_cast<HWND>(static_cast<sal_IntPtr>(SendMessageW( pSalData->mpInstance->mhComWnd,
1533 bAsChild ? SAL_MSG_RECREATECHILDHWND : SAL_MSG_RECREATEHWND,
1534 reinterpret_cast<WPARAM>(hWndParent), reinterpret_cast<LPARAM>(mhWnd) )));
1536 // succeeded ?
1537 SAL_WARN_IF( !IsWindow( hWnd ), "vcl", "WinSalFrame::SetParent not successful");
1539 // re-create thread DC
1540 if( bHadThreadGraphics )
1542 HDC hDC = reinterpret_cast<HDC>(static_cast<sal_IntPtr>(
1543 SendMessageW( pSalData->mpInstance->mhComWnd,
1544 SAL_MSG_GETCACHEDDC, reinterpret_cast<WPARAM>(hWnd), 0 )));
1545 InitFrameGraphicsDC( mpThreadGraphics, hDC, hWnd );
1546 if ( hDC )
1548 // re-select saved gdi objects
1549 if( hFont )
1550 SelectObject( hDC, hFont );
1551 if( hPen )
1552 SelectObject( hDC, hPen );
1553 if( hBrush )
1554 SelectObject( hDC, hBrush );
1556 SAL_WARN_IF( oldCount != pSalData->mnCacheDCInUse, "vcl", "WinSalFrame::SetParent() hDC count corrupted");
1560 // re-create local DC
1561 if( bHadLocalGraphics )
1562 InitFrameGraphicsDC( mpLocalGraphics, GetDC( hWnd ), hWnd );
1564 // TODO: add SetParent() call for SalObjects
1565 SAL_WARN_IF( !systemChildren.empty(), "vcl", "WinSalFrame::SetParent() parent of living system child window will be destroyed!");
1567 // reparent children before old parent is destroyed
1568 for (auto & child : children)
1569 child->ImplSetParentFrame( hWnd, false );
1571 children.clear();
1572 systemChildren.clear();
1574 // Now destroy original HWND in the thread where it was created.
1575 SendMessageW( GetSalData()->mpInstance->mhComWnd,
1576 SAL_MSG_DESTROYHWND, WPARAM(0), reinterpret_cast<LPARAM>(hWndOld));
1579 void WinSalFrame::SetParent( SalFrame* pNewParent )
1581 WinSalFrame::mbInReparent = true;
1582 ImplSetParentFrame( static_cast<WinSalFrame*>(pNewParent)->mhWnd, false );
1583 WinSalFrame::mbInReparent = false;
1586 void WinSalFrame::SetPluginParent( SystemParentData* pNewParent )
1588 if ( pNewParent->hWnd == nullptr )
1590 pNewParent->hWnd = GetDesktopWindow();
1593 WinSalFrame::mbInReparent = true;
1594 ImplSetParentFrame( pNewParent->hWnd, true );
1595 WinSalFrame::mbInReparent = false;
1598 void WinSalFrame::GetWorkArea( AbsoluteScreenPixelRectangle &rRect )
1600 RECT aRect;
1602 // pass cursor's position to ImplSalGetWorkArea to determine work area on
1603 // multi monitor setups correctly.
1604 POINT aPoint;
1605 GetCursorPos(&aPoint);
1606 RECT aRect2{ aPoint.x, aPoint.y, aPoint.x + 2, aPoint.y + 2 };
1608 ImplSalGetWorkArea( mhWnd, &aRect, &aRect2 );
1609 rRect.SetLeft( aRect.left );
1610 rRect.SetRight( aRect.right-1 );
1611 rRect.SetTop( aRect.top );
1612 rRect.SetBottom( aRect.bottom-1 );
1615 void WinSalFrame::GetClientSize( tools::Long& rWidth, tools::Long& rHeight )
1617 rWidth = maGeometry.width();
1618 rHeight = maGeometry.height();
1621 void WinSalFrame::SetWindowState(const vcl::WindowData* pState)
1623 // Check if the window fits into the screen, in case the screen
1624 // resolution changed
1625 int nX;
1626 int nY;
1627 int nWidth;
1628 int nHeight;
1629 int nScreenX;
1630 int nScreenY;
1631 int nScreenWidth;
1632 int nScreenHeight;
1634 RECT aRect;
1635 ImplSalGetWorkArea( mhWnd, &aRect, nullptr );
1636 // #102500# allow some overlap, the window could have been made a little larger than the physical screen
1637 nScreenX = aRect.left-10;
1638 nScreenY = aRect.top-10;
1639 nScreenWidth = aRect.right-aRect.left+20;
1640 nScreenHeight = aRect.bottom-aRect.top+20;
1642 UINT nPosSize = 0;
1643 RECT aWinRect;
1644 GetWindowRect( mhWnd, &aWinRect );
1646 // to be consistent with Unix, the frame state is without(!) decoration
1647 // ->add the decoration
1648 RECT aRect2 = aWinRect;
1649 AdjustWindowRectEx( &aRect2, GetWindowStyle( mhWnd ),
1650 FALSE, GetWindowExStyle( mhWnd ) );
1651 tools::Long nTopDeco = abs( aWinRect.top - aRect2.top );
1652 tools::Long nLeftDeco = abs( aWinRect.left - aRect2.left );
1653 tools::Long nBottomDeco = abs( aWinRect.bottom - aRect2.bottom );
1654 tools::Long nRightDeco = abs( aWinRect.right - aRect2.right );
1656 // adjust window position/size to fit the screen
1657 if ( !(pState->mask() & vcl::WindowDataMask::Pos) )
1658 nPosSize |= SWP_NOMOVE;
1659 if ( !(pState->mask() & vcl::WindowDataMask::Size) )
1660 nPosSize |= SWP_NOSIZE;
1661 if ( pState->mask() & vcl::WindowDataMask::X )
1662 nX = static_cast<int>(pState->x()) - nLeftDeco;
1663 else
1664 nX = aWinRect.left;
1665 if ( pState->mask() & vcl::WindowDataMask::Y )
1666 nY = static_cast<int>(pState->y()) - nTopDeco;
1667 else
1668 nY = aWinRect.top;
1669 if ( pState->mask() & vcl::WindowDataMask::Width )
1670 nWidth = static_cast<int>(pState->width()) + nLeftDeco + nRightDeco;
1671 else
1672 nWidth = aWinRect.right-aWinRect.left;
1673 if ( pState->mask() & vcl::WindowDataMask::Height )
1674 nHeight = static_cast<int>(pState->height()) + nTopDeco + nBottomDeco;
1675 else
1676 nHeight = aWinRect.bottom-aWinRect.top;
1678 // Adjust Window in the screen:
1679 // if it does not fit into the screen do nothing, ie default pos/size will be used
1680 // if there is an overlap with the screen border move the window while keeping its size
1682 if( nWidth > nScreenWidth || nHeight > nScreenHeight )
1683 nPosSize |= (SWP_NOMOVE | SWP_NOSIZE);
1685 if ( nX+nWidth > nScreenX+nScreenWidth )
1686 nX = (nScreenX+nScreenWidth) - nWidth;
1687 if ( nY+nHeight > nScreenY+nScreenHeight )
1688 nY = (nScreenY+nScreenHeight) - nHeight;
1689 if ( nX < nScreenX )
1690 nX = nScreenX;
1691 if ( nY < nScreenY )
1692 nY = nScreenY;
1694 // set Restore-Position
1695 WINDOWPLACEMENT aPlacement;
1696 aPlacement.length = sizeof( aPlacement );
1697 GetWindowPlacement( mhWnd, &aPlacement );
1699 // set State
1700 const bool bIsMinimized = IsIconic(mhWnd);
1701 const bool bIsMaximized = IsZoomed(mhWnd);
1702 const bool bVisible = (GetWindowStyle(mhWnd) & WS_VISIBLE);
1703 bool bUpdateHiddenFramePos = false;
1704 if ( !bVisible )
1706 aPlacement.showCmd = SW_HIDE;
1708 if (mbOverwriteState && (pState->mask() & vcl::WindowDataMask::State))
1710 if (pState->state() & vcl::WindowState::Minimized)
1711 mnShowState = SW_SHOWMINIMIZED;
1712 else if (pState->state() & vcl::WindowState::Maximized)
1714 mnShowState = SW_SHOWMAXIMIZED;
1715 bUpdateHiddenFramePos = true;
1717 else if (pState->state() & vcl::WindowState::Normal)
1718 mnShowState = SW_SHOWNORMAL;
1721 else
1723 if ( pState->mask() & vcl::WindowDataMask::State )
1725 if ( pState->state() & vcl::WindowState::Minimized )
1727 if ( pState->state() & vcl::WindowState::Maximized )
1728 aPlacement.flags |= WPF_RESTORETOMAXIMIZED;
1729 aPlacement.showCmd = SW_SHOWMINIMIZED;
1731 else if ( pState->state() & vcl::WindowState::Maximized )
1732 aPlacement.showCmd = SW_SHOWMAXIMIZED;
1733 else if ( pState->state() & vcl::WindowState::Normal )
1734 aPlacement.showCmd = SW_RESTORE;
1738 // if a window is neither minimized nor maximized or need not be
1739 // positioned visibly (that is in visible state), do not use
1740 // SetWindowPlacement since it calculates including the TaskBar
1741 if (!bIsMinimized && !bIsMaximized && (!bVisible || (aPlacement.showCmd == SW_RESTORE)))
1743 if( bUpdateHiddenFramePos )
1745 RECT aStateRect;
1746 aStateRect.left = nX;
1747 aStateRect.top = nY;
1748 aStateRect.right = nX+nWidth;
1749 aStateRect.bottom = nY+nHeight;
1750 // #96084 set a useful internal window size because
1751 // the window will not be maximized (and the size updated) before show()
1752 SetMaximizedFrameGeometry( mhWnd, this, &aStateRect );
1753 SetWindowPos( mhWnd, nullptr,
1754 maGeometry.x(), maGeometry.y(), maGeometry.width(), maGeometry.height(),
1755 SWP_NOZORDER | SWP_NOACTIVATE | nPosSize );
1757 else
1758 SetWindowPos( mhWnd, nullptr,
1759 nX, nY, nWidth, nHeight,
1760 SWP_NOZORDER | SWP_NOACTIVATE | nPosSize );
1762 else
1764 if( !(nPosSize & (SWP_NOMOVE|SWP_NOSIZE)) )
1766 aPlacement.rcNormalPosition.left = nX-nScreenX;
1767 aPlacement.rcNormalPosition.top = nY-nScreenY;
1768 aPlacement.rcNormalPosition.right = nX+nWidth-nScreenX;
1769 aPlacement.rcNormalPosition.bottom = nY+nHeight-nScreenY;
1771 SetWindowPlacement( mhWnd, &aPlacement );
1774 if( !(nPosSize & SWP_NOMOVE) )
1775 mbDefPos = false; // window was positioned
1778 bool WinSalFrame::GetWindowState(vcl::WindowData* pState)
1780 pState->setPosSize(maGeometry.posSize());
1781 pState->setState(m_eState);
1782 pState->setMask(vcl::WindowDataMask::PosSizeState);
1783 return true;
1786 void WinSalFrame::SetScreenNumber( unsigned int nNewScreen )
1788 WinSalSystem* pSys = static_cast<WinSalSystem*>(ImplGetSalSystem());
1789 if( pSys )
1791 const std::vector<WinSalSystem::DisplayMonitor>& rMonitors =
1792 pSys->getMonitors();
1793 size_t nMon = rMonitors.size();
1794 if( nNewScreen < nMon )
1796 AbsoluteScreenPixelPoint aOldMonPos, aNewMonPos( rMonitors[nNewScreen].m_aArea.TopLeft() );
1797 AbsoluteScreenPixelPoint aCurPos(maGeometry.pos());
1798 for( size_t i = 0; i < nMon; i++ )
1800 if( rMonitors[i].m_aArea.Contains( aCurPos ) )
1802 aOldMonPos = rMonitors[i].m_aArea.TopLeft();
1803 break;
1806 mnDisplay = nNewScreen;
1807 maGeometry.setScreen(nNewScreen);
1808 SetPosSize( aNewMonPos.X() + (maGeometry.x() - aOldMonPos.X()),
1809 aNewMonPos.Y() + (maGeometry.y() - aOldMonPos.Y()),
1810 0, 0,
1811 SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
1816 void WinSalFrame::SetApplicationID( const OUString &rApplicationID )
1818 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd378430(v=vs.85).aspx
1819 // A window's properties must be removed before the window is closed.
1821 IPropertyStore *pps;
1822 HRESULT hr = SHGetPropertyStoreForWindow(mhWnd, IID_PPV_ARGS(&pps));
1823 if (SUCCEEDED(hr))
1825 PROPVARIANT pv;
1826 if (!rApplicationID.isEmpty())
1828 hr = InitPropVariantFromString(o3tl::toW(rApplicationID.getStr()), &pv);
1829 mbPropertiesStored = true;
1831 else
1832 // if rApplicationID we remove the property from the window, if present
1833 PropVariantInit(&pv);
1835 if (SUCCEEDED(hr))
1837 hr = pps->SetValue(PKEY_AppUserModel_ID, pv);
1838 PropVariantClear(&pv);
1840 pps->Release();
1844 void WinSalFrame::ShowFullScreen(const bool bFullScreen, const sal_Int32 nDisplay)
1846 if ((isFullScreen() == bFullScreen) && (!bFullScreen || (mnDisplay == nDisplay)))
1847 return;
1849 mnDisplay = nDisplay;
1851 if ( bFullScreen )
1853 m_eState |= vcl::WindowState::FullScreen;
1854 // to hide the Windows taskbar
1855 DWORD nExStyle = GetWindowExStyle( mhWnd );
1856 if ( nExStyle & WS_EX_TOOLWINDOW )
1858 mbFullScreenToolWin = true;
1859 nExStyle &= ~WS_EX_TOOLWINDOW;
1860 SetWindowExStyle( mhWnd, nExStyle );
1862 // save old position
1863 GetWindowRect( mhWnd, &maFullScreenRect );
1865 // save show state
1866 mnFullScreenShowState = mnShowState;
1867 if ( !(GetWindowStyle( mhWnd ) & WS_VISIBLE) )
1868 mnShowState = SW_SHOW;
1870 // Save caption state.
1871 mbFullScreenCaption = mbCaption;
1872 if (mbCaption)
1874 DWORD nStyle = GetWindowStyle(mhWnd);
1875 SetWindowStyle(mhWnd, nStyle & ~WS_CAPTION);
1876 mbCaption = false;
1879 // set window to screen size
1880 ImplSalFrameFullScreenPos( this, true );
1882 else
1884 m_eState &= ~vcl::WindowState::FullScreen;
1885 // when the ShowState has to be reset, hide the window first to
1886 // reduce flicker
1887 bool bVisible = (GetWindowStyle( mhWnd ) & WS_VISIBLE) != 0;
1888 if ( bVisible && (mnShowState != mnFullScreenShowState) )
1889 ShowWindow( mhWnd, SW_HIDE );
1891 if ( mbFullScreenToolWin )
1892 SetWindowExStyle( mhWnd, GetWindowExStyle( mhWnd ) | WS_EX_TOOLWINDOW );
1893 mbFullScreenToolWin = false;
1895 // Restore caption state.
1896 if (mbFullScreenCaption)
1898 DWORD nStyle = GetWindowStyle(mhWnd);
1899 SetWindowStyle(mhWnd, nStyle | WS_CAPTION);
1901 mbCaption = mbFullScreenCaption;
1903 SetWindowPos( mhWnd, nullptr,
1904 maFullScreenRect.left,
1905 maFullScreenRect.top,
1906 maFullScreenRect.right-maFullScreenRect.left,
1907 maFullScreenRect.bottom-maFullScreenRect.top,
1908 SWP_NOZORDER | SWP_NOACTIVATE );
1910 // restore show state
1911 if ( mnShowState != mnFullScreenShowState )
1913 mnShowState = mnFullScreenShowState;
1914 if ( bVisible )
1916 mbInShow = true;
1917 ShowWindow( mhWnd, mnShowState );
1918 mbInShow = false;
1919 UpdateWindow( mhWnd );
1925 void WinSalFrame::StartPresentation( bool bStart )
1927 if ( mbPresentation == bStart )
1928 return;
1930 mbPresentation = bStart;
1932 if ( bStart )
1934 // turn off screen-saver / power saving when in Presentation mode
1935 SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);
1937 else
1939 // turn on screen-saver / power saving back
1940 SetThreadExecutionState(ES_CONTINUOUS);
1944 void WinSalFrame::SetAlwaysOnTop( bool bOnTop )
1946 HWND hWnd;
1947 if ( bOnTop )
1948 hWnd = HWND_TOPMOST;
1949 else
1950 hWnd = HWND_NOTOPMOST;
1951 SetWindowPos( mhWnd, hWnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
1954 static bool EnableAttachThreadInputHack()
1956 OUString aBootstrapUri;
1957 if (osl_getProcessWorkingDir(&aBootstrapUri.pData) != osl_Process_E_None)
1958 return false;
1959 aBootstrapUri += "/bootstrap.ini";
1961 OUString aSystemFileName;
1962 if (osl::FileBase::getSystemPathFromFileURL(aBootstrapUri, aSystemFileName) != osl::FileBase::E_None)
1963 return false;
1964 if (aSystemFileName.getLength() > MAX_PATH)
1965 return false;
1967 // this uses the Boost ini parser, instead of tools::Config, as we already use it to read other
1968 // values from bootstrap.ini in desktop/win32/source/loader.cxx, because that watchdog process
1969 // can't access LO libs. This way the handling is consistent.
1972 boost::property_tree::ptree pt;
1973 std::ifstream aFile(o3tl::toW(aSystemFileName.getStr()));
1974 boost::property_tree::ini_parser::read_ini(aFile, pt);
1975 const bool bEnabled = pt.get("Win32.EnableAttachThreadInputHack", false);
1976 SAL_WARN_IF(bEnabled, "vcl", "AttachThreadInput hack is enabled. Watch out for deadlocks!");
1977 return bEnabled;
1979 catch (...)
1981 return false;
1985 static void ImplSalToTop( HWND hWnd, SalFrameToTop nFlags )
1987 static const bool bEnableAttachThreadInputHack = EnableAttachThreadInputHack();
1989 WinSalFrame* pToTopFrame = GetWindowPtr( hWnd );
1990 if( pToTopFrame && (pToTopFrame->mnStyle & SalFrameStyleFlags::SYSTEMCHILD) )
1991 BringWindowToTop( hWnd );
1993 if ( nFlags & SalFrameToTop::ForegroundTask )
1995 // LO used to always call AttachThreadInput here, which resulted in deadlocks
1996 // in some installations for unknown reasons!
1997 if (bEnableAttachThreadInputHack)
1999 // This magic code is necessary to connect the input focus of the
2000 // current window thread and the thread which owns the window that
2001 // should be the new foreground window.
2002 HWND hCurrWnd = GetForegroundWindow();
2003 DWORD myThreadID = GetCurrentThreadId();
2004 DWORD currThreadID = GetWindowThreadProcessId(hCurrWnd,nullptr);
2005 AttachThreadInput(myThreadID, currThreadID, TRUE);
2006 SetForegroundWindow_Impl(hWnd);
2007 AttachThreadInput(myThreadID, currThreadID, FALSE);
2009 else
2010 SetForegroundWindow_Impl(hWnd);
2013 if ( nFlags & SalFrameToTop::RestoreWhenMin )
2015 HWND hIconicWnd = hWnd;
2016 while ( hIconicWnd )
2018 if ( IsIconic( hIconicWnd ) )
2020 WinSalFrame* pFrame = GetWindowPtr( hIconicWnd );
2021 if ( pFrame )
2023 if ( GetWindowPtr( hWnd )->mbRestoreMaximize )
2024 ShowWindow( hIconicWnd, SW_MAXIMIZE );
2025 else
2026 ShowWindow( hIconicWnd, SW_RESTORE );
2028 else
2029 ShowWindow( hIconicWnd, SW_RESTORE );
2032 hIconicWnd = ::GetParent( hIconicWnd );
2036 if ( !IsIconic( hWnd ) && IsWindowVisible( hWnd ) )
2038 SetFocus( hWnd );
2040 // Windows sometimes incorrectly reports to have the focus;
2041 // thus make sure to really get the focus
2042 if ( ::GetFocus() == hWnd )
2043 SetForegroundWindow_Impl( hWnd );
2047 void WinSalFrame::ToTop( SalFrameToTop nFlags )
2049 nFlags &= ~SalFrameToTop::GrabFocus; // this flag is not needed on win32
2050 // Post this Message to the window, because this only works
2051 // in the thread of the window, which has create this window.
2052 // We post this message to avoid deadlocks
2053 if ( GetSalData()->mnAppThreadId != GetCurrentThreadId() )
2055 bool const ret = PostMessageW( mhWnd, SAL_MSG_TOTOP, static_cast<WPARAM>(nFlags), 0 );
2056 SAL_WARN_IF(!ret, "vcl", "ERROR: PostMessage() failed!");
2058 else
2059 ImplSalToTop( mhWnd, nFlags );
2062 void WinSalFrame::SetPointer( PointerStyle ePointerStyle )
2064 struct ImplPtrData
2066 HCURSOR mhCursor;
2067 LPCTSTR mnSysId;
2068 UINT mnOwnId;
2071 static o3tl::enumarray<PointerStyle, ImplPtrData> aImplPtrTab =
2073 // [-loplugin:redundantfcast]:
2074 ImplPtrData{ nullptr, IDC_ARROW, 0 }, // POINTER_ARROW
2075 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_NULL }, // POINTER_NULL
2076 ImplPtrData{ nullptr, IDC_WAIT, 0 }, // POINTER_WAIT
2077 ImplPtrData{ nullptr, IDC_IBEAM, 0 }, // POINTER_TEXT
2078 ImplPtrData{ nullptr, IDC_HELP, 0 }, // POINTER_HELP
2079 ImplPtrData{ nullptr, IDC_CROSS, 0 }, // POINTER_CROSS
2080 ImplPtrData{ nullptr, IDC_SIZEALL, 0 }, // POINTER_MOVE
2081 ImplPtrData{ nullptr, IDC_SIZENS, 0 }, // POINTER_NSIZE
2082 ImplPtrData{ nullptr, IDC_SIZENS, 0 }, // POINTER_SSIZE
2083 ImplPtrData{ nullptr, IDC_SIZEWE, 0 }, // POINTER_WSIZE
2084 ImplPtrData{ nullptr, IDC_SIZEWE, 0 }, // POINTER_ESIZE
2085 ImplPtrData{ nullptr, IDC_SIZENWSE, 0 }, // POINTER_NWSIZE
2086 ImplPtrData{ nullptr, IDC_SIZENESW, 0 }, // POINTER_NESIZE
2087 ImplPtrData{ nullptr, IDC_SIZENESW, 0 }, // POINTER_SWSIZE
2088 ImplPtrData{ nullptr, IDC_SIZENWSE, 0 }, // POINTER_SESIZE
2089 ImplPtrData{ nullptr, IDC_SIZENS, 0 }, // POINTER_WINDOW_NSIZE
2090 ImplPtrData{ nullptr, IDC_SIZENS, 0 }, // POINTER_WINDOW_SSIZE
2091 ImplPtrData{ nullptr, IDC_SIZEWE, 0 }, // POINTER_WINDOW_WSIZE
2092 ImplPtrData{ nullptr, IDC_SIZEWE, 0 }, // POINTER_WINDOW_ESIZE
2093 ImplPtrData{ nullptr, IDC_SIZENWSE, 0 }, // POINTER_WINDOW_NWSIZE
2094 ImplPtrData{ nullptr, IDC_SIZENESW, 0 }, // POINTER_WINDOW_NESIZE
2095 ImplPtrData{ nullptr, IDC_SIZENESW, 0 }, // POINTER_WINDOW_SWSIZE
2096 ImplPtrData{ nullptr, IDC_SIZENWSE, 0 }, // POINTER_WINDOW_SESIZE
2097 ImplPtrData{ nullptr, IDC_SIZEWE, 0 }, // POINTER_HSPLIT
2098 ImplPtrData{ nullptr, IDC_SIZENS, 0 }, // POINTER_VSPLIT
2099 ImplPtrData{ nullptr, IDC_SIZEWE, 0 }, // POINTER_HSIZEBAR
2100 ImplPtrData{ nullptr, IDC_SIZENS, 0 }, // POINTER_VSIZEBAR
2101 ImplPtrData{ nullptr, IDC_HAND, 0 }, // POINTER_HAND
2102 ImplPtrData{ nullptr, IDC_HAND, 0 }, // POINTER_REFHAND
2103 ImplPtrData{ nullptr, IDC_PEN, 0 }, // POINTER_PEN
2104 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_MAGNIFY }, // POINTER_MAGNIFY
2105 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_FILL }, // POINTER_FILL
2106 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_ROTATE }, // POINTER_ROTATE
2107 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_HSHEAR }, // POINTER_HSHEAR
2108 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_VSHEAR }, // POINTER_VSHEAR
2109 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_MIRROR }, // POINTER_MIRROR
2110 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_CROOK }, // POINTER_CROOK
2111 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_CROP }, // POINTER_CROP
2112 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_MOVEPOINT }, // POINTER_MOVEPOINT
2113 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_MOVEBEZIERWEIGHT }, // POINTER_MOVEBEZIERWEIGHT
2114 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_MOVEDATA }, // POINTER_MOVEDATA
2115 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_COPYDATA }, // POINTER_COPYDATA
2116 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_LINKDATA }, // POINTER_LINKDATA
2117 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_MOVEDATALINK }, // POINTER_MOVEDATALINK
2118 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_COPYDATALINK }, // POINTER_COPYDATALINK
2119 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_MOVEFILE }, // POINTER_MOVEFILE
2120 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_COPYFILE }, // POINTER_COPYFILE
2121 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_LINKFILE }, // POINTER_LINKFILE
2122 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_MOVEFILELINK }, // POINTER_MOVEFILELINK
2123 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_COPYFILELINK }, // POINTER_COPYFILELINK
2124 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_MOVEFILES }, // POINTER_MOVEFILES
2125 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_COPYFILES }, // POINTER_COPYFILES
2126 ImplPtrData{ nullptr, IDC_NO, 0 }, // POINTER_NOTALLOWED
2127 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DRAW_LINE }, // POINTER_DRAW_LINE
2128 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DRAW_RECT }, // POINTER_DRAW_RECT
2129 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DRAW_POLYGON }, // POINTER_DRAW_POLYGON
2130 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DRAW_BEZIER }, // POINTER_DRAW_BEZIER
2131 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DRAW_ARC }, // POINTER_DRAW_ARC
2132 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DRAW_PIE }, // POINTER_DRAW_PIE
2133 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DRAW_CIRCLECUT }, // POINTER_DRAW_CIRCLECUT
2134 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DRAW_ELLIPSE }, // POINTER_DRAW_ELLIPSE
2135 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DRAW_FREEHAND }, // POINTER_DRAW_FREEHAND
2136 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DRAW_CONNECT }, // POINTER_DRAW_CONNECT
2137 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DRAW_TEXT }, // POINTER_DRAW_TEXT
2138 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DRAW_CAPTION }, // POINTER_DRAW_CAPTION
2139 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_CHART }, // POINTER_CHART
2140 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_DETECTIVE }, // POINTER_DETECTIVE
2141 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_PIVOT_COL }, // POINTER_PIVOT_COL
2142 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_PIVOT_ROW }, // POINTER_PIVOT_ROW
2143 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_PIVOT_FIELD }, // POINTER_PIVOT_FIELD
2144 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_CHAIN }, // POINTER_CHAIN
2145 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_CHAIN_NOTALLOWED }, // POINTER_CHAIN_NOTALLOWED
2146 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_N }, // POINTER_AUTOSCROLL_N
2147 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_S }, // POINTER_AUTOSCROLL_S
2148 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_W }, // POINTER_AUTOSCROLL_W
2149 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_E }, // POINTER_AUTOSCROLL_E
2150 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_NW }, // POINTER_AUTOSCROLL_NW
2151 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_NE }, // POINTER_AUTOSCROLL_NE
2152 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_SW }, // POINTER_AUTOSCROLL_SW
2153 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_SE }, // POINTER_AUTOSCROLL_SE
2154 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_NS }, // POINTER_AUTOSCROLL_NS
2155 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_WE }, // POINTER_AUTOSCROLL_WE
2156 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_NSWE }, // POINTER_AUTOSCROLL_NSWE
2157 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_TEXT_VERTICAL }, // POINTER_TEXT_VERTICAL
2158 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_PIVOT_DELETE }, // POINTER_PIVOT_DELETE
2160 // #i32329#
2161 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_TAB_SELECT_S }, // POINTER_TAB_SELECT_S
2162 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_TAB_SELECT_E }, // POINTER_TAB_SELECT_E
2163 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_TAB_SELECT_SE }, // POINTER_TAB_SELECT_SE
2164 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_TAB_SELECT_W }, // POINTER_TAB_SELECT_W
2165 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_TAB_SELECT_SW }, // POINTER_TAB_SELECT_SW
2167 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_HIDEWHITESPACE }, // POINTER_HIDEWHITESPACE
2168 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_SHOWWHITESPACE }, // POINTER_UNHIDEWHITESPACE
2170 ImplPtrData{ nullptr, nullptr, SAL_RESID_POINTER_FATCROSS } // POINTER_FATCROSS
2173 // Mousepointer loaded ?
2174 if ( !aImplPtrTab[ePointerStyle].mhCursor )
2176 if ( aImplPtrTab[ePointerStyle].mnOwnId )
2177 aImplPtrTab[ePointerStyle].mhCursor = ImplLoadSalCursor( aImplPtrTab[ePointerStyle].mnOwnId );
2178 else
2179 aImplPtrTab[ePointerStyle].mhCursor = LoadCursor( nullptr, aImplPtrTab[ePointerStyle].mnSysId );
2182 // change the mouse pointer if different
2183 if ( mhCursor != aImplPtrTab[ePointerStyle].mhCursor )
2185 mhCursor = aImplPtrTab[ePointerStyle].mhCursor;
2186 SetCursor( mhCursor );
2190 void WinSalFrame::CaptureMouse( bool bCapture )
2192 // Send this Message to the window, because CaptureMouse() only work
2193 // in the thread of the window, which has create this window
2194 int nMsg;
2195 if ( bCapture )
2196 nMsg = SAL_MSG_CAPTUREMOUSE;
2197 else
2198 nMsg = SAL_MSG_RELEASEMOUSE;
2199 SendMessageW( mhWnd, nMsg, 0, 0 );
2202 void WinSalFrame::SetPointerPos( tools::Long nX, tools::Long nY )
2204 POINT aPt;
2205 aPt.x = static_cast<int>(nX);
2206 aPt.y = static_cast<int>(nY);
2207 ClientToScreen( mhWnd, &aPt );
2208 SetCursorPos( aPt.x, aPt.y );
2211 void WinSalFrame::Flush()
2213 if(mpLocalGraphics)
2214 mpLocalGraphics->Flush();
2215 if(mpThreadGraphics)
2216 mpThreadGraphics->Flush();
2217 GdiFlush();
2220 static void ImplSalFrameSetInputContext( HWND hWnd, const SalInputContext* pContext )
2222 WinSalFrame* pFrame = GetWindowPtr( hWnd );
2223 bool bIME(pContext->mnOptions & InputContextFlags::Text);
2224 if ( bIME )
2226 if ( !pFrame->mbIME )
2228 pFrame->mbIME = true;
2230 if ( pFrame->mhDefIMEContext )
2232 ImmAssociateContext( pFrame->mhWnd, pFrame->mhDefIMEContext );
2233 UINT nImeProps = ImmGetProperty( GetKeyboardLayout( 0 ), IGP_PROPERTY );
2234 pFrame->mbSpezIME = (nImeProps & IME_PROP_SPECIAL_UI) != 0;
2235 pFrame->mbAtCursorIME = (nImeProps & IME_PROP_AT_CARET) != 0;
2236 pFrame->mbHandleIME = !pFrame->mbSpezIME;
2240 // When the application can't handle IME messages, then the
2241 // System should handle the IME handling
2242 if ( !(pContext->mnOptions & InputContextFlags::ExtText) )
2243 pFrame->mbHandleIME = false;
2245 // Set the Font for IME Handling
2246 if ( pContext->mpFont )
2248 HIMC hIMC = ImmGetContext( pFrame->mhWnd );
2249 if ( hIMC )
2251 LOGFONTW aLogFont;
2252 ImplGetLogFontFromFontSelect(pContext->mpFont->GetFontSelectPattern(),
2253 nullptr, aLogFont);
2254 ImmSetCompositionFontW( hIMC, &aLogFont );
2255 ImmReleaseContext( pFrame->mhWnd, hIMC );
2259 else
2261 if ( pFrame->mbIME )
2263 pFrame->mbIME = false;
2264 pFrame->mbHandleIME = false;
2265 ImmAssociateContext( pFrame->mhWnd, nullptr );
2270 void WinSalFrame::SetInputContext( SalInputContext* pContext )
2272 // Must be called in the main thread!
2273 SendMessageW( mhWnd, SAL_MSG_SETINPUTCONTEXT, 0, reinterpret_cast<LPARAM>(pContext) );
2276 static void ImplSalFrameEndExtTextInput( HWND hWnd, EndExtTextInputFlags nFlags )
2278 HIMC hIMC = ImmGetContext( hWnd );
2279 if ( hIMC )
2281 DWORD nIndex;
2282 if ( nFlags & EndExtTextInputFlags::Complete )
2283 nIndex = CPS_COMPLETE;
2284 else
2285 nIndex = CPS_CANCEL;
2287 ImmNotifyIME( hIMC, NI_COMPOSITIONSTR, nIndex, 0 );
2288 ImmReleaseContext( hWnd, hIMC );
2292 void WinSalFrame::EndExtTextInput( EndExtTextInputFlags nFlags )
2294 // Must be called in the main thread!
2295 SendMessageW( mhWnd, SAL_MSG_ENDEXTTEXTINPUT, static_cast<WPARAM>(nFlags), 0 );
2298 static void ImplGetKeyNameText( LONG lParam, sal_Unicode* pBuf,
2299 UINT& rCount, UINT nMaxSize,
2300 const char* pReplace )
2302 static_assert( sizeof( WCHAR ) == sizeof( sal_Unicode ), "must be the same size" );
2304 static const int nMaxKeyLen = 350;
2305 WCHAR aKeyBuf[ nMaxKeyLen ];
2306 int nKeyLen = 0;
2307 if ( lParam )
2309 OUString aLang = Application::GetSettings().GetUILanguageTag().getLanguage();
2310 OUString aRet;
2312 aRet = ::vcl_sal::getKeysReplacementName( aLang, lParam );
2313 if( aRet.isEmpty() )
2315 nKeyLen = GetKeyNameTextW( lParam, aKeyBuf, nMaxKeyLen );
2316 SAL_WARN_IF( nKeyLen > nMaxKeyLen, "vcl", "Invalid key name length!" );
2317 if( nKeyLen > nMaxKeyLen )
2318 nKeyLen = 0;
2319 else if( nKeyLen > 0 )
2321 // Capitalize just the first letter of key names
2322 CharLowerBuffW( aKeyBuf, nKeyLen );
2324 bool bUpper = true;
2325 for( WCHAR *pW=aKeyBuf, *pE=pW+nKeyLen; pW < pE; ++pW )
2327 if( bUpper )
2328 CharUpperBuffW( pW, 1 );
2329 bUpper = (*pW=='+') || (*pW=='-') || (*pW==' ') || (*pW=='.');
2333 else
2335 nKeyLen = aRet.getLength();
2336 wcscpy( aKeyBuf, o3tl::toW( aRet.getStr() ));
2340 if ( (nKeyLen > 0) || pReplace )
2342 if( (rCount > 0) && (rCount < nMaxSize) )
2344 pBuf[rCount] = '+';
2345 rCount++;
2348 if( nKeyLen > 0 )
2350 WCHAR *pW = aKeyBuf, *pE = aKeyBuf + nKeyLen;
2351 while ((pW < pE) && *pW && (rCount < nMaxSize))
2352 pBuf[rCount++] = *pW++;
2354 else // fall back to provided default name
2356 while( *pReplace && (rCount < nMaxSize) )
2358 pBuf[rCount] = *pReplace;
2359 rCount++;
2360 pReplace++;
2364 else
2365 rCount = 0;
2368 OUString WinSalFrame::GetKeyName( sal_uInt16 nKeyCode )
2370 static const UINT nMaxKeyLen = 350;
2371 sal_Unicode aKeyBuf[ nMaxKeyLen ];
2372 UINT nKeyBufLen = 0;
2373 UINT nSysCode = 0;
2375 if ( nKeyCode & KEY_MOD1 )
2377 nSysCode = MapVirtualKeyW( VK_CONTROL, 0 );
2378 nSysCode = (nSysCode << 16) | ((sal_uLong(1)) << 25);
2379 ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, "Ctrl" );
2382 if ( nKeyCode & KEY_MOD2 )
2384 nSysCode = MapVirtualKeyW( VK_MENU, 0 );
2385 nSysCode = (nSysCode << 16) | ((sal_uLong(1)) << 25);
2386 ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, "Alt" );
2389 if ( nKeyCode & KEY_SHIFT )
2391 nSysCode = MapVirtualKeyW( VK_SHIFT, 0 );
2392 nSysCode = (nSysCode << 16) | ((sal_uLong(1)) << 25);
2393 ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, "Shift" );
2396 sal_uInt16 nCode = nKeyCode & 0x0FFF;
2397 sal_uLong nSysCode2 = 0;
2398 const char* pReplace = nullptr;
2399 sal_Unicode cSVCode = 0;
2400 char aFBuf[4];
2401 nSysCode = 0;
2403 if ( (nCode >= KEY_0) && (nCode <= KEY_9) )
2404 cSVCode = '0' + (nCode - KEY_0);
2405 else if ( (nCode >= KEY_A) && (nCode <= KEY_Z) )
2406 cSVCode = 'A' + (nCode - KEY_A);
2407 else if ( (nCode >= KEY_F1) && (nCode <= KEY_F26) )
2409 nSysCode = VK_F1 + (nCode - KEY_F1);
2410 aFBuf[0] = 'F';
2411 if (nCode <= KEY_F9)
2413 aFBuf[1] = sal::static_int_cast<char>('1' + (nCode - KEY_F1));
2414 aFBuf[2] = 0;
2416 else if (nCode <= KEY_F19)
2418 aFBuf[1] = '1';
2419 aFBuf[2] = sal::static_int_cast<char>('0' + (nCode - KEY_F10));
2420 aFBuf[3] = 0;
2422 else
2424 aFBuf[1] = '2';
2425 aFBuf[2] = sal::static_int_cast<char>('0' + (nCode - KEY_F20));
2426 aFBuf[3] = 0;
2428 pReplace = aFBuf;
2430 else
2432 switch ( nCode )
2434 case KEY_DOWN:
2435 nSysCode = VK_DOWN;
2436 nSysCode2 = ((sal_uLong(1)) << 24);
2437 pReplace = "Down";
2438 break;
2439 case KEY_UP:
2440 nSysCode = VK_UP;
2441 nSysCode2 = ((sal_uLong(1)) << 24);
2442 pReplace = "Up";
2443 break;
2444 case KEY_LEFT:
2445 nSysCode = VK_LEFT;
2446 nSysCode2 = ((sal_uLong(1)) << 24);
2447 pReplace = "Left";
2448 break;
2449 case KEY_RIGHT:
2450 nSysCode = VK_RIGHT;
2451 nSysCode2 = ((sal_uLong(1)) << 24);
2452 pReplace = "Right";
2453 break;
2454 case KEY_HOME:
2455 nSysCode = VK_HOME;
2456 nSysCode2 = ((sal_uLong(1)) << 24);
2457 pReplace = "Home";
2458 break;
2459 case KEY_END:
2460 nSysCode = VK_END;
2461 nSysCode2 = ((sal_uLong(1)) << 24);
2462 pReplace = "End";
2463 break;
2464 case KEY_PAGEUP:
2465 nSysCode = VK_PRIOR;
2466 nSysCode2 = ((sal_uLong(1)) << 24);
2467 pReplace = "Page Up";
2468 break;
2469 case KEY_PAGEDOWN:
2470 nSysCode = VK_NEXT;
2471 nSysCode2 = ((sal_uLong(1)) << 24);
2472 pReplace = "Page Down";
2473 break;
2474 case KEY_RETURN:
2475 nSysCode = VK_RETURN;
2476 pReplace = "Enter";
2477 break;
2478 case KEY_ESCAPE:
2479 nSysCode = VK_ESCAPE;
2480 pReplace = "Escape";
2481 break;
2482 case KEY_TAB:
2483 nSysCode = VK_TAB;
2484 pReplace = "Tab";
2485 break;
2486 case KEY_BACKSPACE:
2487 nSysCode = VK_BACK;
2488 pReplace = "Backspace";
2489 break;
2490 case KEY_SPACE:
2491 nSysCode = VK_SPACE;
2492 pReplace = "Space";
2493 break;
2494 case KEY_INSERT:
2495 nSysCode = VK_INSERT;
2496 nSysCode2 = ((sal_uLong(1)) << 24);
2497 pReplace = "Insert";
2498 break;
2499 case KEY_DELETE:
2500 nSysCode = VK_DELETE;
2501 nSysCode2 = ((sal_uLong(1)) << 24);
2502 pReplace = "Delete";
2503 break;
2505 case KEY_ADD:
2506 cSVCode = '+';
2507 break;
2508 case KEY_SUBTRACT:
2509 cSVCode = '-';
2510 break;
2511 case KEY_MULTIPLY:
2512 cSVCode = '*';
2513 break;
2514 case KEY_DIVIDE:
2515 cSVCode = '/';
2516 break;
2517 case KEY_POINT:
2518 cSVCode = '.';
2519 break;
2520 case KEY_COMMA:
2521 cSVCode = ',';
2522 break;
2523 case KEY_LESS:
2524 cSVCode = '<';
2525 break;
2526 case KEY_GREATER:
2527 cSVCode = '>';
2528 break;
2529 case KEY_EQUAL:
2530 cSVCode = '=';
2531 break;
2532 case KEY_NUMBERSIGN:
2533 cSVCode = '#';
2534 break;
2535 case KEY_XF86FORWARD:
2536 cSVCode = VK_BROWSER_FORWARD;
2537 break;
2538 case KEY_XF86BACK:
2539 cSVCode = VK_BROWSER_BACK;
2540 break;
2541 case KEY_COLON:
2542 cSVCode = ':';
2543 break;
2544 case KEY_SEMICOLON:
2545 cSVCode = ';';
2546 break;
2547 case KEY_QUOTERIGHT:
2548 cSVCode = '\'';
2549 break;
2550 case KEY_BRACKETLEFT:
2551 cSVCode = '[';
2552 break;
2553 case KEY_BRACKETRIGHT:
2554 cSVCode = ']';
2555 break;
2556 case KEY_QUOTELEFT:
2557 cSVCode = '`';
2558 break;
2559 case KEY_RIGHTCURLYBRACKET:
2560 cSVCode = '}';
2561 break;
2565 if ( nSysCode )
2567 nSysCode = MapVirtualKeyW( nSysCode, 0 );
2568 if ( nSysCode )
2569 nSysCode = (nSysCode << 16) | nSysCode2;
2570 ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, pReplace );
2572 else
2574 if ( cSVCode )
2576 if ( nKeyBufLen > 0 )
2577 aKeyBuf[ nKeyBufLen++ ] = '+';
2578 if( nKeyBufLen < nMaxKeyLen )
2579 aKeyBuf[ nKeyBufLen++ ] = cSVCode;
2583 if( !nKeyBufLen )
2584 return OUString();
2586 return OUString( aKeyBuf, sal::static_int_cast< sal_uInt16 >(nKeyBufLen) );
2589 static Color ImplWinColorToSal( COLORREF nColor )
2591 return Color( GetRValue( nColor ), GetGValue( nColor ), GetBValue( nColor ) );
2594 static void ImplSalUpdateStyleFontW( HDC hDC, const LOGFONTW& rLogFont, vcl::Font& rFont )
2596 ImplSalLogFontToFontW( hDC, rLogFont, rFont );
2598 // On Windows 9x, Windows NT we get sometimes very small sizes
2599 // (for example for the small Caption height).
2600 // So if it is MS Sans Serif, a none scalable font we use
2601 // 8 Point as the minimum control height, in all other cases
2602 // 6 Point is the smallest one
2603 if ( rFont.GetFontHeight() < 8 )
2605 if ( rtl_ustr_compareIgnoreAsciiCase( o3tl::toU(rLogFont.lfFaceName), o3tl::toU(L"MS Sans Serif") ) == 0 )
2606 rFont.SetFontHeight( 8 );
2607 else if ( rFont.GetFontHeight() < 6 )
2608 rFont.SetFontHeight( 6 );
2612 static tools::Long ImplW2I( const wchar_t* pStr )
2614 tools::Long n = 0;
2615 int nSign = 1;
2617 if ( *pStr == '-' )
2619 nSign = -1;
2620 pStr++;
2623 while( (*pStr >= 48) && (*pStr <= 57) )
2625 n *= 10;
2626 n += ((*pStr) - 48);
2627 pStr++;
2630 n *= nSign;
2632 return n;
2635 void WinSalFrame::UpdateSettings( AllSettings& rSettings )
2637 MouseSettings aMouseSettings = rSettings.GetMouseSettings();
2638 aMouseSettings.SetDoubleClickTime( GetDoubleClickTime() );
2639 aMouseSettings.SetDoubleClickWidth( GetSystemMetrics( SM_CXDOUBLECLK ) );
2640 aMouseSettings.SetDoubleClickHeight( GetSystemMetrics( SM_CYDOUBLECLK ) );
2641 tools::Long nDragWidth = GetSystemMetrics( SM_CXDRAG );
2642 tools::Long nDragHeight = GetSystemMetrics( SM_CYDRAG );
2643 if ( nDragWidth )
2644 aMouseSettings.SetStartDragWidth( nDragWidth );
2645 if ( nDragHeight )
2646 aMouseSettings.SetStartDragHeight( nDragHeight );
2647 HKEY hRegKey;
2648 if ( RegOpenKeyW( HKEY_CURRENT_USER,
2649 L"Control Panel\\Desktop",
2650 &hRegKey ) == ERROR_SUCCESS )
2652 wchar_t aValueBuf[10];
2653 DWORD nValueSize = sizeof( aValueBuf );
2654 DWORD nType;
2655 if ( RegQueryValueExW( hRegKey, L"MenuShowDelay", nullptr,
2656 &nType, reinterpret_cast<LPBYTE>(aValueBuf), &nValueSize ) == ERROR_SUCCESS )
2658 if ( nType == REG_SZ )
2659 aMouseSettings.SetMenuDelay( static_cast<sal_uLong>(ImplW2I( aValueBuf )) );
2662 RegCloseKey( hRegKey );
2665 StyleSettings aStyleSettings = rSettings.GetStyleSettings();
2667 // High contrast
2668 HIGHCONTRAST hc;
2669 hc.cbSize = sizeof( HIGHCONTRAST );
2670 if( SystemParametersInfoW( SPI_GETHIGHCONTRAST, hc.cbSize, &hc, 0 )
2671 && (hc.dwFlags & HCF_HIGHCONTRASTON) )
2672 aStyleSettings.SetHighContrastMode( true );
2673 else
2674 aStyleSettings.SetHighContrastMode( false );
2676 aStyleSettings.SetScrollBarSize( GetSystemMetrics( SM_CXVSCROLL ) );
2677 aStyleSettings.SetSpinSize( GetSystemMetrics( SM_CXVSCROLL ) );
2678 UINT blinkTime = GetCaretBlinkTime();
2679 aStyleSettings.SetCursorBlinkTime(
2680 blinkTime == 0 || blinkTime == INFINITE // 0 indicates error
2681 ? STYLE_CURSOR_NOBLINKTIME : blinkTime );
2682 aStyleSettings.SetFloatTitleHeight( GetSystemMetrics( SM_CYSMCAPTION ) );
2683 aStyleSettings.SetTitleHeight( GetSystemMetrics( SM_CYCAPTION ) );
2684 aStyleSettings.SetActiveBorderColor( ImplWinColorToSal( GetSysColor( COLOR_ACTIVEBORDER ) ) );
2685 aStyleSettings.SetDeactiveBorderColor( ImplWinColorToSal( GetSysColor( COLOR_INACTIVEBORDER ) ) );
2686 aStyleSettings.SetDeactiveColor( ImplWinColorToSal( GetSysColor( COLOR_GRADIENTINACTIVECAPTION ) ) );
2688 Color aControlTextColor;
2689 Color aMenuBarTextColor;
2690 Color aMenuBarRolloverTextColor;
2691 Color aHighlightTextColor = ImplWinColorToSal(GetSysColor(COLOR_HIGHLIGHTTEXT));
2693 BOOL bFlatMenus = FALSE;
2694 SystemParametersInfoW( SPI_GETFLATMENU, 0, &bFlatMenus, 0);
2695 if( bFlatMenus )
2697 aStyleSettings.SetUseFlatMenus( true );
2698 // flat borders for our controls etc. as well in this mode (ie, no 3d borders)
2699 // this is not active in the classic style appearance
2700 aStyleSettings.SetUseFlatBorders( true );
2702 else
2704 aStyleSettings.SetUseFlatMenus( false );
2705 aStyleSettings.SetUseFlatBorders( false );
2708 if( bFlatMenus )
2710 aStyleSettings.SetMenuHighlightColor( ImplWinColorToSal( GetSysColor( COLOR_MENUHILIGHT ) ) );
2711 aStyleSettings.SetMenuBarRolloverColor( ImplWinColorToSal( GetSysColor( COLOR_MENUHILIGHT ) ) );
2712 aStyleSettings.SetMenuBorderColor( ImplWinColorToSal( GetSysColor( COLOR_3DSHADOW ) ) );
2714 else
2716 aStyleSettings.SetMenuHighlightColor( ImplWinColorToSal( GetSysColor( COLOR_HIGHLIGHT ) ) );
2717 aStyleSettings.SetMenuBarRolloverColor( ImplWinColorToSal( GetSysColor( COLOR_HIGHLIGHT ) ) );
2718 aStyleSettings.SetMenuBorderColor( ImplWinColorToSal( GetSysColor( COLOR_3DLIGHT ) ) );
2721 const bool bUseDarkMode(UseDarkMode());
2723 OUString sThemeName(!bUseDarkMode ? u"colibre" : u"colibre_dark");
2724 aStyleSettings.SetPreferredIconTheme(sThemeName, bUseDarkMode);
2726 if (bUseDarkMode)
2728 SetWindowTheme(mhWnd, L"Explorer", nullptr);
2730 HTHEME hTheme = OpenThemeData(nullptr, L"ItemsView");
2731 COLORREF color;
2732 GetThemeColor(hTheme, 0, 0, TMT_FILLCOLOR, &color);
2733 aStyleSettings.SetFaceColor( ImplWinColorToSal( color ) );
2734 aStyleSettings.SetWindowColor( ImplWinColorToSal( color ) );
2736 // tdf#156040 in the absence of a better idea, do like
2737 // StyleSettings::Set3DColors does
2738 Color aLightColor(ImplWinColorToSal(color));
2739 aLightColor.DecreaseLuminance(64);
2740 aStyleSettings.SetLightColor(aLightColor);
2742 GetThemeColor(hTheme, 0, 0, TMT_TEXTCOLOR, &color);
2743 aStyleSettings.SetWindowTextColor( ImplWinColorToSal( color ) );
2744 aStyleSettings.SetToolTextColor( ImplWinColorToSal( color ) );
2745 GetThemeColor(hTheme, 0, 0, TMT_SHADOWCOLOR, &color);
2746 aStyleSettings.SetShadowColor( ImplWinColorToSal( color ) );
2747 GetThemeColor(hTheme, 0, 0, TMT_DKSHADOW3D, &color);
2748 aStyleSettings.SetDarkShadowColor( ImplWinColorToSal( color ) );
2749 CloseThemeData(hTheme);
2751 hTheme = OpenThemeData(mhWnd, L"Button");
2752 GetThemeColor(hTheme, BP_PUSHBUTTON, PBS_NORMAL, TMT_TEXTCOLOR, &color);
2753 aControlTextColor = ImplWinColorToSal(color);
2754 GetThemeColor(hTheme, BP_CHECKBOX, CBS_CHECKEDNORMAL, TMT_TEXTCOLOR, &color);
2755 aStyleSettings.SetRadioCheckTextColor( ImplWinColorToSal( color ) );
2756 CloseThemeData(hTheme);
2758 SetWindowTheme(mhWnd, nullptr, nullptr);
2760 hTheme = OpenThemeData(mhWnd, L"Menu");
2761 GetThemeColor(hTheme, MENU_POPUPITEM, MBI_NORMAL, TMT_TEXTCOLOR, &color);
2762 aStyleSettings.SetMenuTextColor( ImplWinColorToSal( color ) );
2763 aMenuBarTextColor = ImplWinColorToSal( color );
2764 aMenuBarRolloverTextColor = ImplWinColorToSal( color );
2765 CloseThemeData(hTheme);
2767 aStyleSettings.SetActiveTabColor( aStyleSettings.GetWindowColor() );
2768 hTheme = OpenThemeData(mhWnd, L"Toolbar");
2769 GetThemeColor(hTheme, 0, 0, TMT_FILLCOLOR, &color);
2770 aStyleSettings.SetInactiveTabColor( ImplWinColorToSal( color ) );
2771 // see ImplDrawNativeControl for dark mode
2772 aStyleSettings.SetMenuBarColor( aStyleSettings.GetWindowColor() );
2773 CloseThemeData(hTheme);
2775 hTheme = OpenThemeData(mhWnd, L"Textstyle");
2776 if (hTheme)
2778 GetThemeColor(hTheme, TEXT_HYPERLINKTEXT, TS_HYPERLINK_NORMAL, TMT_TEXTCOLOR, &color);
2779 aStyleSettings.SetLinkColor(ImplWinColorToSal(color));
2780 CloseThemeData(hTheme);
2783 // tdf#148448 pick a warning color more likely to be readable as a
2784 // background in a dark theme
2785 aStyleSettings.SetWarningColor(Color(0xf5, 0x79, 0x00));
2787 else
2789 aStyleSettings.SetFaceColor( ImplWinColorToSal( GetSysColor( COLOR_3DFACE ) ) );
2790 aStyleSettings.SetWindowColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOW ) ) );
2791 aStyleSettings.SetWindowTextColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOWTEXT ) ) );
2792 aStyleSettings.SetToolTextColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOWTEXT ) ) );
2793 aStyleSettings.SetLightColor( ImplWinColorToSal( GetSysColor( COLOR_3DHILIGHT ) ) );
2794 aStyleSettings.SetShadowColor( ImplWinColorToSal( GetSysColor( COLOR_3DSHADOW ) ) );
2795 aStyleSettings.SetDarkShadowColor( ImplWinColorToSal( GetSysColor( COLOR_3DDKSHADOW ) ) );
2796 aControlTextColor = ImplWinColorToSal(GetSysColor(COLOR_BTNTEXT));
2797 aStyleSettings.SetRadioCheckTextColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOWTEXT ) ) );
2798 aStyleSettings.SetMenuTextColor( ImplWinColorToSal( GetSysColor( COLOR_MENUTEXT ) ) );
2799 aMenuBarTextColor = ImplWinColorToSal( GetSysColor( COLOR_MENUTEXT ) );
2800 aMenuBarRolloverTextColor = aHighlightTextColor;
2801 if( bFlatMenus )
2802 aStyleSettings.SetMenuBarColor( ImplWinColorToSal( GetSysColor( COLOR_MENUBAR ) ) );
2803 else
2804 aStyleSettings.SetMenuBarColor( ImplWinColorToSal( GetSysColor( COLOR_MENU ) ) );
2805 aStyleSettings.SetActiveTabColor( aStyleSettings.GetWindowColor() );
2806 aStyleSettings.SetInactiveTabColor( aStyleSettings.GetFaceColor() );
2809 if ( std::optional<Color> aColor = aStyleSettings.GetPersonaMenuBarTextColor() )
2811 aMenuBarTextColor = *aColor;
2812 if (!aStyleSettings.GetHighContrastMode())
2813 aMenuBarRolloverTextColor = *aColor;
2816 aStyleSettings.SetMenuBarTextColor( aMenuBarTextColor );
2817 aStyleSettings.SetMenuBarRolloverTextColor( aMenuBarRolloverTextColor );
2819 aStyleSettings.SetLightBorderColor( ImplWinColorToSal( GetSysColor( COLOR_3DLIGHT ) ) );
2820 aStyleSettings.SetHelpColor( ImplWinColorToSal( GetSysColor( COLOR_INFOBK ) ) );
2821 aStyleSettings.SetHelpTextColor( ImplWinColorToSal( GetSysColor( COLOR_INFOTEXT ) ) );
2823 aStyleSettings.SetWorkspaceColor(aStyleSettings.GetFaceColor());
2824 aStyleSettings.SetDialogColor(aStyleSettings.GetFaceColor());
2825 aStyleSettings.SetDialogTextColor(aControlTextColor);
2827 Color aHighlightButtonTextColor = aStyleSettings.GetHighContrastMode() ?
2828 aHighlightTextColor : aControlTextColor;
2830 if (aStyleSettings.GetHighContrastMode())
2832 Color aLinkColor(ImplWinColorToSal(GetSysColor(COLOR_HOTLIGHT)));
2833 aStyleSettings.SetLinkColor(aLinkColor);
2834 aStyleSettings.SetVisitedLinkColor(aLinkColor);
2837 aStyleSettings.SetDefaultButtonTextColor(aHighlightButtonTextColor);
2838 aStyleSettings.SetButtonTextColor(aControlTextColor);
2839 aStyleSettings.SetDefaultActionButtonTextColor(aHighlightButtonTextColor);
2840 aStyleSettings.SetActionButtonTextColor(aControlTextColor);
2841 aStyleSettings.SetFlatButtonTextColor(aControlTextColor);
2842 aStyleSettings.SetDefaultButtonRolloverTextColor(aHighlightButtonTextColor);
2843 aStyleSettings.SetButtonRolloverTextColor(aHighlightButtonTextColor);
2844 aStyleSettings.SetDefaultActionButtonRolloverTextColor(aHighlightButtonTextColor);
2845 aStyleSettings.SetActionButtonRolloverTextColor(aHighlightButtonTextColor);
2846 aStyleSettings.SetFlatButtonRolloverTextColor(aHighlightButtonTextColor);
2847 aStyleSettings.SetDefaultButtonPressedRolloverTextColor(aControlTextColor);
2848 aStyleSettings.SetButtonPressedRolloverTextColor(aControlTextColor);
2849 aStyleSettings.SetDefaultActionButtonPressedRolloverTextColor(aControlTextColor);
2850 aStyleSettings.SetActionButtonPressedRolloverTextColor(aControlTextColor);
2851 aStyleSettings.SetFlatButtonPressedRolloverTextColor(aControlTextColor);
2853 aStyleSettings.SetTabTextColor(aControlTextColor);
2854 aStyleSettings.SetTabRolloverTextColor(aControlTextColor);
2855 aStyleSettings.SetTabHighlightTextColor(aControlTextColor);
2857 aStyleSettings.SetGroupTextColor( aStyleSettings.GetRadioCheckTextColor() );
2858 aStyleSettings.SetLabelTextColor( aStyleSettings.GetRadioCheckTextColor() );
2859 aStyleSettings.SetFieldColor( aStyleSettings.GetWindowColor() );
2860 aStyleSettings.SetListBoxWindowBackgroundColor( aStyleSettings.GetWindowColor() );
2861 aStyleSettings.SetFieldTextColor( aStyleSettings.GetWindowTextColor() );
2862 aStyleSettings.SetFieldRolloverTextColor( aStyleSettings.GetFieldTextColor() );
2863 aStyleSettings.SetListBoxWindowTextColor( aStyleSettings.GetFieldTextColor() );
2865 aStyleSettings.SetAccentColor( ImplWinColorToSal( GetSysColor( COLOR_HIGHLIGHT ) ) );
2866 // https://devblogs.microsoft.com/oldnewthing/20170405-00/?p=95905
2868 aStyleSettings.SetHighlightColor( ImplWinColorToSal( GetSysColor( COLOR_HIGHLIGHT ) ) );
2869 aStyleSettings.SetHighlightTextColor(aHighlightTextColor);
2870 aStyleSettings.SetListBoxWindowHighlightColor( aStyleSettings.GetHighlightColor() );
2871 aStyleSettings.SetListBoxWindowHighlightTextColor( aStyleSettings.GetHighlightTextColor() );
2872 aStyleSettings.SetMenuHighlightTextColor( aStyleSettings.GetHighlightTextColor() );
2874 ImplSVData* pSVData = ImplGetSVData();
2875 pSVData->maNWFData.mnMenuFormatBorderX = 0;
2876 pSVData->maNWFData.mnMenuFormatBorderY = 0;
2877 pSVData->maNWFData.maMenuBarHighlightTextColor = COL_TRANSPARENT;
2878 GetSalData()->mbThemeMenuSupport = false;
2879 aStyleSettings.SetMenuColor( ImplWinColorToSal( GetSysColor( COLOR_MENU ) ) );
2880 aStyleSettings.SetMenuBarHighlightTextColor(aStyleSettings.GetMenuHighlightTextColor());
2881 aStyleSettings.SetActiveColor( ImplWinColorToSal( GetSysColor( COLOR_ACTIVECAPTION ) ) );
2882 aStyleSettings.SetActiveTextColor( ImplWinColorToSal( GetSysColor( COLOR_CAPTIONTEXT ) ) );
2883 aStyleSettings.SetDeactiveColor( ImplWinColorToSal( GetSysColor( COLOR_INACTIVECAPTION ) ) );
2884 aStyleSettings.SetDeactiveTextColor( ImplWinColorToSal( GetSysColor( COLOR_INACTIVECAPTIONTEXT ) ) );
2886 aStyleSettings.SetCheckedColorSpecialCase( );
2888 // caret width
2889 DWORD nCaretWidth = 2;
2890 if( SystemParametersInfoW( SPI_GETCARETWIDTH, 0, &nCaretWidth, 0 ) )
2891 aStyleSettings.SetCursorSize( nCaretWidth );
2893 // Query Fonts
2894 vcl::Font aMenuFont = aStyleSettings.GetMenuFont();
2895 vcl::Font aTitleFont = aStyleSettings.GetTitleFont();
2896 vcl::Font aFloatTitleFont = aStyleSettings.GetFloatTitleFont();
2897 vcl::Font aHelpFont = aStyleSettings.GetHelpFont();
2898 vcl::Font aAppFont = aStyleSettings.GetAppFont();
2899 vcl::Font aIconFont = aStyleSettings.GetIconFont();
2900 HDC hDC = GetDC( nullptr );
2901 NONCLIENTMETRICSW aNonClientMetrics;
2902 aNonClientMetrics.cbSize = sizeof( aNonClientMetrics );
2903 if ( SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, sizeof( aNonClientMetrics ), &aNonClientMetrics, 0 ) )
2905 ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfMenuFont, aMenuFont );
2906 ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfCaptionFont, aTitleFont );
2907 ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfSmCaptionFont, aFloatTitleFont );
2908 ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfStatusFont, aHelpFont );
2909 ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfMessageFont, aAppFont );
2911 LOGFONTW aLogFont;
2912 if ( SystemParametersInfoW( SPI_GETICONTITLELOGFONT, 0, &aLogFont, 0 ) )
2913 ImplSalUpdateStyleFontW( hDC, aLogFont, aIconFont );
2916 ReleaseDC( nullptr, hDC );
2918 aStyleSettings.SetToolbarIconSize(ToolbarIconSize::Large);
2920 aStyleSettings.BatchSetFonts( aAppFont, aAppFont );
2922 aStyleSettings.SetMenuFont( aMenuFont );
2923 aStyleSettings.SetTitleFont( aTitleFont );
2924 aStyleSettings.SetFloatTitleFont( aFloatTitleFont );
2925 aStyleSettings.SetHelpFont( aHelpFont );
2926 aStyleSettings.SetIconFont( aIconFont );
2928 if ( aAppFont.GetWeight() > WEIGHT_NORMAL )
2929 aAppFont.SetWeight( WEIGHT_NORMAL );
2930 aStyleSettings.SetToolFont( aAppFont );
2931 aStyleSettings.SetTabFont( aAppFont );
2933 BOOL bDragFull;
2934 if ( SystemParametersInfoW( SPI_GETDRAGFULLWINDOWS, 0, &bDragFull, 0 ) )
2936 DragFullOptions nDragFullOptions = aStyleSettings.GetDragFullOptions();
2937 if ( bDragFull )
2938 nDragFullOptions |= DragFullOptions::WindowMove | DragFullOptions::WindowSize | DragFullOptions::Docking | DragFullOptions::Split;
2939 else
2940 nDragFullOptions &= ~DragFullOptions(DragFullOptions::WindowMove | DragFullOptions::WindowSize | DragFullOptions::Docking | DragFullOptions::Split);
2941 aStyleSettings.SetDragFullOptions( nDragFullOptions );
2944 if ( RegOpenKeyW( HKEY_CURRENT_USER,
2945 L"Control Panel\\International\\Calendars\\TwoDigitYearMax",
2946 &hRegKey ) == ERROR_SUCCESS )
2948 wchar_t aValueBuf[10];
2949 DWORD nValue;
2950 DWORD nValueSize = sizeof( aValueBuf );
2951 DWORD nType;
2952 if ( RegQueryValueExW( hRegKey, L"1", nullptr,
2953 &nType, reinterpret_cast<LPBYTE>(aValueBuf), &nValueSize ) == ERROR_SUCCESS )
2955 if ( nType == REG_SZ )
2957 nValue = static_cast<sal_uLong>(ImplW2I( aValueBuf ));
2958 if ( (nValue > 1000) && (nValue < 10000) )
2960 std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
2961 officecfg::Office::Common::DateFormat::TwoDigitYear::set(static_cast<sal_Int32>(nValue-99), batch);
2962 batch->commit();
2967 RegCloseKey( hRegKey );
2970 rSettings.SetMouseSettings( aMouseSettings );
2971 rSettings.SetStyleSettings( aStyleSettings );
2973 // now apply the values from theming, if available
2974 WinSalGraphics::updateSettingsNative( rSettings );
2977 const SystemEnvData* WinSalFrame::GetSystemData() const
2979 return &maSysData;
2982 void WinSalFrame::Beep()
2984 // a simple beep
2985 MessageBeep( 0 );
2988 SalFrame::SalPointerState WinSalFrame::GetPointerState()
2990 SalPointerState aState;
2991 aState.mnState = 0;
2993 if ( GetKeyState( VK_LBUTTON ) & 0x8000 )
2994 aState.mnState |= MOUSE_LEFT;
2995 if ( GetKeyState( VK_MBUTTON ) & 0x8000 )
2996 aState.mnState |= MOUSE_MIDDLE;
2997 if ( GetKeyState( VK_RBUTTON ) & 0x8000 )
2998 aState.mnState |= MOUSE_RIGHT;
2999 if ( GetKeyState( VK_SHIFT ) & 0x8000 )
3000 aState.mnState |= KEY_SHIFT;
3001 if ( GetKeyState( VK_CONTROL ) & 0x8000 )
3002 aState.mnState |= KEY_MOD1;
3003 if ( GetKeyState( VK_MENU ) & 0x8000 )
3004 aState.mnState |= KEY_MOD2;
3006 POINT pt;
3007 GetCursorPos( &pt );
3009 aState.maPos = Point(pt.x - maGeometry.x(), pt.y - maGeometry.y());
3010 return aState;
3013 KeyIndicatorState WinSalFrame::GetIndicatorState()
3015 KeyIndicatorState aState = KeyIndicatorState::NONE;
3016 if (::GetKeyState(VK_CAPITAL))
3017 aState |= KeyIndicatorState::CAPSLOCK;
3019 if (::GetKeyState(VK_NUMLOCK))
3020 aState |= KeyIndicatorState::NUMLOCK;
3022 if (::GetKeyState(VK_SCROLL))
3023 aState |= KeyIndicatorState::SCROLLLOCK;
3025 return aState;
3028 void WinSalFrame::SimulateKeyPress( sal_uInt16 nKeyCode )
3030 BYTE nVKey = 0;
3031 switch (nKeyCode)
3033 case KEY_CAPSLOCK:
3034 nVKey = VK_CAPITAL;
3035 break;
3038 if (nVKey > 0 && nVKey < 255)
3040 ::keybd_event(nVKey, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
3041 ::keybd_event(nVKey, 0x45, KEYEVENTF_EXTENDEDKEY|KEYEVENTF_KEYUP, 0);
3045 void WinSalFrame::ResetClipRegion()
3047 SetWindowRgn( mhWnd, nullptr, TRUE );
3050 void WinSalFrame::BeginSetClipRegion( sal_uInt32 nRects )
3052 if( mpClipRgnData )
3053 delete [] reinterpret_cast<BYTE*>(mpClipRgnData);
3054 sal_uLong nRectBufSize = sizeof(RECT)*nRects;
3055 mpClipRgnData = reinterpret_cast<RGNDATA*>(new BYTE[sizeof(RGNDATA)-1+nRectBufSize]);
3056 mpClipRgnData->rdh.dwSize = sizeof( RGNDATAHEADER );
3057 mpClipRgnData->rdh.iType = RDH_RECTANGLES;
3058 mpClipRgnData->rdh.nCount = nRects;
3059 mpClipRgnData->rdh.nRgnSize = nRectBufSize;
3060 SetRectEmpty( &(mpClipRgnData->rdh.rcBound) );
3061 mpNextClipRect = reinterpret_cast<RECT*>(&(mpClipRgnData->Buffer));
3062 mbFirstClipRect = true;
3065 void WinSalFrame::UnionClipRegion( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight )
3067 if( ! mpClipRgnData )
3068 return;
3070 RECT* pRect = mpNextClipRect;
3071 RECT* pBoundRect = &(mpClipRgnData->rdh.rcBound);
3072 tools::Long nRight = nX + nWidth;
3073 tools::Long nBottom = nY + nHeight;
3075 if ( mbFirstClipRect )
3077 pBoundRect->left = nX;
3078 pBoundRect->top = nY;
3079 pBoundRect->right = nRight;
3080 pBoundRect->bottom = nBottom;
3081 mbFirstClipRect = false;
3083 else
3085 if ( nX < pBoundRect->left )
3086 pBoundRect->left = static_cast<int>(nX);
3088 if ( nY < pBoundRect->top )
3089 pBoundRect->top = static_cast<int>(nY);
3091 if ( nRight > pBoundRect->right )
3092 pBoundRect->right = static_cast<int>(nRight);
3094 if ( nBottom > pBoundRect->bottom )
3095 pBoundRect->bottom = static_cast<int>(nBottom);
3098 pRect->left = static_cast<int>(nX);
3099 pRect->top = static_cast<int>(nY);
3100 pRect->right = static_cast<int>(nRight);
3101 pRect->bottom = static_cast<int>(nBottom);
3102 if( (mpNextClipRect - reinterpret_cast<RECT*>(&mpClipRgnData->Buffer)) < static_cast<int>(mpClipRgnData->rdh.nCount) )
3103 mpNextClipRect++;
3106 void WinSalFrame::EndSetClipRegion()
3108 if( ! mpClipRgnData )
3109 return;
3111 HRGN hRegion;
3113 // create region from accumulated rectangles
3114 if ( mpClipRgnData->rdh.nCount == 1 )
3116 RECT* pRect = &(mpClipRgnData->rdh.rcBound);
3117 hRegion = CreateRectRgn( pRect->left, pRect->top,
3118 pRect->right, pRect->bottom );
3120 else
3122 sal_uLong nSize = mpClipRgnData->rdh.nRgnSize+sizeof(RGNDATAHEADER);
3123 hRegion = ExtCreateRegion( nullptr, nSize, mpClipRgnData );
3125 delete [] reinterpret_cast<BYTE*>(mpClipRgnData);
3126 mpClipRgnData = nullptr;
3128 SAL_WARN_IF( !hRegion, "vcl", "WinSalFrame::EndSetClipRegion() - Can't create ClipRegion" );
3129 if( hRegion )
3131 RECT aWindowRect;
3132 GetWindowRect( mhWnd, &aWindowRect );
3133 POINT aPt;
3134 aPt.x=0;
3135 aPt.y=0;
3136 ClientToScreen( mhWnd, &aPt );
3137 OffsetRgn( hRegion, aPt.x - aWindowRect.left, aPt.y - aWindowRect.top );
3139 if( SetWindowRgn( mhWnd, hRegion, TRUE ) == 0 )
3140 DeleteObject( hRegion );
3144 void WinSalFrame::UpdateDarkMode()
3146 ::UpdateDarkMode(mhWnd);
3149 bool WinSalFrame::GetUseDarkMode() const
3151 return UseDarkMode();
3154 bool WinSalFrame::GetUseReducedAnimation() const
3156 BOOL bEnableAnimation = FALSE;
3157 SystemParametersInfoW(SPI_GETCLIENTAREAANIMATION, 0, &bEnableAnimation, 0);
3158 return !bEnableAnimation;
3161 static bool ImplHandleMouseMsg( HWND hWnd, UINT nMsg,
3162 WPARAM wParam, LPARAM lParam )
3164 WinSalFrame* pFrame = GetWindowPtr( hWnd );
3165 if ( !pFrame )
3166 return false;
3168 if( nMsg == WM_LBUTTONDOWN || nMsg == WM_MBUTTONDOWN || nMsg == WM_RBUTTONDOWN )
3170 // #103168# post again if async focus has not arrived yet
3171 // hopefully we will not receive the corresponding button up before this
3172 // button down arrives again
3173 vcl::Window *pWin = pFrame->GetWindow();
3174 if( pWin && pWin->ImplGetWindowImpl()->mpFrameData->mnFocusId )
3176 bool const ret = PostMessageW( hWnd, nMsg, wParam, lParam );
3177 SAL_WARN_IF(!ret, "vcl", "ERROR: PostMessage() failed!");
3178 return true;
3181 SalMouseEvent aMouseEvt;
3182 bool nRet;
3183 SalEvent nEvent = SalEvent::NONE;
3184 bool bCall = true;
3186 aMouseEvt.mnX = static_cast<short>(LOWORD( lParam ));
3187 aMouseEvt.mnY = static_cast<short>(HIWORD( lParam ));
3188 aMouseEvt.mnCode = 0;
3189 aMouseEvt.mnTime = GetMessageTime();
3191 // Use GetKeyState(), as some Logitech mouse drivers do not check
3192 // KeyState when simulating double-click with center mouse button
3194 if ( GetKeyState( VK_LBUTTON ) & 0x8000 )
3195 aMouseEvt.mnCode |= MOUSE_LEFT;
3196 if ( GetKeyState( VK_MBUTTON ) & 0x8000 )
3197 aMouseEvt.mnCode |= MOUSE_MIDDLE;
3198 if ( GetKeyState( VK_RBUTTON ) & 0x8000 )
3199 aMouseEvt.mnCode |= MOUSE_RIGHT;
3200 if ( GetKeyState( VK_SHIFT ) & 0x8000 )
3201 aMouseEvt.mnCode |= KEY_SHIFT;
3202 if ( GetKeyState( VK_CONTROL ) & 0x8000 )
3203 aMouseEvt.mnCode |= KEY_MOD1;
3204 if ( GetKeyState( VK_MENU ) & 0x8000 )
3205 aMouseEvt.mnCode |= KEY_MOD2;
3207 switch ( nMsg )
3209 case WM_MOUSEMOVE:
3211 // As the mouse events are not collected correctly when
3212 // pressing modifier keys (as interrupted by KeyEvents)
3213 // we do this here ourselves
3214 if ( aMouseEvt.mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2) )
3216 MSG aTempMsg;
3217 if ( PeekMessageW( &aTempMsg, hWnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE | PM_NOYIELD ) )
3219 if ( (aTempMsg.message == WM_MOUSEMOVE) &&
3220 (aTempMsg.wParam == wParam) )
3221 return true;
3225 SalData* pSalData = GetSalData();
3226 // Test for MouseLeave
3227 if ( pSalData->mhWantLeaveMsg && (pSalData->mhWantLeaveMsg != hWnd) )
3228 SendMessageW( pSalData->mhWantLeaveMsg, SAL_MSG_MOUSELEAVE, 0, GetMessagePos() );
3230 pSalData->mhWantLeaveMsg = hWnd;
3231 aMouseEvt.mnButton = 0;
3232 nEvent = SalEvent::MouseMove;
3234 break;
3236 case WM_NCMOUSEMOVE:
3237 case SAL_MSG_MOUSELEAVE:
3239 SalData* pSalData = GetSalData();
3240 if ( pSalData->mhWantLeaveMsg == hWnd )
3242 // Mouse-Coordinates are relative to the screen
3243 POINT aPt;
3244 aPt.x = static_cast<short>(LOWORD(lParam));
3245 aPt.y = static_cast<short>(HIWORD(lParam));
3246 ScreenToClient(hWnd, &aPt);
3247 if (const auto& pHelpWin = ImplGetSVHelpData().mpHelpWin)
3249 const tools::Rectangle& rHelpRect = pHelpWin->GetHelpArea();
3250 if (rHelpRect.Contains(Point(aPt.x, aPt.y)))
3252 // We have entered a tooltip (help window). Don't call the handler here; it
3253 // would launch the sequence "Mouse leaves the Control->Control redraws->
3254 // Help window gets destroyed->Mouse enters the Control->Control redraws",
3255 // which takes CPU and may flicker. Just destroy the help window and pretend
3256 // we are still over the original window.
3257 ImplDestroyHelpWindow(true);
3258 bCall = false;
3259 break;
3262 pSalData->mhWantLeaveMsg = nullptr;
3263 aMouseEvt.mnX = aPt.x;
3264 aMouseEvt.mnY = aPt.y;
3265 aMouseEvt.mnButton = 0;
3266 nEvent = SalEvent::MouseLeave;
3268 else
3269 bCall = false;
3271 break;
3273 case WM_LBUTTONDOWN:
3274 aMouseEvt.mnButton = MOUSE_LEFT;
3275 nEvent = SalEvent::MouseButtonDown;
3276 break;
3278 case WM_MBUTTONDOWN:
3279 aMouseEvt.mnButton = MOUSE_MIDDLE;
3280 nEvent = SalEvent::MouseButtonDown;
3281 break;
3283 case WM_RBUTTONDOWN:
3284 aMouseEvt.mnButton = MOUSE_RIGHT;
3285 nEvent = SalEvent::MouseButtonDown;
3286 break;
3288 case WM_LBUTTONUP:
3289 aMouseEvt.mnButton = MOUSE_LEFT;
3290 nEvent = SalEvent::MouseButtonUp;
3291 break;
3293 case WM_MBUTTONUP:
3294 aMouseEvt.mnButton = MOUSE_MIDDLE;
3295 nEvent = SalEvent::MouseButtonUp;
3296 break;
3298 case WM_RBUTTONUP:
3299 aMouseEvt.mnButton = MOUSE_RIGHT;
3300 nEvent = SalEvent::MouseButtonUp;
3301 break;
3304 // check if this window was destroyed - this might happen if we are the help window
3305 // and sent a mouse leave message to the application which killed the help window, ie ourselves
3306 if( !IsWindow( hWnd ) )
3307 return false;
3309 if ( bCall )
3311 if ( nEvent == SalEvent::MouseButtonDown )
3312 UpdateWindow( hWnd );
3314 if( AllSettings::GetLayoutRTL() )
3315 aMouseEvt.mnX = pFrame->maGeometry.width() - 1 - aMouseEvt.mnX;
3317 nRet = pFrame->CallCallback( nEvent, &aMouseEvt );
3318 if ( nMsg == WM_MOUSEMOVE )
3319 SetCursor( pFrame->mhCursor );
3321 else
3322 nRet = false;
3324 return nRet;
3327 static bool ImplHandleMouseActivateMsg( HWND hWnd )
3329 WinSalFrame* pFrame = GetWindowPtr( hWnd );
3330 if ( !pFrame )
3331 return false;
3333 if ( pFrame->mbFloatWin )
3334 return true;
3336 return pFrame->CallCallback( SalEvent::MouseActivate, nullptr );
3339 static bool ImplHandleWheelMsg( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
3341 DBG_ASSERT( nMsg == WM_MOUSEWHEEL ||
3342 nMsg == WM_MOUSEHWHEEL,
3343 "ImplHandleWheelMsg() called with no wheel mouse event" );
3345 ImplSalYieldMutexAcquireWithWait();
3347 bool nRet = false;
3348 WinSalFrame* pFrame = GetWindowPtr( hWnd );
3349 if ( pFrame )
3351 WORD nWinModCode = LOWORD( wParam );
3352 POINT aWinPt;
3353 aWinPt.x = static_cast<short>(LOWORD( lParam ));
3354 aWinPt.y = static_cast<short>(HIWORD( lParam ));
3355 ScreenToClient( hWnd, &aWinPt );
3357 SalWheelMouseEvent aWheelEvt;
3358 aWheelEvt.mnTime = GetMessageTime();
3359 aWheelEvt.mnX = aWinPt.x;
3360 aWheelEvt.mnY = aWinPt.y;
3361 aWheelEvt.mnCode = 0;
3362 aWheelEvt.mnDelta = static_cast<short>(HIWORD( wParam ));
3363 aWheelEvt.mnNotchDelta = aWheelEvt.mnDelta/WHEEL_DELTA;
3364 if( aWheelEvt.mnNotchDelta == 0 )
3366 if( aWheelEvt.mnDelta > 0 )
3367 aWheelEvt.mnNotchDelta = 1;
3368 else if( aWheelEvt.mnDelta < 0 )
3369 aWheelEvt.mnNotchDelta = -1;
3372 if( nMsg == WM_MOUSEWHEEL )
3374 if ( aSalShlData.mnWheelScrollLines == WHEEL_PAGESCROLL )
3375 aWheelEvt.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
3376 else
3377 aWheelEvt.mnScrollLines = aSalShlData.mnWheelScrollLines;
3378 aWheelEvt.mbHorz = false;
3380 else
3382 aWheelEvt.mnScrollLines = aSalShlData.mnWheelScrollChars;
3383 aWheelEvt.mbHorz = true;
3385 // fdo#36380 - seems horiz scrolling has swapped direction
3386 aWheelEvt.mnDelta *= -1;
3387 aWheelEvt.mnNotchDelta *= -1;
3390 if ( nWinModCode & MK_SHIFT )
3391 aWheelEvt.mnCode |= KEY_SHIFT;
3392 if ( nWinModCode & MK_CONTROL )
3393 aWheelEvt.mnCode |= KEY_MOD1;
3394 if ( GetKeyState( VK_MENU ) & 0x8000 )
3395 aWheelEvt.mnCode |= KEY_MOD2;
3397 if( AllSettings::GetLayoutRTL() )
3398 aWheelEvt.mnX = pFrame->maGeometry.width() - 1 - aWheelEvt.mnX;
3400 nRet = pFrame->CallCallback( SalEvent::WheelMouse, &aWheelEvt );
3403 ImplSalYieldMutexRelease();
3405 return nRet;
3408 static sal_uInt16 ImplSalGetKeyCode( WPARAM wParam )
3410 sal_uInt16 nKeyCode;
3412 // convert KeyCode
3413 if ( wParam < KEY_TAB_SIZE )
3414 nKeyCode = aImplTranslateKeyTab[wParam];
3415 else
3417 SalData* pSalData = GetSalData();
3418 std::map< UINT, sal_uInt16 >::const_iterator it = pSalData->maVKMap.find( static_cast<UINT>(wParam) );
3419 if( it != pSalData->maVKMap.end() )
3420 nKeyCode = it->second;
3421 else
3422 nKeyCode = 0;
3425 return nKeyCode;
3428 static void ImplUpdateInputLang( WinSalFrame* pFrame )
3430 UINT nLang = LOWORD( GetKeyboardLayout( 0 ) );
3431 if ( nLang && nLang != pFrame->mnInputLang )
3433 // keep input lang up-to-date
3434 pFrame->mnInputLang = nLang;
3437 // We are on Windows NT so we use Unicode FrameProcs and get
3438 // Unicode charcodes directly from Windows no need to set up a
3439 // code page
3440 return;
3443 static sal_Unicode ImplGetCharCode( WinSalFrame* pFrame, WPARAM nCharCode )
3445 ImplUpdateInputLang( pFrame );
3447 // We are on Windows NT so we use Unicode FrameProcs and we
3448 // get Unicode charcodes directly from Windows
3449 return static_cast<sal_Unicode>(nCharCode);
3452 LanguageType WinSalFrame::GetInputLanguage()
3454 if( !mnInputLang )
3455 ImplUpdateInputLang( this );
3457 if( !mnInputLang )
3458 return LANGUAGE_DONTKNOW;
3459 else
3460 return LanguageType(mnInputLang);
3463 bool WinSalFrame::MapUnicodeToKeyCode( sal_Unicode aUnicode, LanguageType aLangType, vcl::KeyCode& rKeyCode )
3465 bool bRet = false;
3466 sal_IntPtr nLangType = static_cast<sal_uInt16>(aLangType);
3467 // just use the passed language identifier, do not try to load additional keyboard support
3468 HKL hkl = reinterpret_cast<HKL>(nLangType);
3470 if( hkl )
3472 SHORT scan = VkKeyScanExW( aUnicode, hkl );
3473 if( LOWORD(scan) == 0xFFFF )
3474 // keyboard not loaded or key cannot be mapped
3475 bRet = false;
3476 else
3478 BYTE vkeycode = LOBYTE(scan);
3479 BYTE shiftstate = HIBYTE(scan);
3481 // Last argument is set to false, because there's no decision made
3482 // yet which key should be assigned to MOD3 modifier on Windows.
3483 // Windows key - user's can be confused, because it should display
3484 // Windows menu (applies to both left/right key)
3485 // Menu key - this key is used to display context menu
3486 // AltGr key - probably it has no sense
3487 rKeyCode = vcl::KeyCode( ImplSalGetKeyCode( vkeycode ),
3488 (shiftstate & 0x01) != 0, // shift
3489 (shiftstate & 0x02) != 0, // ctrl
3490 (shiftstate & 0x04) != 0, // alt
3491 false );
3492 bRet = true;
3496 return bRet;
3499 static void UnsetAltIfAltGr(SalKeyEvent& rKeyEvt, sal_uInt16 nModCode)
3501 if ((nModCode & (KEY_MOD1 | KEY_MOD2)) == (KEY_MOD1 | KEY_MOD2) &&
3502 rKeyEvt.mnCharCode)
3504 // this is actually AltGr and should not be handled as Alt
3505 rKeyEvt.mnCode &= ~(KEY_MOD1 | KEY_MOD2);
3509 // tdf#152404 Commit uncommitted text before dispatching key shortcuts. In
3510 // certain cases such as pressing Control-Alt-C in a Writer document while
3511 // there is uncommitted text will call WinSalFrame::EndExtTextInput() which
3512 // will dispatch a SalEvent::EndExtTextInput event. Writer's handler for that
3513 // event will delete the uncommitted text and then insert the committed text
3514 // but LibreOffice will crash when deleting the uncommitted text because
3515 // deletion of the text also removes and deletes the newly inserted comment.
3516 static void FlushIMBeforeShortCut(WinSalFrame* pFrame, SalEvent nEvent, sal_uInt16 nModCode)
3518 if (pFrame->mbCandidateMode && nEvent == SalEvent::KeyInput
3519 && (nModCode & (KEY_MOD1 | KEY_MOD2)))
3521 pFrame->EndExtTextInput(EndExtTextInputFlags::Complete);
3525 // When Num Lock is off, the key codes from NumPag come as arrows, PgUp/PgDn, etc.
3526 static WORD NumPadFromArrows(WORD vk)
3528 switch (vk)
3530 case VK_CLEAR:
3531 return VK_NUMPAD5;
3532 case VK_PRIOR:
3533 return VK_NUMPAD9;
3534 case VK_NEXT:
3535 return VK_NUMPAD3;
3536 case VK_END:
3537 return VK_NUMPAD1;
3538 case VK_HOME:
3539 return VK_NUMPAD7;
3540 case VK_LEFT:
3541 return VK_NUMPAD4;
3542 case VK_UP:
3543 return VK_NUMPAD8;
3544 case VK_RIGHT:
3545 return VK_NUMPAD6;
3546 case VK_DOWN:
3547 return VK_NUMPAD2;
3548 case VK_INSERT:
3549 return VK_NUMPAD0;
3550 default:
3551 return vk;
3555 static bool HandleAltNumPadCode(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
3557 struct
3559 bool started = false;
3560 //static bool hex = false; // TODO: support HKEY_CURRENT_USER\Control Panel\Input Method\EnableHexNumpad
3561 sal_UCS4 ch = 0;
3562 bool wait_WM_CHAR = false;
3563 void clear()
3565 started = false;
3566 ch = 0;
3567 wait_WM_CHAR = false;
3569 } static state;
3571 WORD vk = LOWORD(wParam);
3572 WORD keyFlags = HIWORD(lParam);
3574 switch (nMsg)
3576 case WM_CHAR:
3577 if (state.wait_WM_CHAR && MapVirtualKeyW(LOBYTE(keyFlags), MAPVK_VSC_TO_VK) == VK_MENU)
3579 state.clear();
3580 // Ignore it - it is synthetized (incorrect, truncated) character from system
3581 return true;
3584 break;
3586 case WM_SYSKEYDOWN:
3587 if (vk == VK_MENU)
3589 if (!(keyFlags & KF_REPEAT))
3590 state.clear();
3591 state.started = true;
3592 return false; // This must be processed further - e.g., to show accelerators
3595 if (!state.started)
3596 break;
3598 if (keyFlags & KF_EXTENDED)
3599 break; // NUMPAD numeric keys are *not* considered extended
3601 vk = NumPadFromArrows(vk);
3602 if (vk >= VK_NUMPAD0 && vk <= VK_NUMPAD9)
3603 return true;
3605 break;
3607 case WM_SYSKEYUP:
3608 if (!state.started)
3609 break;
3611 if (keyFlags & KF_EXTENDED)
3612 break; // NUMPAD numeric keys are *not* considered extended
3614 vk = NumPadFromArrows(vk);
3615 if (vk >= VK_NUMPAD0 && vk <= VK_NUMPAD9)
3617 state.ch *= 10;
3618 state.ch += vk - VK_NUMPAD0;
3619 return true;
3622 break;
3624 case WM_KEYUP:
3625 if (vk == VK_MENU && state.started && state.ch)
3627 sal_UCS4 ch = state.ch;
3628 state.clear();
3629 // Let system provide codes for values below 256
3630 if (ch >= 256 && rtl::isUnicodeCodePoint(ch))
3632 PostMessageW(hWnd, WM_UNICHAR, ch, 0);
3633 state.wait_WM_CHAR = true;
3635 return true;
3637 break;
3640 state.clear();
3641 return false;
3644 static bool ImplHandleKeyMsg( HWND hWnd, UINT nMsg,
3645 WPARAM wParam, LPARAM lParam, LRESULT& rResult )
3647 static bool bIgnoreCharMsg = false;
3648 static WPARAM nDeadChar = 0;
3649 static WPARAM nLastVKChar = 0;
3650 static sal_uInt16 nLastChar = 0;
3651 static ModKeyFlags nLastModKeyCode = ModKeyFlags::NONE;
3652 static bool bWaitForModKeyRelease = false;
3653 sal_uInt16 nRepeat = LOWORD( lParam );
3654 if (nRepeat)
3655 --nRepeat;
3656 sal_uInt16 nModCode = 0;
3658 // this key might have been relayed by SysChild and thus
3659 // may not be processed twice
3660 GetSalData()->mnSalObjWantKeyEvt = 0;
3662 if ( nMsg == WM_DEADCHAR )
3664 nDeadChar = wParam;
3665 return false;
3668 if (HandleAltNumPadCode(hWnd, nMsg, wParam, lParam))
3669 return true; // no default processing
3671 WinSalFrame* pFrame = GetWindowPtr( hWnd );
3672 if ( !pFrame )
3673 return false;
3675 // reset the background mode for each text input,
3676 // as some tools such as RichWin may have changed it
3677 if ( pFrame->mpLocalGraphics &&
3678 pFrame->mpLocalGraphics->getHDC() )
3679 SetBkMode( pFrame->mpLocalGraphics->getHDC(), TRANSPARENT );
3681 // determine modifiers
3682 if ( GetKeyState( VK_SHIFT ) & 0x8000 )
3683 nModCode |= KEY_SHIFT;
3684 if ( GetKeyState( VK_CONTROL ) & 0x8000 )
3685 nModCode |= KEY_MOD1;
3686 if (GetKeyState(VK_MENU) & 0x8000)
3687 nModCode |= KEY_MOD2;
3689 if ( (nMsg == WM_CHAR) || (nMsg == WM_SYSCHAR) )
3691 nDeadChar = 0;
3693 if ( bIgnoreCharMsg )
3695 bIgnoreCharMsg = false;
3696 // #101635# if zero is returned here for WM_SYSCHAR (ALT+<key>) Windows will beep
3697 // because this 'hotkey' was not processed -> better return 1
3698 // except for Alt-SPACE which should always open the sysmenu (#104616#)
3700 // also return zero if a system menubar is available that might process this hotkey
3701 // this also applies to the OLE inplace embedding where we are a child window
3702 if( (GetWindowStyle( hWnd ) & WS_CHILD) || GetMenu( hWnd ) || (wParam == 0x20) )
3703 return false;
3704 else
3705 return true;
3708 // ignore backspace as a single key, so that
3709 // we do not get problems for combinations w/ a DeadKey
3710 if ( wParam == 0x08 ) // BACKSPACE
3711 return false;
3713 // only "free flying" WM_CHAR messages arrive here, that are
3714 // created by typing an ALT-NUMPAD combination
3715 SalKeyEvent aKeyEvt;
3717 if ( (wParam >= '0') && (wParam <= '9') )
3718 aKeyEvt.mnCode = sal::static_int_cast<sal_uInt16>(KEYGROUP_NUM + wParam - '0');
3719 else if ( (wParam >= 'A') && (wParam <= 'Z') )
3720 aKeyEvt.mnCode = sal::static_int_cast<sal_uInt16>(KEYGROUP_ALPHA + wParam - 'A');
3721 else if ( (wParam >= 'a') && (wParam <= 'z') )
3722 aKeyEvt.mnCode = sal::static_int_cast<sal_uInt16>(KEYGROUP_ALPHA + wParam - 'a');
3723 else if ( wParam == 0x0D ) // RETURN
3724 aKeyEvt.mnCode = KEY_RETURN;
3725 else if ( wParam == 0x1B ) // ESCAPE
3726 aKeyEvt.mnCode = KEY_ESCAPE;
3727 else if ( wParam == 0x09 ) // TAB
3728 aKeyEvt.mnCode = KEY_TAB;
3729 else if ( wParam == 0x20 ) // SPACE
3730 aKeyEvt.mnCode = KEY_SPACE;
3731 else
3732 aKeyEvt.mnCode = 0;
3734 aKeyEvt.mnCode |= nModCode;
3735 aKeyEvt.mnCharCode = ImplGetCharCode( pFrame, wParam );
3736 aKeyEvt.mnRepeat = nRepeat;
3738 UnsetAltIfAltGr(aKeyEvt, nModCode);
3739 FlushIMBeforeShortCut(pFrame, SalEvent::KeyInput, nModCode);
3741 nLastChar = 0;
3742 nLastVKChar = 0;
3744 bool nRet = pFrame->CallCallback( SalEvent::KeyInput, &aKeyEvt );
3745 pFrame->CallCallback( SalEvent::KeyUp, &aKeyEvt );
3746 return nRet;
3748 // #i11583#, MCD, 2003-01-13, Support for WM_UNICHAR & Keyman 6.0; addition begins
3749 else if( nMsg == WM_UNICHAR )
3751 // If Windows is asking if we accept WM_UNICHAR, return TRUE
3752 if(wParam == UNICODE_NOCHAR)
3754 rResult = TRUE; // ssa: this will actually return TRUE to windows
3755 return true; // ...but this will only avoid calling the defwindowproc
3758 if (!rtl::isUnicodeCodePoint(wParam))
3759 return false;
3761 SalKeyEvent aKeyEvt;
3762 aKeyEvt.mnCode = nModCode; // Or should it be 0? - as this is always a character returned
3763 aKeyEvt.mnRepeat = 0;
3765 if( wParam >= Uni_SupplementaryPlanesStart )
3767 // character is supplementary char in UTF-32 format - must be converted to UTF-16 supplementary pair
3768 aKeyEvt.mnCharCode = rtl::getHighSurrogate(wParam);
3769 nLastChar = 0;
3770 nLastVKChar = 0;
3771 pFrame->CallCallback(SalEvent::KeyInput, &aKeyEvt);
3772 pFrame->CallCallback(SalEvent::KeyUp, &aKeyEvt);
3773 wParam = rtl::getLowSurrogate(wParam);
3776 aKeyEvt.mnCharCode = static_cast<sal_Unicode>(wParam);
3778 nLastChar = 0;
3779 nLastVKChar = 0;
3780 bool nRet = pFrame->CallCallback( SalEvent::KeyInput, &aKeyEvt );
3781 pFrame->CallCallback( SalEvent::KeyUp, &aKeyEvt );
3783 return nRet;
3785 // MCD, 2003-01-13, Support for WM_UNICHAR & Keyman 6.0; addition ends
3786 else
3788 // for shift, control and menu we issue a KeyModChange event
3789 if ( (wParam == VK_SHIFT) || (wParam == VK_CONTROL) || (wParam == VK_MENU) )
3791 SalKeyModEvent aModEvt;
3792 aModEvt.mbDown = false; // auto-accelerator feature not supported here.
3793 aModEvt.mnCode = nModCode;
3794 aModEvt.mnModKeyCode = ModKeyFlags::NONE; // no command events will be sent if this member is 0
3796 ModKeyFlags tmpCode = ModKeyFlags::NONE;
3797 if( GetKeyState( VK_LSHIFT ) & 0x8000 )
3798 tmpCode |= ModKeyFlags::LeftShift;
3799 if( GetKeyState( VK_RSHIFT ) & 0x8000 )
3800 tmpCode |= ModKeyFlags::RightShift;
3801 if( GetKeyState( VK_LCONTROL ) & 0x8000 )
3802 tmpCode |= ModKeyFlags::LeftMod1;
3803 if( GetKeyState( VK_RCONTROL ) & 0x8000 )
3804 tmpCode |= ModKeyFlags::RightMod1;
3805 if( GetKeyState( VK_LMENU ) & 0x8000 )
3806 tmpCode |= ModKeyFlags::LeftMod2;
3807 if( GetKeyState( VK_RMENU ) & 0x8000 )
3808 tmpCode |= ModKeyFlags::RightMod2;
3810 if( tmpCode < nLastModKeyCode )
3812 aModEvt.mnModKeyCode = nLastModKeyCode;
3813 nLastModKeyCode = ModKeyFlags::NONE;
3814 bWaitForModKeyRelease = true;
3816 else
3818 if( !bWaitForModKeyRelease )
3819 nLastModKeyCode = tmpCode;
3822 if( tmpCode == ModKeyFlags::NONE )
3823 bWaitForModKeyRelease = false;
3825 return pFrame->CallCallback( SalEvent::KeyModChange, &aModEvt );
3827 else
3829 SalKeyEvent aKeyEvt;
3830 SalEvent nEvent;
3831 MSG aCharMsg;
3832 bool bCharPeek = false;
3833 UINT nCharMsg = WM_CHAR;
3834 bool bKeyUp = (nMsg == WM_KEYUP) || (nMsg == WM_SYSKEYUP);
3836 nLastModKeyCode = ModKeyFlags::NONE; // make sure no modkey messages are sent if they belong to a hotkey (see above)
3837 aKeyEvt.mnCharCode = 0;
3838 aKeyEvt.mnCode = ImplSalGetKeyCode( wParam );
3839 if ( !bKeyUp )
3841 // check for charcode
3842 // Get the related WM_CHAR message using PeekMessage, if available.
3843 // The WM_CHAR message is always at the beginning of the
3844 // message queue. Also it is made certain that there is always only
3845 // one WM_CHAR message in the queue.
3846 bCharPeek = PeekMessageW( &aCharMsg, hWnd,
3847 WM_CHAR, WM_CHAR, PM_NOREMOVE | PM_NOYIELD );
3848 if ( bCharPeek && (nDeadChar == aCharMsg.wParam) )
3850 bCharPeek = false;
3851 nDeadChar = 0;
3853 if ( wParam == VK_BACK )
3855 PeekMessageW( &aCharMsg, hWnd,
3856 nCharMsg, nCharMsg, PM_REMOVE | PM_NOYIELD );
3857 return false;
3860 else
3862 if ( !bCharPeek )
3864 bCharPeek = PeekMessageW( &aCharMsg, hWnd,
3865 WM_SYSCHAR, WM_SYSCHAR, PM_NOREMOVE | PM_NOYIELD );
3866 nCharMsg = WM_SYSCHAR;
3869 if ( bCharPeek )
3870 aKeyEvt.mnCharCode = ImplGetCharCode( pFrame, aCharMsg.wParam );
3871 else
3872 aKeyEvt.mnCharCode = 0;
3874 nLastChar = aKeyEvt.mnCharCode;
3875 nLastVKChar = wParam;
3877 else
3879 if ( wParam == nLastVKChar )
3881 aKeyEvt.mnCharCode = nLastChar;
3882 nLastChar = 0;
3883 nLastVKChar = 0;
3887 if ( aKeyEvt.mnCode || aKeyEvt.mnCharCode )
3889 if ( bKeyUp )
3890 nEvent = SalEvent::KeyUp;
3891 else
3892 nEvent = SalEvent::KeyInput;
3894 aKeyEvt.mnCode |= nModCode;
3895 aKeyEvt.mnRepeat = nRepeat;
3897 UnsetAltIfAltGr(aKeyEvt, nModCode);
3898 FlushIMBeforeShortCut(pFrame, nEvent, nModCode);
3900 bIgnoreCharMsg = bCharPeek;
3901 bool nRet = pFrame->CallCallback( nEvent, &aKeyEvt );
3902 // independent part only reacts on keyup but Windows does not send
3903 // keyup for VK_HANJA
3904 if( aKeyEvt.mnCode == KEY_HANGUL_HANJA )
3905 nRet = pFrame->CallCallback( SalEvent::KeyUp, &aKeyEvt );
3907 bIgnoreCharMsg = false;
3909 // char-message, then remove or ignore
3910 if ( bCharPeek )
3912 nDeadChar = 0;
3913 if ( nRet )
3915 PeekMessageW( &aCharMsg, hWnd,
3916 nCharMsg, nCharMsg, PM_REMOVE | PM_NOYIELD );
3918 else
3919 bIgnoreCharMsg = true;
3922 return nRet;
3924 else
3925 return false;
3930 bool ImplHandleSalObjKeyMsg( HWND hWnd, UINT nMsg,
3931 WPARAM wParam, LPARAM lParam )
3933 if ( (nMsg == WM_KEYDOWN) || (nMsg == WM_KEYUP) )
3935 WinSalFrame* pFrame = GetWindowPtr( hWnd );
3936 if ( !pFrame )
3937 return false;
3939 sal_uInt16 nRepeat = LOWORD( lParam )-1;
3940 sal_uInt16 nModCode = 0;
3942 // determine modifiers
3943 if ( GetKeyState( VK_SHIFT ) & 0x8000 )
3944 nModCode |= KEY_SHIFT;
3945 if ( GetKeyState( VK_CONTROL ) & 0x8000 )
3946 nModCode |= KEY_MOD1;
3947 if ( GetKeyState( VK_MENU ) & 0x8000 )
3948 nModCode |= KEY_MOD2;
3950 if ( (wParam != VK_SHIFT) && (wParam != VK_CONTROL) && (wParam != VK_MENU) )
3952 SalKeyEvent aKeyEvt;
3953 SalEvent nEvent;
3955 // convert KeyCode
3956 aKeyEvt.mnCode = ImplSalGetKeyCode( wParam );
3957 aKeyEvt.mnCharCode = 0;
3959 if ( aKeyEvt.mnCode )
3961 if (nMsg == WM_KEYUP)
3962 nEvent = SalEvent::KeyUp;
3963 else
3964 nEvent = SalEvent::KeyInput;
3966 aKeyEvt.mnCode |= nModCode;
3967 aKeyEvt.mnRepeat = nRepeat;
3968 bool nRet = pFrame->CallCallback( nEvent, &aKeyEvt );
3969 return nRet;
3971 else
3972 return false;
3976 return false;
3979 bool ImplHandleSalObjSysCharMsg( HWND hWnd, WPARAM wParam, LPARAM lParam )
3981 WinSalFrame* pFrame = GetWindowPtr( hWnd );
3982 if ( !pFrame )
3983 return false;
3985 sal_uInt16 nRepeat = LOWORD( lParam )-1;
3986 sal_uInt16 nModCode = 0;
3987 sal_uInt16 cKeyCode = static_cast<sal_uInt16>(wParam);
3989 // determine modifiers
3990 if ( GetKeyState( VK_SHIFT ) & 0x8000 )
3991 nModCode |= KEY_SHIFT;
3992 if ( GetKeyState( VK_CONTROL ) & 0x8000 )
3993 nModCode |= KEY_MOD1;
3994 nModCode |= KEY_MOD2;
3996 // assemble KeyEvent
3997 SalKeyEvent aKeyEvt;
3998 if ( (cKeyCode >= 48) && (cKeyCode <= 57) )
3999 aKeyEvt.mnCode = KEY_0+(cKeyCode-48);
4000 else if ( (cKeyCode >= 65) && (cKeyCode <= 90) )
4001 aKeyEvt.mnCode = KEY_A+(cKeyCode-65);
4002 else if ( (cKeyCode >= 97) && (cKeyCode <= 122) )
4003 aKeyEvt.mnCode = KEY_A+(cKeyCode-97);
4004 else
4005 aKeyEvt.mnCode = 0;
4006 aKeyEvt.mnCode |= nModCode;
4007 aKeyEvt.mnCharCode = ImplGetCharCode( pFrame, cKeyCode );
4008 aKeyEvt.mnRepeat = nRepeat;
4009 bool nRet = pFrame->CallCallback( SalEvent::KeyInput, &aKeyEvt );
4010 pFrame->CallCallback( SalEvent::KeyUp, &aKeyEvt );
4011 return nRet;
4014 namespace {
4016 enum class DeferPolicy
4018 Blocked,
4019 Allowed
4024 // Remember to release the solar mutex on success!
4025 static WinSalFrame* ProcessOrDeferMessage( HWND hWnd, INT nMsg, WPARAM pWParam = 0,
4026 DeferPolicy eCanDefer = DeferPolicy::Allowed )
4028 bool bFailedCondition = false, bGotMutex = false;
4029 WinSalFrame* pFrame = nullptr;
4031 if ( DeferPolicy::Blocked == eCanDefer )
4032 assert( (DeferPolicy::Blocked == eCanDefer) && (nMsg == 0) && (pWParam == 0) );
4033 else
4034 assert( (DeferPolicy::Allowed == eCanDefer) && (nMsg != 0) );
4036 if ( DeferPolicy::Blocked == eCanDefer )
4038 ImplSalYieldMutexAcquireWithWait();
4039 bGotMutex = true;
4041 else if ( !(bGotMutex = ImplSalYieldMutexTryToAcquire()) )
4042 bFailedCondition = true;
4044 if ( !bFailedCondition )
4046 pFrame = GetWindowPtr( hWnd );
4047 bFailedCondition = pFrame == nullptr;
4050 if ( bFailedCondition )
4052 if ( bGotMutex )
4053 ImplSalYieldMutexRelease();
4054 if ( DeferPolicy::Allowed == eCanDefer )
4056 bool const ret = PostMessageW(hWnd, nMsg, pWParam, 0);
4057 SAL_WARN_IF(!ret, "vcl", "ERROR: PostMessage() failed!");
4061 return pFrame;
4064 namespace {
4066 enum class PostedState
4068 IsPosted,
4069 IsInitial
4074 static bool ImplHandlePostPaintMsg( HWND hWnd, RECT* pRect,
4075 PostedState eProcessed = PostedState::IsPosted )
4077 RECT* pMsgRect;
4078 if ( PostedState::IsInitial == eProcessed )
4080 pMsgRect = new RECT;
4081 CopyRect( pMsgRect, pRect );
4083 else
4084 pMsgRect = pRect;
4086 WinSalFrame* pFrame = ProcessOrDeferMessage( hWnd, SAL_MSG_POSTPAINT,
4087 reinterpret_cast<WPARAM>(pMsgRect) );
4088 if ( pFrame )
4090 SalPaintEvent aPEvt( pRect->left, pRect->top, pRect->right-pRect->left, pRect->bottom-pRect->top );
4091 pFrame->CallCallback( SalEvent::Paint, &aPEvt );
4092 ImplSalYieldMutexRelease();
4093 if ( PostedState::IsPosted == eProcessed )
4094 delete pRect;
4097 return (pFrame != nullptr);
4100 static bool ImplHandlePaintMsg( HWND hWnd )
4102 bool bPaintSuccessful = false;
4104 // even without the Yield mutex, we can still change the clip region,
4105 // because other threads don't use the Yield mutex
4106 // --> see AcquireGraphics()
4108 WinSalFrame* pFrame = GetWindowPtr( hWnd );
4109 if ( pFrame )
4111 // clip region must be set, as we don't get a proper
4112 // bounding rectangle otherwise
4113 WinSalGraphics *pGraphics = pFrame->mpLocalGraphics;
4114 bool bHasClipRegion = pGraphics &&
4115 pGraphics->getHDC() && pGraphics->getRegion();
4116 if ( bHasClipRegion )
4117 SelectClipRgn( pGraphics->getHDC(), nullptr );
4119 // according to Windows documentation one shall check first if
4120 // there really is a paint-region
4121 RECT aUpdateRect;
4122 PAINTSTRUCT aPs;
4123 bool bHasPaintRegion = GetUpdateRect( hWnd, nullptr, FALSE );
4124 if ( bHasPaintRegion )
4126 // call BeginPaint/EndPaint to query the paint rect and use
4127 // this information in the (deferred) paint
4128 BeginPaint( hWnd, &aPs );
4129 CopyRect( &aUpdateRect, &aPs.rcPaint );
4132 // reset clip region
4133 if ( bHasClipRegion )
4134 SelectClipRgn( pGraphics->getHDC(), pGraphics->getRegion() );
4136 // try painting
4137 if ( bHasPaintRegion )
4139 bPaintSuccessful = ImplHandlePostPaintMsg(
4140 hWnd, &aUpdateRect, PostedState::IsInitial );
4141 EndPaint( hWnd, &aPs );
4143 else // if there is nothing to paint, the paint is successful
4144 bPaintSuccessful = true;
4147 return bPaintSuccessful;
4150 static void SetMaximizedFrameGeometry( HWND hWnd, WinSalFrame* pFrame, RECT* pParentRect )
4152 // calculate and set frame geometry of a maximized window - useful if the window is still hidden
4154 // dualmonitor support:
4155 // Get screensize of the monitor with the mouse pointer
4157 RECT aRectMouse;
4158 if( ! pParentRect )
4160 POINT pt;
4161 GetCursorPos( &pt );
4162 aRectMouse.left = pt.x;
4163 aRectMouse.top = pt.y;
4164 aRectMouse.right = pt.x+2;
4165 aRectMouse.bottom = pt.y+2;
4166 pParentRect = &aRectMouse;
4169 RECT aRect;
4170 ImplSalGetWorkArea( hWnd, &aRect, pParentRect );
4172 // a maximized window has no other borders than the caption
4173 pFrame->maGeometry.setDecorations(0, pFrame->mbCaption ? GetSystemMetrics(SM_CYCAPTION) : 0, 0, 0);
4175 aRect.top += pFrame->maGeometry.topDecoration();
4176 pFrame->maGeometry.setPos({ aRect.left, aRect.top });
4177 SetGeometrySize(pFrame->maGeometry, { aRect.right - aRect.left, aRect.bottom - aRect.top });
4180 static void UpdateFrameGeometry(WinSalFrame* pFrame)
4182 if( !pFrame )
4183 return;
4184 const HWND hWnd = pFrame->mhWnd;
4186 RECT aRect;
4187 GetWindowRect( hWnd, &aRect );
4188 pFrame->maGeometry.setPosSize({ 0, 0 }, { 0, 0 });
4189 pFrame->maGeometry.setDecorations(0, 0, 0, 0);
4190 pFrame->maGeometry.setScreen(0);
4192 if ( IsIconic( hWnd ) )
4193 return;
4195 POINT aPt;
4196 aPt.x=0;
4197 aPt.y=0;
4198 ClientToScreen(hWnd, &aPt);
4199 int cx = aPt.x - aRect.left;
4201 pFrame->maGeometry.setDecorations(cx, aPt.y - aRect.top, cx, 0);
4202 pFrame->maGeometry.setPos({ aPt.x, aPt.y });
4204 RECT aInnerRect;
4205 GetClientRect( hWnd, &aInnerRect );
4206 if( aInnerRect.right )
4208 // improve right decoration
4209 aPt.x=aInnerRect.right;
4210 aPt.y=aInnerRect.top;
4211 ClientToScreen(hWnd, &aPt);
4212 pFrame->maGeometry.setRightDecoration(aRect.right - aPt.x);
4214 if( aInnerRect.bottom ) // may be zero if window was not shown yet
4215 pFrame->maGeometry.setBottomDecoration(aRect.bottom - aPt.y - aInnerRect.bottom);
4216 else
4217 // bottom border is typically the same as left/right
4218 pFrame->maGeometry.setBottomDecoration(pFrame->maGeometry.leftDecoration());
4220 int nWidth = aRect.right - aRect.left
4221 - pFrame->maGeometry.rightDecoration() - pFrame->maGeometry.leftDecoration();
4222 int nHeight = aRect.bottom - aRect.top
4223 - pFrame->maGeometry.bottomDecoration() - pFrame->maGeometry.topDecoration();
4224 SetGeometrySize(pFrame->maGeometry, { nWidth, nHeight });
4225 pFrame->updateScreenNumber();
4228 static void ImplCallClosePopupsHdl( HWND hWnd )
4230 WinSalFrame* pFrame = GetWindowPtr( hWnd );
4231 if ( pFrame )
4233 pFrame->CallCallback( SalEvent::ClosePopups, nullptr );
4237 static void ImplCallMoveHdl(HWND hWnd)
4239 WinSalFrame* pFrame = ProcessOrDeferMessage(hWnd, SAL_MSG_POSTMOVE);
4240 if (!pFrame)
4241 return;
4243 pFrame->CallCallback(SalEvent::Move, nullptr);
4245 ImplSalYieldMutexRelease();
4248 static void ImplHandleMoveMsg(HWND hWnd, LPARAM lParam)
4250 WinSalFrame* pFrame = GetWindowPtr( hWnd );
4251 if (!pFrame)
4252 return;
4254 UpdateFrameGeometry(pFrame);
4256 #ifdef NDEBUG
4257 (void) lParam;
4258 #endif
4259 assert(IsIconic(hWnd) || (pFrame->maGeometry.x() == static_cast<sal_Int16>(LOWORD(lParam))));
4260 assert(IsIconic(hWnd) || (pFrame->maGeometry.y() == static_cast<sal_Int16>(HIWORD(lParam))));
4262 if (GetWindowStyle(hWnd) & WS_VISIBLE)
4263 pFrame->mbDefPos = false;
4265 // protect against recursion
4266 if (!pFrame->mbInMoveMsg)
4268 // adjust window again for FullScreenMode
4269 pFrame->mbInMoveMsg = true;
4270 if (pFrame->isFullScreen())
4271 ImplSalFrameFullScreenPos(pFrame);
4272 pFrame->mbInMoveMsg = false;
4275 pFrame->UpdateFrameState();
4277 ImplCallMoveHdl(hWnd);
4280 static void ImplCallSizeHdl( HWND hWnd )
4282 WinSalFrame* pFrame = ProcessOrDeferMessage( hWnd, SAL_MSG_POSTCALLSIZE );
4283 if (!pFrame)
4284 return;
4286 pFrame->CallCallback(SalEvent::Resize, nullptr);
4287 // to avoid double Paints by VCL and SAL
4288 if (IsWindowVisible(hWnd) && !pFrame->mbInShow)
4289 UpdateWindow(hWnd);
4291 ImplSalYieldMutexRelease();
4294 static void ImplHandleSizeMsg(HWND hWnd, WPARAM wParam, LPARAM lParam)
4296 if ((wParam == SIZE_MAXSHOW) || (wParam == SIZE_MAXHIDE))
4297 return;
4299 WinSalFrame* pFrame = GetWindowPtr(hWnd);
4300 if (!pFrame)
4301 return;
4303 UpdateFrameGeometry(pFrame);
4305 #ifdef NDEBUG
4306 (void) lParam;
4307 #endif
4308 assert(pFrame->maGeometry.width() == static_cast<sal_Int16>(LOWORD(lParam)));
4309 assert(pFrame->maGeometry.height() == static_cast<sal_Int16>(HIWORD(lParam)));
4311 pFrame->UpdateFrameState();
4313 ImplCallSizeHdl(hWnd);
4315 WinSalTimer* pTimer = static_cast<WinSalTimer*>(ImplGetSVData()->maSchedCtx.mpSalTimer);
4316 if (pTimer)
4317 pTimer->SetForceRealTimer(true);
4320 static void ImplHandleFocusMsg( HWND hWnd )
4322 WinSalFrame* pFrame = ProcessOrDeferMessage( hWnd, SAL_MSG_POSTFOCUS );
4323 if (!pFrame)
4324 return;
4325 const ::comphelper::ScopeGuard aScopeGuard([](){ ImplSalYieldMutexRelease(); });
4327 if (WinSalFrame::mbInReparent)
4328 return;
4330 const bool bGotFocus = ::GetFocus() == hWnd;
4331 if (bGotFocus)
4333 if (IsWindowVisible(hWnd) && !pFrame->mbInShow)
4334 UpdateWindow(hWnd);
4336 // do we support IME?
4337 if (pFrame->mbIME && pFrame->mhDefIMEContext)
4339 UINT nImeProps = ImmGetProperty(GetKeyboardLayout(0), IGP_PROPERTY);
4340 pFrame->mbSpezIME = (nImeProps & IME_PROP_SPECIAL_UI) != 0;
4341 pFrame->mbAtCursorIME = (nImeProps & IME_PROP_AT_CARET) != 0;
4342 pFrame->mbHandleIME = !pFrame->mbSpezIME;
4346 pFrame->CallCallback(bGotFocus ? SalEvent::GetFocus : SalEvent::LoseFocus, nullptr);
4349 static void ImplHandleCloseMsg( HWND hWnd )
4351 WinSalFrame* pFrame = ProcessOrDeferMessage( hWnd, WM_CLOSE );
4352 if ( pFrame )
4354 pFrame->CallCallback( SalEvent::Close, nullptr );
4355 ImplSalYieldMutexRelease();
4359 static bool ImplHandleShutDownMsg( HWND hWnd )
4361 bool nRet = false;
4362 WinSalFrame* pFrame = ProcessOrDeferMessage( hWnd, 0, 0, DeferPolicy::Blocked );
4363 if ( pFrame )
4365 nRet = pFrame->CallCallback( SalEvent::Shutdown, nullptr );
4366 ImplSalYieldMutexRelease();
4368 return nRet;
4371 static void ImplHandleSettingsChangeMsg( HWND hWnd, UINT nMsg,
4372 WPARAM wParam, LPARAM lParam )
4374 SalEvent nSalEvent = SalEvent::SettingsChanged;
4376 if ( nMsg == WM_DEVMODECHANGE )
4377 nSalEvent = SalEvent::PrinterChanged;
4378 else if ( nMsg == WM_DISPLAYCHANGE )
4379 nSalEvent = SalEvent::DisplayChanged;
4380 else if ( nMsg == WM_FONTCHANGE )
4381 nSalEvent = SalEvent::FontChanged;
4382 else if ( nMsg == WM_WININICHANGE )
4384 if ( lParam )
4386 if ( ImplSalWICompareAscii( reinterpret_cast<const wchar_t*>(lParam), "devices" ) == 0 )
4387 nSalEvent = SalEvent::PrinterChanged;
4391 if ( nMsg == WM_SETTINGCHANGE )
4393 if ( wParam == SPI_SETWHEELSCROLLLINES )
4394 aSalShlData.mnWheelScrollLines = ImplSalGetWheelScrollLines();
4395 else if( wParam == SPI_SETWHEELSCROLLCHARS )
4396 aSalShlData.mnWheelScrollChars = ImplSalGetWheelScrollChars();
4397 UpdateDarkMode(hWnd);
4398 GetSalData()->mbThemeChanged = true;
4401 if ( WM_SYSCOLORCHANGE == nMsg && GetSalData()->mhDitherPal )
4402 ImplUpdateSysColorEntries();
4404 WinSalFrame* pFrame = ProcessOrDeferMessage( hWnd, 0, 0, DeferPolicy::Blocked );
4405 if (!pFrame)
4406 return;
4408 if (((nMsg == WM_DISPLAYCHANGE) || (nMsg == WM_WININICHANGE)) && pFrame->isFullScreen())
4409 ImplSalFrameFullScreenPos(pFrame);
4411 pFrame->CallCallback(nSalEvent, nullptr);
4413 ImplSalYieldMutexRelease();
4416 static void ImplHandleUserEvent( HWND hWnd, LPARAM lParam )
4418 WinSalFrame* pFrame = ProcessOrDeferMessage( hWnd, 0, 0, DeferPolicy::Blocked );
4419 if ( pFrame )
4421 pFrame->CallCallback( SalEvent::UserEvent, reinterpret_cast<void*>(lParam) );
4422 ImplSalYieldMutexRelease();
4426 static void ImplHandleForcePalette( HWND hWnd )
4428 SalData* pSalData = GetSalData();
4429 HPALETTE hPal = pSalData->mhDitherPal;
4430 if (!hPal)
4431 return;
4433 WinSalFrame* pFrame = ProcessOrDeferMessage(hWnd, SAL_MSG_FORCEPALETTE);
4434 if (!pFrame)
4435 return;
4436 const ::comphelper::ScopeGuard aScopeGuard([](){ ImplSalYieldMutexRelease(); });
4438 WinSalGraphics* pGraphics = pFrame->mpLocalGraphics;
4439 if (!pGraphics || !pGraphics->getHDC() || !pGraphics->getDefPal()
4440 || (pGraphics->setPalette(hPal, FALSE) == GDI_ERROR))
4441 return;
4443 InvalidateRect(hWnd, nullptr, FALSE);
4444 UpdateWindow(hWnd);
4445 pFrame->CallCallback(SalEvent::DisplayChanged, nullptr);
4448 static LRESULT ImplHandlePalette( bool bFrame, HWND hWnd, UINT nMsg,
4449 WPARAM wParam, LPARAM lParam, bool& rDef )
4451 SalData* pSalData = GetSalData();
4452 HPALETTE hPal = pSalData->mhDitherPal;
4453 if ( !hPal )
4454 return 0;
4456 rDef = false;
4457 if ( pSalData->mbInPalChange )
4458 return 0;
4460 if ( (nMsg == WM_PALETTECHANGED) || (nMsg == SAL_MSG_POSTPALCHANGED) )
4462 if ( reinterpret_cast<HWND>(wParam) == hWnd )
4463 return 0;
4466 bool bReleaseMutex = false;
4467 if ( (nMsg == WM_QUERYNEWPALETTE) || (nMsg == WM_PALETTECHANGED) )
4469 // as Windows can send these messages also, we have to use
4470 // the Solar semaphore
4471 if ( ImplSalYieldMutexTryToAcquire() )
4472 bReleaseMutex = true;
4473 else if ( nMsg == WM_QUERYNEWPALETTE )
4475 bool const ret = PostMessageW(hWnd, SAL_MSG_POSTQUERYNEWPAL, wParam, lParam);
4476 SAL_WARN_IF(!ret, "vcl", "ERROR: PostMessage() failed!");
4478 else /* ( nMsg == WM_PALETTECHANGED ) */
4480 bool const ret = PostMessageW(hWnd, SAL_MSG_POSTPALCHANGED, wParam, lParam);
4481 SAL_WARN_IF(!ret, "vcl", "ERROR: PostMessage() failed!");
4485 WinSalVirtualDevice*pTempVD;
4486 WinSalFrame* pTempFrame;
4487 WinSalGraphics* pGraphics;
4488 HDC hDC;
4489 HPALETTE hOldPal = nullptr;
4490 UINT nCols = GDI_ERROR;
4491 bool bUpdate;
4493 pSalData->mbInPalChange = true;
4495 // reset all palettes in VirDevs and Frames
4496 pTempVD = pSalData->mpFirstVD;
4497 while ( pTempVD )
4499 pGraphics = pTempVD->getGraphics();
4500 pGraphics->setPalette(nullptr);
4501 pTempVD = pTempVD->getNext();
4503 pTempFrame = pSalData->mpFirstFrame;
4504 while ( pTempFrame )
4506 pGraphics = pTempFrame->mpLocalGraphics;
4507 pGraphics->setPalette(nullptr);
4508 pTempFrame = pTempFrame->mpNextFrame;
4511 // re-initialize palette
4512 WinSalFrame* pFrame = nullptr;
4513 if ( bFrame )
4514 pFrame = GetWindowPtr( hWnd );
4516 UnrealizeObject(hPal);
4517 const bool bStdDC = pFrame && pFrame->mpLocalGraphics && pFrame->mpLocalGraphics->getHDC();
4518 if (!bStdDC)
4520 hDC = GetDC(hWnd);
4521 hOldPal = SelectPalette(hDC, hPal, TRUE);
4522 if (hOldPal)
4523 nCols = RealizePalette(hDC);
4525 else
4527 hDC = pFrame->mpLocalGraphics->getHDC();
4528 nCols = pFrame->mpLocalGraphics->setPalette(hPal);
4531 bUpdate = nCols != 0 && nCols != GDI_ERROR;
4533 if ( !bStdDC )
4535 if (hOldPal)
4536 SelectPalette(hDC, hOldPal, TRUE);
4537 ReleaseDC( hWnd, hDC );
4540 // reset all palettes in VirDevs and Frames
4541 pTempVD = pSalData->mpFirstVD;
4542 while ( pTempVD )
4544 pGraphics = pTempVD->getGraphics();
4545 if ( pGraphics->getDefPal() )
4546 pGraphics->setPalette(hPal);
4547 pTempVD = pTempVD->getNext();
4550 pTempFrame = pSalData->mpFirstFrame;
4551 while ( pTempFrame )
4553 if ( pTempFrame != pFrame )
4555 pGraphics = pTempFrame->mpLocalGraphics;
4556 if (pGraphics && pGraphics->getDefPal())
4558 UINT nRes = pGraphics->setPalette(hPal);
4559 if (nRes != 0 && nRes != GDI_ERROR)
4560 bUpdate = true;
4563 pTempFrame = pTempFrame->mpNextFrame;
4566 // if colors changed, update the window
4567 if ( bUpdate )
4569 pTempFrame = pSalData->mpFirstFrame;
4570 while ( pTempFrame )
4572 pGraphics = pTempFrame->mpLocalGraphics;
4573 if (pGraphics && pGraphics->getDefPal())
4575 InvalidateRect( pTempFrame->mhWnd, nullptr, FALSE );
4576 UpdateWindow( pTempFrame->mhWnd );
4577 pTempFrame->CallCallback( SalEvent::DisplayChanged, nullptr );
4579 pTempFrame = pTempFrame->mpNextFrame;
4583 pSalData->mbInPalChange = false;
4585 if ( bReleaseMutex )
4586 ImplSalYieldMutexRelease();
4588 if ( nMsg == WM_PALETTECHANGED )
4589 return 0;
4590 else
4591 return nCols;
4594 static bool ImplHandleMinMax( HWND hWnd, LPARAM lParam )
4596 bool bRet = false;
4598 if ( ImplSalYieldMutexTryToAcquire() )
4600 WinSalFrame* pFrame = GetWindowPtr( hWnd );
4601 if ( pFrame )
4603 MINMAXINFO* pMinMax = reinterpret_cast<MINMAXINFO*>(lParam);
4605 if (pFrame->isFullScreen())
4607 int nX;
4608 int nY;
4609 int nDX;
4610 int nDY;
4611 ImplSalCalcFullScreenSize( pFrame, nX, nY, nDX, nDY );
4613 if ( pMinMax->ptMaxPosition.x > nX )
4614 pMinMax->ptMaxPosition.x = nX;
4615 if ( pMinMax->ptMaxPosition.y > nY )
4616 pMinMax->ptMaxPosition.y = nY;
4618 if ( pMinMax->ptMaxSize.x < nDX )
4619 pMinMax->ptMaxSize.x = nDX;
4620 if ( pMinMax->ptMaxSize.y < nDY )
4621 pMinMax->ptMaxSize.y = nDY;
4622 if ( pMinMax->ptMaxTrackSize.x < nDX )
4623 pMinMax->ptMaxTrackSize.x = nDX;
4624 if ( pMinMax->ptMaxTrackSize.y < nDY )
4625 pMinMax->ptMaxTrackSize.y = nDY;
4627 pMinMax->ptMinTrackSize.x = nDX;
4628 pMinMax->ptMinTrackSize.y = nDY;
4630 bRet = true;
4633 if ( pFrame->mnMinWidth || pFrame->mnMinHeight )
4635 int nWidth = pFrame->mnMinWidth;
4636 int nHeight = pFrame->mnMinHeight;
4638 ImplSalAddBorder( pFrame, nWidth, nHeight );
4640 if ( pMinMax->ptMinTrackSize.x < nWidth )
4641 pMinMax->ptMinTrackSize.x = nWidth;
4642 if ( pMinMax->ptMinTrackSize.y < nHeight )
4643 pMinMax->ptMinTrackSize.y = nHeight;
4646 if ( pFrame->mnMaxWidth || pFrame->mnMaxHeight )
4648 int nWidth = pFrame->mnMaxWidth;
4649 int nHeight = pFrame->mnMaxHeight;
4651 ImplSalAddBorder( pFrame, nWidth, nHeight );
4653 if( nWidth > 0 && nHeight > 0 ) // protect against int overflow due to INT_MAX initialisation
4655 if ( pMinMax->ptMaxTrackSize.x > nWidth )
4656 pMinMax->ptMaxTrackSize.x = nWidth;
4657 if ( pMinMax->ptMaxTrackSize.y > nHeight )
4658 pMinMax->ptMaxTrackSize.y = nHeight;
4663 ImplSalYieldMutexRelease();
4666 return bRet;
4669 // retrieves the SalMenuItem pointer from a hMenu
4670 // the pointer is stored in every item, so if no position
4671 // is specified we just use the first item (ie, pos=0)
4672 // if bByPosition is false then nPos denotes a menu id instead of a position
4673 static WinSalMenuItem* ImplGetSalMenuItem( HMENU hMenu, UINT nPos, bool bByPosition=true )
4675 MENUITEMINFOW mi = {};
4676 mi.cbSize = sizeof( mi );
4677 mi.fMask = MIIM_DATA;
4678 if( !GetMenuItemInfoW( hMenu, nPos, bByPosition, &mi) )
4679 SAL_WARN("vcl", "GetMenuItemInfoW failed: " << WindowsErrorString(GetLastError()));
4681 return reinterpret_cast<WinSalMenuItem *>(mi.dwItemData);
4684 // returns the index of the currently selected item if any or -1
4685 static int ImplGetSelectedIndex( HMENU hMenu )
4687 MENUITEMINFOW mi = {};
4688 mi.cbSize = sizeof( mi );
4689 mi.fMask = MIIM_STATE;
4690 int n = GetMenuItemCount( hMenu );
4691 if( n != -1 )
4693 for(int i=0; i<n; i++ )
4695 if( !GetMenuItemInfoW( hMenu, i, TRUE, &mi) )
4696 SAL_WARN( "vcl", "GetMenuItemInfoW failed: " << WindowsErrorString( GetLastError() ) );
4697 else
4699 if( mi.fState & MFS_HILITE )
4700 return i;
4704 return -1;
4707 static LRESULT ImplMenuChar( HWND, WPARAM wParam, LPARAM lParam )
4709 LRESULT nRet = MNC_IGNORE;
4710 HMENU hMenu = reinterpret_cast<HMENU>(lParam);
4711 OUString aMnemonic( "&" + OUStringChar(static_cast<sal_Unicode>(LOWORD(wParam))) );
4712 aMnemonic = aMnemonic.toAsciiLowerCase(); // we only have ascii mnemonics
4714 // search the mnemonic in the current menu
4715 int nItemCount = GetMenuItemCount( hMenu );
4716 int nFound = 0;
4717 int idxFound = -1;
4718 int idxSelected = ImplGetSelectedIndex( hMenu );
4719 int idx = idxSelected != -1 ? idxSelected+1 : 0; // if duplicate mnemonics cycle through menu
4720 for( int i=0; i< nItemCount; i++, idx++ )
4722 WinSalMenuItem* pSalMenuItem = ImplGetSalMenuItem( hMenu, idx % nItemCount );
4723 if( !pSalMenuItem )
4724 continue;
4725 OUString aStr = pSalMenuItem->mText;
4726 aStr = aStr.toAsciiLowerCase();
4727 if( aStr.indexOf( aMnemonic ) != -1 )
4729 if( idxFound == -1 )
4730 idxFound = idx % nItemCount;
4731 if( nFound++ )
4732 break; // duplicate found
4735 if( nFound == 1 )
4736 nRet = MAKELRESULT( idxFound, MNC_EXECUTE );
4737 else
4738 // duplicate mnemonics, just select the next occurrence
4739 nRet = MAKELRESULT( idxFound, MNC_SELECT );
4741 return nRet;
4744 static LRESULT ImplMeasureItem( HWND hWnd, WPARAM wParam, LPARAM lParam )
4746 LRESULT nRet = 0;
4747 if( !wParam )
4749 // request was sent by a menu
4750 nRet = 1;
4751 MEASUREITEMSTRUCT *pMI = reinterpret_cast<LPMEASUREITEMSTRUCT>(lParam);
4752 if( pMI->CtlType != ODT_MENU )
4753 return 0;
4755 WinSalMenuItem *pSalMenuItem = reinterpret_cast<WinSalMenuItem *>(pMI->itemData);
4756 if( !pSalMenuItem )
4757 return 0;
4759 HDC hdc = GetDC( hWnd );
4760 SIZE strSize;
4762 NONCLIENTMETRICSW ncm = {};
4763 ncm.cbSize = sizeof( ncm );
4764 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4766 // Assume every menu item can be default and printed bold
4767 //ncm.lfMenuFont.lfWeight = FW_BOLD;
4769 HFONT hfntOld = static_cast<HFONT>(SelectObject(hdc, CreateFontIndirectW( &ncm.lfMenuFont )));
4771 // menu text and accelerator
4772 OUString aStr(pSalMenuItem->mText);
4773 if( pSalMenuItem->mAccelText.getLength() )
4775 aStr += " " + pSalMenuItem->mAccelText;
4777 GetTextExtentPoint32W( hdc, o3tl::toW(aStr.getStr()),
4778 aStr.getLength(), &strSize );
4780 // image
4781 Size bmpSize( 16, 16 );
4782 //if( pSalMenuItem->maBitmap )
4783 // bmpSize = pSalMenuItem->maBitmap.GetSizePixel();
4785 // checkmark
4786 Size checkSize( GetSystemMetrics( SM_CXMENUCHECK ), GetSystemMetrics( SM_CYMENUCHECK ) );
4788 pMI->itemWidth = checkSize.Width() + 3 + bmpSize.Width() + 3 + strSize.cx;
4789 pMI->itemHeight = std::max( std::max( checkSize.Height(), bmpSize.Height() ), tools::Long(strSize.cy) );
4790 pMI->itemHeight += 4;
4792 DeleteObject( SelectObject(hdc, hfntOld) );
4793 ReleaseDC( hWnd, hdc );
4796 return nRet;
4799 static LRESULT ImplDrawItem(HWND, WPARAM wParam, LPARAM lParam )
4801 LRESULT nRet = 0;
4802 if( !wParam )
4804 // request was sent by a menu
4805 nRet = 1;
4806 DRAWITEMSTRUCT *pDI = reinterpret_cast<LPDRAWITEMSTRUCT>(lParam);
4807 if( pDI->CtlType != ODT_MENU )
4808 return 0;
4810 WinSalMenuItem *pSalMenuItem = reinterpret_cast<WinSalMenuItem *>(pDI->itemData);
4811 if( !pSalMenuItem )
4812 return 0;
4814 COLORREF clrPrevText, clrPrevBkgnd;
4815 HFONT hfntOld;
4816 HBRUSH hbrOld;
4817 bool fChecked = (pDI->itemState & ODS_CHECKED);
4818 bool fSelected = (pDI->itemState & ODS_SELECTED);
4819 bool fDisabled = (pDI->itemState & (ODS_DISABLED | ODS_GRAYED));
4821 // Set the appropriate foreground and background colors.
4822 RECT aRect = pDI->rcItem;
4824 if ( fDisabled )
4825 clrPrevText = SetTextColor( pDI->hDC, GetSysColor( COLOR_GRAYTEXT ) );
4826 else
4827 clrPrevText = SetTextColor( pDI->hDC, GetSysColor( fSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT ) );
4829 DWORD colBackground = GetSysColor( fSelected ? COLOR_HIGHLIGHT : COLOR_MENU );
4830 clrPrevBkgnd = SetBkColor( pDI->hDC, colBackground );
4832 hbrOld = static_cast<HBRUSH>(SelectObject( pDI->hDC, CreateSolidBrush( GetBkColor( pDI->hDC ) ) ));
4834 // Fill background
4835 if(!PatBlt( pDI->hDC, aRect.left, aRect.top, aRect.right-aRect.left, aRect.bottom-aRect.top, PATCOPY ))
4836 SAL_WARN("vcl", "PatBlt failed: " << WindowsErrorString(GetLastError()));
4838 int lineHeight = aRect.bottom-aRect.top;
4840 int x = aRect.left;
4841 int y = aRect.top;
4843 int checkWidth = GetSystemMetrics( SM_CXMENUCHECK );
4844 int checkHeight = GetSystemMetrics( SM_CYMENUCHECK );
4845 if( fChecked )
4847 RECT r;
4848 r.left = 0;
4849 r.top = 0;
4850 r.right = checkWidth;
4851 r.bottom = checkWidth;
4852 HDC memDC = CreateCompatibleDC( pDI->hDC );
4853 HBITMAP memBmp = CreateCompatibleBitmap( pDI->hDC, checkWidth, checkHeight );
4854 HBITMAP hOldBmp = static_cast<HBITMAP>(SelectObject( memDC, memBmp ));
4855 DrawFrameControl( memDC, &r, DFC_MENU, DFCS_MENUCHECK );
4856 BitBlt( pDI->hDC, x, y+(lineHeight-checkHeight)/2, checkWidth, checkHeight, memDC, 0, 0, SRCAND );
4857 DeleteObject( SelectObject( memDC, hOldBmp ) );
4858 DeleteDC( memDC );
4860 x += checkWidth+3;
4862 //Size bmpSize = aBitmap.GetSizePixel();
4863 Size bmpSize(16, 16);
4864 if( !pSalMenuItem->maBitmap.IsEmpty() )
4866 Bitmap aBitmap( pSalMenuItem->maBitmap );
4868 // set transparent pixels to background color
4869 if( fDisabled )
4870 colBackground = RGB(255,255,255);
4871 aBitmap.Replace( COL_LIGHTMAGENTA,
4872 Color( GetRValue(colBackground),GetGValue(colBackground),GetBValue(colBackground) ));
4874 WinSalBitmap* pSalBmp = static_cast<WinSalBitmap*>(aBitmap.ImplGetSalBitmap().get());
4875 HGLOBAL hDrawDIB = pSalBmp->ImplGethDIB();
4877 if( hDrawDIB )
4879 PBITMAPINFO pBI = static_cast<PBITMAPINFO>(GlobalLock( hDrawDIB ));
4880 PBYTE pBits = reinterpret_cast<PBYTE>(pBI) + pBI->bmiHeader.biSize +
4881 WinSalBitmap::ImplGetDIBColorCount( hDrawDIB ) * sizeof( RGBQUAD );
4883 HBITMAP hBmp = CreateDIBitmap( pDI->hDC, &pBI->bmiHeader, CBM_INIT, pBits, pBI, DIB_RGB_COLORS );
4884 GlobalUnlock( hDrawDIB );
4886 HBRUSH hbrIcon = CreateSolidBrush( GetSysColor( COLOR_GRAYTEXT ) );
4887 DrawStateW( pDI->hDC, hbrIcon, nullptr, reinterpret_cast<LPARAM>(hBmp), WPARAM(0),
4888 x, y+(lineHeight-bmpSize.Height())/2, bmpSize.Width(), bmpSize.Height(),
4889 DST_BITMAP | (fDisabled ? (fSelected ? DSS_MONO : DSS_DISABLED) : DSS_NORMAL) );
4891 DeleteObject( hbrIcon );
4892 DeleteObject( hBmp );
4896 x += bmpSize.Width() + 3;
4897 aRect.left = x;
4899 NONCLIENTMETRICSW ncm = {};
4900 ncm.cbSize = sizeof( ncm );
4901 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4903 // Print default menu entry with bold font
4904 //if ( pDI->itemState & ODS_DEFAULT )
4905 // ncm.lfMenuFont.lfWeight = FW_BOLD;
4907 hfntOld = static_cast<HFONT>(SelectObject(pDI->hDC, CreateFontIndirectW( &ncm.lfMenuFont )));
4909 SIZE strSize;
4910 OUString aStr( pSalMenuItem->mText );
4911 GetTextExtentPoint32W( pDI->hDC, o3tl::toW(aStr.getStr()),
4912 aStr.getLength(), &strSize );
4914 if(!DrawStateW( pDI->hDC, nullptr, nullptr,
4915 reinterpret_cast<LPARAM>(aStr.getStr()),
4916 WPARAM(0), aRect.left, aRect.top + (lineHeight - strSize.cy)/2, 0, 0,
4917 DST_PREFIXTEXT | (fDisabled && !fSelected ? DSS_DISABLED : DSS_NORMAL) ) )
4918 SAL_WARN("vcl", "DrawStateW failed: " << WindowsErrorString(GetLastError()));
4920 if( pSalMenuItem->mAccelText.getLength() )
4922 SIZE strSizeA;
4923 aStr = pSalMenuItem->mAccelText;
4924 GetTextExtentPoint32W( pDI->hDC, o3tl::toW(aStr.getStr()),
4925 aStr.getLength(), &strSizeA );
4926 TEXTMETRICW tm;
4927 GetTextMetricsW( pDI->hDC, &tm );
4929 // position the accelerator string to the right but leave space for the
4930 // (potential) submenu arrow (tm.tmMaxCharWidth)
4931 if(!DrawStateW( pDI->hDC, nullptr, nullptr,
4932 reinterpret_cast<LPARAM>(aStr.getStr()),
4933 WPARAM(0), aRect.right-strSizeA.cx-tm.tmMaxCharWidth, aRect.top + (lineHeight - strSizeA.cy)/2, 0, 0,
4934 DST_TEXT | (fDisabled && !fSelected ? DSS_DISABLED : DSS_NORMAL) ) )
4935 SAL_WARN("vcl", "DrawStateW failed: " << WindowsErrorString(GetLastError()));
4938 // Restore the original font and colors.
4939 DeleteObject( SelectObject( pDI->hDC, hbrOld ) );
4940 DeleteObject( SelectObject( pDI->hDC, hfntOld) );
4941 SetTextColor(pDI->hDC, clrPrevText);
4942 SetBkColor(pDI->hDC, clrPrevBkgnd);
4944 return nRet;
4947 static bool ImplHandleMenuActivate( HWND hWnd, WPARAM wParam, LPARAM )
4949 // Menu activation
4950 WinSalFrame* pFrame = GetWindowPtr( hWnd );
4951 if ( !pFrame )
4952 return false;
4954 HMENU hMenu = reinterpret_cast<HMENU>(wParam);
4955 // WORD nPos = LOWORD (lParam);
4956 // bool bWindowMenu = (bool) HIWORD(lParam);
4958 // Send activate and deactivate together, so we have not keep track of opened menus
4959 // this will be enough to have the menus updated correctly
4960 SalMenuEvent aMenuEvt;
4961 WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( hMenu, 0 );
4962 if( pSalMenuItem )
4963 aMenuEvt.mpMenu = pSalMenuItem->mpMenu;
4964 else
4965 aMenuEvt.mpMenu = nullptr;
4967 bool nRet = pFrame->CallCallback( SalEvent::MenuActivate, &aMenuEvt );
4968 if( nRet )
4969 nRet = pFrame->CallCallback( SalEvent::MenuDeactivate, &aMenuEvt );
4970 if( nRet )
4971 pFrame->mLastActivatedhMenu = hMenu;
4973 return nRet;
4976 static bool ImplHandleMenuSelect( HWND hWnd, WPARAM wParam, LPARAM lParam )
4978 // Menu selection
4979 WinSalFrame* pFrame = GetWindowPtr( hWnd );
4980 if ( !pFrame )
4981 return false;
4983 WORD nId = LOWORD(wParam); // menu item or submenu index
4984 WORD nFlags = HIWORD(wParam);
4985 HMENU hMenu = reinterpret_cast<HMENU>(lParam);
4987 // check if we have to process the message
4988 if( !GetSalData()->IsKnownMenuHandle( hMenu ) )
4989 return false;
4991 bool bByPosition = false;
4992 if( nFlags & MF_POPUP )
4993 bByPosition = true;
4995 bool nRet = false;
4996 if ( hMenu && !pFrame->mLastActivatedhMenu )
4998 // we never activated a menu (ie, no WM_INITMENUPOPUP has occurred yet)
4999 // which means this must be the menubar -> send activation/deactivation
5000 SalMenuEvent aMenuEvt;
5001 WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( hMenu, nId, bByPosition );
5002 if( pSalMenuItem )
5003 aMenuEvt.mpMenu = pSalMenuItem->mpMenu;
5004 else
5005 aMenuEvt.mpMenu = nullptr;
5007 nRet = pFrame->CallCallback( SalEvent::MenuActivate, &aMenuEvt );
5008 if( nRet )
5009 nRet = pFrame->CallCallback( SalEvent::MenuDeactivate, &aMenuEvt );
5010 if( nRet )
5011 pFrame->mLastActivatedhMenu = hMenu;
5014 if( !hMenu && nFlags == 0xFFFF )
5016 // all menus are closed, reset activation logic
5017 pFrame->mLastActivatedhMenu = nullptr;
5020 if( hMenu )
5022 // hMenu must be saved, as it is not passed in WM_COMMAND which always occurs after a selection
5023 // if a menu is closed due to a command selection then hMenu is NULL, but WM_COMMAND comes later
5024 // so we must not overwrite it in this case
5025 pFrame->mSelectedhMenu = hMenu;
5027 // send highlight event
5028 if( nFlags & MF_POPUP )
5030 // submenu selected
5031 // wParam now carries an index instead of an id -> retrieve id
5032 MENUITEMINFOW mi = {};
5033 mi.cbSize = sizeof( mi );
5034 mi.fMask = MIIM_ID;
5035 if( GetMenuItemInfoW( hMenu, LOWORD(wParam), TRUE, &mi) )
5036 nId = sal::static_int_cast<WORD>(mi.wID);
5039 SalMenuEvent aMenuEvt;
5040 aMenuEvt.mnId = nId;
5041 WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( hMenu, nId, false );
5042 if( pSalMenuItem )
5043 aMenuEvt.mpMenu = pSalMenuItem->mpMenu;
5044 else
5045 aMenuEvt.mpMenu = nullptr;
5047 nRet = pFrame->CallCallback( SalEvent::MenuHighlight, &aMenuEvt );
5050 return nRet;
5053 static bool ImplHandleCommand( HWND hWnd, WPARAM wParam, LPARAM )
5055 WinSalFrame* pFrame = GetWindowPtr( hWnd );
5056 if ( !pFrame )
5057 return false;
5059 bool nRet = false;
5060 if( !HIWORD(wParam) )
5062 // Menu command
5063 WORD nId = LOWORD(wParam);
5064 if( nId ) // zero for separators
5066 SalMenuEvent aMenuEvt;
5067 aMenuEvt.mnId = nId;
5068 WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( pFrame->mSelectedhMenu, nId, false );
5069 if( pSalMenuItem )
5070 aMenuEvt.mpMenu = pSalMenuItem->mpMenu;
5071 else
5072 aMenuEvt.mpMenu = nullptr;
5074 nRet = pFrame->CallCallback( SalEvent::MenuCommand, &aMenuEvt );
5077 return nRet;
5080 static bool ImplHandleSysCommand( HWND hWnd, WPARAM wParam, LPARAM lParam )
5082 WinSalFrame* pFrame = GetWindowPtr( hWnd );
5083 if ( !pFrame )
5084 return false;
5086 WPARAM nCommand = wParam & 0xFFF0;
5088 if (pFrame->isFullScreen())
5090 bool bMaximize = IsZoomed( pFrame->mhWnd );
5091 bool bMinimize = IsIconic( pFrame->mhWnd );
5092 if ( (nCommand == SC_SIZE) ||
5093 (!bMinimize && (nCommand == SC_MOVE)) ||
5094 (!bMaximize && (nCommand == SC_MAXIMIZE)) ||
5095 (bMaximize && (nCommand == SC_RESTORE)) )
5097 return true;
5101 if ( nCommand == SC_MOVE )
5103 WinSalTimer* pTimer = static_cast<WinSalTimer*>( ImplGetSVData()->maSchedCtx.mpSalTimer );
5104 if ( pTimer )
5105 pTimer->SetForceRealTimer( true );
5108 if ( nCommand == SC_KEYMENU )
5110 // do not process SC_KEYMENU if we have a native menu
5111 // Windows should handle this
5112 if( GetMenu( hWnd ) )
5113 return false;
5115 // Process here KeyMenu events only for Alt to activate the MenuBar,
5116 // or if a SysChild window is in focus, as Alt-key-combinations are
5117 // only processed via this event
5118 if ( !LOWORD( lParam ) )
5120 // Only trigger if no other key is pressed.
5121 // Contrary to Docu the CharCode is delivered with the x-coordinate
5122 // that is pressed in addition.
5123 // Also 32 for space, 99 for c, 100 for d, ...
5124 // As this is not documented, we check the state of the space-bar
5125 if ( GetKeyState( VK_SPACE ) & 0x8000 )
5126 return false;
5128 // to avoid activating the MenuBar for Alt+MouseKey
5129 if ( (GetKeyState( VK_LBUTTON ) & 0x8000) ||
5130 (GetKeyState( VK_RBUTTON ) & 0x8000) ||
5131 (GetKeyState( VK_MBUTTON ) & 0x8000) ||
5132 (GetKeyState( VK_SHIFT ) & 0x8000) )
5133 return true;
5135 SalKeyEvent aKeyEvt;
5136 aKeyEvt.mnCode = KEY_MENU;
5137 aKeyEvt.mnCharCode = 0;
5138 aKeyEvt.mnRepeat = 0;
5139 bool nRet = pFrame->CallCallback( SalEvent::KeyInput, &aKeyEvt );
5140 pFrame->CallCallback( SalEvent::KeyUp, &aKeyEvt );
5141 return nRet;
5143 else
5145 // check if a SysChild is in focus
5146 HWND hFocusWnd = ::GetFocus();
5147 if ( hFocusWnd && ImplFindSalObject( hFocusWnd ) )
5149 char cKeyCode = static_cast<char>(static_cast<unsigned char>(LOWORD( lParam )));
5150 // LowerCase
5151 if ( (cKeyCode >= 65) && (cKeyCode <= 90) )
5152 cKeyCode += 32;
5153 // We only accept 0-9 and A-Z; all other keys have to be
5154 // processed by the SalObj hook
5155 if ( ((cKeyCode >= 48) && (cKeyCode <= 57)) ||
5156 ((cKeyCode >= 97) && (cKeyCode <= 122)) )
5158 sal_uInt16 nModCode = 0;
5159 if ( GetKeyState( VK_SHIFT ) & 0x8000 )
5160 nModCode |= KEY_SHIFT;
5161 if ( GetKeyState( VK_CONTROL ) & 0x8000 )
5162 nModCode |= KEY_MOD1;
5163 nModCode |= KEY_MOD2;
5165 SalKeyEvent aKeyEvt;
5166 if ( (cKeyCode >= 48) && (cKeyCode <= 57) )
5167 aKeyEvt.mnCode = KEY_0+(cKeyCode-48);
5168 else
5169 aKeyEvt.mnCode = KEY_A+(cKeyCode-97);
5170 aKeyEvt.mnCode |= nModCode;
5171 aKeyEvt.mnCharCode = cKeyCode;
5172 aKeyEvt.mnRepeat = 0;
5173 bool nRet = pFrame->CallCallback( SalEvent::KeyInput, &aKeyEvt );
5174 pFrame->CallCallback( SalEvent::KeyUp, &aKeyEvt );
5175 return nRet;
5181 return false;
5184 static void ImplHandleInputLangChange( HWND hWnd, WPARAM, LPARAM lParam )
5186 ImplSalYieldMutexAcquireWithWait();
5188 // check if we support IME
5189 WinSalFrame* pFrame = GetWindowPtr( hWnd );
5191 if ( !pFrame )
5192 return;
5194 if ( pFrame->mbIME && pFrame->mhDefIMEContext )
5196 HKL hKL = reinterpret_cast<HKL>(lParam);
5197 UINT nImeProps = ImmGetProperty( hKL, IGP_PROPERTY );
5199 pFrame->mbSpezIME = (nImeProps & IME_PROP_SPECIAL_UI) != 0;
5200 pFrame->mbAtCursorIME = (nImeProps & IME_PROP_AT_CARET) != 0;
5201 pFrame->mbHandleIME = !pFrame->mbSpezIME;
5204 // trigger input language and codepage update
5205 UINT nLang = pFrame->mnInputLang;
5206 ImplUpdateInputLang( pFrame );
5208 // notify change
5209 if( nLang != pFrame->mnInputLang )
5210 pFrame->CallCallback( SalEvent::InputLanguageChange, nullptr );
5212 // reinit spec. keys
5213 GetSalData()->initKeyCodeMap();
5215 ImplSalYieldMutexRelease();
5218 static void ImplUpdateIMECursorPos( WinSalFrame* pFrame, HIMC hIMC )
5220 COMPOSITIONFORM aForm = {};
5222 // get cursor position and from it calculate default position
5223 // for the composition window
5224 SalExtTextInputPosEvent aPosEvt;
5225 pFrame->CallCallback( SalEvent::ExtTextInputPos, &aPosEvt );
5226 if ( (aPosEvt.mnX == -1) && (aPosEvt.mnY == -1) )
5227 aForm.dwStyle |= CFS_DEFAULT;
5228 else
5230 aForm.dwStyle |= CFS_POINT;
5231 aForm.ptCurrentPos.x = aPosEvt.mnX;
5232 aForm.ptCurrentPos.y = aPosEvt.mnY;
5234 ImmSetCompositionWindow( hIMC, &aForm );
5236 // Because not all IME's use this values, we create
5237 // a Windows caret to force the Position from the IME
5238 if ( GetFocus() == pFrame->mhWnd )
5240 CreateCaret( pFrame->mhWnd, nullptr,
5241 aPosEvt.mnWidth, aPosEvt.mnHeight );
5242 SetCaretPos( aPosEvt.mnX, aPosEvt.mnY );
5246 static bool ImplHandleIMEStartComposition( HWND hWnd )
5248 bool bDef = true;
5250 ImplSalYieldMutexAcquireWithWait();
5252 WinSalFrame* pFrame = GetWindowPtr( hWnd );
5253 if ( pFrame )
5255 HIMC hIMC = ImmGetContext( hWnd );
5256 if ( hIMC )
5258 ImplUpdateIMECursorPos( pFrame, hIMC );
5259 ImmReleaseContext( hWnd, hIMC );
5262 if ( pFrame->mbHandleIME )
5264 if ( pFrame->mbAtCursorIME )
5265 bDef = false;
5269 ImplSalYieldMutexRelease();
5271 return bDef;
5274 static bool ImplHandleIMECompositionInput( WinSalFrame* pFrame,
5275 HIMC hIMC, LPARAM lParam )
5277 bool bDef = true;
5279 // Init Event
5280 SalExtTextInputEvent aEvt;
5281 aEvt.mpTextAttr = nullptr;
5282 aEvt.mnCursorPos = 0;
5283 aEvt.mnCursorFlags = 0;
5285 // If we get a result string, then we handle this input
5286 if ( lParam & GCS_RESULTSTR )
5288 bDef = false;
5290 LONG nTextLen = ImmGetCompositionStringW( hIMC, GCS_RESULTSTR, nullptr, 0 ) / sizeof( WCHAR );
5291 if ( nTextLen >= 0 )
5293 auto pTextBuf = std::make_unique<WCHAR[]>(nTextLen);
5294 ImmGetCompositionStringW( hIMC, GCS_RESULTSTR, pTextBuf.get(), nTextLen*sizeof( WCHAR ) );
5295 aEvt.maText = OUString( o3tl::toU(pTextBuf.get()), static_cast<sal_Int32>(nTextLen) );
5298 aEvt.mnCursorPos = aEvt.maText.getLength();
5299 pFrame->CallCallback( SalEvent::ExtTextInput, &aEvt );
5300 pFrame->CallCallback( SalEvent::EndExtTextInput, nullptr );
5301 ImplUpdateIMECursorPos( pFrame, hIMC );
5304 // If the IME doesn't support OnSpot input, then there is nothing to do
5305 if ( !pFrame->mbAtCursorIME )
5306 return !bDef;
5308 // If we get new Composition data, then we handle this new input
5309 if ( (lParam & (GCS_COMPSTR | GCS_COMPATTR)) ||
5310 ((lParam & GCS_CURSORPOS) && !(lParam & GCS_RESULTSTR)) )
5312 bDef = false;
5314 std::unique_ptr<ExtTextInputAttr[]> pSalAttrAry;
5315 LONG nTextLen = ImmGetCompositionStringW( hIMC, GCS_COMPSTR, nullptr, 0 ) / sizeof( WCHAR );
5316 if ( nTextLen > 0 )
5319 auto pTextBuf = std::make_unique<WCHAR[]>(nTextLen);
5320 ImmGetCompositionStringW( hIMC, GCS_COMPSTR, pTextBuf.get(), nTextLen*sizeof( WCHAR ) );
5321 aEvt.maText = OUString( o3tl::toU(pTextBuf.get()), static_cast<sal_Int32>(nTextLen) );
5324 std::unique_ptr<BYTE[]> pAttrBuf;
5325 LONG nAttrLen = ImmGetCompositionStringW( hIMC, GCS_COMPATTR, nullptr, 0 );
5326 if ( nAttrLen > 0 )
5328 pAttrBuf.reset(new BYTE[nAttrLen]);
5329 ImmGetCompositionStringW( hIMC, GCS_COMPATTR, pAttrBuf.get(), nAttrLen );
5332 if ( pAttrBuf )
5334 sal_Int32 nTextLen2 = aEvt.maText.getLength();
5335 pSalAttrAry.reset(new ExtTextInputAttr[nTextLen2]);
5336 memset( pSalAttrAry.get(), 0, nTextLen2*sizeof( sal_uInt16 ) );
5337 for( sal_Int32 i = 0; (i < nTextLen2) && (i < nAttrLen); i++ )
5339 BYTE nWinAttr = pAttrBuf.get()[i];
5340 ExtTextInputAttr nSalAttr;
5341 if ( nWinAttr == ATTR_TARGET_CONVERTED )
5343 nSalAttr = ExtTextInputAttr::BoldUnderline;
5344 aEvt.mnCursorFlags |= EXTTEXTINPUT_CURSOR_INVISIBLE;
5346 else if ( nWinAttr == ATTR_CONVERTED )
5347 nSalAttr = ExtTextInputAttr::DashDotUnderline;
5348 else if ( nWinAttr == ATTR_TARGET_NOTCONVERTED )
5349 nSalAttr = ExtTextInputAttr::Highlight;
5350 else if ( nWinAttr == ATTR_INPUT_ERROR )
5351 nSalAttr = ExtTextInputAttr::RedText | ExtTextInputAttr::DottedUnderline;
5352 else /* ( nWinAttr == ATTR_INPUT ) */
5353 nSalAttr = ExtTextInputAttr::DottedUnderline;
5354 pSalAttrAry[i] = nSalAttr;
5357 aEvt.mpTextAttr = pSalAttrAry.get();
5361 // Only when we get new composition data, we must send this event
5362 if ( (nTextLen > 0) || !(lParam & GCS_RESULTSTR) )
5364 // End the mode, if the last character is deleted
5365 if ( !nTextLen )
5367 pFrame->CallCallback( SalEvent::ExtTextInput, &aEvt );
5368 pFrame->CallCallback( SalEvent::EndExtTextInput, nullptr );
5370 else
5372 // Because Cursor-Position and DeltaStart never updated
5373 // from the korean input engine, we must handle this here
5374 if ( lParam & CS_INSERTCHAR )
5376 aEvt.mnCursorPos = nTextLen;
5377 if ( aEvt.mnCursorPos && (lParam & CS_NOMOVECARET) )
5378 aEvt.mnCursorPos--;
5380 else
5381 aEvt.mnCursorPos = LOWORD( ImmGetCompositionStringW( hIMC, GCS_CURSORPOS, nullptr, 0 ) );
5383 if ( pFrame->mbCandidateMode )
5384 aEvt.mnCursorFlags |= EXTTEXTINPUT_CURSOR_INVISIBLE;
5385 if ( lParam & CS_NOMOVECARET )
5386 aEvt.mnCursorFlags |= EXTTEXTINPUT_CURSOR_OVERWRITE;
5388 pFrame->CallCallback( SalEvent::ExtTextInput, &aEvt );
5390 ImplUpdateIMECursorPos( pFrame, hIMC );
5394 return !bDef;
5397 static bool ImplHandleIMEComposition( HWND hWnd, LPARAM lParam )
5399 bool bDef = true;
5400 ImplSalYieldMutexAcquireWithWait();
5402 WinSalFrame* pFrame = GetWindowPtr( hWnd );
5403 if ( pFrame && (!lParam || (lParam & GCS_RESULTSTR)) )
5405 // reset the background mode for each text input,
5406 // as some tools such as RichWin may have changed it
5407 if ( pFrame->mpLocalGraphics &&
5408 pFrame->mpLocalGraphics->getHDC() )
5409 SetBkMode( pFrame->mpLocalGraphics->getHDC(), TRANSPARENT );
5412 if ( pFrame && pFrame->mbHandleIME )
5414 if ( !lParam )
5416 SalExtTextInputEvent aEvt;
5417 aEvt.mpTextAttr = nullptr;
5418 aEvt.mnCursorPos = 0;
5419 aEvt.mnCursorFlags = 0;
5420 pFrame->CallCallback( SalEvent::ExtTextInput, &aEvt );
5421 pFrame->CallCallback( SalEvent::EndExtTextInput, nullptr );
5423 else if ( lParam & (GCS_RESULTSTR | GCS_COMPSTR | GCS_COMPATTR | GCS_CURSORPOS) )
5425 HIMC hIMC = ImmGetContext( hWnd );
5426 if ( hIMC )
5428 if ( ImplHandleIMECompositionInput( pFrame, hIMC, lParam ) )
5429 bDef = false;
5431 ImmReleaseContext( hWnd, hIMC );
5436 ImplSalYieldMutexRelease();
5437 return bDef;
5440 static bool ImplHandleIMEEndComposition( HWND hWnd )
5442 bool bDef = true;
5444 ImplSalYieldMutexAcquireWithWait();
5446 WinSalFrame* pFrame = GetWindowPtr( hWnd );
5447 if ( pFrame && pFrame->mbHandleIME )
5449 if ( pFrame->mbAtCursorIME )
5451 pFrame->mbCandidateMode = false;
5452 bDef = false;
5456 ImplSalYieldMutexRelease();
5458 return bDef;
5461 static bool ImplHandleAppCommand( HWND hWnd, LPARAM lParam, LRESULT & nRet )
5463 MediaCommand nCommand;
5464 switch( GET_APPCOMMAND_LPARAM(lParam) )
5466 case APPCOMMAND_MEDIA_CHANNEL_DOWN: nCommand = MediaCommand::ChannelDown; break;
5467 case APPCOMMAND_MEDIA_CHANNEL_UP: nCommand = MediaCommand::ChannelUp; break;
5468 case APPCOMMAND_MEDIA_NEXTTRACK: nCommand = MediaCommand::NextTrack; break;
5469 case APPCOMMAND_MEDIA_PAUSE: nCommand = MediaCommand::Pause; break;
5470 case APPCOMMAND_MEDIA_PLAY: nCommand = MediaCommand::Play; break;
5471 case APPCOMMAND_MEDIA_PLAY_PAUSE: nCommand = MediaCommand::PlayPause; break;
5472 case APPCOMMAND_MEDIA_PREVIOUSTRACK: nCommand = MediaCommand::PreviousTrack; break;
5473 case APPCOMMAND_MEDIA_RECORD: nCommand = MediaCommand::Record; break;
5474 case APPCOMMAND_MEDIA_REWIND: nCommand = MediaCommand::Rewind; break;
5475 case APPCOMMAND_MEDIA_STOP: nCommand = MediaCommand::Stop; break;
5476 case APPCOMMAND_MIC_ON_OFF_TOGGLE: nCommand = MediaCommand::MicOnOffToggle; break;
5477 case APPCOMMAND_MICROPHONE_VOLUME_DOWN: nCommand = MediaCommand::MicrophoneVolumeDown; break;
5478 case APPCOMMAND_MICROPHONE_VOLUME_MUTE: nCommand = MediaCommand::MicrophoneVolumeMute; break;
5479 case APPCOMMAND_MICROPHONE_VOLUME_UP: nCommand = MediaCommand::MicrophoneVolumeUp; break;
5480 case APPCOMMAND_VOLUME_DOWN: nCommand = MediaCommand::VolumeDown; break;
5481 case APPCOMMAND_VOLUME_MUTE: nCommand = MediaCommand::VolumeMute; break;
5482 case APPCOMMAND_VOLUME_UP: nCommand = MediaCommand::VolumeUp; break;
5483 default:
5484 return false;
5487 WinSalFrame* pFrame = GetWindowPtr( hWnd );
5488 vcl::Window *pWindow = pFrame ? pFrame->GetWindow() : nullptr;
5490 if( pWindow )
5492 const Point aPoint;
5493 CommandMediaData aMediaData(nCommand);
5494 CommandEvent aCEvt( aPoint, CommandEventId::Media, false, &aMediaData );
5495 NotifyEvent aNCmdEvt( NotifyEventType::COMMAND, pWindow, &aCEvt );
5497 if ( !ImplCallPreNotify( aNCmdEvt ) )
5499 pWindow->Command( aCEvt );
5500 nRet = 1;
5501 return !aMediaData.GetPassThroughToOS();
5505 return false;
5508 static void ImplHandleIMENotify( HWND hWnd, WPARAM wParam )
5510 if ( wParam == WPARAM(IMN_OPENCANDIDATE) )
5512 ImplSalYieldMutexAcquireWithWait();
5514 WinSalFrame* pFrame = GetWindowPtr( hWnd );
5515 if ( pFrame && pFrame->mbHandleIME &&
5516 pFrame->mbAtCursorIME )
5518 // we want to hide the cursor
5519 pFrame->mbCandidateMode = true;
5520 ImplHandleIMEComposition( hWnd, GCS_CURSORPOS );
5522 HWND hWnd2 = pFrame->mhWnd;
5523 HIMC hIMC = ImmGetContext( hWnd2 );
5524 if ( hIMC )
5526 LONG nBufLen = ImmGetCompositionStringW( hIMC, GCS_COMPSTR, nullptr, 0 );
5527 if ( nBufLen >= 1 )
5529 SalExtTextInputPosEvent aPosEvt;
5530 pFrame->CallCallback( SalEvent::ExtTextInputPos, &aPosEvt );
5532 // Vertical !!!
5533 CANDIDATEFORM aForm;
5534 aForm.dwIndex = 0;
5535 aForm.dwStyle = CFS_EXCLUDE;
5536 aForm.ptCurrentPos.x = aPosEvt.mnX;
5537 aForm.ptCurrentPos.y = aPosEvt.mnY+1;
5538 aForm.rcArea.left = aPosEvt.mnX;
5539 aForm.rcArea.top = aPosEvt.mnY;
5540 aForm.rcArea.right = aForm.rcArea.left+aPosEvt.mnExtWidth+1;
5541 aForm.rcArea.bottom = aForm.rcArea.top+aPosEvt.mnHeight+1;
5542 ImmSetCandidateWindow( hIMC, &aForm );
5545 ImmReleaseContext( hWnd2, hIMC );
5549 ImplSalYieldMutexRelease();
5551 else if ( wParam == WPARAM(IMN_CLOSECANDIDATE) )
5553 ImplSalYieldMutexAcquireWithWait();
5554 WinSalFrame* pFrame = GetWindowPtr( hWnd );
5555 if ( pFrame )
5556 pFrame->mbCandidateMode = false;
5557 ImplSalYieldMutexRelease();
5561 static bool
5562 ImplHandleGetObject(HWND hWnd, LPARAM lParam, WPARAM wParam, LRESULT & nRet)
5564 uno::Reference<accessibility::XMSAAService> xMSAA;
5565 if (ImplSalYieldMutexTryToAcquire())
5567 if (!Application::GetSettings().GetMiscSettings().GetEnableATToolSupport())
5569 // IA2 should be enabled automatically
5570 AllSettings aSettings = Application::GetSettings();
5571 MiscSettings aMisc = aSettings.GetMiscSettings();
5572 aMisc.SetEnableATToolSupport(true);
5573 // The above is enough, since aMisc changes the same shared ImplMiscData as used in global
5574 // settings, so no need to call aSettings.SetMiscSettings and Application::SetSettings
5576 if (!Application::GetSettings().GetMiscSettings().GetEnableATToolSupport())
5577 return false; // locked down somehow ?
5580 ImplSVData* pSVData = ImplGetSVData();
5582 // Make sure to launch Accessibility only the following criteria are satisfied
5583 // to avoid RFT interrupts regular accessibility processing
5584 if ( !pSVData->mxAccessBridge.is() )
5586 if( !InitAccessBridge() )
5587 return false;
5589 xMSAA.set(pSVData->mxAccessBridge, uno::UNO_QUERY);
5590 ImplSalYieldMutexRelease();
5592 else
5593 { // tdf#155794: access without locking: hopefully this should be fine
5594 // as the bridge is typically inited in Desktop::Main() already and the
5595 // WM_GETOBJECT is received only on the main thread and by the time in
5596 // VCL shutdown when ImplSvData dies there should not be Windows any
5597 // more that could receive messages.
5598 xMSAA.set(ImplGetSVData()->mxAccessBridge, uno::UNO_QUERY);
5601 if ( xMSAA.is() )
5603 sal_Int32 lParam32 = static_cast<sal_Int32>(lParam);
5604 sal_uInt32 wParam32 = static_cast<sal_uInt32>(wParam);
5606 // mhOnSetTitleWnd not set to reasonable value anywhere...
5607 if ( lParam32 == OBJID_CLIENT )
5609 nRet = xMSAA->getAccObjectPtr(
5610 reinterpret_cast<sal_Int64>(hWnd), lParam32, wParam32);
5611 if (nRet != 0)
5612 return true;
5615 return false;
5618 static LRESULT ImplHandleIMEReconvertString( HWND hWnd, LPARAM lParam )
5620 WinSalFrame* pFrame = GetWindowPtr( hWnd );
5621 LPRECONVERTSTRING pReconvertString = reinterpret_cast<LPRECONVERTSTRING>(lParam);
5622 LRESULT nRet = 0;
5623 SalSurroundingTextRequestEvent aEvt;
5624 aEvt.maText.clear();
5625 aEvt.mnStart = aEvt.mnEnd = 0;
5627 UINT nImeProps = ImmGetProperty( GetKeyboardLayout( 0 ), IGP_SETCOMPSTR );
5628 if( (nImeProps & SCS_CAP_SETRECONVERTSTRING) == 0 )
5630 // This IME does not support reconversion.
5631 return 0;
5634 if( !pReconvertString )
5636 // The first call for reconversion.
5637 pFrame->CallCallback( SalEvent::StartReconversion, nullptr );
5639 // Retrieve the surrounding text from the focused control.
5640 pFrame->CallCallback( SalEvent::SurroundingTextRequest, &aEvt );
5642 if( aEvt.maText.isEmpty())
5644 return 0;
5647 nRet = sizeof(RECONVERTSTRING) + (aEvt.maText.getLength() + 1) * sizeof(WCHAR);
5649 else
5651 // The second call for reconversion.
5653 // Retrieve the surrounding text from the focused control.
5654 pFrame->CallCallback( SalEvent::SurroundingTextRequest, &aEvt );
5655 nRet = sizeof(RECONVERTSTRING) + (aEvt.maText.getLength() + 1) * sizeof(WCHAR);
5657 pReconvertString->dwStrOffset = sizeof(RECONVERTSTRING);
5658 pReconvertString->dwStrLen = aEvt.maText.getLength();
5659 pReconvertString->dwCompStrOffset = aEvt.mnStart * sizeof(WCHAR);
5660 pReconvertString->dwCompStrLen = aEvt.mnEnd - aEvt.mnStart;
5661 pReconvertString->dwTargetStrOffset = pReconvertString->dwCompStrOffset;
5662 pReconvertString->dwTargetStrLen = pReconvertString->dwCompStrLen;
5664 memcpy( pReconvertString + 1, aEvt.maText.getStr(), (aEvt.maText.getLength() + 1) * sizeof(WCHAR) );
5667 // just return the required size of buffer to reconvert.
5668 return nRet;
5671 static LRESULT ImplHandleIMEConfirmReconvertString( HWND hWnd, LPARAM lParam )
5673 WinSalFrame* pFrame = GetWindowPtr( hWnd );
5674 LPRECONVERTSTRING pReconvertString = reinterpret_cast<LPRECONVERTSTRING>(lParam);
5675 SalSurroundingTextRequestEvent aEvt;
5676 aEvt.maText.clear();
5677 aEvt.mnStart = aEvt.mnEnd = 0;
5679 pFrame->CallCallback( SalEvent::SurroundingTextRequest, &aEvt );
5681 sal_uLong nTmpStart = pReconvertString->dwCompStrOffset / sizeof(WCHAR);
5682 sal_uLong nTmpEnd = nTmpStart + pReconvertString->dwCompStrLen;
5684 if( nTmpStart != aEvt.mnStart || nTmpEnd != aEvt.mnEnd )
5686 SalSurroundingTextSelectionChangeEvent aSelEvt { nTmpStart, nTmpEnd };
5687 pFrame->CallCallback( SalEvent::SurroundingTextSelectionChange, &aSelEvt );
5690 return TRUE;
5693 static LRESULT ImplHandleIMEQueryCharPosition( HWND hWnd, LPARAM lParam ) {
5694 WinSalFrame* pFrame = GetWindowPtr( hWnd );
5695 PIMECHARPOSITION pQueryCharPosition = reinterpret_cast<PIMECHARPOSITION>(lParam);
5696 if ( pQueryCharPosition->dwSize < sizeof(IMECHARPOSITION) )
5697 return FALSE;
5699 SalQueryCharPositionEvent aEvt;
5700 aEvt.mbValid = false;
5701 aEvt.mnCharPos = pQueryCharPosition->dwCharPos;
5703 pFrame->CallCallback( SalEvent::QueryCharPosition, &aEvt );
5705 if ( !aEvt.mbValid )
5706 return FALSE;
5708 if ( aEvt.mbVertical )
5710 // For vertical writing, the base line is left edge of the rectangle
5711 // and the target position is top-right corner.
5712 pQueryCharPosition->pt.x = aEvt.maCursorBound.getX() + aEvt.maCursorBound.GetWidth();
5713 pQueryCharPosition->pt.y = aEvt.maCursorBound.getY();
5714 pQueryCharPosition->cLineHeight = aEvt.maCursorBound.GetWidth();
5716 else
5718 // For horizontal writing, the base line is the bottom edge of the rectangle.
5719 // and the target position is top-left corner.
5720 pQueryCharPosition->pt.x = aEvt.maCursorBound.getX();
5721 pQueryCharPosition->pt.y = aEvt.maCursorBound.getY();
5722 pQueryCharPosition->cLineHeight = aEvt.maCursorBound.GetHeight();
5725 // Currently not supported but many IMEs usually ignore them.
5726 pQueryCharPosition->rcDocument.left = 0;
5727 pQueryCharPosition->rcDocument.top = 0;
5728 pQueryCharPosition->rcDocument.right = 0;
5729 pQueryCharPosition->rcDocument.bottom = 0;
5731 return TRUE;
5734 void SalTestMouseLeave()
5736 SalData* pSalData = GetSalData();
5738 if ( pSalData->mhWantLeaveMsg && !::GetCapture() )
5740 POINT aPt;
5741 GetCursorPos( &aPt );
5743 // a one item cache, because this function is sometimes hot - if the cursor has not moved, then
5744 // no need to call WindowFromPoint
5745 static POINT cachedPoint;
5746 if (cachedPoint.x == aPt.x && cachedPoint.y == aPt.y)
5747 return;
5748 cachedPoint = aPt;
5750 if ( pSalData->mhWantLeaveMsg != WindowFromPoint( aPt ) )
5751 SendMessageW( pSalData->mhWantLeaveMsg, SAL_MSG_MOUSELEAVE, 0, MAKELPARAM( aPt.x, aPt.y ) );
5755 static bool ImplSalWheelMousePos( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ,
5756 LRESULT& rResult )
5758 POINT aPt;
5759 POINT aScreenPt;
5760 aScreenPt.x = static_cast<short>(LOWORD( lParam ));
5761 aScreenPt.y = static_cast<short>(HIWORD( lParam ));
5762 // find child window that is at this position
5763 HWND hChildWnd;
5764 HWND hWheelWnd = hWnd;
5767 hChildWnd = hWheelWnd;
5768 aPt = aScreenPt;
5769 ScreenToClient( hChildWnd, &aPt );
5770 hWheelWnd = ChildWindowFromPointEx( hChildWnd, aPt, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT );
5772 while ( hWheelWnd && (hWheelWnd != hChildWnd) );
5773 if ( hWheelWnd && (hWheelWnd != hWnd) &&
5774 (hWheelWnd != ::GetFocus()) && IsWindowEnabled( hWheelWnd ) )
5776 rResult = SendMessageW( hWheelWnd, nMsg, wParam, lParam );
5777 return false;
5780 return true;
5783 static LRESULT CALLBACK SalFrameWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, bool& rDef )
5785 LRESULT nRet = 0;
5786 static bool bInWheelMsg = false;
5787 static bool bInQueryEnd = false;
5789 SAL_INFO("vcl.gdi.wndproc", "SalFrameWndProc(nMsg=" << nMsg << ", wParam=" << wParam << ", lParam=" << lParam << ")");
5791 // By WM_CREATE we connect the frame with the window handle
5792 if ( nMsg == WM_CREATE )
5794 // Save Window-Instance in Windowhandle
5795 // Can also be used for the A-Version, because the struct
5796 // to access lpCreateParams is the same structure
5797 CREATESTRUCTW* pStruct = reinterpret_cast<CREATESTRUCTW*>(lParam);
5798 WinSalFrame* pFrame = static_cast<WinSalFrame*>(pStruct->lpCreateParams);
5799 if ( pFrame != nullptr )
5801 SetWindowPtr( hWnd, pFrame );
5803 UpdateDarkMode(hWnd);
5805 // Set HWND already here, as data might be used already
5806 // when messages are being sent by CreateWindow()
5807 pFrame->mhWnd = hWnd;
5808 pFrame->maSysData.hWnd = hWnd;
5810 return 0;
5813 ImplSVData* pSVData = ImplGetSVData();
5814 // #i72707# TODO: the mbDeInit check will not be needed
5815 // once all windows that are not properly closed on exit got fixed
5816 if( pSVData->mbDeInit )
5817 return 0;
5819 if ( WM_USER_SYSTEM_WINDOW_ACTIVATED == nMsg )
5821 ImplHideSplash();
5822 return 0;
5825 switch( nMsg )
5827 case WM_MOUSEMOVE:
5828 case WM_LBUTTONDOWN:
5829 case WM_MBUTTONDOWN:
5830 case WM_RBUTTONDOWN:
5831 case WM_LBUTTONUP:
5832 case WM_MBUTTONUP:
5833 case WM_RBUTTONUP:
5834 case WM_NCMOUSEMOVE:
5835 case SAL_MSG_MOUSELEAVE:
5836 ImplSalYieldMutexAcquireWithWait();
5837 rDef = !ImplHandleMouseMsg( hWnd, nMsg, wParam, lParam );
5838 ImplSalYieldMutexRelease();
5839 break;
5841 case WM_NCLBUTTONDOWN:
5842 case WM_NCMBUTTONDOWN:
5843 case WM_NCRBUTTONDOWN:
5844 ImplSalYieldMutexAcquireWithWait();
5845 ImplCallClosePopupsHdl( hWnd ); // close popups...
5846 ImplSalYieldMutexRelease();
5847 break;
5849 case WM_MOUSEACTIVATE:
5850 if ( LOWORD( lParam ) == HTCLIENT )
5852 ImplSalYieldMutexAcquireWithWait();
5853 nRet = LRESULT(ImplHandleMouseActivateMsg( hWnd ));
5854 ImplSalYieldMutexRelease();
5855 if ( nRet )
5857 nRet = MA_NOACTIVATE;
5858 rDef = false;
5861 break;
5863 case WM_KEYDOWN:
5864 case WM_KEYUP:
5865 case WM_DEADCHAR:
5866 case WM_CHAR:
5867 case WM_UNICHAR: // MCD, 2003-01-13, Support for WM_UNICHAR & Keyman 6.0
5868 case WM_SYSKEYDOWN:
5869 case WM_SYSKEYUP:
5870 case WM_SYSCHAR:
5871 ImplSalYieldMutexAcquireWithWait();
5872 rDef = !ImplHandleKeyMsg( hWnd, nMsg, wParam, lParam, nRet );
5873 ImplSalYieldMutexRelease();
5874 break;
5876 case WM_MOUSEWHEEL:
5877 case WM_MOUSEHWHEEL:
5878 // protect against recursion, in case the message is returned
5879 // by IE or the external window
5880 if ( !bInWheelMsg )
5882 bInWheelMsg = true;
5883 rDef = !ImplHandleWheelMsg( hWnd, nMsg, wParam, lParam );
5884 // If we did not process the message, re-check if here is a
5885 // connected (?) window that we have to notify.
5886 if ( rDef )
5887 rDef = ImplSalWheelMousePos( hWnd, nMsg, wParam, lParam, nRet );
5888 bInWheelMsg = false;
5890 break;
5892 case WM_COMMAND:
5893 ImplSalYieldMutexAcquireWithWait();
5894 rDef = !ImplHandleCommand( hWnd, wParam, lParam );
5895 ImplSalYieldMutexRelease();
5896 break;
5898 case WM_INITMENUPOPUP:
5899 ImplSalYieldMutexAcquireWithWait();
5900 rDef = !ImplHandleMenuActivate( hWnd, wParam, lParam );
5901 ImplSalYieldMutexRelease();
5902 break;
5904 case WM_MENUSELECT:
5905 ImplSalYieldMutexAcquireWithWait();
5906 rDef = !ImplHandleMenuSelect( hWnd, wParam, lParam );
5907 ImplSalYieldMutexRelease();
5908 break;
5910 case WM_SYSCOMMAND:
5911 ImplSalYieldMutexAcquireWithWait();
5912 nRet = LRESULT(ImplHandleSysCommand( hWnd, wParam, lParam ));
5913 ImplSalYieldMutexRelease();
5914 if ( nRet )
5915 rDef = false;
5916 break;
5918 case WM_MENUCHAR:
5919 nRet = ImplMenuChar( hWnd, wParam, lParam );
5920 if( nRet )
5921 rDef = false;
5922 break;
5924 case WM_MEASUREITEM:
5925 nRet = ImplMeasureItem(hWnd, wParam, lParam);
5926 if( nRet )
5927 rDef = false;
5928 break;
5930 case WM_DRAWITEM:
5931 nRet = ImplDrawItem(hWnd, wParam, lParam);
5932 if( nRet )
5933 rDef = false;
5934 break;
5936 case WM_MOVE:
5937 ImplHandleMoveMsg(hWnd, lParam);
5938 rDef = false;
5939 break;
5940 case SAL_MSG_POSTMOVE:
5941 ImplCallMoveHdl(hWnd);
5942 rDef = false;
5943 break;
5944 case WM_SIZE:
5945 ImplHandleSizeMsg(hWnd, wParam, lParam);
5946 rDef = false;
5947 break;
5948 case SAL_MSG_POSTCALLSIZE:
5949 ImplCallSizeHdl( hWnd );
5950 rDef = false;
5951 break;
5953 case WM_GETMINMAXINFO:
5954 if ( ImplHandleMinMax( hWnd, lParam ) )
5955 rDef = false;
5956 break;
5958 case WM_ERASEBKGND:
5959 nRet = 1;
5960 rDef = false;
5961 break;
5962 case WM_PAINT:
5963 ImplHandlePaintMsg( hWnd );
5964 rDef = false;
5965 break;
5966 case SAL_MSG_POSTPAINT:
5967 ImplHandlePostPaintMsg( hWnd, reinterpret_cast<RECT*>(wParam) );
5968 rDef = false;
5969 break;
5971 case SAL_MSG_FORCEPALETTE:
5972 ImplHandleForcePalette( hWnd );
5973 rDef = false;
5974 break;
5976 case WM_QUERYNEWPALETTE:
5977 case SAL_MSG_POSTQUERYNEWPAL:
5978 nRet = ImplHandlePalette( true, hWnd, nMsg, wParam, lParam, rDef );
5979 break;
5981 case WM_ACTIVATE:
5982 // Getting activated, we also want to set our palette.
5983 // We do this in Activate, so that other external child windows
5984 // can overwrite our palette. Thus our palette is set only once
5985 // and not recursively, as at all other places it is set only as
5986 // the background palette.
5987 if ( LOWORD( wParam ) != WA_INACTIVE )
5988 SendMessageW( hWnd, SAL_MSG_FORCEPALETTE, 0, 0 );
5989 break;
5991 case WM_ENABLE:
5992 // #95133# a system dialog is opened/closed, using our app window as parent
5994 WinSalFrame* pFrame = GetWindowPtr( hWnd );
5995 vcl::Window *pWin = nullptr;
5996 if( pFrame )
5997 pWin = pFrame->GetWindow();
5999 if( !wParam )
6001 pSVData->maAppData.mnModalMode++;
6003 ImplHideSplash();
6004 if( pWin )
6006 pWin->EnableInput( false, nullptr );
6007 pWin->IncModalCount(); // #106303# support frame based modal count
6010 else
6012 ImplGetSVData()->maAppData.mnModalMode--;
6013 if( pWin )
6015 pWin->EnableInput( true, nullptr );
6016 pWin->DecModalCount(); // #106303# support frame based modal count
6020 break;
6022 case WM_KILLFOCUS:
6023 DestroyCaret();
6024 [[fallthrough]];
6025 case WM_SETFOCUS:
6026 case SAL_MSG_POSTFOCUS:
6027 ImplHandleFocusMsg( hWnd );
6028 rDef = false;
6029 break;
6031 case WM_CLOSE:
6032 ImplHandleCloseMsg( hWnd );
6033 rDef = false;
6034 break;
6036 case WM_QUERYENDSESSION:
6037 if( !bInQueryEnd )
6039 // handle queryendsession only once
6040 bInQueryEnd = true;
6041 nRet = LRESULT(!ImplHandleShutDownMsg( hWnd ));
6042 rDef = false;
6044 // Issue #16314#: ImplHandleShutDownMsg causes a PostMessage in case of allowing shutdown.
6045 // This posted message was never processed and cause Windows XP to hang after log off
6046 // if there are multiple sessions and the current session wasn't the first one started.
6047 // So if shutdown is allowed we assume that a post message was done and retrieve all
6048 // messages in the message queue and dispatch them before we return control to the system.
6050 if ( nRet )
6052 SolarMutexGuard aGuard;
6053 while ( Application::Reschedule( true ) );
6056 else
6058 ImplSalYieldMutexAcquireWithWait();
6059 ImplSalYieldMutexRelease();
6060 rDef = true;
6062 break;
6064 case WM_ENDSESSION:
6065 if( !wParam )
6066 bInQueryEnd = false; // no shutdown: allow query again
6067 nRet = FALSE;
6068 rDef = false;
6069 break;
6071 case WM_DISPLAYCHANGE:
6072 case WM_SETTINGCHANGE:
6073 case WM_DEVMODECHANGE:
6074 case WM_FONTCHANGE:
6075 case WM_SYSCOLORCHANGE:
6076 case WM_TIMECHANGE:
6077 ImplHandleSettingsChangeMsg( hWnd, nMsg, wParam, lParam );
6078 break;
6080 case WM_THEMECHANGED:
6081 GetSalData()->mbThemeChanged = true;
6082 break;
6084 case SAL_MSG_USEREVENT:
6085 ImplHandleUserEvent( hWnd, lParam );
6086 rDef = false;
6087 break;
6089 case SAL_MSG_CAPTUREMOUSE:
6090 SetCapture( hWnd );
6091 rDef = false;
6092 break;
6093 case SAL_MSG_RELEASEMOUSE:
6094 if ( ::GetCapture() == hWnd )
6095 ReleaseCapture();
6096 rDef = false;
6097 break;
6098 case SAL_MSG_TOTOP:
6099 ImplSalToTop( hWnd, static_cast<SalFrameToTop>(wParam) );
6100 rDef = false;
6101 break;
6102 case SAL_MSG_SHOW:
6103 ImplSalShow( hWnd, static_cast<bool>(wParam), static_cast<bool>(lParam) );
6104 rDef = false;
6105 break;
6106 case SAL_MSG_SETINPUTCONTEXT:
6107 ImplSalFrameSetInputContext( hWnd, reinterpret_cast<const SalInputContext*>(lParam) );
6108 rDef = false;
6109 break;
6110 case SAL_MSG_ENDEXTTEXTINPUT:
6111 ImplSalFrameEndExtTextInput( hWnd, static_cast<EndExtTextInputFlags>(wParam) );
6112 rDef = false;
6113 break;
6115 case WM_INPUTLANGCHANGE:
6116 ImplHandleInputLangChange( hWnd, wParam, lParam );
6117 break;
6119 case WM_IME_CHAR:
6120 // #103487#, some IMEs (eg, those that do not work onspot)
6121 // may send WM_IME_CHAR instead of WM_IME_COMPOSITION
6122 // we just handle it like a WM_CHAR message - seems to work fine
6123 ImplSalYieldMutexAcquireWithWait();
6124 rDef = !ImplHandleKeyMsg( hWnd, WM_CHAR, wParam, lParam, nRet );
6125 ImplSalYieldMutexRelease();
6126 break;
6128 case WM_IME_STARTCOMPOSITION:
6129 rDef = ImplHandleIMEStartComposition( hWnd );
6130 break;
6132 case WM_IME_COMPOSITION:
6133 rDef = ImplHandleIMEComposition( hWnd, lParam );
6134 break;
6136 case WM_IME_ENDCOMPOSITION:
6137 rDef = ImplHandleIMEEndComposition( hWnd );
6138 break;
6140 case WM_IME_NOTIFY:
6141 ImplHandleIMENotify( hWnd, wParam );
6142 break;
6144 case WM_GETOBJECT:
6145 // tdf#155794: this must complete without taking SolarMutex
6146 if ( ImplHandleGetObject( hWnd, lParam, wParam, nRet ) )
6148 rDef = false;
6150 break;
6152 case WM_APPCOMMAND:
6153 if( ImplHandleAppCommand( hWnd, lParam, nRet ) )
6155 rDef = false;
6157 break;
6158 case WM_IME_REQUEST:
6159 if ( static_cast<sal_uIntPtr>(wParam) == IMR_RECONVERTSTRING )
6161 nRet = ImplHandleIMEReconvertString( hWnd, lParam );
6162 rDef = false;
6164 else if( static_cast<sal_uIntPtr>(wParam) == IMR_CONFIRMRECONVERTSTRING )
6166 nRet = ImplHandleIMEConfirmReconvertString( hWnd, lParam );
6167 rDef = false;
6169 else if ( static_cast<sal_uIntPtr>(wParam) == IMR_QUERYCHARPOSITION )
6171 if ( ImplSalYieldMutexTryToAcquire() )
6173 nRet = ImplHandleIMEQueryCharPosition( hWnd, lParam );
6174 ImplSalYieldMutexRelease();
6176 else
6177 nRet = FALSE;
6178 rDef = false;
6180 break;
6183 return nRet;
6186 LRESULT CALLBACK SalFrameWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
6188 bool bDef = true;
6189 LRESULT nRet = 0;
6190 __try
6192 nRet = SalFrameWndProc( hWnd, nMsg, wParam, lParam, bDef );
6194 __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))
6198 if ( bDef )
6199 nRet = DefWindowProcW( hWnd, nMsg, wParam, lParam );
6200 return nRet;
6203 bool ImplHandleGlobalMsg( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, LRESULT& rlResult )
6205 // handle all messages concerning all frames so they get processed only once
6206 // Must work for Unicode and none Unicode
6207 bool bResult = false;
6208 if ( (nMsg == WM_PALETTECHANGED) || (nMsg == SAL_MSG_POSTPALCHANGED) )
6210 bResult = true;
6211 rlResult = ImplHandlePalette( false, hWnd, nMsg, wParam, lParam, bResult );
6213 else if( nMsg == WM_DISPLAYCHANGE )
6215 WinSalSystem* pSys = static_cast<WinSalSystem*>(ImplGetSalSystem());
6216 if( pSys )
6217 pSys->clearMonitors();
6218 bResult = (pSys != nullptr);
6220 return bResult;
6223 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */