blob: 242c403e4a941d9d29f48d69655f218d73d44bdc [file] [log] [blame]
/*
* 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
GetThreadDpiAwarenessContextFunc* AwtToolkit::lpGetThreadDpiAwarenessContext = NULL;
SetThreadDpiAwarenessContextFunc* AwtToolkit::lpSetThreadDpiAwarenessContext = NULL;
AreDpiAwarenessContextsEqualFunc* AwtToolkit::lpAreDpiAwarenessContextsEqual = NULL;
EnableNonClientDpiScalingFunc* AwtToolkit::lpEnableNonClientDpiScaling = NULL;
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();
HMODULE hLibUser32Dll = JDK_LoadSystemLibrary("User32.dll");
if (hLibUser32Dll != NULL) {
lpGetThreadDpiAwarenessContext =
(GetThreadDpiAwarenessContextFunc*)GetProcAddress(hLibUser32Dll, "GetThreadDpiAwarenessContext");
lpSetThreadDpiAwarenessContext =
(SetThreadDpiAwarenessContextFunc*)GetProcAddress(hLibUser32Dll, "SetThreadDpiAwarenessContext");
lpAreDpiAwarenessContextsEqual =
(AreDpiAwarenessContextsEqualFunc*)GetProcAddress(hLibUser32Dll, "AreDpiAwarenessContextsEqual");
lpEnableNonClientDpiScaling =
(EnableNonClientDpiScalingFunc*)GetProcAddress(hLibUser32Dll, "EnableNonClientDpiScaling");
::FreeLibrary(hLibUser32Dll);
}
return TRUE;
}
void AwtToolkit::_UpdateToolkitDpiAwarenessContext(void* p = NULL)
{
static DPI_AWARENESS_CONTEXT context = NULL;
if (p != NULL) context = static_cast<DPI_AWARENESS_CONTEXT>(p); // cache the last context
if (context != NULL &&
lpAreDpiAwarenessContextsEqual != NULL &&
!lpAreDpiAwarenessContextsEqual(GetToolkitDpiAwarenessContext(), context))
{
SetToolkitDpiAwarenessContext(context);
}
}
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_MOUSEHWHEEL) ||
(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) || (msg.message == WM_MOUSEHWHEEL)) {
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 || msg.message == WM_MOUSEHWHEEL) {
//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);
}
bool AwtToolkit::GetIntegerProperty(LPTSTR prop, int& value)
{
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
if (!env) return false;
static jclass cInteger = env->FindClass("java/lang/Integer");
DASSERT(cInteger);
static jmethodID mGetInteger = env->GetStaticMethodID(cInteger, "getInteger", "(Ljava/lang/String;)Ljava/lang/Integer;");
DASSERT(mGetInteger);
jstring propStr = JNU_NewStringPlatform(env, prop);
jobject jInt = env->CallStaticObjectMethod(cInteger, mGetInteger, propStr);
env->DeleteLocalRef(propStr);
if (!jInt) return false;
static jmethodID mIntValue = env->GetMethodID(cInteger, "intValue", "()I");
DASSERT(mIntValue);
value = (int)env->CallIntMethod(jInt, mIntValue);
env->DeleteLocalRef(jInt);
if (safe_ExceptionOccurred(env)) return false;
return true;
}
static bool GetWinAppIconID(int& id)
{
static CriticalSection lock;
CriticalSection::Lock l(lock);
static bool initialized = false;
static int* iconID;
if (!initialized) {
initialized = true;
int v;
if (AwtToolkit::GetIntegerProperty(TEXT("jbre.win.app.icon.id"), v)) iconID = new int(v);
}
if (!iconID) return false;
id = *iconID;
return true;
}
HICON AwtToolkit::GetAwtIcon()
{
int iconID;
if (GetWinAppIconID(iconID)) {
return ::LoadIcon(::GetModuleHandle(NULL), MAKEINTRESOURCE(iconID));
} else {
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) {
int iconID;
if (GetWinAppIconID(iconID)) {
// loads the best fitting resolution icon from the resource
defaultIconSm = ::LoadIcon(::GetModuleHandle(NULL), MAKEINTRESOURCE(iconID));
} else {
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;
int width = ::GetSystemMetrics(SM_CXSCREEN);
Devices::InstanceAccess devices;
AwtWin32GraphicsDevice *device = devices->GetDevice(
AwtWin32GraphicsDevice::GetDefaultDeviceIndex());
return (device == NULL) ? width : device->ScaleDownX(width);
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;
int height = ::GetSystemMetrics(SM_CYSCREEN);
Devices::InstanceAccess devices;
AwtWin32GraphicsDevice *device = devices->GetDevice(
AwtWin32GraphicsDevice::GetDefaultDeviceIndex());
return (device == NULL) ? height : device->ScaleDownY(height);
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;
}