/*
* Copyright 2003-2010 Tufts University Licensed under the
* Educational Community License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may
* obtain a copy of the License at
*
* http://www.osedu.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS"
* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package tufts.vue.gui;
import tufts.Util;
import tufts.vue.Actions;
import tufts.vue.VUE;
import tufts.vue.LWMap;
import tufts.vue.DEBUG;
import tufts.vue.MapViewer;
import tufts.vue.VueTool;
import tufts.vue.VueToolbarController;
import tufts.vue.ZoomTool;
import tufts.macosx.MacOSX;
import java.awt.*;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JWindow;
import org.apache.log4j.NDC;
/**
* Code for providing, entering and exiting VUE full screen modes.
*
* @version $Revision: 1.54 $ / $Date: 2010-03-11 21:23:34 $ / $Author: mike $
*
*/
// This code is pretty messy as it's full of old commented out experimental workarounds
// for java limitations relating to window parentage, visibility & z-order. The current
// code seems to be the only thing that actually works, but lots of old code is left in
// all over the place in case we have problems with this again. I've submitted an RFC
// for Java with Sun Micro on this, which was accepted, but the desired clean
// functionality won't be in there till Java 6 at the earliest, maybe not till Java 7.
// -- SMF 2007-05-22
// See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6373178
public class FullScreen
{
private static final org.apache.log4j.Logger Log = org.apache.log4j.Logger.getLogger(FullScreen.class);
private static boolean fullScreenWorking = false;
private static boolean fullScreenNative = false; // using native full-screen mode, that hides even mac menu bar?
private static boolean nativeModeHidAllDockWindows;
private static FSWindow FullScreenWindow;
private static MapViewer FullScreenViewer;
private static MapViewer FullScreenLastActiveViewer;
private static GraphicsDevice FullScreenDevice;
private static final String FULLSCREEN_NAME = "*FULLSCREEN*";
public static final String VIEWER_NAME = "FULL";
//private static final boolean ExtraDockWindowHiding = !Util.isMacPlatform(); // must be done on WinXP
// this "must be done" on XP -- need to recall why
// It also is nice to be done on Mac OS X or the DockWindows appear over the temporary "working"
// full screen window during a presentation (as would be expected), when we drop into that mode
// to allow the display of an external app for content display (e.g., a web browser)
// This may also end up being required for Leopard, tho it's anyones guess what that might
// take at this point...
private static final boolean ExtraDockWindowHiding = true;
/**
* The special full-screen window for VUE -- overrides setVisible for special handling
*/
public static class FSWindow extends javax.swing.JWindow
{
private VueMenuBar mainMenuBar;
private boolean isHidden = false;
private boolean screenBlacked = false;
FSWindow() {
super(VUE.getApplicationFrame());
if (GUI.isMacBrushedMetal())
setName(GUI.OVERRIDE_REDIRECT); // so no background flashing of the texture
else
setName(FULLSCREEN_NAME);
GUI.setRootPaneNames(this, FULLSCREEN_NAME);
if (DEBUG.DOCK) {
Util.printStackTrace("creating FSWindow");
setOffScreen();
if (Util.isMacPlatform() && DockWindow.useManagedWindowHacks()) {
setVisibleImpl(true, true);
setVisibleImpl(false, true);
} else {
super.setVisible(true);
setFocusableWindowState(false);
}
} else {
setOffScreen();
setBackground(Color.black);
if (Util.isMacPlatform() && DockWindow.useManagedWindowHacks()) {
//=============================================================================
// On the Mac, this window *MUST* be shown before any DockWindows display, or they
// won't stay on top of their parents (On top of the main VUE window). This is a
// mac bug; as of 2006 anyway -- SMF 2007-05-22.
// SMF UPDATE 2008-04-21: Still needed on Mac OS X Tiger (10.4.x) for this to work, and
// we must call our setVisible impl, not just super.setVisible(). Unfortunately,
// this is NO LONGER WORKING to keep DockWindow's on top on Mac OSX Leopard
// (10.5+), however, there is SOME way to get it to happen (iconifying the whole
// app and de-iconifying seems to do it), but I don't know if we can find another
// workaround...
//=============================================================================
setVisibleImpl(true, true);
setVisibleImpl(false, true);
}
}
VUE.addActiveListener(tufts.vue.LWMap.class, FSWindow.this);
}
/**
* When set to hide, this instead sets us off-screen and forces us to be
* non-focusable (we don't want an "invisible" window accidentally having the
* focus).
* We need to do this because all the DockWindows are children of this window,
* (so they always stay on top of it in full-screen working mode, which is
* currently the only way to ensure this), and as children, if we actually hid
* this window, they'd all hide with it.
* And when shown, we prophylacticly raise all the DockWindows, in case one of
* the various window hierarchy display bugs in the various java platform
* implementations left them behind something.
*/
@Override
public void setVisible(boolean show) {
if (DEBUG.DOCK) Log.debug("FSW setVisible " + show);
setVisibleImpl(show, false);
}
private void setOffScreen() {
if (DEBUG.DOCK && DEBUG.META) {
// instead of hiding it, keep it around so we can observe it and
// it's layering relative to other VUE windows (it should always
// be OVER the main window, and UNDER all DockWindow's)
// we set the color so we notice this window in its debug state, but it
// turns out it's also important on Leopard for this to work at all (see
// comment below)
setBackground(Color.red);
//setSize(GUI.getScreenWidth() / 10, GUI.getScreenHeight() / 10);
setSize(240,135);
} else {
GUI.setOffScreen(this);
if (Util.isMacLeopard()) {
//------------------------------------------------------------------
// This odd workaround, which I was lucky to stumble upon, is to
// allow us to enter native full screen mode on Leopard more than
// onnce. Forcing an actual color change through to the peer is
// changing some kind of state such that the bug, which normally
// leaves the full screen window entirely blank the second time it's
// set in place appears to go away. Note: the resulting bad case
// behavior of this bug is similar to the other bug that happens if
// any other windows try to appear/get focus while in native full
// screen -- we get a blank screen, except at least in this case, it
// doesn't lock up the entire Mac operating system event loop.
//
// -- SMF 2008-04-21
//------------------------------------------------------------------
Color c = getBackground();
if (Color.black.equals(c))
setBackground(Color.darkGray);
else
setBackground(Color.black);
}
if (DEBUG.PAINT) setBackground(Color.orange);
}
}
private void setVisibleImpl(boolean show, boolean init)
{
setFocusableWindowState(show);
// if set we allow it to actually go invisible
// all children will hide (hiding all the DockWindow's)
if (show) {
super.setVisible(true);
} else {
setOffScreen();
}
// Let this be handled by our callers -- was important before ExtraDockWindowHiding, which is
// pretty much mandatory now.
// if (!init && show && !inNativeFullScreen()) {
// // just in case
// //if (DEBUG.Enabled) Util.printStackTrace("FS DW RAISE ALL");
// DockWindow.raiseAll();
// }
}
public void activeChanged(tufts.vue.ActiveEvent e, tufts.vue.LWMap map) {
if (fullScreenWorking) {
if (VUE.multipleMapsVisible()) {
// TODO:
// bug when multiple maps visible: if right viewer ever becomes
// the active viewer, then it sets it's map to the active map,
// and then we thing the map has changed here, and we
// open up the full screen viewer with the wrong map!
// This is a convenience feature anyway: the only
// time this can be used (in production) is if
// the recently opened files menu is used while in working
// full screen.
// Ideally, we would be best to completely ignore these events
// while we're entering/exiting full-screen mode.
} else {
FullScreenViewer.loadFocal(map);
}
}
}
@Override
public void paint(Graphics g) {
//boolean offscreen = getX() < 0 || getY() < 0;
final boolean offscreen = getY() >= GUI.getOffScreenY();
if (DEBUG.Enabled) Log.debug("paint " + this + "; hidden=" + isHidden + "; offscreen=" + offscreen);
// don't paint if we're offscreen. This is important for the presentation tool,
// as it actually configures some of it's special button locations when it
// paints, so only one viewer at a time should be painting, otherwise the
// buttons could get the wrong location for the visible viewer.
if (offscreen)
return;
super.paint(g);
if (isHidden) {
// wait for paint to finish, then fade us up
fadeUp();
}
if (screenBlacked) {
fadeFromBlack();
screenBlacked = false;
}
}
void screenToBlack() {
screenBlacked = true;
goBlack();
}
private void fadeUp()
{
isHidden = false;
if (Util.isMacCocoaSupported()) {
if (DEBUG.Enabled) Log.debug("requesting fadeup");
GUI.invokeAfterAWT(new Runnable() { public void run() {
doFadeUp();
}});
}
}
private void doFadeUp()
{
if (DEBUG.Enabled) Log.debug("fadeup invoked");
if (Util.isMacCocoaSupported()) {
try {
//if (MacOSX.isMainInvisible())
MacOSX.fadeUpMainWindow();
} catch (Throwable t) {
Log.error("doFadeUp", t);
}
}
isHidden = false;
}
void makeInvisible() {
if (!isHidden && Util.isMacCocoaSupported() && !VUE.isApplet()) {
isHidden = true;
MacOSX.setWindowAlpha(this, 0);
}
}
// void makeVisible() {
// if (isHidden) {
// isHidden = false;
// //MacOSX.cycleAlpha(this, 0f, 1f);
// MacOSX.setAlpha(this, 1f);
// }
// }
// void makeVisibleLater() {
// if (isHidden) {
// GUI.invokeAfterAWT(new Runnable() { public void run() {
// makeVisible();
// }});
// }
// }
private javax.swing.JMenuBar getMainMenuBar() {
if (mainMenuBar == null) {
// fyi, if this is ever called before all the DockWindow's have
// been constructed, the Windows menu in the VueMenuBar
// will be awfully sparse...
mainMenuBar = new VueMenuBar();
}
return mainMenuBar;
}
/**
* Allow a menu bar at the top for full-screen working mode on non-mac
* platforms. (Mac always has a menu bar at the top in any working mode, as
* opposed to full-screen native mode). For Windows full-screen "native" mode,
* we need to make sure this is NOT enabled, or it will show up at the top of
* the full-screen window during a presentation.
*/
private void setMenuBarEnabled(boolean enabled) {
if (GUI.isMacAqua()) {
// we never need to do this in Mac Aqua, as the application
// always has the Mac menu bar at the top of the screen
return;
}
if (enabled)
getRootPane().setJMenuBar(getMainMenuBar());
else
getRootPane().setJMenuBar(null);
}
}
private static boolean goBlack() {
if (Util.isMacCocoaSupported()) {
try {
MacOSX.goBlack();
return true;
} catch (Error e) {
Log.error(e);
return false;
}
}
return false;
}
private static void goClear() {
if (Util.isMacCocoaSupported()) {
try {
MacOSX.hideFSW();
} catch (Error e) {
Log.error(e);
}
}
}
private static void fadeFromBlack() {
if (Util.isMacCocoaSupported()) {
try {
MacOSX.fadeFromBlack();
} catch (Error e) {
Log.error(e);
}
}
}
// public static void fadeToBlack() {
// // None of the MacOSX utils that use a separate NSWindow drawn
// // black on top of everything else work in full-screen native
// // mode -- the full screen window itself always stays on-top,
// // even if we order the special NSWindow to the front.
// // if (Util.isMacPlatform()) {
// // try {
// // MacOSX.fadeToBlack();
// // } catch (Error e) {
// // Log.error(e);
// // }
// // }
// }
public static boolean inFullScreen() {
return fullScreenWorking || fullScreenNative;
}
public static boolean inWorkingFullScreen() {
return fullScreenWorking;
}
public static boolean inNativeFullScreen() {
return fullScreenNative;
//return fullScreenNative || (DEBUG.PRESENT && inWorkingFullScreen());
}
public static void toggleFullScreen() {
toggleFullScreen(false);
}
// public static void setFullScreenWorkingMode() {
// dropFromNativeToWorking();
// }
public static void dropFromNativeToWorking() {
// TODO: merge this code with exitFullScreen
FullScreenWindow.screenToBlack(); // will auto-fade-up next time it completes a paint
final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
final GraphicsDevice device = ge.getDefaultScreenDevice();
if (device.getFullScreenWindow() != null) {
// this will take us out of true full screen mode
Log.debug("clearing native full screen window:"
+ "\n\t controlling device: " + device
+ "\n\tcur device FS window: " + device.getFullScreenWindow());
device.setFullScreenWindow(null);
}
FullScreenWindow.setMenuBarEnabled(true);
VUE.getActiveTool().handleFullScreen(true, false);
GUI.setFullScreenVisible(FullScreenWindow);
fullScreenWorking = true;
fullScreenNative = false;
//FullScreenViewer.grabVueApplicationFocus("FullScreen.nativeDrop", null);
// GUI.invokeAfterAWT(new Runnable() { public void run() {
// VUE.getActiveTool().handleFullScreen(true, false);
// }});
}
public static void dropFromNativeToFrame() {
Actions.ToggleFullScreen.act();
}
public static synchronized void toggleFullScreen(boolean goNative)
{
//agoNative=false;
// TODO: getMapAt in MapTabbedPane fails returning null when, of course, MapViewer is parented out!
// On the mac, the order in which the tool windows are shown (go from hidden to visible) is the
// z-order, with the last being on top -- this INCLUDES the full-screen window, so when it get's
// shown, all the tool windows will always go below it, (including the main VUE frame) so we have
// have to hide/show all the tool windows each time so they come back to the front.
// If the tool window was open when fs popped, you can get it back by hitting it's shortcuut
// twice, hiding it then bringing it back, tho it appeared on mac that this didn't always work.
// More Mac Problems: We need the FSW (full screen window) to be a frame so we can set a
// jmenu-bar for the top (MRJAdapter non-active jmenu bar won't help: it's for only for when
// there's NO window active). But then as a sibling frame, to VUE.frame instead ofa child to it,
// VUE.frame can appear on top of you Option-~. Trying to move VUE.frame off screen doesn't
// appear to be working -- maybe we could set it to zero size? Furthermore, all the tool
// Windows, which are children to VUE.frame, won't stay on top of the FSW after it takes focus.
// We need to see what happens if they're frames, as they're going to need to be anyway. (There
// is the nice ability to Option-~ them all front/back at once, as children of the VUE.frame, if
// they're windows tho...)
// What about using a JDialog instead of a JFrame? JDialog's can have
// a parent frame AND a JMenuBar...
// final boolean doBlack = (goNative || inNativeFullScreen());
// if (doBlack)
// goBlack();
if (fullScreenWorking) {
if (goNative && !inNativeFullScreen())
enterFullScreenMode(true);
else
exitFullScreenMode();
} else {
enterFullScreenMode(goNative);
}
if (!inWorkingFullScreen())
{
tufts.vue.VueToolbarController.getController()
.setSelectedTool(tufts.vue.VueToolbarController.getController().getSelectedTool());
}
else if (!goNative)
{
// TODO: this is problematic: this will unexepectly switch the user to a
// different tool when they enter full screen mode. The floating tool panel is
// not being synced with the main VUE tool panel (it may not be capable of this
// -- it has it's own smaller sub-set of tools on it).
tufts.vue.VueToolbarController.getController()
.setSelectedTool(VUE.getFloatingZoomPanel().getSelectedTool());
// Is causing event loop:
//VUE.setActive(VueTool.class, FullScreen.class, VUE.getFloatingZoomPanel().getSelectedTool());
}
//VUE.getActiveViewer().requestFocus();
////ToolWindow.adjustMacWindows();
VueMenuBar.toggleFullScreenTools();
// if (doBlack)
// VUE.invokeAfterAWT(new Runnable() {
// public void run() { tufts.Util.screenFadeFromBlack();}
// });
}
private static LWMap activeMap = null;
private static MapViewer activeViewer= null;
public static LWMap getObscuredMap()
{
return activeMap;
}
public static MapViewer getObscuredViewer()
{
return activeViewer;
}
private synchronized static void enterFullScreenMode(final boolean goNative)
{
NDC.push("[FS->]");
GUI.reloadGraphicsInfo();
boolean wentBlack = false;
if (goNative && inWorkingFullScreen()) {
// as the working full-screen window is the same window as the native
// full-screen window, we need to show the black window when transitioning
// from working full-screen to native full-screen, otherwise we see the
// working full-screen tear-down and the underlying VUE app/desktop before
// seeing the black screen of the initial native window at 0 alpha.
// Okay to leave this up while in native, as it'll be torn down automatically
// on exit, tho it safer to tear it down just in case.
wentBlack = goBlack();
}
activeMap = VUE.getActiveMap();
activeViewer = VUE.getActiveViewer();
tufts.vue.LWComponent _activeFocal = null;
if (activeViewer != null)
_activeFocal = activeViewer.getFocal();
if (_activeFocal == null && activeMap != null)
_activeFocal = activeMap;
if (activeViewer != FullScreenViewer) {
FullScreenLastActiveViewer = activeViewer;
activeViewer.setFocusable(false);
}
final tufts.vue.LWComponent activeFocal = _activeFocal;
if (goNative) {
// Can't use heavy weights, as they're windows that can't be seen,
// and actually the screen goes blank on Mac OS X trying to handle this.
javax.swing.JPopupMenu.setDefaultLightWeightPopupEnabled(true);
// also: appear to need to do this before anything else
// to have it property take effect?
}
Log.debug("Entering full screen mode; goNative=" + goNative);
if (FullScreenWindow == null) {
FullScreenWindow = (FSWindow) GUI.getFullScreenWindow();
FullScreenWindow.getContentPane().add(FullScreenViewer = new MapViewer(null, VIEWER_NAME));
//fullScreenWindow.pack();
}
FullScreenViewer.setLoading(true);
FullScreenWindow.setMenuBarEnabled(!goNative);
// FullScreenViewer.loadFocal(VUE.getActiveMap()); // can't do till we're sure it has a size!
fullScreenWorking = true; // we're in the mode as soon as the add completes (no going back then)
fullScreenNative = goNative;
// TODO: above two bits need to be more semantic: e.g., inFullScreen
// and inFullScreenPresentation
final boolean useNativeMode =
goNative &&
!Util.isWindowsPlatform() &&
!tufts.vue.Actions.SuperScreen.getToggleState();
if (useNativeMode) {
// MAC & LINUX ONLY:
//final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
final GraphicsDevice device = GUI.getActiveDevice();
if (DEBUG.Enabled) {
Log.debug("entering NATIVE full-screen on " + Util.tags(device));
GUI.dumpGraphicsDevice(device, "VUE-ACTIVE");
}
//out("Native full screen support available: " + device.isFullScreenSupported());
// todo: crap: if the screen resolution changes, we'll need to resize the full-screen window
// Try and prevent us from flashing a big white screen while we load.
// Tho immediately loading the focal below will quickly override this...
FullScreenWindow.setBackground(Color.black);
FullScreenViewer.setBackground(Color.black);
// On Mac, must use native full-screen to get the window over
// the mac menu bar.
FullScreenWindow.makeInvisible();
device.setFullScreenWindow(FullScreenWindow);
FullScreenDevice = device;
// We run into a serious problem using the special java full-screen mode on the mac: if
// you right-click, it attemps to pop-up a menu over the full screen window, which is not
// allowed in mac full-screen, and it apparently auto-switches context somehow for you,
// but just leaves you at a fully blank screen that you can sometimes never recover from
// without powering off! This true as of java version "1.4.2_05-141.3", Mac OS X 10.3.5/6.
// [TODO: JAN 2010: we at worst run in java 1.5 now, and usually java 1.6 -- probably
// don't need this anymore -- retest]
if (ExtraDockWindowHiding && !DockWindow.AllWindowsHidden()) {
nativeModeHidAllDockWindows = true;
DockWindow.HideAllWindows();
}
} else {
// WINDOWS: (why don't we ever use native full-screen w/windows?)
// Or: Mac/Linux when All Screens (SuperScreen) is being used.
// Note that on Mac, this means that the top menu bar will NOT be hidden.
if (goNative) {
if (ExtraDockWindowHiding && !DockWindow.AllWindowsHidden() /*&& !GUI.hasMultipleScreens()*/) {
nativeModeHidAllDockWindows = true;
DockWindow.HideAllWindows();
}
}
GUI.setFullScreenVisible(FullScreenWindow);
}
FullScreenViewer.loadFocal(activeFocal);
if (!goNative && activeViewer != null && activeMap != null && !(VUE.getActiveViewer().getFocal() instanceof tufts.vue.LWSlide))
{
//if (activeViewer.getWidth() != activeViewer.getVisibleWidth() ||activeViewer.getHeight() != activeViewer.getVisibleHeight())
ZoomTool.setZoomFitRegion(FullScreenViewer,activeViewer.getVisibleMapBounds());
// else
// ZoomTool.setZoomFitRegion(FullScreenViewer,activeViewer.getMap().getMapBounds(),activeViewer.getMap().getFocalMargin(),false);
}
if (!goNative && (Util.isUnixPlatform() || (DockWindow.useManagedWindowHacks() && Util.isMacPlatform()))) {
// need this on Leopard for sure, and seems also to help on Linux
// Pretty sure this only needs to be done the first
// time (yet another java / java mac impl bug), but
// can't hurt to do it always.
DockWindow.raiseAll();
}
FullScreenViewer.grabVueApplicationFocus("FullScreen.enter-1", null);
final VueTool activeTool = VueToolbarController.getActiveTool();
GUI.invokeAfterAWT(new Runnable() { public void run() {
if (DEBUG.PRESENT) Log.debug("AWT thread activeTool.handleFullScreen for " + activeTool);
activeTool.handleFullScreen(true, goNative);
}});
if (wentBlack) {
GUI.invokeAfterAWT(new Runnable() { public void run() {
// shouldn't ever be able to see this happen, as the native full-screen should be
// on top of us, but just in case we make sure to clear it out behind us...
goClear();
}});
}
GUI.invokeAfterAWT(new Runnable() { public void run() {
// The initial request for focus sometimes happens while the
// FullScreenViewer already has focus, and immediately after that it
// completely loses focus (to null), so we request again here to be
// absolutely sure we have keyboard focus.
FullScreenViewer.grabVueApplicationFocus("FullScreen.enter-2", null);
if (activeFocal != null) {
// leave as loading if we're clearing out (leaving full-screen) so we'll be ready with it at the next display
FullScreenViewer.setLoading(false);
}
// added this repaint for going native full-screen on the NON-DEFAULT device
// in a Mac OSX multi-monitor setup -- window was appearing, but needed to
// move mouse to see the first paint.
FullScreenViewer.repaint();
NDC.pop();
}});
}
public static MapViewer getLastActive()
{
return FullScreenLastActiveViewer;
}
private synchronized static void exitFullScreenMode()
{
NDC.push("[<-FS]");
GUI.reloadGraphicsInfo();
//final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
//final GraphicsDevice device = ge.getDefaultScreenDevice();
final GraphicsDevice device;
if (FullScreenDevice == null) {
// this should only happen if an external display was literally disconnected
// while we were in full-screen mode
device = GUI.getActiveDevice();
} else {
device = FullScreenDevice;
}
final boolean wasNative = inNativeFullScreen();
final tufts.vue.LWComponent fullScreenFocal = FullScreenViewer.getFocal();
final tufts.vue.LWMap fullScreenMap = FullScreenViewer.getMap();
final Rectangle2D fullScreenVisibleMapBounds = FullScreenViewer.getVisibleMapBounds();
//final Rectangle2D fullScreenMapBounds = fullScreenMap.getBounds();
Log.debug("Exiting full screen mode; inNative=" + wasNative);
final boolean fadeBack = wasNative && Util.isMacPlatform();
if (fadeBack) {
// For Mac: this won't be visible till full-screen is torn down (nothing
// can go over the FSW), but it will be there all full and black once
// the java FSW *is* torn down, then we can fade that out to reveal
// the desktop.
goBlack();
}
//javax.swing.JPopupMenu.setDefaultLightWeightPopupEnabled(true);
// PROBLEM / QUESTION: WHAT HAPPENS IF THE FS DEVICE LITERALLY
// GOES AWAY (is disconnected) while we're in FS mode?
if (device == null) {
Log.error("missing device exiting FS mode");
} else if (device.getFullScreenWindow() != null) {
// this will take us out of true full screen mode
Log.info("clearing native full screen window:"
+ "\n\t controlling device: " + device
+ "\n\tcur device FS window: " + device.getFullScreenWindow());
// note that when coming out of full screen, the java impl
// first restores the given window to it's state before
// we made it the FSW, which is annoying on the mac cause
// it flashes a small window briefly in the upper left.
device.setFullScreenWindow(null);
} else {
Log.warn("device no longer has FS window: " + device);
}
FullScreenDevice = null; // ensure global record of current FS device is nulled
fullScreenWorking = false;
fullScreenNative = false;
FullScreenWindow.setVisible(false);
FullScreenViewer.loadFocal(null);
// Note: several of these invokeAfterAWT calls are probably overkill,
// but the focus issues we're dealing with here can be very delicate,
// so be careful in here...
if (ExtraDockWindowHiding && nativeModeHidAllDockWindows) {
nativeModeHidAllDockWindows = false;
GUI.invokeAfterAWT(new Runnable() { public void run() {
DockWindow.ShowPreviouslyHiddenWindows();
if (Util.isMacPlatform()) {
// This will ensure the windows are fully painted when we return
// from fade-back.
// Only need to do this on mac, as we can't hide what's happening on
// WinXP by fading to/from black anyway.
DockWindow.ImmediatelyRepaintAllWindows();
}
}});
}
if (FullScreenLastActiveViewer != FullScreenViewer) {
GUI.invokeAfterAWT(new Runnable() { public void run() {
// todo: we do NOT want to do this if the active map has changed while in
// full-screen mode: we want to activate the viewer for the map currently
// displayed
FullScreenLastActiveViewer.grabVueApplicationFocus("FullScreen.exit", null);
}});
}
GUI.invokeAfterAWT(new Runnable() { public void run() {
VueToolbarController.getActiveTool().handleFullScreen(false, wasNative);
//Log.debug("activeTool.handleFullScreen " + VueToolbarController.getActiveTool());
//VUE.getActiveViewer().popToMapFocal(); // old active viewer shouldn't have changed...
}});
GUI.invokeAfterAWT(new Runnable() { public void run() {
// Do not now ask for the currently active viewer: use the reference to the one that
// was active when we entered full-screen mode: the java focus system can be very
// unpredicable -- we can't be sure who is getting the focus back. E.g., the active
// viewer at this point may even still be the full-screen viewer, with a null
// map, as it's been unloaded at this point.
// Todo: if the active map has changed while in full screen mode, we should actually
// return to the open viewer that has the same map. Checking the ActiveViewer almost
// works for this, but the corner cases need handling. Easiest approach may be to have
// FullScreenLastActiveViewer actually repoint to the standard viewer for the active
// map if the active map changes.
final MapViewer returnViewer = FullScreenLastActiveViewer;
//final MapViewer returnViewer = VUE.getActiveViewer();
if (DEBUG.Enabled) Log.debug("exit FS cleanup;"
+ "\n\tlastActiveViewer: " + FullScreenLastActiveViewer
+ "\n\t nowActiveViewer: " + VUE.getActiveViewer()
+ "\n\t returnViewer: " + returnViewer
+ "\n\t fullScreenFocal: " + fullScreenFocal
);
try {
if (!wasNative && returnViewer != null) {
// If the focal has changed while in full screen mode, and it's still a
// focal from the same map that's in the viewer we're returning back to,
// swap load the same focal into the returning viewer. (e.g., a slide
// was being edited in full screen mode: make the same slide visible in
// the regular viewer when we return to it).
if (fullScreenMap == returnViewer.getMap()) {
if (returnViewer.getFocal() != fullScreenFocal)
returnViewer.loadFocal(fullScreenFocal);
}
// have the returning viewer zoom to the same region
// that is visible in the full-screen viewer
// problem with this method: the region keeps shrinking on repeated in/out of working FS mode
// ZoomTool.setZoomFitRegion(returnViewer, fullScreenVisibleMapBounds, 0, false, false);
// Current logic: this seems to keep the same region visible if the region is
// "zoomed in" -- there are parts of the map visible off screen, or just force
// a zoom-fit otherwise.
if (returnViewer.getWidth() != returnViewer.getVisibleWidth() ||
returnViewer.getHeight() != returnViewer.getVisibleHeight()) {
if (DEBUG.Enabled) Log.debug("size mismatch (viewer probably scroll-enabled) re-zoom");
ZoomTool.setZoomFitRegion(returnViewer,
returnViewer.getVisibleMapBounds());
} else {
if (DEBUG.Enabled) Log.debug("default re-zoom");
ZoomTool.setZoomFitRegion(returnViewer,
returnViewer.getMap().getMapBounds(),
returnViewer.getMap().getFocalMargin(),
false);
}
}
} finally {
if (!fadeBack) NDC.pop();
}
}});
// This works to have the toolbar painted, vut the tabbed pane and viewer apparently aren't ready yet (just shows dark gray)
// if (Util.isMacPlatform())
// ((javax.swing.JComponent)VUE.getApplicationFrame().getContentPane()).paintImmediately(new Rectangle(-256,-256,4096,4096));
if (fadeBack) {
if (DEBUG.Enabled) Log.debug("requesting fadeFromBlack");
GUI.invokeAfterAWT(new Runnable() { public void run() {
fadeFromBlack();
NDC.pop();
}});
}
}
/*
private static void exitFullScreenMode()
{
NDC.push("[<-FS]");
final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
final GraphicsDevice device = ge.getDefaultScreenDevice();
final boolean wasNative = inNativeFullScreen();
Log.debug("Exiting full screen mode, inNative=" + wasNative);
//javax.swing.JPopupMenu.setDefaultLightWeightPopupEnabled(false);
//javax.swing.JPopupMenu.setDefaultLightWeightPopupEnabled(true);
if (device.getFullScreenWindow() != null) {
// this will take us out of true full screen mode
Log.debug("clearing native full screen window:"
+ "\n\t controlling device: " + device
+ "\n\tcur device FS window: " + device.getFullScreenWindow());
device.setFullScreenWindow(null);
// note that when coming out of full screen, the java impl
// first restores the given window to it's state before
// we made it the FSW, which is annoying on the mac cause
// it flashes a small window briefly in the upper left.
}
fullScreenWindow.setVisible(false);
fullScreenWorking = false;
fullScreenNative = false;
if (fullScreenWindow != VUE.getMainWindow()) {
Log.debug("re-attaching prior extracted viewer content " + fullScreenContent);
fullScreenOldParent.add(fullScreenContent);
//fullScreenOldParent.add(VUE.getActiveViewer());
}
if (VUE.getMainWindow() != null) {
// if (fullScreenOldVUELocation != null)
// VUE.getMainWindow().setLocation(fullScreenOldVUELocation); // mac window manger not allowing
// if (fullScreenOldVUESize != null)
// VUE.getMainWindow().setSize(fullScreenOldVUESize); // mac window manager won't go to 0
//VUE.getMainWindow.setExtendedState(Frame.NORMAL); // iconifies but only until an Option-TAB switch-back
GUI.invokeAfterAWT(new Runnable() { public void run() {
Log.debug("showing main window " + VUE.getMainWindow());
VUE.getMainWindow().setVisible(true);
}});
}
if (nativeModeHidAllDockWindows) {
nativeModeHidAllDockWindows = false;
GUI.invokeAfterAWT(new Runnable() { public void run() {
DockWindow.ShowPreviouslyHiddenWindows();
}});
}
GUI.invokeAfterAWT(new Runnable() {
public void run() {
//Log.debug("activeTool.handleFullScreen " + VueToolbarController.getActiveTool());
VueToolbarController.getActiveTool().handleFullScreen(false, wasNative);
NDC.pop();
}});
//NDC.pop();
}
*/
/*
private static void enterFullScreenMode(boolean goNative)
{
NDC.push("[FS->]");
//goNative = false; // TODO: TEMP DEBUG
if (goNative) {
// Can't use heavy weights, as they're windows that can't be seen,
// and actually the screen goes blank on Mac OS X trying to handle this.
javax.swing.JPopupMenu.setDefaultLightWeightPopupEnabled(true);
// also: appear to need to do this before anything else
// to have it property take effect?
}
final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
final GraphicsDevice device = ge.getDefaultScreenDevice();
final MapViewer viewer = VUE.getActiveViewer();
final VueTool activeTool = VueToolbarController.getActiveTool();
//out("Native full screen support available: " + device.isFullScreenSupported());
// setFullScreenWindow(SwingUtilities.getWindowAncestor(this));
//VUE.frame.setVisible(false); // this also hids all children of the frame, including the new fs window.
// mac bug: if don't create window every time, subsequent full-screen
// modes won't extend to the the bottom of the screen (probably related to mac dock being there)
// Very odd even if not running as a native window... The window reports proper location, but it
// show's up placed at a negative y.
// todo: crap: if the screen resolution changes, we'll need to resize the full-screen window
Log.debug("enterFullScreenMode: goingNative=" + goNative);
// if (false&&goNative) {
// if (VueUtil.isMacPlatform() || cachedFSWnative == null) {
// // have to create full screen native win on mac every time or it comes
// // back trying to avoid the dock??
// if (cachedFSWnative != null)
// cachedFSWnative.setTitle("_old-mac-full-native"); // '_' important for macosx hacks
// cachedFSWnative = GUI.createFrame("VUE-FULL-NATIVE");
// cachedFSWnative.setUndecorated(true);
// cachedFSWnative.setLocation(0,0);
// }
// fullScreenWindow = cachedFSWnative;
// } else {
if (cachedFSW == null) {
cachedFSW = GUI.getFullScreenWindow();
//cachedFSW = GUI.createFrame("VUE-FULL-WORKING");
//cachedFSW.setUndecorated(true);
}
fullScreenWindow = cachedFSW;
//}
// if (false) {
// fullScreenWindow = VUE.getMainWindow();
// } else if (VueUtil.isMacPlatform() || fullScreenWindow == null) {
// //} else if (fullScreenWindow == null) {
// // Terribly wasteful to have to re-create this on the mac all the time..
// if (false) {
// fullScreenWindow = VUE.createWindow(); // if VUE.frame is parent, it will stay on top of it
// } else {
// if (fullScreenWindow != null)
// ((Frame)fullScreenWindow).setTitle("OLD-FULL-FRAME");
// fullScreenWindow = VUE.createFrame("VUE-FULL-FRAME");
// // but we need a Frame in order to have the menu-bar on the mac!
// ((Frame)fullScreenWindow).setUndecorated(true);
// }
// //fullScreenWindow.setName("VUE-FULL-SCREEN");
// //fullScreenWindow.setBackground(Color.RED);
// }
if (fullScreenWindow != VUE.getMainWindow() && VUE.getMainWindow() != null) {
//javax.swing.JComponent fullScreenContent = viewer;
fullScreenContent = viewer;
//fullScreenContent = new JLabel("TEST");
fullScreenOldParent = viewer.getParent();
Log.debug("adding content to FSW:"
+ "\n\tCONTENT: "+ fullScreenContent
+ "\n\t FSW: "+ fullScreenWindow
);
if (fullScreenWindow instanceof DockWindow) {
((DockWindow)fullScreenWindow).add(fullScreenContent);
} else if (fullScreenWindow instanceof JFrame) {
//((JFrame)fullScreenWindow).setContentPane(fullScreenContent);
((JFrame)fullScreenWindow).getContentPane().add(fullScreenContent);
} else if (fullScreenWindow instanceof JWindow) {
//((JWindow)fullScreenWindow).setContentPane(fullScreenContent);
// adding to the contentPane instead of setting as allows
// a JMenuBar to be added to the top and the viewer then
// appears under it (instead of the menu overlapping it at the top)
((JWindow)fullScreenWindow).getContentPane().add(fullScreenContent);
} else // is Window
fullScreenWindow.add(fullScreenContent);
fullScreenWindow.pack();
//getMap().setFillColor(Color.BLACK);
//fullScreenWindow.getContentPane().add(MapViewer.this.getParent().getParent()); // add with scroll bars
}
fullScreenWorking = true; // we're in the mode as soon as the add completes (no going back then)
fullScreenNative = goNative;
// if (VUE.getMainWindow() != null) {
// //fullScreenOldVUELocation = VUE.getMainWindow().getLocation();
// //fullScreenOldVUESize = VUE.getMainWindow().getSize();
// //if (fullScreenWindow != VUE.getMainWindow())
// //VUE.getMainWindow().setVisible(false);
// }
if (fullScreenWindow instanceof FSWindow) {
((FSWindow)fullScreenWindow).setMenuBarEnabled(!goNative);
}
if (goNative) {
// On Mac, must use native full-screen to get the window over
// the mac menu bar.
//tufts.macosx.Screen.goBlack();
device.setFullScreenWindow(fullScreenWindow);
// if (VueUtil.isMacPlatform()) {
// try {
// tufts.macosx.Screen.makeMainInvisible();
// } catch (Exception e) {
// System.err.println(e);
// }
// }
//if (DEBUG.Enabled) out("fsw=" + fullScreenWindow.getPeer().getClass());
//fullScreenWindow.addKeyListener(inputHandler);
//w.enableInputMethods(true);
//enableInputMethods(true);
// We run into a serious problem using the special java full-screen mode on the mac: if
// you right-click, it attemps to pop-up a menu over the full screen window, which is not
// allowed in mac full-screen, and it apparently auto-switches context somehow for you,
// but just leaves you at a fully blank screen that you can sometimes never recover from
// without powering off! This true as of java version "1.4.2_05-141.3", Mac OS X 10.3.5/6.
if (!DockWindow.AllWindowsHidden()) {
nativeModeHidAllDockWindows = true;
DockWindow.HideAllWindows();
}
} else {
GUI.setFullScreenVisible(fullScreenWindow);
}
activeTool.handleFullScreen(true, goNative);
// if (false && fullScreenWindow != VUE.getMainWindow() && VUE.getMainWindow() != null) {
// VUE.getMainWindow().setVisible(false);
// //VUE.getMainWindow().setSize(0,0);
// //tufts.Util.setOffScreen(VUE.getMainWindow());
// //VUE.getMainWindow().setLocation(0,0);
// //VUE.getMainWindow().setLocation(3072,2048);
// //VUE.getMainWindow().setExtendedState(Frame.ICONIFIED);
// }
NDC.pop();
}
*/
private static void out(String s) {
System.out.println("VUE FullScreen: " + s);
}
}