1 /* 2 * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #define _JNI_IMPLEMENTATION_ 27 28 #include "awt.h" 29 #include <signal.h> 30 #include <windowsx.h> 31 #include <process.h> 32 #include <shellapi.h> 33 #include <shlwapi.h> 34 35 #include "awt_DrawingSurface.h" 36 #include "awt_AWTEvent.h" 37 #include "awt_Component.h" 38 #include "awt_Canvas.h" 39 #include "awt_Clipboard.h" 40 #include "awt_Frame.h" 41 #include "awt_Dialog.h" 42 #include "awt_Font.h" 43 #include "awt_Cursor.h" 44 #include "awt_InputEvent.h" 45 #include "awt_KeyEvent.h" 46 #include "awt_List.h" 47 #include "awt_Palette.h" 48 #include "awt_PopupMenu.h" 49 #include "awt_Toolkit.h" 50 #include "awt_DesktopProperties.h" 51 #include "awt_FileDialog.h" 52 #include "CmdIDList.h" 53 #include "awt_new.h" 54 #include "debug_trace.h" 55 #include "debug_mem.h" 56 57 #include "ComCtl32Util.h" 58 #include "DllUtil.h" 59 60 #include "D3DPipelineManager.h" 61 62 #include <awt_DnDDT.h> 63 #include <awt_DnDDS.h> 64 65 #include <java_awt_Toolkit.h> 66 #include <java_awt_event_InputMethodEvent.h> 67 68 extern void initScreens(JNIEnv *env); 69 extern "C" void awt_dnd_initialize(); 70 extern "C" void awt_dnd_uninitialize(); 71 extern "C" void awt_clipboard_uninitialize(JNIEnv *env); 72 extern "C" BOOL g_bUserHasChangedInputLang; 73 74 extern CriticalSection windowMoveLock; 75 extern BOOL windowMoveLockHeld; 76 77 // Needed by JAWT: see awt_DrawingSurface.cpp. 78 extern jclass jawtVImgClass; 79 extern jclass jawtVSMgrClass; 80 extern jclass jawtComponentClass; 81 extern jfieldID jawtPDataID; 82 extern jfieldID jawtSDataID; 83 extern jfieldID jawtSMgrID; 84 85 extern void DWMResetCompositionEnabled(); 86 87 /************************************************************************ 88 * Utilities 89 */ 90 91 /* Initialize the Java VM instance variable when the library is 92 first loaded */ 93 JavaVM *jvm = NULL; 94 95 JNIEXPORT jint JNICALL 96 JNI_OnLoad(JavaVM *vm, void *reserved) 97 { 98 TRY; 99 100 jvm = vm; 101 return JNI_VERSION_1_2; 102 103 CATCH_BAD_ALLOC_RET(0); 104 } 105 106 extern "C" JNIEXPORT jboolean JNICALL AWTIsHeadless() { 107 static JNIEnv *env = NULL; 108 static jboolean isHeadless; 109 jmethodID headlessFn; 110 jclass graphicsEnvClass; 111 112 if (env == NULL) { 113 env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 114 graphicsEnvClass = env->FindClass( 115 "java/awt/GraphicsEnvironment"); 116 if (graphicsEnvClass == NULL) { 117 return JNI_TRUE; 118 } 119 headlessFn = env->GetStaticMethodID( 120 graphicsEnvClass, "isHeadless", "()Z"); 121 if (headlessFn == NULL) { 122 return JNI_TRUE; 123 } 124 isHeadless = env->CallStaticBooleanMethod(graphicsEnvClass, 125 headlessFn); 126 } 127 return isHeadless; 128 } 129 130 #define IDT_AWT_MOUSECHECK 0x101 131 132 static LPCTSTR szAwtToolkitClassName = TEXT("SunAwtToolkit"); 133 134 static const int MOUSE_BUTTONS_WINDOWS_SUPPORTED = 5; //three standard buttons + XBUTTON1 + XBUTTON2. 135 136 UINT AwtToolkit::GetMouseKeyState() 137 { 138 static BOOL mbSwapped = ::GetSystemMetrics(SM_SWAPBUTTON); 139 UINT mouseKeyState = 0; 140 141 if (HIBYTE(::GetKeyState(VK_CONTROL))) 142 mouseKeyState |= MK_CONTROL; 143 if (HIBYTE(::GetKeyState(VK_SHIFT))) 144 mouseKeyState |= MK_SHIFT; 145 if (HIBYTE(::GetKeyState(VK_LBUTTON))) 146 mouseKeyState |= (mbSwapped ? MK_RBUTTON : MK_LBUTTON); 147 if (HIBYTE(::GetKeyState(VK_RBUTTON))) 148 mouseKeyState |= (mbSwapped ? MK_LBUTTON : MK_RBUTTON); 149 if (HIBYTE(::GetKeyState(VK_MBUTTON))) 150 mouseKeyState |= MK_MBUTTON; 151 return mouseKeyState; 152 } 153 154 // 155 // Normal ::GetKeyboardState call only works if current thread has 156 // a message pump, so provide a way for other threads to get 157 // the keyboard state 158 // 159 void AwtToolkit::GetKeyboardState(PBYTE keyboardState) 160 { 161 CriticalSection::Lock l(AwtToolkit::GetInstance().m_lockKB); 162 DASSERT(!IsBadWritePtr(keyboardState, KB_STATE_SIZE)); 163 memcpy(keyboardState, AwtToolkit::GetInstance().m_lastKeyboardState, 164 KB_STATE_SIZE); 165 } 166 167 void AwtToolkit::SetBusy(BOOL busy) { 168 169 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 170 171 static jclass awtAutoShutdownClass = NULL; 172 static jmethodID notifyBusyMethodID = NULL; 173 static jmethodID notifyFreeMethodID = NULL; 174 175 if (awtAutoShutdownClass == NULL) { 176 jclass awtAutoShutdownClassLocal = env->FindClass("sun/awt/AWTAutoShutdown"); 177 DASSERT(awtAutoShutdownClassLocal != NULL); 178 if (!awtAutoShutdownClassLocal) throw std::bad_alloc(); 179 180 awtAutoShutdownClass = (jclass)env->NewGlobalRef(awtAutoShutdownClassLocal); 181 env->DeleteLocalRef(awtAutoShutdownClassLocal); 182 if (!awtAutoShutdownClass) throw std::bad_alloc(); 183 184 notifyBusyMethodID = env->GetStaticMethodID(awtAutoShutdownClass, 185 "notifyToolkitThreadBusy", "()V"); 186 DASSERT(notifyBusyMethodID != NULL); 187 if (!notifyBusyMethodID) throw std::bad_alloc(); 188 189 notifyFreeMethodID = env->GetStaticMethodID(awtAutoShutdownClass, 190 "notifyToolkitThreadFree", "()V"); 191 DASSERT(notifyFreeMethodID != NULL); 192 if (!notifyFreeMethodID) throw std::bad_alloc(); 193 } /* awtAutoShutdownClass == NULL*/ 194 195 if (busy) { 196 env->CallStaticVoidMethod(awtAutoShutdownClass, 197 notifyBusyMethodID); 198 } else { 199 env->CallStaticVoidMethod(awtAutoShutdownClass, 200 notifyFreeMethodID); 201 } 202 203 if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) { 204 env->ExceptionDescribe(); 205 env->ExceptionClear(); 206 } 207 } 208 209 BOOL AwtToolkit::activateKeyboardLayout(HKL hkl) { 210 // This call should succeed in case of one of the following: 211 // 1. Win 9x 212 // 2. NT with that HKL already loaded 213 HKL prev = ::ActivateKeyboardLayout(hkl, 0); 214 215 // If the above call fails, try loading the layout in case of NT 216 if (!prev) { 217 // create input locale string, e.g., "00000409", from hkl. 218 TCHAR inputLocale[9]; 219 TCHAR buf[9]; 220 _tcscpy_s(inputLocale, 9, TEXT("00000000")); 221 222 // 64-bit: ::LoadKeyboardLayout() is such a weird API - a string of 223 // the hex value you want?! Here we're converting our HKL value to 224 // a string. Hopefully there is no 64-bit trouble. 225 _i64tot(reinterpret_cast<INT_PTR>(hkl), buf, 16); 226 size_t len = _tcslen(buf); 227 memcpy(&inputLocale[8-len], buf, len); 228 229 // load and activate the keyboard layout 230 hkl = ::LoadKeyboardLayout(inputLocale, 0); 231 if (hkl != 0) { 232 prev = ::ActivateKeyboardLayout(hkl, 0); 233 } 234 } 235 236 return (prev != 0); 237 } 238 239 /************************************************************************ 240 * Exported functions 241 */ 242 243 extern "C" BOOL APIENTRY DllMain(HANDLE hInstance, DWORD ul_reason_for_call, 244 LPVOID) 245 { 246 // Don't use the TRY and CATCH_BAD_ALLOC_RET macros if we're detaching 247 // the library. Doing so causes awt.dll to call back into the VM during 248 // shutdown. This crashes the HotSpot VM. 249 switch (ul_reason_for_call) { 250 case DLL_PROCESS_ATTACH: 251 TRY; 252 AwtToolkit::GetInstance().SetModuleHandle((HMODULE)hInstance); 253 CATCH_BAD_ALLOC_RET(FALSE); 254 break; 255 case DLL_PROCESS_DETACH: 256 #ifdef DEBUG 257 DTrace_DisableMutex(); 258 DMem_DisableMutex(); 259 #endif DEBUG 260 break; 261 } 262 return TRUE; 263 } 264 265 /************************************************************************ 266 * AwtToolkit fields 267 */ 268 269 AwtToolkit AwtToolkit::theInstance; 270 271 /* ids for WToolkit fields accessed from native code */ 272 jmethodID AwtToolkit::windowsSettingChangeMID; 273 jmethodID AwtToolkit::displayChangeMID; 274 /* ids for Toolkit methods */ 275 jmethodID AwtToolkit::getDefaultToolkitMID; 276 jmethodID AwtToolkit::getFontMetricsMID; 277 jmethodID AwtToolkit::insetsMID; 278 279 /************************************************************************ 280 * AwtToolkit methods 281 */ 282 283 AwtToolkit::AwtToolkit() { 284 m_localPump = FALSE; 285 m_mainThreadId = 0; 286 m_toolkitHWnd = NULL; 287 m_inputMethodHWnd = NULL; 288 m_verbose = FALSE; 289 m_isActive = TRUE; 290 m_isDisposed = FALSE; 291 292 m_vmSignalled = FALSE; 293 294 m_isDynamicLayoutSet = FALSE; 295 m_areExtraMouseButtonsEnabled = TRUE; 296 297 m_isWin8OrLater = FALSE; 298 m_touchKbrdAutoShowIsEnabled = FALSE; 299 m_touchKbrdExeFilePath = NULL; 300 m_pRegisterTouchWindow = NULL; 301 m_pGetTouchInputInfo = NULL; 302 m_pCloseTouchInputHandle = NULL; 303 304 m_verifyComponents = FALSE; 305 m_breakOnError = FALSE; 306 307 m_breakMessageLoop = FALSE; 308 m_messageLoopResult = 0; 309 310 m_lastMouseOver = NULL; 311 m_mouseDown = FALSE; 312 313 m_hGetMessageHook = 0; 314 m_hMouseLLHook = 0; 315 m_lastWindowUnderMouse = NULL; 316 m_timer = 0; 317 318 m_cmdIDs = new AwtCmdIDList(); 319 m_pModalDialog = NULL; 320 m_peer = NULL; 321 m_dllHandle = NULL; 322 323 m_displayChanged = FALSE; 324 m_embedderProcessID = 0; 325 326 // XXX: keyboard mapping should really be moved out of AwtComponent 327 AwtComponent::InitDynamicKeyMapTable(); 328 329 // initialize kb state array 330 ::GetKeyboardState(m_lastKeyboardState); 331 332 m_waitEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); 333 eventNumber = 0; 334 } 335 336 AwtToolkit::~AwtToolkit() { 337 /* 338 * The code has been moved to AwtToolkit::Dispose() method. 339 */ 340 } 341 342 HWND AwtToolkit::CreateToolkitWnd(LPCTSTR name) 343 { 344 HWND hwnd = CreateWindow( 345 szAwtToolkitClassName, 346 (LPCTSTR)name, /* window name */ 347 WS_DISABLED, /* window style */ 348 -1, -1, /* position of window */ 349 0, 0, /* width and height */ 350 NULL, NULL, /* hWndParent and hWndMenu */ 351 GetModuleHandle(), 352 NULL); /* lpParam */ 353 DASSERT(hwnd != NULL); 354 return hwnd; 355 } 356 357 void AwtToolkit::InitTouchKeyboardExeFilePath() { 358 enum RegistryView { WOW64_32BIT, WOW64_64BIT }; 359 const TCHAR tabTipCoKeyName[] = _T("SOFTWARE\\Classes\\CLSID\\") 360 _T("{054AAE20-4BEA-4347-8A35-64A533254A9D}\\LocalServer32"); 361 HKEY hTabTipCoKey = NULL; 362 RegistryView regViewWithTabTipCoKey = WOW64_32BIT; 363 364 if (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, tabTipCoKeyName, 0, 365 KEY_READ | KEY_WOW64_32KEY, &hTabTipCoKey) != ERROR_SUCCESS) { 366 if (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, tabTipCoKeyName, 0, 367 KEY_READ | KEY_WOW64_64KEY, &hTabTipCoKey) != ERROR_SUCCESS) { 368 return; 369 } else { 370 regViewWithTabTipCoKey = WOW64_64BIT; 371 } 372 } 373 374 DWORD keyValType = 0; 375 DWORD bytesCopied = 0; 376 if ((::RegQueryValueEx(hTabTipCoKey, NULL, NULL, &keyValType, NULL, 377 &bytesCopied) != ERROR_SUCCESS) || 378 ((keyValType != REG_EXPAND_SZ) && (keyValType != REG_SZ))) { 379 if (hTabTipCoKey != NULL) { 380 ::RegCloseKey(hTabTipCoKey); 381 } 382 return; 383 } 384 385 // Increase the buffer size for 1 additional null-terminating character. 386 bytesCopied += sizeof(TCHAR); 387 TCHAR* tabTipFilePath = new TCHAR[bytesCopied / sizeof(TCHAR)]; 388 ::memset(tabTipFilePath, 0, bytesCopied); 389 390 DWORD oldBytesCopied = bytesCopied; 391 if (::RegQueryValueEx(hTabTipCoKey, NULL, NULL, NULL, 392 (LPBYTE)tabTipFilePath, &bytesCopied) == ERROR_SUCCESS) { 393 const TCHAR searchedStr[] = _T("%CommonProgramFiles%"); 394 const size_t searchedStrLen = ::_tcslen(searchedStr); 395 int searchedStrStartIndex = -1; 396 397 TCHAR* commonFilesDirPath = NULL; 398 DWORD commonFilesDirPathLen = 0; 399 400 // Check, if '%CommonProgramFiles%' string is present in the defined 401 // path of the touch keyboard executable. 402 TCHAR* const searchedStrStart = ::_tcsstr(tabTipFilePath, searchedStr); 403 if (searchedStrStart != NULL) { 404 searchedStrStartIndex = searchedStrStart - tabTipFilePath; 405 406 // Get value of 'CommonProgramFiles' environment variable, if the 407 // file path of the touch keyboard executable was found in 32-bit 408 // registry view, otherwise get value of 'CommonProgramW6432'. 409 const TCHAR envVar32BitName[] = _T("CommonProgramFiles"); 410 const TCHAR envVar64BitName[] = _T("CommonProgramW6432"); 411 const TCHAR* envVarName = (regViewWithTabTipCoKey == WOW64_32BIT ? 412 envVar32BitName : envVar64BitName); 413 414 DWORD charsStored = ::GetEnvironmentVariable(envVarName, NULL, 0); 415 if (charsStored > 0) { 416 commonFilesDirPath = new TCHAR[charsStored]; 417 ::memset(commonFilesDirPath, 0, charsStored * sizeof(TCHAR)); 418 419 DWORD oldCharsStored = charsStored; 420 if (((charsStored = ::GetEnvironmentVariable(envVarName, 421 commonFilesDirPath, charsStored)) > 0) && 422 (charsStored <= oldCharsStored)) { 423 commonFilesDirPathLen = charsStored; 424 } else { 425 delete[] commonFilesDirPath; 426 commonFilesDirPath = NULL; 427 } 428 } 429 } 430 431 // Calculate 'm_touchKbrdExeFilePath' length in characters including 432 // the null-terminating character. 433 DWORD exeFilePathLen = oldBytesCopied / sizeof(TCHAR); 434 if (commonFilesDirPathLen > 0) { 435 exeFilePathLen = exeFilePathLen - searchedStrLen + 436 commonFilesDirPathLen; 437 } 438 439 if (m_touchKbrdExeFilePath != NULL) { 440 delete[] m_touchKbrdExeFilePath; 441 m_touchKbrdExeFilePath = NULL; 442 } 443 m_touchKbrdExeFilePath = new TCHAR[exeFilePathLen]; 444 ::memset(m_touchKbrdExeFilePath, 0, exeFilePathLen * sizeof(TCHAR)); 445 446 if (commonFilesDirPathLen > 0) { 447 ::_tcsncpy_s(m_touchKbrdExeFilePath, exeFilePathLen, tabTipFilePath, 448 searchedStrStartIndex); 449 DWORD charsCopied = searchedStrStartIndex; 450 451 ::_tcsncpy_s(m_touchKbrdExeFilePath + charsCopied, 452 exeFilePathLen - charsCopied, commonFilesDirPath, 453 commonFilesDirPathLen); 454 charsCopied += commonFilesDirPathLen; 455 456 ::_tcsncpy_s(m_touchKbrdExeFilePath + charsCopied, 457 exeFilePathLen - charsCopied, searchedStrStart + searchedStrLen, 458 bytesCopied / sizeof(TCHAR) - 459 (searchedStrStartIndex + searchedStrLen)); 460 } else { 461 ::_tcsncpy_s(m_touchKbrdExeFilePath, exeFilePathLen, tabTipFilePath, 462 bytesCopied / sizeof(TCHAR)); 463 } 464 465 // Remove leading and trailing quotation marks. 466 ::StrTrim(m_touchKbrdExeFilePath, _T("\"")); 467 468 // Verify that a file with the path 'm_touchKbrdExeFilePath' exists. 469 DWORD fileAttrs = ::GetFileAttributes(m_touchKbrdExeFilePath); 470 DWORD err = ::GetLastError(); 471 if ((fileAttrs == INVALID_FILE_ATTRIBUTES) || 472 (fileAttrs & FILE_ATTRIBUTE_DIRECTORY)) { 473 delete[] m_touchKbrdExeFilePath; 474 m_touchKbrdExeFilePath = NULL; 475 } 476 477 if (commonFilesDirPath != NULL) { 478 delete[] commonFilesDirPath; 479 } 480 } 481 482 if (tabTipFilePath != NULL) { 483 delete[] tabTipFilePath; 484 } 485 if (hTabTipCoKey != NULL) { 486 ::RegCloseKey(hTabTipCoKey); 487 } 488 } 489 490 HWND AwtToolkit::GetTouchKeyboardWindow() { 491 const TCHAR wndClassName[] = _T("IPTip_Main_Window"); 492 HWND hwnd = ::FindWindow(wndClassName, NULL); 493 if ((hwnd != NULL) && ::IsWindow(hwnd) && ::IsWindowEnabled(hwnd) && 494 ::IsWindowVisible(hwnd)) { 495 return hwnd; 496 } 497 return NULL; 498 } 499 500 501 struct ToolkitThreadProc_Data { 502 bool result; 503 HANDLE hCompleted; 504 505 jobject thread; 506 jobject threadGroup; 507 }; 508 509 void ToolkitThreadProc(void *param) 510 { 511 ToolkitThreadProc_Data *data = (ToolkitThreadProc_Data *)param; 512 513 bool bNotified = false; 514 515 JNIEnv *env; 516 JavaVMAttachArgs attachArgs; 517 attachArgs.version = JNI_VERSION_1_2; 518 attachArgs.name = "AWT-Windows"; 519 attachArgs.group = data->threadGroup; 520 521 jint res = jvm->AttachCurrentThreadAsDaemon((void **)&env, &attachArgs); 522 if (res < 0) { 523 return; 524 } 525 526 jobject thread = env->NewGlobalRef(data->thread); 527 if (thread != NULL) { 528 jclass cls = env->GetObjectClass(thread); 529 if (cls != NULL) { 530 jmethodID runId = env->GetMethodID(cls, "run", "()V"); 531 if (runId != NULL) { 532 data->result = true; 533 ::SetEvent(data->hCompleted); 534 bNotified = true; 535 536 env->CallVoidMethod(thread, runId); 537 538 if (env->ExceptionCheck()) { 539 env->ExceptionDescribe(); 540 env->ExceptionClear(); 541 // TODO: handle 542 } 543 } 544 env->DeleteLocalRef(cls); 545 } 546 env->DeleteGlobalRef(thread); 547 } 548 if (!bNotified) { 549 ::SetEvent(data->hCompleted); 550 } 551 552 jvm->DetachCurrentThread(); 553 } 554 555 /* 556 * Class: sun_awt_windows_WToolkit 557 * Method: startToolkitThread 558 * Signature: (Ljava/lang/Runnable;Ljava/lang/ThreadGroup)Z 559 */ 560 JNIEXPORT jboolean JNICALL 561 Java_sun_awt_windows_WToolkit_startToolkitThread(JNIEnv *env, jclass cls, jobject thread, jobject threadGroup) 562 { 563 AwtToolkit& tk = AwtToolkit::GetInstance(); 564 565 ToolkitThreadProc_Data data; 566 data.result = false; 567 data.thread = env->NewGlobalRef(thread); 568 data.threadGroup = env->NewGlobalRef(threadGroup); 569 if (data.thread == NULL || data.threadGroup == NULL) { 570 return JNI_FALSE; 571 } 572 data.hCompleted = ::CreateEvent(NULL, FALSE, FALSE, NULL); 573 574 bool result = tk.GetPreloadThread() 575 .InvokeAndTerminate(ToolkitThreadProc, &data); 576 577 if (result) { 578 ::WaitForSingleObject(data.hCompleted, INFINITE); 579 result = data.result; 580 } else { 581 // no awt preloading 582 // return back to the usual toolkit way 583 } 584 ::CloseHandle(data.hCompleted); 585 586 env->DeleteGlobalRef(data.thread); 587 env->DeleteGlobalRef(data.threadGroup); 588 589 return result ? JNI_TRUE : JNI_FALSE; 590 } 591 592 BOOL AwtToolkit::Initialize(BOOL localPump) { 593 AwtToolkit& tk = AwtToolkit::GetInstance(); 594 595 if (!tk.m_isActive || tk.m_mainThreadId != 0) { 596 /* Already initialized. */ 597 return FALSE; 598 } 599 600 // This call is moved here from AwtToolkit constructor. Having it 601 // there led to the bug 6480630: there could be a situation when 602 // ComCtl32Util was constructed but not disposed 603 ComCtl32Util::GetInstance().InitLibraries(); 604 605 if (!localPump) { 606 // if preload thread was run, terminate it 607 preloadThread.Terminate(true); 608 } 609 610 /* Register this toolkit's helper window */ 611 VERIFY(tk.RegisterClass() != NULL); 612 613 // Set up operator new/malloc out of memory handler. 614 NewHandler::init(); 615 616 //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 617 // Bugs 4032109, 4047966, and 4071991 to fix AWT 618 // crash in 16 color display mode. 16 color mode is supported. Less 619 // than 16 color is not. 620 // creighto@eng.sun.com 1997-10-07 621 // 622 // Check for at least 16 colors 623 HDC hDC = ::GetDC(NULL); 624 if ((::GetDeviceCaps(hDC, BITSPIXEL) * ::GetDeviceCaps(hDC, PLANES)) < 4) { 625 ::MessageBox(NULL, 626 TEXT("Sorry, but this release of Java requires at least 16 colors"), 627 TEXT("AWT Initialization Error"), 628 MB_ICONHAND | MB_APPLMODAL); 629 ::DeleteDC(hDC); 630 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 631 JNU_ThrowByName(env, "java/lang/InternalError", 632 "unsupported screen depth"); 633 return FALSE; 634 } 635 ::ReleaseDC(NULL, hDC); 636 /////////////////////////////////////////////////////////////////////////// 637 638 tk.m_localPump = localPump; 639 tk.m_mainThreadId = ::GetCurrentThreadId(); 640 641 /* 642 * Create the one-and-only toolkit window. This window isn't 643 * displayed, but is used to route messages to this thread. 644 */ 645 tk.m_toolkitHWnd = tk.CreateToolkitWnd(TEXT("theAwtToolkitWindow")); 646 DASSERT(tk.m_toolkitHWnd != NULL); 647 648 /* 649 * Setup a GetMessage filter to watch all messages coming out of our 650 * queue from PreProcessMsg(). 651 */ 652 tk.m_hGetMessageHook = ::SetWindowsHookEx(WH_GETMESSAGE, 653 (HOOKPROC)GetMessageFilter, 654 0, tk.m_mainThreadId); 655 656 awt_dnd_initialize(); 657 658 /* 659 * Initialization of the touch keyboard related variables. 660 */ 661 tk.m_isWin8OrLater = IS_WIN8; 662 663 TRY; 664 665 JNIEnv* env = AwtToolkit::GetEnv(); 666 jclass sunToolkitCls = env->FindClass("sun/awt/SunToolkit"); 667 DASSERT(sunToolkitCls != 0); 668 CHECK_NULL_RETURN(sunToolkitCls, FALSE); 669 670 jmethodID isTouchKeyboardAutoShowEnabledMID = env->GetStaticMethodID( 671 sunToolkitCls, "isTouchKeyboardAutoShowEnabled", "()Z"); 672 DASSERT(isTouchKeyboardAutoShowEnabledMID != 0); 673 CHECK_NULL_RETURN(isTouchKeyboardAutoShowEnabledMID, FALSE); 674 675 tk.m_touchKbrdAutoShowIsEnabled = env->CallStaticBooleanMethod( 676 sunToolkitCls, isTouchKeyboardAutoShowEnabledMID); 677 678 CATCH_BAD_ALLOC_RET(FALSE); 679 680 if (tk.m_isWin8OrLater && tk.m_touchKbrdAutoShowIsEnabled) { 681 tk.InitTouchKeyboardExeFilePath(); 682 HMODULE hUser32Dll = ::LoadLibrary(_T("user32.dll")); 683 if (hUser32Dll != NULL) { 684 tk.m_pRegisterTouchWindow = (RegisterTouchWindowFunc) 685 ::GetProcAddress(hUser32Dll, "RegisterTouchWindow"); 686 tk.m_pGetTouchInputInfo = (GetTouchInputInfoFunc) 687 ::GetProcAddress(hUser32Dll, "GetTouchInputInfo"); 688 tk.m_pCloseTouchInputHandle = (CloseTouchInputHandleFunc) 689 ::GetProcAddress(hUser32Dll, "CloseTouchInputHandle"); 690 } 691 692 if ((tk.m_pRegisterTouchWindow == NULL) || 693 (tk.m_pGetTouchInputInfo == NULL) || 694 (tk.m_pCloseTouchInputHandle == NULL)) { 695 tk.m_pRegisterTouchWindow = NULL; 696 tk.m_pGetTouchInputInfo = NULL; 697 tk.m_pCloseTouchInputHandle = NULL; 698 } 699 } 700 /* 701 * End of the touch keyboard related initialization code. 702 */ 703 704 return TRUE; 705 } 706 707 BOOL AwtToolkit::Dispose() { 708 DTRACE_PRINTLN("In AwtToolkit::Dispose()"); 709 710 AwtToolkit& tk = AwtToolkit::GetInstance(); 711 712 if (!tk.m_isActive || tk.m_mainThreadId != ::GetCurrentThreadId()) { 713 return FALSE; 714 } 715 716 tk.m_isActive = FALSE; 717 718 // dispose Direct3D-related resources. This should be done 719 // before AwtObjectList::Cleanup() as the d3d will attempt to 720 // shutdown when the last of its windows is disposed of 721 D3DInitializer::GetInstance().Clean(); 722 723 AwtObjectList::Cleanup(); 724 725 awt_dnd_uninitialize(); 726 awt_clipboard_uninitialize((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2)); 727 728 if (tk.m_touchKbrdExeFilePath != NULL) { 729 delete[] tk.m_touchKbrdExeFilePath; 730 tk.m_touchKbrdExeFilePath = NULL; 731 } 732 tk.m_pRegisterTouchWindow = NULL; 733 tk.m_pGetTouchInputInfo = NULL; 734 tk.m_pCloseTouchInputHandle = NULL; 735 736 if (tk.m_inputMethodHWnd != NULL) { 737 ::SendMessage(tk.m_inputMethodHWnd, WM_IME_CONTROL, IMC_OPENSTATUSWINDOW, 0); 738 } 739 tk.m_inputMethodHWnd = NULL; 740 741 // wait for any messages to be processed, in particular, 742 // all WM_AWT_DELETEOBJECT messages that delete components; no 743 // new messages will appear as all the windows except toolkit 744 // window are unsubclassed and destroyed 745 MSG msg; 746 while (::GetMessage(&msg, NULL, 0, 0)) { 747 ::TranslateMessage(&msg); 748 ::DispatchMessage(&msg); 749 } 750 751 AwtFont::Cleanup(); 752 753 HWND toolkitHWndToDestroy = tk.m_toolkitHWnd; 754 tk.m_toolkitHWnd = 0; 755 VERIFY(::DestroyWindow(toolkitHWndToDestroy) != NULL); 756 757 tk.UnregisterClass(); 758 759 ::UnhookWindowsHookEx(tk.m_hGetMessageHook); 760 UninstallMouseLowLevelHook(); 761 762 tk.m_mainThreadId = 0; 763 764 delete tk.m_cmdIDs; 765 766 ::CloseHandle(m_waitEvent); 767 768 tk.m_isDisposed = TRUE; 769 770 return TRUE; 771 } 772 773 void AwtToolkit::SetDynamicLayout(BOOL dynamic) { 774 m_isDynamicLayoutSet = dynamic; 775 } 776 777 BOOL AwtToolkit::IsDynamicLayoutSet() { 778 return m_isDynamicLayoutSet; 779 } 780 781 BOOL AwtToolkit::IsDynamicLayoutSupported() { 782 // SPI_GETDRAGFULLWINDOWS is only supported on Win95 if 783 // Windows Plus! is installed. Otherwise, box frame resize. 784 BOOL fullWindowDragEnabled = FALSE; 785 int result = 0; 786 result = ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, 787 &fullWindowDragEnabled, 0); 788 789 return (fullWindowDragEnabled && (result != 0)); 790 } 791 792 BOOL AwtToolkit::IsDynamicLayoutActive() { 793 return (IsDynamicLayoutSet() && IsDynamicLayoutSupported()); 794 } 795 796 ATOM AwtToolkit::RegisterClass() { 797 WNDCLASS wc; 798 799 wc.style = 0; 800 wc.lpfnWndProc = (WNDPROC)WndProc; 801 wc.cbClsExtra = 0; 802 wc.cbWndExtra = 0; 803 wc.hInstance = AwtToolkit::GetInstance().GetModuleHandle(), 804 wc.hIcon = AwtToolkit::GetInstance().GetAwtIcon(); 805 wc.hCursor = NULL; 806 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); 807 wc.lpszMenuName = NULL; 808 wc.lpszClassName = szAwtToolkitClassName; 809 810 ATOM ret = ::RegisterClass(&wc); 811 DASSERT(ret != NULL); 812 return ret; 813 } 814 815 void AwtToolkit::UnregisterClass() { 816 VERIFY(::UnregisterClass(szAwtToolkitClassName, AwtToolkit::GetInstance().GetModuleHandle())); 817 } 818 819 /* 820 * Structure holding the information to create a component. This packet is 821 * sent to the toolkit window. 822 */ 823 struct ComponentCreatePacket { 824 void* hComponent; 825 void* hParent; 826 void (*factory)(void*, void*); 827 }; 828 829 /* 830 * Create an AwtXxxx component using a given factory function 831 * Implemented by sending a message to the toolkit window to invoke the 832 * factory function from that thread 833 */ 834 void AwtToolkit::CreateComponent(void* component, void* parent, 835 ComponentFactory compFactory, BOOL isParentALocalReference) 836 { 837 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 838 839 /* Since Local references are not valid in another Thread, we need to 840 create a global reference before we send this to the Toolkit thread. 841 In some cases this method is called with parent being a native 842 malloced struct so we cannot and do not need to create a Global 843 Reference from it. This is indicated by isParentALocalReference */ 844 845 jobject gcomponent = env->NewGlobalRef((jobject)component); 846 jobject gparent; 847 if (isParentALocalReference) gparent = env->NewGlobalRef((jobject)parent); 848 ComponentCreatePacket ccp = { gcomponent, 849 isParentALocalReference == TRUE ? gparent : parent, 850 compFactory }; 851 AwtToolkit::GetInstance().SendMessage(WM_AWT_COMPONENT_CREATE, 0, 852 (LPARAM)&ccp); 853 env->DeleteGlobalRef(gcomponent); 854 if (isParentALocalReference) env->DeleteGlobalRef(gparent); 855 } 856 857 /* 858 * Destroy an HWND that was created in the toolkit thread. Can be used on 859 * Components and the toolkit window itself. 860 */ 861 void AwtToolkit::DestroyComponentHWND(HWND hwnd) 862 { 863 if (!::IsWindow(hwnd)) { 864 return; 865 } 866 867 AwtToolkit& tk = AwtToolkit::GetInstance(); 868 if ((tk.m_lastMouseOver != NULL) && 869 (tk.m_lastMouseOver->GetHWnd() == hwnd)) 870 { 871 tk.m_lastMouseOver = NULL; 872 } 873 874 ::SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)NULL); 875 tk.SendMessage(WM_AWT_DESTROY_WINDOW, (WPARAM)hwnd, 0); 876 } 877 878 #ifndef SPY_MESSAGES 879 #define SpyWinMessage(hwin,msg,str) 880 #else 881 void SpyWinMessage(HWND hwnd, UINT message, LPCTSTR szComment); 882 #endif 883 884 /* 885 * An AwtToolkit window is just a means of routing toolkit messages to here. 886 */ 887 LRESULT CALLBACK AwtToolkit::WndProc(HWND hWnd, UINT message, 888 WPARAM wParam, LPARAM lParam) 889 { 890 TRY; 891 892 JNIEnv *env = GetEnv(); 893 JNILocalFrame lframe(env, 10); 894 895 SpyWinMessage(hWnd, message, TEXT("AwtToolkit")); 896 897 AwtToolkit::GetInstance().eventNumber++; 898 /* 899 * Awt widget creation messages are routed here so that all 900 * widgets are created on the main thread. Java allows widgets 901 * to live beyond their creating thread -- by creating them on 902 * the main thread, a widget can always be properly disposed. 903 */ 904 switch (message) { 905 case WM_AWT_EXECUTE_SYNC: { 906 jobject peerObject = (jobject)wParam; 907 AwtObject* object = (AwtObject *)JNI_GET_PDATA(peerObject); 908 DASSERT( !IsBadReadPtr(object, sizeof(AwtObject))); 909 AwtObject::ExecuteArgs *args = (AwtObject::ExecuteArgs *)lParam; 910 DASSERT(!IsBadReadPtr(args, sizeof(AwtObject::ExecuteArgs))); 911 LRESULT result = 0; 912 if (object != NULL) 913 { 914 result = object->WinThreadExecProc(args); 915 } 916 env->DeleteGlobalRef(peerObject); 917 return result; 918 } 919 case WM_AWT_COMPONENT_CREATE: { 920 ComponentCreatePacket* ccp = (ComponentCreatePacket*)lParam; 921 DASSERT(ccp->factory != NULL); 922 DASSERT(ccp->hComponent != NULL); 923 (*ccp->factory)(ccp->hComponent, ccp->hParent); 924 return 0; 925 } 926 case WM_AWT_DESTROY_WINDOW: { 927 /* Destroy widgets from this same thread that created them */ 928 VERIFY(::DestroyWindow((HWND)wParam) != NULL); 929 return 0; 930 } 931 case WM_AWT_DISPOSE: { 932 if(wParam != NULL) { 933 jobject self = (jobject)wParam; 934 AwtObject *o = (AwtObject *) JNI_GET_PDATA(self); 935 env->DeleteGlobalRef(self); 936 if(o != NULL && theAwtObjectList.Remove(o)) { 937 o->Dispose(); 938 } 939 } 940 return 0; 941 } 942 case WM_AWT_DISPOSEPDATA: { 943 /* 944 * NOTE: synchronization routine (like in WM_AWT_DISPOSE) was omitted because 945 * this handler is called ONLY while disposing Cursor and Font objects where 946 * synchronization takes place. 947 */ 948 AwtObject *o = (AwtObject *) wParam; 949 if(o != NULL && theAwtObjectList.Remove(o)) { 950 o->Dispose(); 951 } 952 return 0; 953 } 954 case WM_AWT_DELETEOBJECT: { 955 AwtObject *p = (AwtObject *) wParam; 956 if (p->CanBeDeleted()) { 957 // all the messages for this component are processed, so 958 // it can be deleted 959 delete p; 960 } else { 961 // postpone deletion, waiting for all the messages for this 962 // component to be processed 963 AwtToolkit::GetInstance().PostMessage(WM_AWT_DELETEOBJECT, wParam, (LPARAM)0); 964 } 965 return 0; 966 } 967 case WM_AWT_OBJECTLISTCLEANUP: { 968 AwtObjectList::Cleanup(); 969 return 0; 970 } 971 case WM_SYSCOLORCHANGE: { 972 973 jclass systemColorClass = env->FindClass("java/awt/SystemColor"); 974 DASSERT(systemColorClass); 975 if (!systemColorClass) throw std::bad_alloc(); 976 977 jmethodID mid = env->GetStaticMethodID(systemColorClass, "updateSystemColors", "()V"); 978 DASSERT(mid); 979 if (!mid) throw std::bad_alloc(); 980 981 env->CallStaticVoidMethod(systemColorClass, mid); 982 983 /* FALL THROUGH - NO BREAK */ 984 } 985 986 case WM_SETTINGCHANGE: { 987 AwtWin32GraphicsDevice::ResetAllMonitorInfo(); 988 /* FALL THROUGH - NO BREAK */ 989 } 990 // Remove this define when we move to newer (XP) version of SDK. 991 #define WM_THEMECHANGED 0x031A 992 case WM_THEMECHANGED: { 993 /* Upcall to WToolkit when user changes configuration. 994 * 995 * NOTE: there is a bug in Windows 98 and some older versions of 996 * Windows NT (it seems to be fixed in NT4 SP5) where no 997 * WM_SETTINGCHANGE is sent when any of the properties under 998 * Control Panel -> Display are changed. You must _always_ query 999 * the system for these - you can't rely on cached values. 1000 */ 1001 jobject peer = AwtToolkit::GetInstance().m_peer; 1002 if (peer != NULL) { 1003 env->CallVoidMethod(peer, AwtToolkit::windowsSettingChangeMID); 1004 } 1005 return 0; 1006 } 1007 #ifndef WM_DWMCOMPOSITIONCHANGED 1008 #define WM_DWMCOMPOSITIONCHANGED 0x031E 1009 #define WM_DWMNCRENDERINGCHANGED 0x031F 1010 #define WM_DWMCOLORIZATIONCOLORCHANGED 0x0320 1011 #define WM_DWMWINDOWMAXIMIZEDCHANGED 0x0321 1012 #endif // WM_DWMCOMPOSITIONCHANGED 1013 case WM_DWMCOMPOSITIONCHANGED: { 1014 DWMResetCompositionEnabled(); 1015 return 0; 1016 } 1017 1018 case WM_TIMER: { 1019 // 6479820. Should check if a window is in manual resizing process: skip 1020 // sending any MouseExit/Enter events while inside resize-loop. 1021 // Note that window being in manual moving process could still 1022 // produce redundant enter/exit mouse events. In future, they can be 1023 // made skipped in a similar way. 1024 if (AwtWindow::IsResizing()) { 1025 return 0; 1026 } 1027 // Create an artifical MouseExit message if the mouse left to 1028 // a non-java window (bad mouse!) 1029 POINT pt; 1030 AwtToolkit& tk = AwtToolkit::GetInstance(); 1031 if (::GetCursorPos(&pt)) { 1032 HWND hWndOver = ::WindowFromPoint(pt); 1033 AwtComponent * last_M; 1034 if ( AwtComponent::GetComponent(hWndOver) == NULL && tk.m_lastMouseOver != NULL ) { 1035 last_M = tk.m_lastMouseOver; 1036 // translate point from screen to target window 1037 MapWindowPoints(HWND_DESKTOP, last_M->GetHWnd(), &pt, 1); 1038 last_M->SendMessage(WM_AWT_MOUSEEXIT, 1039 GetMouseKeyState(), 1040 POINTTOPOINTS(pt)); 1041 tk.m_lastMouseOver = 0; 1042 } 1043 } 1044 if (tk.m_lastMouseOver == NULL && tk.m_timer != 0) { 1045 VERIFY(::KillTimer(tk.m_toolkitHWnd, tk.m_timer)); 1046 tk.m_timer = 0; 1047 } 1048 return 0; 1049 } 1050 case WM_DESTROYCLIPBOARD: { 1051 if (!AwtClipboard::IsGettingOwnership()) 1052 AwtClipboard::LostOwnership((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2)); 1053 return 0; 1054 } 1055 case WM_CHANGECBCHAIN: { 1056 AwtClipboard::WmChangeCbChain(wParam, lParam); 1057 return 0; 1058 } 1059 case WM_DRAWCLIPBOARD: { 1060 AwtClipboard::WmDrawClipboard((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), wParam, lParam); 1061 return 0; 1062 } 1063 case WM_AWT_LIST_SETMULTISELECT: { 1064 jobject peerObject = (jobject)wParam; 1065 AwtList* list = (AwtList *)JNI_GET_PDATA(peerObject); 1066 DASSERT( !IsBadReadPtr(list, sizeof(AwtObject))); 1067 list->SetMultiSelect(static_cast<BOOL>(lParam)); 1068 return 0; 1069 } 1070 1071 // Special awt message to call Imm APIs. 1072 // ImmXXXX() API must be used in the main thread. 1073 // In other thread these APIs does not work correctly even if 1074 // it returs with no error. (This restriction is not documented) 1075 // So we must use thse messages to call these APIs in main thread. 1076 case WM_AWT_CREATECONTEXT: { 1077 return reinterpret_cast<LRESULT>( 1078 reinterpret_cast<void*>(ImmCreateContext())); 1079 } 1080 case WM_AWT_DESTROYCONTEXT: { 1081 ImmDestroyContext((HIMC)wParam); 1082 return 0; 1083 } 1084 case WM_AWT_ASSOCIATECONTEXT: { 1085 EnableNativeIMEStruct *data = (EnableNativeIMEStruct*)wParam; 1086 1087 jobject peer = data->peer; 1088 jobject self = data->self; 1089 jint context = data->context; 1090 jboolean useNativeCompWindow = data->useNativeCompWindow; 1091 1092 AwtComponent* comp = (AwtComponent*)JNI_GET_PDATA(peer); 1093 if (comp != NULL) 1094 { 1095 comp->SetInputMethod(self, useNativeCompWindow); 1096 comp->ImmAssociateContext((HIMC)context); 1097 } 1098 1099 if (peer != NULL) { 1100 env->DeleteGlobalRef(peer); 1101 } 1102 if (self != NULL) { 1103 env->DeleteGlobalRef(self); 1104 } 1105 1106 delete data; 1107 return 0; 1108 } 1109 case WM_AWT_GET_DEFAULT_IME_HANDLER: { 1110 LRESULT ret = (LRESULT)FALSE; 1111 jobject peer = (jobject)wParam; 1112 1113 AwtComponent* comp = (AwtComponent*)JNI_GET_PDATA(peer); 1114 if (comp != NULL) { 1115 HWND defaultIMEHandler = ImmGetDefaultIMEWnd(comp->GetHWnd()); 1116 if (defaultIMEHandler != NULL) { 1117 AwtToolkit::GetInstance().SetInputMethodWindow(defaultIMEHandler); 1118 ret = (LRESULT)TRUE; 1119 } 1120 } 1121 1122 if (peer != NULL) { 1123 env->DeleteGlobalRef(peer); 1124 } 1125 return ret; 1126 } 1127 case WM_AWT_HANDLE_NATIVE_IME_EVENT: { 1128 jobject peer = (jobject)wParam; 1129 AwtComponent* comp = (AwtComponent*)JNI_GET_PDATA(peer); 1130 MSG* msg = (MSG*)lParam; 1131 1132 long modifiers = comp->GetJavaModifiers(); 1133 if ((comp != NULL) && (msg->message==WM_CHAR || msg->message==WM_SYSCHAR)) { 1134 WCHAR unicodeChar = (WCHAR)msg->wParam; 1135 comp->SendKeyEvent(java_awt_event_KeyEvent_KEY_TYPED, 1136 0, //to be fixed nowMillis(), 1137 java_awt_event_KeyEvent_CHAR_UNDEFINED, 1138 unicodeChar, 1139 modifiers, 1140 java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN, (jlong)0, 1141 msg); 1142 } else if (comp != NULL) { 1143 MSG* pCopiedMsg = new MSG; 1144 *pCopiedMsg = *msg; 1145 comp->SendMessage(WM_AWT_HANDLE_EVENT, (WPARAM) FALSE, 1146 (LPARAM) pCopiedMsg); 1147 } 1148 1149 if (peer != NULL) { 1150 env->DeleteGlobalRef(peer); 1151 } 1152 return 0; 1153 } 1154 case WM_AWT_ENDCOMPOSITION: { 1155 /*right now we just cancel the composition string 1156 may need to commit it in the furture 1157 Changed to commit it according to the flag 10/29/98*/ 1158 ImmNotifyIME((HIMC)wParam, NI_COMPOSITIONSTR, 1159 (lParam ? CPS_COMPLETE : CPS_CANCEL), 0); 1160 return 0; 1161 } 1162 case WM_AWT_SETCONVERSIONSTATUS: { 1163 DWORD cmode; 1164 DWORD smode; 1165 ImmGetConversionStatus((HIMC)wParam, (LPDWORD)&cmode, (LPDWORD)&smode); 1166 ImmSetConversionStatus((HIMC)wParam, (DWORD)LOWORD(lParam), smode); 1167 return 0; 1168 } 1169 case WM_AWT_GETCONVERSIONSTATUS: { 1170 DWORD cmode; 1171 DWORD smode; 1172 ImmGetConversionStatus((HIMC)wParam, (LPDWORD)&cmode, (LPDWORD)&smode); 1173 return cmode; 1174 } 1175 case WM_AWT_ACTIVATEKEYBOARDLAYOUT: { 1176 if (wParam && g_bUserHasChangedInputLang) { 1177 // Input language has been changed since the last WInputMethod.getNativeLocale() 1178 // call. So let's honor the user's selection. 1179 // Note: we need to check this flag inside the toolkit thread to synchronize access 1180 // to the flag. 1181 return FALSE; 1182 } 1183 1184 if (lParam == (LPARAM)::GetKeyboardLayout(0)) { 1185 // already active 1186 return FALSE; 1187 } 1188 1189 // Since ActivateKeyboardLayout does not post WM_INPUTLANGCHANGEREQUEST, 1190 // we explicitly need to do the same thing here. 1191 static BYTE keyboardState[AwtToolkit::KB_STATE_SIZE]; 1192 AwtToolkit::GetKeyboardState(keyboardState); 1193 WORD ignored; 1194 ::ToAscii(VK_SPACE, ::MapVirtualKey(VK_SPACE, 0), 1195 keyboardState, &ignored, 0); 1196 1197 return (LRESULT)activateKeyboardLayout((HKL)lParam); 1198 } 1199 case WM_AWT_OPENCANDIDATEWINDOW: { 1200 jobject peerObject = (jobject)wParam; 1201 AwtComponent* p = (AwtComponent*)JNI_GET_PDATA(peerObject); 1202 DASSERT( !IsBadReadPtr(p, sizeof(AwtObject))); 1203 // fix for 4805862: use GET_X_LPARAM and GET_Y_LPARAM macros 1204 // instead of LOWORD and HIWORD 1205 p->OpenCandidateWindow(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); 1206 env->DeleteGlobalRef(peerObject); 1207 return 0; 1208 } 1209 1210 /* 1211 * send this message via ::SendMessage() and the MPT will acquire the 1212 * HANDLE synchronized with the sender's thread. The HANDLE must be 1213 * signalled or deadlock may occur between the MPT and the caller. 1214 */ 1215 1216 case WM_AWT_WAIT_FOR_SINGLE_OBJECT: { 1217 return ::WaitForSingleObject((HANDLE)lParam, INFINITE); 1218 } 1219 case WM_AWT_INVOKE_METHOD: { 1220 return (LRESULT)(*(void*(*)(void*))wParam)((void *)lParam); 1221 } 1222 case WM_AWT_INVOKE_VOID_METHOD: { 1223 return (LRESULT)(*(void*(*)(void))wParam)(); 1224 } 1225 1226 case WM_AWT_SETOPENSTATUS: { 1227 ImmSetOpenStatus((HIMC)wParam, (BOOL)lParam); 1228 return 0; 1229 } 1230 case WM_AWT_GETOPENSTATUS: { 1231 return (DWORD)ImmGetOpenStatus((HIMC)wParam); 1232 } 1233 case WM_DISPLAYCHANGE: { 1234 // Reinitialize screens 1235 initScreens(env); 1236 1237 // Notify Java side - call WToolkit.displayChanged() 1238 jclass clazz = env->FindClass("sun/awt/windows/WToolkit"); 1239 DASSERT(clazz != NULL); 1240 if (!clazz) throw std::bad_alloc(); 1241 env->CallStaticVoidMethod(clazz, AwtToolkit::displayChangeMID); 1242 1243 GetInstance().m_displayChanged = TRUE; 1244 1245 ::PostMessage(HWND_BROADCAST, WM_PALETTEISCHANGING, NULL, NULL); 1246 break; 1247 } 1248 case WM_AWT_SETCURSOR: { 1249 ::SetCursor((HCURSOR)wParam); 1250 return TRUE; 1251 } 1252 /* Session management */ 1253 case WM_QUERYENDSESSION: { 1254 /* Shut down cleanly */ 1255 if (JVM_RaiseSignal(SIGTERM)) { 1256 AwtToolkit::GetInstance().m_vmSignalled = TRUE; 1257 } 1258 return TRUE; 1259 } 1260 case WM_ENDSESSION: { 1261 // Keep pumping messages until the shutdown sequence halts the VM, 1262 // or we exit the MessageLoop because of a WM_QUIT message 1263 AwtToolkit& tk = AwtToolkit::GetInstance(); 1264 1265 // if WM_QUERYENDSESSION hasn't successfully raised SIGTERM 1266 // we ignore the ENDSESSION message 1267 if (!tk.m_vmSignalled) { 1268 return 0; 1269 } 1270 tk.MessageLoop(AwtToolkit::PrimaryIdleFunc, 1271 AwtToolkit::CommonPeekMessageFunc); 1272 1273 // Dispose here instead of in eventLoop so that we don't have 1274 // to return from the WM_ENDSESSION handler. 1275 tk.Dispose(); 1276 1277 // Never return. The VM will halt the process. 1278 hang_if_shutdown(); 1279 1280 // Should never get here. 1281 DASSERT(FALSE); 1282 break; 1283 } 1284 case WM_SYNC_WAIT: 1285 SetEvent(AwtToolkit::GetInstance().m_waitEvent); 1286 break; 1287 } 1288 1289 return DefWindowProc(hWnd, message, wParam, lParam); 1290 1291 CATCH_BAD_ALLOC_RET(0); 1292 } 1293 1294 LRESULT CALLBACK AwtToolkit::GetMessageFilter(int code, 1295 WPARAM wParam, LPARAM lParam) 1296 { 1297 TRY; 1298 1299 if (code >= 0 && wParam == PM_REMOVE && lParam != 0) { 1300 if (AwtToolkit::GetInstance().PreProcessMsg(*(MSG*)lParam) != 1301 mrPassAlong) { 1302 /* PreProcessMsg() wants us to eat it */ 1303 ((MSG*)lParam)->message = WM_NULL; 1304 } 1305 } 1306 return ::CallNextHookEx(AwtToolkit::GetInstance().m_hGetMessageHook, code, 1307 wParam, lParam); 1308 1309 CATCH_BAD_ALLOC_RET(0); 1310 } 1311 1312 void AwtToolkit::InstallMouseLowLevelHook() 1313 { 1314 // We need the low-level hook since we need to process mouse move 1315 // messages outside of our windows. 1316 m_hMouseLLHook = ::SetWindowsHookEx(WH_MOUSE_LL, 1317 (HOOKPROC)MouseLowLevelHook, 1318 GetModuleHandle(), NULL); 1319 1320 // Reset the old value 1321 m_lastWindowUnderMouse = NULL; 1322 } 1323 1324 void AwtToolkit::UninstallMouseLowLevelHook() 1325 { 1326 if (m_hMouseLLHook != 0) { 1327 ::UnhookWindowsHookEx(m_hMouseLLHook); 1328 m_hMouseLLHook = 0; 1329 } 1330 } 1331 1332 LRESULT CALLBACK AwtToolkit::MouseLowLevelHook(int code, 1333 WPARAM wParam, LPARAM lParam) 1334 { 1335 TRY; 1336 1337 if (code >= 0 && wParam == WM_MOUSEMOVE) { 1338 POINT pt = ((MSLLHOOKSTRUCT*)lParam)->pt; 1339 1340 // We can't use GA_ROOTOWNER since in this case we'll go up to 1341 // the root Java toplevel, not the actual owned toplevel. 1342 HWND hwnd = ::GetAncestor(::WindowFromPoint(pt), GA_ROOT); 1343 1344 AwtToolkit& tk = AwtToolkit::GetInstance(); 1345 1346 if (tk.m_lastWindowUnderMouse != hwnd) { 1347 AwtWindow *fw = NULL, *tw = NULL; 1348 1349 if (tk.m_lastWindowUnderMouse) { 1350 fw = (AwtWindow*) 1351 AwtComponent::GetComponent(tk.m_lastWindowUnderMouse); 1352 } 1353 if (hwnd) { 1354 tw = (AwtWindow*)AwtComponent::GetComponent(hwnd); 1355 } 1356 1357 tk.m_lastWindowUnderMouse = hwnd; 1358 1359 if (fw) { 1360 fw->UpdateSecurityWarningVisibility(); 1361 } 1362 // ... however, because we use GA_ROOT, we may find the warningIcon 1363 // which is not a Java windows. 1364 if (AwtWindow::IsWarningWindow(hwnd)) { 1365 hwnd = ::GetParent(hwnd); 1366 if (hwnd) { 1367 tw = (AwtWindow*)AwtComponent::GetComponent(hwnd); 1368 } 1369 tk.m_lastWindowUnderMouse = hwnd; 1370 } 1371 if (tw) { 1372 tw->UpdateSecurityWarningVisibility(); 1373 } 1374 1375 1376 } 1377 } 1378 1379 return ::CallNextHookEx(AwtToolkit::GetInstance().m_hMouseLLHook, code, 1380 wParam, lParam); 1381 1382 CATCH_BAD_ALLOC_RET(0); 1383 } 1384 1385 /* 1386 * The main message loop 1387 */ 1388 1389 const int AwtToolkit::EXIT_ENCLOSING_LOOP = 0; 1390 const int AwtToolkit::EXIT_ALL_ENCLOSING_LOOPS = -1; 1391 1392 1393 /** 1394 * Called upon event idle to ensure that we have released any 1395 * CriticalSections that we took during window event processing. 1396 * 1397 * Note that this gets used more often than you would think; some 1398 * window moves actually happen over more than one event burst. So, 1399 * for example, we might get a WINDOWPOSCHANGING event, then we 1400 * idle and release the lock here, then eventually we get the 1401 * WINDOWPOSCHANGED event. 1402 * 1403 * This method may be called from WToolkit.embeddedEventLoopIdleProcessing 1404 * if there is a separate event loop that must do the same CriticalSection 1405 * check. 1406 * 1407 * See bug #4526587 for more information. 1408 */ 1409 void VerifyWindowMoveLockReleased() 1410 { 1411 if (windowMoveLockHeld) { 1412 windowMoveLockHeld = FALSE; 1413 windowMoveLock.Leave(); 1414 } 1415 } 1416 1417 UINT 1418 AwtToolkit::MessageLoop(IDLEPROC lpIdleFunc, 1419 PEEKMESSAGEPROC lpPeekMessageFunc) 1420 { 1421 DTRACE_PRINTLN("AWT event loop started"); 1422 1423 DASSERT(lpIdleFunc != NULL); 1424 DASSERT(lpPeekMessageFunc != NULL); 1425 1426 m_messageLoopResult = 0; 1427 while (!m_breakMessageLoop) { 1428 1429 (*lpIdleFunc)(); 1430 1431 PumpWaitingMessages(lpPeekMessageFunc); /* pumps waiting messages */ 1432 1433 // Catch problems with windowMoveLock critical section. In case we 1434 // misunderstood the way windows processes window move/resize 1435 // events, we don't want to hold onto the windowMoveLock CS forever. 1436 // If we've finished processing events for now, release the lock 1437 // if held. 1438 VerifyWindowMoveLockReleased(); 1439 } 1440 if (m_messageLoopResult == EXIT_ALL_ENCLOSING_LOOPS) 1441 ::PostQuitMessage(EXIT_ALL_ENCLOSING_LOOPS); 1442 m_breakMessageLoop = FALSE; 1443 1444 DTRACE_PRINTLN("AWT event loop ended"); 1445 1446 return m_messageLoopResult; 1447 } 1448 1449 /* 1450 * Exit the enclosing message loop(s). 1451 * 1452 * The message will be ignored if Windows is currently is in an internal 1453 * message loop (such as a scroll bar drag). So we first send IDCANCEL and 1454 * WM_CANCELMODE messages to every Window on the thread. 1455 */ 1456 static BOOL CALLBACK CancelAllThreadWindows(HWND hWnd, LPARAM) 1457 { 1458 TRY; 1459 1460 ::SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(IDCANCEL, 0), (LPARAM)hWnd); 1461 ::SendMessage(hWnd, WM_CANCELMODE, 0, 0); 1462 1463 return TRUE; 1464 1465 CATCH_BAD_ALLOC_RET(FALSE); 1466 } 1467 1468 static void DoQuitMessageLoop(void* param) { 1469 int status = *static_cast<int*>(param); 1470 1471 AwtToolkit::GetInstance().QuitMessageLoop(status); 1472 } 1473 1474 void AwtToolkit::QuitMessageLoop(int status) { 1475 /* 1476 * Fix for 4623377. 1477 * Reinvoke QuitMessageLoop on the toolkit thread, so that 1478 * m_breakMessageLoop is accessed on a single thread. 1479 */ 1480 if (!AwtToolkit::IsMainThread()) { 1481 InvokeFunction(DoQuitMessageLoop, &status); 1482 return; 1483 } 1484 1485 /* 1486 * Fix for BugTraq ID 4445747. 1487 * EnumThreadWindows() is very slow during dnd on Win9X/ME. 1488 * This call is unnecessary during dnd, since we postpone processing of all 1489 * messages that can enter internal message loop until dnd is over. 1490 */ 1491 if (status == EXIT_ALL_ENCLOSING_LOOPS) { 1492 ::EnumThreadWindows(MainThread(), (WNDENUMPROC)CancelAllThreadWindows, 1493 0); 1494 } 1495 1496 /* 1497 * Fix for 4623377. 1498 * Modal loop may not exit immediatelly after WM_CANCELMODE, so it still can 1499 * eat WM_QUIT message and the nested message loop will never exit. 1500 * The fix is to use AwtToolkit instance variables instead of WM_QUIT to 1501 * guarantee that we exit from the nested message loop when any possible 1502 * modal loop quits. In this case CancelAllThreadWindows is needed only to 1503 * ensure that the nested message loop exits quickly and doesn't wait until 1504 * a possible modal loop completes. 1505 */ 1506 m_breakMessageLoop = TRUE; 1507 m_messageLoopResult = status; 1508 1509 /* 1510 * Fix for 4683602. 1511 * Post an empty message, to wake up the toolkit thread 1512 * if it is currently in WaitMessage(), 1513 */ 1514 PostMessage(WM_NULL); 1515 } 1516 1517 /* 1518 * Called by the message loop to pump the message queue when there are 1519 * messages waiting. Can also be called anywhere to pump messages. 1520 */ 1521 BOOL AwtToolkit::PumpWaitingMessages(PEEKMESSAGEPROC lpPeekMessageFunc) 1522 { 1523 MSG msg; 1524 BOOL foundOne = FALSE; 1525 1526 DASSERT(lpPeekMessageFunc != NULL); 1527 1528 while (!m_breakMessageLoop && (*lpPeekMessageFunc)(msg)) { 1529 foundOne = TRUE; 1530 ProcessMsg(msg); 1531 } 1532 return foundOne; 1533 } 1534 1535 void AwtToolkit::PumpToDestroy(class AwtComponent* p) 1536 { 1537 MSG msg; 1538 1539 DASSERT(AwtToolkit::PrimaryIdleFunc != NULL); 1540 DASSERT(AwtToolkit::CommonPeekMessageFunc != NULL); 1541 1542 while (p->IsDestroyPaused() && !m_breakMessageLoop) { 1543 1544 PrimaryIdleFunc(); 1545 1546 while (p->IsDestroyPaused() && !m_breakMessageLoop && CommonPeekMessageFunc(msg)) { 1547 ProcessMsg(msg); 1548 } 1549 } 1550 } 1551 1552 void AwtToolkit::ProcessMsg(MSG& msg) 1553 { 1554 if (msg.message == WM_QUIT) { 1555 m_breakMessageLoop = TRUE; 1556 m_messageLoopResult = static_cast<UINT>(msg.wParam); 1557 if (m_messageLoopResult == EXIT_ALL_ENCLOSING_LOOPS) 1558 ::PostQuitMessage(static_cast<int>(msg.wParam)); // make sure all loops exit 1559 } 1560 else if (msg.message != WM_NULL) { 1561 /* 1562 * The AWT in standalone mode (that is, dynamically loaded from the 1563 * Java VM) doesn't have any translation tables to worry about, so 1564 * TranslateAccelerator isn't called. 1565 */ 1566 1567 ::TranslateMessage(&msg); 1568 ::DispatchMessage(&msg); 1569 } 1570 } 1571 1572 VOID CALLBACK 1573 AwtToolkit::PrimaryIdleFunc() { 1574 AwtToolkit::SetBusy(FALSE); 1575 ::WaitMessage(); /* allow system to go idle */ 1576 AwtToolkit::SetBusy(TRUE); 1577 } 1578 1579 VOID CALLBACK 1580 AwtToolkit::SecondaryIdleFunc() { 1581 ::WaitMessage(); /* allow system to go idle */ 1582 } 1583 1584 BOOL 1585 AwtToolkit::CommonPeekMessageFunc(MSG& msg) { 1586 return ::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE); 1587 } 1588 1589 /* 1590 * Perform pre-processing on a message before it is translated & 1591 * dispatched. Returns true to eat the message 1592 */ 1593 BOOL AwtToolkit::PreProcessMsg(MSG& msg) 1594 { 1595 /* 1596 * Offer preprocessing first to the target component, then call out to 1597 * specific mouse and key preprocessor methods 1598 */ 1599 AwtComponent* p = AwtComponent::GetComponent(msg.hwnd); 1600 if (p && p->PreProcessMsg(msg) == mrConsume) 1601 return TRUE; 1602 1603 if ((msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST) || 1604 (msg.message >= WM_NCMOUSEMOVE && msg.message <= WM_NCMBUTTONDBLCLK)) { 1605 if (PreProcessMouseMsg(p, msg)) { 1606 return TRUE; 1607 } 1608 } 1609 else if (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST) { 1610 if (PreProcessKeyMsg(p, msg)) 1611 return TRUE; 1612 } 1613 return FALSE; 1614 } 1615 1616 BOOL AwtToolkit::PreProcessMouseMsg(AwtComponent* p, MSG& msg) 1617 { 1618 WPARAM mouseWParam; 1619 LPARAM mouseLParam; 1620 1621 /* 1622 * Fix for BugTraq ID 4395290. 1623 * Do not synthesize mouse enter/exit events during drag-and-drop, 1624 * since it messes up LightweightDispatcher. 1625 */ 1626 if (AwtDropTarget::IsLocalDnD()) { 1627 return FALSE; 1628 } 1629 1630 if (msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST) { 1631 mouseWParam = msg.wParam; 1632 mouseLParam = msg.lParam; 1633 } else { 1634 mouseWParam = GetMouseKeyState(); 1635 } 1636 1637 /* 1638 * Get the window under the mouse, as it will be different if its 1639 * captured. 1640 */ 1641 DWORD dwCurPos = ::GetMessagePos(); 1642 DWORD dwScreenPos = dwCurPos; 1643 POINT curPos; 1644 // fix for 4805862 1645 // According to MSDN: do not use LOWORD and HIWORD macros to extract x and 1646 // y coordinates because these macros return incorrect results on systems 1647 // with multiple monitors (signed values are treated as unsigned) 1648 curPos.x = GET_X_LPARAM(dwCurPos); 1649 curPos.y = GET_Y_LPARAM(dwCurPos); 1650 HWND hWndFromPoint = ::WindowFromPoint(curPos); 1651 // hWndFromPoint == 0 if mouse is over a scrollbar 1652 AwtComponent* mouseComp = 1653 AwtComponent::GetComponent(hWndFromPoint); 1654 // Need extra copies for non-client area issues 1655 HWND hWndForWheel = hWndFromPoint; 1656 1657 // If the point under the mouse isn't in the client area, 1658 // ignore it to maintain compatibility with Solaris (#4095172) 1659 RECT windowRect; 1660 ::GetClientRect(hWndFromPoint, &windowRect); 1661 POINT topLeft; 1662 topLeft.x = 0; 1663 topLeft.y = 0; 1664 ::ClientToScreen(hWndFromPoint, &topLeft); 1665 windowRect.top += topLeft.y; 1666 windowRect.bottom += topLeft.y; 1667 windowRect.left += topLeft.x; 1668 windowRect.right += topLeft.x; 1669 if ((curPos.y < windowRect.top) || 1670 (curPos.y >= windowRect.bottom) || 1671 (curPos.x < windowRect.left) || 1672 (curPos.x >= windowRect.right)) { 1673 mouseComp = NULL; 1674 hWndFromPoint = NULL; 1675 } 1676 1677 /* 1678 * Look for mouse transitions between windows & create 1679 * MouseExit & MouseEnter messages 1680 */ 1681 // 6479820. Should check if a window is in manual resizing process: skip 1682 // sending any MouseExit/Enter events while inside resize-loop. 1683 // Note that window being in manual moving process could still 1684 // produce redundant enter/exit mouse events. In future, they can be 1685 // made skipped in a similar way. 1686 if (mouseComp != m_lastMouseOver && !AwtWindow::IsResizing()) { 1687 /* 1688 * Send the messages right to the windows so that they are in 1689 * the right sequence. 1690 */ 1691 if (m_lastMouseOver) { 1692 dwCurPos = dwScreenPos; 1693 curPos.x = LOWORD(dwCurPos); 1694 curPos.y = HIWORD(dwCurPos); 1695 ::MapWindowPoints(HWND_DESKTOP, m_lastMouseOver->GetHWnd(), 1696 &curPos, 1); 1697 mouseLParam = MAKELPARAM((WORD)curPos.x, (WORD)curPos.y); 1698 m_lastMouseOver->SendMessage(WM_AWT_MOUSEEXIT, mouseWParam, 1699 mouseLParam); 1700 } 1701 if (mouseComp) { 1702 dwCurPos = dwScreenPos; 1703 curPos.x = LOWORD(dwCurPos); 1704 curPos.y = HIWORD(dwCurPos); 1705 ::MapWindowPoints(HWND_DESKTOP, mouseComp->GetHWnd(), 1706 &curPos, 1); 1707 mouseLParam = MAKELPARAM((WORD)curPos.x, (WORD)curPos.y); 1708 mouseComp->SendMessage(WM_AWT_MOUSEENTER, mouseWParam, 1709 mouseLParam); 1710 } 1711 m_lastMouseOver = mouseComp; 1712 } 1713 1714 /* 1715 * For MouseWheelEvents, hwnd must be changed to be the Component under 1716 * the mouse, not the Component with the input focus. 1717 */ 1718 1719 if (msg.message == WM_MOUSEWHEEL) { 1720 //i.e. mouse is over client area for this window 1721 DWORD hWndForWheelProcess; 1722 DWORD hWndForWheelThread = ::GetWindowThreadProcessId(hWndForWheel, &hWndForWheelProcess); 1723 if (::GetCurrentProcessId() == hWndForWheelProcess) { 1724 if (AwtToolkit::MainThread() == hWndForWheelThread) { 1725 msg.hwnd = hWndForWheel; 1726 } else { 1727 // Interop mode, redispatch the event to another toolkit. 1728 ::SendMessage(hWndForWheel, msg.message, mouseWParam, mouseLParam); 1729 return TRUE; 1730 } 1731 } 1732 } 1733 1734 /* 1735 * Make sure we get at least one last chance to check for transitions 1736 * before we sleep 1737 */ 1738 if (m_lastMouseOver && !m_timer) { 1739 m_timer = ::SetTimer(m_toolkitHWnd, IDT_AWT_MOUSECHECK, 200, 0); 1740 } 1741 return FALSE; /* Now go ahead and process current message as usual */ 1742 } 1743 1744 BOOL AwtToolkit::PreProcessKeyMsg(AwtComponent* p, MSG& msg) 1745 { 1746 // get keyboard state for use in AwtToolkit::GetKeyboardState 1747 CriticalSection::Lock l(m_lockKB); 1748 ::GetKeyboardState(m_lastKeyboardState); 1749 return FALSE; 1750 } 1751 1752 void *AwtToolkit::SyncCall(void *(*ftn)(void *), void *param) { 1753 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 1754 if (!IsMainThread()) { 1755 CriticalSection::Lock l(GetSyncCS()); 1756 return (*ftn)(param); 1757 } else { 1758 return (*ftn)(param); 1759 } 1760 } 1761 1762 void AwtToolkit::SyncCall(void (*ftn)(void *), void *param) { 1763 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 1764 if (!IsMainThread()) { 1765 CriticalSection::Lock l(GetSyncCS()); 1766 (*ftn)(param); 1767 } else { 1768 (*ftn)(param); 1769 } 1770 } 1771 1772 void *AwtToolkit::SyncCall(void *(*ftn)(void)) { 1773 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 1774 if (!IsMainThread()) { 1775 CriticalSection::Lock l(GetSyncCS()); 1776 return (*ftn)(); 1777 } else { 1778 return (*ftn)(); 1779 } 1780 } 1781 1782 void AwtToolkit::SyncCall(void (*ftn)(void)) { 1783 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 1784 if (!IsMainThread()) { 1785 CriticalSection::Lock l(GetSyncCS()); 1786 (*ftn)(); 1787 } else { 1788 (*ftn)(); 1789 } 1790 } 1791 1792 UINT AwtToolkit::CreateCmdID(AwtObject* object) 1793 { 1794 return m_cmdIDs->Add(object); 1795 } 1796 1797 void AwtToolkit::RemoveCmdID(UINT id) 1798 { 1799 m_cmdIDs->Remove(id); 1800 } 1801 1802 AwtObject* AwtToolkit::LookupCmdID(UINT id) 1803 { 1804 return m_cmdIDs->Lookup(id); 1805 } 1806 1807 HICON AwtToolkit::GetAwtIcon() 1808 { 1809 return ::LoadIcon(GetModuleHandle(), TEXT("AWT_ICON")); 1810 } 1811 1812 HICON AwtToolkit::GetAwtIconSm() 1813 { 1814 static HICON defaultIconSm = NULL; 1815 static int prevSmx = 0; 1816 static int prevSmy = 0; 1817 1818 int smx = GetSystemMetrics(SM_CXSMICON); 1819 int smy = GetSystemMetrics(SM_CYSMICON); 1820 1821 // Fixed 6364216: LoadImage() may leak memory 1822 if (defaultIconSm == NULL || smx != prevSmx || smy != prevSmy) { 1823 defaultIconSm = (HICON)LoadImage(GetModuleHandle(), TEXT("AWT_ICON"), IMAGE_ICON, smx, smy, 0); 1824 prevSmx = smx; 1825 prevSmy = smy; 1826 } 1827 return defaultIconSm; 1828 } 1829 1830 // The icon at index 0 must be gray. See AwtWindow::GetSecurityWarningIcon() 1831 HICON AwtToolkit::GetSecurityWarningIcon(UINT index, UINT w, UINT h) 1832 { 1833 //Note: should not exceed 10 because of the current implementation. 1834 static const int securityWarningIconCounter = 3; 1835 1836 static HICON securityWarningIcon[securityWarningIconCounter] = {NULL, NULL, NULL};; 1837 static UINT securityWarningIconWidth[securityWarningIconCounter] = {0, 0, 0}; 1838 static UINT securityWarningIconHeight[securityWarningIconCounter] = {0, 0, 0}; 1839 1840 index = AwtToolkit::CalculateWave(index, securityWarningIconCounter); 1841 1842 if (securityWarningIcon[index] == NULL || 1843 w != securityWarningIconWidth[index] || 1844 h != securityWarningIconHeight[index]) 1845 { 1846 if (securityWarningIcon[index] != NULL) 1847 { 1848 ::DestroyIcon(securityWarningIcon[index]); 1849 } 1850 1851 static const wchar_t securityWarningIconName[] = L"SECURITY_WARNING_"; 1852 wchar_t iconResourceName[sizeof(securityWarningIconName) + 2]; 1853 ::ZeroMemory(iconResourceName, sizeof(iconResourceName)); 1854 wcscpy(iconResourceName, securityWarningIconName); 1855 1856 wchar_t strIndex[2]; 1857 ::ZeroMemory(strIndex, sizeof(strIndex)); 1858 strIndex[0] = L'0' + index; 1859 1860 wcscat(iconResourceName, strIndex); 1861 1862 securityWarningIcon[index] = (HICON)::LoadImage(GetModuleHandle(), 1863 iconResourceName, 1864 IMAGE_ICON, w, h, LR_DEFAULTCOLOR); 1865 securityWarningIconWidth[index] = w; 1866 securityWarningIconHeight[index] = h; 1867 } 1868 1869 return securityWarningIcon[index]; 1870 } 1871 1872 void AwtToolkit::SetHeapCheck(long flag) { 1873 if (flag) { 1874 printf("heap checking not supported with this build\n"); 1875 } 1876 } 1877 1878 void throw_if_shutdown(void) throw (awt_toolkit_shutdown) 1879 { 1880 AwtToolkit::GetInstance().VerifyActive(); 1881 } 1882 void hang_if_shutdown(void) 1883 { 1884 try { 1885 AwtToolkit::GetInstance().VerifyActive(); 1886 } catch (awt_toolkit_shutdown&) { 1887 // Never return. The VM will halt the process. 1888 ::WaitForSingleObject(::CreateEvent(NULL, TRUE, FALSE, NULL), 1889 INFINITE); 1890 // Should never get here. 1891 DASSERT(FALSE); 1892 } 1893 } 1894 1895 // for now we support only one embedder, but should be ready for future 1896 void AwtToolkit::RegisterEmbedderProcessId(HWND embedder) 1897 { 1898 if (m_embedderProcessID) { 1899 // we already set embedder process and do not expect 1900 // two different processes to embed the same AwtToolkit 1901 return; 1902 } 1903 1904 embedder = ::GetAncestor(embedder, GA_ROOT); 1905 ::GetWindowThreadProcessId(embedder, &m_embedderProcessID); 1906 } 1907 1908 JNIEnv* AwtToolkit::m_env; 1909 DWORD AwtToolkit::m_threadId; 1910 1911 void AwtToolkit::SetEnv(JNIEnv *env) { 1912 if (m_env != NULL) { // If already cashed (by means of embeddedInit() call). 1913 return; 1914 } 1915 m_threadId = GetCurrentThreadId(); 1916 m_env = env; 1917 } 1918 1919 JNIEnv* AwtToolkit::GetEnv() { 1920 return (m_env == NULL || m_threadId != GetCurrentThreadId()) ? 1921 (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_2) : m_env; 1922 } 1923 1924 BOOL AwtToolkit::GetScreenInsets(int screenNum, RECT * rect) 1925 { 1926 /* if primary display */ 1927 if (screenNum == 0) { 1928 RECT rRW; 1929 if (::SystemParametersInfo(SPI_GETWORKAREA,0,(void *) &rRW,0) == TRUE) { 1930 rect->top = rRW.top; 1931 rect->left = rRW.left; 1932 rect->bottom = ::GetSystemMetrics(SM_CYSCREEN) - rRW.bottom; 1933 rect->right = ::GetSystemMetrics(SM_CXSCREEN) - rRW.right; 1934 return TRUE; 1935 } 1936 } 1937 /* if additional display */ 1938 else { 1939 MONITORINFO *miInfo; 1940 miInfo = AwtWin32GraphicsDevice::GetMonitorInfo(screenNum); 1941 if (miInfo) { 1942 rect->top = miInfo->rcWork.top - miInfo->rcMonitor.top; 1943 rect->left = miInfo->rcWork.left - miInfo->rcMonitor.left; 1944 rect->bottom = miInfo->rcMonitor.bottom - miInfo->rcWork.bottom; 1945 rect->right = miInfo->rcMonitor.right - miInfo->rcWork.right; 1946 return TRUE; 1947 } 1948 } 1949 return FALSE; 1950 } 1951 1952 1953 void AwtToolkit::GetWindowRect(HWND hWnd, LPRECT lpRect) 1954 { 1955 try { 1956 if (S_OK == DwmAPI::DwmGetWindowAttribute(hWnd, 1957 DwmAPI::DWMWA_EXTENDED_FRAME_BOUNDS, 1958 lpRect, sizeof(*lpRect))) 1959 { 1960 return; 1961 } 1962 } catch (const DllUtil::Exception &) {} 1963 1964 ::GetWindowRect(hWnd, lpRect); 1965 } 1966 1967 1968 /************************************************************************ 1969 * AWT preloading support 1970 */ 1971 bool AwtToolkit::PreloadAction::EnsureInited() 1972 { 1973 DWORD _initThreadId = GetInitThreadID(); 1974 if (_initThreadId != 0) { 1975 // already inited 1976 // ensure the action is inited on correct thread 1977 PreloadThread &preloadThread 1978 = AwtToolkit::GetInstance().GetPreloadThread(); 1979 if (_initThreadId == preloadThread.GetThreadId()) { 1980 if (!preloadThread.IsWrongThread()) { 1981 return true; 1982 } 1983 // inited on preloadThread (wrongThread), not cleaned yet 1984 // have to wait cleanup completion 1985 preloadThread.Wait4Finish(); 1986 } else { 1987 // inited on other thread (Toolkit thread?) 1988 // consider as correctly inited 1989 return true; 1990 } 1991 } 1992 1993 // init on Toolkit thread 1994 AwtToolkit::GetInstance().InvokeFunction(InitWrapper, this); 1995 1996 return true; 1997 } 1998 1999 DWORD AwtToolkit::PreloadAction::GetInitThreadID() 2000 { 2001 CriticalSection::Lock lock(initLock); 2002 return initThreadId; 2003 } 2004 2005 bool AwtToolkit::PreloadAction::Clean() 2006 { 2007 DWORD _initThreadId = GetInitThreadID(); 2008 if (_initThreadId == ::GetCurrentThreadId()) { 2009 // inited on this thread 2010 Clean(false); 2011 return true; 2012 } 2013 return false; 2014 } 2015 2016 /*static*/ 2017 void AwtToolkit::PreloadAction::InitWrapper(void *param) 2018 { 2019 PreloadAction *pThis = (PreloadAction *)param; 2020 pThis->Init(); 2021 } 2022 2023 void AwtToolkit::PreloadAction::Init() 2024 { 2025 CriticalSection::Lock lock(initLock); 2026 if (initThreadId == 0) { 2027 initThreadId = ::GetCurrentThreadId(); 2028 InitImpl(); 2029 } 2030 } 2031 2032 void AwtToolkit::PreloadAction::Clean(bool reInit) { 2033 CriticalSection::Lock lock(initLock); 2034 if (initThreadId != 0) { 2035 //ASSERT(initThreadId == ::GetCurrentThreadId()); 2036 CleanImpl(reInit); 2037 initThreadId = 0; 2038 } 2039 } 2040 2041 // PreloadThread implementation 2042 AwtToolkit::PreloadThread::PreloadThread() 2043 : status(None), wrongThread(false), threadId(0), 2044 pActionChain(NULL), pLastProcessedAction(NULL), 2045 execFunc(NULL), execParam(NULL) 2046 { 2047 hFinished = ::CreateEvent(NULL, TRUE, FALSE, NULL); 2048 hAwake = ::CreateEvent(NULL, FALSE, FALSE, NULL); 2049 } 2050 2051 AwtToolkit::PreloadThread::~PreloadThread() 2052 { 2053 //Terminate(false); 2054 ::CloseHandle(hFinished); 2055 ::CloseHandle(hAwake); 2056 } 2057 2058 bool AwtToolkit::PreloadThread::AddAction(AwtToolkit::PreloadAction *pAction) 2059 { 2060 CriticalSection::Lock lock(threadLock); 2061 2062 if (status > Preloading) { 2063 // too late - the thread already terminated or run as toolkit thread 2064 return false; 2065 } 2066 2067 if (pActionChain == NULL) { 2068 // 1st action 2069 pActionChain = pAction; 2070 } else { 2071 // add the action to the chain 2072 PreloadAction *pChain = pActionChain; 2073 while (true) { 2074 PreloadAction *pNext = pChain->GetNext(); 2075 if (pNext == NULL) { 2076 break; 2077 } 2078 pChain = pNext; 2079 } 2080 pChain->SetNext(pAction); 2081 } 2082 2083 if (status > None) { 2084 // the thread is already running (status == Preloading) 2085 AwakeThread(); 2086 return true; 2087 } 2088 2089 // need to start thread 2090 ::ResetEvent(hAwake); 2091 ::ResetEvent(hFinished); 2092 2093 HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0x100000, StaticThreadProc, 2094 this, 0, &threadId); 2095 2096 if (hThread == 0) { 2097 threadId = 0; 2098 return false; 2099 } 2100 2101 status = Preloading; 2102 2103 ::CloseHandle(hThread); 2104 2105 return true; 2106 } 2107 2108 bool AwtToolkit::PreloadThread::Terminate(bool wrongThread) 2109 { 2110 CriticalSection::Lock lock(threadLock); 2111 2112 if (status != Preloading) { 2113 return false; 2114 } 2115 2116 execFunc = NULL; 2117 execParam = NULL; 2118 this->wrongThread = wrongThread; 2119 status = Cleaning; 2120 AwakeThread(); 2121 2122 return true; 2123 } 2124 2125 bool AwtToolkit::PreloadThread::InvokeAndTerminate(void(_cdecl *fn)(void *), void *param) 2126 { 2127 CriticalSection::Lock lock(threadLock); 2128 2129 if (status != Preloading) { 2130 return false; 2131 } 2132 2133 execFunc = fn; 2134 execParam = param; 2135 status = fn == NULL ? Cleaning : RunningToolkit; 2136 AwakeThread(); 2137 2138 return true; 2139 } 2140 2141 bool AwtToolkit::PreloadThread::OnPreloadThread() 2142 { 2143 return GetThreadId() == ::GetCurrentThreadId(); 2144 } 2145 2146 /*static*/ 2147 unsigned WINAPI AwtToolkit::PreloadThread::StaticThreadProc(void *param) 2148 { 2149 AwtToolkit::PreloadThread *pThis = (AwtToolkit::PreloadThread *)param; 2150 return pThis->ThreadProc(); 2151 } 2152 2153 unsigned AwtToolkit::PreloadThread::ThreadProc() 2154 { 2155 void(_cdecl *_execFunc)(void *) = NULL; 2156 void *_execParam = NULL; 2157 bool _wrongThread = false; 2158 2159 // initialization 2160 while (true) { 2161 PreloadAction *pAction; 2162 { 2163 CriticalSection::Lock lock(threadLock); 2164 if (status != Preloading) { 2165 // get invoke parameters 2166 _execFunc = execFunc; 2167 _execParam = execParam; 2168 _wrongThread = wrongThread; 2169 break; 2170 } 2171 pAction = GetNextAction(); 2172 } 2173 if (pAction != NULL) { 2174 pAction->Init(); 2175 } else { 2176 ::WaitForSingleObject(hAwake, INFINITE); 2177 } 2178 } 2179 2180 // call a function from InvokeAndTerminate 2181 if (_execFunc != NULL) { 2182 _execFunc(_execParam); 2183 } else { 2184 // time to terminate.. 2185 } 2186 2187 // cleanup 2188 { 2189 CriticalSection::Lock lock(threadLock); 2190 pLastProcessedAction = NULL; // goto 1st action in the chain 2191 status = Cleaning; 2192 } 2193 for (PreloadAction *pAction = GetNextAction(); pAction != NULL; 2194 pAction = GetNextAction()) { 2195 pAction->Clean(_wrongThread); 2196 } 2197 2198 // don't clear threadId! it is used by PreloadAction::EnsureInited 2199 2200 { 2201 CriticalSection::Lock lock(threadLock); 2202 status = Finished; 2203 } 2204 ::SetEvent(hFinished); 2205 return 0; 2206 } 2207 2208 AwtToolkit::PreloadAction* AwtToolkit::PreloadThread::GetNextAction() 2209 { 2210 CriticalSection::Lock lock(threadLock); 2211 PreloadAction *pAction = (pLastProcessedAction == NULL) 2212 ? pActionChain 2213 : pLastProcessedAction->GetNext(); 2214 if (pAction != NULL) { 2215 pLastProcessedAction = pAction; 2216 } 2217 2218 return pAction; 2219 } 2220 2221 2222 extern "C" { 2223 2224 /* Terminates preload thread (if it's still alive 2225 * - it may occur if the application doesn't use AWT). 2226 * The function is called from launcher after completion main java thread. 2227 */ 2228 __declspec(dllexport) void preloadStop() 2229 { 2230 AwtToolkit::GetInstance().GetPreloadThread().Terminate(false); 2231 } 2232 2233 } 2234 2235 2236 /************************************************************************ 2237 * Toolkit native methods 2238 */ 2239 2240 extern "C" { 2241 2242 /* 2243 * Class: java_awt_Toolkit 2244 * Method: initIDs 2245 * Signature: ()V 2246 */ 2247 JNIEXPORT void JNICALL 2248 Java_java_awt_Toolkit_initIDs(JNIEnv *env, jclass cls) { 2249 TRY; 2250 2251 AwtToolkit::getDefaultToolkitMID = 2252 env->GetStaticMethodID(cls,"getDefaultToolkit","()Ljava/awt/Toolkit;"); 2253 DASSERT(AwtToolkit::getDefaultToolkitMID != NULL); 2254 CHECK_NULL(AwtToolkit::getDefaultToolkitMID); 2255 2256 AwtToolkit::getFontMetricsMID = 2257 env->GetMethodID(cls, "getFontMetrics", "(Ljava/awt/Font;)Ljava/awt/FontMetrics;"); 2258 DASSERT(AwtToolkit::getFontMetricsMID != NULL); 2259 CHECK_NULL(AwtToolkit::getFontMetricsMID); 2260 2261 jclass insetsClass = env->FindClass("java/awt/Insets"); 2262 DASSERT(insetsClass != NULL); 2263 CHECK_NULL(insetsClass); 2264 AwtToolkit::insetsMID = env->GetMethodID(insetsClass, "<init>", "(IIII)V"); 2265 DASSERT(AwtToolkit::insetsMID != NULL); 2266 CHECK_NULL(AwtToolkit::insetsMID); 2267 2268 CATCH_BAD_ALLOC; 2269 } 2270 2271 2272 } /* extern "C" */ 2273 2274 /************************************************************************ 2275 * WToolkit native methods 2276 */ 2277 2278 extern "C" { 2279 2280 /* 2281 * Class: sun_awt_windows_WToolkit 2282 * Method: initIDs 2283 * Signature: ()V 2284 */ 2285 JNIEXPORT void JNICALL 2286 Java_sun_awt_windows_WToolkit_initIDs(JNIEnv *env, jclass cls) 2287 { 2288 TRY; 2289 2290 AwtToolkit::windowsSettingChangeMID = 2291 env->GetMethodID(cls, "windowsSettingChange", "()V"); 2292 DASSERT(AwtToolkit::windowsSettingChangeMID != 0); 2293 CHECK_NULL(AwtToolkit::windowsSettingChangeMID); 2294 2295 AwtToolkit::displayChangeMID = 2296 env->GetStaticMethodID(cls, "displayChanged", "()V"); 2297 DASSERT(AwtToolkit::displayChangeMID != 0); 2298 CHECK_NULL(AwtToolkit::displayChangeMID); 2299 2300 // Set various global IDs needed by JAWT code. Note: these 2301 // variables cannot be set by JAWT code directly due to 2302 // different permissions that that code may be run under 2303 // (bug 4796548). It would be nice to initialize these 2304 // variables lazily, but given the minimal number of calls 2305 // for this, it seems simpler to just do it at startup with 2306 // negligible penalty. 2307 jclass sDataClassLocal = env->FindClass("sun/java2d/SurfaceData"); 2308 DASSERT(sDataClassLocal != 0); 2309 CHECK_NULL(sDataClassLocal); 2310 2311 jclass vImgClassLocal = env->FindClass("sun/awt/image/SunVolatileImage"); 2312 DASSERT(vImgClassLocal != 0); 2313 CHECK_NULL(vImgClassLocal); 2314 2315 jclass vSMgrClassLocal = 2316 env->FindClass("sun/awt/image/VolatileSurfaceManager"); 2317 DASSERT(vSMgrClassLocal != 0); 2318 CHECK_NULL(vSMgrClassLocal); 2319 2320 jclass componentClassLocal = env->FindClass("java/awt/Component"); 2321 DASSERT(componentClassLocal != 0); 2322 CHECK_NULL(componentClassLocal); 2323 2324 jawtSMgrID = env->GetFieldID(vImgClassLocal, "volSurfaceManager", 2325 "Lsun/awt/image/VolatileSurfaceManager;"); 2326 DASSERT(jawtSMgrID != 0); 2327 CHECK_NULL(jawtSMgrID); 2328 2329 jawtSDataID = env->GetFieldID(vSMgrClassLocal, "sdCurrent", 2330 "Lsun/java2d/SurfaceData;"); 2331 DASSERT(jawtSDataID != 0); 2332 CHECK_NULL(jawtSDataID); 2333 2334 jawtPDataID = env->GetFieldID(sDataClassLocal, "pData", "J"); 2335 DASSERT(jawtPDataID != 0); 2336 CHECK_NULL(jawtPDataID); 2337 // Save these classes in global references for later use 2338 jawtVImgClass = (jclass)env->NewGlobalRef(vImgClassLocal); 2339 CHECK_NULL(jawtVImgClass); 2340 jawtComponentClass = (jclass)env->NewGlobalRef(componentClassLocal); 2341 2342 CATCH_BAD_ALLOC; 2343 } 2344 2345 2346 /* 2347 * Class: sun_awt_windows_Toolkit 2348 * Method: disableCustomPalette 2349 * Signature: ()V 2350 */ 2351 JNIEXPORT void JNICALL 2352 Java_sun_awt_windows_WToolkit_disableCustomPalette(JNIEnv *env, jclass cls) { 2353 AwtPalette::DisableCustomPalette(); 2354 } 2355 2356 /* 2357 * Class: sun_awt_windows_WToolkit 2358 * Method: embeddedInit 2359 * Signature: ()Z 2360 */ 2361 JNIEXPORT jboolean JNICALL 2362 Java_sun_awt_windows_WToolkit_embeddedInit(JNIEnv *env, jclass cls) 2363 { 2364 TRY; 2365 2366 AwtToolkit::SetEnv(env); 2367 2368 return AwtToolkit::GetInstance().Initialize(FALSE); 2369 2370 CATCH_BAD_ALLOC_RET(JNI_FALSE); 2371 } 2372 2373 /* 2374 * Class: sun_awt_windows_WToolkit 2375 * Method: embeddedDispose 2376 * Signature: ()Z 2377 */ 2378 JNIEXPORT jboolean JNICALL 2379 Java_sun_awt_windows_WToolkit_embeddedDispose(JNIEnv *env, jclass cls) 2380 { 2381 TRY; 2382 2383 BOOL retval = AwtToolkit::GetInstance().Dispose(); 2384 AwtToolkit::GetInstance().SetPeer(env, NULL); 2385 return retval; 2386 2387 CATCH_BAD_ALLOC_RET(JNI_FALSE); 2388 } 2389 2390 /* 2391 * Class: sun_awt_windows_WToolkit 2392 * Method: embeddedEventLoopIdleProcessing 2393 * Signature: ()V 2394 */ 2395 JNIEXPORT void JNICALL 2396 Java_sun_awt_windows_WToolkit_embeddedEventLoopIdleProcessing(JNIEnv *env, 2397 jobject self) 2398 { 2399 VerifyWindowMoveLockReleased(); 2400 } 2401 2402 2403 /* 2404 * Class: sun_awt_windows_WToolkit 2405 * Method: init 2406 * Signature: ()Z 2407 */ 2408 JNIEXPORT jboolean JNICALL 2409 Java_sun_awt_windows_WToolkit_init(JNIEnv *env, jobject self) 2410 { 2411 TRY; 2412 2413 AwtToolkit::SetEnv(env); 2414 2415 AwtToolkit::GetInstance().SetPeer(env, self); 2416 2417 // This call will fail if the Toolkit was already initialized. 2418 // In that case, we don't want to start another message pump. 2419 return AwtToolkit::GetInstance().Initialize(TRUE); 2420 2421 CATCH_BAD_ALLOC_RET(FALSE); 2422 } 2423 2424 /* 2425 * Class: sun_awt_windows_WToolkit 2426 * Method: eventLoop 2427 * Signature: ()V 2428 */ 2429 JNIEXPORT void JNICALL 2430 Java_sun_awt_windows_WToolkit_eventLoop(JNIEnv *env, jobject self) 2431 { 2432 TRY; 2433 2434 DASSERT(AwtToolkit::GetInstance().localPump()); 2435 2436 AwtToolkit::SetBusy(TRUE); 2437 2438 AwtToolkit::GetInstance().MessageLoop(AwtToolkit::PrimaryIdleFunc, 2439 AwtToolkit::CommonPeekMessageFunc); 2440 2441 AwtToolkit::GetInstance().Dispose(); 2442 2443 AwtToolkit::SetBusy(FALSE); 2444 2445 /* 2446 * IMPORTANT NOTES: 2447 * The AwtToolkit has been destructed by now. 2448 * DO NOT CALL any method of AwtToolkit!!! 2449 */ 2450 2451 CATCH_BAD_ALLOC; 2452 } 2453 2454 /* 2455 * Class: sun_awt_windows_WToolkit 2456 * Method: shutdown 2457 * Signature: ()V 2458 */ 2459 JNIEXPORT void JNICALL 2460 Java_sun_awt_windows_WToolkit_shutdown(JNIEnv *env, jobject self) 2461 { 2462 TRY; 2463 2464 AwtToolkit& tk = AwtToolkit::GetInstance(); 2465 2466 tk.QuitMessageLoop(AwtToolkit::EXIT_ALL_ENCLOSING_LOOPS); 2467 2468 while (!tk.IsDisposed()) { 2469 Sleep(100); 2470 } 2471 2472 CATCH_BAD_ALLOC; 2473 } 2474 2475 /* 2476 * Class: sun_awt_windows_WToolkit 2477 * Method: startSecondaryEventLoop 2478 * Signature: ()V; 2479 */ 2480 JNIEXPORT void JNICALL 2481 Java_sun_awt_windows_WToolkit_startSecondaryEventLoop( 2482 JNIEnv *env, 2483 jclass) 2484 { 2485 TRY; 2486 2487 DASSERT(AwtToolkit::MainThread() == ::GetCurrentThreadId()); 2488 2489 AwtToolkit::GetInstance().MessageLoop(AwtToolkit::SecondaryIdleFunc, 2490 AwtToolkit::CommonPeekMessageFunc); 2491 2492 CATCH_BAD_ALLOC; 2493 } 2494 2495 /* 2496 * Class: sun_awt_windows_WToolkit 2497 * Method: quitSecondaryEventLoop 2498 * Signature: ()V; 2499 */ 2500 JNIEXPORT void JNICALL 2501 Java_sun_awt_windows_WToolkit_quitSecondaryEventLoop( 2502 JNIEnv *env, 2503 jclass) 2504 { 2505 TRY; 2506 2507 AwtToolkit::GetInstance().QuitMessageLoop(AwtToolkit::EXIT_ENCLOSING_LOOP); 2508 2509 CATCH_BAD_ALLOC; 2510 } 2511 2512 /* 2513 * Class: sun_awt_windows_WToolkit 2514 * Method: makeColorModel 2515 * Signature: ()Ljava/awt/image/ColorModel; 2516 */ 2517 JNIEXPORT jobject JNICALL 2518 Java_sun_awt_windows_WToolkit_makeColorModel(JNIEnv *env, jclass cls) 2519 { 2520 TRY; 2521 2522 return AwtWin32GraphicsDevice::GetColorModel(env, JNI_FALSE, 2523 AwtWin32GraphicsDevice::GetDefaultDeviceIndex()); 2524 2525 CATCH_BAD_ALLOC_RET(NULL); 2526 } 2527 2528 /* 2529 * Class: sun_awt_windows_WToolkit 2530 * Method: getMaximumCursorColors 2531 * Signature: ()I 2532 */ 2533 JNIEXPORT jint JNICALL 2534 Java_sun_awt_windows_WToolkit_getMaximumCursorColors(JNIEnv *env, jobject self) 2535 { 2536 TRY; 2537 2538 HDC hIC = ::CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL); 2539 2540 int nColor = 256; 2541 switch (::GetDeviceCaps(hIC, BITSPIXEL) * ::GetDeviceCaps(hIC, PLANES)) { 2542 case 1: nColor = 2; break; 2543 case 4: nColor = 16; break; 2544 case 8: nColor = 256; break; 2545 case 16: nColor = 65536; break; 2546 case 24: nColor = 16777216; break; 2547 } 2548 ::DeleteDC(hIC); 2549 return nColor; 2550 2551 CATCH_BAD_ALLOC_RET(0); 2552 } 2553 2554 /* 2555 * Class: sun_awt_windows_WToolkit 2556 * Method: getScreenWidth 2557 * Signature: ()I 2558 */ 2559 JNIEXPORT jint JNICALL 2560 Java_sun_awt_windows_WToolkit_getScreenWidth(JNIEnv *env, jobject self) 2561 { 2562 TRY; 2563 2564 return ::GetSystemMetrics(SM_CXSCREEN); 2565 2566 CATCH_BAD_ALLOC_RET(0); 2567 } 2568 2569 /* 2570 * Class: sun_awt_windows_WToolkit 2571 * Method: getScreenHeight 2572 * Signature: ()I 2573 */ 2574 JNIEXPORT jint JNICALL 2575 Java_sun_awt_windows_WToolkit_getScreenHeight(JNIEnv *env, jobject self) 2576 { 2577 TRY; 2578 2579 return ::GetSystemMetrics(SM_CYSCREEN); 2580 2581 CATCH_BAD_ALLOC_RET(0); 2582 } 2583 2584 /* 2585 * Class: sun_awt_windows_WToolkit 2586 * Method: getSreenInsets 2587 * Signature: (I)Ljava/awt/Insets; 2588 */ 2589 JNIEXPORT jobject JNICALL 2590 Java_sun_awt_windows_WToolkit_getScreenInsets(JNIEnv *env, 2591 jobject self, 2592 jint screen) 2593 { 2594 jobject insets = NULL; 2595 RECT rect; 2596 2597 TRY; 2598 2599 if (AwtToolkit::GetScreenInsets(screen, &rect)) { 2600 jclass insetsClass = env->FindClass("java/awt/Insets"); 2601 DASSERT(insetsClass != NULL); 2602 CHECK_NULL_RETURN(insetsClass, NULL); 2603 2604 insets = env->NewObject(insetsClass, 2605 AwtToolkit::insetsMID, 2606 rect.top, 2607 rect.left, 2608 rect.bottom, 2609 rect.right); 2610 } 2611 2612 if (safe_ExceptionOccurred(env)) { 2613 return 0; 2614 } 2615 return insets; 2616 2617 CATCH_BAD_ALLOC_RET(NULL); 2618 } 2619 2620 2621 /* 2622 * Class: sun_awt_windows_WToolkit 2623 * Method: nativeSync 2624 * Signature: ()V 2625 */ 2626 JNIEXPORT void JNICALL 2627 Java_sun_awt_windows_WToolkit_nativeSync(JNIEnv *env, jobject self) 2628 { 2629 TRY; 2630 2631 // Synchronize both GDI and DDraw 2632 VERIFY(::GdiFlush()); 2633 2634 CATCH_BAD_ALLOC; 2635 } 2636 2637 /* 2638 * Class: sun_awt_windows_WToolkit 2639 * Method: beep 2640 * Signature: ()V 2641 */ 2642 JNIEXPORT void JNICALL 2643 Java_sun_awt_windows_WToolkit_beep(JNIEnv *env, jobject self) 2644 { 2645 TRY; 2646 2647 VERIFY(::MessageBeep(MB_OK)); 2648 2649 CATCH_BAD_ALLOC; 2650 } 2651 2652 /* 2653 * Class: sun_awt_windows_WToolkit 2654 * Method: getLockingKeyStateNative 2655 * Signature: (I)Z 2656 */ 2657 JNIEXPORT jboolean JNICALL 2658 Java_sun_awt_windows_WToolkit_getLockingKeyStateNative(JNIEnv *env, jobject self, jint javaKey) 2659 { 2660 TRY; 2661 2662 UINT windowsKey, modifiers; 2663 AwtComponent::JavaKeyToWindowsKey(javaKey, &windowsKey, &modifiers); 2664 2665 if (windowsKey == 0) { 2666 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "Keyboard doesn't have requested key"); 2667 return JNI_FALSE; 2668 } 2669 2670 // low order bit in keyboardState indicates whether the key is toggled 2671 BYTE keyboardState[AwtToolkit::KB_STATE_SIZE]; 2672 AwtToolkit::GetKeyboardState(keyboardState); 2673 return keyboardState[windowsKey] & 0x01; 2674 2675 CATCH_BAD_ALLOC_RET(JNI_FALSE); 2676 } 2677 2678 /* 2679 * Class: sun_awt_windows_WToolkit 2680 * Method: setLockingKeyStateNative 2681 * Signature: (IZ)V 2682 */ 2683 JNIEXPORT void JNICALL 2684 Java_sun_awt_windows_WToolkit_setLockingKeyStateNative(JNIEnv *env, jobject self, jint javaKey, jboolean state) 2685 { 2686 TRY; 2687 2688 UINT windowsKey, modifiers; 2689 AwtComponent::JavaKeyToWindowsKey(javaKey, &windowsKey, &modifiers); 2690 2691 if (windowsKey == 0) { 2692 JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "Keyboard doesn't have requested key"); 2693 return; 2694 } 2695 2696 // if the key isn't in the desired state yet, simulate key events to get there 2697 // low order bit in keyboardState indicates whether the key is toggled 2698 BYTE keyboardState[AwtToolkit::KB_STATE_SIZE]; 2699 AwtToolkit::GetKeyboardState(keyboardState); 2700 if ((keyboardState[windowsKey] & 0x01) != state) { 2701 ::keybd_event(windowsKey, 0, 0, 0); 2702 ::keybd_event(windowsKey, 0, KEYEVENTF_KEYUP, 0); 2703 } 2704 2705 CATCH_BAD_ALLOC; 2706 } 2707 2708 /* 2709 * Class: sun_awt_windows_WToolkit 2710 * Method: loadSystemColors 2711 * Signature: ([I)V 2712 */ 2713 JNIEXPORT void JNICALL 2714 Java_sun_awt_windows_WToolkit_loadSystemColors(JNIEnv *env, jobject self, 2715 jintArray colors) 2716 { 2717 TRY; 2718 2719 static int indexMap[] = { 2720 COLOR_DESKTOP, /* DESKTOP */ 2721 COLOR_ACTIVECAPTION, /* ACTIVE_CAPTION */ 2722 COLOR_CAPTIONTEXT, /* ACTIVE_CAPTION_TEXT */ 2723 COLOR_ACTIVEBORDER, /* ACTIVE_CAPTION_BORDER */ 2724 COLOR_INACTIVECAPTION, /* INACTIVE_CAPTION */ 2725 COLOR_INACTIVECAPTIONTEXT, /* INACTIVE_CAPTION_TEXT */ 2726 COLOR_INACTIVEBORDER, /* INACTIVE_CAPTION_BORDER */ 2727 COLOR_WINDOW, /* WINDOW */ 2728 COLOR_WINDOWFRAME, /* WINDOW_BORDER */ 2729 COLOR_WINDOWTEXT, /* WINDOW_TEXT */ 2730 COLOR_MENU, /* MENU */ 2731 COLOR_MENUTEXT, /* MENU_TEXT */ 2732 COLOR_WINDOW, /* TEXT */ 2733 COLOR_WINDOWTEXT, /* TEXT_TEXT */ 2734 COLOR_HIGHLIGHT, /* TEXT_HIGHLIGHT */ 2735 COLOR_HIGHLIGHTTEXT, /* TEXT_HIGHLIGHT_TEXT */ 2736 COLOR_GRAYTEXT, /* TEXT_INACTIVE_TEXT */ 2737 COLOR_3DFACE, /* CONTROL */ 2738 COLOR_BTNTEXT, /* CONTROL_TEXT */ 2739 COLOR_3DLIGHT, /* CONTROL_HIGHLIGHT */ 2740 COLOR_3DHILIGHT, /* CONTROL_LT_HIGHLIGHT */ 2741 COLOR_3DSHADOW, /* CONTROL_SHADOW */ 2742 COLOR_3DDKSHADOW, /* CONTROL_DK_SHADOW */ 2743 COLOR_SCROLLBAR, /* SCROLLBAR */ 2744 COLOR_INFOBK, /* INFO */ 2745 COLOR_INFOTEXT, /* INFO_TEXT */ 2746 }; 2747 2748 jint colorLen = env->GetArrayLength(colors); 2749 jint* colorsPtr = NULL; 2750 try { 2751 colorsPtr = (jint *)env->GetPrimitiveArrayCritical(colors, 0); 2752 for (int i = 0; i < (sizeof indexMap)/(sizeof *indexMap) && i < colorLen; i++) { 2753 colorsPtr[i] = DesktopColor2RGB(indexMap[i]); 2754 } 2755 } catch (...) { 2756 if (colorsPtr != NULL) { 2757 env->ReleasePrimitiveArrayCritical(colors, colorsPtr, 0); 2758 } 2759 throw; 2760 } 2761 2762 env->ReleasePrimitiveArrayCritical(colors, colorsPtr, 0); 2763 2764 CATCH_BAD_ALLOC; 2765 } 2766 2767 extern "C" JNIEXPORT jobject JNICALL DSGetComponent 2768 (JNIEnv* env, void* platformInfo) 2769 { 2770 TRY; 2771 2772 HWND hWnd = (HWND)platformInfo; 2773 if (!::IsWindow(hWnd)) 2774 return NULL; 2775 2776 AwtComponent* comp = AwtComponent::GetComponent(hWnd); 2777 if (comp == NULL) 2778 return NULL; 2779 2780 return comp->GetTarget(env); 2781 2782 CATCH_BAD_ALLOC_RET(NULL); 2783 } 2784 2785 JNIEXPORT void JNICALL 2786 Java_sun_awt_windows_WToolkit_postDispose(JNIEnv *env, jclass clazz) 2787 { 2788 #ifdef DEBUG 2789 TRY_NO_VERIFY; 2790 2791 // If this method was called, that means runFinalizersOnExit is turned 2792 // on and the VM is exiting cleanly. We should signal the debug memory 2793 // manager to generate a leaks report. 2794 AwtDebugSupport::GenerateLeaksReport(); 2795 2796 CATCH_BAD_ALLOC; 2797 #endif 2798 } 2799 2800 /* 2801 * Class: sun_awt_windows_WToolkit 2802 * Method: setDynamicLayoutNative 2803 * Signature: (Z)V 2804 */ 2805 JNIEXPORT void JNICALL 2806 Java_sun_awt_windows_WToolkit_setDynamicLayoutNative(JNIEnv *env, 2807 jobject self, jboolean dynamic) 2808 { 2809 TRY; 2810 2811 AwtToolkit::GetInstance().SetDynamicLayout(dynamic); 2812 2813 CATCH_BAD_ALLOC; 2814 } 2815 2816 /* 2817 * Class: sun_awt_windows_WToolkit 2818 * Method: isDynamicLayoutSupportedNative 2819 * Signature: ()Z 2820 */ 2821 JNIEXPORT jboolean JNICALL 2822 Java_sun_awt_windows_WToolkit_isDynamicLayoutSupportedNative(JNIEnv *env, 2823 jobject self) 2824 { 2825 TRY; 2826 2827 return (jboolean) AwtToolkit::GetInstance().IsDynamicLayoutSupported(); 2828 2829 CATCH_BAD_ALLOC_RET(FALSE); 2830 } 2831 2832 /* 2833 * Class: sun_awt_windows_WToolkit 2834 * Method: printWindowsVersion 2835 * Signature: ()Ljava/lang/String; 2836 */ 2837 JNIEXPORT jstring JNICALL 2838 Java_sun_awt_windows_WToolkit_getWindowsVersion(JNIEnv *env, jclass cls) 2839 { 2840 TRY; 2841 2842 WCHAR szVer[128]; 2843 2844 DWORD version = ::GetVersion(); 2845 swprintf(szVer, 128, L"0x%x = %ld", version, version); 2846 int l = lstrlen(szVer); 2847 2848 if (IS_WIN2000) { 2849 if (IS_WINXP) { 2850 if (IS_WINVISTA) { 2851 swprintf(szVer + l, 128, L" (Windows Vista)"); 2852 } else { 2853 swprintf(szVer + l, 128, L" (Windows XP)"); 2854 } 2855 } else { 2856 swprintf(szVer + l, 128, L" (Windows 2000)"); 2857 } 2858 } else { 2859 swprintf(szVer + l, 128, L" (Unknown)"); 2860 } 2861 2862 return JNU_NewStringPlatform(env, szVer); 2863 2864 CATCH_BAD_ALLOC_RET(NULL); 2865 } 2866 2867 JNIEXPORT void JNICALL 2868 Java_sun_awt_windows_WToolkit_showTouchKeyboard(JNIEnv *env, jobject self, 2869 jboolean causedByTouchEvent) 2870 { 2871 AwtToolkit& tk = AwtToolkit::GetInstance(); 2872 if (!tk.IsWin8OrLater() || !tk.IsTouchKeyboardAutoShowEnabled()) { 2873 return; 2874 } 2875 2876 if (causedByTouchEvent || 2877 (tk.IsTouchKeyboardAutoShowSystemEnabled() && 2878 !tk.IsAnyKeyboardAttached())) { 2879 tk.ShowTouchKeyboard(); 2880 } 2881 } 2882 2883 JNIEXPORT void JNICALL 2884 Java_sun_awt_windows_WToolkit_hideTouchKeyboard(JNIEnv *env, jobject self) 2885 { 2886 AwtToolkit& tk = AwtToolkit::GetInstance(); 2887 if (!tk.IsWin8OrLater() || !tk.IsTouchKeyboardAutoShowEnabled()) { 2888 return; 2889 } 2890 tk.HideTouchKeyboard(); 2891 } 2892 2893 JNIEXPORT jboolean JNICALL 2894 Java_sun_awt_windows_WToolkit_syncNativeQueue(JNIEnv *env, jobject self, jlong timeout) 2895 { 2896 AwtToolkit & tk = AwtToolkit::GetInstance(); 2897 DWORD eventNumber = tk.eventNumber; 2898 tk.PostMessage(WM_SYNC_WAIT, 0, 0); 2899 ::WaitForSingleObject(tk.m_waitEvent, INFINITE); 2900 DWORD newEventNumber = tk.eventNumber; 2901 return (newEventNumber - eventNumber) > 2; 2902 } 2903 2904 } /* extern "C" */ 2905 2906 /* Convert a Windows desktop color index into an RGB value. */ 2907 COLORREF DesktopColor2RGB(int colorIndex) { 2908 DWORD sysColor = ::GetSysColor(colorIndex); 2909 return ((GetRValue(sysColor)<<16) | (GetGValue(sysColor)<<8) | 2910 (GetBValue(sysColor)) | 0xff000000); 2911 } 2912 2913 2914 /* 2915 * Class: sun_awt_SunToolkit 2916 * Method: closeSplashScreen 2917 * Signature: ()V 2918 */ 2919 extern "C" JNIEXPORT void JNICALL 2920 Java_sun_awt_SunToolkit_closeSplashScreen(JNIEnv *env, jclass cls) 2921 { 2922 typedef void (*SplashClose_t)(); 2923 HMODULE hSplashDll = GetModuleHandle(_T("splashscreen.dll")); 2924 if (!hSplashDll) { 2925 return; // dll not loaded 2926 } 2927 SplashClose_t splashClose = (SplashClose_t)GetProcAddress(hSplashDll, 2928 "SplashClose"); 2929 if (splashClose) { 2930 splashClose(); 2931 } 2932 } 2933 2934 /* 2935 * accessible from awt_Component 2936 */ 2937 BOOL AwtToolkit::areExtraMouseButtonsEnabled() { 2938 return m_areExtraMouseButtonsEnabled; 2939 } 2940 2941 /* 2942 * Class: sun_awt_windows_WToolkit 2943 * Method: setExtraMouseButtonsEnabledNative 2944 * Signature: (Z)V 2945 */ 2946 extern "C" JNIEXPORT void JNICALL Java_sun_awt_windows_WToolkit_setExtraMouseButtonsEnabledNative 2947 (JNIEnv *env, jclass self, jboolean enable){ 2948 TRY; 2949 AwtToolkit::GetInstance().setExtraMouseButtonsEnabled(enable); 2950 CATCH_BAD_ALLOC; 2951 } 2952 2953 void AwtToolkit::setExtraMouseButtonsEnabled(BOOL enable) { 2954 m_areExtraMouseButtonsEnabled = enable; 2955 } 2956 2957 JNIEXPORT jint JNICALL Java_sun_awt_windows_WToolkit_getNumberOfButtonsImpl 2958 (JNIEnv *, jobject self) { 2959 return AwtToolkit::GetNumberOfButtons(); 2960 } 2961 2962 UINT AwtToolkit::GetNumberOfButtons() { 2963 return MOUSE_BUTTONS_WINDOWS_SUPPORTED; 2964 } 2965 2966 bool AwtToolkit::IsWin8OrLater() { 2967 return m_isWin8OrLater; 2968 } 2969 2970 bool AwtToolkit::IsTouchKeyboardAutoShowEnabled() { 2971 return m_touchKbrdAutoShowIsEnabled; 2972 } 2973 2974 bool AwtToolkit::IsAnyKeyboardAttached() { 2975 UINT numDevs = 0; 2976 UINT numDevsRet = 0; 2977 const UINT devListTypeSize = sizeof(RAWINPUTDEVICELIST); 2978 if ((::GetRawInputDeviceList(NULL, &numDevs, devListTypeSize) != 0) || 2979 (numDevs == 0)) { 2980 return false; 2981 } 2982 2983 RAWINPUTDEVICELIST* pDevList = new RAWINPUTDEVICELIST[numDevs]; 2984 while (((numDevsRet = ::GetRawInputDeviceList(pDevList, &numDevs, 2985 devListTypeSize)) == (UINT)-1) && 2986 (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { 2987 if (pDevList != NULL) { 2988 delete[] pDevList; 2989 } 2990 pDevList = new RAWINPUTDEVICELIST[numDevs]; 2991 } 2992 2993 bool keyboardIsAttached = false; 2994 if (numDevsRet != (UINT)-1) { 2995 for (UINT i = 0; i < numDevsRet; i++) { 2996 if (pDevList[i].dwType == RIM_TYPEKEYBOARD) { 2997 keyboardIsAttached = true; 2998 break; 2999 } 3000 } 3001 } 3002 3003 if (pDevList != NULL) { 3004 delete[] pDevList; 3005 } 3006 return keyboardIsAttached; 3007 } 3008 3009 bool AwtToolkit::IsTouchKeyboardAutoShowSystemEnabled() { 3010 const TCHAR tabTipKeyName[] = _T("SOFTWARE\\Microsoft\\TabletTip\\1.7"); 3011 HKEY hTabTipKey = NULL; 3012 if (::RegOpenKeyEx(HKEY_CURRENT_USER, tabTipKeyName, 0, KEY_READ, 3013 &hTabTipKey) != ERROR_SUCCESS) { 3014 return false; 3015 } 3016 3017 const TCHAR enableAutoInvokeValName[] = _T("EnableDesktopModeAutoInvoke"); 3018 DWORD keyValType = 0; 3019 bool autoShowIsEnabled = false; 3020 if (::RegQueryValueEx(hTabTipKey, enableAutoInvokeValName, NULL, 3021 &keyValType, NULL, NULL) == ERROR_SUCCESS) { 3022 if (keyValType == REG_DWORD) { 3023 DWORD enableAutoInvokeVal = 0; 3024 DWORD bytesCopied = sizeof(DWORD); 3025 if (::RegQueryValueEx(hTabTipKey, enableAutoInvokeValName, NULL, 3026 NULL, (LPBYTE)(DWORD*)&enableAutoInvokeVal, 3027 &bytesCopied) == ERROR_SUCCESS) { 3028 autoShowIsEnabled = (enableAutoInvokeVal == 0 ? false : true); 3029 } 3030 } 3031 } 3032 3033 if (hTabTipKey != NULL) { 3034 ::RegCloseKey(hTabTipKey); 3035 } 3036 return autoShowIsEnabled; 3037 } 3038 3039 void AwtToolkit::ShowTouchKeyboard() { 3040 if (m_isWin8OrLater && m_touchKbrdAutoShowIsEnabled && 3041 (m_touchKbrdExeFilePath != NULL)) { 3042 HINSTANCE retVal = ::ShellExecute(NULL, _T("open"), 3043 m_touchKbrdExeFilePath, NULL, NULL, SW_SHOW); 3044 if ((int)retVal <= 32) { 3045 DTRACE_PRINTLN1("AwtToolkit::ShowTouchKeyboard: Failed" 3046 ", retVal='%d'", (int)retVal); 3047 } 3048 } 3049 } 3050 3051 void AwtToolkit::HideTouchKeyboard() { 3052 if (m_isWin8OrLater && m_touchKbrdAutoShowIsEnabled) { 3053 HWND hwnd = GetTouchKeyboardWindow(); 3054 if (hwnd != NULL) { 3055 ::PostMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0); 3056 } 3057 } 3058 } 3059 3060 BOOL AwtToolkit::TIRegisterTouchWindow(HWND hWnd, ULONG ulFlags) { 3061 if (m_pRegisterTouchWindow == NULL) { 3062 return FALSE; 3063 } 3064 return m_pRegisterTouchWindow(hWnd, ulFlags); 3065 } 3066 3067 BOOL AwtToolkit::TIGetTouchInputInfo(HTOUCHINPUT hTouchInput, 3068 UINT cInputs, PTOUCHINPUT pInputs, int cbSize) { 3069 if (m_pGetTouchInputInfo == NULL) { 3070 return FALSE; 3071 } 3072 return m_pGetTouchInputInfo(hTouchInput, cInputs, pInputs, cbSize); 3073 } 3074 3075 BOOL AwtToolkit::TICloseTouchInputHandle(HTOUCHINPUT hTouchInput) { 3076 if (m_pCloseTouchInputHandle == NULL) { 3077 return FALSE; 3078 } 3079 return m_pCloseTouchInputHandle(hTouchInput); 3080 }