bump product version to 6.4.0.3
[LibreOffice.git] / vcl / win / window / salframe.cxx
bloba57e67ce8896ab5795476ab56fec88c6e9636766
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>
24 #include <unotools/misccfg.hxx>
26 #include <officecfg/Office/Common.hxx>
28 #include <memory>
29 #include <string.h>
30 #include <limits.h>
32 #include <svsys.h>
34 #include <comphelper/windowserrorstring.hxx>
36 #include <rtl/string.h>
37 #include <rtl/ustring.h>
38 #include <sal/log.hxx>
40 #include <osl/module.h>
42 #include <tools/debug.hxx>
43 #include <o3tl/enumarray.hxx>
44 #include <o3tl/char16_t2wchar_t.hxx>
46 #include <vcl/event.hxx>
47 #include <vcl/sysdata.hxx>
48 #include <vcl/timer.hxx>
49 #include <vcl/settings.hxx>
50 #include <vcl/keycodes.hxx>
51 #include <vcl/window.hxx>
52 #include <vcl/wrkwin.hxx>
53 #include <vcl/svapp.hxx>
54 #include <vcl/ptrstyle.hxx>
56 #include <win/wincomp.hxx>
57 #include <win/salids.hrc>
58 #include <win/saldata.hxx>
59 #include <win/salinst.h>
60 #include <win/salbmp.h>
61 #include <win/salgdi.h>
62 #include <win/salsys.h>
63 #include <win/salframe.h>
64 #include <win/salvd.h>
65 #include <win/salmenu.h>
66 #include <win/salobj.h>
67 #include <win/saltimer.h>
69 #include <helpwin.hxx>
70 #include <window.h>
71 #include <sallayout.hxx>
73 #define COMPILE_MULTIMON_STUBS
74 #pragma warning(push)
75 #pragma warning(disable:4996) // 'GetVersionExA': was declared deprecated
76 #include <multimon.h>
77 #pragma warning(pop)
78 #include <vector>
80 #include <com/sun/star/uno/Exception.hpp>
82 #include <oleacc.h>
83 #include <com/sun/star/accessibility/XMSAAService.hpp>
84 #ifndef WM_GETOBJECT // TESTME does this ever happen ?
85 # define WM_GETOBJECT 0x003D
86 #endif
88 #include <time.h>
90 #if !defined WIN32_LEAN_AND_MEAN
91 # define WIN32_LEAN_AND_MEAN
92 #endif
93 #include <windows.h>
94 #include <shobjidl.h>
95 #include <propkey.h>
96 #include <propvarutil.h>
97 #include <shellapi.h>
99 using namespace ::com::sun::star;
100 using namespace ::com::sun::star::uno;
101 using namespace ::com::sun::star::lang;
102 using namespace ::com::sun::star::container;
103 using namespace ::com::sun::star::beans;
105 #ifndef SPI_GETWHEELSCROLLCHARS
106 # define SPI_GETWHEELSCROLLCHARS 0x006C
107 #endif
108 #ifndef SPI_SETWHEELSCROLLCHARS
109 # define SPI_SETWHEELSCROLLCHARS 0x006D
110 #endif
111 #ifndef WM_MOUSEHWHEEL
112 # define WM_MOUSEHWHEEL 0x020E
113 #endif
114 #ifndef IDC_PEN
115 # define IDC_PEN MAKEINTRESOURCE(32631)
116 #endif
118 const unsigned int WM_USER_SYSTEM_WINDOW_ACTIVATED = RegisterWindowMessageW(L"SYSTEM_WINDOW_ACTIVATED");
120 bool WinSalFrame::mbInReparent = false;
122 // Macros for support of WM_UNICHAR & Keyman 6.0
123 //#define Uni_UTF32ToSurrogate1(ch) (((unsigned long) (ch) - 0x10000) / 0x400 + 0xD800)
124 #define Uni_UTF32ToSurrogate2(ch) ((static_cast<unsigned long>(ch) - 0x10000) % 0x400 + 0xDC00)
125 #define Uni_SupplementaryPlanesStart 0x10000
127 static void UpdateFrameGeometry( HWND hWnd, WinSalFrame* pFrame );
128 static void SetMaximizedFrameGeometry( HWND hWnd, WinSalFrame* pFrame, RECT* pParentRect = nullptr );
130 static void ImplSaveFrameState( WinSalFrame* pFrame )
132 // save position, size and state for GetWindowState()
133 if ( !pFrame->mbFullScreen )
135 bool bVisible = (GetWindowStyle( pFrame->mhWnd ) & WS_VISIBLE) != 0;
136 if ( IsIconic( pFrame->mhWnd ) )
138 pFrame->maState.mnState |= WindowStateState::Minimized;
139 if ( bVisible )
140 pFrame->mnShowState = SW_SHOWMAXIMIZED;
142 else if ( IsZoomed( pFrame->mhWnd ) )
144 pFrame->maState.mnState &= ~WindowStateState::Minimized;
145 pFrame->maState.mnState |= WindowStateState::Maximized;
146 if ( bVisible )
147 pFrame->mnShowState = SW_SHOWMAXIMIZED;
148 pFrame->mbRestoreMaximize = true;
150 WINDOWPLACEMENT aPlacement;
151 aPlacement.length = sizeof(aPlacement);
152 if( GetWindowPlacement( pFrame->mhWnd, &aPlacement ) )
154 RECT aRect = aPlacement.rcNormalPosition;
155 RECT aRect2 = aRect;
156 AdjustWindowRectEx( &aRect2, GetWindowStyle( pFrame->mhWnd ),
157 FALSE, GetWindowExStyle( pFrame->mhWnd ) );
158 long nTopDeco = abs( aRect.top - aRect2.top );
159 long nLeftDeco = abs( aRect.left - aRect2.left );
160 long nBottomDeco = abs( aRect.bottom - aRect2.bottom );
161 long nRightDeco = abs( aRect.right - aRect2.right );
163 pFrame->maState.mnX = aRect.left + nLeftDeco;
164 pFrame->maState.mnY = aRect.top + nTopDeco;
165 pFrame->maState.mnWidth = aRect.right - aRect.left - nLeftDeco - nRightDeco;
166 pFrame->maState.mnHeight = aRect.bottom - aRect.top - nTopDeco - nBottomDeco;
169 else
171 RECT aRect;
172 GetWindowRect( pFrame->mhWnd, &aRect );
174 // to be consistent with Unix, the frame state is without(!) decoration
175 RECT aRect2 = aRect;
176 AdjustWindowRectEx( &aRect2, GetWindowStyle( pFrame->mhWnd ),
177 FALSE, GetWindowExStyle( pFrame->mhWnd ) );
178 long nTopDeco = abs( aRect.top - aRect2.top );
179 long nLeftDeco = abs( aRect.left - aRect2.left );
180 long nBottomDeco = abs( aRect.bottom - aRect2.bottom );
181 long nRightDeco = abs( aRect.right - aRect2.right );
183 pFrame->maState.mnState &= ~WindowStateState(WindowStateState::Minimized | WindowStateState::Maximized);
184 // subtract decoration
185 pFrame->maState.mnX = aRect.left+nLeftDeco;
186 pFrame->maState.mnY = aRect.top+nTopDeco;
187 pFrame->maState.mnWidth = aRect.right-aRect.left-nLeftDeco-nRightDeco;
188 pFrame->maState.mnHeight = aRect.bottom-aRect.top-nTopDeco-nBottomDeco;
189 if ( bVisible )
190 pFrame->mnShowState = SW_SHOWNORMAL;
191 pFrame->mbRestoreMaximize = false;
196 // if pParentRect is set, the workarea of the monitor that contains pParentRect is returned
197 void ImplSalGetWorkArea( HWND hWnd, RECT *pRect, const RECT *pParentRect )
199 // check if we or our parent is fullscreen, then the taskbar should be ignored
200 bool bIgnoreTaskbar = false;
201 WinSalFrame* pFrame = GetWindowPtr( hWnd );
202 if( pFrame )
204 vcl::Window *pWin = pFrame->GetWindow();
205 while( pWin )
207 WorkWindow *pWorkWin = (pWin->GetType() == WindowType::WORKWINDOW) ? static_cast<WorkWindow *>(pWin) : nullptr;
208 if( pWorkWin && pWorkWin->ImplGetWindowImpl()->mbReallyVisible && pWorkWin->IsFullScreenMode() )
210 bIgnoreTaskbar = true;
211 break;
213 else
214 pWin = pWin->ImplGetWindowImpl()->mpParent;
218 // calculates the work area taking multiple monitors into account
219 static int nMonitors = GetSystemMetrics( SM_CMONITORS );
220 if( nMonitors == 1 )
222 if( bIgnoreTaskbar )
224 pRect->left = pRect->top = 0;
225 pRect->right = GetSystemMetrics( SM_CXSCREEN );
226 pRect->bottom = GetSystemMetrics( SM_CYSCREEN );
228 else
229 SystemParametersInfoW( SPI_GETWORKAREA, 0, pRect, 0 );
231 else
233 if( pParentRect != nullptr )
235 // return the size of the monitor where pParentRect lives
236 HMONITOR hMonitor;
237 MONITORINFO mi;
239 // get the nearest monitor to the passed rect.
240 hMonitor = MonitorFromRect(pParentRect, MONITOR_DEFAULTTONEAREST);
242 // get the work area or entire monitor rect.
243 mi.cbSize = sizeof(mi);
244 GetMonitorInfo(hMonitor, &mi);
245 if( !bIgnoreTaskbar )
246 *pRect = mi.rcWork;
247 else
248 *pRect = mi.rcMonitor;
250 else
252 // return the union of all monitors
253 pRect->left = GetSystemMetrics( SM_XVIRTUALSCREEN );
254 pRect->top = GetSystemMetrics( SM_YVIRTUALSCREEN );
255 pRect->right = pRect->left + GetSystemMetrics( SM_CXVIRTUALSCREEN );
256 pRect->bottom = pRect->top + GetSystemMetrics( SM_CYVIRTUALSCREEN );
258 // virtualscreen does not take taskbar into account, so use the corresponding
259 // diffs between screen and workarea from the default screen
260 // however, this is still not perfect: the taskbar might not be on the primary screen
261 if( !bIgnoreTaskbar )
263 RECT wRect, scrRect;
264 SystemParametersInfoW( SPI_GETWORKAREA, 0, &wRect, 0 );
265 scrRect.left = 0;
266 scrRect.top = 0;
267 scrRect.right = GetSystemMetrics( SM_CXSCREEN );
268 scrRect.bottom = GetSystemMetrics( SM_CYSCREEN );
270 pRect->left += wRect.left;
271 pRect->top += wRect.top;
272 pRect->right -= scrRect.right - wRect.right;
273 pRect->bottom -= scrRect.bottom - wRect.bottom;
279 SalFrame* ImplSalCreateFrame( WinSalInstance* pInst,
280 HWND hWndParent, SalFrameStyleFlags nSalFrameStyle )
282 WinSalFrame* pFrame = new WinSalFrame;
283 HWND hWnd;
284 DWORD nSysStyle = 0;
285 DWORD nExSysStyle = 0;
286 bool bSubFrame = false;
288 static const char* pEnvSynchronize = getenv("SAL_SYNCHRONIZE");
289 if ( pEnvSynchronize ) // no buffering of drawing commands
290 GdiSetBatchLimit( 1 );
292 static const char* pEnvTransparentFloats = getenv("SAL_TRANSPARENT_FLOATS" );
294 // determine creation data
295 if ( nSalFrameStyle & (SalFrameStyleFlags::PLUG | SalFrameStyleFlags::SYSTEMCHILD) )
297 nSysStyle |= WS_CHILD;
298 if( nSalFrameStyle & SalFrameStyleFlags::SYSTEMCHILD )
299 nSysStyle |= WS_CLIPSIBLINGS;
301 else
303 // #i87402# commenting out WS_CLIPCHILDREN
304 // this breaks SalFrameStyleFlags::SYSTEMCHILD handling, which is not
305 // used currently. Probably SalFrameStyleFlags::SYSTEMCHILD should be
306 // removed again.
308 // nSysStyle |= WS_CLIPCHILDREN;
309 if ( hWndParent )
311 nSysStyle |= WS_POPUP;
312 bSubFrame = true;
313 pFrame->mbNoIcon = true;
315 else
317 // Only with WS_OVERLAPPED we get a useful default position/size
318 if ( (nSalFrameStyle & (SalFrameStyleFlags::SIZEABLE | SalFrameStyleFlags::MOVEABLE)) ==
319 (SalFrameStyleFlags::SIZEABLE | SalFrameStyleFlags::MOVEABLE) )
320 nSysStyle |= WS_OVERLAPPED;
321 else
323 nSysStyle |= WS_POPUP;
324 if ( !(nSalFrameStyle & SalFrameStyleFlags::MOVEABLE) )
325 nExSysStyle |= WS_EX_TOOLWINDOW; // avoid taskbar appearance, for eg splash screen
329 if ( nSalFrameStyle & SalFrameStyleFlags::MOVEABLE )
331 pFrame->mbCaption = true;
332 nSysStyle |= WS_SYSMENU | WS_CAPTION;
333 if ( !hWndParent )
334 nSysStyle |= WS_SYSMENU | WS_MINIMIZEBOX;
335 else
336 nExSysStyle |= WS_EX_DLGMODALFRAME;
338 if ( nSalFrameStyle & SalFrameStyleFlags::SIZEABLE )
340 pFrame->mbSizeBorder = true;
341 nSysStyle |= WS_THICKFRAME;
342 if ( !hWndParent )
343 nSysStyle |= WS_MAXIMIZEBOX;
345 else
346 pFrame->mbFixBorder = true;
348 if ( nSalFrameStyle & SalFrameStyleFlags::DEFAULT )
349 nExSysStyle |= WS_EX_APPWINDOW;
351 if( nSalFrameStyle & SalFrameStyleFlags::TOOLWINDOW
352 // #100656# toolwindows lead to bad alt-tab behaviour, if they have the focus
353 // you must press it twice to leave the application
354 // so toolwindows are only used for non sizeable windows
355 // which are typically small, so a small caption makes sense
357 // #103578# looked too bad - above changes reverted
358 /* && !(nSalFrameStyle & SalFrameStyleFlags::SIZEABLE) */ )
360 pFrame->mbNoIcon = true;
361 nExSysStyle |= WS_EX_TOOLWINDOW;
362 if ( pEnvTransparentFloats /*&& !(nSalFrameStyle & SalFrameStyleFlags::MOVEABLE) */)
363 nExSysStyle |= WS_EX_LAYERED;
366 if ( nSalFrameStyle & SalFrameStyleFlags::FLOAT )
368 nExSysStyle |= WS_EX_TOOLWINDOW;
369 pFrame->mbFloatWin = true;
371 if (pEnvTransparentFloats)
372 nExSysStyle |= WS_EX_LAYERED;
375 if (nSalFrameStyle & SalFrameStyleFlags::TOOLTIP)
376 nExSysStyle |= WS_EX_TOPMOST;
378 // init frame data
379 pFrame->mnStyle = nSalFrameStyle;
381 // determine show style
382 pFrame->mnShowState = SW_SHOWNORMAL;
383 if ( (nSysStyle & (WS_POPUP | WS_MAXIMIZEBOX | WS_THICKFRAME)) == (WS_MAXIMIZEBOX | WS_THICKFRAME) )
385 if ( GetSystemMetrics( SM_CXSCREEN ) <= 1024 )
386 pFrame->mnShowState = SW_SHOWMAXIMIZED;
387 else
389 if ( nSalFrameStyle & SalFrameStyleFlags::DEFAULT )
391 SalData* pSalData = GetSalData();
392 pFrame->mnShowState = pSalData->mnCmdShow;
393 if ( (pFrame->mnShowState != SW_SHOWMINIMIZED) &&
394 (pFrame->mnShowState != SW_MINIMIZE) &&
395 (pFrame->mnShowState != SW_SHOWMINNOACTIVE) )
397 if ( (pFrame->mnShowState == SW_SHOWMAXIMIZED) ||
398 (pFrame->mnShowState == SW_MAXIMIZE) )
399 pFrame->mbOverwriteState = false;
400 pFrame->mnShowState = SW_SHOWMAXIMIZED;
402 else
403 pFrame->mbOverwriteState = false;
405 else
407 // Document Windows are also maximized, if the current Document Window
408 // is also maximized
409 HWND hWnd2 = GetForegroundWindow();
410 if ( hWnd2 && IsMaximized( hWnd2 ) &&
411 (GetWindowInstance( hWnd2 ) == pInst->mhInst) &&
412 ((GetWindowStyle( hWnd2 ) & (WS_POPUP | WS_MAXIMIZEBOX | WS_THICKFRAME)) == (WS_MAXIMIZEBOX | WS_THICKFRAME)) )
413 pFrame->mnShowState = SW_SHOWMAXIMIZED;
418 // create frame
419 LPCWSTR pClassName;
420 if ( bSubFrame )
422 if ( nSalFrameStyle & (SalFrameStyleFlags::MOVEABLE|SalFrameStyleFlags::NOSHADOW) ) // check if shadow not wanted
423 pClassName = SAL_SUBFRAME_CLASSNAMEW;
424 else
425 pClassName = SAL_TMPSUBFRAME_CLASSNAMEW; // undecorated floaters will get shadow on XP
427 else
429 if ( nSalFrameStyle & SalFrameStyleFlags::MOVEABLE )
430 pClassName = SAL_FRAME_CLASSNAMEW;
431 else
432 pClassName = SAL_TMPSUBFRAME_CLASSNAMEW;
434 hWnd = CreateWindowExW( nExSysStyle, pClassName, L"", nSysStyle,
435 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
436 hWndParent, nullptr, pInst->mhInst, pFrame );
437 SAL_WARN_IF(!hWnd, "vcl", "CreateWindowExW failed: " << WindowsErrorString(GetLastError()));
439 #if OSL_DEBUG_LEVEL > 1
440 // set transparency value
441 if( GetWindowExStyle( hWnd ) & WS_EX_LAYERED )
442 SetLayeredWindowAttributes( hWnd, 0, 230, 0x00000002 /*LWA_ALPHA*/ );
443 #endif
444 if ( !hWnd )
446 delete pFrame;
447 return nullptr;
450 // If we have a Window with a Caption Bar and without
451 // a MaximizeBox, we change the SystemMenu
452 if ( (nSysStyle & (WS_CAPTION | WS_MAXIMIZEBOX)) == (WS_CAPTION) )
454 HMENU hSysMenu = GetSystemMenu( hWnd, FALSE );
455 if ( hSysMenu )
457 if ( !(nSysStyle & (WS_MINIMIZEBOX | WS_MAXIMIZEBOX)) )
458 DeleteMenu( hSysMenu, SC_RESTORE, MF_BYCOMMAND );
459 else
460 EnableMenuItem( hSysMenu, SC_RESTORE, MF_BYCOMMAND | MF_GRAYED | MF_DISABLED );
461 if ( !(nSysStyle & WS_MINIMIZEBOX) )
462 DeleteMenu( hSysMenu, SC_MINIMIZE, MF_BYCOMMAND );
463 if ( !(nSysStyle & WS_MAXIMIZEBOX) )
464 DeleteMenu( hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND );
465 if ( !(nSysStyle & WS_THICKFRAME) )
466 DeleteMenu( hSysMenu, SC_SIZE, MF_BYCOMMAND );
469 if ( (nSysStyle & WS_SYSMENU) && !(nSalFrameStyle & SalFrameStyleFlags::CLOSEABLE) )
471 HMENU hSysMenu = GetSystemMenu( hWnd, FALSE );
472 if ( hSysMenu )
473 EnableMenuItem( hSysMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED | MF_DISABLED );
476 // reset input context
477 pFrame->mhDefIMEContext = ImmAssociateContext( hWnd, nullptr );
479 // determine output size and state
480 RECT aRect;
481 GetClientRect( hWnd, &aRect );
482 pFrame->mnWidth = aRect.right;
483 pFrame->mnHeight = aRect.bottom;
484 ImplSaveFrameState( pFrame );
485 pFrame->mbDefPos = true;
487 UpdateFrameGeometry( hWnd, pFrame );
489 if( pFrame->mnShowState == SW_SHOWMAXIMIZED )
491 // #96084 set a useful internal window size because
492 // the window will not be maximized (and the size updated) before show()
494 SetMaximizedFrameGeometry( hWnd, pFrame );
497 return pFrame;
500 // helper that only creates the HWND
501 // to allow for easy reparenting of system windows, (i.e. destroy and create new)
502 HWND ImplSalReCreateHWND( HWND hWndParent, HWND oldhWnd, bool bAsChild )
504 HINSTANCE hInstance = GetSalData()->mhInst;
505 sal_uLong nSysStyle = GetWindowLongW( oldhWnd, GWL_STYLE );
506 sal_uLong nExSysStyle = GetWindowLongW( oldhWnd, GWL_EXSTYLE );
508 if( bAsChild )
510 nSysStyle = WS_CHILD;
511 nExSysStyle = 0;
514 LPCWSTR pClassName = SAL_SUBFRAME_CLASSNAMEW;
515 return CreateWindowExW( nExSysStyle, pClassName, L"", nSysStyle,
516 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
517 hWndParent, nullptr, hInstance, GetWindowPtr( oldhWnd ) );
520 // translation table from System keycodes into StartView keycodes
521 #define KEY_TAB_SIZE 146
523 static const sal_uInt16 aImplTranslateKeyTab[KEY_TAB_SIZE] =
525 // StarView-Code System-Code Index
526 0, // 0
527 0, // VK_LBUTTON 1
528 0, // VK_RBUTTON 2
529 0, // VK_CANCEL 3
530 0, // VK_MBUTTON 4
531 0, // 5
532 0, // 6
533 0, // 7
534 KEY_BACKSPACE, // VK_BACK 8
535 KEY_TAB, // VK_TAB 9
536 0, // 10
537 0, // 11
538 0, // VK_CLEAR 12
539 KEY_RETURN, // VK_RETURN 13
540 0, // 14
541 0, // 15
542 0, // VK_SHIFT 16
543 0, // VK_CONTROL 17
544 0, // VK_MENU 18
545 0, // VK_PAUSE 19
546 0, // VK_CAPITAL 20
547 0, // VK_HANGUL 21
548 0, // 22
549 0, // 23
550 0, // 24
551 KEY_HANGUL_HANJA, // VK_HANJA 25
552 0, // 26
553 KEY_ESCAPE, // VK_ESCAPE 27
554 0, // 28
555 0, // 29
556 0, // 30
557 0, // 31
558 KEY_SPACE, // VK_SPACE 32
559 KEY_PAGEUP, // VK_PRIOR 33
560 KEY_PAGEDOWN, // VK_NEXT 34
561 KEY_END, // VK_END 35
562 KEY_HOME, // VK_HOME 36
563 KEY_LEFT, // VK_LEFT 37
564 KEY_UP, // VK_UP 38
565 KEY_RIGHT, // VK_RIGHT 39
566 KEY_DOWN, // VK_DOWN 40
567 0, // VK_SELECT 41
568 0, // VK_PRINT 42
569 0, // VK_EXECUTE 43
570 0, // VK_SNAPSHOT 44
571 KEY_INSERT, // VK_INSERT 45
572 KEY_DELETE, // VK_DELETE 46
573 KEY_HELP, // VK_HELP 47
574 KEY_0, // 48
575 KEY_1, // 49
576 KEY_2, // 50
577 KEY_3, // 51
578 KEY_4, // 52
579 KEY_5, // 53
580 KEY_6, // 54
581 KEY_7, // 55
582 KEY_8, // 56
583 KEY_9, // 57
584 0, // 58
585 0, // 59
586 0, // 60
587 0, // 61
588 0, // 62
589 0, // 63
590 0, // 64
591 KEY_A, // 65
592 KEY_B, // 66
593 KEY_C, // 67
594 KEY_D, // 68
595 KEY_E, // 69
596 KEY_F, // 70
597 KEY_G, // 71
598 KEY_H, // 72
599 KEY_I, // 73
600 KEY_J, // 74
601 KEY_K, // 75
602 KEY_L, // 76
603 KEY_M, // 77
604 KEY_N, // 78
605 KEY_O, // 79
606 KEY_P, // 80
607 KEY_Q, // 81
608 KEY_R, // 82
609 KEY_S, // 83
610 KEY_T, // 84
611 KEY_U, // 85
612 KEY_V, // 86
613 KEY_W, // 87
614 KEY_X, // 88
615 KEY_Y, // 89
616 KEY_Z, // 90
617 0, // VK_LWIN 91
618 0, // VK_RWIN 92
619 KEY_CONTEXTMENU, // VK_APPS 93
620 0, // 94
621 0, // 95
622 KEY_0, // VK_NUMPAD0 96
623 KEY_1, // VK_NUMPAD1 97
624 KEY_2, // VK_NUMPAD2 98
625 KEY_3, // VK_NUMPAD3 99
626 KEY_4, // VK_NUMPAD4 100
627 KEY_5, // VK_NUMPAD5 101
628 KEY_6, // VK_NUMPAD6 102
629 KEY_7, // VK_NUMPAD7 103
630 KEY_8, // VK_NUMPAD8 104
631 KEY_9, // VK_NUMPAD9 105
632 KEY_MULTIPLY, // VK_MULTIPLY 106
633 KEY_ADD, // VK_ADD 107
634 KEY_DECIMAL, // VK_SEPARATOR 108
635 KEY_SUBTRACT, // VK_SUBTRACT 109
636 KEY_DECIMAL, // VK_DECIMAL 110
637 KEY_DIVIDE, // VK_DIVIDE 111
638 KEY_F1, // VK_F1 112
639 KEY_F2, // VK_F2 113
640 KEY_F3, // VK_F3 114
641 KEY_F4, // VK_F4 115
642 KEY_F5, // VK_F5 116
643 KEY_F6, // VK_F6 117
644 KEY_F7, // VK_F7 118
645 KEY_F8, // VK_F8 119
646 KEY_F9, // VK_F9 120
647 KEY_F10, // VK_F10 121
648 KEY_F11, // VK_F11 122
649 KEY_F12, // VK_F12 123
650 KEY_F13, // VK_F13 124
651 KEY_F14, // VK_F14 125
652 KEY_F15, // VK_F15 126
653 KEY_F16, // VK_F16 127
654 KEY_F17, // VK_F17 128
655 KEY_F18, // VK_F18 129
656 KEY_F19, // VK_F19 130
657 KEY_F20, // VK_F20 131
658 KEY_F21, // VK_F21 132
659 KEY_F22, // VK_F22 133
660 KEY_F23, // VK_F23 134
661 KEY_F24, // VK_F24 135
662 0, // 136
663 0, // 137
664 0, // 138
665 0, // 139
666 0, // 140
667 0, // 141
668 0, // 142
669 0, // 143
670 0, // NUMLOCK 144
671 0 // SCROLLLOCK 145
674 static UINT ImplSalGetWheelScrollLines()
676 UINT nScrLines = 0;
677 HWND hWndMsWheel = FindWindowW( MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE );
678 if ( hWndMsWheel )
680 UINT nGetScrollLinesMsgId = RegisterWindowMessageW( MSH_SCROLL_LINES );
681 nScrLines = static_cast<UINT>(SendMessageW( hWndMsWheel, nGetScrollLinesMsgId, 0, 0 ));
684 if ( !nScrLines )
685 if( !SystemParametersInfoW( SPI_GETWHEELSCROLLLINES, 0, &nScrLines, 0 ) )
686 nScrLines = 0 ;
688 if ( !nScrLines )
689 nScrLines = 3;
691 return nScrLines;
694 static UINT ImplSalGetWheelScrollChars()
696 UINT nScrChars = 0;
697 if( !SystemParametersInfoW( SPI_GETWHEELSCROLLCHARS, 0, &nScrChars, 0 ) )
699 return 3;
702 // system settings successfully read
703 return nScrChars;
706 static void ImplSalAddBorder( const WinSalFrame* pFrame, int& width, int& height )
708 // transform client size into window size
709 RECT aWinRect;
710 aWinRect.left = 0;
711 aWinRect.right = width-1;
712 aWinRect.top = 0;
713 aWinRect.bottom = height-1;
714 AdjustWindowRectEx( &aWinRect, GetWindowStyle( pFrame->mhWnd ),
715 FALSE, GetWindowExStyle( pFrame->mhWnd ) );
716 width = aWinRect.right - aWinRect.left + 1;
717 height = aWinRect.bottom - aWinRect.top + 1;
720 static void ImplSalCalcFullScreenSize( const WinSalFrame* pFrame,
721 int& rX, int& rY, int& rDX, int& rDY )
723 // set window to screen size
724 int nFrameX;
725 int nFrameY;
726 int nCaptionY;
727 int nScreenX = 0;
728 int nScreenY = 0;
729 int nScreenDX = 0;
730 int nScreenDY = 0;
732 if ( pFrame->mbSizeBorder )
734 nFrameX = GetSystemMetrics( SM_CXSIZEFRAME );
735 nFrameY = GetSystemMetrics( SM_CYSIZEFRAME );
737 else if ( pFrame->mbFixBorder )
739 nFrameX = GetSystemMetrics( SM_CXFIXEDFRAME );
740 nFrameY = GetSystemMetrics( SM_CYFIXEDFRAME );
742 else if ( pFrame->mbBorder )
744 nFrameX = GetSystemMetrics( SM_CXBORDER );
745 nFrameY = GetSystemMetrics( SM_CYBORDER );
747 else
749 nFrameX = 0;
750 nFrameY = 0;
752 if ( pFrame->mbCaption )
753 nCaptionY = GetSystemMetrics( SM_CYCAPTION );
754 else
755 nCaptionY = 0;
759 sal_Int32 nMonitors = Application::GetScreenCount();
760 if( (pFrame->mnDisplay >= 0) && (pFrame->mnDisplay < nMonitors) )
762 tools::Rectangle aRect = Application::GetScreenPosSizePixel( pFrame->mnDisplay );
763 nScreenX = aRect.Left();
764 nScreenY = aRect.Top();
765 nScreenDX = aRect.GetWidth();
766 nScreenDY = aRect.GetHeight();
768 else
770 tools::Rectangle aCombined = Application::GetScreenPosSizePixel( 0 );
771 for( sal_Int32 i = 1 ; i < nMonitors ; i++ )
773 aCombined.Union( Application::GetScreenPosSizePixel( i ) );
775 nScreenX = aCombined.Left();
776 nScreenY = aCombined.Top();
777 nScreenDX = aCombined.GetWidth();
778 nScreenDY = aCombined.GetHeight();
781 catch( Exception& )
785 if( !nScreenDX || !nScreenDY )
787 nScreenDX = GetSystemMetrics( SM_CXSCREEN );
788 nScreenDY = GetSystemMetrics( SM_CYSCREEN );
791 rX = nScreenX -nFrameX;
792 rY = nScreenY -(nFrameY+nCaptionY);
793 rDX = nScreenDX+(nFrameX*2);
794 rDY = nScreenDY+(nFrameY*2)+nCaptionY;
797 static void ImplSalFrameFullScreenPos( WinSalFrame* pFrame, bool bAlways = false )
799 if ( bAlways || !IsIconic( pFrame->mhWnd ) )
801 // set window to screen size
802 int nX;
803 int nY;
804 int nWidth;
805 int nHeight;
806 ImplSalCalcFullScreenSize( pFrame, nX, nY, nWidth, nHeight );
807 SetWindowPos( pFrame->mhWnd, nullptr,
808 nX, nY, nWidth, nHeight,
809 SWP_NOZORDER | SWP_NOACTIVATE );
813 namespace {
815 void SetForegroundWindow_Impl(HWND hwnd)
817 if (!Application::IsHeadlessModeEnabled())
818 SetForegroundWindow(hwnd);
823 WinSalFrame::WinSalFrame()
825 SalData* pSalData = GetSalData();
827 mhWnd = nullptr;
828 mhCursor = LoadCursor( nullptr, IDC_ARROW );
829 mhDefIMEContext = nullptr;
830 mpLocalGraphics = nullptr;
831 mpThreadGraphics = nullptr;
832 mnShowState = SW_SHOWNORMAL;
833 mnWidth = 0;
834 mnHeight = 0;
835 mnMinWidth = 0;
836 mnMinHeight = 0;
837 mnMaxWidth = SHRT_MAX;
838 mnMaxHeight = SHRT_MAX;
839 mnInputLang = 0;
840 mnInputCodePage = 0;
841 mbGraphics = false;
842 mbCaption = false;
843 mbBorder = false;
844 mbFixBorder = false;
845 mbSizeBorder = false;
846 mbFullScreenCaption = false;
847 mbFullScreen = false;
848 mbPresentation = false;
849 mbInShow = false;
850 mbRestoreMaximize = false;
851 mbInMoveMsg = false;
852 mbInSizeMsg = false;
853 mbFullScreenToolWin = false;
854 mbDefPos = true;
855 mbOverwriteState = true;
856 mbIME = false;
857 mbHandleIME = false;
858 mbSpezIME = false;
859 mbAtCursorIME = false;
860 mbCandidateMode = false;
861 mbFloatWin = false;
862 mbNoIcon = false;
863 mSelectedhMenu = nullptr;
864 mLastActivatedhMenu = nullptr;
865 mpClipRgnData = nullptr;
866 mbFirstClipRect = true;
867 mpNextClipRect = nullptr;
868 mnDisplay = 0;
869 mbPropertiesStored = false;
871 // get data, when making 1st frame
872 if ( !pSalData->mpFirstFrame )
874 if ( !aSalShlData.mnWheelScrollLines )
875 aSalShlData.mnWheelScrollLines = ImplSalGetWheelScrollLines();
876 if ( !aSalShlData.mnWheelScrollChars )
877 aSalShlData.mnWheelScrollChars = ImplSalGetWheelScrollChars();
880 // insert frame in framelist
881 mpNextFrame = pSalData->mpFirstFrame;
882 pSalData->mpFirstFrame = this;
885 void WinSalFrame::updateScreenNumber()
887 if( mnDisplay == -1 ) // spans all monitors
888 return;
889 WinSalSystem* pSys = static_cast<WinSalSystem*>(ImplGetSalSystem());
890 if( pSys )
892 const std::vector<WinSalSystem::DisplayMonitor>& rMonitors =
893 pSys->getMonitors();
894 Point aPoint( maGeometry.nX, maGeometry.nY );
895 size_t nMon = rMonitors.size();
896 for( size_t i = 0; i < nMon; i++ )
898 if( rMonitors[i].m_aArea.IsInside( aPoint ) )
900 mnDisplay = static_cast<sal_Int32>(i);
901 maGeometry.nDisplayScreenNumber = static_cast<unsigned int>(i);
907 bool WinSalFrame::ReleaseFrameGraphicsDC( WinSalGraphics* pGraphics )
909 assert( pGraphics );
910 SalData* pSalData = GetSalData();
911 HDC hDC = pGraphics->getHDC();
912 if ( !hDC )
913 return false;
914 if ( pGraphics->getDefPal() )
915 SelectPalette( hDC, pGraphics->getDefPal(), TRUE );
916 pGraphics->DeInitGraphics();
917 SendMessageW( pSalData->mpInstance->mhComWnd, SAL_MSG_RELEASEDC,
918 reinterpret_cast<WPARAM>(mhWnd), reinterpret_cast<LPARAM>(hDC) );
919 if ( pGraphics == mpThreadGraphics )
920 pSalData->mnCacheDCInUse--;
921 pGraphics->setHDC(nullptr);
922 return true;
925 WinSalFrame::~WinSalFrame()
927 SalData* pSalData = GetSalData();
929 if( mpClipRgnData )
930 delete [] reinterpret_cast<BYTE*>(mpClipRgnData);
932 // remove frame from framelist
933 WinSalFrame** ppFrame = &pSalData->mpFirstFrame;
934 for(; (*ppFrame != this) && *ppFrame; ppFrame = &(*ppFrame)->mpNextFrame );
935 if( *ppFrame )
936 *ppFrame = mpNextFrame;
937 mpNextFrame = nullptr;
939 // destroy the thread SalGraphics
940 if ( mpThreadGraphics )
942 ReleaseFrameGraphicsDC( mpThreadGraphics );
943 delete mpThreadGraphics;
944 mpThreadGraphics = nullptr;
947 // destroy the local SalGraphics
948 if ( mpLocalGraphics )
950 ReleaseFrameGraphicsDC( mpLocalGraphics );
951 delete mpLocalGraphics;
952 mpLocalGraphics = nullptr;
955 if ( mhWnd )
957 // reset mouse leave data
958 if ( pSalData->mhWantLeaveMsg == mhWnd )
960 pSalData->mhWantLeaveMsg = nullptr;
961 if ( pSalData->mpMouseLeaveTimer )
963 delete pSalData->mpMouseLeaveTimer;
964 pSalData->mpMouseLeaveTimer = nullptr;
968 // remove windows properties
969 if ( mbPropertiesStored )
970 SetApplicationID( OUString() );
972 // destroy system frame
973 if ( !DestroyWindow( mhWnd ) )
974 SetWindowPtr( mhWnd, nullptr );
976 mhWnd = nullptr;
980 bool WinSalFrame::InitFrameGraphicsDC( WinSalGraphics *pGraphics, HDC hDC, HWND hWnd )
982 SalData* pSalData = GetSalData();
983 assert( pGraphics );
984 pGraphics->setHWND( hWnd );
986 HDC hCurrentDC = pGraphics->getHDC();
987 assert( !hCurrentDC || (hCurrentDC == hDC) );
988 if ( hCurrentDC )
989 return true;
990 pGraphics->setHDC( hDC );
992 if ( !hDC )
993 return false;
995 if ( pSalData->mhDitherPal )
997 pGraphics->setDefPal(SelectPalette( hDC, pSalData->mhDitherPal, TRUE ));
998 RealizePalette( hDC );
1000 pGraphics->InitGraphics();
1002 if ( pGraphics == mpThreadGraphics )
1003 pSalData->mnCacheDCInUse++;
1004 return true;
1007 SalGraphics* WinSalFrame::AcquireGraphics()
1009 if ( mbGraphics || !mhWnd )
1010 return nullptr;
1012 SalData* pSalData = GetSalData();
1013 WinSalGraphics *pGraphics = nullptr;
1014 HDC hDC = nullptr;
1016 // Other threads get an own DC, because Windows modify in the
1017 // other case our DC (changing clip region), when they send a
1018 // WM_ERASEBACKGROUND message
1019 if ( !pSalData->mpInstance->IsMainThread() )
1021 // We use only three CacheDC's for all threads, because W9x is limited
1022 // to max. 5 Cache DC's per thread
1023 if ( pSalData->mnCacheDCInUse >= 3 )
1024 return nullptr;
1026 if ( !mpThreadGraphics )
1027 mpThreadGraphics = new WinSalGraphics(WinSalGraphics::WINDOW, true, mhWnd, this);
1028 pGraphics = mpThreadGraphics;
1029 assert( !pGraphics->getHDC() );
1030 hDC = reinterpret_cast<HDC>(static_cast<sal_IntPtr>(SendMessageW( pSalData->mpInstance->mhComWnd,
1031 SAL_MSG_GETCACHEDDC, reinterpret_cast<WPARAM>(mhWnd), 0 )));
1033 else
1035 if ( !mpLocalGraphics )
1036 mpLocalGraphics = new WinSalGraphics(WinSalGraphics::WINDOW, true, mhWnd, this);
1037 pGraphics = mpLocalGraphics;
1038 hDC = pGraphics->getHDC();
1039 if ( !hDC )
1040 hDC = GetDC( mhWnd );
1043 mbGraphics = InitFrameGraphicsDC( pGraphics, hDC, mhWnd );
1044 return mbGraphics ? pGraphics : nullptr;
1047 void WinSalFrame::ReleaseGraphics( SalGraphics* pGraphics )
1049 if ( mpThreadGraphics == pGraphics )
1050 ReleaseFrameGraphicsDC( mpThreadGraphics );
1051 mbGraphics = false;
1054 bool WinSalFrame::PostEvent(std::unique_ptr<ImplSVEvent> pData)
1056 BOOL const ret = PostMessageW(mhWnd, SAL_MSG_USEREVENT, 0, reinterpret_cast<LPARAM>(pData.release()));
1057 SAL_WARN_IF(0 == ret, "vcl", "ERROR: PostMessage() failed!");
1058 return static_cast<bool>(ret);
1061 void WinSalFrame::SetTitle( const OUString& rTitle )
1063 static_assert( sizeof( WCHAR ) == sizeof( sal_Unicode ), "must be the same size" );
1065 SetWindowTextW( mhWnd, o3tl::toW(rTitle.getStr()) );
1068 void WinSalFrame::SetIcon( sal_uInt16 nIcon )
1070 // If we have a window without an Icon (for example a dialog), ignore this call
1071 if ( mbNoIcon )
1072 return;
1074 // 0 means default (class) icon
1075 HICON hIcon = nullptr, hSmIcon = nullptr;
1076 if ( !nIcon )
1077 nIcon = 1;
1079 ImplLoadSalIcon( nIcon, hIcon, hSmIcon );
1081 SAL_WARN_IF( !hIcon , "vcl", "WinSalFrame::SetIcon(): Could not load large icon !" );
1082 SAL_WARN_IF( !hSmIcon , "vcl", "WinSalFrame::SetIcon(): Could not load small icon !" );
1084 SendMessageW( mhWnd, WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(hIcon) );
1085 SendMessageW( mhWnd, WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>(hSmIcon) );
1088 void WinSalFrame::SetMenu( SalMenu* pSalMenu )
1090 WinSalMenu* pWMenu = static_cast<WinSalMenu*>(pSalMenu);
1091 if( pSalMenu && pWMenu->mbMenuBar )
1092 ::SetMenu( mhWnd, pWMenu->mhMenu );
1095 void WinSalFrame::DrawMenuBar()
1097 ::DrawMenuBar( mhWnd );
1100 static HWND ImplGetParentHwnd( HWND hWnd )
1102 WinSalFrame* pFrame = GetWindowPtr( hWnd );
1103 if( !pFrame || !pFrame->GetWindow())
1104 return ::GetParent( hWnd );
1105 vcl::Window *pRealParent = pFrame->GetWindow()->ImplGetWindowImpl()->mpRealParent;
1106 if( pRealParent )
1107 return static_cast<WinSalFrame*>(pRealParent->ImplGetWindowImpl()->mpFrame)->mhWnd;
1108 else
1109 return ::GetParent( hWnd );
1113 SalFrame* WinSalFrame::GetParent() const
1115 return GetWindowPtr( ImplGetParentHwnd( mhWnd ) );
1118 static void ImplSalShow( HWND hWnd, bool bVisible, bool bNoActivate )
1120 WinSalFrame* pFrame = GetWindowPtr( hWnd );
1121 if ( !pFrame )
1122 return;
1124 if ( bVisible )
1126 pFrame->mbDefPos = false;
1127 pFrame->mbOverwriteState = true;
1128 pFrame->mbInShow = true;
1130 // #i4715, save position
1131 RECT aRectPreMatrox, aRectPostMatrox;
1132 GetWindowRect( hWnd, &aRectPreMatrox );
1134 vcl::DeletionListener aDogTag( pFrame );
1135 if( bNoActivate )
1136 ShowWindow( hWnd, SW_SHOWNOACTIVATE );
1137 else
1138 ShowWindow( hWnd, pFrame->mnShowState );
1139 if( aDogTag.isDeleted() )
1140 return;
1142 if (pFrame->mbFloatWin && !(pFrame->mnStyle & SalFrameStyleFlags::NOSHADOW))
1144 // erase the window immediately to improve XP shadow effect
1145 // otherwise the shadow may appears long time before the rest of the window
1146 // especially when accessibility is on
1147 HDC dc = GetDC( hWnd );
1148 RECT aRect;
1149 GetClientRect( hWnd, &aRect );
1150 FillRect( dc, &aRect, reinterpret_cast<HBRUSH>(COLOR_MENU+1) ); // choose the menucolor, because its mostly noticeable for menus
1151 ReleaseDC( hWnd, dc );
1154 // #i4715, matrox centerpopup might have changed our position
1155 // reposition popups without caption (menus, dropdowns, tooltips)
1156 GetWindowRect( hWnd, &aRectPostMatrox );
1157 if( (GetWindowStyle( hWnd ) & WS_POPUP) &&
1158 !pFrame->mbCaption &&
1159 (aRectPreMatrox.left != aRectPostMatrox.left || aRectPreMatrox.top != aRectPostMatrox.top) )
1160 SetWindowPos( hWnd, nullptr, aRectPreMatrox.left, aRectPreMatrox.top, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE );
1162 if( aDogTag.isDeleted() )
1163 return;
1164 vcl::Window *pClientWin = pFrame->GetWindow()->ImplGetClientWindow();
1165 if ( pFrame->mbFloatWin || ( pClientWin && (pClientWin->GetStyle() & WB_SYSTEMFLOATWIN) ) )
1166 pFrame->mnShowState = SW_SHOWNOACTIVATE;
1167 else
1168 pFrame->mnShowState = SW_SHOW;
1169 // hide toolbar for W98
1170 if ( pFrame->mbPresentation )
1172 HWND hWndParent = ::GetParent( hWnd );
1173 if ( hWndParent )
1174 SetForegroundWindow_Impl( hWndParent );
1175 SetForegroundWindow_Impl( hWnd );
1178 pFrame->mbInShow = false;
1179 pFrame->updateScreenNumber();
1181 // Direct Paint only, if we get the SolarMutex
1182 if ( ImplSalYieldMutexTryToAcquire() )
1184 UpdateWindow( hWnd );
1185 ImplSalYieldMutexRelease();
1188 else
1190 ShowWindow( hWnd, SW_HIDE );
1194 void WinSalFrame::SetExtendedFrameStyle( SalExtStyle )
1198 void WinSalFrame::Show( bool bVisible, bool bNoActivate )
1200 // Post this Message to the window, because this only works
1201 // in the thread of the window, which has create this window.
1202 // We post this message to avoid deadlocks
1203 if ( GetSalData()->mnAppThreadId != GetCurrentThreadId() )
1205 BOOL const ret = PostMessageW(mhWnd, SAL_MSG_SHOW, WPARAM(bVisible), LPARAM(bNoActivate));
1206 SAL_WARN_IF(0 == ret, "vcl", "ERROR: PostMessage() failed!");
1208 else
1209 ImplSalShow( mhWnd, bVisible, bNoActivate );
1212 void WinSalFrame::SetMinClientSize( long nWidth, long nHeight )
1214 mnMinWidth = nWidth;
1215 mnMinHeight = nHeight;
1218 void WinSalFrame::SetMaxClientSize( long nWidth, long nHeight )
1220 mnMaxWidth = nWidth;
1221 mnMaxHeight = nHeight;
1224 void WinSalFrame::SetPosSize( long nX, long nY, long nWidth, long nHeight,
1225 sal_uInt16 nFlags )
1227 bool bVisible = (GetWindowStyle( mhWnd ) & WS_VISIBLE) != 0;
1228 if ( !bVisible )
1230 vcl::Window *pClientWin = GetWindow()->ImplGetClientWindow();
1231 if ( mbFloatWin || ( pClientWin && (pClientWin->GetStyle() & WB_SYSTEMFLOATWIN) ) )
1232 mnShowState = SW_SHOWNOACTIVATE;
1233 else
1234 mnShowState = SW_SHOWNORMAL;
1236 else
1238 if ( IsIconic( mhWnd ) || IsZoomed( mhWnd ) )
1239 ShowWindow( mhWnd, SW_RESTORE );
1242 SalEvent nEvent = SalEvent::NONE;
1243 UINT nPosSize = 0;
1244 RECT aClientRect, aWindowRect;
1245 GetClientRect( mhWnd, &aClientRect ); // x,y always 0,0, but width and height without border
1246 GetWindowRect( mhWnd, &aWindowRect ); // x,y in screen coordinates, width and height with border
1248 if ( !(nFlags & (SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y)) )
1249 nPosSize |= SWP_NOMOVE;
1250 else
1252 //SAL_WARN_IF( !nX || !nY, "vcl", " Windowposition of (0,0) requested!" );
1253 nEvent = SalEvent::Move;
1255 if ( !(nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT)) )
1256 nPosSize |= SWP_NOSIZE;
1257 else
1258 nEvent = (nEvent == SalEvent::Move) ? SalEvent::MoveResize : SalEvent::Resize;
1260 if ( !(nFlags & SAL_FRAME_POSSIZE_X) )
1261 nX = aWindowRect.left;
1262 if ( !(nFlags & SAL_FRAME_POSSIZE_Y) )
1263 nY = aWindowRect.top;
1264 if ( !(nFlags & SAL_FRAME_POSSIZE_WIDTH) )
1265 nWidth = aClientRect.right-aClientRect.left;
1266 if ( !(nFlags & SAL_FRAME_POSSIZE_HEIGHT) )
1267 nHeight = aClientRect.bottom-aClientRect.top;
1269 // Calculate window size including the border
1270 RECT aWinRect;
1271 aWinRect.left = 0;
1272 aWinRect.right = static_cast<int>(nWidth)-1;
1273 aWinRect.top = 0;
1274 aWinRect.bottom = static_cast<int>(nHeight)-1;
1275 AdjustWindowRectEx( &aWinRect, GetWindowStyle( mhWnd ),
1276 FALSE, GetWindowExStyle( mhWnd ) );
1277 nWidth = aWinRect.right - aWinRect.left + 1;
1278 nHeight = aWinRect.bottom - aWinRect.top + 1;
1280 if ( !(nPosSize & SWP_NOMOVE) && ::GetParent( mhWnd ) )
1282 RECT aParentRect;
1283 GetClientRect( ImplGetParentHwnd( mhWnd ), &aParentRect );
1284 if( AllSettings::GetLayoutRTL() )
1285 nX = (aParentRect.right - aParentRect.left) - nWidth-1 - nX;
1287 //#110386#, do not transform coordinates for system child windows
1288 if( !(GetWindowStyle( mhWnd ) & WS_CHILD) )
1290 POINT aPt;
1291 aPt.x = nX;
1292 aPt.y = nY;
1294 HWND parentHwnd = ImplGetParentHwnd( mhWnd );
1295 WinSalFrame* pParentFrame = GetWindowPtr( parentHwnd );
1296 if ( pParentFrame && pParentFrame->mnShowState == SW_SHOWMAXIMIZED )
1298 // #i42485#: parent will be shown maximized in which case
1299 // a ClientToScreen uses the wrong coordinates (i.e. those from the restore pos)
1300 // so use the (already updated) frame geometry for the transformation
1301 aPt.x += pParentFrame->maGeometry.nX;
1302 aPt.y += pParentFrame->maGeometry.nY;
1304 else
1305 ClientToScreen( parentHwnd, &aPt );
1307 nX = aPt.x;
1308 nY = aPt.y;
1310 // the position is set
1311 mbDefPos = false;
1315 // #i3338# to be conformant to UNIX we must position the client window, ie without the decoration
1316 // #i43250# if the position was read from the system (GetWindowRect(), see above), it must not be modified
1317 if ( nFlags & SAL_FRAME_POSSIZE_X )
1318 nX += aWinRect.left;
1319 if ( nFlags & SAL_FRAME_POSSIZE_Y )
1320 nY += aWinRect.top;
1322 int nScreenX;
1323 int nScreenY;
1324 int nScreenWidth;
1325 int nScreenHeight;
1327 RECT aRect;
1328 ImplSalGetWorkArea( mhWnd, &aRect, nullptr );
1329 nScreenX = aRect.left;
1330 nScreenY = aRect.top;
1331 nScreenWidth = aRect.right-aRect.left;
1332 nScreenHeight = aRect.bottom-aRect.top;
1334 if ( mbDefPos && (nPosSize & SWP_NOMOVE)) // we got no positioning request, so choose default position
1336 // center window
1338 HWND hWndParent = ::GetParent( mhWnd );
1339 // Search for TopLevel Frame
1340 while ( hWndParent && (GetWindowStyle( hWndParent ) & WS_CHILD) )
1341 hWndParent = ::GetParent( hWndParent );
1342 // if the Window has a Parent, then center the window to
1343 // the parent, in the other case to the screen
1344 if ( hWndParent && !IsIconic( hWndParent ) &&
1345 (GetWindowStyle( hWndParent ) & WS_VISIBLE) )
1347 RECT aParentRect;
1348 GetWindowRect( hWndParent, &aParentRect );
1349 int nParentWidth = aParentRect.right-aParentRect.left;
1350 int nParentHeight = aParentRect.bottom-aParentRect.top;
1352 // We don't center, when Parent is smaller than our window
1353 if ( (nParentWidth-GetSystemMetrics( SM_CXFIXEDFRAME ) <= nWidth) &&
1354 (nParentHeight-GetSystemMetrics( SM_CYFIXEDFRAME ) <= nHeight) )
1356 int nOff = GetSystemMetrics( SM_CYSIZEFRAME ) + GetSystemMetrics( SM_CYCAPTION );
1357 nX = aParentRect.left+nOff;
1358 nY = aParentRect.top+nOff;
1360 else
1362 nX = (nParentWidth-nWidth)/2 + aParentRect.left;
1363 nY = (nParentHeight-nHeight)/2 + aParentRect.top;
1366 else
1368 POINT pt;
1369 GetCursorPos( &pt );
1370 RECT aRect2;
1371 aRect2.left = pt.x;
1372 aRect2.top = pt.y;
1373 aRect2.right = pt.x+2;
1374 aRect2.bottom = pt.y+2;
1376 // dualmonitor support:
1377 // Get screensize of the monitor with the mouse pointer
1378 ImplSalGetWorkArea( mhWnd, &aRect2, &aRect2 );
1380 nX = ((aRect2.right-aRect2.left)-nWidth)/2 + aRect2.left;
1381 nY = ((aRect2.bottom-aRect2.top)-nHeight)/2 + aRect2.top;
1384 //if ( bVisible )
1385 // mbDefPos = FALSE;
1387 mbDefPos = false; // center only once
1388 nPosSize &= ~SWP_NOMOVE; // activate positioning
1389 nEvent = SalEvent::MoveResize;
1392 // Adjust Window in the screen
1393 bool bCheckOffScreen = true;
1395 // but don't do this for floaters or ownerdraw windows that are currently moved interactively
1396 if( (mnStyle & SalFrameStyleFlags::FLOAT) && !(mnStyle & SalFrameStyleFlags::OWNERDRAWDECORATION) )
1397 bCheckOffScreen = false;
1399 if( mnStyle & SalFrameStyleFlags::OWNERDRAWDECORATION )
1401 // may be the window is currently being moved (mouse is captured), then no check is required
1402 if( mhWnd == ::GetCapture() )
1403 bCheckOffScreen = false;
1404 else
1405 bCheckOffScreen = true;
1408 if( bCheckOffScreen )
1410 if ( nX+nWidth > nScreenX+nScreenWidth )
1411 nX = (nScreenX+nScreenWidth) - nWidth;
1412 if ( nY+nHeight > nScreenY+nScreenHeight )
1413 nY = (nScreenY+nScreenHeight) - nHeight;
1414 if ( nX < nScreenX )
1415 nX = nScreenX;
1416 if ( nY < nScreenY )
1417 nY = nScreenY;
1420 UINT nPosFlags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | nPosSize;
1421 // bring floating windows always to top
1422 if( !(mnStyle & SalFrameStyleFlags::FLOAT) )
1423 nPosFlags |= SWP_NOZORDER; // do not change z-order
1425 SetWindowPos( mhWnd, HWND_TOP, nX, nY, static_cast<int>(nWidth), static_cast<int>(nHeight), nPosFlags );
1427 UpdateFrameGeometry( mhWnd, this );
1429 // Notification -- really ???
1430 if( nEvent != SalEvent::NONE )
1431 CallCallback( nEvent, nullptr );
1434 void WinSalFrame::ImplSetParentFrame( HWND hNewParentWnd, bool bAsChild )
1436 // save hwnd, will be overwritten in WM_CREATE during createwindow
1437 HWND hWndOld = mhWnd;
1438 HWND hWndOldParent = ::GetParent( hWndOld );
1439 SalData* pSalData = GetSalData();
1441 if( hNewParentWnd == hWndOldParent )
1442 return;
1444 ::std::vector< WinSalFrame* > children;
1445 ::std::vector< WinSalObject* > systemChildren;
1447 // search child windows
1448 WinSalFrame *pFrame = pSalData->mpFirstFrame;
1449 while( pFrame )
1451 HWND hWndParent = ::GetParent( pFrame->mhWnd );
1452 if( mhWnd == hWndParent )
1453 children.push_back( pFrame );
1454 pFrame = pFrame->mpNextFrame;
1457 // search system child windows (plugins etc.)
1458 WinSalObject *pObject = pSalData->mpFirstObject;
1459 while( pObject )
1461 HWND hWndParent = ::GetParent( pObject->mhWnd );
1462 if( mhWnd == hWndParent )
1463 systemChildren.push_back( pObject );
1464 pObject = pObject->mpNextObject;
1467 // to recreate the DCs, if they were destroyed
1468 bool bHadLocalGraphics = false, bHadThreadGraphics = false;
1470 HFONT hFont = nullptr;
1471 HPEN hPen = nullptr;
1472 HBRUSH hBrush = nullptr;
1474 int oldCount = pSalData->mnCacheDCInUse;
1476 // release the thread DC
1477 if ( mpThreadGraphics )
1479 // save current gdi objects before hdc is gone
1480 HDC hDC = mpThreadGraphics->getHDC();
1481 if ( hDC )
1483 hFont = static_cast<HFONT>(GetCurrentObject( hDC, OBJ_FONT ));
1484 hPen = static_cast<HPEN>(GetCurrentObject( hDC, OBJ_PEN ));
1485 hBrush = static_cast<HBRUSH>(GetCurrentObject( hDC, OBJ_BRUSH ));
1488 bHadThreadGraphics = ReleaseFrameGraphicsDC( mpThreadGraphics );
1489 assert( (bHadThreadGraphics && hDC) || (!bHadThreadGraphics && !hDC) );
1492 // release the local DC
1493 if ( mpLocalGraphics )
1494 bHadLocalGraphics = ReleaseFrameGraphicsDC( mpLocalGraphics );
1496 // create a new hwnd with the same styles
1497 HWND hWndParent = hNewParentWnd;
1498 // forward to main thread
1499 HWND hWnd = reinterpret_cast<HWND>(static_cast<sal_IntPtr>(SendMessageW( pSalData->mpInstance->mhComWnd,
1500 bAsChild ? SAL_MSG_RECREATECHILDHWND : SAL_MSG_RECREATEHWND,
1501 reinterpret_cast<WPARAM>(hWndParent), reinterpret_cast<LPARAM>(mhWnd) )));
1503 // succeeded ?
1504 SAL_WARN_IF( !IsWindow( hWnd ), "vcl", "WinSalFrame::SetParent not successful");
1506 // re-create thread DC
1507 if( bHadThreadGraphics )
1509 HDC hDC = reinterpret_cast<HDC>(static_cast<sal_IntPtr>(
1510 SendMessageW( pSalData->mpInstance->mhComWnd,
1511 SAL_MSG_GETCACHEDDC, reinterpret_cast<WPARAM>(hWnd), 0 )));
1512 InitFrameGraphicsDC( mpThreadGraphics, hDC, hWnd );
1513 if ( hDC )
1515 // re-select saved gdi objects
1516 if( hFont )
1517 SelectObject( hDC, hFont );
1518 if( hPen )
1519 SelectObject( hDC, hPen );
1520 if( hBrush )
1521 SelectObject( hDC, hBrush );
1523 SAL_WARN_IF( oldCount != pSalData->mnCacheDCInUse, "vcl", "WinSalFrame::SetParent() hDC count corrupted");
1527 // re-create local DC
1528 if( bHadLocalGraphics )
1529 InitFrameGraphicsDC( mpLocalGraphics, GetDC( hWnd ), hWnd );
1531 // TODO: add SetParent() call for SalObjects
1532 SAL_WARN_IF( !systemChildren.empty(), "vcl", "WinSalFrame::SetParent() parent of living system child window will be destroyed!");
1534 // reparent children before old parent is destroyed
1535 for (auto & child : children)
1536 child->ImplSetParentFrame( hWnd, false );
1538 children.clear();
1539 systemChildren.clear();
1541 // Now destroy original HWND in the thread where it was created.
1542 SendMessageW( GetSalData()->mpInstance->mhComWnd,
1543 SAL_MSG_DESTROYHWND, WPARAM(0), reinterpret_cast<LPARAM>(hWndOld));
1546 void WinSalFrame::SetParent( SalFrame* pNewParent )
1548 WinSalFrame::mbInReparent = true;
1549 ImplSetParentFrame( static_cast<WinSalFrame*>(pNewParent)->mhWnd, false );
1550 WinSalFrame::mbInReparent = false;
1553 bool WinSalFrame::SetPluginParent( SystemParentData* pNewParent )
1555 if ( pNewParent->hWnd == nullptr )
1557 pNewParent->hWnd = GetDesktopWindow();
1560 WinSalFrame::mbInReparent = true;
1561 ImplSetParentFrame( pNewParent->hWnd, true );
1562 WinSalFrame::mbInReparent = false;
1563 return true;
1566 void WinSalFrame::GetWorkArea( tools::Rectangle &rRect )
1568 RECT aRect;
1569 ImplSalGetWorkArea( mhWnd, &aRect, nullptr );
1570 rRect.SetLeft( aRect.left );
1571 rRect.SetRight( aRect.right-1 );
1572 rRect.SetTop( aRect.top );
1573 rRect.SetBottom( aRect.bottom-1 );
1576 void WinSalFrame::GetClientSize( long& rWidth, long& rHeight )
1578 rWidth = maGeometry.nWidth;
1579 rHeight = maGeometry.nHeight;
1582 void WinSalFrame::SetWindowState( const SalFrameState* pState )
1584 // Check if the window fits into the screen, in case the screen
1585 // resolution changed
1586 int nX;
1587 int nY;
1588 int nWidth;
1589 int nHeight;
1590 int nScreenX;
1591 int nScreenY;
1592 int nScreenWidth;
1593 int nScreenHeight;
1595 RECT aRect;
1596 ImplSalGetWorkArea( mhWnd, &aRect, nullptr );
1597 // #102500# allow some overlap, the window could have been made a little larger than the physical screen
1598 nScreenX = aRect.left-10;
1599 nScreenY = aRect.top-10;
1600 nScreenWidth = aRect.right-aRect.left+20;
1601 nScreenHeight = aRect.bottom-aRect.top+20;
1603 UINT nPosSize = 0;
1604 RECT aWinRect;
1605 GetWindowRect( mhWnd, &aWinRect );
1607 // to be consistent with Unix, the frame state is without(!) decoration
1608 // ->add the decoration
1609 RECT aRect2 = aWinRect;
1610 AdjustWindowRectEx( &aRect2, GetWindowStyle( mhWnd ),
1611 FALSE, GetWindowExStyle( mhWnd ) );
1612 long nTopDeco = abs( aWinRect.top - aRect2.top );
1613 long nLeftDeco = abs( aWinRect.left - aRect2.left );
1614 long nBottomDeco = abs( aWinRect.bottom - aRect2.bottom );
1615 long nRightDeco = abs( aWinRect.right - aRect2.right );
1617 // adjust window position/size to fit the screen
1618 if ( !(pState->mnMask & (WindowStateMask::X | WindowStateMask::Y)) )
1619 nPosSize |= SWP_NOMOVE;
1620 if ( !(pState->mnMask & (WindowStateMask::Width | WindowStateMask::Height)) )
1621 nPosSize |= SWP_NOSIZE;
1622 if ( pState->mnMask & WindowStateMask::X )
1623 nX = static_cast<int>(pState->mnX) - nLeftDeco;
1624 else
1625 nX = aWinRect.left;
1626 if ( pState->mnMask & WindowStateMask::Y )
1627 nY = static_cast<int>(pState->mnY) - nTopDeco;
1628 else
1629 nY = aWinRect.top;
1630 if ( pState->mnMask & WindowStateMask::Width )
1631 nWidth = static_cast<int>(pState->mnWidth) + nLeftDeco + nRightDeco;
1632 else
1633 nWidth = aWinRect.right-aWinRect.left;
1634 if ( pState->mnMask & WindowStateMask::Height )
1635 nHeight = static_cast<int>(pState->mnHeight) + nTopDeco + nBottomDeco;
1636 else
1637 nHeight = aWinRect.bottom-aWinRect.top;
1639 // Adjust Window in the screen:
1640 // if it does not fit into the screen do nothing, ie default pos/size will be used
1641 // if there is an overlap with the screen border move the window while keeping its size
1643 if( nWidth > nScreenWidth || nHeight > nScreenHeight )
1644 nPosSize |= (SWP_NOMOVE | SWP_NOSIZE);
1646 if ( nX+nWidth > nScreenX+nScreenWidth )
1647 nX = (nScreenX+nScreenWidth) - nWidth;
1648 if ( nY+nHeight > nScreenY+nScreenHeight )
1649 nY = (nScreenY+nScreenHeight) - nHeight;
1650 if ( nX < nScreenX )
1651 nX = nScreenX;
1652 if ( nY < nScreenY )
1653 nY = nScreenY;
1655 // set Restore-Position
1656 WINDOWPLACEMENT aPlacement;
1657 aPlacement.length = sizeof( aPlacement );
1658 GetWindowPlacement( mhWnd, &aPlacement );
1660 // set State
1661 bool bVisible = (GetWindowStyle( mhWnd ) & WS_VISIBLE) != 0;
1662 bool bUpdateHiddenFramePos = false;
1663 if ( !bVisible )
1665 aPlacement.showCmd = SW_HIDE;
1667 if ( mbOverwriteState )
1669 if ( pState->mnMask & WindowStateMask::State )
1671 if ( pState->mnState & WindowStateState::Minimized )
1672 mnShowState = SW_SHOWMINIMIZED;
1673 else if ( pState->mnState & WindowStateState::Maximized )
1675 mnShowState = SW_SHOWMAXIMIZED;
1676 bUpdateHiddenFramePos = true;
1678 else if ( pState->mnState & WindowStateState::Normal )
1679 mnShowState = SW_SHOWNORMAL;
1683 else
1685 if ( pState->mnMask & WindowStateMask::State )
1687 if ( pState->mnState & WindowStateState::Minimized )
1689 if ( pState->mnState & WindowStateState::Maximized )
1690 aPlacement.flags |= WPF_RESTORETOMAXIMIZED;
1691 aPlacement.showCmd = SW_SHOWMINIMIZED;
1693 else if ( pState->mnState & WindowStateState::Maximized )
1694 aPlacement.showCmd = SW_SHOWMAXIMIZED;
1695 else if ( pState->mnState & WindowStateState::Normal )
1696 aPlacement.showCmd = SW_RESTORE;
1700 // if a window is neither minimized nor maximized or need not be
1701 // positioned visibly (that is in visible state), do not use
1702 // SetWindowPlacement since it calculates including the TaskBar
1703 if ( !IsIconic( mhWnd ) && !IsZoomed( mhWnd ) &&
1704 (!bVisible || (aPlacement.showCmd == SW_RESTORE)) )
1706 if( bUpdateHiddenFramePos )
1708 RECT aStateRect;
1709 aStateRect.left = nX;
1710 aStateRect.top = nY;
1711 aStateRect.right = nX+nWidth;
1712 aStateRect.bottom = nY+nHeight;
1713 // #96084 set a useful internal window size because
1714 // the window will not be maximized (and the size updated) before show()
1715 SetMaximizedFrameGeometry( mhWnd, this, &aStateRect );
1716 SetWindowPos( mhWnd, nullptr,
1717 maGeometry.nX, maGeometry.nY, maGeometry.nWidth, maGeometry.nHeight,
1718 SWP_NOZORDER | SWP_NOACTIVATE | nPosSize );
1720 else
1721 SetWindowPos( mhWnd, nullptr,
1722 nX, nY, nWidth, nHeight,
1723 SWP_NOZORDER | SWP_NOACTIVATE | nPosSize );
1725 else
1727 if( !(nPosSize & (SWP_NOMOVE|SWP_NOSIZE)) )
1729 aPlacement.rcNormalPosition.left = nX-nScreenX;
1730 aPlacement.rcNormalPosition.top = nY-nScreenY;
1731 aPlacement.rcNormalPosition.right = nX+nWidth-nScreenX;
1732 aPlacement.rcNormalPosition.bottom = nY+nHeight-nScreenY;
1734 SetWindowPlacement( mhWnd, &aPlacement );
1737 if( !(nPosSize & SWP_NOMOVE) )
1738 mbDefPos = false; // window was positioned
1741 bool WinSalFrame::GetWindowState( SalFrameState* pState )
1743 if ( maState.mnWidth && maState.mnHeight )
1745 *pState = maState;
1746 // #94144# allow Minimize again, should be masked out when read from configuration
1747 // 91625 - Don't save minimize
1748 //if ( !(pState->mnState & WindowStateState::Maximized) )
1749 if ( !(pState->mnState & (WindowStateState::Minimized | WindowStateState::Maximized)) )
1750 pState->mnState |= WindowStateState::Normal;
1751 return true;
1754 return false;
1757 void WinSalFrame::SetScreenNumber( unsigned int nNewScreen )
1759 WinSalSystem* pSys = static_cast<WinSalSystem*>(ImplGetSalSystem());
1760 if( pSys )
1762 const std::vector<WinSalSystem::DisplayMonitor>& rMonitors =
1763 pSys->getMonitors();
1764 size_t nMon = rMonitors.size();
1765 if( nNewScreen < nMon )
1767 Point aOldMonPos, aNewMonPos( rMonitors[nNewScreen].m_aArea.TopLeft() );
1768 Point aCurPos( maGeometry.nX, maGeometry.nY );
1769 for( size_t i = 0; i < nMon; i++ )
1771 if( rMonitors[i].m_aArea.IsInside( aCurPos ) )
1773 aOldMonPos = rMonitors[i].m_aArea.TopLeft();
1774 break;
1777 mnDisplay = nNewScreen;
1778 maGeometry.nDisplayScreenNumber = nNewScreen;
1779 SetPosSize( aNewMonPos.X() + (maGeometry.nX - aOldMonPos.X()),
1780 aNewMonPos.Y() + (maGeometry.nY - aOldMonPos.Y()),
1781 0, 0,
1782 SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y );
1787 void WinSalFrame::SetApplicationID( const OUString &rApplicationID )
1789 // http://msdn.microsoft.com/en-us/library/windows/desktop/dd378430(v=vs.85).aspx
1790 // A window's properties must be removed before the window is closed.
1792 IPropertyStore *pps;
1793 HRESULT hr = SHGetPropertyStoreForWindow(mhWnd, IID_PPV_ARGS(&pps));
1794 if (SUCCEEDED(hr))
1796 PROPVARIANT pv;
1797 if (!rApplicationID.isEmpty())
1799 hr = InitPropVariantFromString(o3tl::toW(rApplicationID.getStr()), &pv);
1800 mbPropertiesStored = true;
1802 else
1803 // if rApplicationID we remove the property from the window, if present
1804 PropVariantInit(&pv);
1806 if (SUCCEEDED(hr))
1808 hr = pps->SetValue(PKEY_AppUserModel_ID, pv);
1809 PropVariantClear(&pv);
1811 pps->Release();
1815 void WinSalFrame::ShowFullScreen( bool bFullScreen, sal_Int32 nDisplay )
1817 if ( (mbFullScreen == bFullScreen) && (!bFullScreen || (mnDisplay == nDisplay)) )
1818 return;
1820 mbFullScreen = bFullScreen;
1821 mnDisplay = nDisplay;
1823 if ( bFullScreen )
1825 // to hide the Windows taskbar
1826 DWORD nExStyle = GetWindowExStyle( mhWnd );
1827 if ( nExStyle & WS_EX_TOOLWINDOW )
1829 mbFullScreenToolWin = true;
1830 nExStyle &= ~WS_EX_TOOLWINDOW;
1831 SetWindowExStyle( mhWnd, nExStyle );
1833 // save old position
1834 GetWindowRect( mhWnd, &maFullScreenRect );
1836 // save show state
1837 mnFullScreenShowState = mnShowState;
1838 if ( !(GetWindowStyle( mhWnd ) & WS_VISIBLE) )
1839 mnShowState = SW_SHOW;
1841 // Save caption state.
1842 mbFullScreenCaption = mbCaption;
1843 if (mbCaption)
1845 DWORD nStyle = GetWindowStyle(mhWnd);
1846 SetWindowStyle(mhWnd, nStyle & ~WS_CAPTION);
1847 mbCaption = false;
1850 // set window to screen size
1851 ImplSalFrameFullScreenPos( this, true );
1853 else
1855 // when the ShowState has to be reset, hide the window first to
1856 // reduce flicker
1857 bool bVisible = (GetWindowStyle( mhWnd ) & WS_VISIBLE) != 0;
1858 if ( bVisible && (mnShowState != mnFullScreenShowState) )
1859 ShowWindow( mhWnd, SW_HIDE );
1861 if ( mbFullScreenToolWin )
1862 SetWindowExStyle( mhWnd, GetWindowExStyle( mhWnd ) | WS_EX_TOOLWINDOW );
1863 mbFullScreenToolWin = false;
1865 // Restore caption state.
1866 if (mbFullScreenCaption)
1868 DWORD nStyle = GetWindowStyle(mhWnd);
1869 SetWindowStyle(mhWnd, nStyle | WS_CAPTION);
1871 mbCaption = mbFullScreenCaption;
1873 SetWindowPos( mhWnd, nullptr,
1874 maFullScreenRect.left,
1875 maFullScreenRect.top,
1876 maFullScreenRect.right-maFullScreenRect.left,
1877 maFullScreenRect.bottom-maFullScreenRect.top,
1878 SWP_NOZORDER | SWP_NOACTIVATE );
1880 // restore show state
1881 if ( mnShowState != mnFullScreenShowState )
1883 mnShowState = mnFullScreenShowState;
1884 if ( bVisible )
1886 mbInShow = true;
1887 ShowWindow( mhWnd, mnShowState );
1888 mbInShow = false;
1889 UpdateWindow( mhWnd );
1895 void WinSalFrame::StartPresentation( bool bStart )
1897 if ( mbPresentation == bStart )
1898 return;
1900 mbPresentation = bStart;
1902 SalData* pSalData = GetSalData();
1903 if ( bStart )
1905 // turn off screen-saver when in Presentation mode
1906 SystemParametersInfoW( SPI_GETSCREENSAVEACTIVE, 0,
1907 &(pSalData->mbScrSvrEnabled), 0 );
1908 if ( pSalData->mbScrSvrEnabled )
1909 SystemParametersInfoW( SPI_SETSCREENSAVEACTIVE, FALSE, nullptr, 0 );
1911 else
1913 // turn on screen-saver
1914 if ( pSalData->mbScrSvrEnabled )
1915 SystemParametersInfoW( SPI_SETSCREENSAVEACTIVE, pSalData->mbScrSvrEnabled, nullptr, 0 );
1919 void WinSalFrame::SetAlwaysOnTop( bool bOnTop )
1921 HWND hWnd;
1922 if ( bOnTop )
1923 hWnd = HWND_TOPMOST;
1924 else
1925 hWnd = HWND_NOTOPMOST;
1926 SetWindowPos( mhWnd, hWnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
1929 static void ImplSalToTop( HWND hWnd, SalFrameToTop nFlags )
1931 WinSalFrame* pToTopFrame = GetWindowPtr( hWnd );
1932 if( pToTopFrame && (pToTopFrame->mnStyle & SalFrameStyleFlags::SYSTEMCHILD) )
1933 BringWindowToTop( hWnd );
1935 if ( nFlags & SalFrameToTop::ForegroundTask )
1937 // This magic code is necessary to connect the input focus of the
1938 // current window thread and the thread which owns the window that
1939 // should be the new foreground window.
1940 HWND hCurrWnd = GetForegroundWindow();
1941 DWORD myThreadID = GetCurrentThreadId();
1942 DWORD currThreadID = GetWindowThreadProcessId(hCurrWnd,nullptr);
1943 AttachThreadInput(myThreadID, currThreadID,TRUE);
1944 SetForegroundWindow_Impl(hWnd);
1945 AttachThreadInput(myThreadID,currThreadID,FALSE);
1948 if ( nFlags & SalFrameToTop::RestoreWhenMin )
1950 HWND hIconicWnd = hWnd;
1951 while ( hIconicWnd )
1953 if ( IsIconic( hIconicWnd ) )
1955 WinSalFrame* pFrame = GetWindowPtr( hIconicWnd );
1956 if ( pFrame )
1958 if ( GetWindowPtr( hWnd )->mbRestoreMaximize )
1959 ShowWindow( hIconicWnd, SW_MAXIMIZE );
1960 else
1961 ShowWindow( hIconicWnd, SW_RESTORE );
1963 else
1964 ShowWindow( hIconicWnd, SW_RESTORE );
1967 hIconicWnd = ::GetParent( hIconicWnd );
1971 if ( !IsIconic( hWnd ) && IsWindowVisible( hWnd ) )
1973 SetFocus( hWnd );
1975 // Windows sometimes incorrectly reports to have the focus;
1976 // thus make sure to really get the focus
1977 if ( ::GetFocus() == hWnd )
1978 SetForegroundWindow_Impl( hWnd );
1982 void WinSalFrame::ToTop( SalFrameToTop nFlags )
1984 nFlags &= ~SalFrameToTop::GrabFocus; // this flag is not needed on win32
1985 // Post this Message to the window, because this only works
1986 // in the thread of the window, which has create this window.
1987 // We post this message to avoid deadlocks
1988 if ( GetSalData()->mnAppThreadId != GetCurrentThreadId() )
1990 BOOL const ret = PostMessageW( mhWnd, SAL_MSG_TOTOP, static_cast<WPARAM>(nFlags), 0 );
1991 SAL_WARN_IF(0 == ret, "vcl", "ERROR: PostMessage() failed!");
1993 else
1994 ImplSalToTop( mhWnd, nFlags );
1997 void WinSalFrame::SetPointer( PointerStyle ePointerStyle )
1999 struct ImplPtrData
2001 HCURSOR mhCursor;
2002 LPCTSTR mnSysId;
2003 UINT mnOwnId;
2006 static o3tl::enumarray<PointerStyle, ImplPtrData> aImplPtrTab =
2008 ImplPtrData{ nullptr, IDC_ARROW, 0 }, // POINTER_ARROW
2009 { nullptr, nullptr, SAL_RESID_POINTER_NULL }, // POINTER_NULL
2010 { nullptr, IDC_WAIT, 0 }, // POINTER_WAIT
2011 { nullptr, IDC_IBEAM, 0 }, // POINTER_TEXT
2012 { nullptr, IDC_HELP, 0 }, // POINTER_HELP
2013 { nullptr, IDC_CROSS, 0 }, // POINTER_CROSS
2014 { nullptr, IDC_SIZEALL, 0 }, // POINTER_MOVE
2015 { nullptr, IDC_SIZENS, 0 }, // POINTER_NSIZE
2016 { nullptr, IDC_SIZENS, 0 }, // POINTER_SSIZE
2017 { nullptr, IDC_SIZEWE, 0 }, // POINTER_WSIZE
2018 { nullptr, IDC_SIZEWE, 0 }, // POINTER_ESIZE
2019 { nullptr, IDC_SIZENWSE, 0 }, // POINTER_NWSIZE
2020 { nullptr, IDC_SIZENESW, 0 }, // POINTER_NESIZE
2021 { nullptr, IDC_SIZENESW, 0 }, // POINTER_SWSIZE
2022 { nullptr, IDC_SIZENWSE, 0 }, // POINTER_SESIZE
2023 { nullptr, IDC_SIZENS, 0 }, // POINTER_WINDOW_NSIZE
2024 { nullptr, IDC_SIZENS, 0 }, // POINTER_WINDOW_SSIZE
2025 { nullptr, IDC_SIZEWE, 0 }, // POINTER_WINDOW_WSIZE
2026 { nullptr, IDC_SIZEWE, 0 }, // POINTER_WINDOW_ESIZE
2027 { nullptr, IDC_SIZENWSE, 0 }, // POINTER_WINDOW_NWSIZE
2028 { nullptr, IDC_SIZENESW, 0 }, // POINTER_WINDOW_NESIZE
2029 { nullptr, IDC_SIZENESW, 0 }, // POINTER_WINDOW_SWSIZE
2030 { nullptr, IDC_SIZENWSE, 0 }, // POINTER_WINDOW_SESIZE
2031 { nullptr, IDC_SIZEWE, 0 }, // POINTER_HSPLIT
2032 { nullptr, IDC_SIZENS, 0 }, // POINTER_VSPLIT
2033 { nullptr, IDC_SIZEWE, 0 }, // POINTER_HSIZEBAR
2034 { nullptr, IDC_SIZENS, 0 }, // POINTER_VSIZEBAR
2035 { nullptr, IDC_HAND, 0 }, // POINTER_HAND
2036 { nullptr, IDC_HAND, 0 }, // POINTER_REFHAND
2037 { nullptr, IDC_PEN, 0 }, // POINTER_PEN
2038 { nullptr, nullptr, SAL_RESID_POINTER_MAGNIFY }, // POINTER_MAGNIFY
2039 { nullptr, nullptr, SAL_RESID_POINTER_FILL }, // POINTER_FILL
2040 { nullptr, nullptr, SAL_RESID_POINTER_ROTATE }, // POINTER_ROTATE
2041 { nullptr, nullptr, SAL_RESID_POINTER_HSHEAR }, // POINTER_HSHEAR
2042 { nullptr, nullptr, SAL_RESID_POINTER_VSHEAR }, // POINTER_VSHEAR
2043 { nullptr, nullptr, SAL_RESID_POINTER_MIRROR }, // POINTER_MIRROR
2044 { nullptr, nullptr, SAL_RESID_POINTER_CROOK }, // POINTER_CROOK
2045 { nullptr, nullptr, SAL_RESID_POINTER_CROP }, // POINTER_CROP
2046 { nullptr, nullptr, SAL_RESID_POINTER_MOVEPOINT }, // POINTER_MOVEPOINT
2047 { nullptr, nullptr, SAL_RESID_POINTER_MOVEBEZIERWEIGHT }, // POINTER_MOVEBEZIERWEIGHT
2048 { nullptr, nullptr, SAL_RESID_POINTER_MOVEDATA }, // POINTER_MOVEDATA
2049 { nullptr, nullptr, SAL_RESID_POINTER_COPYDATA }, // POINTER_COPYDATA
2050 { nullptr, nullptr, SAL_RESID_POINTER_LINKDATA }, // POINTER_LINKDATA
2051 { nullptr, nullptr, SAL_RESID_POINTER_MOVEDATALINK }, // POINTER_MOVEDATALINK
2052 { nullptr, nullptr, SAL_RESID_POINTER_COPYDATALINK }, // POINTER_COPYDATALINK
2053 { nullptr, nullptr, SAL_RESID_POINTER_MOVEFILE }, // POINTER_MOVEFILE
2054 { nullptr, nullptr, SAL_RESID_POINTER_COPYFILE }, // POINTER_COPYFILE
2055 { nullptr, nullptr, SAL_RESID_POINTER_LINKFILE }, // POINTER_LINKFILE
2056 { nullptr, nullptr, SAL_RESID_POINTER_MOVEFILELINK }, // POINTER_MOVEFILELINK
2057 { nullptr, nullptr, SAL_RESID_POINTER_COPYFILELINK }, // POINTER_COPYFILELINK
2058 { nullptr, nullptr, SAL_RESID_POINTER_MOVEFILES }, // POINTER_MOVEFILES
2059 { nullptr, nullptr, SAL_RESID_POINTER_COPYFILES }, // POINTER_COPYFILES
2060 { nullptr, IDC_NO, 0 }, // POINTER_NOTALLOWED
2061 { nullptr, nullptr, SAL_RESID_POINTER_DRAW_LINE }, // POINTER_DRAW_LINE
2062 { nullptr, nullptr, SAL_RESID_POINTER_DRAW_RECT }, // POINTER_DRAW_RECT
2063 { nullptr, nullptr, SAL_RESID_POINTER_DRAW_POLYGON }, // POINTER_DRAW_POLYGON
2064 { nullptr, nullptr, SAL_RESID_POINTER_DRAW_BEZIER }, // POINTER_DRAW_BEZIER
2065 { nullptr, nullptr, SAL_RESID_POINTER_DRAW_ARC }, // POINTER_DRAW_ARC
2066 { nullptr, nullptr, SAL_RESID_POINTER_DRAW_PIE }, // POINTER_DRAW_PIE
2067 { nullptr, nullptr, SAL_RESID_POINTER_DRAW_CIRCLECUT }, // POINTER_DRAW_CIRCLECUT
2068 { nullptr, nullptr, SAL_RESID_POINTER_DRAW_ELLIPSE }, // POINTER_DRAW_ELLIPSE
2069 { nullptr, nullptr, SAL_RESID_POINTER_DRAW_FREEHAND }, // POINTER_DRAW_FREEHAND
2070 { nullptr, nullptr, SAL_RESID_POINTER_DRAW_CONNECT }, // POINTER_DRAW_CONNECT
2071 { nullptr, nullptr, SAL_RESID_POINTER_DRAW_TEXT }, // POINTER_DRAW_TEXT
2072 { nullptr, nullptr, SAL_RESID_POINTER_DRAW_CAPTION }, // POINTER_DRAW_CAPTION
2073 { nullptr, nullptr, SAL_RESID_POINTER_CHART }, // POINTER_CHART
2074 { nullptr, nullptr, SAL_RESID_POINTER_DETECTIVE }, // POINTER_DETECTIVE
2075 { nullptr, nullptr, SAL_RESID_POINTER_PIVOT_COL }, // POINTER_PIVOT_COL
2076 { nullptr, nullptr, SAL_RESID_POINTER_PIVOT_ROW }, // POINTER_PIVOT_ROW
2077 { nullptr, nullptr, SAL_RESID_POINTER_PIVOT_FIELD }, // POINTER_PIVOT_FIELD
2078 { nullptr, nullptr, SAL_RESID_POINTER_CHAIN }, // POINTER_CHAIN
2079 { nullptr, nullptr, SAL_RESID_POINTER_CHAIN_NOTALLOWED }, // POINTER_CHAIN_NOTALLOWED
2080 { nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_N }, // POINTER_AUTOSCROLL_N
2081 { nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_S }, // POINTER_AUTOSCROLL_S
2082 { nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_W }, // POINTER_AUTOSCROLL_W
2083 { nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_E }, // POINTER_AUTOSCROLL_E
2084 { nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_NW }, // POINTER_AUTOSCROLL_NW
2085 { nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_NE }, // POINTER_AUTOSCROLL_NE
2086 { nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_SW }, // POINTER_AUTOSCROLL_SW
2087 { nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_SE }, // POINTER_AUTOSCROLL_SE
2088 { nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_NS }, // POINTER_AUTOSCROLL_NS
2089 { nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_WE }, // POINTER_AUTOSCROLL_WE
2090 { nullptr, nullptr, SAL_RESID_POINTER_AUTOSCROLL_NSWE }, // POINTER_AUTOSCROLL_NSWE
2091 { nullptr, nullptr, SAL_RESID_POINTER_TEXT_VERTICAL }, // POINTER_TEXT_VERTICAL
2092 { nullptr, nullptr, SAL_RESID_POINTER_PIVOT_DELETE }, // POINTER_PIVOT_DELETE
2094 // #i32329#
2095 { nullptr, nullptr, SAL_RESID_POINTER_TAB_SELECT_S }, // POINTER_TAB_SELECT_S
2096 { nullptr, nullptr, SAL_RESID_POINTER_TAB_SELECT_E }, // POINTER_TAB_SELECT_E
2097 { nullptr, nullptr, SAL_RESID_POINTER_TAB_SELECT_SE }, // POINTER_TAB_SELECT_SE
2098 { nullptr, nullptr, SAL_RESID_POINTER_TAB_SELECT_W }, // POINTER_TAB_SELECT_W
2099 { nullptr, nullptr, SAL_RESID_POINTER_TAB_SELECT_SW }, // POINTER_TAB_SELECT_SW
2101 { nullptr, nullptr, SAL_RESID_POINTER_HIDEWHITESPACE }, // POINTER_HIDEWHITESPACE
2102 { nullptr, nullptr, SAL_RESID_POINTER_SHOWWHITESPACE } // POINTER_UNHIDEWHITESPACE
2105 // Mousepointer loaded ?
2106 if ( !aImplPtrTab[ePointerStyle].mhCursor )
2108 if ( aImplPtrTab[ePointerStyle].mnOwnId )
2109 aImplPtrTab[ePointerStyle].mhCursor = ImplLoadSalCursor( aImplPtrTab[ePointerStyle].mnOwnId );
2110 else
2111 aImplPtrTab[ePointerStyle].mhCursor = LoadCursor( nullptr, aImplPtrTab[ePointerStyle].mnSysId );
2114 // change the mouse pointer if different
2115 if ( mhCursor != aImplPtrTab[ePointerStyle].mhCursor )
2117 mhCursor = aImplPtrTab[ePointerStyle].mhCursor;
2118 SetCursor( mhCursor );
2122 void WinSalFrame::CaptureMouse( bool bCapture )
2124 // Send this Message to the window, because CaptureMouse() only work
2125 // in the thread of the window, which has create this window
2126 int nMsg;
2127 if ( bCapture )
2128 nMsg = SAL_MSG_CAPTUREMOUSE;
2129 else
2130 nMsg = SAL_MSG_RELEASEMOUSE;
2131 SendMessageW( mhWnd, nMsg, 0, 0 );
2134 void WinSalFrame::SetPointerPos( long nX, long nY )
2136 POINT aPt;
2137 aPt.x = static_cast<int>(nX);
2138 aPt.y = static_cast<int>(nY);
2139 ClientToScreen( mhWnd, &aPt );
2140 SetCursorPos( aPt.x, aPt.y );
2143 void WinSalFrame::Flush()
2145 GdiFlush();
2148 static void ImplSalFrameSetInputContext( HWND hWnd, const SalInputContext* pContext )
2150 WinSalFrame* pFrame = GetWindowPtr( hWnd );
2151 bool bIME(pContext->mnOptions & InputContextFlags::Text);
2152 if ( bIME )
2154 if ( !pFrame->mbIME )
2156 pFrame->mbIME = true;
2158 if ( pFrame->mhDefIMEContext )
2160 ImmAssociateContext( pFrame->mhWnd, pFrame->mhDefIMEContext );
2161 UINT nImeProps = ImmGetProperty( GetKeyboardLayout( 0 ), IGP_PROPERTY );
2162 pFrame->mbSpezIME = (nImeProps & IME_PROP_SPECIAL_UI) != 0;
2163 pFrame->mbAtCursorIME = (nImeProps & IME_PROP_AT_CARET) != 0;
2164 pFrame->mbHandleIME = !pFrame->mbSpezIME;
2168 // When the application can't handle IME messages, then the
2169 // System should handle the IME handling
2170 if ( !(pContext->mnOptions & InputContextFlags::ExtText) )
2171 pFrame->mbHandleIME = false;
2173 // Set the Font for IME Handling
2174 if ( pContext->mpFont )
2176 HIMC hIMC = ImmGetContext( pFrame->mhWnd );
2177 if ( hIMC )
2179 LOGFONTW aLogFont;
2180 HDC hDC = GetDC( pFrame->mhWnd );
2181 // In case of vertical writing, always append a '@' to the
2182 // Windows font name, not only if such a Windows font really is
2183 // available (bTestVerticalAvail == false in the below call):
2184 // The Windows IME's candidates window seems to always use a
2185 // font that has all necessary glyphs, not necessarily the one
2186 // specified by this font name; but it seems to decide whether
2187 // to use that font's horizontal or vertical variant based on a
2188 // '@' in front of this font name.
2189 ImplGetLogFontFromFontSelect(hDC, pContext->mpFont->GetFontSelectPattern(),
2190 nullptr, aLogFont);
2191 ReleaseDC( pFrame->mhWnd, hDC );
2192 ImmSetCompositionFontW( hIMC, &aLogFont );
2193 ImmReleaseContext( pFrame->mhWnd, hIMC );
2197 else
2199 if ( pFrame->mbIME )
2201 pFrame->mbIME = false;
2202 pFrame->mbHandleIME = false;
2203 ImmAssociateContext( pFrame->mhWnd, nullptr );
2208 void WinSalFrame::SetInputContext( SalInputContext* pContext )
2210 // Must be called in the main thread!
2211 SendMessageW( mhWnd, SAL_MSG_SETINPUTCONTEXT, 0, reinterpret_cast<LPARAM>(pContext) );
2214 static void ImplSalFrameEndExtTextInput( HWND hWnd, EndExtTextInputFlags nFlags )
2216 HIMC hIMC = ImmGetContext( hWnd );
2217 if ( hIMC )
2219 DWORD nIndex;
2220 if ( nFlags & EndExtTextInputFlags::Complete )
2221 nIndex = CPS_COMPLETE;
2222 else
2223 nIndex = CPS_CANCEL;
2225 ImmNotifyIME( hIMC, NI_COMPOSITIONSTR, nIndex, 0 );
2226 ImmReleaseContext( hWnd, hIMC );
2230 void WinSalFrame::EndExtTextInput( EndExtTextInputFlags nFlags )
2232 // Must be called in the main thread!
2233 SendMessageW( mhWnd, SAL_MSG_ENDEXTTEXTINPUT, static_cast<WPARAM>(nFlags), 0 );
2236 static void ImplGetKeyNameText( LONG lParam, sal_Unicode* pBuf,
2237 UINT& rCount, UINT nMaxSize,
2238 const sal_Char* pReplace )
2240 static_assert( sizeof( WCHAR ) == sizeof( sal_Unicode ), "must be the same size" );
2242 static const int nMaxKeyLen = 350;
2243 WCHAR aKeyBuf[ nMaxKeyLen ];
2244 int nKeyLen = 0;
2245 if ( lParam )
2247 OUString aLang = Application::GetSettings().GetUILanguageTag().getLanguage();
2248 OUString aRet;
2250 aRet = ::vcl_sal::getKeysReplacementName( aLang, lParam );
2251 if( aRet.isEmpty() )
2253 nKeyLen = GetKeyNameTextW( lParam, aKeyBuf, nMaxKeyLen );
2254 SAL_WARN_IF( nKeyLen > nMaxKeyLen, "vcl", "Invalid key name length!" );
2255 if( nKeyLen > nMaxKeyLen )
2256 nKeyLen = 0;
2257 else if( nKeyLen > 0 )
2259 // Capitalize just the first letter of key names
2260 CharLowerBuffW( aKeyBuf, nKeyLen );
2262 bool bUpper = true;
2263 for( WCHAR *pW=aKeyBuf, *pE=pW+nKeyLen; pW < pE; ++pW )
2265 if( bUpper )
2266 CharUpperBuffW( pW, 1 );
2267 bUpper = (*pW=='+') || (*pW=='-') || (*pW==' ') || (*pW=='.');
2271 else
2273 nKeyLen = aRet.getLength();
2274 wcscpy( aKeyBuf, o3tl::toW( aRet.getStr() ));
2278 if ( (nKeyLen > 0) || pReplace )
2280 if( (rCount > 0) && (rCount < nMaxSize) )
2282 pBuf[rCount] = '+';
2283 rCount++;
2286 if( nKeyLen > 0 )
2288 WCHAR *pW = aKeyBuf, *pE = aKeyBuf + nKeyLen;
2289 while ((pW < pE) && *pW && (rCount < nMaxSize))
2290 pBuf[rCount++] = *pW++;
2292 else // fall back to provided default name
2294 while( *pReplace && (rCount < nMaxSize) )
2296 pBuf[rCount] = *pReplace;
2297 rCount++;
2298 pReplace++;
2302 else
2303 rCount = 0;
2306 OUString WinSalFrame::GetKeyName( sal_uInt16 nKeyCode )
2308 static const UINT nMaxKeyLen = 350;
2309 sal_Unicode aKeyBuf[ nMaxKeyLen ];
2310 UINT nKeyBufLen = 0;
2311 UINT nSysCode = 0;
2313 if ( nKeyCode & KEY_MOD1 )
2315 nSysCode = MapVirtualKeyW( VK_CONTROL, 0 );
2316 nSysCode = (nSysCode << 16) | ((sal_uLong(1)) << 25);
2317 ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, "Ctrl" );
2320 if ( nKeyCode & KEY_MOD2 )
2322 nSysCode = MapVirtualKeyW( VK_MENU, 0 );
2323 nSysCode = (nSysCode << 16) | ((sal_uLong(1)) << 25);
2324 ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, "Alt" );
2327 if ( nKeyCode & KEY_SHIFT )
2329 nSysCode = MapVirtualKeyW( VK_SHIFT, 0 );
2330 nSysCode = (nSysCode << 16) | ((sal_uLong(1)) << 25);
2331 ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, "Shift" );
2334 sal_uInt16 nCode = nKeyCode & 0x0FFF;
2335 sal_uLong nSysCode2 = 0;
2336 const sal_Char* pReplace = nullptr;
2337 sal_Unicode cSVCode = 0;
2338 sal_Char aFBuf[4];
2339 nSysCode = 0;
2341 if ( (nCode >= KEY_0) && (nCode <= KEY_9) )
2342 cSVCode = '0' + (nCode - KEY_0);
2343 else if ( (nCode >= KEY_A) && (nCode <= KEY_Z) )
2344 cSVCode = 'A' + (nCode - KEY_A);
2345 else if ( (nCode >= KEY_F1) && (nCode <= KEY_F26) )
2347 nSysCode = VK_F1 + (nCode - KEY_F1);
2348 aFBuf[0] = 'F';
2349 if (nCode <= KEY_F9)
2351 aFBuf[1] = sal::static_int_cast<sal_Char>('1' + (nCode - KEY_F1));
2352 aFBuf[2] = 0;
2354 else if (nCode <= KEY_F19)
2356 aFBuf[1] = '1';
2357 aFBuf[2] = sal::static_int_cast<sal_Char>('0' + (nCode - KEY_F10));
2358 aFBuf[3] = 0;
2360 else
2362 aFBuf[1] = '2';
2363 aFBuf[2] = sal::static_int_cast<sal_Char>('0' + (nCode - KEY_F20));
2364 aFBuf[3] = 0;
2366 pReplace = aFBuf;
2368 else
2370 switch ( nCode )
2372 case KEY_DOWN:
2373 nSysCode = VK_DOWN;
2374 nSysCode2 = ((sal_uLong(1)) << 24);
2375 pReplace = "Down";
2376 break;
2377 case KEY_UP:
2378 nSysCode = VK_UP;
2379 nSysCode2 = ((sal_uLong(1)) << 24);
2380 pReplace = "Up";
2381 break;
2382 case KEY_LEFT:
2383 nSysCode = VK_LEFT;
2384 nSysCode2 = ((sal_uLong(1)) << 24);
2385 pReplace = "Left";
2386 break;
2387 case KEY_RIGHT:
2388 nSysCode = VK_RIGHT;
2389 nSysCode2 = ((sal_uLong(1)) << 24);
2390 pReplace = "Right";
2391 break;
2392 case KEY_HOME:
2393 nSysCode = VK_HOME;
2394 nSysCode2 = ((sal_uLong(1)) << 24);
2395 pReplace = "Home";
2396 break;
2397 case KEY_END:
2398 nSysCode = VK_END;
2399 nSysCode2 = ((sal_uLong(1)) << 24);
2400 pReplace = "End";
2401 break;
2402 case KEY_PAGEUP:
2403 nSysCode = VK_PRIOR;
2404 nSysCode2 = ((sal_uLong(1)) << 24);
2405 pReplace = "Page Up";
2406 break;
2407 case KEY_PAGEDOWN:
2408 nSysCode = VK_NEXT;
2409 nSysCode2 = ((sal_uLong(1)) << 24);
2410 pReplace = "Page Down";
2411 break;
2412 case KEY_RETURN:
2413 nSysCode = VK_RETURN;
2414 pReplace = "Enter";
2415 break;
2416 case KEY_ESCAPE:
2417 nSysCode = VK_ESCAPE;
2418 pReplace = "Escape";
2419 break;
2420 case KEY_TAB:
2421 nSysCode = VK_TAB;
2422 pReplace = "Tab";
2423 break;
2424 case KEY_BACKSPACE:
2425 nSysCode = VK_BACK;
2426 pReplace = "Backspace";
2427 break;
2428 case KEY_SPACE:
2429 nSysCode = VK_SPACE;
2430 pReplace = "Space";
2431 break;
2432 case KEY_INSERT:
2433 nSysCode = VK_INSERT;
2434 nSysCode2 = ((sal_uLong(1)) << 24);
2435 pReplace = "Insert";
2436 break;
2437 case KEY_DELETE:
2438 nSysCode = VK_DELETE;
2439 nSysCode2 = ((sal_uLong(1)) << 24);
2440 pReplace = "Delete";
2441 break;
2443 case KEY_ADD:
2444 cSVCode = '+';
2445 break;
2446 case KEY_SUBTRACT:
2447 cSVCode = '-';
2448 break;
2449 case KEY_MULTIPLY:
2450 cSVCode = '*';
2451 break;
2452 case KEY_DIVIDE:
2453 cSVCode = '/';
2454 break;
2455 case KEY_POINT:
2456 cSVCode = '.';
2457 break;
2458 case KEY_COMMA:
2459 cSVCode = ',';
2460 break;
2461 case KEY_LESS:
2462 cSVCode = '<';
2463 break;
2464 case KEY_GREATER:
2465 cSVCode = '>';
2466 break;
2467 case KEY_EQUAL:
2468 cSVCode = '=';
2469 break;
2470 case KEY_SEMICOLON:
2471 cSVCode = ';';
2472 break;
2473 case KEY_QUOTERIGHT:
2474 cSVCode = '\'';
2475 break;
2476 case KEY_BRACKETLEFT:
2477 cSVCode = '[';
2478 break;
2479 case KEY_BRACKETRIGHT:
2480 cSVCode = ']';
2481 break;
2485 if ( nSysCode )
2487 nSysCode = MapVirtualKeyW( nSysCode, 0 );
2488 if ( nSysCode )
2489 nSysCode = (nSysCode << 16) | nSysCode2;
2490 ImplGetKeyNameText( nSysCode, aKeyBuf, nKeyBufLen, nMaxKeyLen, pReplace );
2492 else
2494 if ( cSVCode )
2496 if ( nKeyBufLen > 0 )
2497 aKeyBuf[ nKeyBufLen++ ] = '+';
2498 if( nKeyBufLen < nMaxKeyLen )
2499 aKeyBuf[ nKeyBufLen++ ] = cSVCode;
2503 if( !nKeyBufLen )
2504 return OUString();
2506 return OUString( aKeyBuf, sal::static_int_cast< sal_uInt16 >(nKeyBufLen) );
2509 static Color ImplWinColorToSal( COLORREF nColor )
2511 return Color( GetRValue( nColor ), GetGValue( nColor ), GetBValue( nColor ) );
2514 static void ImplSalUpdateStyleFontW( HDC hDC, const LOGFONTW& rLogFont, vcl::Font& rFont )
2516 ImplSalLogFontToFontW( hDC, rLogFont, rFont );
2518 // On Windows 9x, Windows NT we get sometimes very small sizes
2519 // (for example for the small Caption height).
2520 // So if it is MS Sans Serif, a none scalable font we use
2521 // 8 Point as the minimum control height, in all other cases
2522 // 6 Point is the smallest one
2523 if ( rFont.GetFontHeight() < 8 )
2525 if ( rtl_ustr_compareIgnoreAsciiCase( o3tl::toU(rLogFont.lfFaceName), o3tl::toU(L"MS Sans Serif") ) == 0 )
2526 rFont.SetFontHeight( 8 );
2527 else if ( rFont.GetFontHeight() < 6 )
2528 rFont.SetFontHeight( 6 );
2532 static long ImplW2I( const wchar_t* pStr )
2534 long n = 0;
2535 int nSign = 1;
2537 if ( *pStr == '-' )
2539 nSign = -1;
2540 pStr++;
2543 while( (*pStr >= 48) && (*pStr <= 57) )
2545 n *= 10;
2546 n += ((*pStr) - 48);
2547 pStr++;
2550 n *= nSign;
2552 return n;
2555 void WinSalFrame::UpdateSettings( AllSettings& rSettings )
2557 MouseSettings aMouseSettings = rSettings.GetMouseSettings();
2558 aMouseSettings.SetDoubleClickTime( GetDoubleClickTime() );
2559 aMouseSettings.SetDoubleClickWidth( GetSystemMetrics( SM_CXDOUBLECLK ) );
2560 aMouseSettings.SetDoubleClickHeight( GetSystemMetrics( SM_CYDOUBLECLK ) );
2561 long nDragWidth = GetSystemMetrics( SM_CXDRAG );
2562 long nDragHeight = GetSystemMetrics( SM_CYDRAG );
2563 if ( nDragWidth )
2564 aMouseSettings.SetStartDragWidth( nDragWidth );
2565 if ( nDragHeight )
2566 aMouseSettings.SetStartDragHeight( nDragHeight );
2567 HKEY hRegKey;
2568 if ( RegOpenKeyW( HKEY_CURRENT_USER,
2569 L"Control Panel\\Desktop",
2570 &hRegKey ) == ERROR_SUCCESS )
2572 wchar_t aValueBuf[10];
2573 DWORD nValueSize = sizeof( aValueBuf );
2574 DWORD nType;
2575 if ( RegQueryValueExW( hRegKey, L"MenuShowDelay", nullptr,
2576 &nType, reinterpret_cast<LPBYTE>(aValueBuf), &nValueSize ) == ERROR_SUCCESS )
2578 if ( nType == REG_SZ )
2579 aMouseSettings.SetMenuDelay( static_cast<sal_uLong>(ImplW2I( aValueBuf )) );
2582 RegCloseKey( hRegKey );
2585 StyleSettings aStyleSettings = rSettings.GetStyleSettings();
2587 aStyleSettings.SetScrollBarSize( GetSystemMetrics( SM_CXVSCROLL ) );
2588 aStyleSettings.SetSpinSize( GetSystemMetrics( SM_CXVSCROLL ) );
2589 UINT blinkTime = GetCaretBlinkTime();
2590 aStyleSettings.SetCursorBlinkTime(
2591 blinkTime == 0 || blinkTime == INFINITE // 0 indicates error
2592 ? STYLE_CURSOR_NOBLINKTIME : blinkTime );
2593 aStyleSettings.SetFloatTitleHeight( GetSystemMetrics( SM_CYSMCAPTION ) );
2594 aStyleSettings.SetTitleHeight( GetSystemMetrics( SM_CYCAPTION ) );
2595 aStyleSettings.SetActiveBorderColor( ImplWinColorToSal( GetSysColor( COLOR_ACTIVEBORDER ) ) );
2596 aStyleSettings.SetDeactiveBorderColor( ImplWinColorToSal( GetSysColor( COLOR_INACTIVEBORDER ) ) );
2597 aStyleSettings.SetDeactiveColor( ImplWinColorToSal( GetSysColor( COLOR_GRADIENTINACTIVECAPTION ) ) );
2598 aStyleSettings.SetFaceColor( ImplWinColorToSal( GetSysColor( COLOR_3DFACE ) ) );
2599 aStyleSettings.SetInactiveTabColor( aStyleSettings.GetFaceColor() );
2600 aStyleSettings.SetLightColor( ImplWinColorToSal( GetSysColor( COLOR_3DHILIGHT ) ) );
2601 aStyleSettings.SetLightBorderColor( ImplWinColorToSal( GetSysColor( COLOR_3DLIGHT ) ) );
2602 aStyleSettings.SetShadowColor( ImplWinColorToSal( GetSysColor( COLOR_3DSHADOW ) ) );
2603 aStyleSettings.SetDarkShadowColor( ImplWinColorToSal( GetSysColor( COLOR_3DDKSHADOW ) ) );
2604 aStyleSettings.SetHelpColor( ImplWinColorToSal( GetSysColor( COLOR_INFOBK ) ) );
2605 aStyleSettings.SetHelpTextColor( ImplWinColorToSal( GetSysColor( COLOR_INFOTEXT ) ) );
2607 aStyleSettings.SetDialogColor( aStyleSettings.GetFaceColor() );
2609 aStyleSettings.SetDialogTextColor( aStyleSettings.GetButtonTextColor() );
2610 aStyleSettings.SetButtonTextColor( ImplWinColorToSal( GetSysColor( COLOR_BTNTEXT ) ) );
2611 aStyleSettings.SetDefaultActionButtonTextColor( ImplWinColorToSal( GetSysColor( COLOR_BTNTEXT ) ) );
2612 aStyleSettings.SetActionButtonTextColor( aStyleSettings.GetDefaultActionButtonTextColor() );
2613 aStyleSettings.SetActionButtonRolloverTextColor( aStyleSettings.GetActionButtonTextColor() );
2614 aStyleSettings.SetButtonRolloverTextColor( aStyleSettings.GetButtonTextColor() );
2615 aStyleSettings.SetButtonPressedRolloverTextColor( aStyleSettings.GetButtonTextColor() );
2616 aStyleSettings.SetTabTextColor( aStyleSettings.GetButtonTextColor() );
2617 aStyleSettings.SetTabRolloverTextColor( aStyleSettings.GetButtonTextColor() );
2618 aStyleSettings.SetTabHighlightTextColor( aStyleSettings.GetButtonTextColor() );
2619 aStyleSettings.SetRadioCheckTextColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOWTEXT ) ) );
2620 aStyleSettings.SetGroupTextColor( aStyleSettings.GetRadioCheckTextColor() );
2621 aStyleSettings.SetLabelTextColor( aStyleSettings.GetRadioCheckTextColor() );
2622 aStyleSettings.SetWindowColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOW ) ) );
2623 aStyleSettings.SetActiveTabColor( aStyleSettings.GetWindowColor() );
2624 aStyleSettings.SetWindowTextColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOWTEXT ) ) );
2625 aStyleSettings.SetToolTextColor( ImplWinColorToSal( GetSysColor( COLOR_WINDOWTEXT ) ) );
2626 aStyleSettings.SetFieldColor( aStyleSettings.GetWindowColor() );
2627 aStyleSettings.SetFieldTextColor( aStyleSettings.GetWindowTextColor() );
2628 aStyleSettings.SetFieldRolloverTextColor( aStyleSettings.GetFieldTextColor() );
2629 aStyleSettings.SetHighlightColor( ImplWinColorToSal( GetSysColor( COLOR_HIGHLIGHT ) ) );
2630 aStyleSettings.SetHighlightTextColor( ImplWinColorToSal( GetSysColor( COLOR_HIGHLIGHTTEXT ) ) );
2631 aStyleSettings.SetMenuHighlightColor( aStyleSettings.GetHighlightColor() );
2632 aStyleSettings.SetMenuHighlightTextColor( aStyleSettings.GetHighlightTextColor() );
2634 ImplSVData* pSVData = ImplGetSVData();
2635 pSVData->maNWFData.mnMenuFormatBorderX = 0;
2636 pSVData->maNWFData.mnMenuFormatBorderY = 0;
2637 pSVData->maNWFData.maMenuBarHighlightTextColor = COL_TRANSPARENT;
2638 GetSalData()->mbThemeMenuSupport = false;
2639 if (officecfg::Office::Common::Accessibility::AutoDetectSystemHC::get())
2641 aStyleSettings.SetShadowColor( ImplWinColorToSal( GetSysColor( COLOR_ACTIVEBORDER ) ) );
2642 aStyleSettings.SetWorkspaceColor( ImplWinColorToSal( GetSysColor( COLOR_MENU ) ) );
2644 aStyleSettings.SetMenuColor( ImplWinColorToSal( GetSysColor( COLOR_MENU ) ) );
2645 aStyleSettings.SetMenuBarColor( aStyleSettings.GetMenuColor() );
2646 aStyleSettings.SetMenuBarRolloverColor( aStyleSettings.GetHighlightColor() );
2647 aStyleSettings.SetMenuBorderColor( aStyleSettings.GetLightBorderColor() ); // overridden below for flat menus
2648 aStyleSettings.SetUseFlatBorders( false );
2649 aStyleSettings.SetUseFlatMenus( false );
2650 aStyleSettings.SetMenuTextColor( ImplWinColorToSal( GetSysColor( COLOR_MENUTEXT ) ) );
2651 if ( boost::optional<Color> aColor = aStyleSettings.GetPersonaMenuBarTextColor() )
2653 aStyleSettings.SetMenuBarTextColor( *aColor );
2654 aStyleSettings.SetMenuBarRolloverTextColor( *aColor );
2656 else
2658 aStyleSettings.SetMenuBarTextColor( ImplWinColorToSal( GetSysColor( COLOR_MENUTEXT ) ) );
2659 aStyleSettings.SetMenuBarRolloverTextColor( ImplWinColorToSal( GetSysColor( COLOR_HIGHLIGHTTEXT ) ) );
2661 aStyleSettings.SetMenuBarHighlightTextColor(aStyleSettings.GetMenuHighlightTextColor());
2662 aStyleSettings.SetActiveColor( ImplWinColorToSal( GetSysColor( COLOR_ACTIVECAPTION ) ) );
2663 aStyleSettings.SetActiveTextColor( ImplWinColorToSal( GetSysColor( COLOR_CAPTIONTEXT ) ) );
2664 aStyleSettings.SetDeactiveColor( ImplWinColorToSal( GetSysColor( COLOR_INACTIVECAPTION ) ) );
2665 aStyleSettings.SetDeactiveTextColor( ImplWinColorToSal( GetSysColor( COLOR_INACTIVECAPTIONTEXT ) ) );
2666 BOOL bFlatMenus = FALSE;
2667 SystemParametersInfoW( SPI_GETFLATMENU, 0, &bFlatMenus, 0);
2668 if( bFlatMenus )
2670 aStyleSettings.SetUseFlatMenus( true );
2671 aStyleSettings.SetMenuBarColor( ImplWinColorToSal( GetSysColor( COLOR_MENUBAR ) ) );
2672 aStyleSettings.SetMenuHighlightColor( ImplWinColorToSal( GetSysColor( COLOR_MENUHILIGHT ) ) );
2673 aStyleSettings.SetMenuBarRolloverColor( ImplWinColorToSal( GetSysColor( COLOR_MENUHILIGHT ) ) );
2674 aStyleSettings.SetMenuBorderColor( ImplWinColorToSal( GetSysColor( COLOR_3DSHADOW ) ) );
2676 // flat borders for our controls etc. as well in this mode (ie, no 3d borders)
2677 // this is not active in the classic style appearance
2678 aStyleSettings.SetUseFlatBorders( true );
2680 aStyleSettings.SetCheckedColorSpecialCase( );
2682 // caret width
2683 DWORD nCaretWidth = 2;
2684 if( SystemParametersInfoW( SPI_GETCARETWIDTH, 0, &nCaretWidth, 0 ) )
2685 aStyleSettings.SetCursorSize( nCaretWidth );
2687 // High contrast
2688 HIGHCONTRAST hc;
2689 hc.cbSize = sizeof( HIGHCONTRAST );
2690 if( SystemParametersInfoW( SPI_GETHIGHCONTRAST, hc.cbSize, &hc, 0 )
2691 && (hc.dwFlags & HCF_HIGHCONTRASTON) )
2692 aStyleSettings.SetHighContrastMode( true );
2693 else
2694 aStyleSettings.SetHighContrastMode( false );
2696 // Query Fonts
2697 vcl::Font aMenuFont = aStyleSettings.GetMenuFont();
2698 vcl::Font aTitleFont = aStyleSettings.GetTitleFont();
2699 vcl::Font aFloatTitleFont = aStyleSettings.GetFloatTitleFont();
2700 vcl::Font aHelpFont = aStyleSettings.GetHelpFont();
2701 vcl::Font aAppFont = aStyleSettings.GetAppFont();
2702 vcl::Font aIconFont = aStyleSettings.GetIconFont();
2703 HDC hDC = GetDC( nullptr );
2704 NONCLIENTMETRICSW aNonClientMetrics;
2705 aNonClientMetrics.cbSize = sizeof( aNonClientMetrics );
2706 if ( SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, sizeof( aNonClientMetrics ), &aNonClientMetrics, 0 ) )
2708 ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfMenuFont, aMenuFont );
2709 ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfCaptionFont, aTitleFont );
2710 ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfSmCaptionFont, aFloatTitleFont );
2711 ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfStatusFont, aHelpFont );
2712 ImplSalUpdateStyleFontW( hDC, aNonClientMetrics.lfMessageFont, aAppFont );
2714 LOGFONTW aLogFont;
2715 if ( SystemParametersInfoW( SPI_GETICONTITLELOGFONT, 0, &aLogFont, 0 ) )
2716 ImplSalUpdateStyleFontW( hDC, aLogFont, aIconFont );
2719 ReleaseDC( nullptr, hDC );
2721 aStyleSettings.SetToolbarIconSize(ToolbarIconSize::Large);
2723 aStyleSettings.BatchSetFonts( aAppFont, aAppFont );
2725 aStyleSettings.SetMenuFont( aMenuFont );
2726 aStyleSettings.SetTitleFont( aTitleFont );
2727 aStyleSettings.SetFloatTitleFont( aFloatTitleFont );
2728 aStyleSettings.SetHelpFont( aHelpFont );
2729 aStyleSettings.SetIconFont( aIconFont );
2731 if ( aAppFont.GetWeight() > WEIGHT_NORMAL )
2732 aAppFont.SetWeight( WEIGHT_NORMAL );
2733 aStyleSettings.SetToolFont( aAppFont );
2734 aStyleSettings.SetTabFont( aAppFont );
2736 BOOL bDragFull;
2737 if ( SystemParametersInfoW( SPI_GETDRAGFULLWINDOWS, 0, &bDragFull, 0 ) )
2739 DragFullOptions nDragFullOptions = aStyleSettings.GetDragFullOptions();
2740 if ( bDragFull )
2741 nDragFullOptions |= DragFullOptions::WindowMove | DragFullOptions::WindowSize | DragFullOptions::Docking | DragFullOptions::Split;
2742 else
2743 nDragFullOptions &= ~DragFullOptions(DragFullOptions::WindowMove | DragFullOptions::WindowSize | DragFullOptions::Docking | DragFullOptions::Split);
2744 aStyleSettings.SetDragFullOptions( nDragFullOptions );
2747 if ( RegOpenKeyW( HKEY_CURRENT_USER,
2748 L"Control Panel\\International\\Calendars\\TwoDigitYearMax",
2749 &hRegKey ) == ERROR_SUCCESS )
2751 wchar_t aValueBuf[10];
2752 DWORD nValue;
2753 DWORD nValueSize = sizeof( aValueBuf );
2754 DWORD nType;
2755 if ( RegQueryValueExW( hRegKey, L"1", nullptr,
2756 &nType, reinterpret_cast<LPBYTE>(aValueBuf), &nValueSize ) == ERROR_SUCCESS )
2758 if ( nType == REG_SZ )
2760 nValue = static_cast<sal_uLong>(ImplW2I( aValueBuf ));
2761 if ( (nValue > 1000) && (nValue < 10000) )
2763 MiscSettings aMiscSettings = rSettings.GetMiscSettings();
2764 utl::MiscCfg().SetYear2000( static_cast<sal_Int32>(nValue-99) );
2765 rSettings.SetMiscSettings( aMiscSettings );
2770 RegCloseKey( hRegKey );
2773 rSettings.SetMouseSettings( aMouseSettings );
2774 rSettings.SetStyleSettings( aStyleSettings );
2776 // now apply the values from theming, if available
2777 WinSalGraphics::updateSettingsNative( rSettings );
2780 const SystemEnvData* WinSalFrame::GetSystemData() const
2782 return &maSysData;
2785 void WinSalFrame::Beep()
2787 // a simple beep
2788 MessageBeep( 0 );
2791 SalFrame::SalPointerState WinSalFrame::GetPointerState()
2793 SalPointerState aState;
2794 aState.mnState = 0;
2796 if ( GetKeyState( VK_LBUTTON ) & 0x8000 )
2797 aState.mnState |= MOUSE_LEFT;
2798 if ( GetKeyState( VK_MBUTTON ) & 0x8000 )
2799 aState.mnState |= MOUSE_MIDDLE;
2800 if ( GetKeyState( VK_RBUTTON ) & 0x8000 )
2801 aState.mnState |= MOUSE_RIGHT;
2802 if ( GetKeyState( VK_SHIFT ) & 0x8000 )
2803 aState.mnState |= KEY_SHIFT;
2804 if ( GetKeyState( VK_CONTROL ) & 0x8000 )
2805 aState.mnState |= KEY_MOD1;
2806 if ( GetKeyState( VK_MENU ) & 0x8000 )
2807 aState.mnState |= KEY_MOD2;
2809 POINT pt;
2810 GetCursorPos( &pt );
2812 aState.maPos = Point( pt.x - maGeometry.nX, pt.y - maGeometry.nY );
2813 return aState;
2816 KeyIndicatorState WinSalFrame::GetIndicatorState()
2818 KeyIndicatorState aState = KeyIndicatorState::NONE;
2819 if (::GetKeyState(VK_CAPITAL))
2820 aState |= KeyIndicatorState::CAPSLOCK;
2822 if (::GetKeyState(VK_NUMLOCK))
2823 aState |= KeyIndicatorState::NUMLOCK;
2825 if (::GetKeyState(VK_SCROLL))
2826 aState |= KeyIndicatorState::SCROLLLOCK;
2828 return aState;
2831 void WinSalFrame::SimulateKeyPress( sal_uInt16 nKeyCode )
2833 BYTE nVKey = 0;
2834 switch (nKeyCode)
2836 case KEY_CAPSLOCK:
2837 nVKey = VK_CAPITAL;
2838 break;
2841 if (nVKey > 0 && nVKey < 255)
2843 ::keybd_event(nVKey, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
2844 ::keybd_event(nVKey, 0x45, KEYEVENTF_EXTENDEDKEY|KEYEVENTF_KEYUP, 0);
2848 void WinSalFrame::ResetClipRegion()
2850 SetWindowRgn( mhWnd, nullptr, TRUE );
2853 void WinSalFrame::BeginSetClipRegion( sal_uInt32 nRects )
2855 if( mpClipRgnData )
2856 delete [] reinterpret_cast<BYTE*>(mpClipRgnData);
2857 sal_uLong nRectBufSize = sizeof(RECT)*nRects;
2858 mpClipRgnData = reinterpret_cast<RGNDATA*>(new BYTE[sizeof(RGNDATA)-1+nRectBufSize]);
2859 mpClipRgnData->rdh.dwSize = sizeof( RGNDATAHEADER );
2860 mpClipRgnData->rdh.iType = RDH_RECTANGLES;
2861 mpClipRgnData->rdh.nCount = nRects;
2862 mpClipRgnData->rdh.nRgnSize = nRectBufSize;
2863 SetRectEmpty( &(mpClipRgnData->rdh.rcBound) );
2864 mpNextClipRect = reinterpret_cast<RECT*>(&(mpClipRgnData->Buffer));
2865 mbFirstClipRect = true;
2868 void WinSalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight )
2870 if( ! mpClipRgnData )
2871 return;
2873 RECT* pRect = mpNextClipRect;
2874 RECT* pBoundRect = &(mpClipRgnData->rdh.rcBound);
2875 long nRight = nX + nWidth;
2876 long nBottom = nY + nHeight;
2878 if ( mbFirstClipRect )
2880 pBoundRect->left = nX;
2881 pBoundRect->top = nY;
2882 pBoundRect->right = nRight;
2883 pBoundRect->bottom = nBottom;
2884 mbFirstClipRect = false;
2886 else
2888 if ( nX < pBoundRect->left )
2889 pBoundRect->left = static_cast<int>(nX);
2891 if ( nY < pBoundRect->top )
2892 pBoundRect->top = static_cast<int>(nY);
2894 if ( nRight > pBoundRect->right )
2895 pBoundRect->right = static_cast<int>(nRight);
2897 if ( nBottom > pBoundRect->bottom )
2898 pBoundRect->bottom = static_cast<int>(nBottom);
2901 pRect->left = static_cast<int>(nX);
2902 pRect->top = static_cast<int>(nY);
2903 pRect->right = static_cast<int>(nRight);
2904 pRect->bottom = static_cast<int>(nBottom);
2905 if( (mpNextClipRect - reinterpret_cast<RECT*>(&mpClipRgnData->Buffer)) < static_cast<int>(mpClipRgnData->rdh.nCount) )
2906 mpNextClipRect++;
2909 void WinSalFrame::EndSetClipRegion()
2911 if( ! mpClipRgnData )
2912 return;
2914 HRGN hRegion;
2916 // create region from accumulated rectangles
2917 if ( mpClipRgnData->rdh.nCount == 1 )
2919 RECT* pRect = &(mpClipRgnData->rdh.rcBound);
2920 hRegion = CreateRectRgn( pRect->left, pRect->top,
2921 pRect->right, pRect->bottom );
2923 else
2925 sal_uLong nSize = mpClipRgnData->rdh.nRgnSize+sizeof(RGNDATAHEADER);
2926 hRegion = ExtCreateRegion( nullptr, nSize, mpClipRgnData );
2928 delete [] reinterpret_cast<BYTE*>(mpClipRgnData);
2929 mpClipRgnData = nullptr;
2931 SAL_WARN_IF( !hRegion, "vcl", "WinSalFrame::EndSetClipRegion() - Can't create ClipRegion" );
2932 if( hRegion )
2934 RECT aWindowRect;
2935 GetWindowRect( mhWnd, &aWindowRect );
2936 POINT aPt;
2937 aPt.x=0;
2938 aPt.y=0;
2939 ClientToScreen( mhWnd, &aPt );
2940 OffsetRgn( hRegion, aPt.x - aWindowRect.left, aPt.y - aWindowRect.top );
2942 if( SetWindowRgn( mhWnd, hRegion, TRUE ) == 0 )
2943 DeleteObject( hRegion );
2947 static bool ImplHandleMouseMsg( HWND hWnd, UINT nMsg,
2948 WPARAM wParam, LPARAM lParam )
2950 WinSalFrame* pFrame = GetWindowPtr( hWnd );
2951 if ( !pFrame )
2952 return false;
2954 if( nMsg == WM_LBUTTONDOWN || nMsg == WM_MBUTTONDOWN || nMsg == WM_RBUTTONDOWN )
2956 // #103168# post again if async focus has not arrived yet
2957 // hopefully we will not receive the corresponding button up before this
2958 // button down arrives again
2959 vcl::Window *pWin = pFrame->GetWindow();
2960 if( pWin && pWin->ImplGetWindowImpl()->mpFrameData->mnFocusId )
2962 BOOL const ret = PostMessageW( hWnd, nMsg, wParam, lParam );
2963 SAL_WARN_IF(0 == ret, "vcl", "ERROR: PostMessage() failed!");
2964 return true;
2967 SalMouseEvent aMouseEvt;
2968 bool nRet;
2969 SalEvent nEvent = SalEvent::NONE;
2970 bool bCall = true;
2972 aMouseEvt.mnX = static_cast<short>(LOWORD( lParam ));
2973 aMouseEvt.mnY = static_cast<short>(HIWORD( lParam ));
2974 aMouseEvt.mnCode = 0;
2975 aMouseEvt.mnTime = GetMessageTime();
2977 // Use GetKeyState(), as some Logitech mouse drivers do not check
2978 // KeyState when simulating double-click with center mouse button
2980 if ( GetKeyState( VK_LBUTTON ) & 0x8000 )
2981 aMouseEvt.mnCode |= MOUSE_LEFT;
2982 if ( GetKeyState( VK_MBUTTON ) & 0x8000 )
2983 aMouseEvt.mnCode |= MOUSE_MIDDLE;
2984 if ( GetKeyState( VK_RBUTTON ) & 0x8000 )
2985 aMouseEvt.mnCode |= MOUSE_RIGHT;
2986 if ( GetKeyState( VK_SHIFT ) & 0x8000 )
2987 aMouseEvt.mnCode |= KEY_SHIFT;
2988 if ( GetKeyState( VK_CONTROL ) & 0x8000 )
2989 aMouseEvt.mnCode |= KEY_MOD1;
2990 if ( GetKeyState( VK_MENU ) & 0x8000 )
2991 aMouseEvt.mnCode |= KEY_MOD2;
2993 switch ( nMsg )
2995 case WM_MOUSEMOVE:
2997 // As the mouse events are not collected correctly when
2998 // pressing modifier keys (as interrupted by KeyEvents)
2999 // we do this here ourselves
3000 if ( aMouseEvt.mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2) )
3002 MSG aTempMsg;
3003 if ( PeekMessageW( &aTempMsg, hWnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE | PM_NOYIELD ) )
3005 if ( (aTempMsg.message == WM_MOUSEMOVE) &&
3006 (aTempMsg.wParam == wParam) )
3007 return true;
3011 SalData* pSalData = GetSalData();
3012 // Test for MouseLeave
3013 if ( pSalData->mhWantLeaveMsg && (pSalData->mhWantLeaveMsg != hWnd) )
3014 SendMessageW( pSalData->mhWantLeaveMsg, SAL_MSG_MOUSELEAVE, 0, GetMessagePos() );
3016 pSalData->mhWantLeaveMsg = hWnd;
3017 // Start MouseLeave-Timer
3018 if ( !pSalData->mpMouseLeaveTimer )
3020 pSalData->mpMouseLeaveTimer = new AutoTimer;
3021 pSalData->mpMouseLeaveTimer->SetDebugName( "ImplHandleMouseMsg SalData::mpMouseLeaveTimer" );
3022 pSalData->mpMouseLeaveTimer->SetTimeout( SAL_MOUSELEAVE_TIMEOUT );
3023 pSalData->mpMouseLeaveTimer->Start();
3024 // We don't need to set a timeout handler, because we test
3025 // for mouseleave in the timeout callback
3027 aMouseEvt.mnButton = 0;
3028 nEvent = SalEvent::MouseMove;
3030 break;
3032 case WM_NCMOUSEMOVE:
3033 case SAL_MSG_MOUSELEAVE:
3035 SalData* pSalData = GetSalData();
3036 if ( pSalData->mhWantLeaveMsg == hWnd )
3038 // Mouse-Coordinates are relative to the screen
3039 POINT aPt;
3040 aPt.x = static_cast<short>(LOWORD(lParam));
3041 aPt.y = static_cast<short>(HIWORD(lParam));
3042 ScreenToClient(hWnd, &aPt);
3043 if (const auto& pHelpWin = ImplGetSVData()->maHelpData.mpHelpWin)
3045 const tools::Rectangle& rHelpRect = pHelpWin->GetHelpArea();
3046 if (rHelpRect.IsInside(Point(aPt.x, aPt.y)))
3048 // We have entered a tooltip (help window). Don't call the handler here; it
3049 // would launch the sequence "Mouse leaves the Control->Control redraws->
3050 // Help window gets destroyed->Mouse enters the Control->Control redraws",
3051 // which takes CPU and may flicker. Just destroy the help window and pretend
3052 // we are still over the original window.
3053 ImplDestroyHelpWindow(true);
3054 bCall = false;
3055 break;
3058 pSalData->mhWantLeaveMsg = nullptr;
3059 if ( pSalData->mpMouseLeaveTimer )
3061 delete pSalData->mpMouseLeaveTimer;
3062 pSalData->mpMouseLeaveTimer = nullptr;
3064 aMouseEvt.mnX = aPt.x;
3065 aMouseEvt.mnY = aPt.y;
3066 aMouseEvt.mnButton = 0;
3067 nEvent = SalEvent::MouseLeave;
3069 else
3070 bCall = false;
3072 break;
3074 case WM_LBUTTONDOWN:
3075 aMouseEvt.mnButton = MOUSE_LEFT;
3076 nEvent = SalEvent::MouseButtonDown;
3077 break;
3079 case WM_MBUTTONDOWN:
3080 aMouseEvt.mnButton = MOUSE_MIDDLE;
3081 nEvent = SalEvent::MouseButtonDown;
3082 break;
3084 case WM_RBUTTONDOWN:
3085 aMouseEvt.mnButton = MOUSE_RIGHT;
3086 nEvent = SalEvent::MouseButtonDown;
3087 break;
3089 case WM_LBUTTONUP:
3090 aMouseEvt.mnButton = MOUSE_LEFT;
3091 nEvent = SalEvent::MouseButtonUp;
3092 break;
3094 case WM_MBUTTONUP:
3095 aMouseEvt.mnButton = MOUSE_MIDDLE;
3096 nEvent = SalEvent::MouseButtonUp;
3097 break;
3099 case WM_RBUTTONUP:
3100 aMouseEvt.mnButton = MOUSE_RIGHT;
3101 nEvent = SalEvent::MouseButtonUp;
3102 break;
3105 // check if this window was destroyed - this might happen if we are the help window
3106 // and sent a mouse leave message to the application which killed the help window, ie ourselves
3107 if( !IsWindow( hWnd ) )
3108 return false;
3110 if ( bCall )
3112 if ( nEvent == SalEvent::MouseButtonDown )
3113 UpdateWindow( hWnd );
3115 if( AllSettings::GetLayoutRTL() )
3116 aMouseEvt.mnX = pFrame->maGeometry.nWidth-1-aMouseEvt.mnX;
3118 nRet = pFrame->CallCallback( nEvent, &aMouseEvt );
3119 if ( nMsg == WM_MOUSEMOVE )
3120 SetCursor( pFrame->mhCursor );
3122 else
3123 nRet = false;
3125 return nRet;
3128 static bool ImplHandleMouseActivateMsg( HWND hWnd )
3130 WinSalFrame* pFrame = GetWindowPtr( hWnd );
3131 if ( !pFrame )
3132 return false;
3134 if ( pFrame->mbFloatWin )
3135 return true;
3137 return pFrame->CallCallback( SalEvent::MouseActivate, nullptr );
3140 static bool ImplHandleWheelMsg( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
3142 DBG_ASSERT( nMsg == WM_MOUSEWHEEL ||
3143 nMsg == WM_MOUSEHWHEEL,
3144 "ImplHandleWheelMsg() called with no wheel mouse event" );
3146 ImplSalYieldMutexAcquireWithWait();
3148 bool nRet = false;
3149 WinSalFrame* pFrame = GetWindowPtr( hWnd );
3150 if ( pFrame )
3152 WORD nWinModCode = LOWORD( wParam );
3153 POINT aWinPt;
3154 aWinPt.x = static_cast<short>(LOWORD( lParam ));
3155 aWinPt.y = static_cast<short>(HIWORD( lParam ));
3156 ScreenToClient( hWnd, &aWinPt );
3158 SalWheelMouseEvent aWheelEvt;
3159 aWheelEvt.mnTime = GetMessageTime();
3160 aWheelEvt.mnX = aWinPt.x;
3161 aWheelEvt.mnY = aWinPt.y;
3162 aWheelEvt.mnCode = 0;
3163 aWheelEvt.mnDelta = static_cast<short>(HIWORD( wParam ));
3164 aWheelEvt.mnNotchDelta = aWheelEvt.mnDelta/WHEEL_DELTA;
3165 if( aWheelEvt.mnNotchDelta == 0 )
3167 if( aWheelEvt.mnDelta > 0 )
3168 aWheelEvt.mnNotchDelta = 1;
3169 else if( aWheelEvt.mnDelta < 0 )
3170 aWheelEvt.mnNotchDelta = -1;
3173 if( nMsg == WM_MOUSEWHEEL )
3175 if ( aSalShlData.mnWheelScrollLines == WHEEL_PAGESCROLL )
3176 aWheelEvt.mnScrollLines = SAL_WHEELMOUSE_EVENT_PAGESCROLL;
3177 else
3178 aWheelEvt.mnScrollLines = aSalShlData.mnWheelScrollLines;
3179 aWheelEvt.mbHorz = false;
3181 else
3183 aWheelEvt.mnScrollLines = aSalShlData.mnWheelScrollChars;
3184 aWheelEvt.mbHorz = true;
3186 // fdo#36380 - seems horiz scrolling has swapped direction
3187 aWheelEvt.mnDelta *= -1;
3188 aWheelEvt.mnNotchDelta *= -1;
3191 if ( nWinModCode & MK_SHIFT )
3192 aWheelEvt.mnCode |= KEY_SHIFT;
3193 if ( nWinModCode & MK_CONTROL )
3194 aWheelEvt.mnCode |= KEY_MOD1;
3195 if ( GetKeyState( VK_MENU ) & 0x8000 )
3196 aWheelEvt.mnCode |= KEY_MOD2;
3198 if( AllSettings::GetLayoutRTL() )
3199 aWheelEvt.mnX = pFrame->maGeometry.nWidth-1-aWheelEvt.mnX;
3201 nRet = pFrame->CallCallback( SalEvent::WheelMouse, &aWheelEvt );
3204 ImplSalYieldMutexRelease();
3206 return nRet;
3209 static sal_uInt16 ImplSalGetKeyCode( WPARAM wParam )
3211 sal_uInt16 nKeyCode;
3213 // convert KeyCode
3214 if ( wParam < KEY_TAB_SIZE )
3215 nKeyCode = aImplTranslateKeyTab[wParam];
3216 else
3218 SalData* pSalData = GetSalData();
3219 std::map< UINT, sal_uInt16 >::const_iterator it = pSalData->maVKMap.find( static_cast<UINT>(wParam) );
3220 if( it != pSalData->maVKMap.end() )
3221 nKeyCode = it->second;
3222 else
3223 nKeyCode = 0;
3226 return nKeyCode;
3229 static void ImplUpdateInputLang( WinSalFrame* pFrame )
3231 UINT nLang = LOWORD( GetKeyboardLayout( 0 ) );
3232 if ( nLang && nLang != pFrame->mnInputLang )
3234 // keep input lang up-to-date
3235 pFrame->mnInputLang = nLang;
3238 // We are on Windows NT so we use Unicode FrameProcs and get
3239 // Unicode charcodes directly from Windows no need to set up a
3240 // code page
3241 return;
3244 static sal_Unicode ImplGetCharCode( WinSalFrame* pFrame, WPARAM nCharCode )
3246 ImplUpdateInputLang( pFrame );
3248 // We are on Windows NT so we use Unicode FrameProcs and we
3249 // get Unicode charcodes directly from Windows
3250 return static_cast<sal_Unicode>(nCharCode);
3253 LanguageType WinSalFrame::GetInputLanguage()
3255 if( !mnInputLang )
3256 ImplUpdateInputLang( this );
3258 if( !mnInputLang )
3259 return LANGUAGE_DONTKNOW;
3260 else
3261 return LanguageType(mnInputLang);
3264 bool WinSalFrame::MapUnicodeToKeyCode( sal_Unicode aUnicode, LanguageType aLangType, vcl::KeyCode& rKeyCode )
3266 bool bRet = false;
3267 sal_IntPtr nLangType = static_cast<sal_uInt16>(aLangType);
3268 // just use the passed language identifier, do not try to load additional keyboard support
3269 HKL hkl = reinterpret_cast<HKL>(nLangType);
3271 if( hkl )
3273 SHORT scan = VkKeyScanExW( aUnicode, hkl );
3274 if( LOWORD(scan) == 0xFFFF )
3275 // keyboard not loaded or key cannot be mapped
3276 bRet = false;
3277 else
3279 BYTE vkeycode = LOBYTE(scan);
3280 BYTE shiftstate = HIBYTE(scan);
3282 // Last argument is set to false, because there's no decision made
3283 // yet which key should be assigned to MOD3 modifier on Windows.
3284 // Windows key - user's can be confused, because it should display
3285 // Windows menu (applies to both left/right key)
3286 // Menu key - this key is used to display context menu
3287 // AltGr key - probably it has no sense
3288 rKeyCode = vcl::KeyCode( ImplSalGetKeyCode( vkeycode ),
3289 (shiftstate & 0x01) != 0, // shift
3290 (shiftstate & 0x02) != 0, // ctrl
3291 (shiftstate & 0x04) != 0, // alt
3292 false );
3293 bRet = true;
3297 return bRet;
3300 static bool ImplHandleKeyMsg( HWND hWnd, UINT nMsg,
3301 WPARAM wParam, LPARAM lParam, LRESULT& rResult )
3303 static bool bIgnoreCharMsg = false;
3304 static WPARAM nDeadChar = 0;
3305 static WPARAM nLastVKChar = 0;
3306 static sal_uInt16 nLastChar = 0;
3307 static ModKeyFlags nLastModKeyCode = ModKeyFlags::NONE;
3308 static bool bWaitForModKeyRelease = false;
3309 sal_uInt16 nRepeat = LOWORD( lParam )-1;
3310 sal_uInt16 nModCode = 0;
3312 // this key might have been relayed by SysChild and thus
3313 // may not be processed twice
3314 GetSalData()->mnSalObjWantKeyEvt = 0;
3316 if ( nMsg == WM_DEADCHAR )
3318 nDeadChar = wParam;
3319 return false;
3322 WinSalFrame* pFrame = GetWindowPtr( hWnd );
3323 if ( !pFrame )
3324 return false;
3326 // reset the background mode for each text input,
3327 // as some tools such as RichWin may have changed it
3328 if ( pFrame->mpLocalGraphics &&
3329 pFrame->mpLocalGraphics->getHDC() )
3330 SetBkMode( pFrame->mpLocalGraphics->getHDC(), TRANSPARENT );
3332 // determine modifiers
3333 if ( GetKeyState( VK_SHIFT ) & 0x8000 )
3334 nModCode |= KEY_SHIFT;
3335 if ( GetKeyState( VK_CONTROL ) & 0x8000 )
3336 nModCode |= KEY_MOD1;
3337 if (GetKeyState(VK_MENU) & 0x8000)
3338 nModCode |= KEY_MOD2;
3340 if ( (nMsg == WM_CHAR) || (nMsg == WM_SYSCHAR) )
3342 nDeadChar = 0;
3344 if ( bIgnoreCharMsg )
3346 bIgnoreCharMsg = false;
3347 // #101635# if zero is returned here for WM_SYSCHAR (ALT+<key>) Windows will beep
3348 // because this 'hotkey' was not processed -> better return 1
3349 // except for Alt-SPACE which should always open the sysmenu (#104616#)
3351 // also return zero if a system menubar is available that might process this hotkey
3352 // this also applies to the OLE inplace embedding where we are a child window
3353 if( (GetWindowStyle( hWnd ) & WS_CHILD) || GetMenu( hWnd ) || (wParam == 0x20) )
3354 return false;
3355 else
3356 return true;
3359 // ignore backspace as a single key, so that
3360 // we do not get problems for combinations w/ a DeadKey
3361 if ( wParam == 0x08 ) // BACKSPACE
3362 return false;
3364 // only "free flying" WM_CHAR messages arrive here, that are
3365 // created by typing an ALT-NUMPAD combination
3366 SalKeyEvent aKeyEvt;
3368 if ( (wParam >= '0') && (wParam <= '9') )
3369 aKeyEvt.mnCode = sal::static_int_cast<sal_uInt16>(KEYGROUP_NUM + wParam - '0');
3370 else if ( (wParam >= 'A') && (wParam <= 'Z') )
3371 aKeyEvt.mnCode = sal::static_int_cast<sal_uInt16>(KEYGROUP_ALPHA + wParam - 'A');
3372 else if ( (wParam >= 'a') && (wParam <= 'z') )
3373 aKeyEvt.mnCode = sal::static_int_cast<sal_uInt16>(KEYGROUP_ALPHA + wParam - 'a');
3374 else if ( wParam == 0x0D ) // RETURN
3375 aKeyEvt.mnCode = KEY_RETURN;
3376 else if ( wParam == 0x1B ) // ESCAPE
3377 aKeyEvt.mnCode = KEY_ESCAPE;
3378 else if ( wParam == 0x09 ) // TAB
3379 aKeyEvt.mnCode = KEY_TAB;
3380 else if ( wParam == 0x20 ) // SPACE
3381 aKeyEvt.mnCode = KEY_SPACE;
3382 else
3383 aKeyEvt.mnCode = 0;
3385 aKeyEvt.mnCode |= nModCode;
3386 aKeyEvt.mnCharCode = ImplGetCharCode( pFrame, wParam );
3387 aKeyEvt.mnRepeat = nRepeat;
3388 nLastChar = 0;
3389 nLastVKChar = 0;
3390 bool nRet = pFrame->CallCallback( SalEvent::KeyInput, &aKeyEvt );
3391 pFrame->CallCallback( SalEvent::KeyUp, &aKeyEvt );
3392 return nRet;
3394 // #i11583#, MCD, 2003-01-13, Support for WM_UNICHAR & Keyman 6.0; addition begins
3395 else if( nMsg == WM_UNICHAR )
3397 // If Windows is asking if we accept WM_UNICHAR, return TRUE
3398 if(wParam == UNICODE_NOCHAR)
3400 rResult = TRUE; // ssa: this will actually return TRUE to windows
3401 return true; // ...but this will only avoid calling the defwindowproc
3404 SalKeyEvent aKeyEvt;
3405 aKeyEvt.mnCode = nModCode; // Or should it be 0? - as this is always a character returned
3406 aKeyEvt.mnRepeat = 0;
3408 if( wParam >= Uni_SupplementaryPlanesStart )
3410 // character is supplementary char in UTF-32 format - must be converted to UTF-16 supplementary pair
3411 // sal_Unicode ch = (sal_Unicode) Uni_UTF32ToSurrogate1(wParam);
3412 nLastChar = 0;
3413 nLastVKChar = 0;
3414 pFrame->CallCallback( SalEvent::KeyInput, &aKeyEvt );
3415 pFrame->CallCallback( SalEvent::KeyUp, &aKeyEvt );
3416 wParam = static_cast<sal_Unicode>(Uni_UTF32ToSurrogate2( wParam ));
3419 aKeyEvt.mnCharCode = static_cast<sal_Unicode>(wParam);
3421 nLastChar = 0;
3422 nLastVKChar = 0;
3423 bool nRet = pFrame->CallCallback( SalEvent::KeyInput, &aKeyEvt );
3424 pFrame->CallCallback( SalEvent::KeyUp, &aKeyEvt );
3426 return nRet;
3428 // MCD, 2003-01-13, Support for WM_UNICHAR & Keyman 6.0; addition ends
3429 else
3431 // for shift, control and menu we issue a KeyModChange event
3432 if ( (wParam == VK_SHIFT) || (wParam == VK_CONTROL) || (wParam == VK_MENU) )
3434 SalKeyModEvent aModEvt;
3435 aModEvt.mbDown = false; // auto-accelerator feature not supported here.
3436 aModEvt.mnCode = nModCode;
3437 aModEvt.mnModKeyCode = ModKeyFlags::NONE; // no command events will be sent if this member is 0
3439 ModKeyFlags tmpCode = ModKeyFlags::NONE;
3440 if( GetKeyState( VK_LSHIFT ) & 0x8000 )
3441 tmpCode |= ModKeyFlags::LeftShift;
3442 if( GetKeyState( VK_RSHIFT ) & 0x8000 )
3443 tmpCode |= ModKeyFlags::RightShift;
3444 if( GetKeyState( VK_LCONTROL ) & 0x8000 )
3445 tmpCode |= ModKeyFlags::LeftMod1;
3446 if( GetKeyState( VK_RCONTROL ) & 0x8000 )
3447 tmpCode |= ModKeyFlags::RightMod1;
3448 if( GetKeyState( VK_LMENU ) & 0x8000 )
3449 tmpCode |= ModKeyFlags::LeftMod2;
3450 if( GetKeyState( VK_RMENU ) & 0x8000 )
3451 tmpCode |= ModKeyFlags::RightMod2;
3453 if( tmpCode < nLastModKeyCode )
3455 aModEvt.mnModKeyCode = nLastModKeyCode;
3456 nLastModKeyCode = ModKeyFlags::NONE;
3457 bWaitForModKeyRelease = true;
3459 else
3461 if( !bWaitForModKeyRelease )
3462 nLastModKeyCode = tmpCode;
3465 if( tmpCode == ModKeyFlags::NONE )
3466 bWaitForModKeyRelease = false;
3468 return pFrame->CallCallback( SalEvent::KeyModChange, &aModEvt );
3470 else
3472 SalKeyEvent aKeyEvt;
3473 SalEvent nEvent;
3474 MSG aCharMsg;
3475 BOOL bCharPeek = FALSE;
3476 UINT nCharMsg = WM_CHAR;
3477 bool bKeyUp = (nMsg == WM_KEYUP) || (nMsg == WM_SYSKEYUP);
3479 nLastModKeyCode = ModKeyFlags::NONE; // make sure no modkey messages are sent if they belong to a hotkey (see above)
3480 aKeyEvt.mnCharCode = 0;
3481 aKeyEvt.mnCode = ImplSalGetKeyCode( wParam );
3482 if ( !bKeyUp )
3484 // check for charcode
3485 // Get the related WM_CHAR message using PeekMessage, if available.
3486 // The WM_CHAR message is always at the beginning of the
3487 // message queue. Also it is made certain that there is always only
3488 // one WM_CHAR message in the queue.
3489 bCharPeek = PeekMessageW( &aCharMsg, hWnd,
3490 WM_CHAR, WM_CHAR, PM_NOREMOVE | PM_NOYIELD );
3491 if ( bCharPeek && (nDeadChar == aCharMsg.wParam) )
3493 bCharPeek = FALSE;
3494 nDeadChar = 0;
3496 if ( wParam == VK_BACK )
3498 PeekMessageW( &aCharMsg, hWnd,
3499 nCharMsg, nCharMsg, PM_REMOVE | PM_NOYIELD );
3500 return false;
3503 else
3505 if ( !bCharPeek )
3507 bCharPeek = PeekMessageW( &aCharMsg, hWnd,
3508 WM_SYSCHAR, WM_SYSCHAR, PM_NOREMOVE | PM_NOYIELD );
3509 nCharMsg = WM_SYSCHAR;
3512 if ( bCharPeek )
3513 aKeyEvt.mnCharCode = ImplGetCharCode( pFrame, aCharMsg.wParam );
3514 else
3515 aKeyEvt.mnCharCode = 0;
3517 nLastChar = aKeyEvt.mnCharCode;
3518 nLastVKChar = wParam;
3520 else
3522 if ( wParam == nLastVKChar )
3524 aKeyEvt.mnCharCode = nLastChar;
3525 nLastChar = 0;
3526 nLastVKChar = 0;
3530 if ( aKeyEvt.mnCode || aKeyEvt.mnCharCode )
3532 if ( bKeyUp )
3533 nEvent = SalEvent::KeyUp;
3534 else
3535 nEvent = SalEvent::KeyInput;
3537 aKeyEvt.mnCode |= nModCode;
3538 aKeyEvt.mnRepeat = nRepeat;
3540 if ((nModCode & (KEY_MOD1 | KEY_MOD2)) == (KEY_MOD1 | KEY_MOD2) &&
3541 aKeyEvt.mnCharCode)
3543 // this is actually AltGr and should not be handled as Alt
3544 aKeyEvt.mnCode &= ~(KEY_MOD1 | KEY_MOD2);
3547 bIgnoreCharMsg = bCharPeek;
3548 bool nRet = pFrame->CallCallback( nEvent, &aKeyEvt );
3549 // independent part only reacts on keyup but Windows does not send
3550 // keyup for VK_HANJA
3551 if( aKeyEvt.mnCode == KEY_HANGUL_HANJA )
3552 nRet = pFrame->CallCallback( SalEvent::KeyUp, &aKeyEvt );
3554 bIgnoreCharMsg = false;
3556 // char-message, then remove or ignore
3557 if ( bCharPeek )
3559 nDeadChar = 0;
3560 if ( nRet )
3562 PeekMessageW( &aCharMsg, hWnd,
3563 nCharMsg, nCharMsg, PM_REMOVE | PM_NOYIELD );
3565 else
3566 bIgnoreCharMsg = true;
3569 return nRet;
3571 else
3572 return false;
3577 bool ImplHandleSalObjKeyMsg( HWND hWnd, UINT nMsg,
3578 WPARAM wParam, LPARAM lParam )
3580 if ( (nMsg == WM_KEYDOWN) || (nMsg == WM_KEYUP) )
3582 WinSalFrame* pFrame = GetWindowPtr( hWnd );
3583 if ( !pFrame )
3584 return false;
3586 sal_uInt16 nRepeat = LOWORD( lParam )-1;
3587 sal_uInt16 nModCode = 0;
3589 // determine modifiers
3590 if ( GetKeyState( VK_SHIFT ) & 0x8000 )
3591 nModCode |= KEY_SHIFT;
3592 if ( GetKeyState( VK_CONTROL ) & 0x8000 )
3593 nModCode |= KEY_MOD1;
3594 if ( GetKeyState( VK_MENU ) & 0x8000 )
3595 nModCode |= KEY_MOD2;
3597 if ( (wParam != VK_SHIFT) && (wParam != VK_CONTROL) && (wParam != VK_MENU) )
3599 SalKeyEvent aKeyEvt;
3600 SalEvent nEvent;
3602 // convert KeyCode
3603 aKeyEvt.mnCode = ImplSalGetKeyCode( wParam );
3604 aKeyEvt.mnCharCode = 0;
3606 if ( aKeyEvt.mnCode )
3608 if (nMsg == WM_KEYUP)
3609 nEvent = SalEvent::KeyUp;
3610 else
3611 nEvent = SalEvent::KeyInput;
3613 aKeyEvt.mnCode |= nModCode;
3614 aKeyEvt.mnRepeat = nRepeat;
3615 bool nRet = pFrame->CallCallback( nEvent, &aKeyEvt );
3616 return nRet;
3618 else
3619 return false;
3623 return false;
3626 bool ImplHandleSalObjSysCharMsg( HWND hWnd, WPARAM wParam, LPARAM lParam )
3628 WinSalFrame* pFrame = GetWindowPtr( hWnd );
3629 if ( !pFrame )
3630 return false;
3632 sal_uInt16 nRepeat = LOWORD( lParam )-1;
3633 sal_uInt16 nModCode = 0;
3634 sal_uInt16 cKeyCode = static_cast<sal_uInt16>(wParam);
3636 // determine modifiers
3637 if ( GetKeyState( VK_SHIFT ) & 0x8000 )
3638 nModCode |= KEY_SHIFT;
3639 if ( GetKeyState( VK_CONTROL ) & 0x8000 )
3640 nModCode |= KEY_MOD1;
3641 nModCode |= KEY_MOD2;
3643 // assemble KeyEvent
3644 SalKeyEvent aKeyEvt;
3645 if ( (cKeyCode >= 48) && (cKeyCode <= 57) )
3646 aKeyEvt.mnCode = KEY_0+(cKeyCode-48);
3647 else if ( (cKeyCode >= 65) && (cKeyCode <= 90) )
3648 aKeyEvt.mnCode = KEY_A+(cKeyCode-65);
3649 else if ( (cKeyCode >= 97) && (cKeyCode <= 122) )
3650 aKeyEvt.mnCode = KEY_A+(cKeyCode-97);
3651 else
3652 aKeyEvt.mnCode = 0;
3653 aKeyEvt.mnCode |= nModCode;
3654 aKeyEvt.mnCharCode = ImplGetCharCode( pFrame, cKeyCode );
3655 aKeyEvt.mnRepeat = nRepeat;
3656 bool nRet = pFrame->CallCallback( SalEvent::KeyInput, &aKeyEvt );
3657 pFrame->CallCallback( SalEvent::KeyUp, &aKeyEvt );
3658 return nRet;
3661 enum class DeferPolicy
3663 Blocked,
3664 Allowed
3667 // Remember to release the solar mutex on success!
3668 static WinSalFrame* ProcessOrDeferMessage( HWND hWnd, INT nMsg, WPARAM pWParam = 0,
3669 DeferPolicy eCanDefer = DeferPolicy::Allowed )
3671 bool bFailedCondition = false, bGotMutex = false;
3672 WinSalFrame* pFrame = nullptr;
3674 if ( DeferPolicy::Blocked == eCanDefer )
3675 assert( (DeferPolicy::Blocked == eCanDefer) && (nMsg == 0) && (pWParam == 0) );
3676 else
3677 assert( (DeferPolicy::Allowed == eCanDefer) && (nMsg != 0) );
3679 if ( DeferPolicy::Blocked == eCanDefer )
3681 ImplSalYieldMutexAcquireWithWait();
3682 bGotMutex = true;
3684 else if ( !(bGotMutex = ImplSalYieldMutexTryToAcquire()) )
3685 bFailedCondition = true;
3687 if ( !bFailedCondition )
3689 pFrame = GetWindowPtr( hWnd );
3690 bFailedCondition = pFrame == nullptr;
3693 if ( bFailedCondition )
3695 if ( bGotMutex )
3696 ImplSalYieldMutexRelease();
3697 if ( DeferPolicy::Allowed == eCanDefer )
3699 BOOL const ret = PostMessageW(hWnd, nMsg, pWParam, 0);
3700 SAL_WARN_IF(0 == ret, "vcl", "ERROR: PostMessage() failed!");
3704 return pFrame;
3707 enum class PostedState
3709 IsPosted,
3710 IsInitial
3713 static bool ImplHandlePostPaintMsg( HWND hWnd, RECT* pRect,
3714 PostedState eProcessed = PostedState::IsPosted )
3716 RECT* pMsgRect;
3717 if ( PostedState::IsInitial == eProcessed )
3719 pMsgRect = new RECT;
3720 CopyRect( pMsgRect, pRect );
3722 else
3723 pMsgRect = pRect;
3725 WinSalFrame* pFrame = ProcessOrDeferMessage( hWnd, SAL_MSG_POSTPAINT,
3726 reinterpret_cast<WPARAM>(pMsgRect) );
3727 if ( pFrame )
3729 SalPaintEvent aPEvt( pRect->left, pRect->top, pRect->right-pRect->left, pRect->bottom-pRect->top );
3730 pFrame->CallCallback( SalEvent::Paint, &aPEvt );
3731 ImplSalYieldMutexRelease();
3732 if ( PostedState::IsPosted == eProcessed )
3733 delete pRect;
3736 return (pFrame != nullptr);
3739 static bool ImplHandlePaintMsg( HWND hWnd )
3741 bool bPaintSuccessful = false;
3743 // even without the Yield mutex, we can still change the clip region,
3744 // because other threads don't use the Yield mutex
3745 // --> see AcquireGraphics()
3747 WinSalFrame* pFrame = GetWindowPtr( hWnd );
3748 if ( pFrame )
3750 // clip region must be set, as we don't get a proper
3751 // bounding rectangle otherwise
3752 WinSalGraphics *pGraphics = pFrame->mpLocalGraphics;
3753 bool bHasClipRegion = pGraphics &&
3754 pGraphics->getHDC() && pGraphics->getRegion();
3755 if ( bHasClipRegion )
3756 SelectClipRgn( pGraphics->getHDC(), nullptr );
3758 // according to Windows documentation one shall check first if
3759 // there really is a paint-region
3760 RECT aUpdateRect;
3761 PAINTSTRUCT aPs;
3762 bool bHasPaintRegion = GetUpdateRect( hWnd, nullptr, FALSE );
3763 if ( bHasPaintRegion )
3765 // call BeginPaint/EndPaint to query the paint rect and use
3766 // this information in the (deferred) paint
3767 BeginPaint( hWnd, &aPs );
3768 CopyRect( &aUpdateRect, &aPs.rcPaint );
3771 // reset clip region
3772 if ( bHasClipRegion )
3773 SelectClipRgn( pGraphics->getHDC(), pGraphics->getRegion() );
3775 // try painting
3776 if ( bHasPaintRegion )
3778 bPaintSuccessful = ImplHandlePostPaintMsg(
3779 hWnd, &aUpdateRect, PostedState::IsInitial );
3780 EndPaint( hWnd, &aPs );
3782 else // if there is nothing to paint, the paint is successful
3783 bPaintSuccessful = true;
3786 return bPaintSuccessful;
3789 static void SetMaximizedFrameGeometry( HWND hWnd, WinSalFrame* pFrame, RECT* pParentRect )
3791 // calculate and set frame geometry of a maximized window - useful if the window is still hidden
3793 // dualmonitor support:
3794 // Get screensize of the monitor with the mouse pointer
3796 RECT aRectMouse;
3797 if( ! pParentRect )
3799 POINT pt;
3800 GetCursorPos( &pt );
3801 aRectMouse.left = pt.x;
3802 aRectMouse.top = pt.y;
3803 aRectMouse.right = pt.x+2;
3804 aRectMouse.bottom = pt.y+2;
3805 pParentRect = &aRectMouse;
3808 RECT aRect;
3809 ImplSalGetWorkArea( hWnd, &aRect, pParentRect );
3811 // a maximized window has no other borders than the caption
3812 pFrame->maGeometry.nLeftDecoration = pFrame->maGeometry.nRightDecoration = pFrame->maGeometry.nBottomDecoration = 0;
3813 pFrame->maGeometry.nTopDecoration = pFrame->mbCaption ? GetSystemMetrics( SM_CYCAPTION ) : 0;
3815 aRect.top += pFrame->maGeometry.nTopDecoration;
3816 pFrame->maGeometry.nX = aRect.left;
3817 pFrame->maGeometry.nY = aRect.top;
3818 pFrame->maGeometry.nWidth = aRect.right - aRect.left;
3819 pFrame->maGeometry.nHeight = aRect.bottom - aRect.top;
3822 static void UpdateFrameGeometry( HWND hWnd, WinSalFrame* pFrame )
3824 if( !pFrame )
3825 return;
3827 RECT aRect;
3828 GetWindowRect( hWnd, &aRect );
3829 pFrame->maGeometry.nX = 0;
3830 pFrame->maGeometry.nY = 0;
3831 pFrame->maGeometry.nWidth = 0;
3832 pFrame->maGeometry.nHeight = 0;
3833 pFrame->maGeometry.nLeftDecoration = 0;
3834 pFrame->maGeometry.nTopDecoration = 0;
3835 pFrame->maGeometry.nRightDecoration = 0;
3836 pFrame->maGeometry.nBottomDecoration = 0;
3837 pFrame->maGeometry.nDisplayScreenNumber = 0;
3839 if ( IsIconic( hWnd ) )
3840 return;
3842 POINT aPt;
3843 aPt.x=0;
3844 aPt.y=0;
3845 ClientToScreen(hWnd, &aPt);
3846 int cx = aPt.x - aRect.left;
3847 pFrame->maGeometry.nTopDecoration = aPt.y - aRect.top;
3849 pFrame->maGeometry.nLeftDecoration = cx;
3850 pFrame->maGeometry.nRightDecoration = cx;
3852 pFrame->maGeometry.nX = aPt.x;
3853 pFrame->maGeometry.nY = aPt.y;
3855 RECT aInnerRect;
3856 GetClientRect( hWnd, &aInnerRect );
3857 if( aInnerRect.right )
3859 // improve right decoration
3860 aPt.x=aInnerRect.right;
3861 aPt.y=aInnerRect.top;
3862 ClientToScreen(hWnd, &aPt);
3863 pFrame->maGeometry.nRightDecoration = aRect.right - aPt.x;
3865 if( aInnerRect.bottom ) // may be zero if window was not shown yet
3866 pFrame->maGeometry.nBottomDecoration += aRect.bottom - aPt.y - aInnerRect.bottom;
3867 else
3868 // bottom border is typically the same as left/right
3869 pFrame->maGeometry.nBottomDecoration = pFrame->maGeometry.nLeftDecoration;
3871 int nWidth = aRect.right - aRect.left
3872 - pFrame->maGeometry.nRightDecoration - pFrame->maGeometry.nLeftDecoration;
3873 int nHeight = aRect.bottom - aRect.top
3874 - pFrame->maGeometry.nBottomDecoration - pFrame->maGeometry.nTopDecoration;
3875 // clamp to zero
3876 pFrame->maGeometry.nHeight = nHeight < 0 ? 0 : nHeight;
3877 pFrame->maGeometry.nWidth = nWidth < 0 ? 0 : nWidth;
3878 pFrame->updateScreenNumber();
3881 static void ImplCallMoveHdl( HWND hWnd )
3883 WinSalFrame* pFrame = GetWindowPtr( hWnd );
3884 if ( pFrame )
3886 pFrame->CallCallback( SalEvent::Move, nullptr );
3887 // to avoid doing Paint twice by VCL and SAL
3888 //if ( IsWindowVisible( hWnd ) && !pFrame->mbInShow )
3889 // UpdateWindow( hWnd );
3893 static void ImplCallClosePopupsHdl( HWND hWnd )
3895 WinSalFrame* pFrame = GetWindowPtr( hWnd );
3896 if ( pFrame )
3898 pFrame->CallCallback( SalEvent::ClosePopups, nullptr );
3902 static void ImplHandleMoveMsg( HWND hWnd )
3904 WinSalFrame* pFrame = ProcessOrDeferMessage( hWnd, SAL_MSG_POSTMOVE );
3905 if ( pFrame )
3907 UpdateFrameGeometry( hWnd, pFrame );
3909 if ( GetWindowStyle( hWnd ) & WS_VISIBLE )
3910 pFrame->mbDefPos = false;
3912 // protect against recursion
3913 if ( !pFrame->mbInMoveMsg )
3915 // adjust window again for FullScreenMode
3916 pFrame->mbInMoveMsg = true;
3917 if ( pFrame->mbFullScreen )
3918 ImplSalFrameFullScreenPos( pFrame );
3919 pFrame->mbInMoveMsg = false;
3922 // save state
3923 ImplSaveFrameState( pFrame );
3925 // Call Hdl
3926 //#93851 if we call this handler, VCL floating windows are not updated correctly
3927 ImplCallMoveHdl( hWnd );
3929 ImplSalYieldMutexRelease();
3933 static void ImplCallSizeHdl( HWND hWnd )
3935 // as Windows can send these messages also, we have to use
3936 // the Solar semaphore
3937 WinSalFrame* pFrame = ProcessOrDeferMessage( hWnd, SAL_MSG_POSTCALLSIZE );
3938 if ( pFrame )
3940 pFrame->CallCallback( SalEvent::Resize, nullptr );
3941 // to avoid double Paints by VCL and SAL
3942 if ( IsWindowVisible( hWnd ) && !pFrame->mbInShow )
3943 UpdateWindow( hWnd );
3945 ImplSalYieldMutexRelease();
3949 static void ImplHandleSizeMsg( HWND hWnd, WPARAM wParam, LPARAM lParam )
3951 if ( (wParam != SIZE_MAXSHOW) && (wParam != SIZE_MAXHIDE) )
3953 WinSalFrame* pFrame = GetWindowPtr( hWnd );
3954 if ( pFrame )
3956 UpdateFrameGeometry( hWnd, pFrame );
3958 pFrame->mnWidth = static_cast<int>(LOWORD(lParam));
3959 pFrame->mnHeight = static_cast<int>(HIWORD(lParam));
3960 // save state
3961 ImplSaveFrameState( pFrame );
3962 // Call Hdl
3963 ImplCallSizeHdl( hWnd );
3965 WinSalTimer* pTimer = static_cast<WinSalTimer*>( ImplGetSVData()->maSchedCtx.mpSalTimer );
3966 if ( pTimer )
3967 pTimer->SetForceRealTimer( true );
3972 static void ImplHandleFocusMsg( HWND hWnd )
3974 WinSalFrame* pFrame = ProcessOrDeferMessage( hWnd, SAL_MSG_POSTFOCUS );
3975 if ( pFrame )
3977 if ( !WinSalFrame::mbInReparent )
3979 bool bGotFocus = ::GetFocus() == hWnd;
3980 if ( bGotFocus )
3982 if ( IsWindowVisible( hWnd ) && !pFrame->mbInShow )
3983 UpdateWindow( hWnd );
3985 // do we support IME?
3986 if ( pFrame->mbIME && pFrame->mhDefIMEContext )
3988 UINT nImeProps = ImmGetProperty( GetKeyboardLayout( 0 ), IGP_PROPERTY );
3990 pFrame->mbSpezIME = (nImeProps & IME_PROP_SPECIAL_UI) != 0;
3991 pFrame->mbAtCursorIME = (nImeProps & IME_PROP_AT_CARET) != 0;
3992 pFrame->mbHandleIME = !pFrame->mbSpezIME;
3995 pFrame->CallCallback( bGotFocus ? SalEvent::GetFocus : SalEvent::LoseFocus, nullptr );
3997 ImplSalYieldMutexRelease();
4001 static void ImplHandleCloseMsg( HWND hWnd )
4003 WinSalFrame* pFrame = ProcessOrDeferMessage( hWnd, WM_CLOSE );
4004 if ( pFrame )
4006 pFrame->CallCallback( SalEvent::Close, nullptr );
4007 ImplSalYieldMutexRelease();
4011 static bool ImplHandleShutDownMsg( HWND hWnd )
4013 bool nRet = false;
4014 WinSalFrame* pFrame = ProcessOrDeferMessage( hWnd, 0, 0, DeferPolicy::Blocked );
4015 if ( pFrame )
4017 nRet = pFrame->CallCallback( SalEvent::Shutdown, nullptr );
4018 ImplSalYieldMutexRelease();
4020 return nRet;
4023 static void ImplHandleSettingsChangeMsg( HWND hWnd, UINT nMsg,
4024 WPARAM wParam, LPARAM lParam )
4026 SalEvent nSalEvent = SalEvent::SettingsChanged;
4028 if ( nMsg == WM_DEVMODECHANGE )
4029 nSalEvent = SalEvent::PrinterChanged;
4030 else if ( nMsg == WM_DISPLAYCHANGE )
4031 nSalEvent = SalEvent::DisplayChanged;
4032 else if ( nMsg == WM_FONTCHANGE )
4033 nSalEvent = SalEvent::FontChanged;
4034 else if ( nMsg == WM_WININICHANGE )
4036 if ( lParam )
4038 if ( ImplSalWICompareAscii( reinterpret_cast<const wchar_t*>(lParam), "devices" ) == 0 )
4039 nSalEvent = SalEvent::PrinterChanged;
4043 if ( nMsg == WM_SETTINGCHANGE )
4045 if ( wParam == SPI_SETWHEELSCROLLLINES )
4046 aSalShlData.mnWheelScrollLines = ImplSalGetWheelScrollLines();
4047 else if( wParam == SPI_SETWHEELSCROLLCHARS )
4048 aSalShlData.mnWheelScrollChars = ImplSalGetWheelScrollChars();
4051 if ( WM_SYSCOLORCHANGE == nMsg && GetSalData()->mhDitherPal )
4052 ImplUpdateSysColorEntries();
4054 WinSalFrame* pFrame = ProcessOrDeferMessage( hWnd, 0, 0, DeferPolicy::Blocked );
4055 if ( pFrame )
4057 if ( (nMsg == WM_DISPLAYCHANGE) || (nMsg == WM_WININICHANGE) )
4059 if ( pFrame->mbFullScreen )
4060 ImplSalFrameFullScreenPos( pFrame );
4063 pFrame->CallCallback( nSalEvent, nullptr );
4064 ImplSalYieldMutexRelease();
4068 static void ImplHandleUserEvent( HWND hWnd, LPARAM lParam )
4070 WinSalFrame* pFrame = ProcessOrDeferMessage( hWnd, 0, 0, DeferPolicy::Blocked );
4071 if ( pFrame )
4073 pFrame->CallCallback( SalEvent::UserEvent, reinterpret_cast<void*>(lParam) );
4074 ImplSalYieldMutexRelease();
4078 static void ImplHandleForcePalette( HWND hWnd )
4080 SalData* pSalData = GetSalData();
4081 HPALETTE hPal = pSalData->mhDitherPal;
4082 if ( hPal )
4084 WinSalFrame* pFrame = ProcessOrDeferMessage( hWnd, SAL_MSG_FORCEPALETTE );
4085 if ( pFrame && pFrame->mpLocalGraphics && pFrame->mpLocalGraphics->getHDC() )
4087 WinSalGraphics* pGraphics = pFrame->mpLocalGraphics;
4088 if (pGraphics->getDefPal())
4090 SelectPalette( pGraphics->getHDC(), hPal, FALSE );
4091 if ( RealizePalette( pGraphics->getHDC() ) )
4093 InvalidateRect( hWnd, nullptr, FALSE );
4094 UpdateWindow( hWnd );
4095 pFrame->CallCallback( SalEvent::DisplayChanged, nullptr );
4099 if ( pFrame )
4100 ImplSalYieldMutexRelease();
4104 static LRESULT ImplHandlePalette( bool bFrame, HWND hWnd, UINT nMsg,
4105 WPARAM wParam, LPARAM lParam, bool& rDef )
4107 SalData* pSalData = GetSalData();
4108 HPALETTE hPal = pSalData->mhDitherPal;
4109 if ( !hPal )
4110 return 0;
4112 rDef = false;
4113 if ( pSalData->mbInPalChange )
4114 return 0;
4116 if ( (nMsg == WM_PALETTECHANGED) || (nMsg == SAL_MSG_POSTPALCHANGED) )
4118 if ( reinterpret_cast<HWND>(wParam) == hWnd )
4119 return 0;
4122 bool bReleaseMutex = false;
4123 if ( (nMsg == WM_QUERYNEWPALETTE) || (nMsg == WM_PALETTECHANGED) )
4125 // as Windows can send these messages also, we have to use
4126 // the Solar semaphore
4127 if ( ImplSalYieldMutexTryToAcquire() )
4128 bReleaseMutex = true;
4129 else if ( nMsg == WM_QUERYNEWPALETTE )
4131 BOOL const ret = PostMessageW(hWnd, SAL_MSG_POSTQUERYNEWPAL, wParam, lParam);
4132 SAL_WARN_IF(0 == ret, "vcl", "ERROR: PostMessage() failed!");
4134 else /* ( nMsg == WM_PALETTECHANGED ) */
4136 BOOL const ret = PostMessageW(hWnd, SAL_MSG_POSTPALCHANGED, wParam, lParam);
4137 SAL_WARN_IF(0 == ret, "vcl", "ERROR: PostMessage() failed!");
4141 WinSalVirtualDevice*pTempVD;
4142 WinSalFrame* pTempFrame;
4143 WinSalGraphics* pGraphics;
4144 HDC hDC;
4145 HPALETTE hOldPal;
4146 UINT nCols;
4147 bool bStdDC;
4148 bool bUpdate;
4150 pSalData->mbInPalChange = true;
4152 // reset all palettes in VirDevs and Frames
4153 pTempVD = pSalData->mpFirstVD;
4154 while ( pTempVD )
4156 pGraphics = pTempVD->getGraphics();
4157 if ( pGraphics->getDefPal() )
4159 SelectPalette( pGraphics->getHDC(),
4160 pGraphics->getDefPal(),
4161 TRUE );
4163 pTempVD = pTempVD->getNext();
4165 pTempFrame = pSalData->mpFirstFrame;
4166 while ( pTempFrame )
4168 pGraphics = pTempFrame->mpLocalGraphics;
4169 if ( pGraphics && pGraphics->getHDC() && pGraphics->getDefPal() )
4171 SelectPalette( pGraphics->getHDC(),
4172 pGraphics->getDefPal(),
4173 TRUE );
4175 pTempFrame = pTempFrame->mpNextFrame;
4178 // re-initialize palette
4179 WinSalFrame* pFrame = nullptr;
4180 if ( bFrame )
4181 pFrame = GetWindowPtr( hWnd );
4182 if ( pFrame && pFrame->mpLocalGraphics && pFrame->mpLocalGraphics->getHDC() )
4184 hDC = pFrame->mpLocalGraphics->getHDC();
4185 bStdDC = true;
4187 else
4189 hDC = GetDC( hWnd );
4190 bStdDC = false;
4192 UnrealizeObject( hPal );
4193 hOldPal = SelectPalette( hDC, hPal, TRUE );
4194 nCols = RealizePalette( hDC );
4195 bUpdate = nCols != 0;
4196 if ( !bStdDC )
4198 SelectPalette( hDC, hOldPal, TRUE );
4199 ReleaseDC( hWnd, hDC );
4202 // reset all palettes in VirDevs and Frames
4203 pTempVD = pSalData->mpFirstVD;
4204 while ( pTempVD )
4206 pGraphics = pTempVD->getGraphics();
4207 if ( pGraphics->getDefPal() )
4209 SelectPalette( pGraphics->getHDC(), hPal, TRUE );
4210 RealizePalette( pGraphics->getHDC() );
4212 pTempVD = pTempVD->getNext();
4214 pTempFrame = pSalData->mpFirstFrame;
4215 while ( pTempFrame )
4217 if ( pTempFrame != pFrame )
4219 pGraphics = pTempFrame->mpLocalGraphics;
4220 if ( pGraphics && pGraphics->getHDC() && pGraphics->getDefPal() )
4222 SelectPalette( pGraphics->getHDC(), hPal, TRUE );
4223 if ( RealizePalette( pGraphics->getHDC() ) )
4224 bUpdate = true;
4227 pTempFrame = pTempFrame->mpNextFrame;
4230 // if colors changed, update the window
4231 if ( bUpdate )
4233 pTempFrame = pSalData->mpFirstFrame;
4234 while ( pTempFrame )
4236 pGraphics = pTempFrame->mpLocalGraphics;
4237 if ( pGraphics && pGraphics->getHDC() && pGraphics->getDefPal() )
4239 InvalidateRect( pTempFrame->mhWnd, nullptr, FALSE );
4240 UpdateWindow( pTempFrame->mhWnd );
4241 pTempFrame->CallCallback( SalEvent::DisplayChanged, nullptr );
4243 pTempFrame = pTempFrame->mpNextFrame;
4247 pSalData->mbInPalChange = false;
4249 if ( bReleaseMutex )
4250 ImplSalYieldMutexRelease();
4252 if ( nMsg == WM_PALETTECHANGED )
4253 return 0;
4254 else
4255 return nCols;
4258 static bool ImplHandleMinMax( HWND hWnd, LPARAM lParam )
4260 bool bRet = false;
4262 if ( ImplSalYieldMutexTryToAcquire() )
4264 WinSalFrame* pFrame = GetWindowPtr( hWnd );
4265 if ( pFrame )
4267 MINMAXINFO* pMinMax = reinterpret_cast<MINMAXINFO*>(lParam);
4269 if ( pFrame->mbFullScreen )
4271 int nX;
4272 int nY;
4273 int nDX;
4274 int nDY;
4275 ImplSalCalcFullScreenSize( pFrame, nX, nY, nDX, nDY );
4277 if ( pMinMax->ptMaxPosition.x > nX )
4278 pMinMax->ptMaxPosition.x = nX;
4279 if ( pMinMax->ptMaxPosition.y > nY )
4280 pMinMax->ptMaxPosition.y = nY;
4282 if ( pMinMax->ptMaxSize.x < nDX )
4283 pMinMax->ptMaxSize.x = nDX;
4284 if ( pMinMax->ptMaxSize.y < nDY )
4285 pMinMax->ptMaxSize.y = nDY;
4286 if ( pMinMax->ptMaxTrackSize.x < nDX )
4287 pMinMax->ptMaxTrackSize.x = nDX;
4288 if ( pMinMax->ptMaxTrackSize.y < nDY )
4289 pMinMax->ptMaxTrackSize.y = nDY;
4291 pMinMax->ptMinTrackSize.x = nDX;
4292 pMinMax->ptMinTrackSize.y = nDY;
4294 bRet = true;
4297 if ( pFrame->mnMinWidth || pFrame->mnMinHeight )
4299 int nWidth = pFrame->mnMinWidth;
4300 int nHeight = pFrame->mnMinHeight;
4302 ImplSalAddBorder( pFrame, nWidth, nHeight );
4304 if ( pMinMax->ptMinTrackSize.x < nWidth )
4305 pMinMax->ptMinTrackSize.x = nWidth;
4306 if ( pMinMax->ptMinTrackSize.y < nHeight )
4307 pMinMax->ptMinTrackSize.y = nHeight;
4310 if ( pFrame->mnMaxWidth || pFrame->mnMaxHeight )
4312 int nWidth = pFrame->mnMaxWidth;
4313 int nHeight = pFrame->mnMaxHeight;
4315 ImplSalAddBorder( pFrame, nWidth, nHeight );
4317 if( nWidth > 0 && nHeight > 0 ) // protect against int overflow due to INT_MAX initialisation
4319 if ( pMinMax->ptMaxTrackSize.x > nWidth )
4320 pMinMax->ptMaxTrackSize.x = nWidth;
4321 if ( pMinMax->ptMaxTrackSize.y > nHeight )
4322 pMinMax->ptMaxTrackSize.y = nHeight;
4327 ImplSalYieldMutexRelease();
4330 return bRet;
4333 // retrieves the SalMenuItem pointer from a hMenu
4334 // the pointer is stored in every item, so if no position
4335 // is specified we just use the first item (ie, pos=0)
4336 // if bByPosition is false then nPos denotes a menu id instead of a position
4337 static WinSalMenuItem* ImplGetSalMenuItem( HMENU hMenu, UINT nPos, bool bByPosition=true )
4339 MENUITEMINFOW mi = {};
4340 mi.cbSize = sizeof( mi );
4341 mi.fMask = MIIM_DATA;
4342 if( !GetMenuItemInfoW( hMenu, nPos, bByPosition, &mi) )
4343 SAL_WARN("vcl", "GetMenuItemInfoW failed: " << WindowsErrorString(GetLastError()));
4345 return reinterpret_cast<WinSalMenuItem *>(mi.dwItemData);
4348 // returns the index of the currently selected item if any or -1
4349 static int ImplGetSelectedIndex( HMENU hMenu )
4351 MENUITEMINFOW mi = {};
4352 mi.cbSize = sizeof( mi );
4353 mi.fMask = MIIM_STATE;
4354 int n = GetMenuItemCount( hMenu );
4355 if( n != -1 )
4357 for(int i=0; i<n; i++ )
4359 if( !GetMenuItemInfoW( hMenu, i, TRUE, &mi) )
4360 SAL_WARN( "vcl", "GetMenuItemInfoW failed: " << WindowsErrorString( GetLastError() ) );
4361 else
4363 if( mi.fState & MFS_HILITE )
4364 return i;
4368 return -1;
4371 static LRESULT ImplMenuChar( HWND, WPARAM wParam, LPARAM lParam )
4373 LRESULT nRet = MNC_IGNORE;
4374 HMENU hMenu = reinterpret_cast<HMENU>(lParam);
4375 OUString aMnemonic( "&" + OUStringChar(static_cast<sal_Unicode>(LOWORD(wParam))) );
4376 aMnemonic = aMnemonic.toAsciiLowerCase(); // we only have ascii mnemonics
4378 // search the mnemonic in the current menu
4379 int nItemCount = GetMenuItemCount( hMenu );
4380 int nFound = 0;
4381 int idxFound = -1;
4382 int idxSelected = ImplGetSelectedIndex( hMenu );
4383 int idx = idxSelected != -1 ? idxSelected+1 : 0; // if duplicate mnemonics cycle through menu
4384 for( int i=0; i< nItemCount; i++, idx++ )
4386 WinSalMenuItem* pSalMenuItem = ImplGetSalMenuItem( hMenu, idx % nItemCount );
4387 if( !pSalMenuItem )
4388 continue;
4389 OUString aStr = pSalMenuItem->mText;
4390 aStr = aStr.toAsciiLowerCase();
4391 if( aStr.indexOf( aMnemonic ) != -1 )
4393 if( idxFound == -1 )
4394 idxFound = idx % nItemCount;
4395 if( nFound++ )
4396 break; // duplicate found
4399 if( nFound == 1 )
4400 nRet = MAKELRESULT( idxFound, MNC_EXECUTE );
4401 else
4402 // duplicate mnemonics, just select the next occurrence
4403 nRet = MAKELRESULT( idxFound, MNC_SELECT );
4405 return nRet;
4408 static LRESULT ImplMeasureItem( HWND hWnd, WPARAM wParam, LPARAM lParam )
4410 LRESULT nRet = 0;
4411 if( !wParam )
4413 // request was sent by a menu
4414 nRet = 1;
4415 MEASUREITEMSTRUCT *pMI = reinterpret_cast<LPMEASUREITEMSTRUCT>(lParam);
4416 if( pMI->CtlType != ODT_MENU )
4417 return 0;
4419 WinSalMenuItem *pSalMenuItem = reinterpret_cast<WinSalMenuItem *>(pMI->itemData);
4420 if( !pSalMenuItem )
4421 return 0;
4423 HDC hdc = GetDC( hWnd );
4424 SIZE strSize;
4426 NONCLIENTMETRICSW ncm = {};
4427 ncm.cbSize = sizeof( ncm );
4428 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4430 // Assume every menu item can be default and printed bold
4431 //ncm.lfMenuFont.lfWeight = FW_BOLD;
4433 HFONT hfntOld = static_cast<HFONT>(SelectObject(hdc, CreateFontIndirectW( &ncm.lfMenuFont )));
4435 // menu text and accelerator
4436 OUString aStr(pSalMenuItem->mText);
4437 if( pSalMenuItem->mAccelText.getLength() )
4439 aStr += " " + pSalMenuItem->mAccelText;
4441 GetTextExtentPoint32W( hdc, o3tl::toW(aStr.getStr()),
4442 aStr.getLength(), &strSize );
4444 // image
4445 Size bmpSize( 16, 16 );
4446 //if( !!pSalMenuItem->maBitmap )
4447 // bmpSize = pSalMenuItem->maBitmap.GetSizePixel();
4449 // checkmark
4450 Size checkSize( GetSystemMetrics( SM_CXMENUCHECK ), GetSystemMetrics( SM_CYMENUCHECK ) );
4452 pMI->itemWidth = checkSize.Width() + 3 + bmpSize.Width() + 3 + strSize.cx;
4453 pMI->itemHeight = std::max( std::max( checkSize.Height(), bmpSize.Height() ), strSize.cy );
4454 pMI->itemHeight += 4;
4456 DeleteObject( SelectObject(hdc, hfntOld) );
4457 ReleaseDC( hWnd, hdc );
4460 return nRet;
4463 static LRESULT ImplDrawItem(HWND, WPARAM wParam, LPARAM lParam )
4465 LRESULT nRet = 0;
4466 if( !wParam )
4468 // request was sent by a menu
4469 nRet = 1;
4470 DRAWITEMSTRUCT *pDI = reinterpret_cast<LPDRAWITEMSTRUCT>(lParam);
4471 if( pDI->CtlType != ODT_MENU )
4472 return 0;
4474 WinSalMenuItem *pSalMenuItem = reinterpret_cast<WinSalMenuItem *>(pDI->itemData);
4475 if( !pSalMenuItem )
4476 return 0;
4478 COLORREF clrPrevText, clrPrevBkgnd;
4479 HFONT hfntOld;
4480 HBRUSH hbrOld;
4481 bool fChecked = (pDI->itemState & ODS_CHECKED);
4482 bool fSelected = (pDI->itemState & ODS_SELECTED);
4483 bool fDisabled = (pDI->itemState & (ODS_DISABLED | ODS_GRAYED));
4485 // Set the appropriate foreground and background colors.
4486 RECT aRect = pDI->rcItem;
4488 if ( fDisabled )
4489 clrPrevText = SetTextColor( pDI->hDC, GetSysColor( COLOR_GRAYTEXT ) );
4490 else
4491 clrPrevText = SetTextColor( pDI->hDC, GetSysColor( fSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT ) );
4493 DWORD colBackground = GetSysColor( fSelected ? COLOR_HIGHLIGHT : COLOR_MENU );
4494 clrPrevBkgnd = SetBkColor( pDI->hDC, colBackground );
4496 hbrOld = static_cast<HBRUSH>(SelectObject( pDI->hDC, CreateSolidBrush( GetBkColor( pDI->hDC ) ) ));
4498 // Fill background
4499 if(!PatBlt( pDI->hDC, aRect.left, aRect.top, aRect.right-aRect.left, aRect.bottom-aRect.top, PATCOPY ))
4500 SAL_WARN("vcl", "PatBlt failed: " << WindowsErrorString(GetLastError()));
4502 int lineHeight = aRect.bottom-aRect.top;
4504 int x = aRect.left;
4505 int y = aRect.top;
4507 int checkWidth = GetSystemMetrics( SM_CXMENUCHECK );
4508 int checkHeight = GetSystemMetrics( SM_CYMENUCHECK );
4509 if( fChecked )
4511 RECT r;
4512 r.left = 0;
4513 r.top = 0;
4514 r.right = checkWidth;
4515 r.bottom = checkWidth;
4516 HDC memDC = CreateCompatibleDC( pDI->hDC );
4517 HBITMAP memBmp = CreateCompatibleBitmap( pDI->hDC, checkWidth, checkHeight );
4518 HBITMAP hOldBmp = static_cast<HBITMAP>(SelectObject( memDC, memBmp ));
4519 DrawFrameControl( memDC, &r, DFC_MENU, DFCS_MENUCHECK );
4520 BitBlt( pDI->hDC, x, y+(lineHeight-checkHeight)/2, checkWidth, checkHeight, memDC, 0, 0, SRCAND );
4521 DeleteObject( SelectObject( memDC, hOldBmp ) );
4522 DeleteDC( memDC );
4524 x += checkWidth+3;
4526 //Size bmpSize = aBitmap.GetSizePixel();
4527 Size bmpSize(16, 16);
4528 if( !!pSalMenuItem->maBitmap )
4530 Bitmap aBitmap( pSalMenuItem->maBitmap );
4532 // set transparent pixels to background color
4533 if( fDisabled )
4534 colBackground = RGB(255,255,255);
4535 aBitmap.Replace( COL_LIGHTMAGENTA,
4536 Color( GetRValue(colBackground),GetGValue(colBackground),GetBValue(colBackground) ));
4538 WinSalBitmap* pSalBmp = static_cast<WinSalBitmap*>(aBitmap.ImplGetSalBitmap().get());
4539 HGLOBAL hDrawDIB = pSalBmp->ImplGethDIB();
4541 if( hDrawDIB )
4543 PBITMAPINFO pBI = static_cast<PBITMAPINFO>(GlobalLock( hDrawDIB ));
4544 PBYTE pBits = reinterpret_cast<PBYTE>(pBI) + pBI->bmiHeader.biSize +
4545 WinSalBitmap::ImplGetDIBColorCount( hDrawDIB ) * sizeof( RGBQUAD );
4547 HBITMAP hBmp = CreateDIBitmap( pDI->hDC, &pBI->bmiHeader, CBM_INIT, pBits, pBI, DIB_RGB_COLORS );
4548 GlobalUnlock( hDrawDIB );
4550 HBRUSH hbrIcon = CreateSolidBrush( GetSysColor( COLOR_GRAYTEXT ) );
4551 DrawStateW( pDI->hDC, hbrIcon, nullptr, reinterpret_cast<LPARAM>(hBmp), WPARAM(0),
4552 x, y+(lineHeight-bmpSize.Height())/2, bmpSize.Width(), bmpSize.Height(),
4553 DST_BITMAP | (fDisabled ? (fSelected ? DSS_MONO : DSS_DISABLED) : DSS_NORMAL) );
4555 DeleteObject( hbrIcon );
4556 DeleteObject( hBmp );
4560 x += bmpSize.Width() + 3;
4561 aRect.left = x;
4563 NONCLIENTMETRICSW ncm = {};
4564 ncm.cbSize = sizeof( ncm );
4565 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
4567 // Print default menu entry with bold font
4568 //if ( pDI->itemState & ODS_DEFAULT )
4569 // ncm.lfMenuFont.lfWeight = FW_BOLD;
4571 hfntOld = static_cast<HFONT>(SelectObject(pDI->hDC, CreateFontIndirectW( &ncm.lfMenuFont )));
4573 SIZE strSize;
4574 OUString aStr( pSalMenuItem->mText );
4575 GetTextExtentPoint32W( pDI->hDC, o3tl::toW(aStr.getStr()),
4576 aStr.getLength(), &strSize );
4578 if(!DrawStateW( pDI->hDC, nullptr, nullptr,
4579 reinterpret_cast<LPARAM>(aStr.getStr()),
4580 WPARAM(0), aRect.left, aRect.top + (lineHeight - strSize.cy)/2, 0, 0,
4581 DST_PREFIXTEXT | (fDisabled && !fSelected ? DSS_DISABLED : DSS_NORMAL) ) )
4582 SAL_WARN("vcl", "DrawStateW failed: " << WindowsErrorString(GetLastError()));
4584 if( pSalMenuItem->mAccelText.getLength() )
4586 SIZE strSizeA;
4587 aStr = pSalMenuItem->mAccelText;
4588 GetTextExtentPoint32W( pDI->hDC, o3tl::toW(aStr.getStr()),
4589 aStr.getLength(), &strSizeA );
4590 TEXTMETRICW tm;
4591 GetTextMetricsW( pDI->hDC, &tm );
4593 // position the accelerator string to the right but leave space for the
4594 // (potential) submenu arrow (tm.tmMaxCharWidth)
4595 if(!DrawStateW( pDI->hDC, nullptr, nullptr,
4596 reinterpret_cast<LPARAM>(aStr.getStr()),
4597 WPARAM(0), aRect.right-strSizeA.cx-tm.tmMaxCharWidth, aRect.top + (lineHeight - strSizeA.cy)/2, 0, 0,
4598 DST_TEXT | (fDisabled && !fSelected ? DSS_DISABLED : DSS_NORMAL) ) )
4599 SAL_WARN("vcl", "DrawStateW failed: " << WindowsErrorString(GetLastError()));
4602 // Restore the original font and colors.
4603 DeleteObject( SelectObject( pDI->hDC, hbrOld ) );
4604 DeleteObject( SelectObject( pDI->hDC, hfntOld) );
4605 SetTextColor(pDI->hDC, clrPrevText);
4606 SetBkColor(pDI->hDC, clrPrevBkgnd);
4608 return nRet;
4611 static bool ImplHandleMenuActivate( HWND hWnd, WPARAM wParam, LPARAM )
4613 // Menu activation
4614 WinSalFrame* pFrame = GetWindowPtr( hWnd );
4615 if ( !pFrame )
4616 return false;
4618 HMENU hMenu = reinterpret_cast<HMENU>(wParam);
4619 // WORD nPos = LOWORD (lParam);
4620 // bool bWindowMenu = (bool) HIWORD(lParam);
4622 // Send activate and deactivate together, so we have not keep track of opened menus
4623 // this will be enough to have the menus updated correctly
4624 SalMenuEvent aMenuEvt;
4625 WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( hMenu, 0 );
4626 if( pSalMenuItem )
4627 aMenuEvt.mpMenu = pSalMenuItem->mpMenu;
4628 else
4629 aMenuEvt.mpMenu = nullptr;
4631 bool nRet = pFrame->CallCallback( SalEvent::MenuActivate, &aMenuEvt );
4632 if( nRet )
4633 nRet = pFrame->CallCallback( SalEvent::MenuDeactivate, &aMenuEvt );
4634 if( nRet )
4635 pFrame->mLastActivatedhMenu = hMenu;
4637 return nRet;
4640 static bool ImplHandleMenuSelect( HWND hWnd, WPARAM wParam, LPARAM lParam )
4642 // Menu selection
4643 WinSalFrame* pFrame = GetWindowPtr( hWnd );
4644 if ( !pFrame )
4645 return false;
4647 WORD nId = LOWORD(wParam); // menu item or submenu index
4648 WORD nFlags = HIWORD(wParam);
4649 HMENU hMenu = reinterpret_cast<HMENU>(lParam);
4651 // check if we have to process the message
4652 if( !GetSalData()->IsKnownMenuHandle( hMenu ) )
4653 return false;
4655 bool bByPosition = false;
4656 if( nFlags & MF_POPUP )
4657 bByPosition = true;
4659 bool nRet = false;
4660 if ( hMenu && !pFrame->mLastActivatedhMenu )
4662 // we never activated a menu (ie, no WM_INITMENUPOPUP has occurred yet)
4663 // which means this must be the menubar -> send activation/deactivation
4664 SalMenuEvent aMenuEvt;
4665 WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( hMenu, nId, bByPosition );
4666 if( pSalMenuItem )
4667 aMenuEvt.mpMenu = pSalMenuItem->mpMenu;
4668 else
4669 aMenuEvt.mpMenu = nullptr;
4671 nRet = pFrame->CallCallback( SalEvent::MenuActivate, &aMenuEvt );
4672 if( nRet )
4673 nRet = pFrame->CallCallback( SalEvent::MenuDeactivate, &aMenuEvt );
4674 if( nRet )
4675 pFrame->mLastActivatedhMenu = hMenu;
4678 if( !hMenu && nFlags == 0xFFFF )
4680 // all menus are closed, reset activation logic
4681 pFrame->mLastActivatedhMenu = nullptr;
4684 if( hMenu )
4686 // hMenu must be saved, as it is not passed in WM_COMMAND which always occurs after a selection
4687 // if a menu is closed due to a command selection then hMenu is NULL, but WM_COMMAND comes later
4688 // so we must not overwrite it in this case
4689 pFrame->mSelectedhMenu = hMenu;
4691 // send highlight event
4692 if( nFlags & MF_POPUP )
4694 // submenu selected
4695 // wParam now carries an index instead of an id -> retrieve id
4696 MENUITEMINFOW mi = {};
4697 mi.cbSize = sizeof( mi );
4698 mi.fMask = MIIM_ID;
4699 if( GetMenuItemInfoW( hMenu, LOWORD(wParam), TRUE, &mi) )
4700 nId = sal::static_int_cast<WORD>(mi.wID);
4703 SalMenuEvent aMenuEvt;
4704 aMenuEvt.mnId = nId;
4705 WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( hMenu, nId, false );
4706 if( pSalMenuItem )
4707 aMenuEvt.mpMenu = pSalMenuItem->mpMenu;
4708 else
4709 aMenuEvt.mpMenu = nullptr;
4711 nRet = pFrame->CallCallback( SalEvent::MenuHighlight, &aMenuEvt );
4714 return nRet;
4717 static bool ImplHandleCommand( HWND hWnd, WPARAM wParam, LPARAM )
4719 WinSalFrame* pFrame = GetWindowPtr( hWnd );
4720 if ( !pFrame )
4721 return false;
4723 bool nRet = false;
4724 if( !HIWORD(wParam) )
4726 // Menu command
4727 WORD nId = LOWORD(wParam);
4728 if( nId ) // zero for separators
4730 SalMenuEvent aMenuEvt;
4731 aMenuEvt.mnId = nId;
4732 WinSalMenuItem *pSalMenuItem = ImplGetSalMenuItem( pFrame->mSelectedhMenu, nId, false );
4733 if( pSalMenuItem )
4734 aMenuEvt.mpMenu = pSalMenuItem->mpMenu;
4735 else
4736 aMenuEvt.mpMenu = nullptr;
4738 nRet = pFrame->CallCallback( SalEvent::MenuCommand, &aMenuEvt );
4741 return nRet;
4744 static bool ImplHandleSysCommand( HWND hWnd, WPARAM wParam, LPARAM lParam )
4746 WinSalFrame* pFrame = GetWindowPtr( hWnd );
4747 if ( !pFrame )
4748 return false;
4750 WPARAM nCommand = wParam & 0xFFF0;
4752 if ( pFrame->mbFullScreen )
4754 BOOL bMaximize = IsZoomed( pFrame->mhWnd );
4755 BOOL bMinimize = IsIconic( pFrame->mhWnd );
4756 if ( (nCommand == SC_SIZE) ||
4757 (!bMinimize && (nCommand == SC_MOVE)) ||
4758 (!bMaximize && (nCommand == SC_MAXIMIZE)) ||
4759 (bMaximize && (nCommand == SC_RESTORE)) )
4761 return true;
4765 if ( nCommand == SC_MOVE )
4767 WinSalTimer* pTimer = static_cast<WinSalTimer*>( ImplGetSVData()->maSchedCtx.mpSalTimer );
4768 if ( pTimer )
4769 pTimer->SetForceRealTimer( true );
4772 if ( nCommand == SC_KEYMENU )
4774 // do not process SC_KEYMENU if we have a native menu
4775 // Windows should handle this
4776 if( GetMenu( hWnd ) )
4777 return false;
4779 // Process here KeyMenu events only for Alt to activate the MenuBar,
4780 // or if a SysChild window is in focus, as Alt-key-combinations are
4781 // only processed via this event
4782 if ( !LOWORD( lParam ) )
4784 // Only trigger if no other key is pressed.
4785 // Contrary to Docu the CharCode is delivered with the x-coordinate
4786 // that is pressed in addition.
4787 // Also 32 for space, 99 for c, 100 for d, ...
4788 // As this is not documented, we check the state of the space-bar
4789 if ( GetKeyState( VK_SPACE ) & 0x8000 )
4790 return false;
4792 // to avoid activating the MenuBar for Alt+MouseKey
4793 if ( (GetKeyState( VK_LBUTTON ) & 0x8000) ||
4794 (GetKeyState( VK_RBUTTON ) & 0x8000) ||
4795 (GetKeyState( VK_MBUTTON ) & 0x8000) ||
4796 (GetKeyState( VK_SHIFT ) & 0x8000) )
4797 return true;
4799 SalKeyEvent aKeyEvt;
4800 aKeyEvt.mnCode = KEY_MENU;
4801 aKeyEvt.mnCharCode = 0;
4802 aKeyEvt.mnRepeat = 0;
4803 bool nRet = pFrame->CallCallback( SalEvent::KeyInput, &aKeyEvt );
4804 pFrame->CallCallback( SalEvent::KeyUp, &aKeyEvt );
4805 return nRet;
4807 else
4809 // check if a SysChild is in focus
4810 HWND hFocusWnd = ::GetFocus();
4811 if ( hFocusWnd && ImplFindSalObject( hFocusWnd ) )
4813 char cKeyCode = static_cast<char>(static_cast<unsigned char>(LOWORD( lParam )));
4814 // LowerCase
4815 if ( (cKeyCode >= 65) && (cKeyCode <= 90) )
4816 cKeyCode += 32;
4817 // We only accept 0-9 and A-Z; all other keys have to be
4818 // processed by the SalObj hook
4819 if ( ((cKeyCode >= 48) && (cKeyCode <= 57)) ||
4820 ((cKeyCode >= 97) && (cKeyCode <= 122)) )
4822 sal_uInt16 nModCode = 0;
4823 if ( GetKeyState( VK_SHIFT ) & 0x8000 )
4824 nModCode |= KEY_SHIFT;
4825 if ( GetKeyState( VK_CONTROL ) & 0x8000 )
4826 nModCode |= KEY_MOD1;
4827 nModCode |= KEY_MOD2;
4829 SalKeyEvent aKeyEvt;
4830 if ( (cKeyCode >= 48) && (cKeyCode <= 57) )
4831 aKeyEvt.mnCode = KEY_0+(cKeyCode-48);
4832 else
4833 aKeyEvt.mnCode = KEY_A+(cKeyCode-97);
4834 aKeyEvt.mnCode |= nModCode;
4835 aKeyEvt.mnCharCode = cKeyCode;
4836 aKeyEvt.mnRepeat = 0;
4837 bool nRet = pFrame->CallCallback( SalEvent::KeyInput, &aKeyEvt );
4838 pFrame->CallCallback( SalEvent::KeyUp, &aKeyEvt );
4839 return nRet;
4845 return false;
4848 static void ImplHandleInputLangChange( HWND hWnd, WPARAM, LPARAM lParam )
4850 ImplSalYieldMutexAcquireWithWait();
4852 // check if we support IME
4853 WinSalFrame* pFrame = GetWindowPtr( hWnd );
4855 if ( !pFrame )
4856 return;
4858 if ( pFrame->mbIME && pFrame->mhDefIMEContext )
4860 HKL hKL = reinterpret_cast<HKL>(lParam);
4861 UINT nImeProps = ImmGetProperty( hKL, IGP_PROPERTY );
4863 pFrame->mbSpezIME = (nImeProps & IME_PROP_SPECIAL_UI) != 0;
4864 pFrame->mbAtCursorIME = (nImeProps & IME_PROP_AT_CARET) != 0;
4865 pFrame->mbHandleIME = !pFrame->mbSpezIME;
4868 // trigger input language and codepage update
4869 UINT nLang = pFrame->mnInputLang;
4870 ImplUpdateInputLang( pFrame );
4872 // notify change
4873 if( nLang != pFrame->mnInputLang )
4874 pFrame->CallCallback( SalEvent::InputLanguageChange, nullptr );
4876 // reinit spec. keys
4877 GetSalData()->initKeyCodeMap();
4879 ImplSalYieldMutexRelease();
4882 static void ImplUpdateIMECursorPos( WinSalFrame* pFrame, HIMC hIMC )
4884 COMPOSITIONFORM aForm = {};
4886 // get cursor position and from it calculate default position
4887 // for the composition window
4888 SalExtTextInputPosEvent aPosEvt;
4889 pFrame->CallCallback( SalEvent::ExtTextInputPos, &aPosEvt );
4890 if ( (aPosEvt.mnX == -1) && (aPosEvt.mnY == -1) )
4891 aForm.dwStyle |= CFS_DEFAULT;
4892 else
4894 aForm.dwStyle |= CFS_POINT;
4895 aForm.ptCurrentPos.x = aPosEvt.mnX;
4896 aForm.ptCurrentPos.y = aPosEvt.mnY;
4898 ImmSetCompositionWindow( hIMC, &aForm );
4900 // Because not all IME's use this values, we create
4901 // a Windows caret to force the Position from the IME
4902 if ( GetFocus() == pFrame->mhWnd )
4904 CreateCaret( pFrame->mhWnd, nullptr,
4905 aPosEvt.mnWidth, aPosEvt.mnHeight );
4906 SetCaretPos( aPosEvt.mnX, aPosEvt.mnY );
4910 static bool ImplHandleIMEStartComposition( HWND hWnd )
4912 bool bDef = true;
4914 ImplSalYieldMutexAcquireWithWait();
4916 WinSalFrame* pFrame = GetWindowPtr( hWnd );
4917 if ( pFrame )
4919 HIMC hIMC = ImmGetContext( hWnd );
4920 if ( hIMC )
4922 ImplUpdateIMECursorPos( pFrame, hIMC );
4923 ImmReleaseContext( hWnd, hIMC );
4926 if ( pFrame->mbHandleIME )
4928 if ( pFrame->mbAtCursorIME )
4929 bDef = false;
4933 ImplSalYieldMutexRelease();
4935 return bDef;
4938 static bool ImplHandleIMECompositionInput( WinSalFrame* pFrame,
4939 HIMC hIMC, LPARAM lParam )
4941 bool bDef = true;
4943 // Init Event
4944 SalExtTextInputEvent aEvt;
4945 aEvt.mpTextAttr = nullptr;
4946 aEvt.mnCursorPos = 0;
4947 aEvt.mnCursorFlags = 0;
4949 // If we get a result string, then we handle this input
4950 if ( lParam & GCS_RESULTSTR )
4952 bDef = false;
4954 LONG nTextLen = ImmGetCompositionStringW( hIMC, GCS_RESULTSTR, nullptr, 0 ) / sizeof( WCHAR );
4955 if ( nTextLen >= 0 )
4957 auto pTextBuf = std::make_unique<WCHAR[]>(nTextLen);
4958 ImmGetCompositionStringW( hIMC, GCS_RESULTSTR, pTextBuf.get(), nTextLen*sizeof( WCHAR ) );
4959 aEvt.maText = OUString( o3tl::toU(pTextBuf.get()), static_cast<sal_Int32>(nTextLen) );
4962 aEvt.mnCursorPos = aEvt.maText.getLength();
4963 pFrame->CallCallback( SalEvent::ExtTextInput, &aEvt );
4964 pFrame->CallCallback( SalEvent::EndExtTextInput, nullptr );
4965 ImplUpdateIMECursorPos( pFrame, hIMC );
4968 // If the IME doesn't support OnSpot input, then there is nothing to do
4969 if ( !pFrame->mbAtCursorIME )
4970 return !bDef;
4972 // If we get new Composition data, then we handle this new input
4973 if ( (lParam & (GCS_COMPSTR | GCS_COMPATTR)) ||
4974 ((lParam & GCS_CURSORPOS) && !(lParam & GCS_RESULTSTR)) )
4976 bDef = false;
4978 ExtTextInputAttr* pSalAttrAry = nullptr;
4979 LONG nTextLen = ImmGetCompositionStringW( hIMC, GCS_COMPSTR, nullptr, 0 ) / sizeof( WCHAR );
4980 if ( nTextLen > 0 )
4983 auto pTextBuf = std::make_unique<WCHAR[]>(nTextLen);
4984 ImmGetCompositionStringW( hIMC, GCS_COMPSTR, pTextBuf.get(), nTextLen*sizeof( WCHAR ) );
4985 aEvt.maText = OUString( o3tl::toU(pTextBuf.get()), static_cast<sal_Int32>(nTextLen) );
4988 std::unique_ptr<BYTE[]> pAttrBuf;
4989 LONG nAttrLen = ImmGetCompositionStringW( hIMC, GCS_COMPATTR, nullptr, 0 );
4990 if ( nAttrLen > 0 )
4992 pAttrBuf.reset(new BYTE[nAttrLen]);
4993 ImmGetCompositionStringW( hIMC, GCS_COMPATTR, pAttrBuf.get(), nAttrLen );
4996 if ( pAttrBuf )
4998 sal_Int32 nTextLen2 = aEvt.maText.getLength();
4999 pSalAttrAry = new ExtTextInputAttr[nTextLen2];
5000 memset( pSalAttrAry, 0, nTextLen2*sizeof( sal_uInt16 ) );
5001 for( sal_Int32 i = 0; (i < nTextLen2) && (i < nAttrLen); i++ )
5003 BYTE nWinAttr = pAttrBuf.get()[i];
5004 ExtTextInputAttr nSalAttr;
5005 if ( nWinAttr == ATTR_TARGET_CONVERTED )
5007 nSalAttr = ExtTextInputAttr::BoldUnderline;
5008 aEvt.mnCursorFlags |= EXTTEXTINPUT_CURSOR_INVISIBLE;
5010 else if ( nWinAttr == ATTR_CONVERTED )
5011 nSalAttr = ExtTextInputAttr::DashDotUnderline;
5012 else if ( nWinAttr == ATTR_TARGET_NOTCONVERTED )
5013 nSalAttr = ExtTextInputAttr::Highlight;
5014 else if ( nWinAttr == ATTR_INPUT_ERROR )
5015 nSalAttr = ExtTextInputAttr::RedText | ExtTextInputAttr::DottedUnderline;
5016 else /* ( nWinAttr == ATTR_INPUT ) */
5017 nSalAttr = ExtTextInputAttr::DottedUnderline;
5018 pSalAttrAry[i] = nSalAttr;
5021 aEvt.mpTextAttr = pSalAttrAry;
5025 // Only when we get new composition data, we must send this event
5026 if ( (nTextLen > 0) || !(lParam & GCS_RESULTSTR) )
5028 // End the mode, if the last character is deleted
5029 if ( !nTextLen && !pFrame->mbCandidateMode )
5031 pFrame->CallCallback( SalEvent::ExtTextInput, &aEvt );
5032 pFrame->CallCallback( SalEvent::EndExtTextInput, nullptr );
5034 else
5036 // Because Cursor-Position and DeltaStart never updated
5037 // from the korean input engine, we must handle this here
5038 if ( lParam & CS_INSERTCHAR )
5040 aEvt.mnCursorPos = nTextLen;
5041 if ( aEvt.mnCursorPos && (lParam & CS_NOMOVECARET) )
5042 aEvt.mnCursorPos--;
5044 else
5045 aEvt.mnCursorPos = LOWORD( ImmGetCompositionStringW( hIMC, GCS_CURSORPOS, nullptr, 0 ) );
5047 if ( pFrame->mbCandidateMode )
5048 aEvt.mnCursorFlags |= EXTTEXTINPUT_CURSOR_INVISIBLE;
5049 if ( lParam & CS_NOMOVECARET )
5050 aEvt.mnCursorFlags |= EXTTEXTINPUT_CURSOR_OVERWRITE;
5052 pFrame->CallCallback( SalEvent::ExtTextInput, &aEvt );
5054 ImplUpdateIMECursorPos( pFrame, hIMC );
5057 if ( pSalAttrAry )
5058 delete [] pSalAttrAry;
5061 return !bDef;
5064 static bool ImplHandleIMEComposition( HWND hWnd, LPARAM lParam )
5066 bool bDef = true;
5067 ImplSalYieldMutexAcquireWithWait();
5069 WinSalFrame* pFrame = GetWindowPtr( hWnd );
5070 if ( pFrame && (!lParam || (lParam & GCS_RESULTSTR)) )
5072 // reset the background mode for each text input,
5073 // as some tools such as RichWin may have changed it
5074 if ( pFrame->mpLocalGraphics &&
5075 pFrame->mpLocalGraphics->getHDC() )
5076 SetBkMode( pFrame->mpLocalGraphics->getHDC(), TRANSPARENT );
5079 if ( pFrame && pFrame->mbHandleIME )
5081 if ( !lParam )
5083 SalExtTextInputEvent aEvt;
5084 aEvt.mpTextAttr = nullptr;
5085 aEvt.mnCursorPos = 0;
5086 aEvt.mnCursorFlags = 0;
5087 pFrame->CallCallback( SalEvent::ExtTextInput, &aEvt );
5088 pFrame->CallCallback( SalEvent::EndExtTextInput, nullptr );
5090 else if ( lParam & (GCS_RESULTSTR | GCS_COMPSTR | GCS_COMPATTR | GCS_CURSORPOS) )
5092 HIMC hIMC = ImmGetContext( hWnd );
5093 if ( hIMC )
5095 if ( ImplHandleIMECompositionInput( pFrame, hIMC, lParam ) )
5096 bDef = false;
5098 ImmReleaseContext( hWnd, hIMC );
5103 ImplSalYieldMutexRelease();
5104 return bDef;
5107 static bool ImplHandleIMEEndComposition( HWND hWnd )
5109 bool bDef = true;
5111 ImplSalYieldMutexAcquireWithWait();
5113 WinSalFrame* pFrame = GetWindowPtr( hWnd );
5114 if ( pFrame && pFrame->mbHandleIME )
5116 if ( pFrame->mbAtCursorIME )
5117 bDef = false;
5120 ImplSalYieldMutexRelease();
5122 return bDef;
5125 static bool ImplHandleAppCommand( HWND hWnd, LPARAM lParam, LRESULT & nRet )
5127 MediaCommand nCommand;
5128 switch( GET_APPCOMMAND_LPARAM(lParam) )
5130 case APPCOMMAND_MEDIA_CHANNEL_DOWN: nCommand = MediaCommand::ChannelDown; break;
5131 case APPCOMMAND_MEDIA_CHANNEL_UP: nCommand = MediaCommand::ChannelUp; break;
5132 case APPCOMMAND_MEDIA_NEXTTRACK: nCommand = MediaCommand::NextTrack; break;
5133 case APPCOMMAND_MEDIA_PAUSE: nCommand = MediaCommand::Pause; break;
5134 case APPCOMMAND_MEDIA_PLAY: nCommand = MediaCommand::Play; break;
5135 case APPCOMMAND_MEDIA_PLAY_PAUSE: nCommand = MediaCommand::PlayPause; break;
5136 case APPCOMMAND_MEDIA_PREVIOUSTRACK: nCommand = MediaCommand::PreviousTrack; break;
5137 case APPCOMMAND_MEDIA_RECORD: nCommand = MediaCommand::Record; break;
5138 case APPCOMMAND_MEDIA_REWIND: nCommand = MediaCommand::Rewind; break;
5139 case APPCOMMAND_MEDIA_STOP: nCommand = MediaCommand::Stop; break;
5140 case APPCOMMAND_MIC_ON_OFF_TOGGLE: nCommand = MediaCommand::MicOnOffToggle; break;
5141 case APPCOMMAND_MICROPHONE_VOLUME_DOWN: nCommand = MediaCommand::MicrophoneVolumeDown; break;
5142 case APPCOMMAND_MICROPHONE_VOLUME_MUTE: nCommand = MediaCommand::MicrophoneVolumeMute; break;
5143 case APPCOMMAND_MICROPHONE_VOLUME_UP: nCommand = MediaCommand::MicrophoneVolumeUp; break;
5144 case APPCOMMAND_VOLUME_DOWN: nCommand = MediaCommand::VolumeDown; break;
5145 case APPCOMMAND_VOLUME_MUTE: nCommand = MediaCommand::VolumeMute; break;
5146 case APPCOMMAND_VOLUME_UP: nCommand = MediaCommand::VolumeUp; break;
5147 default:
5148 return false;
5151 WinSalFrame* pFrame = GetWindowPtr( hWnd );
5152 vcl::Window *pWindow = pFrame ? pFrame->GetWindow() : nullptr;
5154 if( pWindow )
5156 const Point aPoint;
5157 CommandMediaData aMediaData(nCommand);
5158 CommandEvent aCEvt( aPoint, CommandEventId::Media, false, &aMediaData );
5159 NotifyEvent aNCmdEvt( MouseNotifyEvent::COMMAND, pWindow, &aCEvt );
5161 if ( !ImplCallPreNotify( aNCmdEvt ) )
5163 pWindow->Command( aCEvt );
5164 nRet = 1;
5165 return !aMediaData.GetPassThroughToOS();
5169 return false;
5172 static void ImplHandleIMENotify( HWND hWnd, WPARAM wParam )
5174 if ( wParam == WPARAM(IMN_OPENCANDIDATE) )
5176 ImplSalYieldMutexAcquireWithWait();
5178 WinSalFrame* pFrame = GetWindowPtr( hWnd );
5179 if ( pFrame && pFrame->mbHandleIME &&
5180 pFrame->mbAtCursorIME )
5182 // we want to hide the cursor
5183 pFrame->mbCandidateMode = true;
5184 ImplHandleIMEComposition( hWnd, GCS_CURSORPOS );
5186 HWND hWnd2 = pFrame->mhWnd;
5187 HIMC hIMC = ImmGetContext( hWnd2 );
5188 if ( hIMC )
5190 LONG nBufLen = ImmGetCompositionStringW( hIMC, GCS_COMPSTR, nullptr, 0 );
5191 if ( nBufLen >= 1 )
5193 SalExtTextInputPosEvent aPosEvt;
5194 pFrame->CallCallback( SalEvent::ExtTextInputPos, &aPosEvt );
5196 // Vertical !!!
5197 CANDIDATEFORM aForm;
5198 aForm.dwIndex = 0;
5199 aForm.dwStyle = CFS_EXCLUDE;
5200 aForm.ptCurrentPos.x = aPosEvt.mnX;
5201 aForm.ptCurrentPos.y = aPosEvt.mnY+1;
5202 aForm.rcArea.left = aPosEvt.mnX;
5203 aForm.rcArea.top = aPosEvt.mnY;
5204 aForm.rcArea.right = aForm.rcArea.left+aPosEvt.mnExtWidth+1;
5205 aForm.rcArea.bottom = aForm.rcArea.top+aPosEvt.mnHeight+1;
5206 ImmSetCandidateWindow( hIMC, &aForm );
5209 ImmReleaseContext( hWnd2, hIMC );
5213 ImplSalYieldMutexRelease();
5215 else if ( wParam == WPARAM(IMN_CLOSECANDIDATE) )
5217 ImplSalYieldMutexAcquireWithWait();
5218 WinSalFrame* pFrame = GetWindowPtr( hWnd );
5219 if ( pFrame )
5220 pFrame->mbCandidateMode = false;
5221 ImplSalYieldMutexRelease();
5225 static bool
5226 ImplHandleGetObject(HWND hWnd, LPARAM lParam, WPARAM wParam, LRESULT & nRet)
5228 // IA2 should be enabled automatically
5229 AllSettings aSettings = Application::GetSettings();
5230 MiscSettings aMisc = aSettings.GetMiscSettings();
5231 aMisc.SetEnableATToolSupport( true );
5232 aSettings.SetMiscSettings( aMisc );
5233 Application::SetSettings( aSettings );
5235 if (!Application::GetSettings().GetMiscSettings().GetEnableATToolSupport())
5236 return false; // locked down somehow ?
5238 ImplSVData* pSVData = ImplGetSVData();
5240 // Make sure to launch Accessibility only the following criteria are satisfied
5241 // to avoid RFT interrupts regular accessibility processing
5242 if ( !pSVData->mxAccessBridge.is() )
5244 if( !InitAccessBridge() )
5245 return false;
5248 uno::Reference< accessibility::XMSAAService > xMSAA( pSVData->mxAccessBridge, uno::UNO_QUERY );
5249 if ( xMSAA.is() )
5251 sal_Int32 lParam32 = static_cast<sal_Int32>(lParam);
5252 sal_uInt32 wParam32 = static_cast<sal_uInt32>(wParam);
5254 // mhOnSetTitleWnd not set to reasonable value anywhere...
5255 if ( lParam32 == OBJID_CLIENT )
5257 nRet = xMSAA->getAccObjectPtr(
5258 reinterpret_cast<sal_Int64>(hWnd), lParam32, wParam32);
5259 if (nRet != 0)
5260 return true;
5263 return false;
5266 static LRESULT ImplHandleIMEReconvertString( HWND hWnd, LPARAM lParam )
5268 WinSalFrame* pFrame = GetWindowPtr( hWnd );
5269 LPRECONVERTSTRING pReconvertString = reinterpret_cast<LPRECONVERTSTRING>(lParam);
5270 LRESULT nRet = 0;
5271 SalSurroundingTextRequestEvent aEvt;
5272 aEvt.maText.clear();
5273 aEvt.mnStart = aEvt.mnEnd = 0;
5275 UINT nImeProps = ImmGetProperty( GetKeyboardLayout( 0 ), IGP_SETCOMPSTR );
5276 if( (nImeProps & SCS_CAP_SETRECONVERTSTRING) == 0 )
5278 // This IME does not support reconversion.
5279 return 0;
5282 if( !pReconvertString )
5284 // The first call for reconversion.
5285 pFrame->CallCallback( SalEvent::StartReconversion, nullptr );
5287 // Retrieve the surrounding text from the focused control.
5288 pFrame->CallCallback( SalEvent::SurroundingTextRequest, &aEvt );
5290 if( aEvt.maText.isEmpty())
5292 return 0;
5295 nRet = sizeof(RECONVERTSTRING) + (aEvt.maText.getLength() + 1) * sizeof(WCHAR);
5297 else
5299 // The second call for reconversion.
5301 // Retrieve the surrounding text from the focused control.
5302 pFrame->CallCallback( SalEvent::SurroundingTextRequest, &aEvt );
5303 nRet = sizeof(RECONVERTSTRING) + (aEvt.maText.getLength() + 1) * sizeof(WCHAR);
5305 pReconvertString->dwStrOffset = sizeof(RECONVERTSTRING);
5306 pReconvertString->dwStrLen = aEvt.maText.getLength();
5307 pReconvertString->dwCompStrOffset = aEvt.mnStart * sizeof(WCHAR);
5308 pReconvertString->dwCompStrLen = aEvt.mnEnd - aEvt.mnStart;
5309 pReconvertString->dwTargetStrOffset = pReconvertString->dwCompStrOffset;
5310 pReconvertString->dwTargetStrLen = pReconvertString->dwCompStrLen;
5312 memcpy( pReconvertString + 1, aEvt.maText.getStr(), (aEvt.maText.getLength() + 1) * sizeof(WCHAR) );
5315 // just return the required size of buffer to reconvert.
5316 return nRet;
5319 static LRESULT ImplHandleIMEConfirmReconvertString( HWND hWnd, LPARAM lParam )
5321 WinSalFrame* pFrame = GetWindowPtr( hWnd );
5322 LPRECONVERTSTRING pReconvertString = reinterpret_cast<LPRECONVERTSTRING>(lParam);
5323 SalSurroundingTextRequestEvent aEvt;
5324 aEvt.maText.clear();
5325 aEvt.mnStart = aEvt.mnEnd = 0;
5327 pFrame->CallCallback( SalEvent::SurroundingTextRequest, &aEvt );
5329 sal_uLong nTmpStart = pReconvertString->dwCompStrOffset / sizeof(WCHAR);
5330 sal_uLong nTmpEnd = nTmpStart + pReconvertString->dwCompStrLen;
5332 if( nTmpStart != aEvt.mnStart || nTmpEnd != aEvt.mnEnd )
5334 SalSurroundingTextSelectionChangeEvent aSelEvt { nTmpStart, nTmpEnd };
5335 pFrame->CallCallback( SalEvent::SurroundingTextSelectionChange, &aSelEvt );
5338 return TRUE;
5341 static LRESULT ImplHandleIMEQueryCharPosition( HWND hWnd, LPARAM lParam ) {
5342 WinSalFrame* pFrame = GetWindowPtr( hWnd );
5343 PIMECHARPOSITION pQueryCharPosition = reinterpret_cast<PIMECHARPOSITION>(lParam);
5344 if ( pQueryCharPosition->dwSize < sizeof(IMECHARPOSITION) )
5345 return FALSE;
5347 SalQueryCharPositionEvent aEvt;
5348 aEvt.mbValid = false;
5349 aEvt.mnCharPos = pQueryCharPosition->dwCharPos;
5351 pFrame->CallCallback( SalEvent::QueryCharPosition, &aEvt );
5353 if ( !aEvt.mbValid )
5354 return FALSE;
5356 if ( aEvt.mbVertical )
5358 // For vertical writing, the base line is left edge of the rectangle
5359 // and the target position is top-right corner.
5360 pQueryCharPosition->pt.x = aEvt.mnCursorBoundX + aEvt.mnCursorBoundWidth;
5361 pQueryCharPosition->pt.y = aEvt.mnCursorBoundY;
5362 pQueryCharPosition->cLineHeight = aEvt.mnCursorBoundWidth;
5364 else
5366 // For horizontal writing, the base line is the bottom edge of the rectangle.
5367 // and the target position is top-left corner.
5368 pQueryCharPosition->pt.x = aEvt.mnCursorBoundX;
5369 pQueryCharPosition->pt.y = aEvt.mnCursorBoundY;
5370 pQueryCharPosition->cLineHeight = aEvt.mnCursorBoundHeight;
5373 // Currently not supported but many IMEs usually ignore them.
5374 pQueryCharPosition->rcDocument.left = 0;
5375 pQueryCharPosition->rcDocument.top = 0;
5376 pQueryCharPosition->rcDocument.right = 0;
5377 pQueryCharPosition->rcDocument.bottom = 0;
5379 return TRUE;
5382 void SalTestMouseLeave()
5384 SalData* pSalData = GetSalData();
5386 if ( pSalData->mhWantLeaveMsg && !::GetCapture() )
5388 POINT aPt;
5389 GetCursorPos( &aPt );
5390 if ( pSalData->mhWantLeaveMsg != WindowFromPoint( aPt ) )
5391 SendMessageW( pSalData->mhWantLeaveMsg, SAL_MSG_MOUSELEAVE, 0, MAKELPARAM( aPt.x, aPt.y ) );
5395 static bool ImplSalWheelMousePos( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ,
5396 LRESULT& rResult )
5398 POINT aPt;
5399 POINT aScreenPt;
5400 aScreenPt.x = static_cast<short>(LOWORD( lParam ));
5401 aScreenPt.y = static_cast<short>(HIWORD( lParam ));
5402 // find child window that is at this position
5403 HWND hChildWnd;
5404 HWND hWheelWnd = hWnd;
5407 hChildWnd = hWheelWnd;
5408 aPt = aScreenPt;
5409 ScreenToClient( hChildWnd, &aPt );
5410 hWheelWnd = ChildWindowFromPointEx( hChildWnd, aPt, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT );
5412 while ( hWheelWnd && (hWheelWnd != hChildWnd) );
5413 if ( hWheelWnd && (hWheelWnd != hWnd) &&
5414 (hWheelWnd != ::GetFocus()) && IsWindowEnabled( hWheelWnd ) )
5416 rResult = SendMessageW( hWheelWnd, nMsg, wParam, lParam );
5417 return false;
5420 return true;
5423 static LRESULT CALLBACK SalFrameWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, bool& rDef )
5425 LRESULT nRet = 0;
5426 static bool bInWheelMsg = false;
5427 static bool bInQueryEnd = false;
5429 SAL_INFO("vcl.gdi.wndproc", "SalFrameWndProc(nMsg=" << nMsg << ", wParam=" << wParam << ", lParam=" << lParam << ")");
5431 // By WM_CREATE we connect the frame with the window handle
5432 if ( nMsg == WM_CREATE )
5434 // Save Window-Instance in Windowhandle
5435 // Can also be used for the A-Version, because the struct
5436 // to access lpCreateParams is the same structure
5437 CREATESTRUCTW* pStruct = reinterpret_cast<CREATESTRUCTW*>(lParam);
5438 WinSalFrame* pFrame = static_cast<WinSalFrame*>(pStruct->lpCreateParams);
5439 if ( pFrame != nullptr )
5441 SetWindowPtr( hWnd, pFrame );
5442 // Set HWND already here, as data might be used already
5443 // when messages are being sent by CreateWindow()
5444 pFrame->mhWnd = hWnd;
5445 pFrame->maSysData.hWnd = hWnd;
5447 return 0;
5450 ImplSVData* pSVData = ImplGetSVData();
5451 // #i72707# TODO: the mbDeInit check will not be needed
5452 // once all windows that are not properly closed on exit got fixed
5453 if( pSVData->mbDeInit )
5454 return 0;
5456 if ( WM_USER_SYSTEM_WINDOW_ACTIVATED == nMsg )
5458 ImplHideSplash();
5459 return 0;
5462 switch( nMsg )
5464 case WM_MOUSEMOVE:
5465 case WM_LBUTTONDOWN:
5466 case WM_MBUTTONDOWN:
5467 case WM_RBUTTONDOWN:
5468 case WM_LBUTTONUP:
5469 case WM_MBUTTONUP:
5470 case WM_RBUTTONUP:
5471 case WM_NCMOUSEMOVE:
5472 case SAL_MSG_MOUSELEAVE:
5473 ImplSalYieldMutexAcquireWithWait();
5474 rDef = !ImplHandleMouseMsg( hWnd, nMsg, wParam, lParam );
5475 ImplSalYieldMutexRelease();
5476 break;
5478 case WM_NCLBUTTONDOWN:
5479 case WM_NCMBUTTONDOWN:
5480 case WM_NCRBUTTONDOWN:
5481 ImplSalYieldMutexAcquireWithWait();
5482 ImplCallClosePopupsHdl( hWnd ); // close popups...
5483 ImplSalYieldMutexRelease();
5484 break;
5486 case WM_MOUSEACTIVATE:
5487 if ( LOWORD( lParam ) == HTCLIENT )
5489 ImplSalYieldMutexAcquireWithWait();
5490 nRet = LRESULT(ImplHandleMouseActivateMsg( hWnd ));
5491 ImplSalYieldMutexRelease();
5492 if ( nRet )
5494 nRet = MA_NOACTIVATE;
5495 rDef = false;
5498 break;
5500 case WM_KEYDOWN:
5501 case WM_KEYUP:
5502 case WM_DEADCHAR:
5503 case WM_CHAR:
5504 case WM_UNICHAR: // MCD, 2003-01-13, Support for WM_UNICHAR & Keyman 6.0
5505 case WM_SYSKEYDOWN:
5506 case WM_SYSKEYUP:
5507 case WM_SYSCHAR:
5508 ImplSalYieldMutexAcquireWithWait();
5509 rDef = !ImplHandleKeyMsg( hWnd, nMsg, wParam, lParam, nRet );
5510 ImplSalYieldMutexRelease();
5511 break;
5513 case WM_MOUSEWHEEL:
5514 case WM_MOUSEHWHEEL:
5515 // protect against recursion, in case the message is returned
5516 // by IE or the external window
5517 if ( !bInWheelMsg )
5519 bInWheelMsg = true;
5520 rDef = !ImplHandleWheelMsg( hWnd, nMsg, wParam, lParam );
5521 // If we did not process the message, re-check if here is a
5522 // connected (?) window that we have to notify.
5523 if ( rDef )
5524 rDef = ImplSalWheelMousePos( hWnd, nMsg, wParam, lParam, nRet );
5525 bInWheelMsg = false;
5527 break;
5529 case WM_COMMAND:
5530 ImplSalYieldMutexAcquireWithWait();
5531 rDef = !ImplHandleCommand( hWnd, wParam, lParam );
5532 ImplSalYieldMutexRelease();
5533 break;
5535 case WM_INITMENUPOPUP:
5536 ImplSalYieldMutexAcquireWithWait();
5537 rDef = !ImplHandleMenuActivate( hWnd, wParam, lParam );
5538 ImplSalYieldMutexRelease();
5539 break;
5541 case WM_MENUSELECT:
5542 ImplSalYieldMutexAcquireWithWait();
5543 rDef = !ImplHandleMenuSelect( hWnd, wParam, lParam );
5544 ImplSalYieldMutexRelease();
5545 break;
5547 case WM_SYSCOMMAND:
5548 ImplSalYieldMutexAcquireWithWait();
5549 nRet = LRESULT(ImplHandleSysCommand( hWnd, wParam, lParam ));
5550 ImplSalYieldMutexRelease();
5551 if ( nRet )
5552 rDef = false;
5553 break;
5555 case WM_MENUCHAR:
5556 nRet = ImplMenuChar( hWnd, wParam, lParam );
5557 if( nRet )
5558 rDef = false;
5559 break;
5561 case WM_MEASUREITEM:
5562 nRet = ImplMeasureItem(hWnd, wParam, lParam);
5563 if( nRet )
5564 rDef = false;
5565 break;
5567 case WM_DRAWITEM:
5568 nRet = ImplDrawItem(hWnd, wParam, lParam);
5569 if( nRet )
5570 rDef = false;
5571 break;
5573 case WM_MOVE:
5574 case SAL_MSG_POSTMOVE:
5575 ImplHandleMoveMsg( hWnd );
5576 rDef = false;
5577 break;
5578 case WM_SIZE:
5579 ImplHandleSizeMsg( hWnd, wParam, lParam );
5580 rDef = false;
5581 break;
5582 case SAL_MSG_POSTCALLSIZE:
5583 ImplCallSizeHdl( hWnd );
5584 rDef = false;
5585 break;
5587 case WM_GETMINMAXINFO:
5588 if ( ImplHandleMinMax( hWnd, lParam ) )
5589 rDef = false;
5590 break;
5592 case WM_ERASEBKGND:
5593 nRet = 1;
5594 rDef = false;
5595 break;
5596 case WM_PAINT:
5597 ImplHandlePaintMsg( hWnd );
5598 rDef = false;
5599 break;
5600 case SAL_MSG_POSTPAINT:
5601 ImplHandlePostPaintMsg( hWnd, reinterpret_cast<RECT*>(wParam) );
5602 rDef = false;
5603 break;
5605 case SAL_MSG_FORCEPALETTE:
5606 ImplHandleForcePalette( hWnd );
5607 rDef = false;
5608 break;
5610 case WM_QUERYNEWPALETTE:
5611 case SAL_MSG_POSTQUERYNEWPAL:
5612 nRet = ImplHandlePalette( true, hWnd, nMsg, wParam, lParam, rDef );
5613 break;
5615 case WM_ACTIVATE:
5616 // Getting activated, we also want to set our palette.
5617 // We do this in Activate, so that other external child windows
5618 // can overwrite our palette. Thus our palette is set only once
5619 // and not recursively, as at all other places it is set only as
5620 // the background palette.
5621 if ( LOWORD( wParam ) != WA_INACTIVE )
5622 SendMessageW( hWnd, SAL_MSG_FORCEPALETTE, 0, 0 );
5623 break;
5625 case WM_ENABLE:
5626 // #95133# a system dialog is opened/closed, using our app window as parent
5628 WinSalFrame* pFrame = GetWindowPtr( hWnd );
5629 vcl::Window *pWin = nullptr;
5630 if( pFrame )
5631 pWin = pFrame->GetWindow();
5633 if( !wParam )
5635 pSVData->maAppData.mnModalMode++;
5637 ImplHideSplash();
5638 if( pWin )
5640 pWin->EnableInput( false, nullptr );
5641 pWin->IncModalCount(); // #106303# support frame based modal count
5644 else
5646 ImplGetSVData()->maAppData.mnModalMode--;
5647 if( pWin )
5649 pWin->EnableInput( true, nullptr );
5650 pWin->DecModalCount(); // #106303# support frame based modal count
5654 break;
5656 case WM_KILLFOCUS:
5657 DestroyCaret();
5658 [[fallthrough]];
5659 case WM_SETFOCUS:
5660 case SAL_MSG_POSTFOCUS:
5661 ImplHandleFocusMsg( hWnd );
5662 rDef = false;
5663 break;
5665 case WM_CLOSE:
5666 ImplHandleCloseMsg( hWnd );
5667 rDef = false;
5668 break;
5670 case WM_QUERYENDSESSION:
5671 if( !bInQueryEnd )
5673 // handle queryendsession only once
5674 bInQueryEnd = true;
5675 nRet = LRESULT(!ImplHandleShutDownMsg( hWnd ));
5676 rDef = false;
5678 // Issue #16314#: ImplHandleShutDownMsg causes a PostMessage in case of allowing shutdown.
5679 // This posted message was never processed and cause Windows XP to hang after log off
5680 // if there are multiple sessions and the current session wasn't the first one started.
5681 // So if shutdown is allowed we assume that a post message was done and retrieve all
5682 // messages in the message queue and dispatch them before we return control to the system.
5684 if ( nRet )
5686 SolarMutexGuard aGuard;
5687 while ( Application::Reschedule( true ) );
5690 else
5692 ImplSalYieldMutexAcquireWithWait();
5693 ImplSalYieldMutexRelease();
5694 rDef = true;
5696 break;
5698 case WM_ENDSESSION:
5699 if( !wParam )
5700 bInQueryEnd = false; // no shutdown: allow query again
5701 nRet = FALSE;
5702 rDef = false;
5703 break;
5705 case WM_DISPLAYCHANGE:
5706 case WM_SETTINGCHANGE:
5707 case WM_DEVMODECHANGE:
5708 case WM_FONTCHANGE:
5709 case WM_SYSCOLORCHANGE:
5710 case WM_TIMECHANGE:
5711 ImplHandleSettingsChangeMsg( hWnd, nMsg, wParam, lParam );
5712 break;
5714 case WM_THEMECHANGED:
5715 GetSalData()->mbThemeChanged = true;
5716 break;
5718 case SAL_MSG_USEREVENT:
5719 ImplHandleUserEvent( hWnd, lParam );
5720 rDef = false;
5721 break;
5723 case SAL_MSG_CAPTUREMOUSE:
5724 SetCapture( hWnd );
5725 rDef = false;
5726 break;
5727 case SAL_MSG_RELEASEMOUSE:
5728 if ( ::GetCapture() == hWnd )
5729 ReleaseCapture();
5730 rDef = false;
5731 break;
5732 case SAL_MSG_TOTOP:
5733 ImplSalToTop( hWnd, static_cast<SalFrameToTop>(wParam) );
5734 rDef = false;
5735 break;
5736 case SAL_MSG_SHOW:
5737 ImplSalShow( hWnd, static_cast<bool>(wParam), static_cast<bool>(lParam) );
5738 rDef = false;
5739 break;
5740 case SAL_MSG_SETINPUTCONTEXT:
5741 ImplSalFrameSetInputContext( hWnd, reinterpret_cast<const SalInputContext*>(lParam) );
5742 rDef = false;
5743 break;
5744 case SAL_MSG_ENDEXTTEXTINPUT:
5745 ImplSalFrameEndExtTextInput( hWnd, static_cast<EndExtTextInputFlags>(wParam) );
5746 rDef = false;
5747 break;
5749 case WM_INPUTLANGCHANGE:
5750 ImplHandleInputLangChange( hWnd, wParam, lParam );
5751 break;
5753 case WM_IME_CHAR:
5754 // #103487#, some IMEs (eg, those that do not work onspot)
5755 // may send WM_IME_CHAR instead of WM_IME_COMPOSITION
5756 // we just handle it like a WM_CHAR message - seems to work fine
5757 ImplSalYieldMutexAcquireWithWait();
5758 rDef = !ImplHandleKeyMsg( hWnd, WM_CHAR, wParam, lParam, nRet );
5759 ImplSalYieldMutexRelease();
5760 break;
5762 case WM_IME_STARTCOMPOSITION:
5763 rDef = ImplHandleIMEStartComposition( hWnd );
5764 break;
5766 case WM_IME_COMPOSITION:
5767 rDef = ImplHandleIMEComposition( hWnd, lParam );
5768 break;
5770 case WM_IME_ENDCOMPOSITION:
5771 rDef = ImplHandleIMEEndComposition( hWnd );
5772 break;
5774 case WM_IME_NOTIFY:
5775 ImplHandleIMENotify( hWnd, wParam );
5776 break;
5778 case WM_GETOBJECT:
5779 ImplSalYieldMutexAcquireWithWait();
5780 if ( ImplHandleGetObject( hWnd, lParam, wParam, nRet ) )
5782 rDef = false;
5784 ImplSalYieldMutexRelease();
5785 break;
5787 case WM_APPCOMMAND:
5788 if( ImplHandleAppCommand( hWnd, lParam, nRet ) )
5790 rDef = false;
5792 break;
5793 case WM_IME_REQUEST:
5794 if ( static_cast<sal_uIntPtr>(wParam) == IMR_RECONVERTSTRING )
5796 nRet = ImplHandleIMEReconvertString( hWnd, lParam );
5797 rDef = false;
5799 else if( static_cast<sal_uIntPtr>(wParam) == IMR_CONFIRMRECONVERTSTRING )
5801 nRet = ImplHandleIMEConfirmReconvertString( hWnd, lParam );
5802 rDef = false;
5804 else if ( static_cast<sal_uIntPtr>(wParam) == IMR_QUERYCHARPOSITION )
5806 if ( ImplSalYieldMutexTryToAcquire() )
5808 nRet = ImplHandleIMEQueryCharPosition( hWnd, lParam );
5809 ImplSalYieldMutexRelease();
5811 else
5812 nRet = FALSE;
5813 rDef = false;
5815 break;
5818 return nRet;
5821 LRESULT CALLBACK SalFrameWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
5823 bool bDef = true;
5824 LRESULT nRet = 0;
5825 __try
5827 nRet = SalFrameWndProc( hWnd, nMsg, wParam, lParam, bDef );
5829 __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))
5833 if ( bDef )
5834 nRet = DefWindowProcW( hWnd, nMsg, wParam, lParam );
5835 return nRet;
5838 bool ImplHandleGlobalMsg( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, LRESULT& rlResult )
5840 // handle all messages concerning all frames so they get processed only once
5841 // Must work for Unicode and none Unicode
5842 bool bResult = false;
5843 if ( (nMsg == WM_PALETTECHANGED) || (nMsg == SAL_MSG_POSTPALCHANGED) )
5845 bResult = true;
5846 rlResult = ImplHandlePalette( false, hWnd, nMsg, wParam, lParam, bResult );
5848 else if( nMsg == WM_DISPLAYCHANGE )
5850 WinSalSystem* pSys = static_cast<WinSalSystem*>(ImplGetSalSystem());
5851 if( pSys )
5852 pSys->clearMonitors();
5853 bResult = (pSys != nullptr);
5855 return bResult;
5858 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */