6608456: need API to define RepaintManager per components hierarchy
Reviewed-by: alexp
--- a/jdk/make/javax/swing/Makefile Fri Jul 25 17:50:36 2008 +0400
+++ b/jdk/make/javax/swing/Makefile Fri Jul 25 11:32:12 2008 -0400
@@ -33,7 +33,7 @@
# Files
#
include FILES.gmk
-AUTO_FILES_JAVA_DIRS = javax/swing sun/swing
+AUTO_FILES_JAVA_DIRS = javax/swing sun/swing com/sun/java/swing
AUTO_JAVA_PRUNE = plaf
SUBDIRS = html32dtd plaf
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/java/swing/SwingUtilities3.java Fri Jul 25 11:32:12 2008 -0400
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.java.swing;
+
+import sun.awt.AppContext;
+import java.awt.Component;
+import javax.swing.JComponent;
+import javax.swing.RepaintManager;
+
+/**
+ * A collection of utility methods for Swing.
+ * <p>
+ * <b>WARNING:</b> While this class is public, it should not be treated as
+ * public API and its API may change in incompatable ways between dot dot
+ * releases and even patch releases. You should not rely on this class even
+ * existing.
+ *
+ * This is a second part of sun.swing.SwingUtilities2. It is required
+ * to provide services for JavaFX applets.
+ *
+ */
+public class SwingUtilities3 {
+ /**
+ * The {@code clientProperty} key for delegate {@code RepaintManager}
+ */
+ private static final Object DELEGATE_REPAINT_MANAGER_KEY =
+ new StringBuilder("DelegateRepaintManagerKey");
+
+ /**
+ * Registers delegate RepaintManager for {@code JComponent}.
+ */
+ public static void setDelegateRepaintManager(JComponent component,
+ RepaintManager repaintManager) {
+ /* setting up flag in AppContext to speed up lookups in case
+ * there are no delegate RepaintManagers used.
+ */
+ AppContext.getAppContext().put(DELEGATE_REPAINT_MANAGER_KEY,
+ Boolean.TRUE);
+
+ component.putClientProperty(DELEGATE_REPAINT_MANAGER_KEY,
+ repaintManager);
+ }
+
+ /**
+ * Returns delegate {@code RepaintManager} for {@code component} hierarchy.
+ */
+ public static RepaintManager getDelegateRepaintManager(Component
+ component) {
+ RepaintManager delegate = null;
+ if (Boolean.TRUE == AppContext.getAppContext().get(
+ DELEGATE_REPAINT_MANAGER_KEY)) {
+ while (delegate == null && component != null) {
+ while (component != null
+ && ! (component instanceof JComponent)) {
+ component = component.getParent();
+ }
+ if (component != null) {
+ delegate = (RepaintManager)
+ ((JComponent) component)
+ .getClientProperty(DELEGATE_REPAINT_MANAGER_KEY);
+ component = component.getParent();
+ }
+
+ }
+ }
+ return delegate;
+ }
+}
--- a/jdk/src/share/classes/javax/swing/RepaintManager.java Fri Jul 25 17:50:36 2008 +0400
+++ b/jdk/src/share/classes/javax/swing/RepaintManager.java Fri Jul 25 11:32:12 2008 -0400
@@ -40,6 +40,8 @@
import sun.java2d.SunGraphicsEnvironment;
import sun.security.action.GetPropertyAction;
+import com.sun.java.swing.SwingUtilities3;
+
/**
* This class manages repaint requests, allowing the number
@@ -303,6 +305,11 @@
*/
public synchronized void addInvalidComponent(JComponent invalidComponent)
{
+ RepaintManager delegate = getDelegate(invalidComponent);
+ if (delegate != null) {
+ delegate.addInvalidComponent(invalidComponent);
+ return;
+ }
Component validateRoot = null;
/* Find the first JComponent ancestor of this component whose
@@ -373,6 +380,11 @@
* @see #addInvalidComponent
*/
public synchronized void removeInvalidComponent(JComponent component) {
+ RepaintManager delegate = getDelegate(component);
+ if (delegate != null) {
+ delegate.removeInvalidComponent(component);
+ return;
+ }
if(invalidComponents != null) {
int index = invalidComponents.indexOf(component);
if(index != -1) {
@@ -464,6 +476,11 @@
*/
public void addDirtyRegion(JComponent c, int x, int y, int w, int h)
{
+ RepaintManager delegate = getDelegate(c);
+ if (delegate != null) {
+ delegate.addDirtyRegion(c, x, y, w, h);
+ return;
+ }
addDirtyRegion0(c, x, y, w, h);
}
@@ -588,6 +605,10 @@
* dirty.
*/
public Rectangle getDirtyRegion(JComponent aComponent) {
+ RepaintManager delegate = getDelegate(aComponent);
+ if (delegate != null) {
+ return delegate.getDirtyRegion(aComponent);
+ }
Rectangle r = null;
synchronized(this) {
r = (Rectangle)dirtyComponents.get(aComponent);
@@ -603,6 +624,11 @@
* completely painted during the next paintDirtyRegions() call.
*/
public void markCompletelyDirty(JComponent aComponent) {
+ RepaintManager delegate = getDelegate(aComponent);
+ if (delegate != null) {
+ delegate.markCompletelyDirty(aComponent);
+ return;
+ }
addDirtyRegion(aComponent,0,0,Integer.MAX_VALUE,Integer.MAX_VALUE);
}
@@ -611,6 +637,11 @@
* get painted during the next paintDirtyRegions() call.
*/
public void markCompletelyClean(JComponent aComponent) {
+ RepaintManager delegate = getDelegate(aComponent);
+ if (delegate != null) {
+ delegate.markCompletelyClean(aComponent);
+ return;
+ }
synchronized(this) {
dirtyComponents.remove(aComponent);
}
@@ -623,6 +654,10 @@
* if it return true.
*/
public boolean isCompletelyDirty(JComponent aComponent) {
+ RepaintManager delegate = getDelegate(aComponent);
+ if (delegate != null) {
+ return delegate.isCompletelyDirty(aComponent);
+ }
Rectangle r;
r = getDirtyRegion(aComponent);
@@ -900,6 +935,10 @@
* repaint manager.
*/
public Image getOffscreenBuffer(Component c,int proposedWidth,int proposedHeight) {
+ RepaintManager delegate = getDelegate(c);
+ if (delegate != null) {
+ return delegate.getOffscreenBuffer(c, proposedWidth, proposedHeight);
+ }
return _getOffscreenBuffer(c, proposedWidth, proposedHeight);
}
@@ -917,6 +956,11 @@
*/
public Image getVolatileOffscreenBuffer(Component c,
int proposedWidth,int proposedHeight) {
+ RepaintManager delegate = getDelegate(c);
+ if (delegate != null) {
+ return delegate.getVolatileOffscreenBuffer(c, proposedWidth,
+ proposedHeight);
+ }
GraphicsConfiguration config = c.getGraphicsConfiguration();
if (config == null) {
config = GraphicsEnvironment.getLocalGraphicsEnvironment().
@@ -1550,4 +1594,11 @@
prePaintDirtyRegions();
}
}
+ private RepaintManager getDelegate(Component c) {
+ RepaintManager delegate = SwingUtilities3.getDelegateRepaintManager(c);
+ if (this == delegate) {
+ delegate = null;
+ }
+ return delegate;
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/RepaintManager/6608456/bug6608456.java Fri Jul 25 11:32:12 2008 -0400
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ *
+ * @bug 6608456
+ * @author Igor Kushnirskiy
+ * @summary tests if delegate RepaintManager gets invoked.
+ */
+
+import java.awt.*;
+import java.lang.reflect.Method;
+import java.util.concurrent.Callable;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+
+import javax.swing.JComponent;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.RepaintManager;
+import javax.swing.SwingUtilities;
+
+
+
+public class bug6608456 {
+ private static final TestFuture testFuture = new TestFuture();
+ public static void main(String[] args) throws Exception {
+ final JComponent component = invokeAndWait(
+ new Callable<JComponent>() {
+ public JComponent call() throws Exception {
+ RepaintManager.setCurrentManager(new TestRepaintManager());
+ JFrame frame = new JFrame("test");
+ frame.setLayout(new FlowLayout());
+ JButton button = new JButton("default");
+
+ frame.add(button);
+ button = new JButton("delegate");
+ if ( ! registerDelegate(
+ button, new TestRepaintManager())) {
+ return null;
+ }
+ frame.add(button);
+ frame.pack();
+ frame.setVisible(true);
+ return button;
+ }
+ });
+ if (component == null) {
+ throw new RuntimeException("failed. can not register delegate");
+ }
+ blockTillDisplayed(component);
+ // trigger repaint for delegate RepaintManager
+ invokeAndWait(
+ new Callable<Void>() {
+ public Void call() {
+ component.repaint();
+ return null;
+ }
+ });
+ try {
+ if (testFuture.get(10, TimeUnit.SECONDS)) {
+ // passed
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("failed", e);
+ } finally {
+ JFrame frame = (JFrame) SwingUtilities
+ .getAncestorOfClass(JFrame.class, component);
+ if (frame != null) {
+ frame.dispose();
+ }
+ }
+ }
+ static class TestRepaintManager extends RepaintManager {
+ @Override
+ public void addDirtyRegion(JComponent c, int x, int y, int w, int h) {
+ if (RepaintManager.currentManager(c) == this) {
+ testFuture.defaultCalled();
+ } else {
+ testFuture.delegateCalled();
+ }
+ super.addDirtyRegion(c, x, y, w, h);
+ }
+ }
+ static class TestFuture extends FutureTask<Boolean> {
+ private volatile boolean defaultCalled = false;
+ private volatile boolean delegateCalled = false;
+ public TestFuture() {
+ super(new Callable<Boolean>() {
+ public Boolean call() {
+ return null;
+ }
+ });
+ }
+ public void defaultCalled() {
+ defaultCalled = true;
+ updateState();
+ }
+ public void delegateCalled() {
+ delegateCalled = true;
+ updateState();
+ }
+ private void updateState() {
+ if (defaultCalled && delegateCalled) {
+ set(Boolean.TRUE);
+ }
+ }
+ }
+
+ private static boolean registerDelegate(JComponent c,
+ RepaintManager repaintManager) {
+ boolean rv = false;
+ try {
+ Class<?> clazz = Class.forName("com.sun.java.swing.SwingUtilities3");
+ Method method = clazz.getMethod("setDelegateRepaintManager",
+ JComponent.class, RepaintManager.class);
+ method.invoke(clazz, c, repaintManager);
+ rv = true;
+ } catch (Exception ignore) {
+ }
+ return rv;
+ }
+ static <T> T invokeAndWait(Callable<T> callable) throws Exception {
+ FutureTask<T> future = new FutureTask<T>(callable);
+ SwingUtilities.invokeLater(future);
+ return future.get();
+ }
+
+ public static void blockTillDisplayed(Component comp) {
+ Point p = null;
+ while (p == null) {
+ try {
+ p = comp.getLocationOnScreen();
+ } catch (IllegalStateException e) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ie) {
+ }
+ }
+ }
+ }
+}