Skip to content

Commit 2493a23

Browse files
author
Martin Fox
committed
8301219: JavaFX crash when closing with the escape key
8087368: java runtime environment error when trying to execute showAndWait() function Reviewed-by: kcr, tsayao
1 parent ab68b71 commit 2493a23

File tree

5 files changed

+199
-9
lines changed

5 files changed

+199
-9
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
26+
#ifndef DELETEDMEMDEBUG_H
27+
#define DELETEDMEMDEBUG_H
28+
29+
#include <cstring>
30+
31+
//#define DEBUGDELETEDMEM
32+
33+
template <int FILL>
34+
struct DeletedMemDebug
35+
{
36+
#ifdef DEBUGDELETEDMEM
37+
public:
38+
static void operator delete(void* ptr, std::size_t sz)
39+
{
40+
::memset(ptr, FILL, sz);
41+
::operator delete(ptr);
42+
}
43+
44+
static void operator delete[](void* ptr, std::size_t sz)
45+
{
46+
::memset(ptr, FILL, sz);
47+
::operator delete[](ptr);
48+
}
49+
#endif
50+
};
51+
52+
#endif // DELETEDMEMDEBUG_H

Diff for: modules/javafx.graphics/src/main/native-glass/gtk/GlassApplication.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -480,14 +480,15 @@ static void process_events(GdkEvent* event, gpointer data)
480480
return;
481481
}
482482

483+
EventsCounterHelper helper(ctx);
484+
483485
if (ctx != NULL && ctx->hasIME() && ctx->filterIME(event)) {
484486
return;
485487
}
486488

487489
glass_evloop_call_hooks(event);
488490

