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