Skip to content

Commit 8cf7c96

Browse files
kurashige23Paul Hohensee
authored andcommitted
8021961: setAlwaysOnTop doesn't behave correctly in Linux/Solaris under certain scenarios
Reviewed-by: andrew Backport-of: 09a7c4bc4624dd39ab5500c394c1e298a43a711a
1 parent a226a47 commit 8cf7c96

File tree

2 files changed

+200
-11
lines changed

2 files changed

+200
-11
lines changed

jdk/src/solaris/classes/sun/awt/X11/XWindowPeer.java

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
8585
// used for modal blocking to keep existing z-order
8686
protected XWindowPeer prevTransientFor, nextTransientFor;
8787
// value of WM_TRANSIENT_FOR hint set on this window
88-
private XWindowPeer curRealTransientFor;
88+
private XBaseWindow curRealTransientFor;
8989

9090
private boolean grab = false; // Whether to do a grab during showing
9191

@@ -1052,13 +1052,23 @@ private void updateAlwaysOnTop() {
10521052
log.fine("Promoting always-on-top state {0}", Boolean.valueOf(alwaysOnTop));
10531053
}
10541054
XWM.getWM().setLayer(this,
1055-
alwaysOnTop ?
1056-
XLayerProtocol.LAYER_ALWAYS_ON_TOP :
1057-
XLayerProtocol.LAYER_NORMAL);
1055+
alwaysOnTop ?
1056+
XLayerProtocol.LAYER_ALWAYS_ON_TOP :
1057+
XLayerProtocol.LAYER_NORMAL);
10581058
}
10591059

10601060
public void updateAlwaysOnTopState() {
10611061
this.alwaysOnTop = ((Window) this.target).isAlwaysOnTop();
1062+
if (ownerPeer != null) {
1063+
XToolkit.awtLock();
1064+
try {
1065+
restoreTransientFor(this);
1066+
applyWindowType();
1067+
}
1068+
finally {
1069+
XToolkit.awtUnlock();
1070+
}
1071+
}
10621072
updateAlwaysOnTop();
10631073
}
10641074

