# HG changeset patch # User idk # Date 1217009639 14400 # Node ID ef349b440fc99c004b5eb786f3dc26624a24727c # Parent e91af84fbe9fd7adf195b6d76fdecc13e6219e17 6638195: need API for EventQueueDelegate Reviewed-by: bchristi diff -r e91af84fbe9f -r ef349b440fc9 jdk/src/share/classes/com/sun/java/swing/SwingUtilities3.java --- a/jdk/src/share/classes/com/sun/java/swing/SwingUtilities3.java Fri Jul 25 21:00:05 2008 +0400 +++ b/jdk/src/share/classes/com/sun/java/swing/SwingUtilities3.java Fri Jul 25 14:13:59 2008 -0400 @@ -25,7 +25,12 @@ package com.sun.java.swing; +import sun.awt.EventQueueDelegate; import sun.awt.AppContext; +import java.util.Map; +import java.util.concurrent.Callable; +import java.awt.AWTEvent; +import java.awt.EventQueue; import java.awt.Component; import javax.swing.JComponent; import javax.swing.RepaintManager; @@ -88,4 +93,82 @@ } return delegate; } + + /* + * We use maps to avoid reflection. Hopefully it should perform better + * this way. + */ + public static void setEventQueueDelegate( + Map> map) { + EventQueueDelegate.setDelegate(new EventQueueDelegateFromMap(map)); + } + + private static class EventQueueDelegateFromMap + implements EventQueueDelegate.Delegate { + private final AWTEvent[] afterDispatchEventArgument; + private final Object[] afterDispatchHandleArgument; + private final Callable afterDispatchCallable; + + private final AWTEvent[] beforeDispatchEventArgument; + private final Callable beforeDispatchCallable; + + private final EventQueue[] getNextEventEventQueueArgument; + private final Callable getNextEventCallable; + + @SuppressWarnings("unchecked") + public EventQueueDelegateFromMap(Map> objectMap) { + Map methodMap = objectMap.get("afterDispatch"); + afterDispatchEventArgument = (AWTEvent[]) methodMap.get("event"); + afterDispatchHandleArgument = (Object[]) methodMap.get("handle"); + afterDispatchCallable = (Callable) methodMap.get("method"); + + methodMap = objectMap.get("beforeDispatch"); + beforeDispatchEventArgument = (AWTEvent[]) methodMap.get("event"); + beforeDispatchCallable = (Callable) methodMap.get("method"); + + methodMap = objectMap.get("getNextEvent"); + getNextEventEventQueueArgument = + (EventQueue[]) methodMap.get("eventQueue"); + getNextEventCallable = (Callable) methodMap.get("method"); + } + + @Override + public void afterDispatch(AWTEvent event, Object handle) { + afterDispatchEventArgument[0] = event; + afterDispatchHandleArgument[0] = handle; + try { + afterDispatchCallable.call(); + } catch (Exception e) { + if (e instanceof RuntimeException) { + throw (RuntimeException) e; + } + } + } + + @Override + public Object beforeDispatch(AWTEvent event) { + beforeDispatchEventArgument[0] = event; + try { + return beforeDispatchCallable.call(); + } catch (Exception e) { + if (e instanceof RuntimeException) { + throw (RuntimeException) e; + } + } + return null; + } + + @Override + public AWTEvent getNextEvent(EventQueue eventQueue) { + getNextEventEventQueueArgument[0] = eventQueue; + try { + return getNextEventCallable.call(); + } catch (Exception e) { + if (e instanceof RuntimeException) { + throw (RuntimeException) e; + } + } + return null; + } + } } diff -r e91af84fbe9f -r ef349b440fc9 jdk/src/share/classes/java/awt/EventDispatchThread.java --- a/jdk/src/share/classes/java/awt/EventDispatchThread.java Fri Jul 25 21:00:05 2008 +0400 +++ b/jdk/src/share/classes/java/awt/EventDispatchThread.java Fri Jul 25 14:13:59 2008 -0400 @@ -39,6 +39,7 @@ import java.util.logging.*; import sun.awt.dnd.SunDragSourceContextPeer; +import sun.awt.EventQueueDelegate; /** * EventDispatchThread is a package-private AWT class which takes @@ -243,10 +244,16 @@ try { AWTEvent event; boolean eventOK; + EventQueueDelegate.Delegate delegate = + EventQueueDelegate.getDelegate(); do { - event = (id == ANY_EVENT) - ? theQueue.getNextEvent() - : theQueue.getNextEvent(id); + if (delegate != null && id == ANY_EVENT) { + event = delegate.getNextEvent(theQueue); + } else { + event = (id == ANY_EVENT) + ? theQueue.getNextEvent() + : theQueue.getNextEvent(id); + } eventOK = true; synchronized (eventFilters) { @@ -272,7 +279,14 @@ eventLog.log(Level.FINEST, "Dispatching: " + event); } + Object handle = null; + if (delegate != null) { + handle = delegate.beforeDispatch(event); + } theQueue.dispatchEvent(event); + if (delegate != null) { + delegate.afterDispatch(event, handle); + } return true; } catch (ThreadDeath death) { diff -r e91af84fbe9f -r ef349b440fc9 jdk/src/share/classes/sun/awt/EventQueueDelegate.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/awt/EventQueueDelegate.java Fri Jul 25 14:13:59 2008 -0400 @@ -0,0 +1,71 @@ +/* + * Copyright 2008 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 sun.awt; + +import java.awt.AWTEvent; +import java.awt.EventQueue; + + +public class EventQueueDelegate { + private static final Object EVENT_QUEUE_DELEGATE_KEY = + new StringBuilder("EventQueueDelegate.Delegate"); + + public static void setDelegate(Delegate delegate) { + AppContext.getAppContext().put(EVENT_QUEUE_DELEGATE_KEY, delegate); + } + public static Delegate getDelegate() { + return + (Delegate) AppContext.getAppContext().get(EVENT_QUEUE_DELEGATE_KEY); + } + public interface Delegate { + /** + * This method allows for changing {@code EventQueue} events order. + * + * @param eventQueue current {@code EventQueue} + * @return next {@code event} for the {@code EventDispatchThread} + */ + + public AWTEvent getNextEvent(EventQueue eventQueue) throws InterruptedException; + + /** + * Notifies delegate before EventQueue.dispatch method. + * + * Note: this method may mutate the event + * + * @param event to be dispatched by {@code dispatch} method + * @return handle to be passed to {@code afterDispatch} method + */ + public Object beforeDispatch(AWTEvent event); + + /** + * Notifies delegate after EventQueue.dispatch method. + * + * @param event {@code event} dispatched by the {@code dispatch} method + * @param handle object which came from {@code beforeDispatch} method + */ + public void afterDispatch(AWTEvent event, Object handle); + } +} diff -r e91af84fbe9f -r ef349b440fc9 jdk/test/java/awt/EventQueue/6638195/bug6638195.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/EventQueue/6638195/bug6638195.java Fri Jul 25 14:13:59 2008 -0400 @@ -0,0 +1,138 @@ +/* + * Copyright 2008 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 6638195 + * @author Igor Kushnirskiy + * @summary tests if EventQueueDelegate.Delegate is invoked. + */ + +import sun.awt.EventQueueDelegate; +import com.sun.java.swing.SwingUtilities3; + +import java.util.*; +import java.util.concurrent.*; +import java.awt.*; + +public class bug6638195 { + public static void main(String[] args) throws Exception { + MyEventQueueDelegate delegate = new MyEventQueueDelegate(); + EventQueueDelegate.setDelegate(delegate); + runTest(delegate); + + delegate = new MyEventQueueDelegate(); + SwingUtilities3.setEventQueueDelegate(getObjectMap(delegate)); + runTest(delegate); + } + + private static void runTest(MyEventQueueDelegate delegate) throws Exception { + EventQueue.invokeLater( + new Runnable() { + public void run() { + } + }); + final CountDownLatch latch = new CountDownLatch(1); + EventQueue.invokeLater( + new Runnable() { + public void run() { + latch.countDown(); + } + }); + latch.await(); + if (! delegate.allInvoked()) { + throw new RuntimeException("failed"); + } + } + + static Map> getObjectMap( + final EventQueueDelegate.Delegate delegate) { + Map> objectMap = + new HashMap>(); + Map methodMap; + + final AWTEvent[] afterDispatchEventArgument = new AWTEvent[1]; + final Object[] afterDispatchHandleArgument = new Object[1]; + Callable afterDispatchCallable = + new Callable() { + public Void call() { + delegate.afterDispatch(afterDispatchEventArgument[0], + afterDispatchHandleArgument[0]); + return null; + } + }; + methodMap = new HashMap(); + methodMap.put("event", afterDispatchEventArgument); + methodMap.put("handle", afterDispatchHandleArgument); + methodMap.put("method", afterDispatchCallable); + objectMap.put("afterDispatch", methodMap); + + final AWTEvent[] beforeDispatchEventArgument = new AWTEvent[1]; + Callable beforeDispatchCallable = + new Callable() { + public Object call() { + return delegate.beforeDispatch( + beforeDispatchEventArgument[0]); + } + }; + methodMap = new HashMap(); + methodMap.put("event", beforeDispatchEventArgument); + methodMap.put("method", beforeDispatchCallable); + objectMap.put("beforeDispatch", methodMap); + + final EventQueue[] getNextEventEventQueueArgument = new EventQueue[1]; + Callable getNextEventCallable = + new Callable() { + public AWTEvent call() throws Exception { + return delegate.getNextEvent( + getNextEventEventQueueArgument[0]); + } + }; + methodMap = new HashMap(); + methodMap.put("eventQueue", getNextEventEventQueueArgument); + methodMap.put("method", getNextEventCallable); + objectMap.put("getNextEvent", methodMap); + + return objectMap; + } + static class MyEventQueueDelegate implements EventQueueDelegate.Delegate { + private volatile boolean getNextEventInvoked = false; + private volatile boolean beforeDispatchInvoked = false; + private volatile boolean afterDispatchInvoked = false; + public AWTEvent getNextEvent(EventQueue eventQueue) + throws InterruptedException { + getNextEventInvoked = true; + return eventQueue.getNextEvent(); + } + public Object beforeDispatch(AWTEvent event) { + beforeDispatchInvoked = true; + return null; + } + public void afterDispatch(AWTEvent event, Object handle) { + afterDispatchInvoked = true; + } + private boolean allInvoked() { + return getNextEventInvoked && beforeDispatchInvoked && afterDispatchInvoked; + } + } +}