1 /* 2 * Copyright (c) 2012, 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 /* @test 25 @bug 7123767 26 @summary Wrong tooltip location in Multi-Monitor configurations 27 @author Vladislav Karnaukhov 28 @run main bug7123767 29 */ 30 31 import javax.swing.*; 32 import javax.swing.plaf.metal.MetalLookAndFeel; 33 import java.awt.*; 34 import java.awt.event.MouseEvent; 35 import java.lang.reflect.InvocationTargetException; 36 37 public class bug7123767 extends JFrame { 38 39 private static class TestFactory extends PopupFactory { 40 41 private static TestFactory newFactory = new TestFactory(); 42 private static PopupFactory oldFactory; 43 44 private TestFactory() { 45 super(); 46 } 47 48 public static void install() { 49 if (oldFactory == null) { 50 oldFactory = getSharedInstance(); 51 setSharedInstance(newFactory); 52 } 53 } 54 55 public static void uninstall() { 56 if (oldFactory != null) { 57 setSharedInstance(oldFactory); 58 } 59 } 60 61 // Actual test happens here 62 public Popup getPopup(Component owner, Component contents, int x, int y) { 63 GraphicsConfiguration mouseGC = testGC(MouseInfo.getPointerInfo().getLocation()); 64 if (mouseGC == null) { 65 throw new RuntimeException("Can't find GraphicsConfiguration that mouse pointer belongs to"); 66 } 67 68 GraphicsConfiguration tipGC = testGC(new Point(x, y)); 69 if (tipGC == null) { 70 throw new RuntimeException("Can't find GraphicsConfiguration that tip belongs to"); 71 } 72 73 if (!mouseGC.equals(tipGC)) { 74 throw new RuntimeException("Mouse and tip GCs are not equal"); 75 } 76 77 return super.getPopup(owner, contents, x, y); 78 } 79 80 private static GraphicsConfiguration testGC(Point pt) { 81 GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment(); 82 GraphicsDevice[] devices = environment.getScreenDevices(); 83 for (GraphicsDevice device : devices) { 84 GraphicsConfiguration[] configs = device.getConfigurations(); 85 for (GraphicsConfiguration config : configs) { 86 Rectangle rect = config.getBounds(); 87 Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(config); 88 adjustInsets(rect, insets); 89 if (rect.contains(pt)) 90 return config; 91 } 92 } 93 94 return null; 95 } 96 } 97 98 private static final int MARGIN = 10; 99 private static bug7123767 frame; 100 private static Robot robot; 101 102 public static void main(String[] args) throws Exception { 103 UIManager.setLookAndFeel(new MetalLookAndFeel()); 104 setUp(); 105 testToolTip(); 106 TestFactory.uninstall(); 107 } 108 109 // Creates a window that is stretched across all available monitors 110 // and adds itself as ContainerListener to track tooltips drawing 111 private bug7123767() { 112 super(); 113 114 ToolTipManager.sharedInstance().setInitialDelay(0); 115 setDefaultCloseOperation(DISPOSE_ON_CLOSE); 116 TestFactory.install(); 117 118 JLabel label1 = new JLabel("no preferred location"); 119 label1.setToolTipText("tip"); 120 add(label1, BorderLayout.WEST); 121 122 JLabel label2 = new JLabel("preferred location (20000, 20000)") { 123 public Point getToolTipLocation(MouseEvent event) { 124 return new Point(20000, 20000); 125 } 126 }; 127 128 label2.setToolTipText("tip"); 129 add(label2, BorderLayout.EAST); 130 131 setUndecorated(true); 132 pack(); 133 134 Rectangle rect = new Rectangle(); 135 GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment(); 136 GraphicsDevice[] devices = environment.getScreenDevices(); 137 for (GraphicsDevice device : devices) { 138 GraphicsConfiguration[] configs = device.getConfigurations(); 139 for (GraphicsConfiguration config : configs) { 140 Insets localInsets = Toolkit.getDefaultToolkit().getScreenInsets(config); 141 Rectangle localRect = config.getBounds(); 142 adjustInsets(localRect, localInsets); 143 rect.add(localRect); 144 } 145 } 146 setBounds(rect); 147 } 148 149 private static void setUp() throws InterruptedException, InvocationTargetException { 150 SwingUtilities.invokeAndWait(new Runnable() { 151 @Override 152 public void run() { 153 frame = new bug7123767(); 154 frame.setVisible(true); 155 } 156 }); 157 } 158 159 // Moves mouse pointer to the corners of every GraphicsConfiguration 160 private static void testToolTip() throws AWTException { 161 162 robot = new Robot(); 163 robot.setAutoDelay(20); 164 robot.waitForIdle(); 165 166 GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment(); 167 GraphicsDevice[] devices = environment.getScreenDevices(); 168 for (GraphicsDevice device : devices) { 169 GraphicsConfiguration[] configs = device.getConfigurations(); 170 for (GraphicsConfiguration config : configs) { 171 Rectangle rect = config.getBounds(); 172 Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(config); 173 adjustInsets(rect, insets); 174 175 // Upper left 176 glide(rect.x + rect.width / 2, rect.y + rect.height / 2, 177 rect.x + MARGIN, rect.y + MARGIN); 178 robot.waitForIdle(); 179 180 // Lower left 181 glide(rect.x + rect.width / 2, rect.y + rect.height / 2, 182 rect.x + MARGIN, rect.y + rect.height - MARGIN); 183 robot.waitForIdle(); 184 185 // Upper right 186 glide(rect.x + rect.width / 2, rect.y + rect.height / 2, 187 rect.x + rect.width - MARGIN, rect.y + MARGIN); 188 robot.waitForIdle(); 189 190 // Lower right 191 glide(rect.x + rect.width / 2, rect.y + rect.height / 2, 192 rect.x + rect.width - MARGIN, rect.y + rect.height - MARGIN); 193 robot.waitForIdle(); 194 } 195 } 196 } 197 198 private static void glide(int x0, int y0, int x1, int y1) throws AWTException { 199 if (robot == null) { 200 robot = new Robot(); 201 robot.setAutoDelay(20); 202 } 203 204 float dmax = (float) Math.max(Math.abs(x1 - x0), Math.abs(y1 - y0)); 205 float dx = (x1 - x0) / dmax; 206 float dy = (y1 - y0) / dmax; 207 208 robot.mouseMove(x0, y0); 209 for (int i = 1; i <= dmax; i += 10) { 210 robot.mouseMove((int) (x0 + dx * i), (int) (y0 + dy * i)); 211 } 212 } 213 214 private static void adjustInsets(Rectangle rect, final Insets insets) { 215 rect.x += insets.left; 216 rect.y += insets.top; 217 rect.width -= (insets.left + insets.right); 218 rect.height -= (insets.top + insets.bottom); 219 } 220 }