--- old/src/macosx/classes/sun/lwawt/LWLightweightFramePeer.java 2013-09-04 12:42:09.570736200 +0400 +++ new/src/macosx/classes/sun/lwawt/LWLightweightFramePeer.java 2013-09-04 12:42:09.383535900 +0400 @@ -25,6 +25,10 @@ package sun.lwawt; +import sun.awt.CausedFocusEvent; +import sun.awt.LightweightFrame; +import sun.awt.LightweightFramePeer; + import java.awt.Graphics; import java.awt.Insets; import java.awt.Point; @@ -32,10 +36,8 @@ import java.awt.Window; import java.awt.dnd.DropTarget; -import sun.awt.CausedFocusEvent; -import sun.awt.LightweightFrame; -public class LWLightweightFramePeer extends LWWindowPeer { +public class LWLightweightFramePeer extends LWWindowPeer implements LightweightFramePeer { public LWLightweightFramePeer(LightweightFrame target, PlatformComponent platformComponent, @@ -91,11 +93,6 @@ } @Override - public void updateCursorImmediately() { - // TODO: tries to switch to the awt/fx toolkit thread and causes a deadlock on macosx - } - - @Override public void addDropTarget(DropTarget dt) { } @@ -112,4 +109,14 @@ public void ungrab() { getLwTarget().ungrabFocus(); } + + @Override + public void setLightweightFrameUnderMouse() { + setLastCommonMouseEventPeer(this); + } + + @Override + public boolean cleanLightweightFrameUnderMouse() { + return cleanLastCommonMouseEventPeer(this); + } } --- old/src/macosx/classes/sun/lwawt/LWWindowPeer.java 2013-09-04 12:42:13.408343000 +0400 +++ new/src/macosx/classes/sun/lwawt/LWWindowPeer.java 2013-09-04 12:42:13.236742700 +0400 @@ -81,9 +81,10 @@ // check that the mouse is over the window private volatile boolean isMouseOver = false; + private static final Object lastCommonMouseEventPeerLock = new Object(); // A peer where the last mouse event came to. Used by cursor manager to // find the component under cursor - private static volatile LWComponentPeer lastCommonMouseEventPeer = null; + private static LWComponentPeer lastCommonMouseEventPeer = null; // A peer where the last mouse event came to. Used to generate // MOUSE_ENTERED/EXITED notifications @@ -710,9 +711,7 @@ // Sometimes we may get MOUSE_EXITED after lastCommonMouseEventPeer is switched // to a peer from another window. So we must first check if this peer is // the same as lastWindowPeer - if (lastCommonMouseEventPeer != null && lastCommonMouseEventPeer.getWindowPeerOrSelf() == this) { - lastCommonMouseEventPeer = null; - } + cleanLastCommonMouseEventPeer(this); lastMouseEventPeer = null; } } else if(id == MouseEvent.MOUSE_ENTERED) { @@ -724,7 +723,7 @@ postMouseEnteredEvent(target, when, modifiers, lp, screenX, screenY, clickCount, popupTrigger, button); } - lastCommonMouseEventPeer = targetPeer; + setLastCommonMouseEventPeer(targetPeer); lastMouseEventPeer = targetPeer; } } else { @@ -853,7 +852,7 @@ postMouseExitedEvent(target, when, modifiers, oldp, screenX, screenY, clickCount, popupTrigger, button); } - lastCommonMouseEventPeer = targetPeer; + setLastCommonMouseEventPeer(targetPeer); lastMouseEventPeer = targetPeer; // Generate Mouse Enter for components @@ -1111,11 +1110,31 @@ } public static LWWindowPeer getWindowUnderCursor() { - return lastCommonMouseEventPeer != null ? lastCommonMouseEventPeer.getWindowPeerOrSelf() : null; + synchronized (lastCommonMouseEventPeerLock) { + return lastCommonMouseEventPeer != null ? lastCommonMouseEventPeer.getWindowPeerOrSelf() : null; + } } public static LWComponentPeer getPeerUnderCursor() { - return lastCommonMouseEventPeer; + synchronized (lastCommonMouseEventPeerLock) { + return lastCommonMouseEventPeer; + } + } + + static boolean cleanLastCommonMouseEventPeer(LWWindowPeer previous) { + synchronized (lastCommonMouseEventPeerLock) { + if (lastCommonMouseEventPeer != null && lastCommonMouseEventPeer.getWindowPeerOrSelf() == previous) { + lastCommonMouseEventPeer = null; + return true; + } + return false; + } + } + + static void setLastCommonMouseEventPeer(LWComponentPeer newValue) { + synchronized (lastCommonMouseEventPeerLock) { + lastCommonMouseEventPeer = newValue; + } } /* --- old/src/share/classes/sun/swing/JLightweightFrame.java 2013-09-04 12:42:15.748347100 +0400 +++ new/src/share/classes/sun/swing/JLightweightFrame.java 2013-09-04 12:42:15.576746800 +0400 @@ -25,6 +25,7 @@ package sun.swing; +import java.awt.AWTEvent; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; @@ -33,10 +34,16 @@ import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.MouseInfo; +import java.awt.Point; import java.awt.Rectangle; +import java.awt.event.AWTEventListener; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.event.ContainerEvent; import java.awt.event.ContainerListener; +import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.awt.image.DataBufferInt; import java.beans.PropertyChangeEvent; @@ -48,8 +55,10 @@ import javax.swing.JRootPane; import javax.swing.LayoutFocusTraversalPolicy; import javax.swing.RootPaneContainer; +import javax.swing.SwingUtilities; import sun.awt.LightweightFrame; +import sun.awt.LightweightFramePeer; import sun.security.action.GetPropertyAction; /** @@ -64,6 +73,15 @@ */ public final class JLightweightFrame extends LightweightFrame implements RootPaneContainer { + static { + SwingAccessor.setJLightweightFrameAccessor(new SwingAccessor.JLightweightFrameAccessor() { + @Override + public LightweightContent getLightweightContent(JLightweightFrame frame) { + return frame.content; + } + }); + } + private final JRootPane rootPane = new JRootPane(); private LightweightContent content; @@ -121,6 +139,54 @@ }; } + private LightweightFramePeer getLwPeer() { + return (LightweightFramePeer)getPeer(); + } + + private final AWTEventListener mouseEventListener = (AWTEvent event) -> { + MouseEvent m = (MouseEvent)event; + + if (!SwingUtilities.isDescendingFrom(m.getComponent(), this)) return; + + switch (m.getID()) { + case MouseEvent.MOUSE_ENTERED: + getLwPeer().setLightweightFrameUnderMouse(); + getLwPeer().updateCursorImmediately(); + break; + case MouseEvent.MOUSE_EXITED: + Point location = SwingUtilities.convertPoint(m.getComponent(), m.getPoint(), this); + if ((!this.contains(location) || !this.isActive()) && + getLwPeer().cleanLightweightFrameUnderMouse()) { + getLwPeer().updateCursorImmediately(); + } + break; + } + }; + + private final ComponentListener componentListener = new ComponentAdapter() { + @Override + public void componentShown(ComponentEvent e) { + if (getBounds().contains(MouseInfo.getPointerInfo().getLocation())) { + getLwPeer().setLightweightFrameUnderMouse(); + getLwPeer().updateCursorImmediately(); + } + } + }; + + @Override + public void addNotify() { + super.addNotify(); + getToolkit().addAWTEventListener(mouseEventListener, AWTEvent.MOUSE_EVENT_MASK); + addComponentListener(componentListener); + } + + @Override + public void removeNotify() { + super.removeNotify(); + getToolkit().removeAWTEventListener(mouseEventListener); + removeComponentListener(componentListener); + } + /** * Sets the {@link LightweightContent} instance for this frame. * The {@code JComponent} object returned by the --- old/src/share/classes/sun/swing/LightweightContent.java 2013-09-04 12:42:18.010351000 +0400 +++ new/src/share/classes/sun/swing/LightweightContent.java 2013-09-04 12:42:17.854350800 +0400 @@ -179,4 +179,12 @@ * application that the content minimum size has changed. */ public void minimumSizeChanged(int width, int height); + + /** + * Invokes a runnable on the client's toolkit thread + * @param r a runnable to invoke + */ + default public void invokeOnClientToolkitThread(Runnable r) { + throw new UnsupportedOperationException("Unsupported client implementation"); + } } --- old/src/share/classes/sun/swing/SwingAccessor.java 2013-09-04 12:42:20.287955000 +0400 +++ new/src/share/classes/sun/swing/SwingAccessor.java 2013-09-04 12:42:20.147554800 +0400 @@ -72,9 +72,24 @@ } /** + * An accessor for the sun.swing.JLightweightFrame class + */ + public interface JLightweightFrameAccessor { + + /* + * Returns the content LightweightContent for the frame + */ + LightweightContent getLightweightContent(JLightweightFrame frame); + } + + /** * The javax.swing.text.JTextComponent class accessor object. */ private static JTextComponentAccessor jtextComponentAccessor; + /** + * The sun.swing.JLightweightFrame class accessor object + */ + private static JLightweightFrameAccessor jLightweightFrameAccessor; /** * Set an accessor object for the javax.swing.text.JTextComponent class. @@ -93,4 +108,18 @@ return jtextComponentAccessor; } + + /** + * Set an accessor object for sun.swing.JLightweightFrame class + */ + public static void setJLightweightFrameAccessor(JLightweightFrameAccessor accessor) { + jLightweightFrameAccessor = accessor; + } + + /** + * Retrieve an accessor object for sun.swing.JLightweightFrame class + */ + public static JLightweightFrameAccessor getJLightweightFrameAccessor() { + return jLightweightFrameAccessor; + } } --- old/src/solaris/classes/sun/awt/X11/XLightweightFramePeer.java 2013-09-04 12:42:23.033559900 +0400 +++ new/src/solaris/classes/sun/awt/X11/XLightweightFramePeer.java 2013-09-04 12:42:22.861959600 +0400 @@ -28,13 +28,29 @@ import java.awt.Graphics; import sun.awt.LightweightFrame; +import sun.awt.LightweightFramePeer; +import sun.swing.JLightweightFrame; -public class XLightweightFramePeer extends XFramePeer { +public class XLightweightFramePeer extends XFramePeer implements LightweightFramePeer { XLightweightFramePeer(LightweightFrame target) { super(target); } + @Override + public void setLightweightFrameUnderMouse() { + XAwtState.setComponentMouseEntered(getLwTarget()); + } + + @Override + public boolean cleanLightweightFrameUnderMouse() { + if (XAwtState.getComponentMouseEntered() == getLwTarget()) { + XAwtState.setComponentMouseEntered(null); + return true; + } + return false; + } + private LightweightFrame getLwTarget() { return (LightweightFrame)target; } --- old/src/windows/classes/sun/awt/windows/WGlobalCursorManager.java 2013-09-04 12:42:25.373564000 +0400 +++ new/src/windows/classes/sun/awt/windows/WGlobalCursorManager.java 2013-09-04 12:42:25.217563700 +0400 @@ -27,6 +27,10 @@ import java.awt.*; import sun.awt.GlobalCursorManager; +import sun.awt.LightweightFrame; +import sun.swing.JLightweightFrame; +import sun.swing.LightweightContent; +import sun.swing.SwingAccessor; public final class WGlobalCursorManager extends GlobalCursorManager { private static WGlobalCursorManager manager; @@ -46,7 +50,20 @@ WGlobalCursorManager.getCursorManager().updateCursorLater(heavy); } - protected native void setCursor(Component comp, Cursor cursor, boolean u); + protected void setCursor(final Component comp, final Cursor cursor, final boolean u) { + JLightweightFrame lwFrameUnderCursor = WLightweightFramePeer.getFrameUnderCursor(); + if (lwFrameUnderCursor != null) { + LightweightContent lwContent = SwingAccessor + .getJLightweightFrameAccessor() + .getLightweightContent(lwFrameUnderCursor); + lwContent.invokeOnClientToolkitThread(() -> setCursorDirect(comp, cursor, u)); + } else { + setCursorImpl(comp, cursor, u); + } + } + + protected native void setCursorImpl(Component comp, Cursor cursor, boolean u); + protected native void setCursorDirect(Component component, Cursor cursor, boolean u); protected native void getCursorPos(Point p); protected native Component findComponentAt(Container con, int x, int y); /* --- old/src/windows/classes/sun/awt/windows/WLightweightFramePeer.java 2013-09-04 12:42:27.807168200 +0400 +++ new/src/windows/classes/sun/awt/windows/WLightweightFramePeer.java 2013-09-04 12:42:27.651168000 +0400 @@ -31,13 +31,44 @@ import java.awt.event.MouseEvent; import sun.awt.LightweightFrame; +import sun.awt.LightweightFramePeer; +import sun.awt.LightweightFramePeerInterface; +import sun.swing.JLightweightFrame; -public class WLightweightFramePeer extends WFramePeer { +public class WLightweightFramePeer extends WFramePeer implements LightweightFramePeer { public WLightweightFramePeer(LightweightFrame target) { super(target); } + private static WLightweightFramePeer lightweightFramePeerUnderMouse = null; + + @Override + public void setLightweightFrameUnderMouse() { + lightweightFramePeerUnderMouse = this; + setLWFrameUnderMouse(this); + } + + @Override + public boolean cleanLightweightFrameUnderMouse() { + if (lightweightFramePeerUnderMouse == this) { + lightweightFramePeerUnderMouse = null; + setLWFrameUnderMouse(null); + return true; + } + return false; + } + + static JLightweightFrame getFrameUnderCursor() { + if (lightweightFramePeerUnderMouse == null) { + return null; + } else { + return (JLightweightFrame)lightweightFramePeerUnderMouse.getLwTarget(); + } + } + + private static native void setLWFrameUnderMouse(WLightweightFramePeer lwFrame); + private LightweightFrame getLwTarget() { return (LightweightFrame)target; } --- old/src/windows/native/sun/windows/awt_Component.cpp 2013-09-04 12:42:30.225172500 +0400 +++ new/src/windows/native/sun/windows/awt_Component.cpp 2013-09-04 12:42:30.022372100 +0400 @@ -713,6 +713,10 @@ POINT p = { 0, 0 }; AwtComponent *comp = NULL; + if ((comp = AwtFrame::sm_lwFrameUnderMouse) != NULL) { + goto found; + } + if (useCache) { if (sm_cursorOn == NULL) { return NULL; --- old/src/windows/native/sun/windows/awt_Cursor.cpp 2013-09-04 12:42:33.376378000 +0400 +++ new/src/windows/native/sun/windows/awt_Cursor.cpp 2013-09-04 12:42:33.220377800 +0400 @@ -227,7 +227,7 @@ cur = GetCursor(env , comp); } if (cur != NULL) { - ::SetCursor(cur); + ::SetCursor(cur); } if (AwtCursor::updateCursorID == NULL) { @@ -391,16 +391,9 @@ DASSERT(hCursor); - try { - AwtCursor::setPData(self, ptr_to_jlong(new AwtCursor(env, hCursor, self, xHotSpot, - yHotSpot, nW, nH, nSS, cols, - (BYTE *)andMaskPtr))); - } catch (...) { - if (cols) { - delete[] cols; - } - throw; - } + AwtCursor::setPData(self, ptr_to_jlong(new AwtCursor(env, hCursor, self, xHotSpot, + yHotSpot, nW, nH, nSS, cols, + (BYTE *)andMaskPtr))); CATCH_BAD_ALLOC; } @@ -504,11 +497,11 @@ /* * Class: sun_awt_windows_WGlobalCursorManager - * Method: setCursor + * Method: setCursorImpl * Signature: (Ljava/awt/Component;Ljava/awt/Cursor;)V */ JNIEXPORT void JNICALL -Java_sun_awt_windows_WGlobalCursorManager_setCursor(JNIEnv *env, jobject, +Java_sun_awt_windows_WGlobalCursorManager_setCursorImpl(JNIEnv *env, jobject, jobject, jobject cursor, jboolean u) { TRY; @@ -523,6 +516,28 @@ } else { JNU_ThrowNullPointerException(env, "NullPointerException"); } + CATCH_BAD_ALLOC; +} + +/* + * Class: sun_awt_windows_WGlobalCursorManager + * Method: setCursorDirect + * Signature: (Ljava/awt/Component;Ljava/awt/Cursor;)V + */ +JNIEXPORT void JNICALL +Java_sun_awt_windows_WGlobalCursorManager_setCursorDirect(JNIEnv *env, jobject, + jobject, jobject cursor, jboolean u) +{ + TRY; + + if (cursor != NULL) { + GlobalSetCursorStruct data; + data.cursor = env->NewGlobalRef(cursor); + data.u = u; + GlobalSetCursor((void *)&data); + } else { + JNU_ThrowNullPointerException(env, "NullPointerException"); + } CATCH_BAD_ALLOC; } --- old/src/windows/native/sun/windows/awt_Frame.cpp 2013-09-04 12:42:36.199983000 +0400 +++ new/src/windows/native/sun/windows/awt_Frame.cpp 2013-09-04 12:42:36.043982700 +0400 @@ -82,6 +82,10 @@ HHOOK mouseHook; HHOOK modalHook; }; +// Struct for _SetLwFrameUnderMouse method +struct SetLwFrameUnderMouseStruct { + jobject frame; +}; /************************************************************************ * AwtFrame fields */ @@ -96,6 +100,8 @@ Hashtable AwtFrame::sm_BlockedThreads("AWTBlockedThreads"); +AwtFrame* AwtFrame::sm_lwFrameUnderMouse = NULL; + /************************************************************************ * AwtFrame methods */ @@ -1576,6 +1582,32 @@ delete nmbs; } +void AwtFrame::_SetLwFrameUnderMouse(void *param) +{ + JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); + + SetLwFrameUnderMouseStruct *sfums = (SetLwFrameUnderMouseStruct *)param; + jobject self = sfums->frame; + + if (self == NULL) { + AwtFrame::sm_lwFrameUnderMouse = NULL; + } else { + AwtFrame *frame = NULL; + + PDATA pData; + JNI_CHECK_PEER_GOTO(self, ret); + frame = (AwtFrame *)pData; + if (::IsWindow(frame->GetHWnd())) + { + AwtFrame::sm_lwFrameUnderMouse = frame; + } + } +ret: + env->DeleteGlobalRef(self); + + delete sfums; +} + /************************************************************************ * WFramePeer native methods */ @@ -1926,5 +1958,19 @@ CATCH_BAD_ALLOC; } + +JNIEXPORT void JNICALL +Java_sun_awt_windows_WLightweightFramePeer_setLWFrameUnderMouse(JNIEnv *env, jclass selfClass, jobject peer) +{ + TRY; + + SetLwFrameUnderMouseStruct *sfums = new SetLwFrameUnderMouseStruct; + sfums->frame = env->NewGlobalRef(peer); + + AwtToolkit::GetInstance().InvokeFunction(AwtFrame::_SetLwFrameUnderMouse, sfums); + // global ref and sfums are deleted in _SetLwFrameUnderMouse() + + CATCH_BAD_ALLOC; +} } /* extern "C" */ --- old/src/windows/native/sun/windows/awt_Frame.h 2013-09-04 12:42:38.742787500 +0400 +++ new/src/windows/native/sun/windows/awt_Frame.h 2013-09-04 12:42:38.493187000 +0400 @@ -48,6 +48,8 @@ FRAME_SETMENUBAR }; + static AwtFrame* sm_lwFrameUnderMouse; + /* java.awt.Frame fields and method IDs */ static jfieldID undecoratedID; @@ -144,6 +146,7 @@ static void _SetIMMOption(void *param); static void _SynthesizeWmActivate(void *param); static void _NotifyModalBlocked(void *param); + static void _SetLwFrameUnderMouse(void* param); virtual void Reshape(int x, int y, int width, int height); --- /dev/null 2013-09-04 12:42:41.000000000 +0400 +++ new/src/share/classes/sun/awt/LightweightFramePeer.java 2013-09-04 12:42:40.848791200 +0400 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.awt; + +import java.awt.peer.FramePeer; + +/** + * An interface containing the methods common to all peers of the LightweightFrame + */ +public interface LightweightFramePeer extends FramePeer { + + /** + * Sets this peer to be the window peer under mouse + */ + void setLightweightFrameUnderMouse(); + + /** + * Sets the window peer under mouse to null if the current value is equal to this peer + * @return true if the the window peer under mouse was successfully cleaned + */ + boolean cleanLightweightFrameUnderMouse(); + +}