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     public void initGUI() {
  77 
  78         window = new Window(background);
  79         south = new Button("South Button");
  80         center = new TextArea("Center Text Area");
  81         north = new TextField("North Text Field");
  82 
  83         window.setLocation(250, 250);
  84         window.setPreferredSize(new Dimension(200, 200));
  85         window.setOpacity(0.7f);
  86         applyShape();
  87         window.setLayout(new BorderLayout());
  88 
  89         window.add(south, BorderLayout.SOUTH);
  90         window.add(center, BorderLayout.CENTER);
  91         window.add(north, BorderLayout.NORTH);
  92 
  93         window.pack();
  94         window.setVisible(true);
  95         window.toFront();
  96 
  97         System.out.println("Checking " + window.getClass().getName() + "...");
  98     }
  99 
 100     public void doTest() throws Exception {
 101 
 102         robot.waitForIdle();
 103         robot.mouseMove(background.getLocationOnScreen().x+50, background.getLocationOnScreen().y+50);
 104         robot.waitForIdle();
 105         robot.click();
 106 
 107         Point wls = window.getLocationOnScreen();
 108         Point ls;
 109         int y;
 110 
 111         robot.waitForIdle();
 112 
 113         ls = north.getLocationOnScreen();
 114         checkClickType(ls.x + north.getWidth() / 3, ls.y + north.getHeight() / 2, northFlags);
 115 
 116         ls = center.getLocationOnScreen();
 117         checkClickType(ls.x + center.getWidth() / 4, ls.y + center.getHeight() / 4, centerFlags);
 118 
 119         ls = center.getLocationOnScreen();
 120         checkClickType(ls.x + center.getWidth() * 3 / 4, ls.y + center.getHeight() * 3 / 4, centerFlags);
 121 
 122         ls = south.getLocationOnScreen();
 123         checkClickType(ls.x + south.getWidth() * 2 / 3, ls.y + south.getHeight() / 2, southFlags);
 124 
 125         ls = north.getLocationOnScreen();
 126         y = ls.y + north.getHeight() / 2;
 127         checkClickType(wls.x + 200 - (y - wls.y), y, backgroundFlags);
 128 
 129         EventQueue.invokeAndWait(window::toFront);
 130         robot.waitForIdle();
 131 
 132         ls = center.getLocationOnScreen();
 133         y = ls.y + center.getHeight() / 2;
 134         checkClickType(wls.x + 200 - (y - wls.y), y, backgroundFlags);
 135 
 136         EventQueue.invokeAndWait(window::toFront);
 137         robot.waitForIdle();
 138 
 139         ls = south.getLocationOnScreen();
 140         y = ls.y + south.getHeight() / 2;
 141         checkClickType(wls.x + 200 - (y - wls.y), y, backgroundFlags);
 142 
 143         EventQueue.invokeAndWait(window::dispose);
 144         EventQueue.invokeAndWait(background::dispose);
 145 
 146         robot.waitForIdle();
 147     }
 148 
 149     @Override
 150     public void applyShape() {
 151         Area shape = new Area(new Rectangle2D.Float(0, 0, 200, 200));
 152         GeneralPath gp;
 153         gp = new GeneralPath();
 154         gp.moveTo(190, 0);
 155         gp.lineTo(200, 0);
 156         gp.lineTo(200, 10);
 157         gp.lineTo(10, 200);
 158         gp.lineTo(0, 200);
 159         gp.lineTo(0, 190);
 160         gp.closePath();
 161         shape.subtract(new Area(gp));
 162 
 163         window.setShape(shape);
 164     }
 165 
 166     void checkClickType(int x, int y, BitSet bits){
 167         bits.clear(0, 10);
 168 
 169         robot.mouseMove(x, y);
 170         robot.click();
 171         robot.dragAndDrop(MouseInfo.getPointerInfo().getLocation(), new Point(x+5, y));
 172         robot.mouseWheel(1);
 173         robot.waitForIdle();
 174 
 175         robot.type('a');
 176 
 177         robot.mouseMove(350, 50);
 178         robot.waitForIdle();
 179 
 180         //robot.delay(20*1000);
 181         if (!bits.equals(reference)){
 182             for( int i = 0; i < 11; i++)
 183                 System.err.print(( bits.get(i) ? 1 : 0 ) + ", ");
 184             System.err.println();
 185             throw new RuntimeException("Bit mask is not fully set: "+bits);
 186         }
 187     }
 188 
 189     static void addListeners(Component component, BitSet bits) {
 190         component.addMouseListener(new MouseListener() {
 191             public void mouseClicked(MouseEvent e) { bits.set(0);}
 192             public void mousePressed(MouseEvent e) { bits.set(1); }
 193             public void mouseReleased(MouseEvent e) { bits.set(2); }
 194             public void mouseEntered(MouseEvent e) { bits.set(3); }
 195             public void mouseExited(MouseEvent e) { bits.set(4); }
 196         });
 197         component.addMouseMotionListener(new MouseMotionListener() {
 198             public void mouseDragged(MouseEvent e) { bits.set(5); }
 199             public void mouseMoved(MouseEvent e) { bits.set(6); }
 200         });
 201         component.addMouseWheelListener((e) -> bits.set(7));
 202         component.addKeyListener(new KeyListener() {
 203             public void keyTyped(KeyEvent e) { bits.set(8); }
 204             public void keyPressed(KeyEvent e) { bits.set(9); }
 205             public void keyReleased(KeyEvent e) { bits.set(10); }
 206         });
 207     };
 208 }