changeset 6360:e6dbd26e20c2

8021275: Better screening for ScreenMenu Reviewed-by: art
author serb
date Thu, 10 Oct 2013 16:07:40 +0100
parents 664dbef2bca9
children 17829ce31387
files src/macosx/classes/com/apple/laf/ScreenMenu.java
diffstat 1 files changed, 69 insertions(+), 61 deletions(-) [+]
line wrap: on
line diff
--- a/src/macosx/classes/com/apple/laf/ScreenMenu.java	Mon Jul 22 14:06:39 2013 -0700
+++ b/src/macosx/classes/com/apple/laf/ScreenMenu.java	Thu Oct 10 16:07:40 2013 +0100
@@ -36,26 +36,31 @@
 import sun.lwawt.LWToolkit;
 import sun.lwawt.macosx.*;
 
-class ScreenMenu extends Menu implements ContainerListener, ComponentListener, ScreenMenuPropertyHandler {
+final class ScreenMenu extends Menu
+        implements ContainerListener, ComponentListener,
+                   ScreenMenuPropertyHandler {
+
     static {
         java.security.AccessController.doPrivileged((PrivilegedAction<?>)new sun.security.action.LoadLibraryAction("awt"));
     }
 
     // screen menu stuff
-    public static native long addMenuListeners(ScreenMenu listener, long nativeMenu);
-    public static native void removeMenuListeners(long modelPtr);
+    private static native long addMenuListeners(ScreenMenu listener, long nativeMenu);
+    private static native void removeMenuListeners(long modelPtr);
 
-    long fModelPtr = 0;
+    private transient long fModelPtr;
 
-    Hashtable<Component, MenuItem> fItems;
-    JMenu fInvoker;
+    private final Hashtable<Component, MenuItem> fItems;
+    private final JMenu fInvoker;
 
-    Component fLastMouseEventTarget;
-    Rectangle fLastTargetRect;
+    private Component fLastMouseEventTarget;
+    private Rectangle fLastTargetRect;
     private volatile Rectangle[] fItemBounds;
 
+    private ScreenMenuPropertyListener fPropertyListener;
+
     // Array of child hashes used to see if we need to recreate the Menu.
-    int childHashArray[];
+    private int childHashArray[];
 
     ScreenMenu(final JMenu invoker) {
         super(invoker.getText());
@@ -68,25 +73,12 @@
         updateItems();
     }
 
-    // I'm always 'visible', but never on screen
-    static class ScreenMenuComponent extends Container {
-        public boolean isVisible() { return true; }
-        public boolean isShowing() { return true; }
-        public void setVisible(final boolean b) {}
-        public void show() {}
-    }
-
-    ScreenMenuComponent makeScreenMenuComponent() {
-        return new ScreenMenuComponent();
-    }
-
-
     /**
      * Determine if we need to tear down the Menu and re-create it, since the contents may have changed in the Menu opened listener and
      * we do not get notified of it, because EDT is busy in our code. We only need to update if the menu contents have changed in some
      * way, such as the number of menu items, the text of the menuitems, icon, shortcut etc.
      */
-    static boolean needsUpdate(final Component items[], final int childHashArray[]) {
+    private static boolean needsUpdate(final Component items[], final int childHashArray[]) {
       if (items == null || childHashArray == null) {
         return true;
       }
@@ -106,7 +98,7 @@
      * Used to recreate the AWT based Menu structure that implements the Screen Menu.
      * Also computes hashcode and stores them so that we can compare them later in needsUpdate.
      */
-    void updateItems() {
+    private void updateItems() {
         final int count = fInvoker.getMenuComponentCount();
         final Component[] items = fInvoker.getMenuComponents();
         if (needsUpdate(items, childHashArray)) {
@@ -231,49 +223,56 @@
         });
     }
 
-    ScreenMenuPropertyListener fPropertyListener;
+    @Override
     public void addNotify() {
-        super.addNotify();
-        if (fModelPtr == 0) {
-        fInvoker.addContainerListener(this);
-        fInvoker.addComponentListener(this);
-        fPropertyListener = new ScreenMenuPropertyListener(this);
-        fInvoker.addPropertyChangeListener(fPropertyListener);
+        synchronized (getTreeLock()) {
+            super.addNotify();
+            if (fModelPtr == 0) {
+                fInvoker.addContainerListener(this);
+                fInvoker.addComponentListener(this);
+                fPropertyListener = new ScreenMenuPropertyListener(this);
+                fInvoker.addPropertyChangeListener(fPropertyListener);
 
-        final Icon icon = fInvoker.getIcon();
-        if (icon != null) {
-            this.setIcon(icon);
-        }
+                final Icon icon = fInvoker.getIcon();
+                if (icon != null) {
+                    setIcon(icon);
+                }
 
-        final String tooltipText = fInvoker.getToolTipText();
-        if (tooltipText != null) {
-            this.setToolTipText(tooltipText);
-        }
-        final MenuComponentPeer peer = getPeer();
-        if (peer instanceof CMenu) {
-            final CMenu menu = (CMenu)peer;
-            final long nativeMenu = menu.getNativeMenu();
-            fModelPtr = addMenuListeners(this, nativeMenu);
+                final String tooltipText = fInvoker.getToolTipText();
+                if (tooltipText != null) {
+                    setToolTipText(tooltipText);
+                }
+                final MenuComponentPeer peer = getPeer();
+                if (peer instanceof CMenu) {
+                    final CMenu menu = (CMenu) peer;
+                    final long nativeMenu = menu.getNativeMenu();
+                    fModelPtr = addMenuListeners(this, nativeMenu);
+                }
             }
         }
     }
 
+    @Override
     public void removeNotify() {
-        // Call super so that the NSMenu has been removed, before we release the delegate in removeMenuListeners
-        super.removeNotify();
-        fItems.clear();
-        if (fModelPtr != 0) {
-            removeMenuListeners(fModelPtr);
-            fModelPtr = 0;
-            fInvoker.removeContainerListener(this);
-            fInvoker.removeComponentListener(this);
-            fInvoker.removePropertyChangeListener(fPropertyListener);
+        synchronized (getTreeLock()) {
+            // Call super so that the NSMenu has been removed, before we release
+            // the delegate in removeMenuListeners
+            super.removeNotify();
+            fItems.clear();
+            if (fModelPtr != 0) {
+                removeMenuListeners(fModelPtr);
+                fModelPtr = 0;
+                fInvoker.removeContainerListener(this);
+                fInvoker.removeComponentListener(this);
+                fInvoker.removePropertyChangeListener(fPropertyListener);
+            }
         }
     }
 
     /**
      * Invoked when a component has been added to the container.
      */
+    @Override
     public void componentAdded(final ContainerEvent e) {
         addItem(e.getChild());
     }
@@ -281,23 +280,26 @@
     /**
      * Invoked when a component has been removed from the container.
      */
+    @Override
     public void componentRemoved(final ContainerEvent e) {
         final Component child = e.getChild();
         final MenuItem sm = fItems.get(child);
         if (sm == null) return;
 
-            remove(sm);
-            fItems.remove(sm);
-        }
+        remove(sm);
+        fItems.remove(sm);
+    }
 
     /**
      * Invoked when the component's size changes.
      */
+    @Override
     public void componentResized(final ComponentEvent e) {}
 
     /**
      * Invoked when the component's position changes.
      */
+    @Override
     public void componentMoved(final ComponentEvent e) {}
 
     /**
@@ -305,6 +307,7 @@
      * See componentHidden - we should still have a MenuItem
      * it just isn't inserted
      */
+    @Override
     public void componentShown(final ComponentEvent e) {
         setVisible(true);
     }
@@ -315,11 +318,12 @@
      * so we remove the ScreenMenuItem from the ScreenMenu
      * but leave it in fItems
      */
+    @Override
     public void componentHidden(final ComponentEvent e) {
         setVisible(false);
     }
 
-    public void setVisible(final boolean b) {
+    private void setVisible(final boolean b) {
         // Tell our parent to add/remove us
         final MenuContainer parent = getParent();
 
@@ -327,20 +331,24 @@
             if (parent instanceof ScreenMenu) {
                 final ScreenMenu sm = (ScreenMenu)parent;
                 sm.setChildVisible(fInvoker, b);
-    }
+            }
         }
     }
 
+    @Override
     public void setChildVisible(final JMenuItem child, final boolean b) {
         fItems.remove(child);
         updateItems();
     }
 
+    @Override
     public void setAccelerator(final KeyStroke ks) {}
 
     // only check and radio items can be indeterminate
+    @Override
     public void setIndeterminate(boolean indeterminate) { }
 
+    @Override
     public void setToolTipText(final String text) {
         final MenuComponentPeer peer = getPeer();
         if (!(peer instanceof CMenuItem)) return;
@@ -349,6 +357,7 @@
         cmi.setToolTipText(text);
     }
 
+    @Override
     public void setIcon(final Icon i) {
         final MenuComponentPeer peer = getPeer();
         if (!(peer instanceof CMenuItem)) return;
@@ -368,9 +377,8 @@
     /**
      * Gets a hashCode for a JMenu or JMenuItem or subclass so that we can compare for
      * changes in the Menu.
-     *
      */
-    static int getHashCode(final Component m) {
+    private static int getHashCode(final Component m) {
         int hashCode = m.hashCode();
 
         if (m instanceof JMenuItem) {
@@ -402,7 +410,7 @@
         return hashCode;
     }
 
-    void addItem(final Component m) {
+    private void addItem(final Component m) {
         if (!m.isVisible()) return;
         MenuItem sm = fItems.get(m);