While working on an app that makes use of threading (the app is based on the commercial Espresso toolkit, a Swing-alike toolkit based on AWT), I noticed that we don't tree-lock some methods in Component/Container that must be tree-locked. Generally we must synchronize on:

- coode that changes the state of the peer
- code that changes the structure of the component tree
- code that affects the layout of the component tree
- code that somehow accesses the above 3 points (like getLocationOnScreen depends on the structure and layout, and thus must be locked)

I added locking to a couple of places that seem critical. That's basically all I could make up from reading my AWT books, the specs and pure thinking (yay!).

2006-07-14  Roman Kennke  <[EMAIL PROTECTED]>

        * java/awt/Component.java
        (enable): Added tree locking.
        (disable): Added tree locking.
        (show): Added tree locking.
        (hide): Added tree locking.
        (getLocationOnScreen): Added tree locking.
        (reshape): Added tree locking.
        (addHierarchyListener): Added tree locking.
        (removeHierarchyListener): Added tree locking.
        (addHierarchyBoundsListener): Added tree locking.
        (removeHierarchyBoundsListener): Added tree locking.
        (addNotify): Added tree locking.
        (removeNotify): Added tree locking.
        * java/awt/Container.java
        (invalidateTree): Added tree locking.
        (getAlignmentX): Added tree locking.
        (getAlignmentY): Added tree locking.
        (addNotify): Added tree locking.
        (setComponentZOrder): Added tree locking.
        (getComponentZOrder): Added tree locking.


