diff --git a/src/macosx/classes/sun/lwawt/LWWindowPeer.java b/src/macosx/classes/sun/lwawt/LWWindowPeer.java index c356a1168554ea688ffccc8b4b0ce114adee1523..5d3c88295e4e0b3ca2cca81065e3a37ae2f55732 100644 --- a/src/macosx/classes/sun/lwawt/LWWindowPeer.java +++ b/src/macosx/classes/sun/lwawt/LWWindowPeer.java @@ -675,8 +675,9 @@ public class LWWindowPeer getLWToolkit().getCursorManager().updateCursorLater(this); } - public void notifyActivation(boolean activation) { - changeFocusedWindow(activation); + public void notifyActivation(boolean activation, LWWindowPeer opposite) { + Window oppositeWindow = (opposite == null)? null : opposite.getTarget(); + changeFocusedWindow(activation, oppositeWindow); } // MouseDown in non-client area @@ -1151,6 +1152,9 @@ public class LWWindowPeer Window currentActive = KeyboardFocusManager. getCurrentKeyboardFocusManager().getActiveWindow(); + Window opposite = LWKeyboardFocusManagerPeer.getInstance(). + getCurrentFocusedWindow(); + // Make the owner active window. if (isSimpleWindow()) { LWWindowPeer owner = getOwnerFrameDialog(this); @@ -1177,16 +1181,17 @@ public class LWWindowPeer } // DKFM will synthesize all the focus/activation events correctly. - changeFocusedWindow(true); + changeFocusedWindow(true, opposite); return true; // In case the toplevel is active but not focused, change focus directly, // as requesting native focus on it will not have effect. } else if (getTarget() == currentActive && !getTarget().hasFocus()) { - changeFocusedWindow(true); + changeFocusedWindow(true, opposite); return true; } + return platformWindow.requestWindowFocus(); } @@ -1216,7 +1221,7 @@ public class LWWindowPeer /* * Changes focused window on java level. */ - private void changeFocusedWindow(boolean becomesFocused) { + private void changeFocusedWindow(boolean becomesFocused, Window opposite) { if (focusLog.isLoggable(PlatformLogger.FINE)) { focusLog.fine((becomesFocused?"gaining":"loosing") + " focus window: " + this); } @@ -1240,9 +1245,6 @@ public class LWWindowPeer } } - KeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance(); - Window oppositeWindow = becomesFocused ? kfmPeer.getCurrentFocusedWindow() : null; - // Note, the method is not called: // - when the opposite (gaining focus) window is an owned/owner window. // - for a simple window in any case. @@ -1254,10 +1256,11 @@ public class LWWindowPeer grabbingWindow.ungrab(); } + KeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance(); kfmPeer.setCurrentFocusedWindow(becomesFocused ? getTarget() : null); int eventID = becomesFocused ? WindowEvent.WINDOW_GAINED_FOCUS : WindowEvent.WINDOW_LOST_FOCUS; - WindowEvent windowEvent = new TimedWindowEvent(getTarget(), eventID, oppositeWindow, System.currentTimeMillis()); + WindowEvent windowEvent = new TimedWindowEvent(getTarget(), eventID, opposite, System.currentTimeMillis()); // TODO: wrap in SequencedEvent postEvent(windowEvent); diff --git a/src/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java b/src/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java index 2415ff7d8d83c2127871e02fc1708b5123e8edac..823beaedc4a0f5b2c4c678756224a71d956e495e 100644 --- a/src/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java +++ b/src/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java @@ -113,14 +113,14 @@ public class CEmbeddedFrame extends EmbeddedFrame { public void handleFocusEvent(boolean focused) { this.focused = focused; if (parentWindowActive) { - responder.handleWindowFocusEvent(focused); + responder.handleWindowFocusEvent(focused, null); } } public void handleWindowFocusEvent(boolean parentWindowActive) { this.parentWindowActive = parentWindowActive; if (focused) { - responder.handleWindowFocusEvent(parentWindowActive); + responder.handleWindowFocusEvent(parentWindowActive, null); } } diff --git a/src/macosx/classes/sun/lwawt/macosx/CPlatformResponder.java b/src/macosx/classes/sun/lwawt/macosx/CPlatformResponder.java index a7580a6f0cd0191d27c0e65898065c9e285249cc..c47a5f73dba29becaef16424c064b907ff2a3251 100644 --- a/src/macosx/classes/sun/lwawt/macosx/CPlatformResponder.java +++ b/src/macosx/classes/sun/lwawt/macosx/CPlatformResponder.java @@ -218,7 +218,7 @@ final class CPlatformResponder { } } - void handleWindowFocusEvent(boolean gained) { - peer.notifyActivation(gained); + void handleWindowFocusEvent(boolean gained, LWWindowPeer opposite) { + peer.notifyActivation(gained, opposite); } } diff --git a/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java b/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java index f52046e1298f2018bfabfdd58d7fd3d35dee7129..7fbc64c4f8dfd3c98d3665419bb9fda743a04bb4 100644 --- a/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java +++ b/src/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java @@ -878,13 +878,15 @@ public final class CPlatformWindow extends CFRetainedResource implements Platfor /************************************************************* * Callbacks from the AWTWindow and AWTView objc classes. *************************************************************/ - private void deliverWindowFocusEvent(boolean gained){ + private void deliverWindowFocusEvent(boolean gained, CPlatformWindow opposite){ // Fix for 7150349: ingore "gained" notifications when the app is inactive. if (gained && !((LWCToolkit)Toolkit.getDefaultToolkit()).isApplicationActive()) { focusLogger.fine("the app is inactive, so the notification is ignored"); return; } - responder.handleWindowFocusEvent(gained); + + LWWindowPeer oppositePeer = (opposite == null)? null : opposite.getPeer(); + responder.handleWindowFocusEvent(gained, oppositePeer); } private void deliverMoveResizeEvent(int x, int y, int width, int height) { diff --git a/src/macosx/native/sun/awt/AWTWindow.h b/src/macosx/native/sun/awt/AWTWindow.h index 991953f0f8f8784804152953e4b89d93154031dd..c3949a62bb11bf3428fa52fc9f1deb8255d158ea 100644 --- a/src/macosx/native/sun/awt/AWTWindow.h +++ b/src/macosx/native/sun/awt/AWTWindow.h @@ -69,6 +69,9 @@ - (BOOL) worksWhenModal; - (void)sendEvent:(NSEvent *)event; ++ (void) setLastKeyWindow:(AWTWindow *)window; ++ (AWTWindow *) lastKeyWindow; + @end @interface AWTWindow_Normal : NSWindow diff --git a/src/macosx/native/sun/awt/AWTWindow.m b/src/macosx/native/sun/awt/AWTWindow.m index f2958e388943e852ab6d04a2e0027a969041d349..3e25a6cb63c98fca83495271c5a5c5a91e2943b0 100644 --- a/src/macosx/native/sun/awt/AWTWindow.m +++ b/src/macosx/native/sun/awt/AWTWindow.m @@ -51,6 +51,14 @@ static JNF_CLASS_CACHE(jc_CPlatformWindow, "sun/lwawt/macosx/CPlatformWindow"); +// Cocoa windowDidBecomeKey/windowDidResignKey notifications +// doesn't provide information about "opposite" window, so we +// have to do a bit of tracking. This variable points to a window +// which had been the key window just before a new key window +// was set. It would be nil if the new key window isn't an AWT +// window or the app currently has no key window. +static AWTWindow* lastKeyWindow = nil; + // -------------------------------------------------------------- // NSWindow/NSPanel descendants implementation #define AWT_NS_WINDOW_IMPLEMENTATION \ @@ -505,15 +513,17 @@ AWT_ASSERT_APPKIT_THREAD; [self _deliverIconify:JNI_FALSE]; } -- (void) _deliverWindowFocusEvent:(BOOL)focused { +- (void) _deliverWindowFocusEvent:(BOOL)focused oppositeWindow:(AWTWindow *)opposite { //AWT_ASSERT_APPKIT_THREAD; - JNIEnv *env = [ThreadUtilities getJNIEnvUncached]; jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env]; if (platformWindow != NULL) { - static JNF_MEMBER_CACHE(jm_deliverWindowFocusEvent, jc_CPlatformWindow, "deliverWindowFocusEvent", "(Z)V"); - JNFCallVoidMethod(env, platformWindow, jm_deliverWindowFocusEvent, (jboolean)focused); + jobject oppositeWindow = [opposite.javaPlatformWindow jObjectWithEnv:env]; + + static JNF_MEMBER_CACHE(jm_deliverWindowFocusEvent, jc_CPlatformWindow, "deliverWindowFocusEvent", "(ZLsun/lwawt/macosx/CPlatformWindow;)V"); + JNFCallVoidMethod(env, platformWindow, jm_deliverWindowFocusEvent, (jboolean)focused, oppositeWindow); (*env)->DeleteLocalRef(env, platformWindow); + (*env)->DeleteLocalRef(env, oppositeWindow); } } @@ -522,7 +532,10 @@ AWT_ASSERT_APPKIT_THREAD; AWT_ASSERT_APPKIT_THREAD; [AWTToolkit eventCountPlusPlus]; [CMenuBar activate:self.javaMenuBar modallyDisabled:NO]; - [self _deliverWindowFocusEvent:YES]; + AWTWindow *opposite = [AWTWindow lastKeyWindow]; + [AWTWindow setLastKeyWindow:nil]; + + [self _deliverWindowFocusEvent:YES oppositeWindow: opposite]; } - (void) windowDidResignKey: (NSNotification *) notification { @@ -530,7 +543,18 @@ AWT_ASSERT_APPKIT_THREAD; AWT_ASSERT_APPKIT_THREAD; [AWTToolkit eventCountPlusPlus]; [self.javaMenuBar deactivate]; - [self _deliverWindowFocusEvent:NO]; + + // the new key window + NSWindow *keyWindow = [NSApp keyWindow]; + AWTWindow *opposite = nil; + if ([AWTWindow isAWTWindow: keyWindow]) { + opposite = (AWTWindow *)[keyWindow delegate]; + [AWTWindow setLastKeyWindow: self]; + } else { + [AWTWindow setLastKeyWindow: nil]; + } + + [self _deliverWindowFocusEvent:NO oppositeWindow: opposite]; } - (void) windowDidBecomeMain: (NSNotification *) notification { @@ -684,6 +708,17 @@ AWT_ASSERT_APPKIT_THREAD; } } ++ (void) setLastKeyWindow:(AWTWindow *)window { + [window retain]; + [lastKeyWindow release]; + lastKeyWindow = window; +} + ++ (AWTWindow *) lastKeyWindow { + return lastKeyWindow; +} + + @end // AWTWindow @@ -1208,6 +1243,10 @@ JNF_COCOA_ENTER(env); [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){ AWTWindow *window = (AWTWindow*)[nsWindow delegate]; + if ([AWTWindow lastKeyWindow] == window) { + [AWTWindow setLastKeyWindow: nil]; + } + // AWTWindow holds a reference to the NSWindow in its nsWindow // property. Unsetting the delegate allows it to be deallocated // which releases the reference. This, in turn, allows the window