mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +01:00
JBR-3676 WINDOW_ACTIVATED/DEACTIVATED events sent to a frame when child window closes on macOS
(cherry-picked from commit 824f9ebec3)
This commit is contained in:
@@ -292,23 +292,6 @@ public class LWWindowPeer
|
||||
super.setVisibleImpl(visible);
|
||||
// TODO: update graphicsConfig, see 4868278
|
||||
platformWindow.setVisible(visible);
|
||||
if (isSimpleWindow()) {
|
||||
KeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();
|
||||
if (visible) {
|
||||
if (!getTarget().isAutoRequestFocus()) {
|
||||
return;
|
||||
} else {
|
||||
requestWindowFocus(FocusEvent.Cause.ACTIVATION);
|
||||
}
|
||||
// Focus the owner in case this window is focused.
|
||||
} else if (kfmPeer.getCurrentFocusedWindow() == getTarget()) {
|
||||
// Transfer focus to the owner.
|
||||
LWWindowPeer owner = getOwnerFrameDialog(LWWindowPeer.this);
|
||||
if (owner != null) {
|
||||
owner.requestWindowFocus(FocusEvent.Cause.ACTIVATION);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -87,6 +87,7 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
|
||||
private static native void nativeSetNSWindowMinMax(long nsWindowPtr, double minW, double minH, double maxW, double maxH);
|
||||
private static native void nativePushNSWindowToBack(long nsWindowPtr);
|
||||
private static native void nativePushNSWindowToFront(long nsWindowPtr, boolean wait);
|
||||
private static native void nativeHideWindow(long nsWindowPtr, boolean wait);
|
||||
private static native void nativeSetNSWindowTitle(long nsWindowPtr, String title);
|
||||
private static native void nativeRevalidateNSWindowShadow(long nsWindowPtr);
|
||||
private static native void nativeSetNSWindowMinimizedIcon(long nsWindowPtr, long nsImage);
|
||||
@@ -713,7 +714,9 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
|
||||
|
||||
// Actually show or hide the window
|
||||
LWWindowPeer blocker = (peer == null)? null : peer.getBlocker();
|
||||
if (visible && delayShowing()) {
|
||||
if (!visible) {
|
||||
execute(ptr -> AWTThreading.executeWaitToolkit(wait -> nativeHideWindow(ptr, wait)));
|
||||
} else if (delayShowing()) {
|
||||
if (blocker == null) {
|
||||
Window focusedWindow = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow();
|
||||
LWWindowPeer focusedWindowBlocker = getBlockerFor(focusedWindow);
|
||||
@@ -723,51 +726,42 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
|
||||
owner.execute(CWrapper.NSWindow::orderFront);
|
||||
}
|
||||
}
|
||||
} else if (blocker == null || !visible) {
|
||||
} else if (blocker == null) {
|
||||
// If it ain't blocked, or is being hidden, go regular way
|
||||
if (visible) {
|
||||
contentView.execute(viewPtr -> {
|
||||
execute(ptr -> CWrapper.NSWindow.makeFirstResponder(ptr,
|
||||
viewPtr));
|
||||
});
|
||||
contentView.execute(viewPtr -> {
|
||||
execute(ptr -> CWrapper.NSWindow.makeFirstResponder(ptr,
|
||||
viewPtr));
|
||||
});
|
||||
|
||||
boolean isPopup = (target.getType() == Window.Type.POPUP);
|
||||
execute(ptr -> {
|
||||
if (isPopup) {
|
||||
// Popups in applets don't activate applet's process
|
||||
CWrapper.NSWindow.orderFrontRegardless(ptr);
|
||||
} else {
|
||||
CWrapper.NSWindow.orderFront(ptr);
|
||||
boolean isPopup = (target.getType() == Window.Type.POPUP);
|
||||
execute(ptr -> {
|
||||
if (isPopup) {
|
||||
// Popups in applets don't activate applet's process
|
||||
CWrapper.NSWindow.orderFrontRegardless(ptr);
|
||||
} else {
|
||||
CWrapper.NSWindow.orderFront(ptr);
|
||||
}
|
||||
|
||||
boolean isKeyWindow = CWrapper.NSWindow.isKeyWindow(ptr);
|
||||
if (!isKeyWindow) {
|
||||
logger.fine("setVisible: makeKeyWindow");
|
||||
CWrapper.NSWindow.makeKeyWindow(ptr);
|
||||
}
|
||||
|
||||
if (owner != null
|
||||
&& owner.getPeer() instanceof LWLightweightFramePeer) {
|
||||
LWLightweightFramePeer peer =
|
||||
(LWLightweightFramePeer) owner.getPeer();
|
||||
|
||||
long ownerWindowPtr = peer.getOverriddenWindowHandle();
|
||||
if (ownerWindowPtr != 0) {
|
||||
//Place window above JavaFX stage
|
||||
CWrapper.NSWindow.addChildWindow(
|
||||
ownerWindowPtr, ptr,
|
||||
CWrapper.NSWindow.NSWindowAbove);
|
||||
}
|
||||
|
||||
boolean isKeyWindow = CWrapper.NSWindow.isKeyWindow(ptr);
|
||||
if (!isKeyWindow) {
|
||||
logger.fine("setVisible: makeKeyWindow");
|
||||
CWrapper.NSWindow.makeKeyWindow(ptr);
|
||||
}
|
||||
|
||||
if (owner != null
|
||||
&& owner.getPeer() instanceof LWLightweightFramePeer) {
|
||||
LWLightweightFramePeer peer =
|
||||
(LWLightweightFramePeer) owner.getPeer();
|
||||
|
||||
long ownerWindowPtr = peer.getOverriddenWindowHandle();
|
||||
if (ownerWindowPtr != 0) {
|
||||
//Place window above JavaFX stage
|
||||
CWrapper.NSWindow.addChildWindow(
|
||||
ownerWindowPtr, ptr,
|
||||
CWrapper.NSWindow.NSWindowAbove);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
execute(ptr->{
|
||||
// immediately hide the window
|
||||
CWrapper.NSWindow.orderOut(ptr);
|
||||
// process the close
|
||||
CWrapper.NSWindow.close(ptr);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// otherwise, put it in a proper z-order
|
||||
CPlatformWindow bw
|
||||
|
||||
@@ -1524,6 +1524,38 @@ JNI_COCOA_ENTER(env);
|
||||
JNI_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_lwawt_macosx_CPlatformWindow
|
||||
* Method: nativeHideWindow
|
||||
* Signature: (JZ)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeHideWindow
|
||||
(JNIEnv *env, jclass clazz, jlong windowPtr, jboolean wait)
|
||||
{
|
||||
JNF_COCOA_ENTER(env);
|
||||
|
||||
NSWindow *nsWindow = OBJC(windowPtr);
|
||||
[ThreadUtilities performOnMainThreadWaiting:(BOOL)wait block:^(){
|
||||
if (nsWindow.keyWindow) {
|
||||
// When 'windowDidResignKey' is called during 'orderOut', current key window
|
||||
// is reported as 'nil', so it's impossible to create WINDOW_FOCUS_LOST event
|
||||
// with correct 'opposite' window.
|
||||
// So, as a workaround, we perform focus transfer to a parent window explicitly here.
|
||||
NSWindow *parentWindow = nsWindow;
|
||||
while ((parentWindow = ((AWTWindow*)parentWindow.delegate).ownerWindow.nsWindow) != nil) {
|
||||
if (parentWindow.canBecomeKeyWindow) {
|
||||
[parentWindow makeKeyWindow];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
[nsWindow orderOut:nsWindow];
|
||||
[nsWindow close];
|
||||
}];
|
||||
|
||||
JNF_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_lwawt_macosx_CPlatformWindow
|
||||
* Method: nativeSetNSWindowTitle
|
||||
|
||||
109
test/jdk/jb/java/awt/Window/WindowEventsOnPopupShowing.java
Normal file
109
test/jdk/jb/java/awt/Window/WindowEventsOnPopupShowing.java
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2000-2021 JetBrains s.r.o.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @summary Regression test for JBR-3676 WINDOW_ACTIVATED/DEACTIVATED events
|
||||
* sent to a frame when child window closes on macOS
|
||||
* @key headful
|
||||
*/
|
||||
|
||||
public class WindowEventsOnPopupShowing {
|
||||
private static final AtomicInteger events = new AtomicInteger();
|
||||
private static Robot robot;
|
||||
private static JFrame frame;
|
||||
private static JButton openButton;
|
||||
private static JButton closeButton;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
robot = new Robot();
|
||||
try {
|
||||
SwingUtilities.invokeAndWait(WindowEventsOnPopupShowing::initUI);
|
||||
robot.delay(1000); // wait for frame to be shown
|
||||
events.set(0);
|
||||
clickAt(openButton);
|
||||
robot.delay(1000); // wait for popup to be shown
|
||||
clickAt(closeButton);
|
||||
robot.delay(1000); // wait for popup to be closed
|
||||
int eventCount = events.get();
|
||||
if (eventCount != 0) {
|
||||
throw new RuntimeException("Unexpected events received: " + eventCount);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
SwingUtilities.invokeAndWait(WindowEventsOnPopupShowing::disposeUI);
|
||||
}
|
||||
}
|
||||
|
||||
private static void initUI() {
|
||||
openButton = new JButton("Open popup");
|
||||
closeButton = new JButton("Close");
|
||||
|
||||
frame = new JFrame("WindowEventsOnPopupShowing");
|
||||
frame.add(openButton);
|
||||
frame.pack();
|
||||
|
||||
JWindow popup = new JWindow(frame);
|
||||
popup.add(closeButton);
|
||||
popup.pack();
|
||||
|
||||
openButton.addActionListener(e -> popup.setVisible(true));
|
||||
closeButton.addActionListener(e -> popup.dispose());
|
||||
|
||||
frame.addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowActivated(WindowEvent e) {
|
||||
events.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowDeactivated(WindowEvent e) {
|
||||
events.incrementAndGet();
|
||||
}
|
||||
});
|
||||
|
||||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
private static void disposeUI() {
|
||||
if (frame != null) frame.dispose();
|
||||
}
|
||||
|
||||
private static void clickAt(int x, int y) {
|
||||
robot.mouseMove(x, y);
|
||||
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
|
||||
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
|
||||
}
|
||||
|
||||
private static void clickAt(Component component) {
|
||||
Point location = component.getLocationOnScreen();
|
||||
clickAt(location.x + component.getWidth() / 2, location.y + component.getHeight() / 2);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user