/Roman
Index: java/awt/Component.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/awt/Component.java,v
retrieving revision 1.134
diff -u -1 -2 -r1.134 Component.java
--- java/awt/Component.java	14 Jul 2006 10:27:17 -0000	1.134
+++ java/awt/Component.java	14 Jul 2006 11:49:08 -0000
@@ -842,54 +842,70 @@
   public void setEnabled(boolean enabled)
   {
     enable(enabled);
   }
 
   /**
    * Enables this component.
    *
    * @deprecated use [EMAIL PROTECTED] #setEnabled(boolean)} instead
    */
   public void enable()
   {
-    this.enabled = true;
-    if (peer != null)
-      peer.setEnabled (true);
+    if (! enabled)
+      {
+        // Need to lock the tree here, because the peers are involved.
+        synchronized (getTreeLock())
+          {
+            enabled = true;
+            ComponentPeer p = peer;
+            if (p != null)
+              p.enable();
+          }
+      }
   }
 
   /**
    * Enables or disables this component.
    *
    * @param enabled true to enable this component
    * 
    * @deprecated use [EMAIL PROTECTED] #setEnabled(boolean)} instead
    */
   public void enable(boolean enabled)
   {
     if (enabled)
       enable();
     else
       disable();
   }
 
   /**
    * Disables this component.
    *
    * @deprecated use [EMAIL PROTECTED] #setEnabled(boolean)} instead
    */
   public void disable()
   {
-    this.enabled = false;
-    if (peer != null)
-      peer.setEnabled (false);
+    if (enabled)
+      {
+        // Need to lock the tree here, because the peers are involved.
+        synchronized (getTreeLock())
+          {
+            enabled = false;
+            ComponentPeer p = peer;
+            if (p != null)
+              p.disable();
+          }
+      }
   }
 
   /**
    * Checks if this image is painted to an offscreen image buffer that is
    * later copied to screen (double buffering reduces flicker). This version
    * returns false, so subclasses must override it if they provide double
    * buffering.
    *
    * @return true if this is double buffered; defaults to false
    */
   public boolean isDoubleBuffered()
   {
@@ -936,57 +952,63 @@
    *
    * @deprecated use [EMAIL PROTECTED] #setVisible(boolean)} instead
    */
   public void show()
   {
     // We must set visible before showing the peer.  Otherwise the
     // peer could post paint events before visible is true, in which
     // case lightweight components are not initially painted --
     // Container.paint first calls isShowing () before painting itself
     // and its children.
     if(!isVisible())
       {
-        this.visible = true;
-        // Avoid NullPointerExceptions by creating a local reference.
-        ComponentPeer currentPeer=peer;
-        if (currentPeer != null)
+        // Need to lock the tree here to avoid races and inconsistencies.
+        synchronized (getTreeLock())
           {
-            currentPeer.show();
+            visible = true;
+            // Avoid NullPointerExceptions by creating a local reference.
+            ComponentPeer currentPeer=peer;
+            if (currentPeer != null)
+              {
+                currentPeer.show();
+
+                // Fire HierarchyEvent.
+                fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED,
+                                   this, parent,
+                                   HierarchyEvent.SHOWING_CHANGED);
+
+                // The JDK repaints the component before invalidating the parent.
+                // So do we.
+                if (isLightweight())
+                  repaint();
+              }
 
-            // Fire HierarchyEvent.
-            fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED,
-                               this, parent,
-                               HierarchyEvent.SHOWING_CHANGED);
-
-            // The JDK repaints the component before invalidating the parent.
-            // So do we.
-            if (isLightweight())
-              repaint();
+            // Only post an event if this component actually has a listener
+            // or has this event explicitly enabled.
+            if (componentListener != null
+                || (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0)
+              {
+                ComponentEvent ce =
+                  new ComponentEvent(this,ComponentEvent.COMPONENT_SHOWN);
+                getToolkit().getSystemEventQueue().postEvent(ce);
+              }
           }
+
         // Invalidate the parent if we have one. The component itself must
         // not be invalidated. We also avoid NullPointerException with
         // a local reference here.
         Container currentParent = parent;
         if (currentParent != null)
           currentParent.invalidate();
 
-        // Only post an event if this component actually has a listener
-        // or has this event explicitly enabled.
-        if (componentListener != null
-            || (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0)
-          {
-            ComponentEvent ce =
-              new ComponentEvent(this,ComponentEvent.COMPONENT_SHOWN);
-            getToolkit().getSystemEventQueue().postEvent(ce);
-          }
       }
   }
 
   /**
    * Makes this component visible or invisible.
    *
    * @param visible true to make this component visible
    * 
    * @deprecated use [EMAIL PROTECTED] #setVisible(boolean)} instead
    */
   public void show(boolean visible)
   {
@@ -996,59 +1018,63 @@
       hide();
   }
 
   /**
    * Hides this component so that it is no longer shown on the screen.
    *
    * @deprecated use [EMAIL PROTECTED] #setVisible(boolean)} instead
    */
   public void hide()
   {
     if (isVisible())
       {
-        // Avoid NullPointerExceptions by creating a local reference.
-        ComponentPeer currentPeer=peer;
-        if (currentPeer != null)
+        // Need to lock the tree here to avoid races and inconsistencies.
+        synchronized (getTreeLock())
           {
-            currentPeer.hide();
+            visible = false;
 
-            // Fire hierarchy event.
-            fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED,
-                                     this, parent,
-                                     HierarchyEvent.SHOWING_CHANGED);
-          }
+            // Avoid NullPointerExceptions by creating a local reference.
+            ComponentPeer currentPeer=peer;
+            if (currentPeer != null)
+              {
+                currentPeer.hide();
 
-        boolean wasShowing = isShowing();
-        this.visible = false;
+                // Fire hierarchy event.
+                fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED,
+                                   this, parent,
+                                   HierarchyEvent.SHOWING_CHANGED);
+                // The JDK repaints the component before invalidating the
+                // parent. So do we. This only applies for lightweights.
+                if (peer instanceof LightweightPeer)
+                  repaint();
+              }
 
-        // The JDK repaints the component before invalidating the parent.
-        // So do we.
-        if (wasShowing)
-          repaint();
-        // Invalidate the parent if we have one. The component itself must
+            // Only post an event if this component actually has a listener
+            // or has this event explicitly enabled.
+            if (componentListener != null
+                || (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0)
+              {
+                ComponentEvent ce =
+                  new ComponentEvent(this,ComponentEvent.COMPONENT_HIDDEN);
+                getToolkit().getSystemEventQueue().postEvent(ce);
+              }
+          }
+
+        // Invalidate the parent if we have one. The component itself need
         // not be invalidated. We also avoid NullPointerException with
         // a local reference here.
         Container currentParent = parent;
         if (currentParent != null)
           currentParent.invalidate();
 
-        // Only post an event if this component actually has a listener
-        // or has this event explicitly enabled.
-        if (componentListener != null
-            || (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0)
-          {
-            ComponentEvent ce =
-              new ComponentEvent(this,ComponentEvent.COMPONENT_HIDDEN);
-            getToolkit().getSystemEventQueue().postEvent(ce);
-          }
       }
   }
 
   /**
    * Returns this component's foreground color. If not set, this is inherited
    * from the parent.
    *
    * @return this component's foreground color, or null
    * @see #setForeground(Color)
    */
   public Color getForeground()
   {
@@ -1251,26 +1277,33 @@
    * Returns the location of this component's top left corner in screen
    * coordinates.
    *
    * @return the location of this component in screen coordinates
    * @throws IllegalComponentStateException if the component is not showing
    */
   public Point getLocationOnScreen()
   {
     if (! isShowing())
       throw new IllegalComponentStateException("component "
                                                + getClass().getName()
                                                + " not showing");
-    // We know peer != null here.
-    return peer.getLocationOnScreen();
+
+    // Need to lock the tree here. We get crazy races and explosions when
+    // the tree changes while we are trying to find the location of this
+    // component.
+    synchronized (getTreeLock())
+      {
+        // We know peer != null here.
+        return peer.getLocationOnScreen();
+      }
   }
 
   /**
    * Returns the location of this component's top left corner relative to
    * its parent component.
    *
    * @return the location of this component
    * @deprecated use [EMAIL PROTECTED] #getLocation()} instead
    */
   public Point location()
   {
     return new Point (x, y);
@@ -1446,101 +1479,106 @@
   /**
    * Sets the bounding rectangle for this component to the specified values.
    * Note that these coordinates are relative to the parent, not to the screen.
    *
    * @param x the X coordinate of the upper left corner of the rectangle
    * @param y the Y coordinate of the upper left corner of the rectangle
    * @param width the width of the rectangle
    * @param height the height of the rectangle
    * @deprecated use [EMAIL PROTECTED] #setBounds(int, int, int, int)} instead
    */
   public void reshape(int x, int y, int width, int height)
   {
-    int oldx = this.x;
-    int oldy = this.y;
-    int oldwidth = this.width;
-    int oldheight = this.height;
+    // We need to lock the tree here, otherwise we risk races and
+    // inconsistencies.
+    synchronized (getTreeLock())
+      {
+        int oldx = this.x;
+        int oldy = this.y;
+        int oldwidth = this.width;
+        int oldheight = this.height;
     
-    if (this.x == x && this.y == y && this.width == width
-        && this.height == height)
-      return;
+        if (this.x == x && this.y == y && this.width == width
+            && this.height == height)
+          return;
 
-    invalidate();
+        invalidate();
     
-    this.x = x;
-    this.y = y;
-    this.width = width;
-    this.height = height;
-    if (peer != null)
-      peer.setBounds (x, y, width, height);
+        this.x = x;
+        this.y = y;
+        this.width = width;
+        this.height = height;
+        if (peer != null)
+          peer.setBounds (x, y, width, height);
     
-    // Erase old bounds and repaint new bounds for lightweights.
-    if (isLightweight() && isShowing())
-      {
-        if (parent != null)
+        // Erase old bounds and repaint new bounds for lightweights.
+        if (isLightweight() && isShowing())
           {
-            Rectangle oldBounds = new Rectangle(oldx, oldy, oldwidth,
-                                                oldheight);
-            Rectangle newBounds = new Rectangle(x, y, width, height);
-            Rectangle destroyed = oldBounds.union(newBounds);
-            if (!destroyed.isEmpty())
-              parent.repaint(0, destroyed.x, destroyed.y, destroyed.width,
-                             destroyed.height);
+            if (parent != null)
+              {
+                Rectangle oldBounds = new Rectangle(oldx, oldy, oldwidth,
+                                                    oldheight);
+                Rectangle newBounds = new Rectangle(x, y, width, height);
+                Rectangle destroyed = oldBounds.union(newBounds);
+                if (!destroyed.isEmpty())
+                  parent.repaint(0, destroyed.x, destroyed.y, destroyed.width,
+                                 destroyed.height);
+              }
           }
-      }
 
-    boolean resized = oldwidth != width || oldheight != height;
-    boolean moved = oldx != x || oldy != y;
-    // Only post an event if this component actually has a listener
-    // or has this event explicitly enabled.
-    if (componentListener != null
-        || (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0)
-      {
-        // Fire component event on this component.
-        if (moved)
-          {
-            ComponentEvent ce = new ComponentEvent(this,
-                                              ComponentEvent.COMPONENT_MOVED);
-            getToolkit().getSystemEventQueue().postEvent(ce);
-          }
-        if (resized)
+        boolean resized = oldwidth != width || oldheight != height;
+        boolean moved = oldx != x || oldy != y;
+        // Only post an event if this component actually has a listener
+        // or has this event explicitly enabled.
+        if (componentListener != null
+            || (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0)
           {
-            ComponentEvent ce = new ComponentEvent(this,
+            // Fire component event on this component.
+            if (moved)
+              {
+                ComponentEvent ce = new ComponentEvent(this,
+                                               ComponentEvent.COMPONENT_MOVED);
+                getToolkit().getSystemEventQueue().postEvent(ce);
+              }
+            if (resized)
+              {
+                ComponentEvent ce = new ComponentEvent(this,
                                              ComponentEvent.COMPONENT_RESIZED);
-            getToolkit().getSystemEventQueue().postEvent(ce);
+                getToolkit().getSystemEventQueue().postEvent(ce);
+              }
           }
-      }
-    else
-      {
-        // Otherwise we might need to notify child components when this is
-        // a Container.
-        if (this instanceof Container)
+        else
           {
-            Container cont = (Container) this;
-            if (resized)
+            // Otherwise we might need to notify child components when this is
+            // a Container.
+            if (this instanceof Container)
               {
-                for (int i = 0; i < cont.getComponentCount(); i++)
+                Container cont = (Container) this;
+                if (resized)
                   {
-                    Component child = cont.getComponent(i);
-                    child.fireHierarchyEvent(HierarchyEvent.ANCESTOR_RESIZED,
-                                             this, parent, 0);
+                    for (int i = 0; i < cont.getComponentCount(); i++)
+                      {
+                        Component child = cont.getComponent(i);
+                        child.fireHierarchyEvent(HierarchyEvent.ANCESTOR_RESIZED,
+                                                 this, parent, 0);
+                      }
                   }
-              }
-            if (moved)
-              {
-                for (int i = 0; i < cont.getComponentCount(); i++)
+                if (moved)
                   {
-                    Component child = cont.getComponent(i);
-                    child.fireHierarchyEvent(HierarchyEvent.ANCESTOR_MOVED,
-                                             this, parent, 0);
+                    for (int i = 0; i < cont.getComponentCount(); i++)
+                      {
+                        Component child = cont.getComponent(i);
+                        child.fireHierarchyEvent(HierarchyEvent.ANCESTOR_MOVED,
+                                                 this, parent, 0);
+                      }
                   }
               }
           }
       }
   }
 
   /**
    * Sets the bounding rectangle for this component to the specified
    * rectangle. Note that these coordinates are relative to the parent, not
    * to the screen.
    *
    * @param r the new bounding rectangle
@@ -2738,46 +2776,55 @@
    * @param listener the new listener to add
    * @see HierarchyEvent
    * @see #removeHierarchyListener(HierarchyListener)
    * @see #getHierarchyListeners()
    * @since 1.3
    */
   public synchronized void addHierarchyListener(HierarchyListener listener)
   {
     hierarchyListener = AWTEventMulticaster.add(hierarchyListener, listener);
     if (hierarchyListener != null)
       enableEvents(AWTEvent.HIERARCHY_EVENT_MASK);
 
-    numHierarchyListeners++;
-    if (parent != null)
-      parent.updateHierarchyListenerCount(AWTEvent.HIERARCHY_EVENT_MASK, 1);
+    // Need to lock the tree, otherwise we might end up inconsistent.
+    synchronized (getTreeLock())
+      {
+        numHierarchyListeners++;
+        if (parent != null)
+          parent.updateHierarchyListenerCount(AWTEvent.HIERARCHY_EVENT_MASK, 1);
+      }
   }
 
   /**
    * Removes the specified listener from the component. This is harmless if
    * the listener was not previously registered.
    *
    * @param listener the listener to remove
    * @see HierarchyEvent
    * @see #addHierarchyListener(HierarchyListener)
    * @see #getHierarchyListeners()
    * @since 1.3
    */
   public synchronized void removeHierarchyListener(HierarchyListener listener)
   {
     hierarchyListener = AWTEventMulticaster.remove(hierarchyListener, listener);
 
-    numHierarchyListeners--;
-    if (parent != null)
-      parent.updateHierarchyListenerCount(AWTEvent.HIERARCHY_EVENT_MASK, -1);
+    // Need to lock the tree, otherwise we might end up inconsistent.
+    synchronized (getTreeLock())
+      {
+        numHierarchyListeners--;
+        if (parent != null)
+          parent.updateHierarchyListenerCount(AWTEvent.HIERARCHY_EVENT_MASK,
+                                              -1);
+      }
   }
 
   /**
    * Returns an array of all specified listeners registered on this component.
    *
    * @return an array of listeners
    * @see #addHierarchyListener(HierarchyListener)
    * @see #removeHierarchyListener(HierarchyListener)
    * @since 1.4
    */
   public synchronized HierarchyListener[] getHierarchyListeners()
   {
@@ -2796,50 +2843,60 @@
    * @see #removeHierarchyBoundsListener(HierarchyBoundsListener)
    * @see #getHierarchyBoundsListeners()
    * @since 1.3
    */
   public synchronized void
     addHierarchyBoundsListener(HierarchyBoundsListener listener)
   {
     hierarchyBoundsListener =
       AWTEventMulticaster.add(hierarchyBoundsListener, listener);
     if (hierarchyBoundsListener != null)
       enableEvents(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK);
 
-    numHierarchyBoundsListeners++;
-    if (parent != null)
-      parent.updateHierarchyListenerCount(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
-                                          1);
+    // Need to lock the tree, otherwise we might end up inconsistent.
+    synchronized (getTreeLock())
+      {
+        numHierarchyBoundsListeners++;
+        if (parent != null)
+          parent.updateHierarchyListenerCount
+                                        (AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
+                                         1);
+      }
   }
 
   /**
    * Removes the specified listener from the component. This is harmless if
    * the listener was not previously registered.
    *
    * @param listener the listener to remove
    * @see HierarchyEvent
    * @see #addHierarchyBoundsListener(HierarchyBoundsListener)
    * @see #getHierarchyBoundsListeners()
    * @since 1.3
    */
   public synchronized void
     removeHierarchyBoundsListener(HierarchyBoundsListener listener)
   {
     hierarchyBoundsListener =
       AWTEventMulticaster.remove(hierarchyBoundsListener, listener);
 
-    numHierarchyBoundsListeners--;
-    if (parent != null)
-      parent.updateHierarchyListenerCount(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
+    // Need to lock the tree, otherwise we might end up inconsistent.
+    synchronized (getTreeLock())
+      {
+        numHierarchyBoundsListeners--;
+        if (parent != null)
+          parent.updateHierarchyListenerCount
+                                         (AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK,
                                           -1);
+      }
   }
 
   /**
    * Returns an array of all specified listeners registered on this component.
    *
    * @return an array of listeners
    * @see #addHierarchyBoundsListener(HierarchyBoundsListener)
    * @see #removeHierarchyBoundsListener(HierarchyBoundsListener)
    * @since 1.4
    */
   public synchronized HierarchyBoundsListener[] getHierarchyBoundsListeners()
   {
@@ -3775,60 +3832,68 @@
   /**
    * Called when the parent of this Component is made visible or when
    * the Component is added to an already visible Container and needs
    * to be shown.  A native peer - if any - is created at this
    * time. This method is called automatically by the AWT system and
    * should not be called by user level code.
    *
    * @see #isDisplayable()
    * @see #removeNotify()
    */
   public void addNotify()
   {
-    if (peer == null)
-      peer = getToolkit().createComponent(this);
-    else if (parent != null && parent.isLightweight())
-      new HeavyweightInLightweightListener(parent);
-    /* Now that all the children has gotten their peers, we should
+    // We need to lock the tree here to avoid races and inconsistencies.
+    synchronized (getTreeLock())
+      {
+        if (peer == null)
+          peer = getToolkit().createComponent(this);
+        else if (parent != null && parent.isLightweight())
+          new HeavyweightInLightweightListener(parent);
+        /* Now that all the children has gotten their peers, we should
        have the event mask needed for this component and its
        lightweight subcomponents. */
-    peer.setEventMask(eventMask);
-    /* We do not invalidate here, but rather leave that job up to
+        peer.setEventMask(eventMask);
+        /* We do not invalidate here, but rather leave that job up to
        the peer. For efficiency, the peer can choose not to
        invalidate if it is happy with the current dimensions,
        etc. */
+      }
   }
 
   /**
    * Called to inform this component is has been removed from its
    * container. Its native peer - if any - is destroyed at this time.
    * This method is called automatically by the AWT system and should
    * not be called by user level code.
    *
    * @see #isDisplayable()
    * @see #addNotify()
    */
   public void removeNotify()
   {
-    // We null our peer field before disposing of it, such that if we're
-    // not the event dispatch thread and the dispatch thread is awoken by
-    // the dispose call, there will be no race checking the peer's null
-    // status.
-
-    ComponentPeer tmp = peer;
-    peer = null;
-    if (tmp != null)
+    // We need to lock the tree here to avoid races and inconsistencies.
+    synchronized (getTreeLock())
       {
-        tmp.hide();
-        tmp.dispose();
+        // We null our peer field before disposing of it, such that if we're
+        // not the event dispatch thread and the dispatch thread is awoken by
+        // the dispose call, there will be no race checking the peer's null
+        // status.
+
+        ComponentPeer tmp = peer;
+        peer = null;
+        if (tmp != null)
+          {
+            tmp.hide();
+            tmp.dispose();
+          }
       }
   }
 
   /**
    * AWT 1.0 GOT_FOCUS event handler.  This method is meant to be
    * overridden by components providing their own GOT_FOCUS handler.
    * The default implementation simply returns false.
    *
    * @param evt the event to handle
    * @param what the Object focused, ignored
    * @return false
    * @deprecated use [EMAIL PROTECTED] #processFocusEvent(FocusEvent)} instead
Index: java/awt/Container.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/awt/Container.java,v
retrieving revision 1.99
diff -u -1 -2 -r1.99 Container.java
--- java/awt/Container.java	14 Jul 2006 10:27:17 -0000	1.99
+++ java/awt/Container.java	14 Jul 2006 11:49:08 -0000
@@ -593,37 +593,40 @@
         if (! isValid() && peer != null)
           {
             validateTree();
           }
       }
   }
 
   /**
    * Recursively invalidates the container tree.
    */
   void invalidateTree()
   {
-    super.invalidate();  // Clean cached layout state.
-    for (int i = 0; i < ncomponents; i++)
+    synchronized (getTreeLock())
       {
-        Component comp = component[i];
-        comp.invalidate();
-        if (comp instanceof Container)
-          ((Container) comp).invalidateTree();
-      }
+        super.invalidate();  // Clean cached layout state.
+        for (int i = 0; i < ncomponents; i++)
+          {
+            Component comp = component[i];
+            comp.invalidate();
+            if (comp instanceof Container)
+              ((Container) comp).invalidateTree();
+          }
 
-    if (layoutMgr != null && layoutMgr instanceof LayoutManager2)
-      {
-        LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
-        lm2.invalidateLayout(this);
+        if (layoutMgr != null && layoutMgr instanceof LayoutManager2)
+          {
+            LayoutManager2 lm2 = (LayoutManager2) layoutMgr;
+            lm2.invalidateLayout(this);
+          }
       }
   }
 
   /**
    * Recursively validates the container tree, recomputing any invalid
    * layouts.
    */
   protected void validateTree()
   {
     if (valid)
       return;
 
@@ -794,47 +797,53 @@
    * Returns the preferred alignment along the X axis.  This is a value
    * between 0 and 1 where 0 represents alignment flush left and
    * 1 means alignment flush right, and 0.5 means centered.
    *
    * @return The preferred alignment along the X axis.
    */
   public float getAlignmentX()
   {
     LayoutManager layout = getLayout();
     float alignmentX = 0.0F;
     if (layout != null && layout instanceof LayoutManager2)
       {
-        LayoutManager2 lm2 = (LayoutManager2) layout;
-        alignmentX = lm2.getLayoutAlignmentX(this);
+        synchronized (getTreeLock())
+          {
+            LayoutManager2 lm2 = (LayoutManager2) layout;
+            alignmentX = lm2.getLayoutAlignmentX(this);
+          }
       }
     else
       alignmentX = super.getAlignmentX();
     return alignmentX;
   }
 
   /**
    * Returns the preferred alignment along the Y axis.  This is a value
    * between 0 and 1 where 0 represents alignment flush top and
    * 1 means alignment flush bottom, and 0.5 means centered.
    *
    * @return The preferred alignment along the Y axis.
    */
   public float getAlignmentY()
   {
     LayoutManager layout = getLayout();
     float alignmentY = 0.0F;
     if (layout != null && layout instanceof LayoutManager2)
       {
-        LayoutManager2 lm2 = (LayoutManager2) layout;
-        alignmentY = lm2.getLayoutAlignmentY(this);
+        synchronized (getTreeLock())
+          {
+            LayoutManager2 lm2 = (LayoutManager2) layout;
+            alignmentY = lm2.getLayoutAlignmentY(this);
+          }
       }
     else
       alignmentY = super.getAlignmentY();
     return alignmentY;
   }
 
   /**
    * Paints this container.  The implementation of this method in this
    * class forwards to any lightweight components in this container.  If
    * this method is subclassed, this method should still be invoked as
    * a superclass method so that lightweight components are properly
    * drawn.
@@ -1213,26 +1222,29 @@
   public Component findComponentAt(Point p)
   {
     return findComponentAt(p.x, p.y);
   }
 
   /**
    * Called when this container is added to another container to inform it
    * to create its peer.  Peers for any child components will also be
    * created.
    */
   public void addNotify()
   {
-    super.addNotify();
-    addNotifyContainerChildren();
+    synchronized (getTreeLock())
+      {
+        super.addNotify();
+        addNotifyContainerChildren();
+      }
   }
 
   /**
    * Called when this container is removed from its parent container to
    * inform it to destroy its peer.  This causes the peers of all child
    * component to be destroyed as well.
    */
   public void removeNotify()
   {
     synchronized (getTreeLock ())
       {
         for (int i = 0; i < ncomponents; ++i)
@@ -1695,73 +1707,79 @@
   {
     if (comp == null)
       throw new NullPointerException("comp must not be null");
     if (comp instanceof Container && ((Container) comp).isAncestorOf(this))
       throw new IllegalArgumentException("comp must not be an ancestor of "
                                          + "this");
     if (comp instanceof Window)
       throw new IllegalArgumentException("comp must not be a Window");
 
     if (comp == this)
       throw new IllegalArgumentException("cannot add component to itself");
 
-    // FIXME: Implement reparenting.
-    if ( comp.getParent() != this)
-      throw new AssertionError("Reparenting is not implemented yet");
-    else
+    synchronized (getTreeLock())
       {
-        // Find current component index.
-        int currentIndex = getComponentZOrder(comp);
-        if (currentIndex < index)
-          {
-            System.arraycopy(component, currentIndex + 1, component,
-                             currentIndex, index - currentIndex);
-          }
+        // FIXME: Implement reparenting.
+        if ( comp.getParent() != this)
+          throw new AssertionError("Reparenting is not implemented yet");
         else
           {
-            System.arraycopy(component, index, component, index + 1,
-                             currentIndex - index);
+            // Find current component index.
+            int currentIndex = getComponentZOrder(comp);
+            if (currentIndex < index)
+              {
+                System.arraycopy(component, currentIndex + 1, component,
+                                 currentIndex, index - currentIndex);
+              }
+            else
+              {
+                System.arraycopy(component, index, component, index + 1,
+                                 currentIndex - index);
+              }
+            component[index] = comp;
           }
-        component[index] = comp;
       }
   }
 
   /**
    * Returns the Z ordering index of <code>comp</code>. If <code>comp</code>
    * is not a child component of this Container, this returns <code>-1</code>.
    *
    * @param comp the component for which to query the Z ordering
    *
    * @return the Z ordering index of <code>comp</code> or <code>-1</code> if
    *         <code>comp</code> is not a child of this Container
    *
    * @see #setComponentZOrder(Component, int)
    *
    * @since 1.5
    */
   public final int getComponentZOrder(Component comp)
   {
-    int index = -1;
-    if (component != null)
+    synchronized (getTreeLock())
       {
-        for (int i = 0; i < ncomponents; i++)
+        int index = -1;
+        if (component != null)
           {
-            if (component[i] == comp)
+            for (int i = 0; i < ncomponents; i++)
               {
-                index = i;
-                break;
+                if (component[i] == comp)
+                  {
+                    index = i;
+                    break;
+                  }
               }
           }
+        return index;
       }
-    return index;
   }
 
   // Hidden helper methods.
 
   /**
    * Perform a graphics operation on the children of this container.
    * For each applicable child, the visitChild() method will be called
    * to perform the graphics operation.
    *
    * @param gfx The graphics object that will be used to derive new
    * graphics objects for the children.
    *

Reply via email to