001/**
002 * Copyright (c) 2011, The University of Southampton and the individual contributors.
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification,
006 * are permitted provided that the following conditions are met:
007 *
008 *   *  Redistributions of source code must retain the above copyright notice,
009 *      this list of conditions and the following disclaimer.
010 *
011 *   *  Redistributions in binary form must reproduce the above copyright notice,
012 *      this list of conditions and the following disclaimer in the documentation
013 *      and/or other materials provided with the distribution.
014 *
015 *   *  Neither the name of the University of Southampton nor the names of its
016 *      contributors may be used to endorse or promote products derived from this
017 *      software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package org.openimaj.content.slideshow;
031
032import java.awt.GraphicsDevice;
033import java.awt.GraphicsEnvironment;
034import java.awt.Window;
035import java.lang.reflect.Method;
036
037import javax.swing.JFrame;
038
039import org.apache.commons.lang.SystemUtils;
040
041/**
042 * Utility class for dealing with fullscreen Swing applications.
043 *
044 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
045 *
046 */
047public class FullscreenUtility {
048        protected JFrame window;
049        protected boolean fullscreen = false;
050
051        /**
052         * Construct with the given JFrame. The utility will allow the frame to be
053         * toggled between windowed and fullscreen mode.
054         *
055         * @param frame
056         *            The frame.
057         */
058        public FullscreenUtility(JFrame frame) {
059                this.window = frame;
060
061                if (SystemUtils.IS_OS_MAC_OSX) {
062                        // if we're on a mac, we'll add the fullscreen hint to the window so
063                        // the standard controls work
064                        try {
065                                final Class<?> util = Class.forName("com.apple.eawt.FullScreenUtilities");
066                                final Class<?> params[] = new Class[] { Window.class, Boolean.TYPE };
067                                final Method method = util.getMethod("setWindowCanFullScreen", params);
068
069                                method.invoke(util, window, true);
070                        } catch (final Exception e) {
071                                // ignore
072                        }
073                }
074        }
075
076        /**
077         * Method allows changing whether this window is displayed in fullscreen or
078         * windowed mode.
079         *
080         * @param fullscreen
081         *            true = change to fullscreen, false = change to windowed
082         */
083        public void setFullscreen(boolean fullscreen) {
084                if (this.fullscreen != fullscreen) {
085                        if (SystemUtils.IS_OS_MAC_OSX) {
086                                setFullscreenOSX(fullscreen);
087                        } else {
088                                setFullscreenAWT(fullscreen);
089                        }
090                }
091        }
092
093        // See https://bugs.openjdk.java.net/browse/JDK-8013547
094        // basically AWT fullscreen has big problems (with comboboxes and
095        // keylisteners) on OSX with Java 7 & 8 (and maybe later versions of 6).
096        // We'll try and use the EAWT fullscreen stuff if possible and fall back if
097        // not...
098        private void setFullscreenOSX(boolean fullscreen) {
099                // change modes
100                this.fullscreen = fullscreen;
101
102                try {
103                        final Class<?> appClz = Class.forName("com.apple.eawt.Application");
104                        final Method getApp = appClz.getMethod("getApplication");
105                        final Object app = getApp.invoke(appClz);
106                        final Class<?> params[] = new Class[] { Window.class };
107                        final Method reqFS = appClz.getMethod("requestToggleFullScreen", params);
108                        reqFS.invoke(app, window);
109                } catch (final ClassNotFoundException e1) {
110                } catch (final Exception e) {
111                        // revert mode change
112                        this.fullscreen = !fullscreen;
113                        setFullscreenAWT(fullscreen);
114                }
115        }
116
117        private void setFullscreenAWT(boolean fullscreen)
118        {
119                // get a reference to the device.
120                final GraphicsDevice device = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
121
122                // change modes.
123                this.fullscreen = fullscreen;
124                // toggle fullscreen mode
125                if (!fullscreen)
126                {
127                        // hide the frame so we can change it.
128                        window.setVisible(false);
129                        // remove the frame from being displayable.
130                        window.dispose();
131                        // put the borders back on the frame.
132                        window.setUndecorated(false);
133                        // needed to unset this window as the fullscreen window.
134                        device.setFullScreenWindow(null);
135                        // recenter window
136                        window.setLocationRelativeTo(null);
137                        window.setResizable(true);
138
139                        // reset the display mode to what it was before
140                        // we changed it.
141                        window.setVisible(true);
142                }
143                else
144                { // change to fullscreen.
145                        // hide everything
146                        window.setVisible(false);
147                        // remove the frame from being displayable.
148                        window.dispose();
149                        // remove borders around the frame
150                        window.setUndecorated(true);
151                        // attempt to change the screen resolution.
152                        window.setResizable(false);
153                        window.setAlwaysOnTop(false);
154                        // make the window fullscreen.
155                        device.setFullScreenWindow(window);
156
157                        if (SystemUtils.IS_JAVA_1_7 && SystemUtils.IS_OS_MAC_OSX) {
158                                System.err.println("Applying first responder fix");
159                                // OSX first responder bug:
160                                // http://mail.openjdk.java.net/pipermail/macosx-port-dev/2012-November/005109.html
161                                // unfortunately this might not be a complete fix...
162                                window.setVisible(false);
163                        }
164                        // show the frame
165                        window.setVisible(true);
166                }
167                // make sure that the screen is refreshed.
168                window.repaint();
169        }
170}