Skip to content

Commit 7c75cb3

Browse files
Jeremy Woodaivanov-jdk
authored andcommitted
8367376: Bad ButtonUI prevents other components from updating when system changes desktop properties
Reviewed-by: aivanov, prr, psadhukhan
1 parent 9891cd6 commit 7c75cb3

File tree

4 files changed

+186
-9
lines changed

4 files changed

+186
-9
lines changed

src/java.desktop/share/classes/javax/swing/plaf/metal/MetalLookAndFeel.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -2291,8 +2291,11 @@ protected void updateUI() {
22912291
setUpdatePending(true);
22922292
Runnable uiUpdater = new Runnable() {
22932293
public void run() {
2294-
updateAllUIs();
2295-
setUpdatePending(false);
2294+
try {
2295+
updateAllUIs();
2296+
} finally {
2297+
setUpdatePending(false);
2298+
}
22962299
}
22972300
};
22982301
SwingUtilities.invokeLater(uiUpdater);

src/java.desktop/share/classes/javax/swing/plaf/synth/SynthLookAndFeel.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -909,8 +909,11 @@ protected void updateUI() {
909909
Runnable uiUpdater = new Runnable() {
910910
@Override
911911
public void run() {
912-
updateAllUIs();
913-
setUpdatePending(false);
912+
try {
913+
updateAllUIs();
914+
} finally {
915+
setUpdatePending(false);
916+
}
914917
}
915918
};
916919
SwingUtilities.invokeLater(uiUpdater);

src/java.desktop/share/classes/sun/swing/plaf/DesktopProperty.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -214,8 +214,11 @@ protected void updateUI() {
214214
setUpdatePending(true);
215215
Runnable uiUpdater = new Runnable() {
216216
public void run() {
217-
updateAllUIs();
218-
setUpdatePending(false);
217+
try {
218+
updateAllUIs();
219+
} finally {
220+
setUpdatePending(false);
221+
}
219222
}
220223
};
221224
SwingUtilities.invokeLater(uiUpdater);
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
/*
2+
* Copyright (c) 2025, 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.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8367376
27+
* @key headful
28+
* @summary DesktopProperty never reset pending status to process new updates
29+
* @modules java.desktop/sun.swing.plaf
30+
* @run main DesktopPropertyResetPendingFlagTest
31+
*/
32+
33+
import javax.swing.JButton;
34+
import javax.swing.JComponent;
35+
import javax.swing.JFrame;
36+
import javax.swing.JPanel;
37+
import javax.swing.SwingUtilities;
38+
import javax.swing.UIManager;
39+
import javax.swing.plaf.basic.BasicButtonUI;
40+
41+
import sun.swing.plaf.DesktopProperty;
42+
43+
import java.awt.AWTEvent;
44+
import java.awt.EventQueue;
45+
import java.awt.Toolkit;
46+
import java.util.concurrent.CountDownLatch;
47+
import java.util.concurrent.atomic.AtomicReference;
48+
49+
public class DesktopPropertyResetPendingFlagTest extends JFrame {
50+
51+
static class ExpectedException extends RuntimeException {}
52+
53+
/**
54+
* The original ticket required changing the system accessibility settings.
55+
* But we can instead automate this test if we just create & update our own
56+
* DesktopProperty.
57+
*/
58+
static class TestDesktopProperty extends DesktopProperty {
59+
60+
public TestDesktopProperty(String key, Object fallback) {
61+
super(key, fallback);
62+
}
63+
64+
@Override
65+
public void updateUI() {
66+
super.updateUI();
67+
}
68+
}
69+
70+
private static void assertEquals(int expectedValue, int actualValue) {
71+
String msg = "expected " + expectedValue +
72+
" observed " + actualValue;
73+
if (expectedValue != actualValue) {
74+
throw new RuntimeException(msg);
75+
}
76+
System.out.println(msg);
77+
}
78+
79+
public static void main(String[] args) throws Exception {
80+
// we only override this to intercept ExpectedExceptions
81+
EventQueue newEventQueue = new EventQueue() {
82+
@Override
83+
protected void dispatchEvent(AWTEvent event) {
84+
try {
85+
super.dispatchEvent(event);
86+
} catch (ExpectedException e) {
87+
// This is part of the test. But if we don't catch
88+
// this here the test harness says our test failed.
89+
observedExpectedExceptionCounter++;
90+
}
91+
}
92+
};
93+
Toolkit.getDefaultToolkit().getSystemEventQueue().push(newEventQueue);
94+
95+
for (UIManager.LookAndFeelInfo info :
96+
UIManager.getInstalledLookAndFeels()) {
97+
System.out.println("Setting L&F: " + info.getClassName());
98+
UIManager.setLookAndFeel(info.getClassName());
99+
runTest();
100+
}
101+
}
102+
103+
private static void runTest() throws Exception {
104+
AtomicReference<JFrame> frameRef = new AtomicReference<>();
105+
SwingUtilities.invokeLater(() -> {
106+
DesktopPropertyResetPendingFlagTest t =
107+
new DesktopPropertyResetPendingFlagTest();
108+
t.pack();
109+
t.setVisible(true);
110+
frameRef.set(t);
111+
});
112+
113+
try {
114+
panelUpdateUICounter = 0;
115+
observedExpectedExceptionCounter = 0;
116+
117+
TestDesktopProperty property =
118+
new TestDesktopProperty("test", new Object());
119+
120+
SwingUtilities.invokeLater(property::updateUI);
121+
SwingUtilities.invokeAndWait(() -> {
122+
});
123+
124+
SwingUtilities.invokeLater(property::updateUI);
125+
SwingUtilities.invokeAndWait(() -> {
126+
});
127+
128+
CountDownLatch keepAliveLatch = new CountDownLatch(1);
129+
130+
SwingUtilities.invokeLater(() -> {
131+
// We expect 3 updateUI invocations: during construction, the first
132+
// property.updateUI, & the second property.updateUI
133+
assertEquals(3, panelUpdateUICounter);
134+
135+
// We expect 2 attempts on buttonUI.uninstallUI
136+
assertEquals(2, observedExpectedExceptionCounter);
137+
138+
// The test is finished
139+
keepAliveLatch.countDown();
140+
});
141+
142+
keepAliveLatch.await();
143+
} finally {
144+
SwingUtilities.invokeAndWait(() -> frameRef.get().dispose());
145+
}
146+
}
147+
148+
static int panelUpdateUICounter;
149+
static int observedExpectedExceptionCounter;
150+
151+
DesktopPropertyResetPendingFlagTest() {
152+
JButton button = new JButton("button");
153+
button.setUI(new BasicButtonUI() {
154+
@Override
155+
public void uninstallUI(JComponent c) {
156+
throw new ExpectedException();
157+
}
158+
});
159+
JPanel p = new JPanel() {
160+
@Override
161+
public void updateUI() {
162+
panelUpdateUICounter++;
163+
}
164+
};
165+
p.add(button);
166+
getContentPane().add(p);
167+
}
168+
}

0 commit comments

Comments
 (0)