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
55import java.awt.Button;
56import java.awt.Checkbox;
57import java.awt.CheckboxGroup;
58import java.awt.Color;
59import java.awt.Component;
60import java.awt.Dialog;
61import java.awt.DisplayMode;
62import java.awt.Font;
63import java.awt.Frame;
64import java.awt.Graphics;
65import java.awt.GraphicsConfiguration;
66import java.awt.GraphicsDevice;
67import java.awt.GraphicsEnvironment;
68import java.awt.GridLayout;
69import java.awt.Panel;
70import java.awt.Rectangle;
71import java.awt.Window;
72import java.awt.event.ActionEvent;
73import java.awt.event.ActionListener;
74import java.awt.event.ItemEvent;
75import java.awt.event.ItemListener;
76import java.awt.event.MouseAdapter;
77import java.awt.event.MouseEvent;
78import java.awt.event.WindowAdapter;
79import java.awt.event.WindowEvent;
80import java.awt.image.BufferStrategy;
81import java.util.HashMap;
82import java.util.Random;
83
84/**
85 */
86
87public 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}
388