8381037: Remove AppContext from miscellaneous awt shared classes

Reviewed-by: azvegint, dnguyen
This commit is contained in:
Phil Race 2026-04-01 18:36:47 +00:00
parent 9131c72d63
commit 3cb4d7db19
11 changed files with 20 additions and 355 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2026, 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
@ -203,8 +203,8 @@ class EventDispatchThread extends Thread {
eq.dispatchEvent(event);
}
catch (InterruptedException interruptedException) {
doDispatch = false; // AppContext.dispose() interrupts all
// Threads in the AppContext
// keep this catch case for compatibility
doDispatch = false;
}
catch (Throwable e) {
processException(e);

View File

@ -2264,15 +2264,14 @@ public abstract class KeyboardFocusManager
temporary, descendant, cause);
// Fix 5028014. Rolled out.
// SunToolkit.postPriorityEvent(currentFocusOwnerEvent);
SunToolkit.postEvent(currentFocusOwner.appContext,
currentFocusOwnerEvent);
SunToolkit.postEvent(currentFocusOwnerEvent);
}
FocusEvent newFocusOwnerEvent =
new FocusEvent(descendant, FocusEvent.FOCUS_GAINED,
temporary, currentFocusOwner, cause);
// Fix 5028014. Rolled out.
// SunToolkit.postPriorityEvent(newFocusOwnerEvent);
SunToolkit.postEvent(descendant.appContext, newFocusOwnerEvent);
SunToolkit.postEvent(newFocusOwnerEvent);
if (focusLog.isLoggable(PlatformLogger.Level.FINEST))
focusLog.finest("2. SNFH_HANDLED for {0}", String.valueOf(descendant));

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2026, 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
@ -27,7 +27,6 @@ package java.awt;
import java.io.Serial;
import sun.awt.AppContext;
import sun.awt.SunToolkit;
/**
@ -51,22 +50,16 @@ class SentEvent extends AWTEvent implements ActiveEvent {
boolean dispatched;
private AWTEvent nested;
@SuppressWarnings("serial") // Not statically typed as Serializable
private AppContext toNotify;
SentEvent() {
this(null);
}
SentEvent(AWTEvent nested) {
this(nested, null);
}
SentEvent(AWTEvent nested, AppContext toNotify) {
super((nested != null)
? nested.getSource()
: Toolkit.getDefaultToolkit(),
ID);
this.nested = nested;
this.toNotify = toNotify;
}
public void dispatch() {
@ -76,9 +69,6 @@ class SentEvent extends AWTEvent implements ActiveEvent {
}
} finally {
dispatched = true;
if (toNotify != null) {
SunToolkit.postEvent(toNotify, new SentEvent());
}
synchronized (this) {
notifyAll();
}
@ -86,9 +76,6 @@ class SentEvent extends AWTEvent implements ActiveEvent {
}
final void dispose() {
dispatched = true;
if (toNotify != null) {
SunToolkit.postEvent(toNotify, new SentEvent());
}
synchronized (this) {
notifyAll();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2026, 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
@ -211,8 +211,6 @@ class WaitDispatchSupport implements SecondaryLoop {
}
}, interval);
}
// Dispose SequencedEvent we are dispatching on the current
// AppContext, to prevent us from hang - see 4531693 for details
SequencedEvent currentSE = KeyboardFocusManager.
getCurrentKeyboardFocusManager().getCurrentSequencedEvent();
if (currentSE != null) {

View File

@ -164,11 +164,8 @@ public abstract class EmbeddedFrame extends Frame
}
/**
* Because there may be many AppContexts, and we can't be sure where this
* EmbeddedFrame is first created or shown, we can't automatically determine
* the correct KeyboardFocusManager to attach to as KeyEventDispatcher.
* Those who want to use the functionality of traversing out of the EmbeddedFrame
* must call this method on the AppContext. After that, all the changes
* must call this method. After that, all the changes
* can be handled automatically, including possible replacement of
* KeyboardFocusManager.
*/
@ -184,7 +181,7 @@ public abstract class EmbeddedFrame extends Frame
/**
* Needed to avoid memory leak: we register this EmbeddedFrame as a listener with
* KeyboardFocusManager of an AppContext. We don't want the KFM to keep
* the KeyboardFocusManager. We don't want the KFM to keep
* reference to our EmbeddedFrame forever if the Frame is no longer in use, so we
* add listeners in show() and remove them in hide().
*/
@ -198,7 +195,7 @@ public abstract class EmbeddedFrame extends Frame
/**
* Needed to avoid memory leak: we register this EmbeddedFrame as a listener with
* KeyboardFocusManager of an AppContext. We don't want the KFM to keep
* the KeyboardFocusManager. We don't want the KFM to keep
* reference to our EmbeddedFrame forever if the Frame is no longer in use, so we
* add listeners in show() and remove them in hide().
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2026, 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
@ -61,7 +61,7 @@ public abstract class GlobalCursorManager {
}
}
if (shouldPost) {
SunToolkit.postEvent(SunToolkit.targetToAppContext(heavy), in);
SunToolkit.postEvent(in);
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2026, 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
@ -127,7 +127,7 @@ public abstract class KeyboardFocusManagerPeerImpl implements KeyboardFocusManag
if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
focusLog.finer("Posting focus event: " + fl);
}
SunToolkit.postEvent(SunToolkit.targetToAppContext(currentOwner), fl);
SunToolkit.postEvent(fl);
}
FocusEvent fg = new FocusEvent(lightweightChild, FocusEvent.FOCUS_GAINED,
@ -136,7 +136,7 @@ public abstract class KeyboardFocusManagerPeerImpl implements KeyboardFocusManag
if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
focusLog.finer("Posting focus event: " + fg);
}
SunToolkit.postEvent(SunToolkit.targetToAppContext(lightweightChild), fg);
SunToolkit.postEvent(fg);
return true;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2026, 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
@ -93,7 +93,7 @@ public class PaintEventDispatcher {
* This method is invoked from the toolkit thread when the surface
* data of the component needs to be replaced. The method run() of
* the Runnable argument performs surface data replacing, run()
* should be invoked on the EDT of this component's AppContext.
* should be invoked on the EDT.
* Returns true if the Runnable has been enqueued to be invoked
* on the EDT.
* (Fix 6255371.)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2026, 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
@ -2480,30 +2480,12 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE {
* SunGraphicsEnvironment it performs the same initialization as is
* performed normally. There may be some duplication of effort, but
* that code is already written to be able to perform properly if called
* to duplicate work. The main difference is that if we detect we are
* in an AppContext environment these new fonts
* are not placed in the "default" maps but into an AppContext instance.
* The font lookup mechanism in java.awt.Font.getFont2D() is also updated
* so that look-up for composite fonts will in that case always
* do a lookup rather than returning a cached result.
* This is inefficient but necessary else singleton java.awt.Font
* instances would not retrieve the correct Font2D for the appcontext.
* sun.font.FontManager.findFont2D is also updated to that it uses
* a name map cache specific to that appcontext.
*
* Getting an AppContext is expensive, so there is a global variable
* that records whether these methods have ever been called and can
* avoid the expense for almost all applications. Once the correct
* CompositeFont is associated with the Font, everything should work
* through existing mechanisms.
* A special case is that GraphicsEnvironment.getAllFonts() must
* return an AppContext specific list.
* to duplicate work.
*
* Calling the methods below is "heavyweight" but it is expected that
* these methods will be called very rarely.
*
* If _usingAlternateComposites is true, we are not in an "AppContext"
* environment and the (single) application has selected
* If _usingAlternateComposites is true, the application has selected
* an alternate composite font behaviour.
*
* - Printing: The implementation delegates logical fonts to an AWT

View File

@ -1,205 +0,0 @@
/*
* Copyright (c) 2009, 2017, 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.
*
* 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.
*/
/**
* @test
* @bug 6799345
* @key headful
* @summary Tests that no exceptions are thrown from TimerQueue and
* SwingWorker on AppContext shutdown
* @author art
* @modules java.desktop/sun.awt
* @run main TestShutdown
*/
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import sun.awt.*;
public class TestShutdown
{
private static AppContext targetAppContext;
private static JFrame f;
private static JTextField tf;
private static volatile boolean exceptionsOccurred = false;
private static volatile boolean appcontextInitDone = false;
private static int timerValue = 0;
public static void main(String[] args)
throws Exception
{
ThreadGroup tg = new TestThreadGroup("TTG");
Thread t = new Thread(tg, new TestRunnable(), "InitThread");
t.start();
while (!appcontextInitDone)
{
Thread.sleep(1000);
}
targetAppContext.dispose();
if (exceptionsOccurred)
{
throw new RuntimeException("Test FAILED: some exceptions occurred");
}
}
static void initGUI()
{
f = new JFrame("F");
f.setBounds(100, 100, 200, 100);
tf = new JTextField("Test");
f.add(tf);
f.setVisible(true);
}
static void startGUI()
{
// caret blink Timer
tf.requestFocusInWindow();
// misc Timer
ActionListener al = new ActionListener()
{
@Override
public void actionPerformed(ActionEvent ae)
{
System.out.println("Timer tick: " + timerValue++);
}
};
new javax.swing.Timer(30, al).start();
}
static class TestThreadGroup extends ThreadGroup
{
public TestThreadGroup(String name)
{
super(name);
}
@Override
public synchronized void uncaughtException(Thread thread, Throwable t)
{
if (t instanceof ThreadDeath)
{
// this one is expected, rethrow
throw (ThreadDeath)t;
}
System.err.println("Test FAILED: an exception is caught in the " +
"target thread group on thread " + thread.getName());
t.printStackTrace(System.err);
exceptionsOccurred = true;
}
}
static class TestRunnable implements Runnable
{
@Override
public void run()
{
SunToolkit stk = (SunToolkit)Toolkit.getDefaultToolkit();
targetAppContext = stk.createNewAppContext();
// create and show frame and text field
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
initGUI();
}
});
stk.realSync();
// start some Timers
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
startGUI();
}
});
// start multiple SwingWorkers
while (!Thread.interrupted())
{
try
{
new TestSwingWorker().execute();
Thread.sleep(40);
}
catch (Exception e)
{
// exception here is expected, skip
break;
}
}
}
}
static class TestSwingWorker extends SwingWorker<String, Integer>
{
@Override
public String doInBackground()
{
Random r = new Random();
for (int i = 0; i < 10; i++)
{
try
{
int delay = r.nextInt() % 50;
Thread.sleep(delay);
publish(delay);
}
catch (Exception z)
{
break;
}
}
if (!appcontextInitDone)
{
appcontextInitDone = true;
}
return "Done";
}
@Override
public void process(java.util.List<Integer> chunks)
{
for (Integer i : chunks)
{
System.err.println("Processed: " + i);
}
}
}
}

