Compare commits

..

10 Commits

Author SHA1 Message Date
Dmitry Batrak
ee298f5287 JBR-3024 Popups are shown with 1x1 size sometimes 2021-01-15 17:49:24 +03:00
Dmitry Batrak
a7fd723e43 log LWCToolkit invokeAndWait requests
as part of JBR-3017, to make investigation of similar issues simpler in the future
2021-01-15 15:21:05 +03:00
Dmitry Batrak
7e6db54f77 fix occasional freezes of JBR-3017 reproducer after the fix 2021-01-15 15:21:04 +03:00
Dmitry Batrak
88ead5d9e3 JBR-3017 Focus issue in presence of third-party accessibility tool 2021-01-15 15:21:04 +03:00
Dmitry Batrak
eeef67a335 refactor nativeCreateNSWindow call wrapping
as part of JBR-3017
2021-01-15 15:21:02 +03:00
Dmitry Batrak
f1dd523ba8 remove excessive wrapping with AccessController (AWTThreading does it internally now)
as part of JBR-3017
2021-01-15 15:21:01 +03:00
Vitaly Provodin
84ff4eab21 JBR-1718 add a regression test 2021-01-14 05:34:23 +07:00
Vitaly Provodin
0e7f9ce4ca JBR-2957 notarize JBR and JBRSDK as APPL 2021-01-02 07:01:23 +07:00
Elena Sayapina
1714d7b627 JBR-2890 [TESTUPDATE] Enable jcef tests on macOS aarch64 platform 2020-12-29 20:37:14 +07:00
Dmitry Batrak
95be4351d4 JBR-2934 Serious usability issue with GoLand 2020.3 caused by JBR 2020-12-28 20:37:55 +03:00
21 changed files with 297 additions and 82 deletions

View File

@@ -58,7 +58,7 @@ file="$APP_NAME.zip"
log "Zipping $file..."
rm -rf "$file"
ditto -c -k --sequesterRsrc --keepParent "$APP_DIRECTORY/Contents" "$file"
ditto -c -k --sequesterRsrc --keepParent "$APP_DIRECTORY" "$file"
log "Notarizing $file..."
rm -rf "altool.init.out" "altool.check.out"

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/bash -x
#immediately exit script with an error if a command fails
set -euo pipefail
@@ -32,8 +32,10 @@ mkdir "$BACKUP_JMODS"
log "Unzipping $INPUT_FILE to $EXPLODED ..."
tar -xzvf "$INPUT_FILE" --directory $EXPLODED
rm "$INPUT_FILE"
BUILD_NAME="$(ls "$EXPLODED")"
sed -i '' s/BNDL/APPL/ $EXPLODED/$BUILD_NAME/Contents/Info.plist
rm -f $EXPLODED/$BUILD_NAME/Contents/CodeResources
rm "$INPUT_FILE"
if test -d $EXPLODED/$BUILD_NAME/Contents/Home/jmods; then
mv $EXPLODED/$BUILD_NAME/Contents/Home/jmods $BACKUP_JMODS
fi
@@ -129,4 +131,4 @@ log "Zipping $BUILD_NAME to $INPUT_FILE ..."
log "Finished zipping"
)
rm -rf "$EXPLODED"
log "Done"
log "Done"

View File

