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.*;
  26 import java.awt.geom.Area;
  27 import java.awt.geom.GeneralPath;
  28 import java.awt.geom.Rectangle2D;
  29 import java.util.BitSet;
  30 
  31 /*
  32  * @test
  33  * @summary Check if a translucent shaped window trigger events correctly.
  34  *
  35  * Test Description: Check if TRANSLUCENT and PERPIXEL_TRANSPARENT traslucency
  36  *      types are supported on the current platform. Proceed if both are
  37  *      supported. Create a window with some components in it and a shape
  38  *      applied. Apply the shape such that some components are partially
  39  *      clipped. Set an opacity value less than 1. Check if the components
  40  *      behave correctly on mouse and key events. Do this test for awt Window.
  41  * Expected Result: Mouse and key events must work correctly. Only that portion
  42  *      of a component within the shape should trigger events. Key events
  43  *      should be tested for focus events and TextField/TextArea.
  44  *
  45  * @author mrkam
  46  * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com)
  47  * @library ../../../../lib/testlibrary
  48  * @build Common ExtendedRobot
  49  * @run main ShapedTranslucentWindowClick
  50  */
  51 
  52 public class ShapedTranslucentWindowClick extends Common {
  53 
  54     Component south, center, north;
  55 
  56     volatile BitSet backgroundFlags = new BitSet(11);
  57     volatile BitSet southFlags = new BitSet(11);
  58     volatile BitSet centerFlags = new BitSet(11);
  59     volatile BitSet northFlags = new BitSet(11);
  60     static BitSet reference = BitSet.valueOf(new long[] {2047}); // 111 1111 1111
  61 
  62     public static void main(String[] ignored) throws Exception{
  63         if (checkTranslucencyMode(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSPARENT) &&
  64                 checkTranslucencyMode(GraphicsDevice.WindowTranslucency.TRANSLUCENT))
  65             new ShapedTranslucentWindowClick(Window.class).doTest();
  66     }
  67 
  68     public ShapedTranslucentWindowClick(Class windowClass) throws Exception {
  69         super(windowClass);
  70         addListeners(south, southFlags);
  71         addListeners(center, centerFlags);
  72         addListeners(north, northFlags);
  73         addListeners(background, backgroundFlags);
  74     }
  75 
  76     @Override
  77     public void initGUI() {
  78 
  79         window = new Window(background);
  80         south = new Button("South Button");
  81         center = new TextArea("Center Text Area");
  82         north = new TextField("North Text Field");
  83 
  84         window.setLocation(250, 250);
  85         window.setPreferredSize(new Dimension(200, 200));
  86         window.setOpacity(0.7f);
  87         applyShape();
  88         window.setLayout(new BorderLayout());
  89 
  90         window.add(south, BorderLayout.SOUTH);
  91         window.add(center, BorderLayout.CENTER);
  92         window.add(north, BorderLayout.NORTH);
  93 
  94         window.pack();
  95         window.setVisible(true);
  96         window.toFront();
  97 
  98         System.out.println("Checking " + window.getClass().getName() + "...");
  99     }
 100 
 101     @Override
 102     public void doTest() throws Exception {
 103 
 104         robot.waitForIdle();
 105         robot.mouseMove(background.getLocationOnScreen().x+50, background.getLocationOnScreen().y+50);
 106         robot.waitForIdle();
 107         robot.click();
 108 
 109         Point wls = window.getLocationOnScreen();
 110         Point ls;
 111         int y;
 112 
 113         robot.waitForIdle();
 114 
 115         ls = north.getLocationOnScreen();
 116         checkClickAndType(ls.x + north.getWidth() / 3, ls.y + north.getHeight() / 2, northFlags);
 117 
 118         ls = center.getLocationOnScreen();
 119         checkClickAndType(ls.x + center.getWidth() / 4, ls.y + center.getHeight() / 4, centerFlags);
 120 
 121         ls = center.getLocationOnScreen();
 122         checkClickAndType(ls.x + center.getWidth() * 3 / 4, ls.y + center.getHeight() * 3 / 4, centerFlags);
 123 
 124         ls = south.getLocationOnScreen();
 125         checkClickAndType(ls.x + south.getWidth() * 2 / 3, ls.y + south.getHeight() / 2, southFlags);
 126 
 127         ls = north.getLocationOnScreen();
 128         y = ls.y + north.getHeight() / 2;
 129         checkClickAndType(wls.x + 200 - (y - wls.y), y, backgroundFlags);
 130 
 131         EventQueue.invokeAndWait(window::toFront);
 132         robot.waitForIdle();
 133 
 134         ls = center.getLocationOnScreen();
 135         y = ls.y + center.getHeight() / 2;
 136         checkClickAndType(wls.x + 200 - (y - wls.y), y, backgroundFlags);
 137 
 138         EventQueue.invokeAndWait(window::toFront);
 139         robot.waitForIdle();
 140 
 141         ls = south.getLocationOnScreen();
 142         y = ls.y + south.getHeight() / 2;
 143         checkClickAndType(wls.x + 200 - (y - wls.y), y, backgroundFlags);
 144 
 145         EventQueue.invokeAndWait(window::dispose);
 146         EventQueue.invokeAndWait(background::dispose);
 147 
 148         robot.waitForIdle();
 149     }
 150 
 151     @Override
 152     public void applyShape() {
 153         Area shape = new Area(new Rectangle2D.Float(0, 0, 200, 200));
 154         GeneralPath gp;
 155         gp = new GeneralPath();
 156         gp.moveTo(190, 0);
 157         gp.lineTo(200, 0);
 158         gp.lineTo(200, 10);
 159         gp.lineTo(10, 200);
 160         gp.lineTo(0, 200);
 161         gp.lineTo(0, 190);
 162         gp.closePath();
 163         shape.subtract(new Area(gp));
 164 
 165         window.setShape(shape);
 166     }
 167 
 168     void checkClickAndType(int x, int y, BitSet bits){
 169         bits.clear(0, 10);
 170 
 171         robot.mouseMove(x, y);
 172         robot.click();
 173         robot.dragAndDrop(MouseInfo.getPointerInfo().getLocation(), new Point(x+5, y));
 174         robot.mouseWheel(1);
 175         robot.waitForIdle();
 176 
 177         robot.type('a');
 178 
 179         robot.mouseMove(350, 50);
 180         robot.waitForIdle();
 181 
 182         //robot.delay(20*1000);
 183         if (!bits.equals(reference)){
 184             for( int i = 0; i < 11; i++)
 185                 System.err.print(( bits.get(i) ? 1 : 0 ) + ", ");
 186             System.err.println();
 187             throw new RuntimeException("Bit mask is not fully set: "+bits);
 188         }
 189     }
 190 
 191     static void addListeners(Component component, BitSet bits) {
 192         component.addMouseListener(new MouseListener() {
 193             public void mouseClicked(MouseEvent e) { bits.set(0);}
 194             public void mousePressed(MouseEvent e) { bits.set(1); }
 195             public void mouseReleased(MouseEvent e) { bits.set(2); }
 196             public void mouseEntered(MouseEvent e) { bits.set(3); }
 197             public void mouseExited(MouseEvent e) { bits.set(4); }
 198         });
 199         component.addMouseMotionListener(new MouseMotionListener() {
 200             public void mouseDragged(MouseEvent e) { bits.set(5); }
 201             public void mouseMoved(MouseEvent e) { bits.set(6); }
 202         });
 203         component.addMouseWheelListener((e) -> bits.set(7));
 204         component.addKeyListener(new KeyListener() {
 205             public void keyTyped(KeyEvent e) { bits.set(8); }
 206             public void keyPressed(KeyEvent e) { bits.set(9); }
 207             public void keyReleased(KeyEvent e) { bits.set(10); }
 208         });
 209     };
 210 }