# HG changeset patch # User azvegint # Date 1421405624 -10800 # Node ID 33e7de0337d99315d65be9c73edc2e7308cc1400 # Parent 12031ba2dc38c2c51a160ea0347d79166641fa17 8061636: Fix for JDK-7079254 changes behavior of MouseListener, MouseMotionListener Reviewed-by: alexsch, serb diff -r 12031ba2dc38 -r 33e7de0337d9 jdk/src/java.desktop/share/classes/java/awt/Component.java --- a/jdk/src/java.desktop/share/classes/java/awt/Component.java Thu Jan 15 16:52:10 2015 +0100 +++ b/jdk/src/java.desktop/share/classes/java/awt/Component.java Fri Jan 16 13:53:44 2015 +0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2015, Oracle and/or its affiliates. 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 @@ -1690,15 +1690,6 @@ /* do nothing */ } - /* - * Delete references from LightweightDispatcher of a heavyweight parent - */ - void clearLightweightDispatcherOnRemove(Component removedComponent) { - if (parent != null) { - parent.clearLightweightDispatcherOnRemove(removedComponent); - } - } - /** * @deprecated As of JDK version 1.1, * replaced by setVisible(boolean). @@ -6242,7 +6233,7 @@ /** * Indicates whether a class or its superclasses override coalesceEvents. * Must be called with lock on coalesceMap and privileged. - * @see checkCoalsecing + * @see checkCoalescing */ private static boolean isCoalesceEventsOverriden(Class clazz) { assert Thread.holdsLock(coalesceMap); @@ -7083,8 +7074,6 @@ } synchronized (getTreeLock()) { - clearLightweightDispatcherOnRemove(this); - if (isFocusOwner() && KeyboardFocusManager.isAutoFocusTransferEnabledFor(this)) { transferFocus(true); } diff -r 12031ba2dc38 -r 33e7de0337d9 jdk/src/java.desktop/share/classes/java/awt/Container.java --- a/jdk/src/java.desktop/share/classes/java/awt/Container.java Thu Jan 15 16:52:10 2015 +0100 +++ b/jdk/src/java.desktop/share/classes/java/awt/Container.java Fri Jan 16 13:53:44 2015 +0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2015, Oracle and/or its affiliates. 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 @@ -41,6 +41,7 @@ import java.io.PrintStream; import java.io.PrintWriter; +import java.lang.ref.WeakReference; import java.security.AccessController; import java.util.EventListener; @@ -3321,16 +3322,6 @@ } } - @Override - void clearLightweightDispatcherOnRemove(Component removedComponent) { - if (dispatcher != null) { - dispatcher.removeReferences(removedComponent); - } else { - //It is a Lightweight Container, should clear parent`s Dispatcher - super.clearLightweightDispatcherOnRemove(removedComponent); - } - } - final Container getTraversalRoot() { if (isFocusCycleRoot()) { return findTraversalRoot(); @@ -4431,7 +4422,9 @@ LightweightDispatcher(Container nativeContainer) { this.nativeContainer = nativeContainer; - mouseEventTarget = null; + mouseEventTarget = new WeakReference<>(null); + targetLastEntered = new WeakReference<>(null); + targetLastEnteredDT = new WeakReference<>(null); eventMask = 0; } @@ -4442,9 +4435,9 @@ void dispose() { //System.out.println("Disposing lw dispatcher"); stopListeningForOtherDrags(); - mouseEventTarget = null; - targetLastEntered = null; - targetLastEnteredDT = null; + mouseEventTarget.clear(); + targetLastEntered.clear(); + targetLastEnteredDT.clear(); } /** @@ -4531,65 +4524,62 @@ trackMouseEnterExit(mouseOver, e); - // 4508327 : MOUSE_CLICKED should only go to the recipient of - // the accompanying MOUSE_PRESSED, so don't reset mouseEventTarget on a - // MOUSE_CLICKED. - if (!isMouseGrab(e) && id != MouseEvent.MOUSE_CLICKED) { - mouseEventTarget = (mouseOver != nativeContainer) ? mouseOver: null; - isCleaned = false; + Component met = mouseEventTarget.get(); + // 4508327 : MOUSE_CLICKED should only go to the recipient of + // the accompanying MOUSE_PRESSED, so don't reset mouseEventTarget on a + // MOUSE_CLICKED. + if (!isMouseGrab(e) && id != MouseEvent.MOUSE_CLICKED) { + met = (mouseOver != nativeContainer) ? mouseOver : null; + mouseEventTarget = new WeakReference<>(met); } - if (mouseEventTarget != null) { + if (met != null) { switch (id) { - case MouseEvent.MOUSE_ENTERED: - case MouseEvent.MOUSE_EXITED: - break; - case MouseEvent.MOUSE_PRESSED: - retargetMouseEvent(mouseEventTarget, id, e); - break; - case MouseEvent.MOUSE_RELEASED: - retargetMouseEvent(mouseEventTarget, id, e); - break; - case MouseEvent.MOUSE_CLICKED: - // 4508327: MOUSE_CLICKED should never be dispatched to a Component - // other than that which received the MOUSE_PRESSED event. If the - // mouse is now over a different Component, don't dispatch the event. - // The previous fix for a similar problem was associated with bug - // 4155217. - if (mouseOver == mouseEventTarget) { - retargetMouseEvent(mouseOver, id, e); - } - break; - case MouseEvent.MOUSE_MOVED: - retargetMouseEvent(mouseEventTarget, id, e); - break; - case MouseEvent.MOUSE_DRAGGED: - if (isMouseGrab(e)) { - retargetMouseEvent(mouseEventTarget, id, e); - } - break; - case MouseEvent.MOUSE_WHEEL: - // This may send it somewhere that doesn't have MouseWheelEvents - // enabled. In this case, Component.dispatchEventImpl() will - // retarget the event to a parent that DOES have the events enabled. - if (eventLog.isLoggable(PlatformLogger.Level.FINEST) && (mouseOver != null)) { - eventLog.finest("retargeting mouse wheel to " + + case MouseEvent.MOUSE_ENTERED: + case MouseEvent.MOUSE_EXITED: + break; + case MouseEvent.MOUSE_PRESSED: + retargetMouseEvent(met, id, e); + break; + case MouseEvent.MOUSE_RELEASED: + retargetMouseEvent(met, id, e); + break; + case MouseEvent.MOUSE_CLICKED: + // 4508327: MOUSE_CLICKED should never be dispatched to a Component + // other than that which received the MOUSE_PRESSED event. If the + // mouse is now over a different Component, don't dispatch the event. + // The previous fix for a similar problem was associated with bug + // 4155217. + if (mouseOver == met) { + retargetMouseEvent(mouseOver, id, e); + } + break; + case MouseEvent.MOUSE_MOVED: + retargetMouseEvent(met, id, e); + break; + case MouseEvent.MOUSE_DRAGGED: + if (isMouseGrab(e)) { + retargetMouseEvent(met, id, e); + } + break; + case MouseEvent.MOUSE_WHEEL: + // This may send it somewhere that doesn't have MouseWheelEvents + // enabled. In this case, Component.dispatchEventImpl() will + // retarget the event to a parent that DOES have the events enabled. + if (eventLog.isLoggable(PlatformLogger.Level.FINEST) && (mouseOver != null)) { + eventLog.finest("retargeting mouse wheel to " + mouseOver.getName() + ", " + mouseOver.getClass()); - } - retargetMouseEvent(mouseOver, id, e); - break; + } + retargetMouseEvent(mouseOver, id, e); + break; } - //Consuming of wheel events is implemented in "retargetMouseEvent". - if (id != MouseEvent.MOUSE_WHEEL) { - e.consume(); + //Consuming of wheel events is implemented in "retargetMouseEvent". + if (id != MouseEvent.MOUSE_WHEEL) { + e.consume(); + } } - } else if (isCleaned && id != MouseEvent.MOUSE_WHEEL) { - //After mouseEventTarget was removed and cleaned should consume all events - //until new mouseEventTarget is found - e.consume(); - } - return e.isConsumed(); + return e.isConsumed(); } private boolean processDropTargetEvent(SunDropTargetEvent e) { @@ -4652,9 +4642,10 @@ } else if (id == MouseEvent.MOUSE_EXITED) { isMouseDTInNativeContainer = false; } - targetLastEnteredDT = retargetMouseEnterExit(targetOver, e, - targetLastEnteredDT, + Component tle = retargetMouseEnterExit(targetOver, e, + targetLastEnteredDT.get(), isMouseDTInNativeContainer); + targetLastEnteredDT = new WeakReference<>(tle); } /* @@ -4680,9 +4671,10 @@ isMouseInNativeContainer = false; stopListeningForOtherDrags(); } - targetLastEntered = retargetMouseEnterExit(targetOver, e, - targetLastEntered, + Component tle = retargetMouseEnterExit(targetOver, e, + targetLastEntered.get(), isMouseInNativeContainer); + targetLastEntered = new WeakReference<>(tle); } private Component retargetMouseEnterExit(Component targetOver, MouseEvent e, @@ -4944,22 +4936,17 @@ * is null, there are currently no events being forwarded to * a subcomponent. */ - private transient Component mouseEventTarget; + private transient WeakReference mouseEventTarget; /** * The last component entered by the {@code MouseEvent}. */ - private transient Component targetLastEntered; + private transient WeakReference targetLastEntered; /** * The last component entered by the {@code SunDropTargetEvent}. */ - private transient Component targetLastEnteredDT; - - /** - * Indicates whether {@code mouseEventTarget} was removed and nulled - */ - private transient boolean isCleaned; + private transient WeakReference targetLastEnteredDT; /** * Is the mouse over the native container. @@ -5000,17 +4987,4 @@ AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_WHEEL_EVENT_MASK; - - void removeReferences(Component removedComponent) { - if (mouseEventTarget == removedComponent) { - isCleaned = true; - mouseEventTarget = null; - } - if (targetLastEntered == removedComponent) { - targetLastEntered = null; - } - if (targetLastEnteredDT == removedComponent) { - targetLastEnteredDT = null; - } - } } diff -r 12031ba2dc38 -r 33e7de0337d9 jdk/test/java/awt/Mouse/RemovedComponentMouseListener/RemovedComponentMouseListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/Mouse/RemovedComponentMouseListener/RemovedComponentMouseListener.java Fri Jan 16 13:53:44 2015 +0300 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8061636 + * @summary fix for 7079254 changes behavior of MouseListener, MouseMotionListener + * @library ../../regtesthelpers + * @build Util + * @author Alexander Zvegintsev + * @run main RemovedComponentMouseListener + */ + +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.*; +import test.java.awt.regtesthelpers.Util; + +public class RemovedComponentMouseListener extends JFrame { + + static boolean mouseReleasedReceived; + static JButton button; + + public RemovedComponentMouseListener() { + JPanel panel = new JPanel(); + JPanel buttonPanel = new JPanel(); + button = new JButton("Button"); + + setSize(300, 300); + + buttonPanel.add(button); + panel.add(buttonPanel); + setContentPane(panel); + + button.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + buttonPanel.remove(button); + panel.add(button); + button.revalidate(); + button.repaint(); + } + + @Override + public void mouseReleased(MouseEvent e) { + mouseReleasedReceived = true; + } + }); + + setVisible(true); + } + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(() -> { + new RemovedComponentMouseListener(); + }); + + Robot r = Util.createRobot(); + r.setAutoDelay(100); + r.waitForIdle(); + Util.pointOnComp(button, r); + + r.waitForIdle(); + r.mousePress(InputEvent.BUTTON1_MASK); + r.waitForIdle(); + r.mouseRelease(InputEvent.BUTTON1_MASK); + r.waitForIdle(); + if (!mouseReleasedReceived) { + throw new RuntimeException("mouseReleased event was not received"); + } + } +}