638 lines
23 KiB
Java
638 lines
23 KiB
Java
/*
|
|
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation. Oracle designates this
|
|
* particular file as subject to the "Classpath" exception as provided
|
|
* by Oracle in the LICENSE file that accompanied this code.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
package sun.awt;
|
|
|
|
import java.awt.AWTPermission;
|
|
import java.awt.GraphicsDevice;
|
|
import java.awt.GraphicsConfiguration;
|
|
import java.awt.GraphicsEnvironment;
|
|
import java.awt.DisplayMode;
|
|
import java.awt.EventQueue;
|
|
import java.awt.Frame;
|
|
import java.awt.Rectangle;
|
|
import java.awt.Window;
|
|
import java.awt.event.WindowAdapter;
|
|
import java.awt.event.WindowEvent;
|
|
import java.awt.event.WindowListener;
|
|
import java.awt.image.ColorModel;
|
|
import java.util.ArrayList;
|
|
import java.util.Vector;
|
|
import java.awt.peer.WindowPeer;
|
|
import sun.awt.windows.WWindowPeer;
|
|
import sun.java2d.opengl.WGLGraphicsConfig;
|
|
import sun.java2d.windows.WindowsFlags;
|
|
|
|
/**
|
|
* This is an implementation of a GraphicsDevice object for a single
|
|
* Win32 screen.
|
|
*
|
|
* @see GraphicsEnvironment
|
|
* @see GraphicsConfiguration
|
|
*/
|
|
public class Win32GraphicsDevice extends GraphicsDevice implements
|
|
DisplayChangedListener {
|
|
int screen;
|
|
ColorModel dynamicColorModel; // updated with dev changes
|
|
ColorModel colorModel; // static for device
|
|
protected GraphicsConfiguration[] configs;
|
|
protected GraphicsConfiguration defaultConfig;
|
|
|
|
private final String idString;
|
|
protected String descString;
|
|
// Note that we do not synchronize access to this variable - it doesn't
|
|
// really matter if a thread does an operation on graphics device which is
|
|
// about to become invalid (or already become) - we are prepared to deal
|
|
// with this on the native level.
|
|
private boolean valid;
|
|
|
|
// keep track of top-level windows on this display
|
|
private SunDisplayChanger topLevels = new SunDisplayChanger();
|
|
// REMIND: we may disable the use of pixel formats for some accelerated
|
|
// pipelines which are mutually exclusive with opengl, for which
|
|
// pixel formats were added in the first place
|
|
protected static boolean pfDisabled;
|
|
private static AWTPermission fullScreenExclusivePermission;
|
|
// the original display mode we had before entering the fullscreen
|
|
// mode
|
|
private DisplayMode defaultDisplayMode;
|
|
// activation/deactivation listener for the full-screen window
|
|
private WindowListener fsWindowListener;
|
|
|
|
static {
|
|
|
|
// 4455041 - Even when ddraw is disabled, ddraw.dll is loaded when
|
|
// pixel format calls are made. This causes problems when a Java app
|
|
// is run as an NT service. To prevent the loading of ddraw.dll
|
|
// completely, sun.awt.nopixfmt should be set as well. Apps which use
|
|
// OpenGL w/ Java probably don't want to set this.
|
|
String nopixfmt = (String)java.security.AccessController.doPrivileged(
|
|
new sun.security.action.GetPropertyAction("sun.awt.nopixfmt"));
|
|
pfDisabled = (nopixfmt != null);
|
|
initIDs();
|
|
}
|
|
|
|
private static native void initIDs();
|
|
|
|
native void initDevice(int screen);
|
|
|
|
public Win32GraphicsDevice(int screennum) {
|
|
this.screen = screennum;
|
|
// we cache the strings because we want toString() and getIDstring
|
|
// to reflect the original screen number (which may change if the
|
|
// device is removed)
|
|
idString = "\\Display"+screen;
|
|
// REMIND: may be should use class name?
|
|
descString = "Win32GraphicsDevice[screen=" + screen;
|
|
valid = true;
|
|
|
|
initDevice(screennum);
|
|
}
|
|
|
|
/**
|
|
* Returns the type of the graphics device.
|
|
* @see #TYPE_RASTER_SCREEN
|
|
* @see #TYPE_PRINTER
|
|
* @see #TYPE_IMAGE_BUFFER
|
|
*/
|
|
public int getType() {
|
|
return TYPE_RASTER_SCREEN;
|
|
}
|
|
|
|
/**
|
|
* Returns the Win32 screen of the device.
|
|
*/
|
|
public int getScreen() {
|
|
return screen;
|
|
}
|
|
|
|
/**
|
|
* Returns whether this is a valid devicie. Device can become
|
|
* invalid as a result of device removal event.
|
|
*/
|
|
public boolean isValid() {
|
|
return valid;
|
|
}
|
|
|
|
/**
|
|
* Called from native code when the device was removed.
|
|
*
|
|
* @param defaultScreen the current default screen
|
|
*/
|
|
protected void invalidate(int defaultScreen) {
|
|
valid = false;
|
|
screen = defaultScreen;
|
|
}
|
|
|
|
/**
|
|
* Returns the identification string associated with this graphics
|
|
* device.
|
|
*/
|
|
public String getIDstring() {
|
|
return idString;
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns all of the graphics
|
|
* configurations associated with this graphics device.
|
|
*/
|
|
public GraphicsConfiguration[] getConfigurations() {
|
|
if (configs==null) {
|
|
if (WindowsFlags.isOGLEnabled() && isDefaultDevice()) {
|
|
defaultConfig = getDefaultConfiguration();
|
|
if (defaultConfig != null) {
|
|
configs = new GraphicsConfiguration[1];
|
|
configs[0] = defaultConfig;
|
|
return configs.clone();
|
|
}
|
|
}
|
|
|
|
int max = getMaxConfigs(screen);
|
|
int defaultPixID = getDefaultPixID(screen);
|
|
Vector v = new Vector( max );
|
|
if (defaultPixID == 0) {
|
|
// Workaround for failing GDI calls
|
|
defaultConfig = Win32GraphicsConfig.getConfig(this,
|
|
defaultPixID);
|
|
v.addElement(defaultConfig);
|
|
}
|
|
else {
|
|
for (int i = 1; i <= max; i++) {
|
|
if (isPixFmtSupported(i, screen)) {
|
|
if (i == defaultPixID) {
|
|
defaultConfig = Win32GraphicsConfig.getConfig(
|
|
this, i);
|
|
v.addElement(defaultConfig);
|
|
}
|
|
else {
|
|
v.addElement(Win32GraphicsConfig.getConfig(
|
|
this, i));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
configs = new GraphicsConfiguration[v.size()];
|
|
v.copyInto(configs);
|
|
}
|
|
return configs.clone();
|
|
}
|
|
|
|
/**
|
|
* Returns the maximum number of graphics configurations available, or 1
|
|
* if PixelFormat calls fail or are disabled.
|
|
* This number is less than or equal to the number of graphics
|
|
* configurations supported.
|
|
*/
|
|
protected int getMaxConfigs(int screen) {
|
|
if (pfDisabled) {
|
|
return 1;
|
|
} else {
|
|
return getMaxConfigsImpl(screen);
|
|
}
|
|
}
|
|
|
|
private native int getMaxConfigsImpl(int screen);
|
|
|
|
/**
|
|
* Returns whether or not the PixelFormat indicated by index is
|
|
* supported. Supported PixelFormats support drawing to a Window
|
|
* (PFD_DRAW_TO_WINDOW), support GDI (PFD_SUPPORT_GDI), and in the
|
|
* case of an 8-bit format (cColorBits <= 8) uses indexed colors
|
|
* (iPixelType == PFD_TYPE_COLORINDEX).
|
|
* We use the index 0 to indicate that PixelFormat calls don't work, or
|
|
* are disabled. Do not call this function with an index of 0.
|
|
* @param index a PixelFormat index
|
|
*/
|
|
protected native boolean isPixFmtSupported(int index, int screen);
|
|
|
|
/**
|
|
* Returns the PixelFormatID of the default graphics configuration
|
|
* associated with this graphics device, or 0 if PixelFormats calls fail or
|
|
* are disabled.
|
|
*/
|
|
protected int getDefaultPixID(int screen) {
|
|
if (pfDisabled) {
|
|
return 0;
|
|
} else {
|
|
return getDefaultPixIDImpl(screen);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the default PixelFormat ID from GDI. Do not call if PixelFormats
|
|
* are disabled.
|
|
*/
|
|
private native int getDefaultPixIDImpl(int screen);
|
|
|
|
/**
|
|
* Returns the default graphics configuration
|
|
* associated with this graphics device.
|
|
*/
|
|
public GraphicsConfiguration getDefaultConfiguration() {
|
|
if (defaultConfig == null) {
|
|
// first try to create a WGLGraphicsConfig if OGL is enabled
|
|
// REMIND: the WGL code does not yet work properly in multimon
|
|
// situations, so we will fallback on GDI if we are not on the
|
|
// default device...
|
|
if (WindowsFlags.isOGLEnabled() && isDefaultDevice()) {
|
|
int defPixID = WGLGraphicsConfig.getDefaultPixFmt(screen);
|
|
defaultConfig = WGLGraphicsConfig.getConfig(this, defPixID);
|
|
if (WindowsFlags.isOGLVerbose()) {
|
|
if (defaultConfig != null) {
|
|
System.out.print("OpenGL pipeline enabled");
|
|
} else {
|
|
System.out.print("Could not enable OpenGL pipeline");
|
|
}
|
|
System.out.println(" for default config on screen " +
|
|
screen);
|
|
}
|
|
}
|
|
|
|
// Fix for 4669614. Most apps are not concerned with PixelFormats,
|
|
// yet we ALWAYS used them for determining ColorModels and such.
|
|
// By passing in 0 as the PixelFormatID here, we signal that
|
|
// PixelFormats should not be used, thus avoid loading the opengl
|
|
// library. Apps concerned with PixelFormats can still use
|
|
// GraphicsConfiguration.getConfigurations().
|
|
// Note that calling native pixel format functions tends to cause
|
|
// problems between those functions (which are OpenGL-related)
|
|
// and our use of DirectX. For example, some Matrox boards will
|
|
// crash or hang calling these functions when any app is running
|
|
// in DirectX fullscreen mode. So avoiding these calls unless
|
|
// absolutely necessary is preferable.
|
|
if (defaultConfig == null) {
|
|
defaultConfig = Win32GraphicsConfig.getConfig(this, 0);
|
|
}
|
|
}
|
|
return defaultConfig;
|
|
}
|
|
|
|
public String toString() {
|
|
return valid ? descString + "]" : descString + ", removed]";
|
|
}
|
|
|
|
/**
|
|
* Returns true if this is the default GraphicsDevice for the
|
|
* GraphicsEnvironment.
|
|
*/
|
|
private boolean isDefaultDevice() {
|
|
return (this ==
|
|
GraphicsEnvironment.
|
|
getLocalGraphicsEnvironment().getDefaultScreenDevice());
|
|
}
|
|
|
|
private static boolean isFSExclusiveModeAllowed() {
|
|
SecurityManager security = System.getSecurityManager();
|
|
if (security != null) {
|
|
if (fullScreenExclusivePermission == null) {
|
|
fullScreenExclusivePermission =
|
|
new AWTPermission("fullScreenExclusive");
|
|
}
|
|
try {
|
|
security.checkPermission(fullScreenExclusivePermission);
|
|
} catch (SecurityException e) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* returns true unless we're not allowed to use fullscreen mode.
|
|
*/
|
|
@Override
|
|
public boolean isFullScreenSupported() {
|
|
return isFSExclusiveModeAllowed();
|
|
}
|
|
|
|
@Override
|
|
public synchronized void setFullScreenWindow(Window w) {
|
|
Window old = getFullScreenWindow();
|
|
if (w == old) {
|
|
return;
|
|
}
|
|
if (!isFullScreenSupported()) {
|
|
super.setFullScreenWindow(w);
|
|
return;
|
|
}
|
|
|
|
// Enter windowed mode.
|
|
if (old != null) {
|
|
// restore the original display mode
|
|
if (defaultDisplayMode != null) {
|
|
setDisplayMode(defaultDisplayMode);
|
|
// we set the default display mode to null here
|
|
// because the default mode could change during
|
|
// the life of the application (user can change it through
|
|
// the desktop properties dialog, for example), so
|
|
// we need to record it every time prior to
|
|
// entering the fullscreen mode.
|
|
defaultDisplayMode = null;
|
|
}
|
|
WWindowPeer peer = (WWindowPeer)old.getPeer();
|
|
if (peer != null) {
|
|
peer.setFullScreenExclusiveModeState(false);
|
|
// we used to destroy the buffers on exiting fs mode, this
|
|
// is no longer needed since fs change will cause a surface
|
|
// data replacement
|
|
synchronized(peer) {
|
|
exitFullScreenExclusive(screen, peer);
|
|
}
|
|
}
|
|
removeFSWindowListener(old);
|
|
}
|
|
super.setFullScreenWindow(w);
|
|
if (w != null) {
|
|
// always record the default display mode prior to going
|
|
// fullscreen
|
|
defaultDisplayMode = getDisplayMode();
|
|
addFSWindowListener(w);
|
|
// Enter full screen exclusive mode.
|
|
WWindowPeer peer = (WWindowPeer)w.getPeer();
|
|
if (peer != null) {
|
|
synchronized(peer) {
|
|
enterFullScreenExclusive(screen, peer);
|
|
// Note: removed replaceSurfaceData() call because
|
|
// changing the window size or making it visible
|
|
// will cause this anyway, and both of these events happen
|
|
// as part of switching into fullscreen mode.
|
|
}
|
|
peer.setFullScreenExclusiveModeState(true);
|
|
}
|
|
|
|
// fix for 4868278
|
|
peer.updateGC();
|
|
}
|
|
}
|
|
|
|
// Entering and exiting full-screen mode are done within a
|
|
// tree-lock and should never lock on any resources which are
|
|
// required by other threads which may have them and may require
|
|
// the tree-lock.
|
|
// REMIND: in the future these methods may need to become protected so that
|
|
// subclasses could override them and use appropriate api other than GDI
|
|
// for implementing these functions.
|
|
protected native void enterFullScreenExclusive(int screen, WindowPeer w);
|
|
protected native void exitFullScreenExclusive(int screen, WindowPeer w);
|
|
|
|
@Override
|
|
public boolean isDisplayChangeSupported() {
|
|
return (isFullScreenSupported() && getFullScreenWindow() != null);
|
|
}
|
|
|
|
@Override
|
|
public synchronized void setDisplayMode(DisplayMode dm) {
|
|
if (!isDisplayChangeSupported()) {
|
|
super.setDisplayMode(dm);
|
|
return;
|
|
}
|
|
if (dm == null || (dm = getMatchingDisplayMode(dm)) == null) {
|
|
throw new IllegalArgumentException("Invalid display mode");
|
|
}
|
|
if (getDisplayMode().equals(dm)) {
|
|
return;
|
|
}
|
|
Window w = getFullScreenWindow();
|
|
if (w != null) {
|
|
WWindowPeer peer = (WWindowPeer)w.getPeer();
|
|
configDisplayMode(screen, peer, dm.getWidth(), dm.getHeight(),
|
|
dm.getBitDepth(), dm.getRefreshRate());
|
|
// resize the fullscreen window to the dimensions of the new
|
|
// display mode
|
|
Rectangle screenBounds = getDefaultConfiguration().getBounds();
|
|
w.setBounds(screenBounds.x, screenBounds.y,
|
|
dm.getWidth(), dm.getHeight());
|
|
// Note: no call to replaceSurfaceData is required here since
|
|
// replacement will be caused by an upcoming display change event
|
|
} else {
|
|
throw new IllegalStateException("Must be in fullscreen mode " +
|
|
"in order to set display mode");
|
|
}
|
|
}
|
|
|
|
protected native DisplayMode getCurrentDisplayMode(int screen);
|
|
protected native void configDisplayMode(int screen, WindowPeer w, int width,
|
|
int height, int bitDepth,
|
|
int refreshRate);
|
|
protected native void enumDisplayModes(int screen, ArrayList modes);
|
|
|
|
@Override
|
|
public synchronized DisplayMode getDisplayMode() {
|
|
DisplayMode res = getCurrentDisplayMode(screen);
|
|
return res;
|
|
}
|
|
|
|
@Override
|
|
public synchronized DisplayMode[] getDisplayModes() {
|
|
ArrayList modes = new ArrayList();
|
|
enumDisplayModes(screen, modes);
|
|
int listSize = modes.size();
|
|
DisplayMode[] retArray = new DisplayMode[listSize];
|
|
for (int i = 0; i < listSize; i++) {
|
|
retArray[i] = (DisplayMode)modes.get(i);
|
|
}
|
|
return retArray;
|
|
}
|
|
|
|
protected synchronized DisplayMode getMatchingDisplayMode(DisplayMode dm) {
|
|
if (!isDisplayChangeSupported()) {
|
|
return null;
|
|
}
|
|
DisplayMode[] modes = getDisplayModes();
|
|
for (DisplayMode mode : modes) {
|
|
if (dm.equals(mode) ||
|
|
(dm.getRefreshRate() == DisplayMode.REFRESH_RATE_UNKNOWN &&
|
|
dm.getWidth() == mode.getWidth() &&
|
|
dm.getHeight() == mode.getHeight() &&
|
|
dm.getBitDepth() == mode.getBitDepth()))
|
|
{
|
|
return mode;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/*
|
|
* From the DisplayChangeListener interface.
|
|
* Called from Win32GraphicsEnvironment when the display settings have
|
|
* changed.
|
|
*/
|
|
public void displayChanged() {
|
|
dynamicColorModel = null;
|
|
defaultConfig = null;
|
|
configs = null;
|
|
// pass on to all top-level windows on this display
|
|
topLevels.notifyListeners();
|
|
}
|
|
|
|
/**
|
|
* Part of the DisplayChangedListener interface: devices
|
|
* do not need to react to this event
|
|
*/
|
|
public void paletteChanged() {
|
|
}
|
|
|
|
/*
|
|
* Add a DisplayChangeListener to be notified when the display settings
|
|
* are changed. Typically, only top-level containers need to be added
|
|
* to Win32GraphicsDevice.
|
|
*/
|
|
public void addDisplayChangedListener(DisplayChangedListener client) {
|
|
topLevels.add(client);
|
|
}
|
|
|
|
/*
|
|
* Remove a DisplayChangeListener from this Win32GraphicsDevice
|
|
*/
|
|
public void removeDisplayChangedListener(DisplayChangedListener client) {
|
|
topLevels.remove(client);
|
|
}
|
|
|
|
/**
|
|
* Creates and returns the color model associated with this device
|
|
*/
|
|
private native ColorModel makeColorModel (int screen,
|
|
boolean dynamic);
|
|
|
|
/**
|
|
* Returns a dynamic ColorModel which is updated when there
|
|
* are any changes (e.g., palette changes) in the device
|
|
*/
|
|
public ColorModel getDynamicColorModel() {
|
|
if (dynamicColorModel == null) {
|
|
dynamicColorModel = makeColorModel(screen, true);
|
|
}
|
|
return dynamicColorModel;
|
|
}
|
|
|
|
/**
|
|
* Returns the non-dynamic ColorModel associated with this device
|
|
*/
|
|
public ColorModel getColorModel() {
|
|
if (colorModel == null) {
|
|
colorModel = makeColorModel(screen, false);
|
|
}
|
|
return colorModel;
|
|
}
|
|
|
|
/**
|
|
* WindowAdapter class responsible for de/iconifying full-screen window
|
|
* of this device.
|
|
*
|
|
* The listener restores the default display mode when window is iconified
|
|
* and sets it back to the one set by the user on de-iconification.
|
|
*/
|
|
private static class Win32FSWindowAdapter extends WindowAdapter {
|
|
private Win32GraphicsDevice device;
|
|
private DisplayMode dm;
|
|
|
|
Win32FSWindowAdapter(Win32GraphicsDevice device) {
|
|
this.device = device;
|
|
}
|
|
|
|
private void setFSWindowsState(Window other, int state) {
|
|
GraphicsDevice gds[] =
|
|
GraphicsEnvironment.getLocalGraphicsEnvironment().
|
|
getScreenDevices();
|
|
// check if the de/activation was caused by other
|
|
// fs window and ignore the event if that's the case
|
|
if (other != null) {
|
|
for (GraphicsDevice gd : gds) {
|
|
if (other == gd.getFullScreenWindow()) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
// otherwise apply state to all fullscreen windows
|
|
for (GraphicsDevice gd : gds) {
|
|
Window fsw = gd.getFullScreenWindow();
|
|
if (fsw instanceof Frame) {
|
|
((Frame)fsw).setExtendedState(state);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void windowDeactivated(WindowEvent e) {
|
|
setFSWindowsState(e.getOppositeWindow(), Frame.ICONIFIED);
|
|
}
|
|
|
|
@Override
|
|
public void windowActivated(WindowEvent e) {
|
|
setFSWindowsState(e.getOppositeWindow(), Frame.NORMAL);
|
|
}
|
|
|
|
@Override
|
|
public void windowIconified(WindowEvent e) {
|
|
// restore the default display mode for this device
|
|
DisplayMode ddm = device.defaultDisplayMode;
|
|
if (ddm != null) {
|
|
dm = device.getDisplayMode();
|
|
device.setDisplayMode(ddm);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void windowDeiconified(WindowEvent e) {
|
|
// restore the user-set display mode for this device
|
|
if (dm != null) {
|
|
device.setDisplayMode(dm);
|
|
dm = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds a WindowListener to be used as
|
|
* activation/deactivation listener for the current full-screen window.
|
|
*
|
|
* @param w full-screen window
|
|
*/
|
|
protected void addFSWindowListener(final Window w) {
|
|
// Note: even though we create a listener for Window instances of
|
|
// fs windows they will not receive window events.
|
|
fsWindowListener = new Win32FSWindowAdapter(this);
|
|
|
|
// Fix for 6709453. Using invokeLater to avoid listening
|
|
// for the events already posted to the queue.
|
|
EventQueue.invokeLater(new Runnable() {
|
|
public void run() {
|
|
w.addWindowListener(fsWindowListener);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Removes the fs window listener.
|
|
*
|
|
* @param w full-screen window
|
|
*/
|
|
protected void removeFSWindowListener(Window w) {
|
|
w.removeWindowListener(fsWindowListener);
|
|
fsWindowListener = null;
|
|
}
|
|
}
|