View File

@ -1,93 +0,0 @@
/*
* Copyright (c) 2013, 2015, 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.
*
* 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.
*/
/*
* @test
* @bug 8012933
* @summary Tests (although somewhat indirectly) that createNewAppContext()
* immediately followed by dispose() works correctly
* @author Leonid Romanov
* @modules java.desktop/sun.awt
*/
import sun.awt.SunToolkit;
import sun.awt.AppContext;
public class Test8012933 {
private AppContext appContext = null;
final ThreadGroup threadGroup = new ThreadGroup("test thread group");
final Object lock = new Object();
boolean isCreated = false;
public static void main(String[] args) throws Exception {
SunToolkit.createNewAppContext();
new Test8012933().test();
}
private void test() throws Exception {
createAppContext();
long startTime = System.currentTimeMillis();
appContext.dispose();
long endTime = System.currentTimeMillis();
// In case of the bug, calling dispose() when there is no EQ
// dispatch thread running fails to create it, so it takes
// almost 10 sec to return from dispose(), which is spent
// waiting on the notificationLock.
if ((endTime - startTime) > 9000) {
throw new RuntimeException("Returning from dispose() took too much time, probably a bug");
}
}
private void createAppContext() {
isCreated = false;
final Runnable runnable = new Runnable() {
public void run() {
appContext = SunToolkit.createNewAppContext();
synchronized (lock) {
isCreated = true;
lock.notifyAll();
}
}
};
final Thread thread = new Thread(threadGroup, runnable, "creates app context");
synchronized (lock) {
thread.start();
while (!isCreated) {
try {
lock.wait();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
if (appContext == null) {
throw new RuntimeException("failed to create app context.");
} else {
System.out.println("app context was created.");
}
}
}