@@ -25,7 +25,6 @@
package sun.lwawt.macosx;
import java.awt.AWTError;
import java.awt.Color;
import java.awt.Component;
import java.awt.DefaultKeyboardFocusManager;
@@ -52,7 +51,6 @@ import java.util.Comparator;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.security.PrivilegedAction;
import javax.swing.JRootPane;
import javax.swing.RootPaneContainer;
@@ -74,7 +72,6 @@ import sun.lwawt.PlatformWindow;
import sun.util.logging.PlatformLogger;
import java.security.AccessController;
import java.security.PrivilegedAction;
import sun.security.action.GetPropertyAction;
@@ -361,51 +358,41 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
} else {
bounds = _peer.constrainBounds(_target.getBounds());
}
long nativeWindowPtr = java.security.AccessController.doPrivileged(
(PrivilegedAction<Long>) () -> {
try {
return AWTThreading.executeWaitToolkit(() -> {
AtomicLong ref = new AtomicLong();
contentView.execute(viewPtr -> {
boolean hasOwnerPtr = false;
AtomicLong ref = new AtomicLong();
contentView.execute(viewPtr -> {
boolean hasOwnerPtr = false;
if (owner != null) {
hasOwnerPtr = 0L != owner.executeGet(ownerPtr -> {
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
logger.fine("nativeCreateNSWindow: owner=" + Long.toHexString(ownerPtr)
+ ", styleBits=" + Integer.toHexString(styleBits)
+ ", bounds=" + bounds);
}
long windowPtr = nativeCreateNSWindow(viewPtr, ownerPtr, styleBits,
bounds.x, bounds.y, bounds.width, bounds.height);
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
logger.fine("window created: " + Long.toHexString(windowPtr));
}
ref.set(windowPtr);
return 1;
});
}
if (!hasOwnerPtr) {
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
logger.fine("nativeCreateNSWindow: styleBits=" + Integer.toHexString(styleBits)
+ ", bounds=" + bounds);
}
long windowPtr = nativeCreateNSWindow(viewPtr, 0, styleBits,
bounds.x, bounds.y, bounds.width, bounds.height);
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
logger.fine("window created: " + Long.toHexString(windowPtr));
}
ref.set(windowPtr);
}
});
return ref.get();
});
} catch (Throwable throwable) {
throw new AWTError(throwable.getMessage());
if (owner != null) {
hasOwnerPtr = 0L != owner.executeGet(ownerPtr -> {
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
logger.fine("createNSWindow: owner=" + Long.toHexString(ownerPtr)
+ ", styleBits=" + Integer.toHexString(styleBits)
+ ", bounds=" + bounds);
}
long windowPtr = createNSWindow(viewPtr, ownerPtr, styleBits,
bounds.x, bounds.y, bounds.width, bounds.height);
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
logger.fine("window created: " + Long.toHexString(windowPtr));
}
ref.set(windowPtr);
return 1;
});
setPtr(nativeWindowPtr);
}
if (!hasOwnerPtr) {
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
logger.fine("createNSWindow: styleBits=" + Integer.toHexString(styleBits)
+ ", bounds=" + bounds);
}
long windowPtr = createNSWindow(viewPtr, 0, styleBits,
bounds.x, bounds.y, bounds.width, bounds.height);
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
logger.fine("window created: " + Long.toHexString(windowPtr));
}
ref.set(windowPtr);
}
});
setPtr(ref.get());
if (target instanceof javax.swing.RootPaneContainer) {
final javax.swing.JRootPane rootpane = ((javax.swing.RootPaneContainer)target).getRootPane();
@@ -679,7 +666,7 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
@Override // PlatformWindow
public void setBounds(int x, int y, int w, int h) {
execute(ptr -> nativeSetNSWindowBounds(ptr, x, y, w, h));
execute(ptr -> AWTThreading.executeWaitToolkit(() -> nativeSetNSWindowBounds(ptr, x, y, w, h)));
}
public void setMaximizedBounds(int x, int y, int w, int h) {
@@ -1421,6 +1408,10 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
return false;
}
private long createNSWindow(long nsViewPtr,long ownerPtr, long styleBits, double x, double y, double w, double h) {
return AWTThreading.executeWaitToolkit(() -> nativeCreateNSWindow(nsViewPtr, ownerPtr, styleBits, x, y, w, h));
}
// ----------------------------------------------------------------------
// NATIVE CALLBACKS
// ----------------------------------------------------------------------

View File

@@ -25,6 +25,8 @@
package sun.lwawt.macosx;
import sun.awt.AWTThreading;
final class CWrapper {
private CWrapper() { }
@@ -59,7 +61,11 @@ final class CWrapper {
*
* @param window the pointer of the NSWindow
*/
static native void orderOut(long window);
static void orderOut(long window) {
AWTThreading.executeWaitToolkit(() -> nativeOrderOut(window));
}
private static native void nativeOrderOut(long window);
/**
* Removes the window from the screen and releases it. According to

View File

@@ -115,6 +115,7 @@ import sun.lwawt.PlatformDropTarget;
import sun.lwawt.PlatformWindow;
import sun.lwawt.SecurityWarningWindow;
import sun.security.action.GetBooleanAction;
import sun.util.logging.PlatformLogger;
@SuppressWarnings("serial") // JDK implementation class
final class NamedCursor extends Cursor {
@@ -186,6 +187,8 @@ public final class LWCToolkit extends LWToolkit {
*/
private static final boolean inAWT;
private static final PlatformLogger log = PlatformLogger.getLogger("sun.lwawt.macosx.LWCToolkit");
public LWCToolkit() {
areExtraMouseButtonsEnabled = Boolean.parseBoolean(System.getProperty("sun.awt.enableExtraMouseButtons", "true"));
//set system property if not yet assigned
@@ -668,6 +671,11 @@ public final class LWCToolkit extends LWToolkit {
if (e != null) throw e;
return object;
}
@Override
public String toString() {
return "CallableWrapper{" + callable + "}";
}
}
private static final AtomicInteger blockingRunLoopCounter = new AtomicInteger(0);
@@ -715,6 +723,10 @@ public final class LWCToolkit extends LWToolkit {
public static void invokeAndWait(Runnable runnable, Component component, boolean processEvents)
throws InvocationTargetException
{
if (log.isLoggable(PlatformLogger.Level.FINE)) {
log.fine("invokeAndWait started: " + runnable);
}
boolean nonBlockingRunLoop;
if (!processEvents) {
@@ -754,6 +766,10 @@ public final class LWCToolkit extends LWToolkit {
doAWTRunLoop(mediator, nonBlockingRunLoop);
if (!nonBlockingRunLoop) blockingRunLoopCounter.decrementAndGet();
if (log.isLoggable(PlatformLogger.Level.FINE)) {
log.fine("invokeAndWait finished: " + runnable);
}
checkException(invocationEvent);
}

View File

@@ -1341,7 +1341,7 @@ JNF_COCOA_ENTER(env);
// TODO: not sure we need displayIfNeeded message in our view
NSWindow *nsWindow = OBJC(windowPtr);
[ThreadUtilities performOnMainThreadWaiting:NO block:^(){
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
AWTWindow *window = (AWTWindow*)[nsWindow delegate];

View File

@@ -135,11 +135,11 @@ JNF_COCOA_EXIT(env);
/*
* Class: sun_lwawt_macosx_CWrapper$NSWindow
* Method: orderOut
* Method: nativeOrderOut
* Signature: (J)V
*/
JNIEXPORT void JNICALL
Java_sun_lwawt_macosx_CWrapper_00024NSWindow_orderOut
Java_sun_lwawt_macosx_CWrapper_00024NSWindow_nativeOrderOut
(JNIEnv *env, jclass cls, jlong windowPtr)
{
JNF_COCOA_ENTER(env);
@@ -148,7 +148,7 @@ JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(orderOut:)
on:window
withObject:window
waitUntilDone:NO];
waitUntilDone:YES];
JNF_COCOA_EXIT(env);
}

View File

@@ -4,7 +4,7 @@ import sun.font.FontUtilities;
import java.awt.*;
import java.awt.event.InvocationEvent;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Map;
@@ -50,6 +50,16 @@ public class AWTThreading {
return executeWaitToolkit(callable, -1, null);
}
/**
* Same as {@link #executeWaitToolkit(Callable)}, but without returning a value.
*/
public static void executeWaitToolkit(Runnable runnable) {
executeWaitToolkit(() -> {
runnable.run();
return null;
});
}
/**
* Same as {@link #executeWaitToolkit(Callable)} except that the method waits no longer than the specified timeout.
*/
@@ -170,7 +180,7 @@ public class AWTThreading {
// - guarantees a single run either from dispatch or dispose
// - removes the invocation event from the tracking queue
new Runnable() {
SoftReference<TrackingQueue> queueRef = new SoftReference<>(queue);
WeakReference<TrackingQueue> queueRef = new WeakReference<>(queue);
@Override
public void run() {
@@ -181,7 +191,6 @@ public class AWTThreading {
TrackingQueue q = queueRef.get();
if (q != null) {
q.remove(eventRef[0]);
q.clear();
}
queueRef = null;
}

View File

@@ -1105,26 +1105,29 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
}
}
/*
* This decides on a mechanism to suppress newly created window from getting
* focus, if 'autoRequestFocus' is set to 'false'. The 'old' (historically
* used) way is to suppress WM_TAKE_FOCUS protocol temporarily, until the
* window is mapped. This approach doesn't work for i3 window manager
* though, as the latter doesn't track updates to WM_TAKE_FOCUS property
* (it's not required as per ICCCM specification). So another approach is
* used - setting _NET_WM_USER_TIME to 0, as specified in EWMH spec (see
* 'setUserTimeBeforeShowing' method). The same method is used currently for
* KDE (KWin) to solve a specific problem in 'focus follows mouse' mode
* (JBR-2934). Ideally, the new approach should be used for all supporting
* window managers, as it doesn't require additional calls to X server.
*/
private boolean shouldSuppressWmTakeFocus() {
int wmId = XWM.getWMID();
return wmId != XWM.I3_WM && wmId != XWM.KDE2_WM;
}
public void setVisible(boolean vis) {
if (!isVisible() && vis) {
isBeforeFirstMapNotify = true;
winAttr.initialFocus = isAutoRequestFocus();
if (!winAttr.initialFocus && XWM.getWMID() != XWM.I3_WM) {
/*
* It's easier and safer to temporary suppress WM_TAKE_FOCUS
* protocol itself than to ignore WM_TAKE_FOCUS client message.
* Because we will have to make the difference between
* the message come after showing and the message come after
* activation. Also, on Metacity, for some reason, we have _two_
* WM_TAKE_FOCUS client messages when showing a frame/dialog.
*
* i3 window manager doesn't track updates to WM_TAKE_FOCUS
* property, so this approach won't work for it, breaking
* focus behaviour completely. So another way is used to
* suppress focus take over - via setting _NET_WM_USER_TIME
* to 0, as specified in EWMH spec (see
* 'setUserTimeBeforeShowing' method).
*/
if (!winAttr.initialFocus && shouldSuppressWmTakeFocus()) {
suppressWmTakeFocus(true);
}
}
@@ -1202,7 +1205,7 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
@Override
void setUserTimeBeforeShowing() {
if (winAttr.initialFocus || XWM.getWMID() != XWM.I3_WM) {
if (winAttr.initialFocus || shouldSuppressWmTakeFocus()) {
super.setUserTimeBeforeShowing();
}
else {
@@ -1451,7 +1454,7 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
isUnhiding |= isWMStateNetHidden();
super.handleMapNotifyEvent(xev);
if (!winAttr.initialFocus && XWM.getWMID() != XWM.I3_WM) {
if (!winAttr.initialFocus && shouldSuppressWmTakeFocus()) {
suppressWmTakeFocus(false); // restore the protocol.
/*
* For some reason, on Metacity, a frame/dialog being shown

View File

@@ -0,0 +1,92 @@
/*
* Copyright 2000-2021 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import java.awt.AWTException;
import java.awt.Desktop;
import java.awt.Robot;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
/**
* @test
* @key headful
* @requires (os.family == "mac")
* @summary Regression test for JBR-1718.
* When opening the apps About dialog, "AboutHandler hits" should be written to the console and
* NO dialog should appear.
* @run main/othervm AboutHandlerTest
*/
public class AboutHandlerTest {
private static final int WAIT_TIME = 1000;
private static Robot robot;
private static JFrame myApp = new JFrame("MyApp");
private static boolean testPassed = false;
public static void main(String[] args) throws InterruptedException, AWTException {
robot = new Robot();
robot.setAutoDelay(50);
Desktop.getDesktop().setAboutHandler(e -> {
System.out.println("AboutHandler hits");
testPassed = true;
});
SwingUtilities.invokeLater(() -> {
doTest();
});
// waiting for AboutHandler
sleep(WAIT_TIME);
myApp.dispose();
if (!testPassed)
throw new RuntimeException("AboutHandler was not hit");
}
private static void doTest() {
myApp.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myApp.setBounds(10, 10, 100, 100);
myApp.setVisible(true);
// move at Apple's menu
robot.mouseMove(0, 0);
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
// move at AboutHandlerTest menu
robot.keyPress(KeyEvent.VK_RIGHT);
robot.keyRelease(KeyEvent.VK_RIGHT);
// move at the "About AboutHandlerTest" menu item
robot.keyPress(KeyEvent.VK_DOWN);
robot.keyRelease(KeyEvent.VK_DOWN);
// hit the "About AboutHandlerTest" menu item
robot.keyPress(KeyEvent.VK_ENTER);
robot.keyRelease(KeyEvent.VK_ENTER);
}
private static void sleep(int millis) throws InterruptedException {
Thread.sleep(millis);
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright 2021 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
* @test
* @summary Regression test for JBR-3024 Popups are shown with 1x1 size sometimes
* @key headful
*/
public class PopupSizeOnOpeningTest {
private static Robot robot;
private static JFrame frame;
private static JLabel clickPlace;
private static JWindow popup;
public static void main(String[] args) throws Exception {
robot = new Robot();
try {
SwingUtilities.invokeAndWait(PopupSizeOnOpeningTest::initUI);
robot.delay(3000);
clickAt(clickPlace); // make sure frame is focused
for (int i = 0; i < 10; i++) {
robot.delay(1000);
pressAndReleaseSpace(); // open popup
robot.delay(1000);
Dimension size = popup.getSize();
if (size.width <= 1 || size.height <= 1) {
throw new RuntimeException("Unexpected popup size: " + size);
}
pressAndReleaseSpace(); // close popup
}
} finally {
SwingUtilities.invokeAndWait(PopupSizeOnOpeningTest::disposeUI);
}
}
private static void initUI() {
frame = new JFrame("PopupSizeOnOpeningTest");
frame.setLayout(new FlowLayout());
frame.add(clickPlace = new JLabel("Click here"));
JButton openButton = new JButton("Open popup");
openButton.addActionListener(e -> {
popup = new JWindow(frame);
JButton closeButton = new JButton("Close popup");
closeButton.addActionListener(ev -> {
popup.dispose();
popup = null;
});
popup.add(closeButton);
popup.pack();
popup.setLocationRelativeTo(frame);
popup.setVisible(true);
});
frame.add(openButton);
frame.pack();
frame.setVisible(true);
}
private static void disposeUI() {
if (frame != null) frame.dispose();
}
private static void pressAndReleaseSpace() {
robot.keyPress(KeyEvent.VK_SPACE);
robot.keyRelease(KeyEvent.VK_SPACE);
}
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);
}
}

View File

@@ -17,7 +17,7 @@ import java.util.concurrent.TimeUnit;
/**
* @test
* @key headful
* @requires (os.arch != "x86" & os.arch != "i386" & os.arch != "aarch64")
* @requires (os.arch == "amd64" | os.arch == "x86_64" | (os.arch == "aarch64" & os.family == "mac"))
* @summary Regression test for JBR-2430. The test checks that JS Query is handled in 2nd opened browser.
* @run main/othervm HandleJSQueryTest
*/

View File

@@ -12,7 +12,7 @@ import java.util.function.Consumer;
/**
* @test
* @key headful
* @requires (os.family == "windows") & (os.arch != "x86" & os.arch != "i386" & os.arch != "aarch64")
* @requires (os.family == "windows") & (os.arch == "amd64" | os.arch == "x86_64")
* @summary JBR-2866 - Tests that HwFacade window used in IDEA does not bring to front when shown.
* @author Anton Tarasov
* @run main/othervm HwFacadeWindowNoFrontTest

View File

@@ -14,7 +14,7 @@ import java.util.concurrent.TimeUnit;
/**
* @test
* @key headful
* @requires (os.arch != "x86" & os.arch != "i386" & os.arch != "aarch64")
* @requires (os.arch == "amd64" | os.arch == "x86_64" | (os.arch == "aarch64" & os.family == "mac"))
* @summary Tests that JCEF starts and loads empty page with no crash
* @author Anton Tarasov
* @run main JCEFStartupTest

View File

@@ -14,7 +14,7 @@ import java.util.concurrent.TimeUnit;
/**
* @test
* @key headful
* @requires (os.arch != "x86" & os.arch != "i386" & os.arch != "aarch64")
* @requires (os.arch == "amd64" | os.arch == "x86_64" | (os.arch == "aarch64" & os.family == "mac"))
* @summary Regression test for JBR-2259. The test checks that website is loaded with and without showing Browser UI.
* @run main LoadPageWithoutUI
*/

View File

@@ -8,7 +8,7 @@ import java.util.concurrent.TimeUnit;
/**
* @test
* @key headful
* @requires (os.arch != "x86" & os.arch != "i386" & os.arch != "aarch64")
* @requires (os.arch == "amd64" | os.arch == "x86_64" | (os.arch == "aarch64" & os.family == "mac"))
* @summary Regression test for JBR-2412. The test checks that mouse actions are handled on jcef browser after hide and show it.
* @run main/othervm MouseEventAfterHideAndShowBrowserTest
*/

View File

@@ -6,7 +6,7 @@ import java.lang.reflect.InvocationTargetException;
/**
* @test
* @key headful
* @requires (os.arch != "x86" & os.arch != "i386" & os.arch != "aarch64")
* @requires (os.arch == "amd64" | os.arch == "x86_64" | (os.arch == "aarch64" & os.family == "mac"))
* @summary Regression test for JBR-2639. The test checks that mouse actions are handled on jcef browser.
* @run main/othervm MouseEventTest
*/