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 
MultimonFullscreenTest(String title)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();
renderDimensions(Graphics g, Rectangle rectWndBounds, GraphicsConfiguration gc)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 
actionPerformed(ActionEvent ae)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 
main(String args[])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 {
windowClosing(WindowEvent we)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 }
388