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