1 /*
   2  * Copyright (c) 2005, 2008, 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 /**
  25  * @test
  26  * @bug 5041219
  27  * @bug 5101561
  28  * @bug 5035272
  29  * @bug 5096011
  30  * @bug 5101712
  31  * @bug 5098624
  32  * @summary Here are a few assertions worth verification:
  33  *  - the fullscreen window is positioned at 0,0
  34  *  - the fs window appears on the correct screen
  35  *  - if the exclusive FS mode is supported, no other widndow should
  36  *    overlap the fs window (including the taskbar).
  37  *    You could, however, alt+tab out of a fullscreen window, or at least
  38  *    minimize it (if you've entered the fs mode with a Window, you'll need
  39  *    to minimize the owner frame).
  40  *    Note that there may be issues with FS exclusive mode with ddraw and
  41  *    multiple fullscreen windows (one per device).
  42  *  - if display mode is supported that it did change
  43  *  - that the original display mode is restored once
  44  *    the ws window is disposed
  45  *  All of the above should work with and w/o DirectDraw
  46  *  (-Dsun.java2d.noddraw=true) on windows, and w/ and w/o opengl on X11
  47  *  (-Dsun.java2d.opengl=True).
  48  * @run main/manual/othervm -Dsun.java2d.pmoffscreen=true MultimonFullscreenTest
  49  * @run main/manual/othervm -Dsun.java2d.pmoffscreen=false MultimonFullscreenTest
  50  * @run main/manual/othervm -Dsun.java2d.d3d=True MultimonFullscreenTest
  51  * @run main/manual/othervm -Dsun.java2d.noddraw=true MultimonFullscreenTest
  52  * @run main/manual/othervm -Dsun.java2d.opengl=True MultimonFullscreenTest
  53  */
  54 
  55 import java.awt.Button;
  56 import java.awt.Checkbox;
  57 import java.awt.CheckboxGroup;
  58 import java.awt.Color;
  59 import java.awt.Component;
  60 import java.awt.Dialog;
  61 import java.awt.DisplayMode;
  62 import java.awt.Font;
  63 import java.awt.Frame;
  64 import java.awt.Graphics;
  65 import java.awt.GraphicsConfiguration;
  66 import java.awt.GraphicsDevice;
  67 import java.awt.GraphicsEnvironment;
  68 import java.awt.GridLayout;
  69 import java.awt.Panel;
  70 import java.awt.Rectangle;
  71 import java.awt.Window;
  72 import java.awt.event.ActionEvent;
  73 import java.awt.event.ActionListener;
  74 import java.awt.event.ItemEvent;
  75 import java.awt.event.ItemListener;
  76 import java.awt.event.MouseAdapter;
  77 import java.awt.event.MouseEvent;
  78 import java.awt.event.WindowAdapter;
  79 import java.awt.event.WindowEvent;
  80 import java.awt.image.BufferStrategy;
  81 import java.util.HashMap;
  82 import java.util.Random;
  83 
  84 /**
  85  */
  86 
  87 public class MultimonFullscreenTest extends Frame implements ActionListener {
  88     GraphicsDevice  defDev = GraphicsEnvironment.getLocalGraphicsEnvironment().
  89             getDefaultScreenDevice();
  90     GraphicsDevice  gd[] = GraphicsEnvironment.getLocalGraphicsEnvironment().
  91             getScreenDevices();
  92     HashMap<Button, GraphicsDevice> deviceMap;
  93 
  94     private static boolean dmChange = false;
  95     static boolean setNullOnDispose = false;
  96     static boolean useFSFrame = true;
  97     static boolean useFSWindow = false;
  98     static boolean useFSDialog = false;
  99     static boolean useBS = false;
 100     static boolean runRenderLoop = false;
 101     static boolean addHWChildren = false;
 102     static volatile boolean done = true;
 103 
 104     public MultimonFullscreenTest(String title) {
 105         super(title);
 106         addWindowListener(new WindowAdapter() {
 107             public void windowClosing(WindowEvent e) {
 108                 System.exit(0);
 109             }
 110         });
 111         Panel p = new Panel();
 112         deviceMap = new HashMap<Button, GraphicsDevice>(gd.length);
 113         int num = 0;
 114         for (GraphicsDevice dev : gd) {
 115             Button b;
 116             if (dev == defDev) {
 117                 b = new Button("Primary screen: " + num);
 118                 System.out.println("Primary Dev : " + dev + " Bounds: " +
 119                         dev.getDefaultConfiguration().getBounds());
 120             } else {
 121                 b = new Button("Secondary screen " + num);
 122                 System.out.println("Secondary Dev : " + dev + " Bounds: " +
 123                         dev.getDefaultConfiguration().getBounds());
 124             }
 125             b.addActionListener(this);
 126             p.add(b);
 127             deviceMap.put(b, dev);
 128             num++;
 129         }
 130         add("South", p);
 131         Panel p1 = new Panel();
 132         p1.setLayout(new GridLayout(2,0));
 133         Checkbox cb = new Checkbox("Change DM on entering FS");
 134         cb.addItemListener(new ItemListener() {
 135             public void itemStateChanged(ItemEvent e) {
 136                 dmChange = ((Checkbox)e.getSource()).getState();
 137             }
 138         });
 139         p1.add(cb);
 140 //        cb = new Checkbox("Exit FS on window dispose");
 141 //        cb.addItemListener(new ItemListener() {
 142 //            public void itemStateChanged(ItemEvent e) {
 143 //                setNullOnDispose = ((Checkbox)e.getSource()).getState();
 144 //            }
 145 //        });
 146 //        p1.add(cb);
 147         CheckboxGroup cbg = new CheckboxGroup();
 148         cb = new Checkbox("Use Frame to enter FS", cbg, true);
 149         cb.addItemListener(new ItemListener() {
 150             public void itemStateChanged(ItemEvent e) {
 151                 useFSFrame = true;
 152                 useFSWindow = false;
 153                 useFSDialog = false;
 154             }
 155         });
 156         p1.add(cb);
 157         cb = new Checkbox("Use Window to enter FS", cbg, false);
 158         cb.addItemListener(new ItemListener() {
 159             public void itemStateChanged(ItemEvent e) {
 160                 useFSFrame = false;
 161                 useFSWindow = true;
 162                 useFSDialog = false;
 163             }
 164         });
 165         p1.add(cb);
 166         cb = new Checkbox("Use Dialog to enter FS", cbg, false);
 167         cb.addItemListener(new ItemListener() {
 168             public void itemStateChanged(ItemEvent e) {
 169                 useFSFrame = false;
 170                 useFSWindow = false;
 171                 useFSDialog = true;
 172             }
 173         });
 174         p1.add(cb);
 175         cb = new Checkbox("Run render loop");
 176         cb.addItemListener(new ItemListener() {
 177             public void itemStateChanged(ItemEvent e) {
 178                 runRenderLoop = ((Checkbox)e.getSource()).getState();
 179             }
 180         });
 181         p1.add(cb);
 182         cb = new Checkbox("Use BufferStrategy in render loop");
 183         cb.addItemListener(new ItemListener() {
 184             public void itemStateChanged(ItemEvent e) {
 185                 useBS = ((Checkbox)e.getSource()).getState();
 186             }
 187         });
 188         p1.add(cb);
 189         cb = new Checkbox("Add Children to FS window");
 190         cb.addItemListener(new ItemListener() {
 191             public void itemStateChanged(ItemEvent e) {
 192                 addHWChildren = ((Checkbox)e.getSource()).getState();
 193             }
 194         });
 195         p1.add(cb);
 196         add("North", p1);
 197 
 198         pack();
 199         setVisible(true);
 200     }
 201 
 202     Font f = new Font("Dialog", Font.BOLD, 24);
 203     Random rnd = new Random();
 204     public void renderDimensions(Graphics g, Rectangle rectWndBounds,
 205                                  GraphicsConfiguration gc) {
 206         g.setColor(new Color(rnd.nextInt(0xffffff)));
 207         g.fillRect(0, 0, rectWndBounds.width, rectWndBounds.height);
 208 
 209         g.setColor(new Color(rnd.nextInt(0xffffff)));
 210         Rectangle rectStrBounds;
 211 
 212         g.setFont(f);
 213 
 214         rectStrBounds = g.getFontMetrics().
 215                 getStringBounds(rectWndBounds.toString(), g).getBounds();
 216         rectStrBounds.height += 30;
 217         g.drawString(rectWndBounds.toString(), 50, rectStrBounds.height);
 218         int oldHeight = rectStrBounds.height;
 219         String isFSupported = "Exclusive Fullscreen mode supported: " +
 220                               gc.getDevice().isFullScreenSupported();
 221         rectStrBounds = g.getFontMetrics().
 222                 getStringBounds(isFSupported, g).getBounds();
 223         rectStrBounds.height += (10 + oldHeight);
 224         g.drawString(isFSupported, 50, rectStrBounds.height);
 225 
 226         oldHeight = rectStrBounds.height;
 227         String isDMChangeSupported = "Display Mode Change supported: " +
 228                               gc.getDevice().isDisplayChangeSupported();
 229         rectStrBounds = g.getFontMetrics().
 230                 getStringBounds(isDMChangeSupported, g).getBounds();
 231         rectStrBounds.height += (10 + oldHeight);
 232         g.drawString(isDMChangeSupported, 50, rectStrBounds.height);
 233 
 234         oldHeight = rectStrBounds.height;
 235         String usingBS = "Using BufferStrategy: " + useBS;
 236         rectStrBounds = g.getFontMetrics().
 237                 getStringBounds(usingBS, g).getBounds();
 238         rectStrBounds.height += (10 + oldHeight);
 239         g.drawString(usingBS, 50, rectStrBounds.height);
 240 
 241         final String m_strQuitMsg = "Double-click to dispose FullScreen Window";
 242         rectStrBounds = g.getFontMetrics().
 243                 getStringBounds(m_strQuitMsg, g).getBounds();
 244         g.drawString(m_strQuitMsg,
 245                 (rectWndBounds.width - rectStrBounds.width) / 2,
 246                 (rectWndBounds.height - rectStrBounds.height) / 2);
 247 
 248 
 249     }
 250 
 251     public void actionPerformed(ActionEvent ae) {
 252         GraphicsDevice dev = deviceMap.get(ae.getSource());
 253         System.err.println("Setting FS on device:"+dev);
 254         final Window fsWindow;
 255 
 256         if (useFSWindow) {
 257             fsWindow = new Window(this, dev.getDefaultConfiguration()) {
 258                 public void paint(Graphics g) {
 259                     renderDimensions(g, getBounds(),
 260                                      this.getGraphicsConfiguration());
 261                 }
 262             };
 263         } else if (useFSDialog) {
 264             fsWindow = new Dialog((Frame)null, "FS Dialog on device "+dev, false,
 265                                  dev.getDefaultConfiguration());
 266             fsWindow.add(new Component() {
 267                 public void paint(Graphics g) {
 268                     renderDimensions(g, getBounds(),
 269                                      this.getGraphicsConfiguration());
 270                 }
 271             });
 272         } else {
 273             fsWindow = new Frame("FS Frame on device "+dev,
 274                                  dev.getDefaultConfiguration())
 275             {
 276                 public void paint(Graphics g) {
 277                     renderDimensions(g, getBounds(),
 278                                      this.getGraphicsConfiguration());
 279                 }
 280             };
 281             if (addHWChildren) {
 282                 fsWindow.add("South", new Panel() {
 283                     public void paint(Graphics g) {
 284                         g.setColor(Color.red);
 285                         g.fillRect(0, 0, getWidth(), getHeight());
 286                     }
 287                 });
 288                 fsWindow.add("North", new Button("Button, sucka!"));
 289             }
 290         }
 291         fsWindow.addMouseListener(new MouseAdapter() {
 292             public void mouseClicked(MouseEvent e) {
 293                 if (e.getClickCount() > 1) {
 294                     done = true;
 295                     fsWindow.dispose();
 296                 }
 297             }
 298         });
 299 
 300         fsWindow.addWindowListener(new WindowHandler());
 301         dev.setFullScreenWindow(fsWindow);
 302         if (dmChange && dev.isDisplayChangeSupported()) {
 303             DisplayMode dms[] = dev.getDisplayModes();
 304             DisplayMode myDM = null;
 305             for (DisplayMode dm : dms) {
 306                 if (dm.getWidth() == 800 && dm.getHeight() == 600 &&
 307                     (dm.getBitDepth() >= 16 ||
 308                      dm.getBitDepth() == DisplayMode.BIT_DEPTH_MULTI) &&
 309                      (dm.getRefreshRate() >= 60 ||
 310                       dm.getRefreshRate() == DisplayMode.REFRESH_RATE_UNKNOWN))
 311                 {
 312                     myDM = dm;
 313                     break;
 314                 }
 315             }
 316             if (myDM != null) {
 317                 System.err.println("Setting Display Mode: "+
 318                         myDM.getWidth() + "x" + myDM.getHeight() + "x" +
 319                         myDM.getBitDepth() + "@" + myDM.getRefreshRate() +
 320                         "Hz on device" + dev);
 321                 dev.setDisplayMode(myDM);
 322             } else {
 323                 System.err.println("Can't find suitable display mode.");
 324             }
 325         }
 326         done = false;
 327         if (runRenderLoop) {
 328             Thread updateThread = new Thread(new Runnable() {
 329                 public void run() {
 330                     BufferStrategy bs = null;
 331                     if (useBS) {
 332                         fsWindow.createBufferStrategy(2);
 333                         bs = fsWindow.getBufferStrategy();
 334                     }
 335                     while (!done) {
 336                         if (useBS) {
 337                             Graphics g = bs.getDrawGraphics();
 338                             renderDimensions(g, fsWindow.getBounds(),
 339                                            fsWindow.getGraphicsConfiguration());
 340                             bs.show();
 341                         } else {
 342                             fsWindow.repaint();
 343                         }
 344                         try {
 345                             Thread.sleep(1000);
 346                         } catch (InterruptedException e) {}
 347                     }
 348                     if (useBS) {
 349                         bs.dispose();
 350                     }
 351                 }
 352             });
 353             updateThread.start();
 354         }
 355     }
 356 
 357     public static void main(String args[]) {
 358         for (String s : args) {
 359             if (s.equalsIgnoreCase("-dm")) {
 360                 System.err.println("Do Display Change after entering FS mode");
 361                 dmChange = true;
 362             } else if (s.equalsIgnoreCase("-usewindow")) {
 363                 System.err.println("Using Window to enter FS mode");
 364                 useFSWindow = true;
 365             } else if (s.equalsIgnoreCase("-setnull")) {
 366                 System.err.println("Setting null FS window on dispose");
 367                 setNullOnDispose = true;
 368             } else {
 369                 System.err.println("Usage: MultimonFullscreenTest " +
 370                         "[-dm][-usewindow][-setnull]");
 371             }
 372 
 373         }
 374         MultimonFullscreenTest fs =
 375                 new MultimonFullscreenTest("Test Full Screen");
 376     }
 377     class WindowHandler extends WindowAdapter {
 378         public void windowClosing(WindowEvent we) {
 379             done = true;
 380             Window w = (Window)we.getSource();
 381             if (setNullOnDispose) {
 382                 w.getGraphicsConfiguration().getDevice().setFullScreenWindow(null);
 383             }
 384             w.dispose();
 385         }
 386     }
 387 }