489491
if (ctx != NULL) {
490-
EventsCounterHelper helper(ctx);
491492
try {
492493
switch (event->type) {
493494
case GDK_PROPERTY_NOTIFY:

Diff for: modules/javafx.graphics/src/main/native-glass/gtk/glass_view.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,13 @@
2323
* questions.
2424
*/
2525
#ifndef GLASS_VIEW_H
26-
#define GLASS_VIEW_H
26+
#define GLASS_VIEW_H
27+
28+
#include "DeletedMemDebug.h"
2729

2830
class WindowContext;
2931

30-
struct GlassView {
32+
struct GlassView : public DeletedMemDebug<0xCC> {
3133
GlassView() : current_window(), embedded_window() {}
3234

3335
WindowContext* current_window;

Diff for: modules/javafx.graphics/src/main/native-glass/gtk/glass_window.h

+12-6
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
#include <set>
3333
#include <vector>
3434

35+
#include "DeletedMemDebug.h"
36+
3537
#include "glass_view.h"
3638

3739
enum WindowManager {
@@ -92,7 +94,7 @@ struct WindowGeometry {
9294

9395
class WindowContextTop;
9496

95-
class WindowContext {
97+
class WindowContext : public DeletedMemDebug<0xCC> {
9698
public:
9799
virtual bool isEnabled() = 0;
98100
virtual bool hasIME() = 0;
@@ -341,14 +343,18 @@ class EventsCounterHelper {
341343
public:
342344
explicit EventsCounterHelper(WindowContext* context) {
343345
ctx = context;
344-
ctx->increment_events_counter();
346+
if (ctx != nullptr) {
347+
ctx->increment_events_counter();
348+
}
345349
}
346350
~EventsCounterHelper() {
347-
ctx->decrement_events_counter();
348-
if (ctx->is_dead() && ctx->get_events_count() == 0) {
349-
delete ctx;
351+
if (ctx != nullptr) {
352+
ctx->decrement_events_counter();
353+
if (ctx->is_dead() && ctx->get_events_count() == 0) {
354+
delete ctx;
355+
}
356+
ctx = NULL;
350357
}
351-
ctx = NULL;
352358
}
353359
};
354360

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
26+
package test.robot.javafx.stage;
27+
28+
import java.util.concurrent.CountDownLatch;
29+
import java.util.concurrent.TimeUnit;
30+
31+
import javafx.application.Application;
32+
import javafx.application.Platform;
33+
import javafx.scene.Scene;
34+
import javafx.scene.input.KeyCode;
35+
import javafx.scene.input.MouseButton;
36+
import javafx.scene.layout.BorderPane;
37+
import javafx.scene.control.TextArea;
38+
import javafx.scene.robot.Robot;
39+
import javafx.stage.Stage;
40+
41+
import org.junit.jupiter.api.BeforeAll;
42+
import org.junit.jupiter.api.Test;
43+
import org.junit.jupiter.api.TestInstance;
44+
import org.junit.jupiter.api.TestMethodOrder;
45+
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
46+
import org.junit.jupiter.api.Order;
47+
48+
import static org.junit.jupiter.api.Assertions.assertTrue;
49+
import static org.junit.jupiter.api.Assertions.assertFalse;
50+
51+
import test.util.Util;
52+
53+
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
54+
@TestMethodOrder(OrderAnnotation.class)
55+
public class KeyEventClosesStageTest {
56+
private static Robot robot;
57+
private static Stage stage;
58+
private static Scene scene;
59+
private static BorderPane borderPane;
60+
private static TextArea textArea;
61+
62+
private static boolean typedEventArrived = false;
63+
private static CountDownLatch startupLatch = new CountDownLatch(1);
64+
private static CountDownLatch pressedEventLatch = new CountDownLatch(1);
65+
66+
@BeforeAll
67+
public static void initFX() throws Exception {
68+
Util.launch(startupLatch, TestApp.class);
69+
70+
// When run from the command line Windows does not want to
71+
// activate the window.
72+
Util.runAndWait(() -> {
73+
int mouseX = (int) (scene.getWindow().getX() + scene.getX() +
74+
textArea.getLayoutX() + textArea.getLayoutBounds().getWidth() / 2);
75+
int mouseY = (int) (scene.getWindow().getY() + scene.getY() +
76+
textArea.getLayoutY() + textArea.getLayoutBounds().getHeight() / 2);
77+
robot.mouseMove(mouseX, mouseY);
78+
robot.mouseClick(MouseButton.PRIMARY);
79+
});
80+
Util.runAndWait(() -> {
81+
borderPane.requestFocus();
82+
});
83+
}
84+
85+
@Test
86+
@Order(1)
87+
public void pressedEventClosesStage() throws Exception {
88+
Util.runAndWait(() -> {
89+
robot.keyPress(KeyCode.ESCAPE);
90+
robot.keyRelease(KeyCode.ESCAPE);
91+
});
92+
assertTrue(pressedEventLatch.await(1000, TimeUnit.MILLISECONDS),
93+
"Pressed event arrived without crash");
94+
}
95+
96+
@Test
97+
@Order(2)
98+
public void typedEventNeverArrives() throws Exception {
99+
assertFalse(typedEventArrived, "Unexpected typed event arrived");
100+
}
101+
102+
public static class TestApp extends Application {
103+
@Override
104+
public void start(Stage primaryStage) {
105+
robot = new Robot();
106+
stage = primaryStage;
107+
108+
textArea = new TextArea();
109+
borderPane = new BorderPane(textArea);
110+
borderPane.setOnKeyPressed(e -> {
111+
if (e.getCode() == KeyCode.ESCAPE) {
112+
stage.close();
113+
Platform.runLater(pressedEventLatch::countDown);
114+
}
115+
});
116+
borderPane.setOnKeyTyped(e -> {
117+
typedEventArrived = true;
118+
});
119+
120+
scene = new Scene(borderPane, 200, 200);
121+
stage.setScene(scene);
122+
stage.setOnShown(event -> {
123+
Platform.runLater(startupLatch::countDown);
124+
});
125+
stage.setAlwaysOnTop(true);
126+
stage.show();
127+
}
128+
}
129+
}

0 commit comments

Comments
 (0)