| /* |
| * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| #define _JNI_IMPLEMENTATION_ |
| |
| #include "awt.h" |
| #include <signal.h> |
| #include <windowsx.h> |
| #include <process.h> |
| |
| #include "awt_DrawingSurface.h" |
| #include "awt_AWTEvent.h" |
| #include "awt_Component.h" |
| #include "awt_Canvas.h" |
| #include "awt_Clipboard.h" |
| #include "awt_Frame.h" |
| #include "awt_Dialog.h" |
| #include "awt_Font.h" |
| #include "awt_Cursor.h" |
| #include "awt_InputEvent.h" |
| #include "awt_KeyEvent.h" |
| #include "awt_List.h" |
| #include "awt_Palette.h" |
| #include "awt_PopupMenu.h" |
| #include "awt_Toolkit.h" |
| #include "awt_DesktopProperties.h" |
| #include "awt_FileDialog.h" |
| #include "CmdIDList.h" |
| #include "awt_new.h" |
| #include "debug_trace.h" |
| #include "debug_mem.h" |
| |
| #include "ComCtl32Util.h" |
| #include "DllUtil.h" |
| |
| #include "D3DPipelineManager.h" |
| |
| #include <awt_DnDDT.h> |
| #include <awt_DnDDS.h> |
| |
| #include <java_awt_Toolkit.h> |
| #include <java_awt_event_InputMethodEvent.h> |
| |
| extern void initScreens(JNIEnv *env); |
| extern "C" void awt_dnd_initialize(); |
| extern "C" void awt_dnd_uninitialize(); |
| extern "C" void awt_clipboard_uninitialize(JNIEnv *env); |
| extern "C" BOOL g_bUserHasChangedInputLang; |
| |
| extern CriticalSection windowMoveLock; |
| extern BOOL windowMoveLockHeld; |
| |
| // Needed by JAWT: see awt_DrawingSurface.cpp. |
| extern jclass jawtVImgClass; |
| extern jclass jawtVSMgrClass; |
| extern jclass jawtComponentClass; |
| extern jfieldID jawtPDataID; |
| extern jfieldID jawtSDataID; |
| extern jfieldID jawtSMgrID; |
| |
| extern void DWMResetCompositionEnabled(); |
| |
| /************************************************************************ |
| * Utilities |
| */ |
| |
| /* Initialize the Java VM instance variable when the library is |
| first loaded */ |
| JavaVM *jvm = NULL; |
| |
| JNIEXPORT jint JNICALL |
| JNI_OnLoad(JavaVM *vm, void *reserved) |
| { |
| TRY; |
| |
| jvm = vm; |
| return JNI_VERSION_1_2; |
| |
| CATCH_BAD_ALLOC_RET(0); |
| } |
| |
| extern "C" JNIEXPORT jboolean JNICALL AWTIsHeadless() { |
| static JNIEnv *env = NULL; |
| static jboolean isHeadless; |
| jmethodID headlessFn; |
| jclass graphicsEnvClass; |
| |
| if (env == NULL) { |
| env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| graphicsEnvClass = env->FindClass( |
| "java/awt/GraphicsEnvironment"); |
| if (graphicsEnvClass == NULL) { |
| return JNI_TRUE; |
| } |
| headlessFn = env->GetStaticMethodID( |
| graphicsEnvClass, "isHeadless", "()Z"); |
| if (headlessFn == NULL) { |
| return JNI_TRUE; |
| } |
| isHeadless = env->CallStaticBooleanMethod(graphicsEnvClass, |
| headlessFn); |
| } |
| return isHeadless; |
| } |
| |
| #define IDT_AWT_MOUSECHECK 0x101 |
| |
| static LPCTSTR szAwtToolkitClassName = TEXT("SunAwtToolkit"); |
| |
| static const int MOUSE_BUTTONS_WINDOWS_SUPPORTED = 5; //three standard buttons + XBUTTON1 + XBUTTON2. |
| |
| UINT AwtToolkit::GetMouseKeyState() |
| { |
| static BOOL mbSwapped = ::GetSystemMetrics(SM_SWAPBUTTON); |
| UINT mouseKeyState = 0; |
| |
| if (HIBYTE(::GetKeyState(VK_CONTROL))) |
| mouseKeyState |= MK_CONTROL; |
| if (HIBYTE(::GetKeyState(VK_SHIFT))) |
| mouseKeyState |= MK_SHIFT; |
| if (HIBYTE(::GetKeyState(VK_LBUTTON))) |
| mouseKeyState |= (mbSwapped ? MK_RBUTTON : MK_LBUTTON); |
| if (HIBYTE(::GetKeyState(VK_RBUTTON))) |
| mouseKeyState |= (mbSwapped ? MK_LBUTTON : MK_RBUTTON); |
| if (HIBYTE(::GetKeyState(VK_MBUTTON))) |
| mouseKeyState |= MK_MBUTTON; |
| return mouseKeyState; |
| } |
| |
| // |
| // Normal ::GetKeyboardState call only works if current thread has |
| // a message pump, so provide a way for other threads to get |
| // the keyboard state |
| // |
| void AwtToolkit::GetKeyboardState(PBYTE keyboardState) |
| { |
| CriticalSection::Lock l(AwtToolkit::GetInstance().m_lockKB); |
| DASSERT(!IsBadWritePtr(keyboardState, KB_STATE_SIZE)); |
| memcpy(keyboardState, AwtToolkit::GetInstance().m_lastKeyboardState, |
| KB_STATE_SIZE); |
| } |
| |
| void AwtToolkit::SetBusy(BOOL busy) { |
| |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| |
| static jclass awtAutoShutdownClass = NULL; |
| static jmethodID notifyBusyMethodID = NULL; |
| static jmethodID notifyFreeMethodID = NULL; |
| |
| if (awtAutoShutdownClass == NULL) { |
| jclass awtAutoShutdownClassLocal = env->FindClass("sun/awt/AWTAutoShutdown"); |
| DASSERT(awtAutoShutdownClassLocal != NULL); |
| if (!awtAutoShutdownClassLocal) throw std::bad_alloc(); |
| |
| awtAutoShutdownClass = (jclass)env->NewGlobalRef(awtAutoShutdownClassLocal); |
| env->DeleteLocalRef(awtAutoShutdownClassLocal); |
| if (!awtAutoShutdownClass) throw std::bad_alloc(); |
| |
| notifyBusyMethodID = env->GetStaticMethodID(awtAutoShutdownClass, |
| "notifyToolkitThreadBusy", "()V"); |
| DASSERT(notifyBusyMethodID != NULL); |
| if (!notifyBusyMethodID) throw std::bad_alloc(); |
| |
| notifyFreeMethodID = env->GetStaticMethodID(awtAutoShutdownClass, |
| "notifyToolkitThreadFree", "()V"); |
| DASSERT(notifyFreeMethodID != NULL); |
| if (!notifyFreeMethodID) throw std::bad_alloc(); |
| } /* awtAutoShutdownClass == NULL*/ |
| |
| if (busy) { |
| env->CallStaticVoidMethod(awtAutoShutdownClass, |
| notifyBusyMethodID); |
| } else { |
| env->CallStaticVoidMethod(awtAutoShutdownClass, |
| notifyFreeMethodID); |
| } |
| |
| if (!JNU_IsNull(env, safe_ExceptionOccurred(env))) { |
| env->ExceptionDescribe(); |
| env->ExceptionClear(); |
| } |
| } |
| |
| BOOL AwtToolkit::activateKeyboardLayout(HKL hkl) { |
| // This call should succeed in case of one of the following: |
| // 1. Win 9x |
| // 2. NT with that HKL already loaded |
| HKL prev = ::ActivateKeyboardLayout(hkl, 0); |
| |
| // If the above call fails, try loading the layout in case of NT |
| if (!prev) { |
| // create input locale string, e.g., "00000409", from hkl. |
| TCHAR inputLocale[9]; |
| TCHAR buf[9]; |
| _tcscpy_s(inputLocale, 9, TEXT("00000000")); |
| |
| // 64-bit: ::LoadKeyboardLayout() is such a weird API - a string of |
| // the hex value you want?! Here we're converting our HKL value to |
| // a string. Hopefully there is no 64-bit trouble. |
| _i64tot(reinterpret_cast<INT_PTR>(hkl), buf, 16); |
| size_t len = _tcslen(buf); |
| memcpy(&inputLocale[8-len], buf, len); |
| |
| // load and activate the keyboard layout |
| hkl = ::LoadKeyboardLayout(inputLocale, 0); |
| if (hkl != 0) { |
| prev = ::ActivateKeyboardLayout(hkl, 0); |
| } |
| } |
| |
| return (prev != 0); |
| } |
| |
| /************************************************************************ |
| * Exported functions |
| */ |
| |
| extern "C" BOOL APIENTRY DllMain(HANDLE hInstance, DWORD ul_reason_for_call, |
| LPVOID) |
| { |
| // Don't use the TRY and CATCH_BAD_ALLOC_RET macros if we're detaching |
| // the library. Doing so causes awt.dll to call back into the VM during |
| // shutdown. This crashes the HotSpot VM. |
| switch (ul_reason_for_call) { |
| case DLL_PROCESS_ATTACH: |
| TRY; |
| AwtToolkit::GetInstance().SetModuleHandle((HMODULE)hInstance); |
| CATCH_BAD_ALLOC_RET(FALSE); |
| break; |
| case DLL_PROCESS_DETACH: |
| #ifdef DEBUG |
| DTrace_DisableMutex(); |
| DMem_DisableMutex(); |
| #endif DEBUG |
| break; |
| } |
| return TRUE; |
| } |
| |
| /************************************************************************ |
| * AwtToolkit fields |
| */ |
| |
| AwtToolkit AwtToolkit::theInstance; |
| |
| /* ids for WToolkit fields accessed from native code */ |
| jmethodID AwtToolkit::windowsSettingChangeMID; |
| jmethodID AwtToolkit::displayChangeMID; |
| /* ids for Toolkit methods */ |
| jmethodID AwtToolkit::getDefaultToolkitMID; |
| jmethodID AwtToolkit::getFontMetricsMID; |
| jmethodID AwtToolkit::insetsMID; |
| |
| /************************************************************************ |
| * AwtToolkit methods |
| */ |
| |
| AwtToolkit::AwtToolkit() { |
| m_localPump = FALSE; |
| m_mainThreadId = 0; |
| m_toolkitHWnd = NULL; |
| m_inputMethodHWnd = NULL; |
| m_verbose = FALSE; |
| m_isActive = TRUE; |
| m_isDisposed = FALSE; |
| |
| m_vmSignalled = FALSE; |
| |
| m_isDynamicLayoutSet = FALSE; |
| m_areExtraMouseButtonsEnabled = TRUE; |
| |
| m_verifyComponents = FALSE; |
| m_breakOnError = FALSE; |
| |
| m_breakMessageLoop = FALSE; |
| m_messageLoopResult = 0; |
| |
| m_lastMouseOver = NULL; |
| m_mouseDown = FALSE; |
| |
| m_hGetMessageHook = 0; |
| m_hMouseLLHook = 0; |
| m_lastWindowUnderMouse = NULL; |
| m_timer = 0; |
| |
| m_cmdIDs = new AwtCmdIDList(); |
| m_pModalDialog = NULL; |
| m_peer = NULL; |
| m_dllHandle = NULL; |
| |
| m_displayChanged = FALSE; |
| m_embedderProcessID = 0; |
| |
| // XXX: keyboard mapping should really be moved out of AwtComponent |
| AwtComponent::InitDynamicKeyMapTable(); |
| |
| // initialize kb state array |
| ::GetKeyboardState(m_lastKeyboardState); |
| |
| m_waitEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL); |
| eventNumber = 0; |
| } |
| |
| AwtToolkit::~AwtToolkit() { |
| /* |
| * The code has been moved to AwtToolkit::Dispose() method. |
| */ |
| } |
| |
| HWND AwtToolkit::CreateToolkitWnd(LPCTSTR name) |
| { |
| HWND hwnd = CreateWindow( |
| szAwtToolkitClassName, |
| (LPCTSTR)name, /* window name */ |
| WS_DISABLED, /* window style */ |
| -1, -1, /* position of window */ |
| 0, 0, /* width and height */ |
| NULL, NULL, /* hWndParent and hWndMenu */ |
| GetModuleHandle(), |
| NULL); /* lpParam */ |
| DASSERT(hwnd != NULL); |
| return hwnd; |
| } |
| |
| |
| struct ToolkitThreadProc_Data { |
| bool result; |
| HANDLE hCompleted; |
| |
| jobject thread; |
| jobject threadGroup; |
| }; |
| |
| void ToolkitThreadProc(void *param) |
| { |
| ToolkitThreadProc_Data *data = (ToolkitThreadProc_Data *)param; |
| |
| bool bNotified = false; |
| |
| JNIEnv *env; |
| JavaVMAttachArgs attachArgs; |
| attachArgs.version = JNI_VERSION_1_2; |
| attachArgs.name = "AWT-Windows"; |
| attachArgs.group = data->threadGroup; |
| |
| jint res = jvm->AttachCurrentThreadAsDaemon((void **)&env, &attachArgs); |
| if (res < 0) { |
| return; |
| } |
| |
| jobject thread = env->NewGlobalRef(data->thread); |
| if (thread != NULL) { |
| jclass cls = env->GetObjectClass(thread); |
| if (cls != NULL) { |
| jmethodID runId = env->GetMethodID(cls, "run", "()V"); |
| if (runId != NULL) { |
| data->result = true; |
| ::SetEvent(data->hCompleted); |
| bNotified = true; |
| |
| env->CallVoidMethod(thread, runId); |
| |
| if (env->ExceptionCheck()) { |
| env->ExceptionDescribe(); |
| env->ExceptionClear(); |
| // TODO: handle |
| } |
| } |
| env->DeleteLocalRef(cls); |
| } |
| env->DeleteGlobalRef(thread); |
| } |
| if (!bNotified) { |
| ::SetEvent(data->hCompleted); |
| } |
| |
| jvm->DetachCurrentThread(); |
| } |
| |
| /* |
| * Class: sun_awt_windows_WToolkit |
| * Method: startToolkitThread |
| * Signature: (Ljava/lang/Runnable;Ljava/lang/ThreadGroup)Z |
| */ |
| JNIEXPORT jboolean JNICALL |
| Java_sun_awt_windows_WToolkit_startToolkitThread(JNIEnv *env, jclass cls, jobject thread, jobject threadGroup) |
| { |
| AwtToolkit& tk = AwtToolkit::GetInstance(); |
| |
| ToolkitThreadProc_Data data; |
| data.result = false; |
| data.thread = env->NewGlobalRef(thread); |
| data.threadGroup = env->NewGlobalRef(threadGroup); |
| if (data.thread == NULL || data.threadGroup == NULL) { |
| return JNI_FALSE; |
| } |
| data.hCompleted = ::CreateEvent(NULL, FALSE, FALSE, NULL); |
| |
| bool result = tk.GetPreloadThread() |
| .InvokeAndTerminate(ToolkitThreadProc, &data); |
| |
| if (result) { |
| ::WaitForSingleObject(data.hCompleted, INFINITE); |
| result = data.result; |
| } else { |
| // no awt preloading |
| // return back to the usual toolkit way |
| } |
| ::CloseHandle(data.hCompleted); |
| |
| env->DeleteGlobalRef(data.thread); |
| env->DeleteGlobalRef(data.threadGroup); |
| |
| return result ? JNI_TRUE : JNI_FALSE; |
| } |
| |
| BOOL AwtToolkit::Initialize(BOOL localPump) { |
| AwtToolkit& tk = AwtToolkit::GetInstance(); |
| |
| if (!tk.m_isActive || tk.m_mainThreadId != 0) { |
| /* Already initialized. */ |
| return FALSE; |
| } |
| |
| // This call is moved here from AwtToolkit constructor. Having it |
| // there led to the bug 6480630: there could be a situation when |
| // ComCtl32Util was constructed but not disposed |
| ComCtl32Util::GetInstance().InitLibraries(); |
| |
| if (!localPump) { |
| // if preload thread was run, terminate it |
| preloadThread.Terminate(true); |
| } |
| |
| /* Register this toolkit's helper window */ |
| VERIFY(tk.RegisterClass() != NULL); |
| |
| // Set up operator new/malloc out of memory handler. |
| NewHandler::init(); |
| |
| //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ |
| // Bugs 4032109, 4047966, and 4071991 to fix AWT |
| // crash in 16 color display mode. 16 color mode is supported. Less |
| // than 16 color is not. |
| // creighto@eng.sun.com 1997-10-07 |
| // |
| // Check for at least 16 colors |
| HDC hDC = ::GetDC(NULL); |
| if ((::GetDeviceCaps(hDC, BITSPIXEL) * ::GetDeviceCaps(hDC, PLANES)) < 4) { |
| ::MessageBox(NULL, |
| TEXT("Sorry, but this release of Java requires at least 16 colors"), |
| TEXT("AWT Initialization Error"), |
| MB_ICONHAND | MB_APPLMODAL); |
| ::DeleteDC(hDC); |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| JNU_ThrowByName(env, "java/lang/InternalError", |
| "unsupported screen depth"); |
| return FALSE; |
| } |
| ::ReleaseDC(NULL, hDC); |
| /////////////////////////////////////////////////////////////////////////// |
| |
| tk.m_localPump = localPump; |
| tk.m_mainThreadId = ::GetCurrentThreadId(); |
| |
| /* |
| * Create the one-and-only toolkit window. This window isn't |
| * displayed, but is used to route messages to this thread. |
| */ |
| tk.m_toolkitHWnd = tk.CreateToolkitWnd(TEXT("theAwtToolkitWindow")); |
| DASSERT(tk.m_toolkitHWnd != NULL); |
| |
| /* |
| * Setup a GetMessage filter to watch all messages coming out of our |
| * queue from PreProcessMsg(). |
| */ |
| tk.m_hGetMessageHook = ::SetWindowsHookEx(WH_GETMESSAGE, |
| (HOOKPROC)GetMessageFilter, |
| 0, tk.m_mainThreadId); |
| |
| awt_dnd_initialize(); |
| |
| return TRUE; |
| } |
| |
| BOOL AwtToolkit::Dispose() { |
| DTRACE_PRINTLN("In AwtToolkit::Dispose()"); |
| |
| AwtToolkit& tk = AwtToolkit::GetInstance(); |
| |
| if (!tk.m_isActive || tk.m_mainThreadId != ::GetCurrentThreadId()) { |
| return FALSE; |
| } |
| |
| tk.m_isActive = FALSE; |
| |
| // dispose Direct3D-related resources. This should be done |
| // before AwtObjectList::Cleanup() as the d3d will attempt to |
| // shutdown when the last of its windows is disposed of |
| D3DInitializer::GetInstance().Clean(); |
| |
| AwtObjectList::Cleanup(); |
| |
| awt_dnd_uninitialize(); |
| awt_clipboard_uninitialize((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2)); |
| |
| if (tk.m_inputMethodHWnd != NULL) { |
| ::SendMessage(tk.m_inputMethodHWnd, WM_IME_CONTROL, IMC_OPENSTATUSWINDOW, 0); |
| } |
| tk.m_inputMethodHWnd = NULL; |
| |
| // wait for any messages to be processed, in particular, |
| // all WM_AWT_DELETEOBJECT messages that delete components; no |
| // new messages will appear as all the windows except toolkit |
| // window are unsubclassed and destroyed |
| MSG msg; |
| while (::GetMessage(&msg, NULL, 0, 0)) { |
| ::TranslateMessage(&msg); |
| ::DispatchMessage(&msg); |
| } |
| |
| AwtFont::Cleanup(); |
| |
| HWND toolkitHWndToDestroy = tk.m_toolkitHWnd; |
| tk.m_toolkitHWnd = 0; |
| VERIFY(::DestroyWindow(toolkitHWndToDestroy) != NULL); |
| |
| tk.UnregisterClass(); |
| |
| ::UnhookWindowsHookEx(tk.m_hGetMessageHook); |
| UninstallMouseLowLevelHook(); |
| |
| tk.m_mainThreadId = 0; |
| |
| delete tk.m_cmdIDs; |
| |
| ::CloseHandle(m_waitEvent); |
| |
| tk.m_isDisposed = TRUE; |
| |
| return TRUE; |
| } |
| |
| void AwtToolkit::SetDynamicLayout(BOOL dynamic) { |
| m_isDynamicLayoutSet = dynamic; |
| } |
| |
| BOOL AwtToolkit::IsDynamicLayoutSet() { |
| return m_isDynamicLayoutSet; |
| } |
| |
| BOOL AwtToolkit::IsDynamicLayoutSupported() { |
| // SPI_GETDRAGFULLWINDOWS is only supported on Win95 if |
| // Windows Plus! is installed. Otherwise, box frame resize. |
| BOOL fullWindowDragEnabled = FALSE; |
| int result = 0; |
| result = ::SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, |
| &fullWindowDragEnabled, 0); |
| |
| return (fullWindowDragEnabled && (result != 0)); |
| } |
| |
| BOOL AwtToolkit::IsDynamicLayoutActive() { |
| return (IsDynamicLayoutSet() && IsDynamicLayoutSupported()); |
| } |
| |
| ATOM AwtToolkit::RegisterClass() { |
| WNDCLASS wc; |
| |
| wc.style = 0; |
| wc.lpfnWndProc = (WNDPROC)WndProc; |
| wc.cbClsExtra = 0; |
| wc.cbWndExtra = 0; |
| wc.hInstance = AwtToolkit::GetInstance().GetModuleHandle(), |
| wc.hIcon = AwtToolkit::GetInstance().GetAwtIcon(); |
| wc.hCursor = NULL; |
| wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); |
| wc.lpszMenuName = NULL; |
| wc.lpszClassName = szAwtToolkitClassName; |
| |
| ATOM ret = ::RegisterClass(&wc); |
| DASSERT(ret != NULL); |
| return ret; |
| } |
| |
| void AwtToolkit::UnregisterClass() { |
| VERIFY(::UnregisterClass(szAwtToolkitClassName, AwtToolkit::GetInstance().GetModuleHandle())); |
| } |
| |
| /* |
| * Structure holding the information to create a component. This packet is |
| * sent to the toolkit window. |
| */ |
| struct ComponentCreatePacket { |
| void* hComponent; |
| void* hParent; |
| void (*factory)(void*, void*); |
| }; |
| |
| /* |
| * Create an AwtXxxx component using a given factory function |
| * Implemented by sending a message to the toolkit window to invoke the |
| * factory function from that thread |
| */ |
| void AwtToolkit::CreateComponent(void* component, void* parent, |
| ComponentFactory compFactory, BOOL isParentALocalReference) |
| { |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| |
| /* Since Local references are not valid in another Thread, we need to |
| create a global reference before we send this to the Toolkit thread. |
| In some cases this method is called with parent being a native |
| malloced struct so we cannot and do not need to create a Global |
| Reference from it. This is indicated by isParentALocalReference */ |
| |
| jobject gcomponent = env->NewGlobalRef((jobject)component); |
| jobject gparent; |
| if (isParentALocalReference) gparent = env->NewGlobalRef((jobject)parent); |
| ComponentCreatePacket ccp = { gcomponent, |
| isParentALocalReference == TRUE ? gparent : parent, |
| compFactory }; |
| AwtToolkit::GetInstance().SendMessage(WM_AWT_COMPONENT_CREATE, 0, |
| (LPARAM)&ccp); |
| env->DeleteGlobalRef(gcomponent); |
| if (isParentALocalReference) env->DeleteGlobalRef(gparent); |
| } |
| |
| /* |
| * Destroy an HWND that was created in the toolkit thread. Can be used on |
| * Components and the toolkit window itself. |
| */ |
| void AwtToolkit::DestroyComponentHWND(HWND hwnd) |
| { |
| if (!::IsWindow(hwnd)) { |
| return; |
| } |
| |
| AwtToolkit& tk = AwtToolkit::GetInstance(); |
| if ((tk.m_lastMouseOver != NULL) && |
| (tk.m_lastMouseOver->GetHWnd() == hwnd)) |
| { |
| tk.m_lastMouseOver = NULL; |
| } |
| |
| ::SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)NULL); |
| tk.SendMessage(WM_AWT_DESTROY_WINDOW, (WPARAM)hwnd, 0); |
| } |
| |
| #ifndef SPY_MESSAGES |
| #define SpyWinMessage(hwin,msg,str) |
| #else |
| void SpyWinMessage(HWND hwnd, UINT message, LPCTSTR szComment); |
| #endif |
| |
| /* |
| * An AwtToolkit window is just a means of routing toolkit messages to here. |
| */ |
| LRESULT CALLBACK AwtToolkit::WndProc(HWND hWnd, UINT message, |
| WPARAM wParam, LPARAM lParam) |
| { |
| TRY; |
| |
| JNIEnv *env = GetEnv(); |
| JNILocalFrame lframe(env, 10); |
| |
| SpyWinMessage(hWnd, message, TEXT("AwtToolkit")); |
| |
| AwtToolkit::GetInstance().eventNumber++; |
| /* |
| * Awt widget creation messages are routed here so that all |
| * widgets are created on the main thread. Java allows widgets |
| * to live beyond their creating thread -- by creating them on |
| * the main thread, a widget can always be properly disposed. |
| */ |
| switch (message) { |
| case WM_AWT_EXECUTE_SYNC: { |
| jobject peerObject = (jobject)wParam; |
| AwtObject* object = (AwtObject *)JNI_GET_PDATA(peerObject); |
| DASSERT( !IsBadReadPtr(object, sizeof(AwtObject))); |
| AwtObject::ExecuteArgs *args = (AwtObject::ExecuteArgs *)lParam; |
| DASSERT(!IsBadReadPtr(args, sizeof(AwtObject::ExecuteArgs))); |
| LRESULT result = 0; |
| if (object != NULL) |
| { |
| result = object->WinThreadExecProc(args); |
| } |
| env->DeleteGlobalRef(peerObject); |
| return result; |
| } |
| case WM_AWT_COMPONENT_CREATE: { |
| ComponentCreatePacket* ccp = (ComponentCreatePacket*)lParam; |
| DASSERT(ccp->factory != NULL); |
| DASSERT(ccp->hComponent != NULL); |
| (*ccp->factory)(ccp->hComponent, ccp->hParent); |
| return 0; |
| } |
| case WM_AWT_DESTROY_WINDOW: { |
| /* Destroy widgets from this same thread that created them */ |
| VERIFY(::DestroyWindow((HWND)wParam) != NULL); |
| return 0; |
| } |
| case WM_AWT_DISPOSE: { |
| if(wParam != NULL) { |
| jobject self = (jobject)wParam; |
| AwtObject *o = (AwtObject *) JNI_GET_PDATA(self); |
| env->DeleteGlobalRef(self); |
| if(o != NULL && theAwtObjectList.Remove(o)) { |
| o->Dispose(); |
| } |
| } |
| return 0; |
| } |
| case WM_AWT_DISPOSEPDATA: { |
| /* |
| * NOTE: synchronization routine (like in WM_AWT_DISPOSE) was omitted because |
| * this handler is called ONLY while disposing Cursor and Font objects where |
| * synchronization takes place. |
| */ |
| AwtObject *o = (AwtObject *) wParam; |
| if(o != NULL && theAwtObjectList.Remove(o)) { |
| o->Dispose(); |
| } |
| return 0; |
| } |
| case WM_AWT_DELETEOBJECT: { |
| AwtObject *p = (AwtObject *) wParam; |
| if (p->CanBeDeleted()) { |
| // all the messages for this component are processed, so |
| // it can be deleted |
| delete p; |
| } else { |
| // postpone deletion, waiting for all the messages for this |
| // component to be processed |
| AwtToolkit::GetInstance().PostMessage(WM_AWT_DELETEOBJECT, wParam, (LPARAM)0); |
| } |
| return 0; |
| } |
| case WM_AWT_OBJECTLISTCLEANUP: { |
| AwtObjectList::Cleanup(); |
| return 0; |
| } |
| case WM_SYSCOLORCHANGE: { |
| |
| jclass systemColorClass = env->FindClass("java/awt/SystemColor"); |
| DASSERT(systemColorClass); |
| if (!systemColorClass) throw std::bad_alloc(); |
| |
| jmethodID mid = env->GetStaticMethodID(systemColorClass, "updateSystemColors", "()V"); |
| DASSERT(mid); |
| if (!mid) throw std::bad_alloc(); |
| |
| env->CallStaticVoidMethod(systemColorClass, mid); |
| |
| /* FALL THROUGH - NO BREAK */ |
| } |
| |
| case WM_SETTINGCHANGE: { |
| AwtWin32GraphicsDevice::ResetAllMonitorInfo(); |
| /* FALL THROUGH - NO BREAK */ |
| } |
| // Remove this define when we move to newer (XP) version of SDK. |
| #define WM_THEMECHANGED 0x031A |
| case WM_THEMECHANGED: { |
| /* Upcall to WToolkit when user changes configuration. |
| * |
| * NOTE: there is a bug in Windows 98 and some older versions of |
| * Windows NT (it seems to be fixed in NT4 SP5) where no |
| * WM_SETTINGCHANGE is sent when any of the properties under |
| * Control Panel -> Display are changed. You must _always_ query |
| * the system for these - you can't rely on cached values. |
| */ |
| jobject peer = AwtToolkit::GetInstance().m_peer; |
| if (peer != NULL) { |
| env->CallVoidMethod(peer, AwtToolkit::windowsSettingChangeMID); |
| } |
| return 0; |
| } |
| #ifndef WM_DWMCOMPOSITIONCHANGED |
| #define WM_DWMCOMPOSITIONCHANGED 0x031E |
| #define WM_DWMNCRENDERINGCHANGED 0x031F |
| #define WM_DWMCOLORIZATIONCOLORCHANGED 0x0320 |
| #define WM_DWMWINDOWMAXIMIZEDCHANGED 0x0321 |
| #endif // WM_DWMCOMPOSITIONCHANGED |
| case WM_DWMCOMPOSITIONCHANGED: { |
| DWMResetCompositionEnabled(); |
| return 0; |
| } |
| |
| case WM_TIMER: { |
| // 6479820. Should check if a window is in manual resizing process: skip |
| // sending any MouseExit/Enter events while inside resize-loop. |
| // Note that window being in manual moving process could still |
| // produce redundant enter/exit mouse events. In future, they can be |
| // made skipped in a similar way. |
| if (AwtWindow::IsResizing()) { |
| return 0; |
| } |
| // Create an artifical MouseExit message if the mouse left to |
| // a non-java window (bad mouse!) |
| POINT pt; |
| AwtToolkit& tk = AwtToolkit::GetInstance(); |
| if (::GetCursorPos(&pt)) { |
| HWND hWndOver = ::WindowFromPoint(pt); |
| AwtComponent * last_M; |
| if ( AwtComponent::GetComponent(hWndOver) == NULL && tk.m_lastMouseOver != NULL ) { |
| last_M = tk.m_lastMouseOver; |
| // translate point from screen to target window |
| MapWindowPoints(HWND_DESKTOP, last_M->GetHWnd(), &pt, 1); |
| last_M->SendMessage(WM_AWT_MOUSEEXIT, |
| GetMouseKeyState(), |
| POINTTOPOINTS(pt)); |
| tk.m_lastMouseOver = 0; |
| } |
| } |
| if (tk.m_lastMouseOver == NULL && tk.m_timer != 0) { |
| VERIFY(::KillTimer(tk.m_toolkitHWnd, tk.m_timer)); |
| tk.m_timer = 0; |
| } |
| return 0; |
| } |
| case WM_DESTROYCLIPBOARD: { |
| if (!AwtClipboard::IsGettingOwnership()) |
| AwtClipboard::LostOwnership((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2)); |
| return 0; |
| } |
| case WM_CHANGECBCHAIN: { |
| AwtClipboard::WmChangeCbChain(wParam, lParam); |
| return 0; |
| } |
| case WM_DRAWCLIPBOARD: { |
| AwtClipboard::WmDrawClipboard((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), wParam, lParam); |
| return 0; |
| } |
| case WM_AWT_LIST_SETMULTISELECT: { |
| jobject peerObject = (jobject)wParam; |
| AwtList* list = (AwtList *)JNI_GET_PDATA(peerObject); |
| DASSERT( !IsBadReadPtr(list, sizeof(AwtObject))); |
| list->SetMultiSelect(static_cast<BOOL>(lParam)); |
| return 0; |
| } |
| |
| // Special awt message to call Imm APIs. |
| // ImmXXXX() API must be used in the main thread. |
| // In other thread these APIs does not work correctly even if |
| // it returs with no error. (This restriction is not documented) |
| // So we must use thse messages to call these APIs in main thread. |
| case WM_AWT_CREATECONTEXT: { |
| return reinterpret_cast<LRESULT>( |
| reinterpret_cast<void*>(ImmCreateContext())); |
| } |
| case WM_AWT_DESTROYCONTEXT: { |
| ImmDestroyContext((HIMC)wParam); |
| return 0; |
| } |
| case WM_AWT_ASSOCIATECONTEXT: { |
| EnableNativeIMEStruct *data = (EnableNativeIMEStruct*)wParam; |
| |
| jobject peer = data->peer; |
| jobject self = data->self; |
| jint context = data->context; |
| jboolean useNativeCompWindow = data->useNativeCompWindow; |
| |
| AwtComponent* comp = (AwtComponent*)JNI_GET_PDATA(peer); |
| if (comp != NULL) |
| { |
| comp->SetInputMethod(self, useNativeCompWindow); |
| comp->ImmAssociateContext((HIMC)context); |
| } |
| |
| if (peer != NULL) { |
| env->DeleteGlobalRef(peer); |
| } |
| if (self != NULL) { |
| env->DeleteGlobalRef(self); |
| } |
| |
| delete data; |
| return 0; |
| } |
| case WM_AWT_GET_DEFAULT_IME_HANDLER: { |
| LRESULT ret = (LRESULT)FALSE; |
| jobject peer = (jobject)wParam; |
| |
| AwtComponent* comp = (AwtComponent*)JNI_GET_PDATA(peer); |
| if (comp != NULL) { |
| HWND defaultIMEHandler = ImmGetDefaultIMEWnd(comp->GetHWnd()); |
| if (defaultIMEHandler != NULL) { |
| AwtToolkit::GetInstance().SetInputMethodWindow(defaultIMEHandler); |
| ret = (LRESULT)TRUE; |
| } |
| } |
| |
| if (peer != NULL) { |
| env->DeleteGlobalRef(peer); |
| } |
| return ret; |
| } |
| case WM_AWT_HANDLE_NATIVE_IME_EVENT: { |
| jobject peer = (jobject)wParam; |
| AwtComponent* comp = (AwtComponent*)JNI_GET_PDATA(peer); |
| MSG* msg = (MSG*)lParam; |
| |
| long modifiers = comp->GetJavaModifiers(); |
| if ((comp != NULL) && (msg->message==WM_CHAR || msg->message==WM_SYSCHAR)) { |
| WCHAR unicodeChar = (WCHAR)msg->wParam; |
| comp->SendKeyEvent(java_awt_event_KeyEvent_KEY_TYPED, |
| 0, //to be fixed nowMillis(), |
| java_awt_event_KeyEvent_CHAR_UNDEFINED, |
| unicodeChar, |
| modifiers, |
| java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN, (jlong)0, |
| msg); |
| } else if (comp != NULL) { |
| MSG* pCopiedMsg = new MSG; |
| *pCopiedMsg = *msg; |
| comp->SendMessage(WM_AWT_HANDLE_EVENT, (WPARAM) FALSE, |
| (LPARAM) pCopiedMsg); |
| } |
| |
| if (peer != NULL) { |
| env->DeleteGlobalRef(peer); |
| } |
| return 0; |
| } |
| case WM_AWT_ENDCOMPOSITION: { |
| /*right now we just cancel the composition string |
| may need to commit it in the furture |
| Changed to commit it according to the flag 10/29/98*/ |
| ImmNotifyIME((HIMC)wParam, NI_COMPOSITIONSTR, |
| (lParam ? CPS_COMPLETE : CPS_CANCEL), 0); |
| return 0; |
| } |
| case WM_AWT_SETCONVERSIONSTATUS: { |
| DWORD cmode; |
| DWORD smode; |
| ImmGetConversionStatus((HIMC)wParam, (LPDWORD)&cmode, (LPDWORD)&smode); |
| ImmSetConversionStatus((HIMC)wParam, (DWORD)LOWORD(lParam), smode); |
| return 0; |
| } |
| case WM_AWT_GETCONVERSIONSTATUS: { |
| DWORD cmode; |
| DWORD smode; |
| ImmGetConversionStatus((HIMC)wParam, (LPDWORD)&cmode, (LPDWORD)&smode); |
| return cmode; |
| } |
| case WM_AWT_ACTIVATEKEYBOARDLAYOUT: { |
| if (wParam && g_bUserHasChangedInputLang) { |
| // Input language has been changed since the last WInputMethod.getNativeLocale() |
| // call. So let's honor the user's selection. |
| // Note: we need to check this flag inside the toolkit thread to synchronize access |
| // to the flag. |
| return FALSE; |
| } |
| |
| if (lParam == (LPARAM)::GetKeyboardLayout(0)) { |
| // already active |
| return FALSE; |
| } |
| |
| // Since ActivateKeyboardLayout does not post WM_INPUTLANGCHANGEREQUEST, |
| // we explicitly need to do the same thing here. |
| static BYTE keyboardState[AwtToolkit::KB_STATE_SIZE]; |
| AwtToolkit::GetKeyboardState(keyboardState); |
| WORD ignored; |
| ::ToAscii(VK_SPACE, ::MapVirtualKey(VK_SPACE, 0), |
| keyboardState, &ignored, 0); |
| |
| return (LRESULT)activateKeyboardLayout((HKL)lParam); |
| } |
| case WM_AWT_OPENCANDIDATEWINDOW: { |
| jobject peerObject = (jobject)wParam; |
| AwtComponent* p = (AwtComponent*)JNI_GET_PDATA(peerObject); |
| DASSERT( !IsBadReadPtr(p, sizeof(AwtObject))); |
| // fix for 4805862: use GET_X_LPARAM and GET_Y_LPARAM macros |
| // instead of LOWORD and HIWORD |
| p->OpenCandidateWindow(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); |
| env->DeleteGlobalRef(peerObject); |
| return 0; |
| } |
| |
| /* |
| * send this message via ::SendMessage() and the MPT will acquire the |
| * HANDLE synchronized with the sender's thread. The HANDLE must be |
| * signalled or deadlock may occur between the MPT and the caller. |
| */ |
| |
| case WM_AWT_WAIT_FOR_SINGLE_OBJECT: { |
| return ::WaitForSingleObject((HANDLE)lParam, INFINITE); |
| } |
| case WM_AWT_INVOKE_METHOD: { |
| return (LRESULT)(*(void*(*)(void*))wParam)((void *)lParam); |
| } |
| case WM_AWT_INVOKE_VOID_METHOD: { |
| return (LRESULT)(*(void*(*)(void))wParam)(); |
| } |
| |
| case WM_AWT_SETOPENSTATUS: { |
| ImmSetOpenStatus((HIMC)wParam, (BOOL)lParam); |
| return 0; |
| } |
| case WM_AWT_GETOPENSTATUS: { |
| return (DWORD)ImmGetOpenStatus((HIMC)wParam); |
| } |
| case WM_DISPLAYCHANGE: { |
| // Reinitialize screens |
| initScreens(env); |
| |
| // Notify Java side - call WToolkit.displayChanged() |
| jclass clazz = env->FindClass("sun/awt/windows/WToolkit"); |
| DASSERT(clazz != NULL); |
| if (!clazz) throw std::bad_alloc(); |
| env->CallStaticVoidMethod(clazz, AwtToolkit::displayChangeMID); |
| |
| GetInstance().m_displayChanged = TRUE; |
| |
| ::PostMessage(HWND_BROADCAST, WM_PALETTEISCHANGING, NULL, NULL); |
| break; |
| } |
| case WM_AWT_SETCURSOR: { |
| ::SetCursor((HCURSOR)wParam); |
| return TRUE; |
| } |
| /* Session management */ |
| case WM_QUERYENDSESSION: { |
| /* Shut down cleanly */ |
| if (JVM_RaiseSignal(SIGTERM)) { |
| AwtToolkit::GetInstance().m_vmSignalled = TRUE; |
| } |
| return TRUE; |
| } |
| case WM_ENDSESSION: { |
| // Keep pumping messages until the shutdown sequence halts the VM, |
| // or we exit the MessageLoop because of a WM_QUIT message |
| AwtToolkit& tk = AwtToolkit::GetInstance(); |
| |
| // if WM_QUERYENDSESSION hasn't successfully raised SIGTERM |
| // we ignore the ENDSESSION message |
| if (!tk.m_vmSignalled) { |
| return 0; |
| } |
| tk.MessageLoop(AwtToolkit::PrimaryIdleFunc, |
| AwtToolkit::CommonPeekMessageFunc); |
| |
| // Dispose here instead of in eventLoop so that we don't have |
| // to return from the WM_ENDSESSION handler. |
| tk.Dispose(); |
| |
| // Never return. The VM will halt the process. |
| hang_if_shutdown(); |
| |
| // Should never get here. |
| DASSERT(FALSE); |
| break; |
| } |
| case WM_SYNC_WAIT: |
| SetEvent(AwtToolkit::GetInstance().m_waitEvent); |
| break; |
| } |
| |
| return DefWindowProc(hWnd, message, wParam, lParam); |
| |
| CATCH_BAD_ALLOC_RET(0); |
| } |
| |
| LRESULT CALLBACK AwtToolkit::GetMessageFilter(int code, |
| WPARAM wParam, LPARAM lParam) |
| { |
| TRY; |
| |
| if (code >= 0 && wParam == PM_REMOVE && lParam != 0) { |
| if (AwtToolkit::GetInstance().PreProcessMsg(*(MSG*)lParam) != |
| mrPassAlong) { |
| /* PreProcessMsg() wants us to eat it */ |
| ((MSG*)lParam)->message = WM_NULL; |
| } |
| } |
| return ::CallNextHookEx(AwtToolkit::GetInstance().m_hGetMessageHook, code, |
| wParam, lParam); |
| |
| CATCH_BAD_ALLOC_RET(0); |
| } |
| |
| void AwtToolkit::InstallMouseLowLevelHook() |
| { |
| // We need the low-level hook since we need to process mouse move |
| // messages outside of our windows. |
| m_hMouseLLHook = ::SetWindowsHookEx(WH_MOUSE_LL, |
| (HOOKPROC)MouseLowLevelHook, |
| GetModuleHandle(), NULL); |
| |
| // Reset the old value |
| m_lastWindowUnderMouse = NULL; |
| } |
| |
| void AwtToolkit::UninstallMouseLowLevelHook() |
| { |
| if (m_hMouseLLHook != 0) { |
| ::UnhookWindowsHookEx(m_hMouseLLHook); |
| m_hMouseLLHook = 0; |
| } |
| } |
| |
| LRESULT CALLBACK AwtToolkit::MouseLowLevelHook(int code, |
| WPARAM wParam, LPARAM lParam) |
| { |
| TRY; |
| |
| if (code >= 0 && wParam == WM_MOUSEMOVE) { |
| POINT pt = ((MSLLHOOKSTRUCT*)lParam)->pt; |
| |
| // We can't use GA_ROOTOWNER since in this case we'll go up to |
| // the root Java toplevel, not the actual owned toplevel. |
| HWND hwnd = ::GetAncestor(::WindowFromPoint(pt), GA_ROOT); |
| |
| AwtToolkit& tk = AwtToolkit::GetInstance(); |
| |
| if (tk.m_lastWindowUnderMouse != hwnd) { |
| AwtWindow *fw = NULL, *tw = NULL; |
| |
| if (tk.m_lastWindowUnderMouse) { |
| fw = (AwtWindow*) |
| AwtComponent::GetComponent(tk.m_lastWindowUnderMouse); |
| } |
| if (hwnd) { |
| tw = (AwtWindow*)AwtComponent::GetComponent(hwnd); |
| } |
| |
| tk.m_lastWindowUnderMouse = hwnd; |
| |
| if (fw) { |
| fw->UpdateSecurityWarningVisibility(); |
| } |
| // ... however, because we use GA_ROOT, we may find the warningIcon |
| // which is not a Java windows. |
| if (AwtWindow::IsWarningWindow(hwnd)) { |
| hwnd = ::GetParent(hwnd); |
| if (hwnd) { |
| tw = (AwtWindow*)AwtComponent::GetComponent(hwnd); |
| } |
| tk.m_lastWindowUnderMouse = hwnd; |
| } |
| if (tw) { |
| tw->UpdateSecurityWarningVisibility(); |
| } |
| |
| |
| } |
| } |
| |
| return ::CallNextHookEx(AwtToolkit::GetInstance().m_hMouseLLHook, code, |
| wParam, lParam); |
| |
| CATCH_BAD_ALLOC_RET(0); |
| } |
| |
| /* |
| * The main message loop |
| */ |
| |
| const int AwtToolkit::EXIT_ENCLOSING_LOOP = 0; |
| const int AwtToolkit::EXIT_ALL_ENCLOSING_LOOPS = -1; |
| |
| |
| /** |
| * Called upon event idle to ensure that we have released any |
| * CriticalSections that we took during window event processing. |
| * |
| * Note that this gets used more often than you would think; some |
| * window moves actually happen over more than one event burst. So, |
| * for example, we might get a WINDOWPOSCHANGING event, then we |
| * idle and release the lock here, then eventually we get the |
| * WINDOWPOSCHANGED event. |
| * |
| * This method may be called from WToolkit.embeddedEventLoopIdleProcessing |
| * if there is a separate event loop that must do the same CriticalSection |
| * check. |
| * |
| * See bug #4526587 for more information. |
| */ |
| void VerifyWindowMoveLockReleased() |
| { |
| if (windowMoveLockHeld) { |
| windowMoveLockHeld = FALSE; |
| windowMoveLock.Leave(); |
| } |
| } |
| |
| UINT |
| AwtToolkit::MessageLoop(IDLEPROC lpIdleFunc, |
| PEEKMESSAGEPROC lpPeekMessageFunc) |
| { |
| DTRACE_PRINTLN("AWT event loop started"); |
| |
| DASSERT(lpIdleFunc != NULL); |
| DASSERT(lpPeekMessageFunc != NULL); |
| |
| m_messageLoopResult = 0; |
| while (!m_breakMessageLoop) { |
| |
| (*lpIdleFunc)(); |
| |
| PumpWaitingMessages(lpPeekMessageFunc); /* pumps waiting messages */ |
| |
| // Catch problems with windowMoveLock critical section. In case we |
| // misunderstood the way windows processes window move/resize |
| // events, we don't want to hold onto the windowMoveLock CS forever. |
| // If we've finished processing events for now, release the lock |
| // if held. |
| VerifyWindowMoveLockReleased(); |
| } |
| if (m_messageLoopResult == EXIT_ALL_ENCLOSING_LOOPS) |
| ::PostQuitMessage(EXIT_ALL_ENCLOSING_LOOPS); |
| m_breakMessageLoop = FALSE; |
| |
| DTRACE_PRINTLN("AWT event loop ended"); |
| |
| return m_messageLoopResult; |
| } |
| |
| /* |
| * Exit the enclosing message loop(s). |
| * |
| * The message will be ignored if Windows is currently is in an internal |
| * message loop (such as a scroll bar drag). So we first send IDCANCEL and |
| * WM_CANCELMODE messages to every Window on the thread. |
| */ |
| static BOOL CALLBACK CancelAllThreadWindows(HWND hWnd, LPARAM) |
| { |
| TRY; |
| |
| ::SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(IDCANCEL, 0), (LPARAM)hWnd); |
| ::SendMessage(hWnd, WM_CANCELMODE, 0, 0); |
| |
| return TRUE; |
| |
| CATCH_BAD_ALLOC_RET(FALSE); |
| } |
| |
| static void DoQuitMessageLoop(void* param) { |
| int status = *static_cast<int*>(param); |
| |
| AwtToolkit::GetInstance().QuitMessageLoop(status); |
| } |
| |
| void AwtToolkit::QuitMessageLoop(int status) { |
| /* |
| * Fix for 4623377. |
| * Reinvoke QuitMessageLoop on the toolkit thread, so that |
| * m_breakMessageLoop is accessed on a single thread. |
| */ |
| if (!AwtToolkit::IsMainThread()) { |
| InvokeFunction(DoQuitMessageLoop, &status); |
| return; |
| } |
| |
| /* |
| * Fix for BugTraq ID 4445747. |
| * EnumThreadWindows() is very slow during dnd on Win9X/ME. |
| * This call is unnecessary during dnd, since we postpone processing of all |
| * messages that can enter internal message loop until dnd is over. |
| */ |
| if (status == EXIT_ALL_ENCLOSING_LOOPS) { |
| ::EnumThreadWindows(MainThread(), (WNDENUMPROC)CancelAllThreadWindows, |
| 0); |
| } |
| |
| /* |
| * Fix for 4623377. |
| * Modal loop may not exit immediatelly after WM_CANCELMODE, so it still can |
| * eat WM_QUIT message and the nested message loop will never exit. |
| * The fix is to use AwtToolkit instance variables instead of WM_QUIT to |
| * guarantee that we exit from the nested message loop when any possible |
| * modal loop quits. In this case CancelAllThreadWindows is needed only to |
| * ensure that the nested message loop exits quickly and doesn't wait until |
| * a possible modal loop completes. |
| */ |
| m_breakMessageLoop = TRUE; |
| m_messageLoopResult = status; |
| |
| /* |
| * Fix for 4683602. |
| * Post an empty message, to wake up the toolkit thread |
| * if it is currently in WaitMessage(), |
| */ |
| PostMessage(WM_NULL); |
| } |
| |
| /* |
| * Called by the message loop to pump the message queue when there are |
| * messages waiting. Can also be called anywhere to pump messages. |
| */ |
| BOOL AwtToolkit::PumpWaitingMessages(PEEKMESSAGEPROC lpPeekMessageFunc) |
| { |
| MSG msg; |
| BOOL foundOne = FALSE; |
| |
| DASSERT(lpPeekMessageFunc != NULL); |
| |
| while (!m_breakMessageLoop && (*lpPeekMessageFunc)(msg)) { |
| foundOne = TRUE; |
| ProcessMsg(msg); |
| } |
| return foundOne; |
| } |
| |
| void AwtToolkit::PumpToDestroy(class AwtComponent* p) |
| { |
| MSG msg; |
| |
| DASSERT(AwtToolkit::PrimaryIdleFunc != NULL); |
| DASSERT(AwtToolkit::CommonPeekMessageFunc != NULL); |
| |
| while (p->IsDestroyPaused() && !m_breakMessageLoop) { |
| |
| PrimaryIdleFunc(); |
| |
| while (p->IsDestroyPaused() && !m_breakMessageLoop && CommonPeekMessageFunc(msg)) { |
| ProcessMsg(msg); |
| } |
| } |
| } |
| |
| void AwtToolkit::ProcessMsg(MSG& msg) |
| { |
| if (msg.message == WM_QUIT) { |
| m_breakMessageLoop = TRUE; |
| m_messageLoopResult = static_cast<UINT>(msg.wParam); |
| if (m_messageLoopResult == EXIT_ALL_ENCLOSING_LOOPS) |
| ::PostQuitMessage(static_cast<int>(msg.wParam)); // make sure all loops exit |
| } |
| else if (msg.message != WM_NULL) { |
| /* |
| * The AWT in standalone mode (that is, dynamically loaded from the |
| * Java VM) doesn't have any translation tables to worry about, so |
| * TranslateAccelerator isn't called. |
| */ |
| |
| ::TranslateMessage(&msg); |
| ::DispatchMessage(&msg); |
| } |
| } |
| |
| VOID CALLBACK |
| AwtToolkit::PrimaryIdleFunc() { |
| AwtToolkit::SetBusy(FALSE); |
| ::WaitMessage(); /* allow system to go idle */ |
| AwtToolkit::SetBusy(TRUE); |
| } |
| |
| VOID CALLBACK |
| AwtToolkit::SecondaryIdleFunc() { |
| ::WaitMessage(); /* allow system to go idle */ |
| } |
| |
| BOOL |
| AwtToolkit::CommonPeekMessageFunc(MSG& msg) { |
| return ::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE); |
| } |
| |
| /* |
| * Perform pre-processing on a message before it is translated & |
| * dispatched. Returns true to eat the message |
| */ |
| BOOL AwtToolkit::PreProcessMsg(MSG& msg) |
| { |
| /* |
| * Offer preprocessing first to the target component, then call out to |
| * specific mouse and key preprocessor methods |
| */ |
| AwtComponent* p = AwtComponent::GetComponent(msg.hwnd); |
| if (p && p->PreProcessMsg(msg) == mrConsume) |
| return TRUE; |
| |
| if ((msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST) || |
| (msg.message >= WM_NCMOUSEMOVE && msg.message <= WM_NCMBUTTONDBLCLK)) { |
| if (PreProcessMouseMsg(p, msg)) { |
| return TRUE; |
| } |
| } |
| else if (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST) { |
| if (PreProcessKeyMsg(p, msg)) |
| return TRUE; |
| } |
| return FALSE; |
| } |
| |
| BOOL AwtToolkit::PreProcessMouseMsg(AwtComponent* p, MSG& msg) |
| { |
| WPARAM mouseWParam; |
| LPARAM mouseLParam; |
| |
| /* |
| * Fix for BugTraq ID 4395290. |
| * Do not synthesize mouse enter/exit events during drag-and-drop, |
| * since it messes up LightweightDispatcher. |
| */ |
| if (AwtDropTarget::IsLocalDnD()) { |
| return FALSE; |
| } |
| |
| if (msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST) { |
| mouseWParam = msg.wParam; |
| mouseLParam = msg.lParam; |
| } else { |
| mouseWParam = GetMouseKeyState(); |
| } |
| |
| /* |
| * Get the window under the mouse, as it will be different if its |
| * captured. |
| */ |
| DWORD dwCurPos = ::GetMessagePos(); |
| DWORD dwScreenPos = dwCurPos; |
| POINT curPos; |
| // fix for 4805862 |
| // According to MSDN: do not use LOWORD and HIWORD macros to extract x and |
| // y coordinates because these macros return incorrect results on systems |
| // with multiple monitors (signed values are treated as unsigned) |
| curPos.x = GET_X_LPARAM(dwCurPos); |
| curPos.y = GET_Y_LPARAM(dwCurPos); |
| HWND hWndFromPoint = ::WindowFromPoint(curPos); |
| // hWndFromPoint == 0 if mouse is over a scrollbar |
| AwtComponent* mouseComp = |
| AwtComponent::GetComponent(hWndFromPoint); |
| // Need extra copies for non-client area issues |
| HWND hWndForWheel = hWndFromPoint; |
| |
| // If the point under the mouse isn't in the client area, |
| // ignore it to maintain compatibility with Solaris (#4095172) |
| RECT windowRect; |
| ::GetClientRect(hWndFromPoint, &windowRect); |
| POINT topLeft; |
| topLeft.x = 0; |
| topLeft.y = 0; |
| ::ClientToScreen(hWndFromPoint, &topLeft); |
| windowRect.top += topLeft.y; |
| windowRect.bottom += topLeft.y; |
| windowRect.left += topLeft.x; |
| windowRect.right += topLeft.x; |
| if ((curPos.y < windowRect.top) || |
| (curPos.y >= windowRect.bottom) || |
| (curPos.x < windowRect.left) || |
| (curPos.x >= windowRect.right)) { |
| mouseComp = NULL; |
| hWndFromPoint = NULL; |
| } |
| |
| /* |
| * Look for mouse transitions between windows & create |
| * MouseExit & MouseEnter messages |
| */ |
| // 6479820. Should check if a window is in manual resizing process: skip |
| // sending any MouseExit/Enter events while inside resize-loop. |
| // Note that window being in manual moving process could still |
| // produce redundant enter/exit mouse events. In future, they can be |
| // made skipped in a similar way. |
| if (mouseComp != m_lastMouseOver && !AwtWindow::IsResizing()) { |
| /* |
| * Send the messages right to the windows so that they are in |
| * the right sequence. |
| */ |
| if (m_lastMouseOver) { |
| dwCurPos = dwScreenPos; |
| curPos.x = LOWORD(dwCurPos); |
| curPos.y = HIWORD(dwCurPos); |
| ::MapWindowPoints(HWND_DESKTOP, m_lastMouseOver->GetHWnd(), |
| &curPos, 1); |
| mouseLParam = MAKELPARAM((WORD)curPos.x, (WORD)curPos.y); |
| m_lastMouseOver->SendMessage(WM_AWT_MOUSEEXIT, mouseWParam, |
| mouseLParam); |
| } |
| if (mouseComp) { |
| dwCurPos = dwScreenPos; |
| curPos.x = LOWORD(dwCurPos); |
| curPos.y = HIWORD(dwCurPos); |
| ::MapWindowPoints(HWND_DESKTOP, mouseComp->GetHWnd(), |
| &curPos, 1); |
| mouseLParam = MAKELPARAM((WORD)curPos.x, (WORD)curPos.y); |
| mouseComp->SendMessage(WM_AWT_MOUSEENTER, mouseWParam, |
| mouseLParam); |
| } |
| m_lastMouseOver = mouseComp; |
| } |
| |
| /* |
| * For MouseWheelEvents, hwnd must be changed to be the Component under |
| * the mouse, not the Component with the input focus. |
| */ |
| |
| if (msg.message == WM_MOUSEWHEEL) { |
| //i.e. mouse is over client area for this window |
| DWORD hWndForWheelProcess; |
| DWORD hWndForWheelThread = ::GetWindowThreadProcessId(hWndForWheel, &hWndForWheelProcess); |
| if (::GetCurrentProcessId() == hWndForWheelProcess) { |
| if (AwtToolkit::MainThread() == hWndForWheelThread) { |
| msg.hwnd = hWndForWheel; |
| } else { |
| // Interop mode, redispatch the event to another toolkit. |
| ::SendMessage(hWndForWheel, msg.message, mouseWParam, mouseLParam); |
| return TRUE; |
| } |
| } |
| } |
| |
| /* |
| * Make sure we get at least one last chance to check for transitions |
| * before we sleep |
| */ |
| if (m_lastMouseOver && !m_timer) { |
| m_timer = ::SetTimer(m_toolkitHWnd, IDT_AWT_MOUSECHECK, 200, 0); |
| } |
| return FALSE; /* Now go ahead and process current message as usual */ |
| } |
| |
| BOOL AwtToolkit::PreProcessKeyMsg(AwtComponent* p, MSG& msg) |
| { |
| // get keyboard state for use in AwtToolkit::GetKeyboardState |
| CriticalSection::Lock l(m_lockKB); |
| ::GetKeyboardState(m_lastKeyboardState); |
| return FALSE; |
| } |
| |
| void *AwtToolkit::SyncCall(void *(*ftn)(void *), void *param) { |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| if (!IsMainThread()) { |
| CriticalSection::Lock l(GetSyncCS()); |
| return (*ftn)(param); |
| } else { |
| return (*ftn)(param); |
| } |
| } |
| |
| void AwtToolkit::SyncCall(void (*ftn)(void *), void *param) { |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| if (!IsMainThread()) { |
| CriticalSection::Lock l(GetSyncCS()); |
| (*ftn)(param); |
| } else { |
| (*ftn)(param); |
| } |
| } |
| |
| void *AwtToolkit::SyncCall(void *(*ftn)(void)) { |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| if (!IsMainThread()) { |
| CriticalSection::Lock l(GetSyncCS()); |
| return (*ftn)(); |
| } else { |
| return (*ftn)(); |
| } |
| } |
| |
| void AwtToolkit::SyncCall(void (*ftn)(void)) { |
| JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); |
| if (!IsMainThread()) { |
| CriticalSection::Lock l(GetSyncCS()); |
| (*ftn)(); |
| } else { |
| (*ftn)(); |
| } |
| } |
| |
| UINT AwtToolkit::CreateCmdID(AwtObject* object) |
| { |
| return m_cmdIDs->Add(object); |
| } |
| |
| void AwtToolkit::RemoveCmdID(UINT id) |
| { |
| m_cmdIDs->Remove(id); |
| } |
| |
| AwtObject* AwtToolkit::LookupCmdID(UINT id) |
| { |
| return m_cmdIDs->Lookup(id); |
| } |
| |
| HICON AwtToolkit::GetAwtIcon() |
| { |
| return ::LoadIcon(GetModuleHandle(), TEXT("AWT_ICON")); |
| } |
| |
| HICON AwtToolkit::GetAwtIconSm() |
| { |
| static HICON defaultIconSm = NULL; |
| static int prevSmx = 0; |
| static int prevSmy = 0; |
| |
| int smx = GetSystemMetrics(SM_CXSMICON); |
| int smy = GetSystemMetrics(SM_CYSMICON); |
| |
| // Fixed 6364216: LoadImage() may leak memory |
| if (defaultIconSm == NULL || smx != prevSmx || smy != prevSmy) { |
| defaultIconSm = (HICON)LoadImage(GetModuleHandle(), TEXT("AWT_ICON"), IMAGE_ICON, smx, smy, 0); |
| prevSmx = smx; |
| prevSmy = smy; |
| } |
| return defaultIconSm; |
| } |
| |
| // The icon at index 0 must be gray. See AwtWindow::GetSecurityWarningIcon() |
| HICON AwtToolkit::GetSecurityWarningIcon(UINT index, UINT w, UINT h) |
| { |
| //Note: should not exceed 10 because of the current implementation. |
| static const int securityWarningIconCounter = 3; |
| |
| static HICON securityWarningIcon[securityWarningIconCounter] = {NULL, NULL, NULL};; |
| static UINT securityWarningIconWidth[securityWarningIconCounter] = {0, 0, 0}; |
| static UINT securityWarningIconHeight[securityWarningIconCounter] = {0, 0, 0}; |
| |
| index = AwtToolkit::CalculateWave(index, securityWarningIconCounter); |
| |
| if (securityWarningIcon[index] == NULL || |
| w != securityWarningIconWidth[index] || |
| h != securityWarningIconHeight[index]) |
| { |
| if (securityWarningIcon[index] != NULL) |
| { |
| ::DestroyIcon(securityWarningIcon[index]); |
| } |
| |
| static const wchar_t securityWarningIconName[] = L"SECURITY_WARNING_"; |
| wchar_t iconResourceName[sizeof(securityWarningIconName) + 2]; |
| ::ZeroMemory(iconResourceName, sizeof(iconResourceName)); |
| wcscpy(iconResourceName, securityWarningIconName); |
| |
| wchar_t strIndex[2]; |
| ::ZeroMemory(strIndex, sizeof(strIndex)); |
| strIndex[0] = L'0' + index; |
| |
| wcscat(iconResourceName, strIndex); |
| |
| securityWarningIcon[index] = (HICON)::LoadImage(GetModuleHandle(), |
| iconResourceName, |
| IMAGE_ICON, w, h, LR_DEFAULTCOLOR); |
| securityWarningIconWidth[index] = w; |
| securityWarningIconHeight[index] = h; |
| } |
| |
| return securityWarningIcon[index]; |
| } |
| |
| void AwtToolkit::SetHeapCheck(long flag) { |
| if (flag) { |
| printf("heap checking not supported with this build\n"); |
| } |
| } |
| |
| void throw_if_shutdown(void) throw (awt_toolkit_shutdown) |
| { |
| AwtToolkit::GetInstance().VerifyActive(); |
| } |
| void hang_if_shutdown(void) |
| { |
| try { |
| AwtToolkit::GetInstance().VerifyActive(); |
| } catch (awt_toolkit_shutdown&) { |
| // Never return. The VM will halt the process. |
| ::WaitForSingleObject(::CreateEvent(NULL, TRUE, FALSE, NULL), |
| INFINITE); |
| // Should never get here. |
| DASSERT(FALSE); |
| } |
| } |
| |
| // for now we support only one embedder, but should be ready for future |
| void AwtToolkit::RegisterEmbedderProcessId(HWND embedder) |
| { |
| if (m_embedderProcessID) { |
| // we already set embedder process and do not expect |
| // two different processes to embed the same AwtToolkit |
| return; |
| } |
| |
| embedder = ::GetAncestor(embedder, GA_ROOT); |
| ::GetWindowThreadProcessId(embedder, &m_embedderProcessID); |
| } |
| |
| JNIEnv* AwtToolkit::m_env; |
| DWORD AwtToolkit::m_threadId; |
| |
| void AwtToolkit::SetEnv(JNIEnv *env) { |
| if (m_env != NULL) { // If already cashed (by means of embeddedInit() call). |
| return; |
| } |
| m_threadId = GetCurrentThreadId(); |
| m_env = env; |
| } |
| |
| JNIEnv* AwtToolkit::GetEnv() { |
| return (m_env == NULL || m_threadId != GetCurrentThreadId()) ? |
| (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_2) : m_env; |
| } |
| |
| BOOL AwtToolkit::GetScreenInsets(int screenNum, RECT * rect) |
| { |
| /* if primary display */ |
| if (screenNum == 0) { |
| RECT rRW; |
| if (::SystemParametersInfo(SPI_GETWORKAREA,0,(void *) &rRW,0) == TRUE) { |
| rect->top = rRW.top; |
| rect->left = rRW.left; |
| rect->bottom = ::GetSystemMetrics(SM_CYSCREEN) - rRW.bottom; |
| rect->right = ::GetSystemMetrics(SM_CXSCREEN) - rRW.right; |
| return TRUE; |
| } |
| } |
| /* if additional display */ |
| else { |
| MONITORINFO *miInfo; |
| miInfo = AwtWin32GraphicsDevice::GetMonitorInfo(screenNum); |
| if (miInfo) { |
| rect->top = miInfo->rcWork.top - miInfo->rcMonitor.top; |
| rect->left = miInfo->rcWork.left - miInfo->rcMonitor.left; |
| rect->bottom = miInfo->rcMonitor.bottom - miInfo->rcWork.bottom; |
| rect->right = miInfo->rcMonitor.right - miInfo->rcWork.right; |
| return TRUE; |
| } |
| } |
| return FALSE; |
| } |
| |
| |
| void AwtToolkit::GetWindowRect(HWND hWnd, LPRECT lpRect) |
| { |
| try { |
| if (S_OK == DwmAPI::DwmGetWindowAttribute(hWnd, |
| DwmAPI::DWMWA_EXTENDED_FRAME_BOUNDS, |
| lpRect, sizeof(*lpRect))) |
| { |
| return; |
| } |
| } catch (const DllUtil::Exception &) {} |
| |
| ::GetWindowRect(hWnd, lpRect); |
| } |
| |
| |
| /************************************************************************ |
| * AWT preloading support |
| */ |
| bool AwtToolkit::PreloadAction::EnsureInited() |
| { |
| DWORD _initThreadId = GetInitThreadID(); |
| if (_initThreadId != 0) { |
| // already inited |
| // ensure the action is inited on correct thread |
| PreloadThread &preloadThread |
| = AwtToolkit::GetInstance().GetPreloadThread(); |
| if (_initThreadId == preloadThread.GetThreadId()) { |
| if (!preloadThread.IsWrongThread()) { |
| return true; |
| } |
| // inited on preloadThread (wrongThread), not cleaned yet |
| // have to wait cleanup completion |
| preloadThread.Wait4Finish(); |
| } else { |
| // inited on other thread (Toolkit thread?) |
| // consider as correctly inited |
| return true; |
| } |
| } |
| |
| // init on Toolkit thread |
| AwtToolkit::GetInstance().InvokeFunction(InitWrapper, this); |
| |
| return true; |
| } |
| |
| DWORD AwtToolkit::PreloadAction::GetInitThreadID() |
| { |
| CriticalSection::Lock lock(initLock); |
| return initThreadId; |
| } |
| |
| bool AwtToolkit::PreloadAction::Clean() |
| { |
| DWORD _initThreadId = GetInitThreadID(); |
| if (_initThreadId == ::GetCurrentThreadId()) { |
| // inited on this thread |
| Clean(false); |
| return true; |
| } |
| return false; |
| } |
| |
| /*static*/ |
| void AwtToolkit::PreloadAction::InitWrapper(void *param) |
| { |
| PreloadAction *pThis = (PreloadAction *)param; |
| pThis->Init(); |
| } |
| |
| void AwtToolkit::PreloadAction::Init() |
| { |
| CriticalSection::Lock lock(initLock); |
| if (initThreadId == 0) { |
| initThreadId = ::GetCurrentThreadId(); |
| InitImpl(); |
| } |
| } |
| |
| void AwtToolkit::PreloadAction::Clean(bool reInit) { |
| CriticalSection::Lock lock(initLock); |
| if (initThreadId != 0) { |
| //ASSERT(initThreadId == ::GetCurrentThreadId()); |
| CleanImpl(reInit); |
| initThreadId = 0; |
| } |
| } |
| |
| // PreloadThread implementation |
| AwtToolkit::PreloadThread::PreloadThread() |
| : status(None), wrongThread(false), threadId(0), |
| pActionChain(NULL), pLastProcessedAction(NULL), |
| execFunc(NULL), execParam(NULL) |
| { |
| hFinished = ::CreateEvent(NULL, TRUE, FALSE, NULL); |
| hAwake = ::CreateEvent(NULL, FALSE, FALSE, NULL); |
| } |
| |
| AwtToolkit::PreloadThread::~PreloadThread() |
| { |
| //Terminate(false); |
| ::CloseHandle(hFinished); |
| ::CloseHandle(hAwake); |
| } |
| |
| bool AwtToolkit::PreloadThread::AddAction(AwtToolkit::PreloadAction *pAction) |
| { |
| CriticalSection::Lock lock(threadLock); |
| |
| if (status > Preloading) { |
| // too late - the thread already terminated or run as toolkit thread |
| return false; |
| } |
| |
| if (pActionChain == NULL) { |
| // 1st action |
| pActionChain = pAction; |
| } else { |
| // add the action to the chain |
| PreloadAction *pChain = pActionChain; |
| while (true) { |
| PreloadAction *pNext = pChain->GetNext(); |
| if (pNext == NULL) { |
| break; |
| } |
| pChain = pNext; |
| } |
| pChain->SetNext(pAction); |
| } |
| |
| if (status > None) { |
| // the thread is already running (status == Preloading) |
| AwakeThread(); |
| return true; |
| } |
| |
| // need to start thread |
| ::ResetEvent(hAwake); |
| ::ResetEvent(hFinished); |
| |
| HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0x100000, StaticThreadProc, |
| this, 0, &threadId); |
| |
| if (hThread == 0) { |
| threadId = 0; |
| return false; |
| } |
| |
| status = Preloading; |
| |
| ::CloseHandle(hThread); |
| |
| return true; |
| } |
| |
| bool AwtToolkit::PreloadThread::Terminate(bool wrongThread) |
| { |
| CriticalSection::Lock lock(threadLock); |
| |
| if (status != Preloading) { |
| return false; |
| } |
| |
| execFunc = NULL; |
| execParam = NULL; |
| this->wrongThread = wrongThread; |
| status = Cleaning; |
| AwakeThread(); |
| |
| return true; |
| } |
| |
| bool AwtToolkit::PreloadThread::InvokeAndTerminate(void(_cdecl *fn)(void *), void *param) |
| { |
| CriticalSection::Lock lock(threadLock); |
| |
| if (status != Preloading) { |
| return false; |
| } |
| |
| execFunc = fn; |
| execParam = param; |
| status = fn == NULL ? Cleaning : RunningToolkit; |
| AwakeThread(); |
| |
| return true; |
| } |
| |
| bool AwtToolkit::PreloadThread::OnPreloadThread() |
| { |
| return GetThreadId() == ::GetCurrentThreadId(); |
| } |
| |
| /*static*/ |
| unsigned WINAPI AwtToolkit::PreloadThread::StaticThreadProc(void *param) |
| { |
| AwtToolkit::PreloadThread *pThis = (AwtToolkit::PreloadThread *)param; |
| return pThis->ThreadProc(); |
| } |
| |
| unsigned AwtToolkit::PreloadThread::ThreadProc() |
| { |
| void(_cdecl *_execFunc)(void *) = NULL; |
| void *_execParam = NULL; |
| bool _wrongThread = false; |
| |
| // initialization |
| while (true) { |
| PreloadAction *pAction; |
| { |
| CriticalSection::Lock lock(threadLock); |
| if (status != Preloading) { |
| // get invoke parameters |
| _execFunc = execFunc; |
| _execParam = execParam; |
| _wrongThread = wrongThread; |
| break; |
| } |
| pAction = GetNextAction(); |
| } |
| if (pAction != NULL) { |
| pAction->Init(); |
| } else { |
| ::WaitForSingleObject(hAwake, INFINITE); |
| } |
| } |
| |
| // call a function from InvokeAndTerminate |
| if (_execFunc != NULL) { |
| _execFunc(_execParam); |
| } else { |
| // time to terminate.. |
| } |
| |
| // cleanup |
| { |
| CriticalSection::Lock lock(threadLock); |
| pLastProcessedAction = NULL; // goto 1st action in the chain |
| status = Cleaning; |
| } |
| for (PreloadAction *pAction = GetNextAction(); pAction != NULL; |
| pAction = GetNextAction()) { |
| pAction->Clean(_wrongThread); |
| } |
| |
| // don't clear threadId! it is used by PreloadAction::EnsureInited |
| |
| { |
| CriticalSection::Lock lock(threadLock); |
| status = Finished; |
| } |
| ::SetEvent(hFinished); |
| return 0; |
| } |
| |
| AwtToolkit::PreloadAction* AwtToolkit::PreloadThread::GetNextAction() |
| { |
| CriticalSection::Lock lock(threadLock); |
| PreloadAction *pAction = (pLastProcessedAction == NULL) |
| ? pActionChain |
| : pLastProcessedAction->GetNext(); |
| if (pAction != NULL) { |
| pLastProcessedAction = pAction; |
| } |
| |
| return pAction; |
| } |
| |
| |
| extern "C" { |
| |
| /* Terminates preload thread (if it's still alive |
| * - it may occur if the application doesn't use AWT). |
| * The function is called from launcher after completion main java thread. |
| */ |
| __declspec(dllexport) void preloadStop() |
| { |
| AwtToolkit::GetInstance().GetPreloadThread().Terminate(false); |
| } |
| |
| } |
| |
| |
| /************************************************************************ |
| * Toolkit native methods |
| */ |
| |
| extern "C" { |
| |
| /* |
| * Class: java_awt_Toolkit |
| * Method: initIDs |
| * Signature: ()V |
| */ |
| JNIEXPORT void JNICALL |
| Java_java_awt_Toolkit_initIDs(JNIEnv *env, jclass cls) { |
| TRY; |
| |
| AwtToolkit::getDefaultToolkitMID = |
| env->GetStaticMethodID(cls,"getDefaultToolkit","()Ljava/awt/Toolkit;"); |
| DASSERT(AwtToolkit::getDefaultToolkitMID != NULL); |
| CHECK_NULL(AwtToolkit::getDefaultToolkitMID); |
| |
| AwtToolkit::getFontMetricsMID = |
| env->GetMethodID(cls, "getFontMetrics", "(Ljava/awt/Font;)Ljava/awt/FontMetrics;"); |
| DASSERT(AwtToolkit::getFontMetricsMID != NULL); |
| CHECK_NULL(AwtToolkit::getFontMetricsMID); |
| |
| jclass insetsClass = env->FindClass("java/awt/Insets"); |
| DASSERT(insetsClass != NULL); |
| CHECK_NULL(insetsClass); |
| AwtToolkit::insetsMID = env->GetMethodID(insetsClass, "<init>", "(IIII)V"); |
| DASSERT(AwtToolkit::insetsMID != NULL); |
| CHECK_NULL(AwtToolkit::insetsMID); |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| |
| } /* extern "C" */ |
| |
| /************************************************************************ |
| * WToolkit native methods |
| */ |
| |
| extern "C" { |
| |
| /* |
| * Class: sun_awt_windows_WToolkit |
| * Method: initIDs |
| * Signature: ()V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_awt_windows_WToolkit_initIDs(JNIEnv *env, jclass cls) |
| { |
| TRY; |
| |
| AwtToolkit::windowsSettingChangeMID = |
| env->GetMethodID(cls, "windowsSettingChange", "()V"); |
| DASSERT(AwtToolkit::windowsSettingChangeMID != 0); |
| CHECK_NULL(AwtToolkit::windowsSettingChangeMID); |
| |
| AwtToolkit::displayChangeMID = |
| env->GetStaticMethodID(cls, "displayChanged", "()V"); |
| DASSERT(AwtToolkit::displayChangeMID != 0); |
| CHECK_NULL(AwtToolkit::displayChangeMID); |
| |
| // Set various global IDs needed by JAWT code. Note: these |
| // variables cannot be set by JAWT code directly due to |
| // different permissions that that code may be run under |
| // (bug 4796548). It would be nice to initialize these |
| // variables lazily, but given the minimal number of calls |
| // for this, it seems simpler to just do it at startup with |
| // negligible penalty. |
| jclass sDataClassLocal = env->FindClass("sun/java2d/SurfaceData"); |
| DASSERT(sDataClassLocal != 0); |
| CHECK_NULL(sDataClassLocal); |
| |
| jclass vImgClassLocal = env->FindClass("sun/awt/image/SunVolatileImage"); |
| DASSERT(vImgClassLocal != 0); |
| CHECK_NULL(vImgClassLocal); |
| |
| jclass vSMgrClassLocal = |
| env->FindClass("sun/awt/image/VolatileSurfaceManager"); |
| DASSERT(vSMgrClassLocal != 0); |
| CHECK_NULL(vSMgrClassLocal); |
| |
| jclass componentClassLocal = env->FindClass("java/awt/Component"); |
| DASSERT(componentClassLocal != 0); |
| CHECK_NULL(componentClassLocal); |
| |
| jawtSMgrID = env->GetFieldID(vImgClassLocal, "volSurfaceManager", |
| "Lsun/awt/image/VolatileSurfaceManager;"); |
| DASSERT(jawtSMgrID != 0); |
| CHECK_NULL(jawtSMgrID); |
| |
| jawtSDataID = env->GetFieldID(vSMgrClassLocal, "sdCurrent", |
| "Lsun/java2d/SurfaceData;"); |
| DASSERT(jawtSDataID != 0); |
| CHECK_NULL(jawtSDataID); |
| |
| jawtPDataID = env->GetFieldID(sDataClassLocal, "pData", "J"); |
| DASSERT(jawtPDataID != 0); |
| CHECK_NULL(jawtPDataID); |
| // Save these classes in global references for later use |
| jawtVImgClass = (jclass)env->NewGlobalRef(vImgClassLocal); |
| CHECK_NULL(jawtVImgClass); |
| jawtComponentClass = (jclass)env->NewGlobalRef(componentClassLocal); |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| |
| /* |
| * Class: sun_awt_windows_Toolkit |
| * Method: disableCustomPalette |
| * Signature: ()V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_awt_windows_WToolkit_disableCustomPalette(JNIEnv *env, jclass cls) { |
| AwtPalette::DisableCustomPalette(); |
| } |
| |
| /* |
| * Class: sun_awt_windows_WToolkit |
| * Method: embeddedInit |
| * Signature: ()Z |
| */ |
| JNIEXPORT jboolean JNICALL |
| Java_sun_awt_windows_WToolkit_embeddedInit(JNIEnv *env, jclass cls) |
| { |
| TRY; |
| |
| AwtToolkit::SetEnv(env); |
| |
| return AwtToolkit::GetInstance().Initialize(FALSE); |
| |
| CATCH_BAD_ALLOC_RET(JNI_FALSE); |
| } |
| |
| /* |
| * Class: sun_awt_windows_WToolkit |
| * Method: embeddedDispose |
| * Signature: ()Z |
| */ |
| JNIEXPORT jboolean JNICALL |
| Java_sun_awt_windows_WToolkit_embeddedDispose(JNIEnv *env, jclass cls) |
| { |
| TRY; |
| |
| BOOL retval = AwtToolkit::GetInstance().Dispose(); |
| AwtToolkit::GetInstance().SetPeer(env, NULL); |
| return retval; |
| |
| CATCH_BAD_ALLOC_RET(JNI_FALSE); |
| } |
| |
| /* |
| * Class: sun_awt_windows_WToolkit |
| * Method: embeddedEventLoopIdleProcessing |
| * Signature: ()V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_awt_windows_WToolkit_embeddedEventLoopIdleProcessing(JNIEnv *env, |
| jobject self) |
| { |
| VerifyWindowMoveLockReleased(); |
| } |
| |
| |
| /* |
| * Class: sun_awt_windows_WToolkit |
| * Method: init |
| * Signature: ()Z |
| */ |
| JNIEXPORT jboolean JNICALL |
| Java_sun_awt_windows_WToolkit_init(JNIEnv *env, jobject self) |
| { |
| TRY; |
| |
| AwtToolkit::SetEnv(env); |
| |
| AwtToolkit::GetInstance().SetPeer(env, self); |
| |
| // This call will fail if the Toolkit was already initialized. |
| // In that case, we don't want to start another message pump. |
| return AwtToolkit::GetInstance().Initialize(TRUE); |
| |
| CATCH_BAD_ALLOC_RET(FALSE); |
| } |
| |
| /* |
| * Class: sun_awt_windows_WToolkit |
| * Method: eventLoop |
| * Signature: ()V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_awt_windows_WToolkit_eventLoop(JNIEnv *env, jobject self) |
| { |
| TRY; |
| |
| DASSERT(AwtToolkit::GetInstance().localPump()); |
| |
| AwtToolkit::SetBusy(TRUE); |
| |
| AwtToolkit::GetInstance().MessageLoop(AwtToolkit::PrimaryIdleFunc, |
| AwtToolkit::CommonPeekMessageFunc); |
| |
| AwtToolkit::GetInstance().Dispose(); |
| |
| AwtToolkit::SetBusy(FALSE); |
| |
| /* |
| * IMPORTANT NOTES: |
| * The AwtToolkit has been destructed by now. |
| * DO NOT CALL any method of AwtToolkit!!! |
| */ |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| /* |
| * Class: sun_awt_windows_WToolkit |
| * Method: shutdown |
| * Signature: ()V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_awt_windows_WToolkit_shutdown(JNIEnv *env, jobject self) |
| { |
| TRY; |
| |
| AwtToolkit& tk = AwtToolkit::GetInstance(); |
| |
| tk.QuitMessageLoop(AwtToolkit::EXIT_ALL_ENCLOSING_LOOPS); |
| |
| while (!tk.IsDisposed()) { |
| Sleep(100); |
| } |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| /* |
| * Class: sun_awt_windows_WToolkit |
| * Method: startSecondaryEventLoop |
| * Signature: ()V; |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_awt_windows_WToolkit_startSecondaryEventLoop( |
| JNIEnv *env, |
| jclass) |
| { |
| TRY; |
| |
| DASSERT(AwtToolkit::MainThread() == ::GetCurrentThreadId()); |
| |
| AwtToolkit::GetInstance().MessageLoop(AwtToolkit::SecondaryIdleFunc, |
| AwtToolkit::CommonPeekMessageFunc); |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| /* |
| * Class: sun_awt_windows_WToolkit |
| * Method: quitSecondaryEventLoop |
| * Signature: ()V; |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_awt_windows_WToolkit_quitSecondaryEventLoop( |
| JNIEnv *env, |
| jclass) |
| { |
| TRY; |
| |
| AwtToolkit::GetInstance().QuitMessageLoop(AwtToolkit::EXIT_ENCLOSING_LOOP); |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| /* |
| * Class: sun_awt_windows_WToolkit |
| * Method: makeColorModel |
| * Signature: ()Ljava/awt/image/ColorModel; |
| */ |
| JNIEXPORT jobject JNICALL |
| Java_sun_awt_windows_WToolkit_makeColorModel(JNIEnv *env, jclass cls) |
| { |
| TRY; |
| |
| return AwtWin32GraphicsDevice::GetColorModel(env, JNI_FALSE, |
| AwtWin32GraphicsDevice::GetDefaultDeviceIndex()); |
| |
| CATCH_BAD_ALLOC_RET(NULL); |
| } |
| |
| /* |
| * Class: sun_awt_windows_WToolkit |
| * Method: getMaximumCursorColors |
| * Signature: ()I |
| */ |
| JNIEXPORT jint JNICALL |
| Java_sun_awt_windows_WToolkit_getMaximumCursorColors(JNIEnv *env, jobject self) |
| { |
| TRY; |
| |
| HDC hIC = ::CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL); |
| |
| int nColor = 256; |
| switch (::GetDeviceCaps(hIC, BITSPIXEL) * ::GetDeviceCaps(hIC, PLANES)) { |
| case 1: nColor = 2; break; |
| case 4: nColor = 16; break; |
| case 8: nColor = 256; break; |
| case 16: nColor = 65536; break; |
| case 24: nColor = 16777216; break; |
| } |
| ::DeleteDC(hIC); |
| return nColor; |
| |
| CATCH_BAD_ALLOC_RET(0); |
| } |
| |
| /* |
| * Class: sun_awt_windows_WToolkit |
| * Method: getScreenWidth |
| * Signature: ()I |
| */ |
| JNIEXPORT jint JNICALL |
| Java_sun_awt_windows_WToolkit_getScreenWidth(JNIEnv *env, jobject self) |
| { |
| TRY; |
| |
| return ::GetSystemMetrics(SM_CXSCREEN); |
| |
| CATCH_BAD_ALLOC_RET(0); |
| } |
| |
| /* |
| * Class: sun_awt_windows_WToolkit |
| * Method: getScreenHeight |
| * Signature: ()I |
| */ |
| JNIEXPORT jint JNICALL |
| Java_sun_awt_windows_WToolkit_getScreenHeight(JNIEnv *env, jobject self) |
| { |
| TRY; |
| |
| return ::GetSystemMetrics(SM_CYSCREEN); |
| |
| CATCH_BAD_ALLOC_RET(0); |
| } |
| |
| /* |
| * Class: sun_awt_windows_WToolkit |
| * Method: getSreenInsets |
| * Signature: (I)Ljava/awt/Insets; |
| */ |
| JNIEXPORT jobject JNICALL |
| Java_sun_awt_windows_WToolkit_getScreenInsets(JNIEnv *env, |
| jobject self, |
| jint screen) |
| { |
| jobject insets = NULL; |
| RECT rect; |
| |
| TRY; |
| |
| if (AwtToolkit::GetScreenInsets(screen, &rect)) { |
| jclass insetsClass = env->FindClass("java/awt/Insets"); |
| DASSERT(insetsClass != NULL); |
| CHECK_NULL_RETURN(insetsClass, NULL); |
| |
| insets = env->NewObject(insetsClass, |
| AwtToolkit::insetsMID, |
| rect.top, |
| rect.left, |
| rect.bottom, |
| rect.right); |
| } |
| |
| if (safe_ExceptionOccurred(env)) { |
| return 0; |
| } |
| return insets; |
| |
| CATCH_BAD_ALLOC_RET(NULL); |
| } |
| |
| |
| /* |
| * Class: sun_awt_windows_WToolkit |
| * Method: nativeSync |
| * Signature: ()V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_awt_windows_WToolkit_nativeSync(JNIEnv *env, jobject self) |
| { |
| TRY; |
| |
| // Synchronize both GDI and DDraw |
| VERIFY(::GdiFlush()); |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| /* |
| * Class: sun_awt_windows_WToolkit |
| * Method: beep |
| * Signature: ()V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_awt_windows_WToolkit_beep(JNIEnv *env, jobject self) |
| { |
| TRY; |
| |
| VERIFY(::MessageBeep(MB_OK)); |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| /* |
| * Class: sun_awt_windows_WToolkit |
| * Method: getLockingKeyStateNative |
| * Signature: (I)Z |
| */ |
| JNIEXPORT jboolean JNICALL |
| Java_sun_awt_windows_WToolkit_getLockingKeyStateNative(JNIEnv *env, jobject self, jint javaKey) |
| { |
| TRY; |
| |
| UINT windowsKey, modifiers; |
| AwtComponent::JavaKeyToWindowsKey(javaKey, &windowsKey, &modifiers); |
| |
| if (windowsKey == 0) { |
| JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "Keyboard doesn't have requested key"); |
| return JNI_FALSE; |
| } |
| |
| // low order bit in keyboardState indicates whether the key is toggled |
| BYTE keyboardState[AwtToolkit::KB_STATE_SIZE]; |
| AwtToolkit::GetKeyboardState(keyboardState); |
| return keyboardState[windowsKey] & 0x01; |
| |
| CATCH_BAD_ALLOC_RET(JNI_FALSE); |
| } |
| |
| /* |
| * Class: sun_awt_windows_WToolkit |
| * Method: setLockingKeyStateNative |
| * Signature: (IZ)V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_awt_windows_WToolkit_setLockingKeyStateNative(JNIEnv *env, jobject self, jint javaKey, jboolean state) |
| { |
| TRY; |
| |
| UINT windowsKey, modifiers; |
| AwtComponent::JavaKeyToWindowsKey(javaKey, &windowsKey, &modifiers); |
| |
| if (windowsKey == 0) { |
| JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", "Keyboard doesn't have requested key"); |
| return; |
| } |
| |
| // if the key isn't in the desired state yet, simulate key events to get there |
| // low order bit in keyboardState indicates whether the key is toggled |
| BYTE keyboardState[AwtToolkit::KB_STATE_SIZE]; |
| AwtToolkit::GetKeyboardState(keyboardState); |
| if ((keyboardState[windowsKey] & 0x01) != state) { |
| ::keybd_event(windowsKey, 0, 0, 0); |
| ::keybd_event(windowsKey, 0, KEYEVENTF_KEYUP, 0); |
| } |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| /* |
| * Class: sun_awt_windows_WToolkit |
| * Method: loadSystemColors |
| * Signature: ([I)V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_awt_windows_WToolkit_loadSystemColors(JNIEnv *env, jobject self, |
| jintArray colors) |
| { |
| TRY; |
| |
| static int indexMap[] = { |
| COLOR_DESKTOP, /* DESKTOP */ |
| COLOR_ACTIVECAPTION, /* ACTIVE_CAPTION */ |
| COLOR_CAPTIONTEXT, /* ACTIVE_CAPTION_TEXT */ |
| COLOR_ACTIVEBORDER, /* ACTIVE_CAPTION_BORDER */ |
| COLOR_INACTIVECAPTION, /* INACTIVE_CAPTION */ |
| COLOR_INACTIVECAPTIONTEXT, /* INACTIVE_CAPTION_TEXT */ |
| COLOR_INACTIVEBORDER, /* INACTIVE_CAPTION_BORDER */ |
| COLOR_WINDOW, /* WINDOW */ |
| COLOR_WINDOWFRAME, /* WINDOW_BORDER */ |
| COLOR_WINDOWTEXT, /* WINDOW_TEXT */ |
| COLOR_MENU, /* MENU */ |
| COLOR_MENUTEXT, /* MENU_TEXT */ |
| COLOR_WINDOW, /* TEXT */ |
| COLOR_WINDOWTEXT, /* TEXT_TEXT */ |
| COLOR_HIGHLIGHT, /* TEXT_HIGHLIGHT */ |
| COLOR_HIGHLIGHTTEXT, /* TEXT_HIGHLIGHT_TEXT */ |
| COLOR_GRAYTEXT, /* TEXT_INACTIVE_TEXT */ |
| COLOR_3DFACE, /* CONTROL */ |
| COLOR_BTNTEXT, /* CONTROL_TEXT */ |
| COLOR_3DLIGHT, /* CONTROL_HIGHLIGHT */ |
| COLOR_3DHILIGHT, /* CONTROL_LT_HIGHLIGHT */ |
| COLOR_3DSHADOW, /* CONTROL_SHADOW */ |
| COLOR_3DDKSHADOW, /* CONTROL_DK_SHADOW */ |
| COLOR_SCROLLBAR, /* SCROLLBAR */ |
| COLOR_INFOBK, /* INFO */ |
| COLOR_INFOTEXT, /* INFO_TEXT */ |
| }; |
| |
| jint colorLen = env->GetArrayLength(colors); |
| jint* colorsPtr = NULL; |
| try { |
| colorsPtr = (jint *)env->GetPrimitiveArrayCritical(colors, 0); |
| for (int i = 0; i < (sizeof indexMap)/(sizeof *indexMap) && i < colorLen; i++) { |
| colorsPtr[i] = DesktopColor2RGB(indexMap[i]); |
| } |
| } catch (...) { |
| if (colorsPtr != NULL) { |
| env->ReleasePrimitiveArrayCritical(colors, colorsPtr, 0); |
| } |
| throw; |
| } |
| |
| env->ReleasePrimitiveArrayCritical(colors, colorsPtr, 0); |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| extern "C" JNIEXPORT jobject JNICALL DSGetComponent |
| (JNIEnv* env, void* platformInfo) |
| { |
| TRY; |
| |
| HWND hWnd = (HWND)platformInfo; |
| if (!::IsWindow(hWnd)) |
| return NULL; |
| |
| AwtComponent* comp = AwtComponent::GetComponent(hWnd); |
| if (comp == NULL) |
| return NULL; |
| |
| return comp->GetTarget(env); |
| |
| CATCH_BAD_ALLOC_RET(NULL); |
| } |
| |
| JNIEXPORT void JNICALL |
| Java_sun_awt_windows_WToolkit_postDispose(JNIEnv *env, jclass clazz) |
| { |
| #ifdef DEBUG |
| TRY_NO_VERIFY; |
| |
| // If this method was called, that means runFinalizersOnExit is turned |
| // on and the VM is exiting cleanly. We should signal the debug memory |
| // manager to generate a leaks report. |
| AwtDebugSupport::GenerateLeaksReport(); |
| |
| CATCH_BAD_ALLOC; |
| #endif |
| } |
| |
| /* |
| * Class: sun_awt_windows_WToolkit |
| * Method: setDynamicLayoutNative |
| * Signature: (Z)V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_awt_windows_WToolkit_setDynamicLayoutNative(JNIEnv *env, |
| jobject self, jboolean dynamic) |
| { |
| TRY; |
| |
| AwtToolkit::GetInstance().SetDynamicLayout(dynamic); |
| |
| CATCH_BAD_ALLOC; |
| } |
| |
| /* |
| * Class: sun_awt_windows_WToolkit |
| * Method: isDynamicLayoutSupportedNative |
| * Signature: ()Z |
| */ |
| JNIEXPORT jboolean JNICALL |
| Java_sun_awt_windows_WToolkit_isDynamicLayoutSupportedNative(JNIEnv *env, |
| jobject self) |
| { |
| TRY; |
| |
| return (jboolean) AwtToolkit::GetInstance().IsDynamicLayoutSupported(); |
| |
| CATCH_BAD_ALLOC_RET(FALSE); |
| } |
| |
| /* |
| * Class: sun_awt_windows_WToolkit |
| * Method: printWindowsVersion |
| * Signature: ()Ljava/lang/String; |
| */ |
| JNIEXPORT jstring JNICALL |
| Java_sun_awt_windows_WToolkit_getWindowsVersion(JNIEnv *env, jclass cls) |
| { |
| TRY; |
| |
| WCHAR szVer[128]; |
| |
| DWORD version = ::GetVersion(); |
| swprintf(szVer, 128, L"0x%x = %ld", version, version); |
| int l = lstrlen(szVer); |
| |
| if (IS_WIN2000) { |
| if (IS_WINXP) { |
| if (IS_WINVISTA) { |
| swprintf(szVer + l, 128, L" (Windows Vista)"); |
| } else { |
| swprintf(szVer + l, 128, L" (Windows XP)"); |
| } |
| } else { |
| swprintf(szVer + l, 128, L" (Windows 2000)"); |
| } |
| } else { |
| swprintf(szVer + l, 128, L" (Unknown)"); |
| } |
| |
| return JNU_NewStringPlatform(env, szVer); |
| |
| CATCH_BAD_ALLOC_RET(NULL); |
| } |
| |
| JNIEXPORT jboolean JNICALL |
| Java_sun_awt_windows_WToolkit_syncNativeQueue(JNIEnv *env, jobject self, jlong timeout) |
| { |
| AwtToolkit & tk = AwtToolkit::GetInstance(); |
| DWORD eventNumber = tk.eventNumber; |
| tk.PostMessage(WM_SYNC_WAIT, 0, 0); |
| ::WaitForSingleObject(tk.m_waitEvent, INFINITE); |
| DWORD newEventNumber = tk.eventNumber; |
| return (newEventNumber - eventNumber) > 2; |
| } |
| |
| } /* extern "C" */ |
| |
| /* Convert a Windows desktop color index into an RGB value. */ |
| COLORREF DesktopColor2RGB(int colorIndex) { |
| DWORD sysColor = ::GetSysColor(colorIndex); |
| return ((GetRValue(sysColor)<<16) | (GetGValue(sysColor)<<8) | |
| (GetBValue(sysColor)) | 0xff000000); |
| } |
| |
| |
| /* |
| * Class: sun_awt_SunToolkit |
| * Method: closeSplashScreen |
| * Signature: ()V |
| */ |
| extern "C" JNIEXPORT void JNICALL |
| Java_sun_awt_SunToolkit_closeSplashScreen(JNIEnv *env, jclass cls) |
| { |
| typedef void (*SplashClose_t)(); |
| HMODULE hSplashDll = GetModuleHandle(_T("splashscreen.dll")); |
| if (!hSplashDll) { |
| return; // dll not loaded |
| } |
| SplashClose_t splashClose = (SplashClose_t)GetProcAddress(hSplashDll, |
| "SplashClose"); |
| if (splashClose) { |
| splashClose(); |
| } |
| } |
| |
| /* |
| * accessible from awt_Component |
| */ |
| BOOL AwtToolkit::areExtraMouseButtonsEnabled() { |
| return m_areExtraMouseButtonsEnabled; |
| } |
| |
| /* |
| * Class: sun_awt_windows_WToolkit |
| * Method: setExtraMouseButtonsEnabledNative |
| * Signature: (Z)V |
| */ |
| extern "C" JNIEXPORT void JNICALL Java_sun_awt_windows_WToolkit_setExtraMouseButtonsEnabledNative |
| (JNIEnv *env, jclass self, jboolean enable){ |
| TRY; |
| AwtToolkit::GetInstance().setExtraMouseButtonsEnabled(enable); |
| CATCH_BAD_ALLOC; |
| } |
| |
| void AwtToolkit::setExtraMouseButtonsEnabled(BOOL enable) { |
| m_areExtraMouseButtonsEnabled = enable; |
| } |
| |
| JNIEXPORT jint JNICALL Java_sun_awt_windows_WToolkit_getNumberOfButtonsImpl |
| (JNIEnv *, jobject self) { |
| return AwtToolkit::GetNumberOfButtons(); |
| } |
| |
| UINT AwtToolkit::GetNumberOfButtons() { |
| return MOUSE_BUTTONS_WINDOWS_SUPPORTED; |
| } |