4993545: NativeInLightFixer adds asynchronousity
Summary: All the hooks related to the NativeInLightFixer have been moved to the HW/LW mixing handling methods. The NativeInLightFixer itself has been removed.
Reviewed-by: son, alexp
--- a/jdk/src/share/classes/java/awt/Component.java Tue Mar 18 16:19:03 2008 +0300
+++ b/jdk/src/share/classes/java/awt/Component.java Thu Mar 20 11:09:16 2008 +0300
@@ -6492,7 +6492,7 @@
// will need some help.
Container parent = this.parent;
if (parent != null && parent.peer instanceof LightweightPeer) {
- nativeInLightFixer = new NativeInLightFixer();
+ relocateComponent();
}
}
invalidate();
@@ -6603,10 +6603,6 @@
}
}
- if (nativeInLightFixer != null) {
- nativeInLightFixer.uninstall();
- }
-
ComponentPeer p = peer;
if (p != null) {
boolean isLightweight = isLightweight();
@@ -8514,8 +8510,6 @@
setComponentOrientation(orientation);
}
- transient NativeInLightFixer nativeInLightFixer;
-
/**
* Checks that this component meets the prerequesites to be focus owner:
* - it is enabled, visible, focusable
@@ -8541,188 +8535,25 @@
}
/**
- * This odd class is to help out a native component that has been
- * embedded in a lightweight component. Moving lightweight
- * components around and changing their visibility is not seen
- * by the native window system. This is a feature for lightweights,
- * but a problem for native components that depend upon the
- * lightweights. An instance of this class listens to the lightweight
- * parents of an associated native component (the outer class).
- *
- * @author Timothy Prinzing
- */
- final class NativeInLightFixer implements ComponentListener, ContainerListener {
-
- NativeInLightFixer() {
- lightParents = new Vector();
- install(parent);
- }
-
- void install(Container parent) {
- lightParents.clear();
- Container p = parent;
- boolean isLwParentsVisible = true;
- // stash a reference to the components that are being observed so that
- // we can reliably remove ourself as a listener later.
- for (; p.peer instanceof LightweightPeer; p = p.parent) {
-
- // register listeners and stash a reference
- p.addComponentListener(this);
- p.addContainerListener(this);
- lightParents.addElement(p);
- isLwParentsVisible &= p.isVisible();
- }
- // register with the native host (native parent of associated native)
- // to get notified if the top-level lightweight is removed.
- nativeHost = p;
- p.addContainerListener(this);
-
- // kick start the fixup. Since the event isn't looked at
- // we can simulate movement notification.
- componentMoved(null);
- if (!isLwParentsVisible) {
- synchronized (getTreeLock()) {
- if (peer != null) {
- peer.hide();
- }
- }
- }
- }
-
- void uninstall() {
- if (nativeHost != null) {
- removeReferences();
- }
- }
-
- // --- ComponentListener -------------------------------------------
-
- /**
- * Invoked when one of the lightweight parents has been resized.
- * This doesn't change the position of the native child so it
- * is ignored.
- */
- public void componentResized(ComponentEvent e) {
- }
-
- /**
- * Invoked when one of the lightweight parents has been moved.
- * The native peer must be told of the new position which is
- * relative to the native container that is hosting the
- * lightweight components.
- */
- public void componentMoved(ComponentEvent e) {
- synchronized (getTreeLock()) {
- int nativeX = x;
- int nativeY = y;
- for(Component c = parent; (c != null) &&
- (c.peer instanceof LightweightPeer);
- c = c.parent) {
-
- nativeX += c.x;
- nativeY += c.y;
- }
- if (peer != null) {
- peer.setBounds(nativeX, nativeY, width, height,
- ComponentPeer.SET_LOCATION);
- }
- }
- }
-
- /**
- * Invoked when a lightweight parent component has been
- * shown. The associated native component must also be
- * shown if it hasn't had an overriding hide done on it.
- */
- public void componentShown(ComponentEvent e) {
- if (shouldShow()) {
- synchronized (getTreeLock()) {
- if (peer != null) {
- peer.show();
- }
- }
- }
- }
-
- /**
- * Invoked when one of the lightweight parents become visible.
- * Returns true if component and all its lightweight
- * parents are visible.
- */
- private boolean shouldShow() {
- boolean isLwParentsVisible = visible;
- for (int i = lightParents.size() - 1;
- i >= 0 && isLwParentsVisible;
- i--)
+ * Fix the location of the HW component in a LW container hierarchy.
+ */
+ final void relocateComponent() {
+ synchronized (getTreeLock()) {
+ if (peer == null) {
+ return;
+ }
+ int nativeX = x;
+ int nativeY = y;
+ for (Component cont = getContainer();
+ cont != null && cont.isLightweight();
+ cont = cont.getContainer())
{
- isLwParentsVisible &=
- ((Container) lightParents.elementAt(i)).isVisible();
- }
- return isLwParentsVisible;
- }
-
- /**
- * Invoked when component has been hidden.
- */
- public void componentHidden(ComponentEvent e) {
- if (visible) {
- synchronized (getTreeLock()) {
- if (peer != null) {
- peer.hide();
- }
- }
- }
- }
-
- // --- ContainerListener ------------------------------------
-
- /**
- * Invoked when a component has been added to a lightweight
- * parent. This doesn't effect the native component.
- */
- public void componentAdded(ContainerEvent e) {
- }
-
- /**
- * Invoked when a lightweight parent has been removed.
- * This means the services of this listener are no longer
- * required and it should remove all references (ie
- * registered listeners).
- */
- public void componentRemoved(ContainerEvent e) {
- Component c = e.getChild();
- if (c == Component.this) {
- removeReferences();
- } else {
- int n = lightParents.size();
- for (int i = 0; i < n; i++) {
- Container p = (Container) lightParents.elementAt(i);
- if (p == c) {
- removeReferences();
- break;
- }
- }
- }
- }
-
- /**
- * Removes references to this object so it can be
- * garbage collected.
- */
- void removeReferences() {
- int n = lightParents.size();
- for (int i = 0; i < n; i++) {
- Container c = (Container) lightParents.elementAt(i);
- c.removeComponentListener(this);
- c.removeContainerListener(this);
- }
- nativeHost.removeContainerListener(this);
- lightParents.clear();
- nativeHost = null;
- }
-
- Vector lightParents;
- Container nativeHost;
+ nativeX += cont.x;
+ nativeY += cont.y;
+ }
+ peer.setBounds(nativeX, nativeY, width, height,
+ ComponentPeer.SET_LOCATION);
+ }
}
/**
--- a/jdk/src/share/classes/java/awt/Container.java Tue Mar 18 16:19:03 2008 +0300
+++ b/jdk/src/share/classes/java/awt/Container.java Thu Mar 20 11:09:16 2008 +0300
@@ -832,16 +832,8 @@
}
if (!comp.isLightweight() && isLightweight()) {
// If component is heavyweight and one of the containers is lightweight
- // some NativeInLightFixer activity should be performed
- if (!curParent.isLightweight()) {
- // Moving from heavyweight container to lightweight container - should create NativeInLightFixer
- // since addNotify does this
- comp.nativeInLightFixer = new NativeInLightFixer();
- } else {
- // Component already has NativeInLightFixer - just reinstall it
- // because hierarchy changed and he needs to rebuild list of parents to listen.
- comp.nativeInLightFixer.install(this);
- }
+ // the location of the component should be fixed.
+ comp.relocateComponent();
}
}
}
@@ -3953,6 +3945,83 @@
}
}
+ private void recursiveShowHeavyweightChildren() {
+ if (!hasHeavyweightDescendants() || !isVisible()) {
+ return;
+ }
+ for (int index = 0; index < getComponentCount(); index++) {
+ Component comp = getComponent(index);
+ if (comp.isLightweight()) {
+ if (comp instanceof Container) {
+ ((Container)comp).recursiveShowHeavyweightChildren();
+ }
+ } else {
+ if (comp.isVisible()) {
+ ComponentPeer peer = comp.getPeer();
+ if (peer != null) {
+ peer.show();
+ }
+ }
+ }
+ }
+ }
+
+ private void recursiveHideHeavyweightChildren() {
+ if (!hasHeavyweightDescendants()) {
+ return;
+ }
+ for (int index = 0; index < getComponentCount(); index++) {
+ Component comp = getComponent(index);
+ if (comp.isLightweight()) {
+ if (comp instanceof Container) {
+ ((Container)comp).recursiveHideHeavyweightChildren();
+ }
+ } else {
+ if (comp.isVisible()) {
+ ComponentPeer peer = comp.getPeer();
+ if (peer != null) {
+ peer.hide();
+ }
+ }
+ }
+ }
+ }
+
+ private void recursiveRelocateHeavyweightChildren(Point origin) {
+ for (int index = 0; index < getComponentCount(); index++) {
+ Component comp = getComponent(index);
+ if (comp.isLightweight()) {
+ if (comp instanceof Container &&
+ ((Container)comp).hasHeavyweightDescendants())
+ {
+ final Point newOrigin = new Point(origin);
+ newOrigin.translate(comp.getX(), comp.getY());
+ ((Container)comp).recursiveRelocateHeavyweightChildren(newOrigin);
+ }
+ } else {
+ ComponentPeer peer = comp.getPeer();
+ if (peer != null) {
+ peer.setBounds(origin.x + comp.getX(), origin.y + comp.getY(),
+ comp.getWidth(), comp.getHeight(),
+ ComponentPeer.SET_LOCATION);
+ }
+ }
+ }
+ }
+
+ /*
+ * Consider the heavyweight container hides or shows the HW descendants
+ * automatically. Therefore we care of LW containers' visibility only.
+ */
+ private boolean isRecursivelyVisibleUpToHeavyweightContainer() {
+ if (!isLightweight()) {
+ return true;
+ }
+ return isVisible() && (getContainer() == null ||
+ getContainer().isRecursivelyVisibleUpToHeavyweightContainer());
+ }
+
+ @Override
void mixOnShowing() {
synchronized (getTreeLock()) {
if (mixingLog.isLoggable(Level.FINE)) {
@@ -3961,6 +4030,10 @@
boolean isLightweight = isLightweight();
+ if (isLightweight && isRecursivelyVisibleUpToHeavyweightContainer()) {
+ recursiveShowHeavyweightChildren();
+ }
+
if (!isLightweight || (isLightweight && hasHeavyweightDescendants())) {
recursiveApplyCurrentShape();
}
@@ -3969,6 +4042,42 @@
}
}
+ @Override
+ void mixOnHiding(boolean isLightweight) {
+ synchronized (getTreeLock()) {
+ if (mixingLog.isLoggable(Level.FINE)) {
+ mixingLog.fine("this = " + this +
+ "; isLightweight=" + isLightweight);
+ }
+ if (isLightweight) {
+ recursiveHideHeavyweightChildren();
+ }
+ super.mixOnHiding(isLightweight);
+ }
+ }
+
+ @Override
+ void mixOnReshaping() {
+ synchronized (getTreeLock()) {
+ if (mixingLog.isLoggable(Level.FINE)) {
+ mixingLog.fine("this = " + this);
+ }
+ if (isLightweight() && hasHeavyweightDescendants()) {
+ final Point origin = new Point(getX(), getY());
+ for (Container cont = getContainer();
+ cont != null && cont.isLightweight();
+ cont = cont.getContainer())
+ {
+ origin.translate(cont.getX(), cont.getY());
+ }
+
+ recursiveRelocateHeavyweightChildren(origin);
+ }
+ super.mixOnReshaping();
+ }
+ }
+
+ @Override
void mixOnZOrderChanging(int oldZorder, int newZorder) {
synchronized (getTreeLock()) {
if (mixingLog.isLoggable(Level.FINE)) {