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