< prev index next >
src/windows/native/sun/windows/awt_Component.cpp
Print this page
rev 1556 : 6794764: Translucent windows are completely repainted on every paint event, on Windows
6719382: Printing of AWT components on windows is not working
6726866: Repainting artifacts when resizing or dragging JInternalFrames in non-opaque toplevel
6683775: Painting artifacts is seen when panel is made setOpaque(false) for a translucent window
Reviewed-by: anthony, tdv, alexp
rev 1566 : 6680988: KeyEvent is still missing VK values for many keyboards
Summary: 2 new methods and some fields added to KeyEvent, plus hash of constants introduced
Reviewed-by: art
@@ -33,10 +33,11 @@
#include <windowsx.h>
#include <zmouse.h>
#include "jlong.h"
#include "awt_AWTEvent.h"
+#include "awt_BitmapUtil.h"
#include "awt_Component.h"
#include "awt_Cursor.h"
#include "awt_Dimension.h"
#include "awt_Frame.h"
#include "awt_InputEvent.h"
@@ -161,10 +162,11 @@
// Struct for _CreatePrintedPixels() method
struct CreatePrintedPixelsStruct {
jobject component;
int srcx, srcy;
int srcw, srch;
+ jint alpha;
};
// Struct for _SetRectangularShape() method
struct SetRectangularShapeStruct {
jobject component;
jint x1, x2, y1, y2;
@@ -225,10 +227,12 @@
BOOL AwtComponent::sm_rtl = PRIMARYLANGID(GetInputLanguage()) == LANG_ARABIC ||
PRIMARYLANGID(GetInputLanguage()) == LANG_HEBREW;
BOOL AwtComponent::sm_rtlReadingOrder =
PRIMARYLANGID(GetInputLanguage()) == LANG_ARABIC;
+BOOL AwtComponent::sm_PrimaryDynamicTableBuilt = FALSE;
+
HWND AwtComponent::sm_cursorOn;
BOOL AwtComponent::m_QueryNewPaletteCalled = FALSE;
CriticalSection windowMoveLock;
BOOL windowMoveLockHeld = FALSE;
@@ -271,10 +275,15 @@
m_hCursorCache = NULL;
m_bSubclassed = FALSE;
m_MessagesProcessing = 0;
+ if (!sm_PrimaryDynamicTableBuilt) {
+ // do it once.
+ AwtComponent::BuildPrimaryDynamicTable();
+ sm_PrimaryDynamicTableBuilt = TRUE;
+ }
}
AwtComponent::~AwtComponent()
{
DASSERT(AwtToolkit::IsMainThread());
@@ -387,12 +396,12 @@
* hwnd is an AWT component hwnd
*/
AwtComponent* AwtComponent::GetComponentImpl(HWND hWnd) {
AwtComponent *component =
(AwtComponent *)::GetWindowLongPtr(hWnd, GWLP_USERDATA);
- DASSERT( !IsBadReadPtr(component, sizeof(AwtComponent)) );
- DASSERT( component->GetHWnd() == hWnd );
+ DASSERT(!component || !IsBadReadPtr(component, sizeof(AwtComponent)) );
+ DASSERT(!component || component->GetHWnd() == hWnd );
return component;
}
/*
* Single window proc for all the components. Delegates real work to
@@ -1937,15 +1946,18 @@
::SetScrollInfo(GetHWnd(), (int) wParam, si, TRUE);
delete si;
mr = mrConsume;
break;
}
- case WM_AWT_CREATE_PRINTED_PIXELS:
- retValue = (LRESULT)CreatePrintedPixels(*((SIZE *)wParam),
- *((SIZE *)lParam));
+ case WM_AWT_CREATE_PRINTED_PIXELS: {
+ CreatePrintedPixelsStruct* cpps = (CreatePrintedPixelsStruct*)wParam;
+ SIZE loc = { cpps->srcx, cpps->srcy };
+ SIZE size = { cpps->srcw, cpps->srch };
+ retValue = (LRESULT)CreatePrintedPixels(loc, size, cpps->alpha);
mr = mrConsume;
break;
+ }
case WM_UNDOCUMENTED_CLICKMENUBAR:
{
if (::IsWindow(AwtWindow::GetModalBlocker(GetHWnd()))) {
mr = mrConsume;
}
@@ -3184,18 +3196,33 @@
{0x309B, java_awt_event_KeyEvent_VK_DEAD_VOICED_SOUND},
{0x309C, java_awt_event_KeyEvent_VK_DEAD_SEMIVOICED_SOUND},
{0,0}
};
+// The full map of the current keyboard state including
+// windows virtual key, scancode, java virtual key, and unicode
+// for this key sans modifiers.
+// All but first element may be 0.
+// XXX in the update releases this is an addition to the unchanged existing code
+struct DynPrimaryKeymapEntry {
+ UINT wkey;
+ UINT scancode;
+ UINT jkey;
+ WCHAR unicode;
+};
+
+static DynPrimaryKeymapEntry dynPrimaryKeymap[256];
void
AwtComponent::InitDynamicKeyMapTable()
{
static BOOL kbdinited = FALSE;
if (!kbdinited) {
AwtComponent::BuildDynamicKeyMapTable();
+ // We cannot build it here since JNI is not available yet:
+ //AwtComponent::BuildPrimaryDynamicTable();
kbdinited = TRUE;
}
}
void
@@ -3417,11 +3444,15 @@
}
}
for (int j = 0; dynamicKeyMapTable[j].windowsKey != 0; j++) {
if (dynamicKeyMapTable[j].windowsKey == windowsKey) {
+ if (dynamicKeyMapTable[j].javaKey != java_awt_event_KeyEvent_VK_UNDEFINED) {
return dynamicKeyMapTable[j].javaKey;
+ }else{
+ break;
+ }
}
}
return java_awt_event_KeyEvent_VK_UNDEFINED;
}
@@ -3479,10 +3510,126 @@
break;
}
return FALSE;
}
+static void
+resetKbdState( BYTE kstate[256]) {
+ BYTE tmpState[256];
+ WCHAR wc[2];
+ memmove(tmpState, kstate, sizeof(kstate));
+ tmpState[VK_SHIFT] = 0;
+ tmpState[VK_CONTROL] = 0;
+ tmpState[VK_MENU] = 0;
+
+ ::ToUnicodeEx(VK_SPACE,::MapVirtualKey(VK_SPACE, 0), tmpState, wc, 2, 0, GetKeyboardLayout(0));
+}
+
+// XXX in the update releases this is an addition to the unchanged existing code
+// After the call, a table will have a unicode associated with a windows virtual keycode
+// sans modifiers. With some further simplification, one can
+// derive java keycode from it, and anyway we will pass this unicode value
+// all the way up in a comment to a KeyEvent.
+void
+AwtComponent::BuildPrimaryDynamicTable() {
+ JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
+ // XXX: how about that?
+ //CriticalSection::Lock l(GetLock());
+ //if (GetPeer(env) == NULL) {
+ // /* event received during termination. */
+ // return;
+ //}
+
+ HKL hkl = GetKeyboardLayout();
+ UINT sc = 0;
+ BYTE kbdState[AwtToolkit::KB_STATE_SIZE];
+ memset(kbdState, 0, sizeof (kbdState));
+
+ // Use JNI call to obtain java key code. We should keep a list
+ // of currently available keycodes in a single place.
+ static jclass extKeyCodesCls;
+ if( extKeyCodesCls == NULL) {
+ jclass extKeyCodesClsLocal = env->FindClass("sun/awt/ExtendedKeyCodes");
+ DASSERT(extKeyCodesClsLocal);
+ if (extKeyCodesClsLocal == NULL) {
+ /* exception already thrown */
+ return;
+ }
+ extKeyCodesCls = (jclass)env->NewGlobalRef(extKeyCodesClsLocal);
+ env->DeleteLocalRef(extKeyCodesClsLocal);
+ }
+ static jmethodID getExtendedKeyCodeForChar;
+ if (getExtendedKeyCodeForChar == NULL) {
+ getExtendedKeyCodeForChar =
+ env->GetStaticMethodID(extKeyCodesCls, "getExtendedKeyCodeForChar", "(I)I");
+ DASSERT(getExtendedKeyCodeForChar);
+ }
+ jint extJKC; //extended Java key code
+
+ for (UINT i = 0; i < 256; i++) {
+ dynPrimaryKeymap[i].wkey = i;
+ dynPrimaryKeymap[i].jkey = java_awt_event_KeyEvent_VK_UNDEFINED;
+ dynPrimaryKeymap[i].unicode = 0;
+
+ if ((sc = MapVirtualKey (i, 0)) == 0) {
+ dynPrimaryKeymap[i].scancode = 0;
+ continue;
+ }
+ dynPrimaryKeymap[i].scancode = sc;
+
+ // XXX process cases like VK_SHIFT etc.
+ kbdState[i] = 0x80; // "key pressed".
+ WCHAR wc[16];
+ int k = ::ToUnicodeEx(i, sc, kbdState, wc, 16, 0, hkl);
+ if (k == 1) {
+ // unicode
+ dynPrimaryKeymap[i].unicode = wc[0];
+ if (dynPrimaryKeymap[i].jkey == java_awt_event_KeyEvent_VK_UNDEFINED) {
+ // Convert unicode to java keycode.
+ //dynPrimaryKeymap[i].jkey = ((UINT)(wc[0]) + 0x01000000);
+ //
+ //XXX If this key in on the keypad, we should force a special value equal to
+ //XXX an old java keycode: but how to say if it is a keypad key?
+ //XXX We'll do it in WmKeyUp/Down.
+ extJKC = env->CallStaticIntMethod(extKeyCodesCls,
+ getExtendedKeyCodeForChar, (jint)(wc[0]));
+ dynPrimaryKeymap[i].jkey = extJKC;
+ }
+ }else if (k == -1) {
+ // dead key: use charToDeadVKTable
+ dynPrimaryKeymap[i].unicode = wc[0];
+ resetKbdState( kbdState );
+ for (const CharToVKEntry *map = charToDeadVKTable; map->c != 0; ++map) {
+ if (wc[0] == map->c) {
+ dynPrimaryKeymap[i].jkey = map->javaKey;
+ break;
+ }
+ }
+ } else if (k == 0) {
+ // reset
+ resetKbdState( kbdState );
+ }else {
+ printf ("++++Whats that? wkey 0x%x (%d)\n", i,i);
+ }
+ kbdState[i] = 0; // "key unpressed"
+ }
+}
+void
+AwtComponent::UpdateDynPrimaryKeymap(UINT wkey, UINT jkeyLegacy, jint keyLocation, UINT modifiers)
+{
+ if( wkey && wkey < 256 ) {
+ if(keyLocation == java_awt_event_KeyEvent_KEY_LOCATION_NUMPAD) {
+ // At the creation time,
+ // dynPrimaryKeymap cannot distinguish between e.g. "/" and "NumPad /"
+ dynPrimaryKeymap[wkey].jkey = jkeyLegacy;
+ }
+ if(dynPrimaryKeymap[wkey].jkey == java_awt_event_KeyEvent_VK_UNDEFINED) {
+ // E.g. it is non-unicode key
+ dynPrimaryKeymap[wkey].jkey = jkeyLegacy;
+ }
+ }
+}
UINT AwtComponent::WindowsKeyToJavaChar(UINT wkey, UINT modifiers, TransOps ops)
{
static Hashtable transTable("VKEY translations");
@@ -3632,14 +3779,16 @@
UINT modifiers = GetJavaModifiers();
jint keyLocation = GetKeyLocation(wkey, flags);
UINT jkey = WindowsKeyToJavaKey(wkey, modifiers);
UINT character = WindowsKeyToJavaChar(wkey, modifiers, SAVE);
+ UpdateDynPrimaryKeymap(wkey, jkey, keyLocation, modifiers);
+
SendKeyEventToFocusOwner(java_awt_event_KeyEvent_KEY_PRESSED,
TimeHelper::windowsToUTC(msg.time), jkey, character,
- modifiers, keyLocation, &msg);
+ modifiers, keyLocation, (jlong)wkey, &msg);
// bugid 4724007: Windows does not create a WM_CHAR for the Del key
// for some reason, so we need to create the KEY_TYPED event on the
// WM_KEYDOWN. Use null msg so the character doesn't get sent back
// to the native window for processing (this event is synthesized
@@ -3647,11 +3796,11 @@
if (jkey == java_awt_event_KeyEvent_VK_DELETE) {
SendKeyEventToFocusOwner(java_awt_event_KeyEvent_KEY_TYPED,
TimeHelper::windowsToUTC(msg.time),
java_awt_event_KeyEvent_VK_UNDEFINED,
character, modifiers,
- java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN);
+ java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN, (jlong)0);
}
return mrConsume;
}
@@ -3672,14 +3821,15 @@
UINT modifiers = GetJavaModifiers();
jint keyLocation = GetKeyLocation(wkey, flags);
UINT jkey = WindowsKeyToJavaKey(wkey, modifiers);
UINT character = WindowsKeyToJavaChar(wkey, modifiers, LOAD);
+ UpdateDynPrimaryKeymap(wkey, jkey, keyLocation, modifiers);
SendKeyEventToFocusOwner(java_awt_event_KeyEvent_KEY_RELEASED,
TimeHelper::windowsToUTC(msg.time), jkey, character,
- modifiers, keyLocation, &msg);
+ modifiers, keyLocation, (jlong)wkey, &msg);
return mrConsume;
}
MsgRouting AwtComponent::WmInputLangChange(UINT charset, HKL hKeyboardLayout)
{
@@ -3691,10 +3841,11 @@
// keyboard layout handle instead.
m_hkl = hKeyboardLayout;
m_idLang = LOWORD(hKeyboardLayout); // lower word of HKL is LANGID
m_CodePage = LangToCodePage(m_idLang);
BuildDynamicKeyMapTable(); // compute new mappings for VK_OEM
+ BuildPrimaryDynamicTable();
return mrConsume; // do not propagate to children
}
// Convert Language ID to CodePage
UINT AwtComponent::LangToCodePage(LANGID idLang)
@@ -3721,11 +3872,11 @@
jint modifiers = GetJavaModifiers();
SendKeyEventToFocusOwner(java_awt_event_KeyEvent_KEY_TYPED,
TimeHelper::windowsToUTC(msg.time),
java_awt_event_KeyEvent_VK_UNDEFINED,
unicodeChar, modifiers,
- java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN,
+ java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN, (jlong)0,
&msg);
return mrConsume;
}
MsgRouting AwtComponent::WmChar(UINT character, UINT repCnt, UINT flags,
@@ -3806,11 +3957,11 @@
MAKELPARAM(repCnt, flags));
SendKeyEventToFocusOwner(java_awt_event_KeyEvent_KEY_TYPED,
TimeHelper::windowsToUTC(msg.time),
java_awt_event_KeyEvent_VK_UNDEFINED,
unicodeChar, modifiers,
- java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN,
+ java_awt_event_KeyEvent_KEY_LOCATION_UNKNOWN, (jlong)0,
&msg);
return mrConsume;
}
MsgRouting AwtComponent::WmForwardChar(WCHAR character, LPARAM lParam,
@@ -4699,22 +4850,24 @@
VERIFY(::FillRect(hMemoryDC, &eraseR, GetBackgroundBrush()));
}
void AwtComponent::FillAlpha(void *bitmapBits, SIZE &size, BYTE alpha)
{
- if (bitmapBits) {
+ if (!bitmapBits) {
+ return;
+ }
+
DWORD* dest = (DWORD*)bitmapBits;
- //XXX: might be optimized to use one loop (cy*cx -> 0).
+ //XXX: might be optimized to use one loop (cy*cx -> 0)
for (int i = 0; i < size.cy; i++ ) {
for (int j = 0; j < size.cx; j++ ) {
((BYTE*)(dest++))[3] = alpha;
}
}
- }
}
-jintArray AwtComponent::CreatePrintedPixels(SIZE &loc, SIZE &size) {
+jintArray AwtComponent::CreatePrintedPixels(SIZE &loc, SIZE &size, int alpha) {
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
if (!::IsWindowVisible(GetHWnd())) {
return NULL;
}
@@ -4722,23 +4875,31 @@
HDC hdc = GetDCFromComponent();
if (!hdc) {
return NULL;
}
HDC hMemoryDC = ::CreateCompatibleDC(hdc);
- HBITMAP hBitmap = ::CreateCompatibleBitmap(hdc, size.cx, size.cy);
+ void *bitmapBits = NULL;
+ HBITMAP hBitmap = BitmapUtil::CreateARGBBitmap(size.cx, size.cy, &bitmapBits);
HBITMAP hOldBitmap = (HBITMAP)::SelectObject(hMemoryDC, hBitmap);
SendMessage(WM_AWT_RELEASEDC, (WPARAM)hdc);
- RECT eraseR = { 0, 0, size.cx, size.cy };
- VERIFY(::FillRect(hMemoryDC, &eraseR, GetBackgroundBrush()));
+ FillBackground(hMemoryDC, size);
VERIFY(::SetWindowOrgEx(hMemoryDC, loc.cx, loc.cy, NULL));
// Don't bother with PRF_CHECKVISIBLE because we called IsWindowVisible
// above.
SendMessage(WM_PRINT, (WPARAM)hMemoryDC, PRF_CLIENT | PRF_NONCLIENT);
+ // First make sure the system completed any drawing to the bitmap.
+ ::GdiFlush();
+
+ // WM_PRINT does not fill the alpha-channel of the ARGB bitmap
+ // leaving it equal to zero. Hence we need to fill it manually. Otherwise
+ // the pixels will be considered transparent when interpreting the data.
+ FillAlpha(bitmapBits, size, alpha);
+
::SelectObject(hMemoryDC, hOldBitmap);
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(BITMAPINFO));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
@@ -4822,11 +4983,11 @@
child = child->m_next;
}
}
void AwtComponent::SendKeyEvent(jint id, jlong when, jint raw, jint cooked,
- jint modifiers, jint keyLocation, MSG *pMsg)
+ jint modifiers, jint keyLocation, jlong nativeCode, MSG *pMsg)
{
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
CriticalSection::Lock l(GetLock());
if (GetPeer(env) == NULL) {
/* event received during termination. */
@@ -4859,10 +5020,22 @@
id, when, modifiers, raw, cooked,
keyLocation);
if (safe_ExceptionOccurred(env)) env->ExceptionDescribe();
DASSERT(!safe_ExceptionOccurred(env));
DASSERT(keyEvent != NULL);
+ env->SetLongField(keyEvent, AwtKeyEvent::rawCodeID, nativeCode);
+ if( nativeCode && nativeCode < 256 ) {
+ env->SetLongField(keyEvent, AwtKeyEvent::primaryLevelUnicodeID, (jlong)(dynPrimaryKeymap[nativeCode].unicode));
+ env->SetLongField(keyEvent, AwtKeyEvent::extendedKeyCodeID, (jlong)(dynPrimaryKeymap[nativeCode].jkey));
+ if( nativeCode < 255 ) {
+ env->SetLongField(keyEvent, AwtKeyEvent::scancodeID, (jlong)(dynPrimaryKeymap[nativeCode].scancode));
+ }else if( pMsg != NULL ) {
+ // unknown key with virtual keycode 0xFF.
+ // Its scancode is not in the table, pickup it from the message.
+ env->SetLongField(keyEvent, AwtKeyEvent::scancodeID, (jlong)(HIWORD(pMsg->lParam) & 0xFF));
+ }
+ }
if (pMsg != NULL) {
AwtAWTEvent::saveMSG(env, pMsg, keyEvent);
}
SendEvent(keyEvent);
@@ -4872,31 +5045,32 @@
void
AwtComponent::SendKeyEventToFocusOwner(jint id, jlong when,
jint raw, jint cooked,
jint modifiers, jint keyLocation,
+ jlong nativeCode,
MSG *msg)
{
/*
* if focus owner is null, but focused window isn't
* we will send key event to focused window
*/
HWND hwndTarget = ((sm_focusOwner != NULL) ? sm_focusOwner : AwtComponent::GetFocusedWindow());
if (hwndTarget == GetHWnd()) {
- SendKeyEvent(id, when, raw, cooked, modifiers, keyLocation, msg);
+ SendKeyEvent(id, when, raw, cooked, modifiers, keyLocation, nativeCode, msg);
} else {
AwtComponent *target = NULL;
if (hwndTarget != NULL) {
target = AwtComponent::GetComponent(hwndTarget);
if (target == NULL) {
target = this;
}
}
if (target != NULL) {
target->SendKeyEvent(id, when, raw, cooked, modifiers,
- keyLocation, msg);
+ keyLocation, nativeCode, msg);
}
}
}
void AwtComponent::SetDragCapture(UINT flags)
@@ -6103,29 +6277,20 @@
{
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
CreatePrintedPixelsStruct *cpps = (CreatePrintedPixelsStruct *)param;
jobject self = cpps->component;
- jint srcx = cpps->srcx;
- jint srcy = cpps->srcy;
- jint srcw = cpps->srcw;
- jint srch = cpps->srch;
jintArray result = NULL;
AwtComponent *c = NULL;
PDATA pData;
JNI_CHECK_PEER_GOTO(self, ret);
c = (AwtComponent *)pData;
if (::IsWindow(c->GetHWnd()))
{
- SIZE loc = { srcx, srcy };
- SIZE size = { srcw, srch };
-
- result = (jintArray)
- c->SendMessage(WM_AWT_CREATE_PRINTED_PIXELS, (WPARAM)&loc,
- (LPARAM)&size);
+ result = (jintArray)c->SendMessage(WM_AWT_CREATE_PRINTED_PIXELS, (WPARAM)cpps, 0);
}
ret:
env->DeleteGlobalRef(self);
delete cpps;
@@ -6892,11 +7057,11 @@
* Method: createPrintedPixels
* Signature: (IIIIII)I[
*/
JNIEXPORT jintArray JNICALL
Java_sun_awt_windows_WComponentPeer_createPrintedPixels(JNIEnv* env,
- jobject self, jint srcX, jint srcY, jint srcW, jint srcH)
+ jobject self, jint srcX, jint srcY, jint srcW, jint srcH, jint alpha)
{
TRY;
jobject selfGlobalRef = env->NewGlobalRef(self);
@@ -6904,10 +7069,11 @@
cpps->component = selfGlobalRef;
cpps->srcx = srcX;
cpps->srcy = srcY;
cpps->srcw = srcW;
cpps->srch = srcH;
+ cpps->alpha = alpha;
jintArray globalRef = (jintArray)AwtToolkit::GetInstance().SyncCall(
(void*(*)(void*))AwtComponent::_CreatePrintedPixels, cpps);
// selfGlobalRef and cpps are deleted in _CreatePrintedPixels
if (globalRef != NULL)
< prev index next >