4717864: setFont() does not update Fonts of Menus already on screen
authorserb
Fri, 15 Jul 2011 19:25:06 +0400
changeset 10098 0674614189ba
parent 10097 67449ffe5991
child 10099 1887eb63f84c
4717864: setFont() does not update Fonts of Menus already on screen Reviewed-by: art, bagiras
jdk/src/windows/classes/sun/awt/windows/WMenuItemPeer.java
jdk/src/windows/native/sun/windows/awt_Menu.cpp
jdk/src/windows/native/sun/windows/awt_Menu.h
jdk/src/windows/native/sun/windows/awt_MenuBar.cpp
jdk/src/windows/native/sun/windows/awt_MenuBar.h
jdk/src/windows/native/sun/windows/awt_MenuItem.cpp
jdk/src/windows/native/sun/windows/awt_MenuItem.h
--- a/jdk/src/windows/classes/sun/awt/windows/WMenuItemPeer.java	Fri Jul 15 19:24:09 2011 +0400
+++ b/jdk/src/windows/classes/sun/awt/windows/WMenuItemPeer.java	Fri Jul 15 19:25:06 2011 +0400
@@ -183,7 +183,9 @@
      */
     private static native void initIDs();
 
-    // Needed for MenuComponentPeer.
-    public void setFont(Font f) {
+    private native void _setFont(Font f);
+
+    public void setFont(final Font f) {
+        _setFont(f);
     }
 }
--- a/jdk/src/windows/native/sun/windows/awt_Menu.cpp	Fri Jul 15 19:24:09 2011 +0400
+++ b/jdk/src/windows/native/sun/windows/awt_Menu.cpp	Fri Jul 15 19:25:06 2011 +0400
@@ -119,6 +119,41 @@
     return menu;
 }
 
+void AwtMenu::UpdateLayout()
+{
+    UpdateLayout(GetHMenu());
+    RedrawMenuBar();
+}
+
+void AwtMenu::UpdateLayout(const HMENU hmenu)
+{
+    const int nMenuItemCount = ::GetMenuItemCount(hmenu);
+    static MENUITEMINFO  mii;
+    for (int idx = 0; idx < nMenuItemCount; ++idx) {
+        memset(&mii, 0, sizeof(mii));
+        mii.cbSize = sizeof(mii);
+        mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID
+                  | MIIM_STATE | MIIM_SUBMENU | MIIM_TYPE;
+        if (::GetMenuItemInfo(hmenu, idx, TRUE, &mii)) {
+            VERIFY(::RemoveMenu(hmenu, idx, MF_BYPOSITION));
+            VERIFY(::InsertMenuItem(hmenu, idx, TRUE, &mii));
+            if (mii.hSubMenu !=  NULL) {
+                UpdateLayout(mii.hSubMenu);
+            }
+        }
+    }
+}
+
+void AwtMenu::UpdateContainerLayout()
+{
+    AwtMenu* menu = GetMenuContainer();
+    if (menu != NULL) {
+        menu->UpdateLayout();
+    } else {
+        UpdateLayout();
+    }
+}
+
 AwtMenuBar* AwtMenu::GetMenuBar() {
     return (GetMenuContainer() == NULL) ? NULL : GetMenuContainer()->GetMenuBar();
 }
--- a/jdk/src/windows/native/sun/windows/awt_Menu.h	Fri Jul 15 19:24:09 2011 +0400
+++ b/jdk/src/windows/native/sun/windows/awt_Menu.h	Fri Jul 15 19:25:06 2011 +0400
@@ -72,6 +72,8 @@
     virtual AwtMenuBar* GetMenuBar();
 
     void AddSeparator();
+    virtual void UpdateContainerLayout();
+    void UpdateLayout();
     virtual void AddItem(AwtMenuItem *item);
     virtual void DeleteItem(UINT index);
 
@@ -103,6 +105,7 @@
     virtual void RemoveCmdID() { /* do nothing */ }
 
 private:
+    void UpdateLayout(const HMENU hmenu);
     HMENU    m_hMenu;
 };
 
