< 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 >