6608456: need API to define RepaintManager per components hierarchy
authoridk
Fri, 25 Jul 2008 11:32:12 -0400
changeset 1291 e56898d6642d
parent 1290 da8902cd496c
child 1292 e91af84fbe9f
6608456: need API to define RepaintManager per components hierarchy Reviewed-by: alexp
jdk/make/javax/swing/Makefile
jdk/src/share/classes/com/sun/java/swing/SwingUtilities3.java
jdk/src/share/classes/javax/swing/RepaintManager.java
jdk/test/javax/swing/RepaintManager/6608456/bug6608456.java
--- 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) {
+                }
+            }
+        }
+    }
+}