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