1 |
changeset: 10519:e1ca700aaa1f |
2 |
tag: tip |
3 |
user: neugens |
4 |
date: Fri Feb 27 15:50:03 2015 +0100 |
5 |
summary: 8071705: Java application menu misbehaves when running multiple screen stacked vertically |
6 |
|
7 |
diff --git jdk8/jdk/src/share/classes/javax/swing/JMenu.java jdk8/jdk/src/share/classes/javax/swing/JMenu.java |
8 |
--- jdk8/jdk/src/share/classes/javax/swing/JMenu.java |
9 |
+++ jdk8/jdk/src/share/classes/javax/swing/JMenu.java |
10 |
@@ -475,7 +475,8 @@ |
11 |
} |
12 |
// Then the y: |
13 |
y = s.height + yOffset; // Prefer dropping down |
14 |
- if (position.y + y + pmSize.height >= screenBounds.height && |
15 |
+ if (position.y + y + pmSize.height >= screenBounds.height |
16 |
+ + screenBounds.y && |
17 |
// popup doesn't fit - place it wherever there's more room |
18 |
screenBounds.height - s.height < 2*(position.y |
19 |
- screenBounds.y)) { |
20 |
diff --git jdk8/jdk/test/javax/swing/JMenu/8071705/bug8071705.java jdk8/jdk/test/javax/swing/JMenu/8071705/bug8071705.java |
21 |
new file mode 100644 |
22 |
--- /dev/null |
23 |
+++ jdk8/jdk/test/javax/swing/JMenu/8071705/bug8071705.java |
24 |
@@ -0,0 +1,207 @@ |
25 |
+/* |
26 |
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. |
27 |
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
28 |
+ * |
29 |
+ * This code is free software; you can redistribute it and/or modify it |
30 |
+ * under the terms of the GNU General Public License version 2 only, as |
31 |
+ * published by the Free Software Foundation. |
32 |
+ * |
33 |
+ * This code is distributed in the hope that it will be useful, but WITHOUT |
34 |
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
35 |
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
36 |
+ * version 2 for more details (a copy is included in the LICENSE file that |
37 |
+ * accompanied this code). |
38 |
+ * |
39 |
+ * You should have received a copy of the GNU General Public License version |
40 |
+ * 2 along with this work; if not, write to the Free Software Foundation, |
41 |
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
42 |
+ * |
43 |
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
44 |
+ * or visit www.oracle.com if you need additional information or have any |
45 |
+ * questions. |
46 |
+ */ |
47 |
+ |
48 |
+/* |
49 |
+ * @test |
50 |
+ * @bug 8071705 |
51 |
+ * @summary Java application menu misbehaves when running multiple screen stacked vertically |
52 |
+ * @build bug8071705 |
53 |
+ * @run main/othervm bug8071705 |
54 |
+ */ |
55 |
+ |
56 |
+import java.awt.Dimension; |
57 |
+import java.awt.GraphicsConfiguration; |
58 |
+import java.awt.GraphicsDevice; |
59 |
+import java.awt.GraphicsEnvironment; |
60 |
+import java.awt.Point; |
61 |
+import java.awt.Rectangle; |
62 |
+import java.awt.Toolkit; |
63 |
+import java.awt.event.ComponentAdapter; |
64 |
+import java.awt.event.ComponentEvent; |
65 |
+import java.awt.event.KeyEvent; |
66 |
+import java.util.concurrent.CountDownLatch; |
67 |
+ |
68 |
+import javax.swing.JFrame; |
69 |
+import javax.swing.JMenu; |
70 |
+import javax.swing.JMenuBar; |
71 |
+import javax.swing.JMenuItem; |
72 |
+import javax.swing.JPopupMenu; |
73 |
+import javax.swing.SwingUtilities; |
74 |
+import javax.swing.UIManager; |
75 |
+ |
76 |
+public class bug8071705 { |
77 |
+ |
78 |
+ public static void main(String[] args) throws Exception { |
79 |
+ |
80 |
+ final CountDownLatch latch = new CountDownLatch(1); |
81 |
+ final boolean [] result = new boolean[1]; |
82 |
+ |
83 |
+ SwingUtilities.invokeLater(new Runnable() { |
84 |
+ @Override |
85 |
+ public void run() { |
86 |
+ JFrame frame = createGUI(); |
87 |
+ GraphicsDevice[] devices = checkScreens(); |
88 |
+ |
89 |
+ // check if we have more than one and if they are stacked |
90 |
+ // vertically |
91 |
+ GraphicsDevice device = checkConfigs(devices); |
92 |
+ if (device == null) { |
93 |
+ // just pass the test |
94 |
+ frame.dispose(); |
95 |
+ result[0] = true; |
96 |
+ latch.countDown(); |
97 |
+ } else { |
98 |
+ FrameListener listener = |
99 |
+ new FrameListener(device, latch, result); |
100 |
+ frame.addComponentListener(listener); |
101 |
+ frame.setVisible(true); |
102 |
+ } |
103 |
+ } |
104 |
+ }); |
105 |
+ |
106 |
+ latch.await(); |
107 |
+ |
108 |
+ if (result[0] == false) { |
109 |
+ throw new RuntimeException("popup menu rendered in wrong position"); |
110 |
+ } |
111 |
+ |
112 |
+ System.out.println("OK"); |
113 |
+ } |
114 |
+ |
115 |
+ private static GraphicsDevice[] checkScreens() { |
116 |
+ GraphicsEnvironment ge = |
117 |
+ GraphicsEnvironment.getLocalGraphicsEnvironment(); |
118 |
+ return ge.getScreenDevices(); |
119 |
+ } |
120 |
+ |
121 |
+ private static JFrame createGUI() { |
122 |
+ JMenuBar menuBar = new JMenuBar(); |
123 |
+ JMenu menu = new JMenu("Some menu"); |
124 |
+ menuBar.add(menu); |
125 |
+ |
126 |
+ for (int i = 0; i < 10; i++) { |
127 |
+ menu.add(new JMenuItem("Some menu #" + i)); |
128 |
+ } |
129 |
+ |
130 |
+ JFrame frame = new JFrame(); |
131 |
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); |
132 |
+ frame.setMinimumSize(new Dimension(200, 200)); |
133 |
+ frame.setJMenuBar(menuBar); |
134 |
+ return frame; |
135 |
+ } |
136 |
+ |
137 |
+ private static GraphicsDevice checkConfigs(GraphicsDevice[] devices) { |
138 |
+ |
139 |
+ GraphicsDevice correctDevice = null; |
140 |
+ if (devices.length < 2) { |
141 |
+ return correctDevice; |
142 |
+ } |
143 |
+ |
144 |
+ Toolkit toolkit = Toolkit.getDefaultToolkit(); |
145 |
+ Rectangle screenBounds = new Rectangle(toolkit.getScreenSize()); |
146 |
+ int halfScreen = screenBounds.height/2; |
147 |
+ |
148 |
+ for(int i = 0; i < devices.length; i++) { |
149 |
+ if(devices[i].getType() == GraphicsDevice.TYPE_RASTER_SCREEN) { |
150 |
+ GraphicsConfiguration conf = |
151 |
+ devices[i].getDefaultConfiguration(); |
152 |
+ Rectangle bounds = conf.getBounds(); |
153 |
+ if (bounds.y >= halfScreen) { |
154 |
+ // found |
155 |
+ correctDevice = devices[i]; |
156 |
+ break; |
157 |
+ } |
158 |
+ } |
159 |
+ } |
160 |
+ return correctDevice; |
161 |
+ } |
162 |
+ |
163 |
+ private static class FrameListener extends ComponentAdapter { |
164 |
+ |
165 |
+ private GraphicsDevice device; |
166 |
+ private CountDownLatch latch; |
167 |
+ private boolean [] result; |
168 |
+ public FrameListener(GraphicsDevice device, |
169 |
+ CountDownLatch latch, |
170 |
+ boolean [] result) |
171 |
+ { |
172 |
+ this.device = device; |
173 |
+ this.latch = latch; |
174 |
+ this.result = result; |
175 |
+ } |
176 |
+ |
177 |
+ @Override |
178 |
+ public void componentShown(ComponentEvent e) { |
179 |
+ JFrame frame = (JFrame) e.getComponent(); |
180 |
+ |
181 |
+ runActualTest(device, latch, frame, result); |
182 |
+ |
183 |
+ frame.setVisible(false); |
184 |
+ frame.dispose(); |
185 |
+ latch.countDown(); |
186 |
+ } |
187 |
+ } |
188 |
+ |
189 |
+ private static Rectangle setLocation(JFrame frame, GraphicsDevice device) { |
190 |
+ GraphicsConfiguration conf = device.getDefaultConfiguration(); |
191 |
+ Rectangle bounds = conf.getBounds(); |
192 |
+ |
193 |
+ // put just below half screen |
194 |
+ int x = bounds.x + bounds.width/2; |
195 |
+ int y = bounds.y + bounds.height/2; |
196 |
+ frame.setLocation(x, y); |
197 |
+ |
198 |
+ return bounds; |
199 |
+ } |
200 |
+ |
201 |
+ private static void runActualTest(GraphicsDevice device, |
202 |
+ CountDownLatch latch, |
203 |
+ JFrame frame, |
204 |
+ boolean [] result) |
205 |
+ { |
206 |
+ Rectangle screenBounds = setLocation(frame, device); |
207 |
+ JMenu menu = frame.getJMenuBar().getMenu(0); |
208 |
+ menu.doClick(); |
209 |
+ |
210 |
+ Point location = menu.getLocationOnScreen(); |
211 |
+ JPopupMenu pm = menu.getPopupMenu(); |
212 |
+ Dimension pmSize = pm.getSize(); |
213 |
+ |
214 |
+ int yOffset = UIManager.getInt("Menu.submenuPopupOffsetY"); |
215 |
+ int height = location.y + yOffset + pmSize.height + menu.getHeight(); |
216 |
+ int available = screenBounds.y + screenBounds.height - height; |
217 |
+ if (available > 0) { |
218 |
+ Point origin = pm.getLocationOnScreen(); |
219 |
+ if (origin.y < location.y) { |
220 |
+ // growing upward, wrong! |
221 |
+ result[0] = false; |
222 |
+ } else { |
223 |
+ // growing downward, ok! |
224 |
+ result[0] = true; |
225 |
+ } |
226 |
+ } else { |
227 |
+ // there is no space, growing upward would be ok, so we pass |
228 |
+ result[0] = true; |
229 |
+ } |
230 |
+ } |
231 |
+} |
232 |
|