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