1 /*
2  * Copyright (c) 2010, 2014, 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 import java.awt.*;
25 import java.awt.event.MouseAdapter;
26 import java.awt.event.MouseEvent;
27 import java.awt.geom.Area;
28 import java.awt.geom.GeneralPath;
29 import java.awt.geom.Rectangle2D;
30 
31 /*
32  * @test
33  * @summary Check if dynamically setting a shape works
34  *
35  * Test Description: Check if PERPIXEL_TRANSPARENT Translucency type is supported
36  *      by the current platform. Proceed if it is supported. Show a window which
37  *      contains some components and apply a shape for the Window when the window
38  *      is visible. Shape should be applied in such a way that some components
39  *      are partially clipped off. Check if the components appear only partially
40  *      and events work correctly for those components - ie, events occur only on
41  *      the areas which appear and do not occur on the clipped off areas. Events
42  *      should be checked by clicking on the visible and clipped regions. Repeat
43  *      this for Window, Dialog and Frame.
44  * Expected Result: If PERPIXEL_TRANSPARENT translucency type is supported,
45  *      clicking on clipped region should deliver the event to the background (it
46  *      should be another Window behind the test window)
47  *
48  * @author mrkam
49  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
50  * @library ../../../../lib/testlibrary
51  * @build Common ExtendedRobot
52  * @run main SetShapeDynamicallyAndClick
53  */
54 
55 public class SetShapeDynamicallyAndClick extends Common {
56 
57     Component south, center, north;
58     volatile int clicked;
59 
main(String[] args)60     public static void main(String[] args) throws Exception {
61         if (checkTranslucencyMode(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSPARENT))
62             for (Class<Window> windowClass: WINDOWS_TO_TEST)
63                 new SetShapeDynamicallyAndClick(windowClass).doTest();
64     }
65 
SetShapeDynamicallyAndClick(Class windowClass)66     public SetShapeDynamicallyAndClick(Class windowClass) throws Exception {
67         super(windowClass);
68     }
69 
70     @Override
initBackgroundFrame()71     public void initBackgroundFrame() {
72         super.initBackgroundFrame();
73         background.addMouseListener(new MouseAdapter() {
74             @Override
75             public void mouseClicked(MouseEvent e) {
76                 clicked |= 1 << 0;
77             }
78         });
79     }
80 
81     @Override
initGUI()82     public void initGUI() {
83         if (windowClass.equals(Frame.class)) {
84             window = new Frame();
85             ((Frame) window).setUndecorated(true);
86         } else  if (windowClass.equals(Dialog.class)) {
87             window = new Dialog(background);
88             ((Dialog) window).setUndecorated(true);
89         } else {
90             window = new Window(background);
91         }
92 
93         window.setLocation(2 * dl, 2 * dl);
94         window.setPreferredSize(new Dimension(200, 200));
95         window.setLayout(new BorderLayout());
96 
97         south = new Label("South");
98         south.addMouseListener(new MouseAdapter() {
99             @Override
100             public void mouseClicked(MouseEvent e) {
101                 clicked |= 1 << 3;
102             }
103         });
104         window.add(south, BorderLayout.SOUTH);
105 
106         center = new List(5);
107         center.addMouseListener(new MouseAdapter() {
108             @Override
109             public void mouseClicked(MouseEvent e) {
110                 clicked |= 1 << 2;
111             }
112         });
113         window.add(center, BorderLayout.CENTER);
114 
115         north = new TextField("North");
116         north.addMouseListener(new MouseAdapter() {
117             @Override
118             public void mouseClicked(MouseEvent e) {
119                 clicked |= 1 << 1;
120             }
121         });
122         window.add(north, BorderLayout.NORTH);
123 
124         window.pack();
125         window.setVisible(true);
126         window.toFront();
127 
128         System.out.println("Checking " + window.getClass().getName() + "...");
129     }
130 
131     @Override
doTest()132     public void doTest() throws Exception {
133 
134         robot.waitForIdle();
135 
136         Point wls = window.getLocationOnScreen();
137         Point ls;
138         int y;
139 
140         EventQueue.invokeAndWait(this::applyShape);
141 
142         robot.waitForIdle();
143 
144         ls = north.getLocationOnScreen();
145         checkClick(ls.x + north.getWidth() / 3, ls.y + north.getHeight() / 2, 1);
146 
147         ls = center.getLocationOnScreen();
148         checkClick(ls.x + center.getWidth() * 3 / 4, ls.y + center.getHeight() * 3 / 4, 2);
149 
150         ls = south.getLocationOnScreen();
151         checkClick(ls.x + south.getWidth() * 2 / 3, ls.y + south.getHeight() / 2, 3);
152 
153         ls = center.getLocationOnScreen();
154         checkClick(ls.x + center.getWidth() / 4, ls.y + center.getHeight() / 4, 2);
155 
156         ls = north.getLocationOnScreen();
157         y = ls.y + north.getHeight() / 2;
158         checkClick(wls.x + 200 - (y - wls.y), y, 0);
159 
160         EventQueue.invokeAndWait(window::toFront);
161         robot.waitForIdle();
162 
163         ls = center.getLocationOnScreen();
164         y = ls.y + center.getHeight() / 2;
165         checkClick(wls.x + 200 - (y - wls.y), y, 0);
166 
167         EventQueue.invokeAndWait(window::toFront);
168         robot.waitForIdle();
169 
170         ls = south.getLocationOnScreen();
171         y = ls.y + south.getHeight() / 2;
172         checkClick(wls.x + 200 - (y - wls.y), y, 0);
173 
174         EventQueue.invokeAndWait(window::dispose);
175         EventQueue.invokeAndWait(background::dispose);
176 
177         robot.waitForIdle();
178     }
179 
180     @Override
applyShape()181     public void applyShape() {
182         Area shape = new Area(new Rectangle2D.Float(0, 0, 200, 200));
183         GeneralPath gp;
184         gp = new GeneralPath();
185         gp.moveTo(190, 0);
186         gp.lineTo(200, 0);
187         gp.lineTo(200, 10);
188         gp.lineTo(10, 200);
189         gp.lineTo(0, 200);
190         gp.lineTo(0, 190);
191         gp.closePath();
192         shape.subtract(new Area(gp));
193 
194         window.setShape(shape);
195     }
196 
checkClick(int x, int y, int flag)197     void checkClick(int x, int y, int flag) throws Exception {
198 
199         System.out.println("Trying to click point " + x + ", " + y + ", looking for " + flag + " flag to trigger.");
200 
201         clicked = 0;
202         robot.mouseMove(x, y);
203         robot.click();
204 
205         for (int i = 0; i < 100; i++)
206             if ((clicked & (1 << flag)) == 0)
207                 robot.delay(50);
208             else
209                 break;
210 
211         if ((clicked & (1 << flag)) == 0)
212             throw new RuntimeException("FAIL: Flag " + flag + " is not triggered for point " + x + ", " + y + "!");
213     }
214 }
215