--- a/jdk/src/windows/native/sun/windows/awt_MenuBar.cpp	Fri Jul 15 19:24:09 2011 +0400
+++ b/jdk/src/windows/native/sun/windows/awt_MenuBar.cpp	Fri Jul 15 19:25:06 2011 +0400
@@ -198,7 +198,15 @@
     if (hOwnerWnd != NULL) {
         VERIFY(::InvalidateRect(hOwnerWnd,0,TRUE));
     }
-    ::DrawMenuBar(GetOwnerHWnd());
+    RedrawMenuBar();
+}
+
+/**
+ * If the menu changes after the system has created the window,
+ * this function must be called to draw the changed menu bar.
+ */
+void AwtMenuBar::RedrawMenuBar() {
+    VERIFY(::DrawMenuBar(GetOwnerHWnd()));
 }
 
 LRESULT AwtMenuBar::WinThreadExecProc(ExecuteArgs * args)
@@ -232,7 +240,7 @@
     if (::IsWindow(m->GetOwnerHWnd()))
     {
         /* The menu was already created and added during peer creation -- redraw */
-        ::DrawMenuBar(m->GetOwnerHWnd());
+        m->RedrawMenuBar();
     }
 ret:
     env->DeleteGlobalRef(self);
--- a/jdk/src/windows/native/sun/windows/awt_MenuBar.h	Fri Jul 15 19:24:09 2011 +0400
+++ b/jdk/src/windows/native/sun/windows/awt_MenuBar.h	Fri Jul 15 19:25:06 2011 +0400
@@ -65,6 +65,7 @@
     INLINE AwtFrame* GetFrame() { return m_frame; }
 
     virtual HWND GetOwnerHWnd();
+    virtual void RedrawMenuBar();
 
     AwtMenuItem* GetItem(jobject target, long index);
     int CountItem(jobject menuBar);
--- a/jdk/src/windows/native/sun/windows/awt_MenuItem.cpp	Fri Jul 15 19:24:09 2011 +0400
+++ b/jdk/src/windows/native/sun/windows/awt_MenuItem.cpp	Fri Jul 15 19:25:06 2011 +0400
@@ -626,7 +626,7 @@
     mii.dwTypeData = (LPTSTR)(*sb);
 
     // find index by menu item id
-    int nMenuItemCount = ::GetMenuItemCount(hMenu);;
+    int nMenuItemCount = ::GetMenuItemCount(hMenu);
     int idx;
     for (idx = 0; (idx < nMenuItemCount); idx++) {
         memset(&mii1, 0, sizeof(MENUITEMINFO));
@@ -639,10 +639,7 @@
     ::RemoveMenu(hMenu, idx, MF_BYPOSITION);
     ::InsertMenuItem(hMenu, idx, TRUE, &mii);
 
-    // Redraw menu bar if it was affected.
-    if (menu->GetMenuBar() == menu) {
-        ::DrawMenuBar(menu->GetOwnerHWnd());
-    }
+    RedrawMenuBar();
 }
 
 void AwtMenuItem::Enable(BOOL isEnabled)
@@ -658,10 +655,7 @@
                             MF_BYCOMMAND | (isEnabled ? MF_ENABLED : MF_GRAYED))
            != 0xFFFFFFFF);
 
-    // Redraw menu bar if it was affected.
-    if (menu->GetMenuBar() == menu) {
-        ::DrawMenuBar(menu->GetOwnerHWnd());
-    }
+    RedrawMenuBar();
 }
 
 void AwtMenuItem::SetState(BOOL isChecked)
@@ -676,23 +670,31 @@
                            MF_BYCOMMAND | (isChecked ? MF_CHECKED : MF_UNCHECKED))
            != 0xFFFFFFFF);
 