@@ -1102,7 +1112,27 @@ public void setVisible(boolean vis) {
11021112
if (!vis && warningWindow != null) {
11031113
warningWindow.setSecurityWarningVisible(false, false);
11041114
}
1115+
boolean refreshChildsTransientFor = isVisible() != vis;
11051116
super.setVisible(vis);
1117+
if (refreshChildsTransientFor) {
1118+
for (Window child : ((Window) target).getOwnedWindows()) {
1119+
XToolkit.awtLock();
1120+
try {
1121+
if(!child.isLightweight() && child.isVisible()) {
1122+
ComponentPeer childPeer = AWTAccessor.
1123+
getComponentAccessor().getPeer(child);
1124+
if(childPeer instanceof XWindowPeer) {
1125+
XWindowPeer windowPeer = (XWindowPeer) childPeer;
1126+
restoreTransientFor(windowPeer);
1127+
windowPeer.applyWindowType();
1128+
}
1129+
}
1130+
}
1131+
finally {
1132+
XToolkit.awtUnlock();
1133+
}
1134+
}
1135+
}
11061136
if (!vis && !isWithdrawn()) {
11071137
// ICCCM, 4.1.4. Changing Window State:
11081138
// "Iconic -> Withdrawn - The client should unmap the window and follow it
@@ -1631,9 +1661,6 @@ static void setToplevelTransientFor(XWindowPeer window, XWindowPeer transientFor
16311661
window.prevTransientFor = transientForWindow;
16321662
transientForWindow.nextTransientFor = window;
16331663
}
1634-
if (window.curRealTransientFor == transientForWindow) {
1635-
return;
1636-
}
16371664
if (!allStates && (window.getWMState() != transientForWindow.getWMState())) {
16381665
return;
16391666
}
@@ -1645,11 +1672,13 @@ static void setToplevelTransientFor(XWindowPeer window, XWindowPeer transientFor
16451672
bpw = XlibUtil.getParentWindow(bpw);
16461673
}
16471674
long tpw = transientForWindow.getWindow();
1648-
while (!XlibUtil.isToplevelWindow(tpw) && !XlibUtil.isXAWTToplevelWindow(tpw)) {
1675+
XBaseWindow parent = transientForWindow;
1676+
while (tpw != 0 && ((!XlibUtil.isToplevelWindow(tpw) &&
1677+
!XlibUtil.isXAWTToplevelWindow(tpw)) || !parent.isVisible())) {
16491678
tpw = XlibUtil.getParentWindow(tpw);
1679+
parent = XToolkit.windowToXWindow(tpw);
16501680
}
16511681

1652-
XBaseWindow parent = transientForWindow;
16531682
if (parent instanceof XLightweightFramePeer) {
16541683
XLightweightFramePeer peer = (XLightweightFramePeer) parent;
16551684
long ownerWindowPtr = peer.getOverriddenWindowHandle();
@@ -1659,7 +1688,7 @@ static void setToplevelTransientFor(XWindowPeer window, XWindowPeer transientFor
16591688
}
16601689

16611690
XlibWrapper.XSetTransientFor(XToolkit.getDisplay(), bpw, tpw);
1662-
window.curRealTransientFor = transientForWindow;
1691+
window.curRealTransientFor = parent;
16631692
}
16641693

16651694
/*
@@ -1953,7 +1982,7 @@ private void applyWindowType() {
19531982
switch (getWindowType())
19541983
{
19551984
case NORMAL:
1956-
typeAtom = (ownerPeer == null) ?
1985+
typeAtom = curRealTransientFor == null ?
19571986
protocol.XA_NET_WM_WINDOW_TYPE_NORMAL :
19581987
protocol.XA_NET_WM_WINDOW_TYPE_DIALOG;
19591988
break;
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
/*
2+
* Copyright (c) 2015, 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 @summary setAlwaysOnTop doesn't behave correctly in Linux/Solaris under
26+
* certain scenarios
27+
* @bug 8021961
28+
* @author Semyon Sadetsky
29+
* @run main ChildAlwaysOnTopTest
30+
*/
31+
32+
import javax.swing.*;
33+
import java.awt.*;
34+
35+
public class ChildAlwaysOnTopTest {
36+
37+
private static Window win1;
38+
private static Window win2;
39+
private static Point point;
40+
41+
public static void main(String[] args) throws Exception {
42+
if( Toolkit.getDefaultToolkit().isAlwaysOnTopSupported() ) {
43+
44+
45+
test(null);
46+
47+
Window f = new Frame();
48+
f.setBackground(Color.darkGray);
49+
f.setSize(500, 500);
50+
try {
51+
test(f);
52+
} finally {
53+
f.dispose();
54+
}
55+
56+
f = new Frame();
57+
f.setBackground(Color.darkGray);
58+
f.setSize(500, 500);
59+
f.setVisible(true);
60+
f = new Dialog((Frame)f);
61+
try {
62+
test(f);
63+
} finally {
64+
((Frame)f.getParent()).dispose();
65+
}
66+
}
67+
System.out.println("ok");
68+
}
69+
70+
public static void test(Window parent) throws Exception {
71+
SwingUtilities.invokeAndWait(new Runnable() {
72+
@Override
73+
public void run() {
74+
win1 = parent == null ? new JDialog() : new JDialog(parent);
75+
win1.setName("top");
76+
win2 = parent == null ? new JDialog() : new JDialog(parent);
77+
win2.setName("behind");
78+
win1.setSize(200, 200);
79+
Panel panel = new Panel();
80+
panel.setBackground(Color.GREEN);
81+
win1.add(panel);
82+
panel = new Panel();
83+
panel.setBackground(Color.RED);
84+
win2.add(panel);
85+
win1.setAlwaysOnTop(true);
86+
win2.setAlwaysOnTop(false);
87+
win1.setVisible(true);
88+
}
89+
});
90+
91+
Robot robot = new Robot();
92+
robot.delay(200);
93+
robot.waitForIdle();
94+
95+
SwingUtilities.invokeAndWait(new Runnable() {
96+
@Override
97+
public void run() {
98+
point = win1.getLocationOnScreen();
99+
win2.setBounds(win1.getBounds());
100+
win2.setVisible(true);
101+
}
102+
});
103+
104+
robot.delay(200);
105+
robot.waitForIdle();
106+
107+
Color color = robot.getPixelColor(point.x + 100, point.y + 100);
108+
if(!color.equals(Color.GREEN)) {
109+
win1.dispose();
110+
win2.dispose();
111+
throw new RuntimeException("alawaysOnTop window is sent back by " +
112+
"another child window setVisible(). " + color);
113+
}
114+
115+
SwingUtilities.invokeAndWait(new Runnable() {
116+
@Override
117+
public void run() {
118+
win2.toFront();
119+
if (parent != null) {
120+
parent.setLocation(win1.getLocation());
121+
parent.toFront();
122+
}
123+
}
124+
});
125+
126+
robot.delay(200);
127+
robot.waitForIdle();
128+
129+
color = robot.getPixelColor(point.x + 100, point.y + 100);
130+
if(!color.equals(Color.GREEN)) {
131+
win1.dispose();
132+
win2.dispose();
133+
throw new RuntimeException("alawaysOnTop window is sent back by " +
134+
"another child window toFront(). " + color);
135+
}
136+
137+
SwingUtilities.invokeAndWait(new Runnable() {
138+
@Override
139+
public void run() {
140+
win1.setAlwaysOnTop(false);
141+
if (parent != null) {
142+
parent.setVisible(false);
143+
parent.setVisible(true);
144+
}
145+
win2.toFront();
146+
}
147+
});
148+
149+
robot.delay(200);
150+
robot.waitForIdle();
151+
152+
color = robot.getPixelColor(point.x + 100, point.y + 100);
153+
if(!color.equals(Color.RED)) {
154+
throw new RuntimeException("Failed to unset alawaysOnTop " + color);
155+
}
156+
157+
win1.dispose();
158+
win2.dispose();
159+
}
160+
}

0 commit comments

Comments
 (0)