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