-    // Redraw menu bar if it was affected.
-    if (menu->GetMenuBar() == menu) {
-        ::DrawMenuBar(menu->GetOwnerHWnd());
+    RedrawMenuBar();
+}
+
+/**
+ * If the menu changes after the system has created the window,
+ * this function must be called to draw the changed menu bar.
+ */
+void AwtMenuItem::RedrawMenuBar() {
+    AwtMenu* menu = GetMenuContainer();
+    if (menu != NULL && menu->GetMenuBar() == menu){
+        menu->RedrawMenuBar();
+    }
+}
+
+void AwtMenuItem::UpdateContainerLayout() {
+    AwtMenu* menu = GetMenuContainer();
+    if (menu != NULL) {
+        DASSERT(menu != NULL && GetID() >= 0);
+        menu->UpdateLayout();
     }
 }
 
 LRESULT AwtMenuItem::WinThreadExecProc(ExecuteArgs * args)
 {
     switch( args->cmdId ) {
-        case MENUITEM_SETLABEL:
-        {
-            LPCTSTR sb = (LPCTSTR)args->param1;
-            DASSERT(!IsBadStringPtr(sb, 20));
-            this->SetLabel(sb);
-        }
-        break;
-
         case MENUITEM_ENABLE:
         {
             BOOL        isEnabled = (BOOL)args->param1;
@@ -714,75 +716,98 @@
     return 0L;
 }
 
-void AwtMenuItem::_SetLabel(void *param)
-{
-    JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
+void AwtMenuItem::_SetLabel(void *param) {
+    if (AwtToolkit::IsMainThread()) {
+        JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 
-    SetLabelStruct *sls = (SetLabelStruct *)param;
-    jobject self = sls->menuitem;
-    jstring label = sls->label;
+        SetLabelStruct *sls = (SetLabelStruct *)param;
+        jobject self = sls->menuitem;
+        jstring label = sls->label;
 
-    int badAlloc = 0;
-    AwtMenuItem *m = NULL;
+        int badAlloc = 0;
+        AwtMenuItem *m = NULL;
 
-    PDATA pData;
-    JNI_CHECK_PEER_GOTO(self, ret);
-    m = (AwtMenuItem *)pData;
+        PDATA pData;
+        JNI_CHECK_PEER_GOTO(self, ret);
+        m = (AwtMenuItem *)pData;
 //    if (::IsWindow(m->GetOwnerHWnd()))
-    {
-        // fix for bug 4251036 MenuItem setLabel(null/"") behaves differently
-        // under Win32 and Solaris
-        jstring empty = NULL;
-        if (JNU_IsNull(env, label))
         {
-            empty = JNU_NewStringPlatform(env, TEXT(""));
-        }
-        LPCTSTR labelPtr;
-        if (empty != NULL)
-        {
-            labelPtr = JNU_GetStringPlatformChars(env, empty, 0);
-        }
-        else
-        {
-            labelPtr = JNU_GetStringPlatformChars(env, label, 0);
-        }
-        if (labelPtr == NULL)
-        {
-            badAlloc = 1;
-        }
-        else
-        {
-            ExecuteArgs args;
-            args.cmdId = MENUITEM_SETLABEL;
-            args.param1 = (LPARAM)labelPtr;
-            m->WinThreadExecProc(&args);
+            // fix for bug 4251036 MenuItem setLabel(null/"") behaves differently
+            // under Win32 and Solaris
+            jstring empty = NULL;
+            if (JNU_IsNull(env, label))
+            {
+                empty = JNU_NewStringPlatform(env, TEXT(""));
+            }
+            LPCTSTR labelPtr;
             if (empty != NULL)
             {
-                JNU_ReleaseStringPlatformChars(env, empty, labelPtr);
+                labelPtr = JNU_GetStringPlatformChars(env, empty, 0);
+            }
+            else
+            {
+                labelPtr = JNU_GetStringPlatformChars(env, label, 0);
+            }
+            if (labelPtr == NULL)
+            {
+                badAlloc = 1;
             }
             else
             {
-                JNU_ReleaseStringPlatformChars(env, label, labelPtr);
+                DASSERT(!IsBadStringPtr(labelPtr, 20));
+                m->SetLabel(labelPtr);
+                if (empty != NULL)
+                {
+                    JNU_ReleaseStringPlatformChars(env, empty, labelPtr);
+                }
+                else
+                {
+                    JNU_ReleaseStringPlatformChars(env, label, labelPtr);
+                }
+            }
+            if (empty != NULL)
+            {
+                env->DeleteLocalRef(empty);
             }
         }
-        if (empty != NULL)
-        {
-            env->DeleteLocalRef(empty);
-        }
-    }
 
 ret:
-    env->DeleteGlobalRef(self);
-    if (label != NULL)
-    {
-        env->DeleteGlobalRef(label);
+        env->DeleteGlobalRef(self);
+        if (label != NULL)
+        {
+            env->DeleteGlobalRef(label);
+        }
+
+        delete sls;
+
+        if (badAlloc)
+        {
+            throw std::bad_alloc();
+        }
+    } else {
+        AwtToolkit::GetInstance().InvokeFunction(AwtMenuItem::_SetLabel, param);
     }
+}
 
-    delete sls;
+void AwtMenuItem::_UpdateLayout(void *param)
+{
+    if (AwtToolkit::IsMainThread()) {
+        JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
+
+        jobject self = (jobject)param;
+
+        AwtMenuItem *m = NULL;
 
-    if (badAlloc)
-    {
-        throw std::bad_alloc();
+        PDATA pData;
+        JNI_CHECK_PEER_GOTO(self, ret);
+
+        m = (AwtMenuItem *)pData;
+
+        m->UpdateContainerLayout();
+ret:
+        env->DeleteGlobalRef(self);
+    } else {
+        AwtToolkit::GetInstance().InvokeFunction(AwtMenuItem::_UpdateLayout, param);
     }
 }
 
@@ -883,8 +908,8 @@
 
 /*
  * Class:     sun_awt_windows_WMenuItemPeer
- * Method:    _setLabel
- * Signature: (Ljava/lang/String;)V
+ * Method:    initIDs
+ * Signature: ()V
  */
 JNIEXPORT void JNICALL
 Java_sun_awt_windows_WMenuItemPeer_initIDs(JNIEnv *env, jclass cls)
@@ -927,6 +952,26 @@
 
 /*
  * Class:     sun_awt_windows_WMenuItemPeer
+ * Method:    _setFont
+ * Signature: (Ljava/awt/Font;)V
+ */
+JNIEXPORT void JNICALL
+Java_sun_awt_windows_WMenuItemPeer__1setFont(JNIEnv *env, jobject self, jobject)
+{
+    TRY;
+
+    jobject selfGlobalRef = env->NewGlobalRef(self);
+
+    // Current implementation of AwtMenuItem get font attribute from the peer
+    // directly, so we ignore it here, but update current menu layout.
+    AwtToolkit::GetInstance().SyncCall(AwtMenuItem::_UpdateLayout, selfGlobalRef);
+    // selfGlobalRef is deleted in _UpdateLayout
+
+    CATCH_BAD_ALLOC;
+}
+
+/*
+ * Class:     sun_awt_windows_WMenuItemPeer
  * Method:    create
  * Signature: (Lsun/awt/windows/WMenuPeer;)V
  */
--- a/jdk/src/windows/native/sun/windows/awt_MenuItem.h	Fri Jul 15 19:24:09 2011 +0400
+++ b/jdk/src/windows/native/sun/windows/awt_MenuItem.h	Fri Jul 15 19:25:06 2011 +0400
@@ -48,7 +48,6 @@
 public:
     // id's for methods executed on toolkit thread
     enum {
-        MENUITEM_SETLABEL,
         MENUITEM_ENABLE,
         MENUITEM_SETSTATE,
         MENUITEM_LAST
@@ -78,7 +77,6 @@
 
     virtual LPCTSTR GetClassName();
 
-    void AwtMenuItem::LinkObjects(jobject peer);
     static AwtMenuItem* Create(jobject self, jobject menu);
 
     INLINE AwtMenu* GetMenuContainer() { return m_menuContainer; }
@@ -148,6 +146,8 @@
 
     void SetLabel(LPCTSTR sb);
     virtual void Enable(BOOL isEnabled);
+    virtual void UpdateContainerLayout();
+    virtual void RedrawMenuBar();
     void SetState(BOOL isChecked);
 
     /*
@@ -163,6 +163,7 @@
 
     // invoked on Toolkit thread
     static void _SetLabel(void *param);
+    static void _UpdateLayout(void *param);
 
 protected:
     AwtMenu* m_menuContainer;  /* The menu object containing this item */