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