Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/classes/sun/awt/Win32GraphicsDevice.java
32287 views
/*1* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.awt;2627import java.awt.AWTPermission;28import java.awt.GraphicsDevice;29import java.awt.GraphicsConfiguration;30import java.awt.GraphicsEnvironment;31import java.awt.DisplayMode;32import java.awt.EventQueue;33import java.awt.Frame;34import java.awt.Rectangle;35import java.awt.Window;36import java.awt.event.WindowAdapter;37import java.awt.event.WindowEvent;38import java.awt.event.WindowListener;39import java.awt.image.ColorModel;40import java.util.ArrayList;41import java.util.Vector;42import java.awt.peer.WindowPeer;43import sun.awt.windows.WWindowPeer;44import sun.java2d.opengl.WGLGraphicsConfig;45import sun.java2d.windows.WindowsFlags;4647/**48* This is an implementation of a GraphicsDevice object for a single49* Win32 screen.50*51* @see GraphicsEnvironment52* @see GraphicsConfiguration53*/54public class Win32GraphicsDevice extends GraphicsDevice implements55DisplayChangedListener {56int screen;57ColorModel dynamicColorModel; // updated with dev changes58ColorModel colorModel; // static for device59protected GraphicsConfiguration[] configs;60protected GraphicsConfiguration defaultConfig;6162private final String idString;63protected String descString;64// Note that we do not synchronize access to this variable - it doesn't65// really matter if a thread does an operation on graphics device which is66// about to become invalid (or already become) - we are prepared to deal67// with this on the native level.68private boolean valid;6970// keep track of top-level windows on this display71private SunDisplayChanger topLevels = new SunDisplayChanger();72// REMIND: we may disable the use of pixel formats for some accelerated73// pipelines which are mutually exclusive with opengl, for which74// pixel formats were added in the first place75protected static boolean pfDisabled;76private static AWTPermission fullScreenExclusivePermission;77// the original display mode we had before entering the fullscreen78// mode79private DisplayMode defaultDisplayMode;80// activation/deactivation listener for the full-screen window81private WindowListener fsWindowListener;8283static {8485// 4455041 - Even when ddraw is disabled, ddraw.dll is loaded when86// pixel format calls are made. This causes problems when a Java app87// is run as an NT service. To prevent the loading of ddraw.dll88// completely, sun.awt.nopixfmt should be set as well. Apps which use89// OpenGL w/ Java probably don't want to set this.90String nopixfmt = (String)java.security.AccessController.doPrivileged(91new sun.security.action.GetPropertyAction("sun.awt.nopixfmt"));92pfDisabled = (nopixfmt != null);93initIDs();94}9596private static native void initIDs();9798native void initDevice(int screen);99100public Win32GraphicsDevice(int screennum) {101this.screen = screennum;102// we cache the strings because we want toString() and getIDstring103// to reflect the original screen number (which may change if the104// device is removed)105idString = "\\Display"+screen;106// REMIND: may be should use class name?107descString = "Win32GraphicsDevice[screen=" + screen;108valid = true;109110initDevice(screennum);111}112113/**114* Returns the type of the graphics device.115* @see #TYPE_RASTER_SCREEN116* @see #TYPE_PRINTER117* @see #TYPE_IMAGE_BUFFER118*/119public int getType() {120return TYPE_RASTER_SCREEN;121}122123/**124* Returns the Win32 screen of the device.125*/126public int getScreen() {127return screen;128}129130/**131* Returns whether this is a valid devicie. Device can become132* invalid as a result of device removal event.133*/134public boolean isValid() {135return valid;136}137138/**139* Called from native code when the device was removed.140*141* @param defaultScreen the current default screen142*/143protected void invalidate(int defaultScreen) {144valid = false;145screen = defaultScreen;146}147148/**149* Returns the identification string associated with this graphics150* device.151*/152public String getIDstring() {153return idString;154}155156157/**158* Returns all of the graphics159* configurations associated with this graphics device.160*/161public GraphicsConfiguration[] getConfigurations() {162if (configs==null) {163if (WindowsFlags.isOGLEnabled() && isDefaultDevice()) {164defaultConfig = getDefaultConfiguration();165if (defaultConfig != null) {166configs = new GraphicsConfiguration[1];167configs[0] = defaultConfig;168return configs.clone();169}170}171172int max = getMaxConfigs(screen);173int defaultPixID = getDefaultPixID(screen);174Vector v = new Vector( max );175if (defaultPixID == 0) {176// Workaround for failing GDI calls177defaultConfig = Win32GraphicsConfig.getConfig(this,178defaultPixID);179v.addElement(defaultConfig);180}181else {182for (int i = 1; i <= max; i++) {183if (isPixFmtSupported(i, screen)) {184if (i == defaultPixID) {185defaultConfig = Win32GraphicsConfig.getConfig(186this, i);187v.addElement(defaultConfig);188}189else {190v.addElement(Win32GraphicsConfig.getConfig(191this, i));192}193}194}195}196configs = new GraphicsConfiguration[v.size()];197v.copyInto(configs);198}199return configs.clone();200}201202/**203* Returns the maximum number of graphics configurations available, or 1204* if PixelFormat calls fail or are disabled.205* This number is less than or equal to the number of graphics206* configurations supported.207*/208protected int getMaxConfigs(int screen) {209if (pfDisabled) {210return 1;211} else {212return getMaxConfigsImpl(screen);213}214}215216private native int getMaxConfigsImpl(int screen);217218/**219* Returns whether or not the PixelFormat indicated by index is220* supported. Supported PixelFormats support drawing to a Window221* (PFD_DRAW_TO_WINDOW), support GDI (PFD_SUPPORT_GDI), and in the222* case of an 8-bit format (cColorBits <= 8) uses indexed colors223* (iPixelType == PFD_TYPE_COLORINDEX).224* We use the index 0 to indicate that PixelFormat calls don't work, or225* are disabled. Do not call this function with an index of 0.226* @param index a PixelFormat index227*/228protected native boolean isPixFmtSupported(int index, int screen);229230/**231* Returns the PixelFormatID of the default graphics configuration232* associated with this graphics device, or 0 if PixelFormats calls fail or233* are disabled.234*/235protected int getDefaultPixID(int screen) {236if (pfDisabled) {237return 0;238} else {239return getDefaultPixIDImpl(screen);240}241}242243/**244* Returns the default PixelFormat ID from GDI. Do not call if PixelFormats245* are disabled.246*/247private native int getDefaultPixIDImpl(int screen);248249/**250* Returns the default graphics configuration251* associated with this graphics device.252*/253public GraphicsConfiguration getDefaultConfiguration() {254if (defaultConfig == null) {255// first try to create a WGLGraphicsConfig if OGL is enabled256// REMIND: the WGL code does not yet work properly in multimon257// situations, so we will fallback on GDI if we are not on the258// default device...259if (WindowsFlags.isOGLEnabled() && isDefaultDevice()) {260int defPixID = WGLGraphicsConfig.getDefaultPixFmt(screen);261defaultConfig = WGLGraphicsConfig.getConfig(this, defPixID);262if (WindowsFlags.isOGLVerbose()) {263if (defaultConfig != null) {264System.out.print("OpenGL pipeline enabled");265} else {266System.out.print("Could not enable OpenGL pipeline");267}268System.out.println(" for default config on screen " +269screen);270}271}272273// Fix for 4669614. Most apps are not concerned with PixelFormats,274// yet we ALWAYS used them for determining ColorModels and such.275// By passing in 0 as the PixelFormatID here, we signal that276// PixelFormats should not be used, thus avoid loading the opengl277// library. Apps concerned with PixelFormats can still use278// GraphicsConfiguration.getConfigurations().279// Note that calling native pixel format functions tends to cause280// problems between those functions (which are OpenGL-related)281// and our use of DirectX. For example, some Matrox boards will282// crash or hang calling these functions when any app is running283// in DirectX fullscreen mode. So avoiding these calls unless284// absolutely necessary is preferable.285if (defaultConfig == null) {286defaultConfig = Win32GraphicsConfig.getConfig(this, 0);287}288}289return defaultConfig;290}291292public String toString() {293return valid ? descString + "]" : descString + ", removed]";294}295296/**297* Returns true if this is the default GraphicsDevice for the298* GraphicsEnvironment.299*/300private boolean isDefaultDevice() {301return (this ==302GraphicsEnvironment.303getLocalGraphicsEnvironment().getDefaultScreenDevice());304}305306private static boolean isFSExclusiveModeAllowed() {307SecurityManager security = System.getSecurityManager();308if (security != null) {309if (fullScreenExclusivePermission == null) {310fullScreenExclusivePermission =311new AWTPermission("fullScreenExclusive");312}313try {314security.checkPermission(fullScreenExclusivePermission);315} catch (SecurityException e) {316return false;317}318}319return true;320}321322/**323* returns true unless we're not allowed to use fullscreen mode.324*/325@Override326public boolean isFullScreenSupported() {327return isFSExclusiveModeAllowed();328}329330@Override331public synchronized void setFullScreenWindow(Window w) {332Window old = getFullScreenWindow();333if (w == old) {334return;335}336if (!isFullScreenSupported()) {337super.setFullScreenWindow(w);338return;339}340341// Enter windowed mode.342if (old != null) {343// restore the original display mode344if (defaultDisplayMode != null) {345setDisplayMode(defaultDisplayMode);346// we set the default display mode to null here347// because the default mode could change during348// the life of the application (user can change it through349// the desktop properties dialog, for example), so350// we need to record it every time prior to351// entering the fullscreen mode.352defaultDisplayMode = null;353}354WWindowPeer peer = (WWindowPeer)old.getPeer();355if (peer != null) {356peer.setFullScreenExclusiveModeState(false);357// we used to destroy the buffers on exiting fs mode, this358// is no longer needed since fs change will cause a surface359// data replacement360synchronized(peer) {361exitFullScreenExclusive(screen, peer);362}363}364removeFSWindowListener(old);365}366super.setFullScreenWindow(w);367if (w != null) {368// always record the default display mode prior to going369// fullscreen370defaultDisplayMode = getDisplayMode();371addFSWindowListener(w);372// Enter full screen exclusive mode.373WWindowPeer peer = (WWindowPeer)w.getPeer();374if (peer != null) {375synchronized(peer) {376enterFullScreenExclusive(screen, peer);377// Note: removed replaceSurfaceData() call because378// changing the window size or making it visible379// will cause this anyway, and both of these events happen380// as part of switching into fullscreen mode.381}382peer.setFullScreenExclusiveModeState(true);383}384385// fix for 4868278386peer.updateGC();387}388}389390// Entering and exiting full-screen mode are done within a391// tree-lock and should never lock on any resources which are392// required by other threads which may have them and may require393// the tree-lock.394// REMIND: in the future these methods may need to become protected so that395// subclasses could override them and use appropriate api other than GDI396// for implementing these functions.397protected native void enterFullScreenExclusive(int screen, WindowPeer w);398protected native void exitFullScreenExclusive(int screen, WindowPeer w);399400@Override401public boolean isDisplayChangeSupported() {402return (isFullScreenSupported() && getFullScreenWindow() != null);403}404405@Override406public synchronized void setDisplayMode(DisplayMode dm) {407if (!isDisplayChangeSupported()) {408super.setDisplayMode(dm);409return;410}411if (dm == null || (dm = getMatchingDisplayMode(dm)) == null) {412throw new IllegalArgumentException("Invalid display mode");413}414if (getDisplayMode().equals(dm)) {415return;416}417Window w = getFullScreenWindow();418if (w != null) {419WWindowPeer peer = (WWindowPeer)w.getPeer();420configDisplayMode(screen, peer, dm.getWidth(), dm.getHeight(),421dm.getBitDepth(), dm.getRefreshRate());422// resize the fullscreen window to the dimensions of the new423// display mode424Rectangle screenBounds = getDefaultConfiguration().getBounds();425w.setBounds(screenBounds.x, screenBounds.y,426dm.getWidth(), dm.getHeight());427// Note: no call to replaceSurfaceData is required here since428// replacement will be caused by an upcoming display change event429} else {430throw new IllegalStateException("Must be in fullscreen mode " +431"in order to set display mode");432}433}434435protected native DisplayMode getCurrentDisplayMode(int screen);436protected native void configDisplayMode(int screen, WindowPeer w, int width,437int height, int bitDepth,438int refreshRate);439protected native void enumDisplayModes(int screen, ArrayList modes);440441@Override442public synchronized DisplayMode getDisplayMode() {443DisplayMode res = getCurrentDisplayMode(screen);444return res;445}446447@Override448public synchronized DisplayMode[] getDisplayModes() {449ArrayList modes = new ArrayList();450enumDisplayModes(screen, modes);451int listSize = modes.size();452DisplayMode[] retArray = new DisplayMode[listSize];453for (int i = 0; i < listSize; i++) {454retArray[i] = (DisplayMode)modes.get(i);455}456return retArray;457}458459protected synchronized DisplayMode getMatchingDisplayMode(DisplayMode dm) {460if (!isDisplayChangeSupported()) {461return null;462}463DisplayMode[] modes = getDisplayModes();464for (DisplayMode mode : modes) {465if (dm.equals(mode) ||466(dm.getRefreshRate() == DisplayMode.REFRESH_RATE_UNKNOWN &&467dm.getWidth() == mode.getWidth() &&468dm.getHeight() == mode.getHeight() &&469dm.getBitDepth() == mode.getBitDepth()))470{471return mode;472}473}474return null;475}476477/*478* From the DisplayChangeListener interface.479* Called from Win32GraphicsEnvironment when the display settings have480* changed.481*/482public void displayChanged() {483dynamicColorModel = null;484defaultConfig = null;485configs = null;486// pass on to all top-level windows on this display487topLevels.notifyListeners();488}489490/**491* Part of the DisplayChangedListener interface: devices492* do not need to react to this event493*/494public void paletteChanged() {495}496497/*498* Add a DisplayChangeListener to be notified when the display settings499* are changed. Typically, only top-level containers need to be added500* to Win32GraphicsDevice.501*/502public void addDisplayChangedListener(DisplayChangedListener client) {503topLevels.add(client);504}505506/*507* Remove a DisplayChangeListener from this Win32GraphicsDevice508*/509public void removeDisplayChangedListener(DisplayChangedListener client) {510topLevels.remove(client);511}512513/**514* Creates and returns the color model associated with this device515*/516private native ColorModel makeColorModel (int screen,517boolean dynamic);518519/**520* Returns a dynamic ColorModel which is updated when there521* are any changes (e.g., palette changes) in the device522*/523public ColorModel getDynamicColorModel() {524if (dynamicColorModel == null) {525dynamicColorModel = makeColorModel(screen, true);526}527return dynamicColorModel;528}529530/**531* Returns the non-dynamic ColorModel associated with this device532*/533public ColorModel getColorModel() {534if (colorModel == null) {535colorModel = makeColorModel(screen, false);536}537return colorModel;538}539540/**541* WindowAdapter class responsible for de/iconifying full-screen window542* of this device.543*544* The listener restores the default display mode when window is iconified545* and sets it back to the one set by the user on de-iconification.546*/547private static class Win32FSWindowAdapter extends WindowAdapter {548private Win32GraphicsDevice device;549private DisplayMode dm;550551Win32FSWindowAdapter(Win32GraphicsDevice device) {552this.device = device;553}554555private void setFSWindowsState(Window other, int state) {556GraphicsDevice gds[] =557GraphicsEnvironment.getLocalGraphicsEnvironment().558getScreenDevices();559// check if the de/activation was caused by other560// fs window and ignore the event if that's the case561if (other != null) {562for (GraphicsDevice gd : gds) {563if (other == gd.getFullScreenWindow()) {564return;565}566}567}568// otherwise apply state to all fullscreen windows569for (GraphicsDevice gd : gds) {570Window fsw = gd.getFullScreenWindow();571if (fsw instanceof Frame) {572((Frame)fsw).setExtendedState(state);573}574}575}576577@Override578public void windowDeactivated(WindowEvent e) {579setFSWindowsState(e.getOppositeWindow(), Frame.ICONIFIED);580}581582@Override583public void windowActivated(WindowEvent e) {584setFSWindowsState(e.getOppositeWindow(), Frame.NORMAL);585}586587@Override588public void windowIconified(WindowEvent e) {589// restore the default display mode for this device590DisplayMode ddm = device.defaultDisplayMode;591if (ddm != null) {592dm = device.getDisplayMode();593device.setDisplayMode(ddm);594}595}596597@Override598public void windowDeiconified(WindowEvent e) {599// restore the user-set display mode for this device600if (dm != null) {601device.setDisplayMode(dm);602dm = null;603}604}605}606607/**608* Adds a WindowListener to be used as609* activation/deactivation listener for the current full-screen window.610*611* @param w full-screen window612*/613protected void addFSWindowListener(final Window w) {614// Note: even though we create a listener for Window instances of615// fs windows they will not receive window events.616fsWindowListener = new Win32FSWindowAdapter(this);617618// Fix for 6709453. Using invokeLater to avoid listening619// for the events already posted to the queue.620EventQueue.invokeLater(new Runnable() {621public void run() {622w.addWindowListener(fsWindowListener);623}624});625}626627/**628* Removes the fs window listener.629*630* @param w full-screen window631*/632protected void removeFSWindowListener(Window w) {633w.removeWindowListener(fsWindowListener);634fsWindowListener = null;635}636}637638639