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