Path: blob/master/src/java.desktop/macosx/classes/sun/awt/CGraphicsEnvironment.java
41152 views
/*1* Copyright (c) 2011, 2020, 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.Font;28import java.awt.GraphicsConfiguration;29import java.awt.GraphicsDevice;30import java.awt.HeadlessException;31import java.awt.Toolkit;32import java.lang.ref.WeakReference;33import java.util.ArrayList;34import java.util.HashMap;35import java.util.List;36import java.util.ListIterator;37import java.util.Map;3839import sun.java2d.MacosxSurfaceManagerFactory;40import sun.java2d.SunGraphicsEnvironment;41import sun.java2d.SurfaceManagerFactory;4243/**44* This is an implementation of a GraphicsEnvironment object for the default45* local GraphicsEnvironment used by the Java Runtime Environment for Mac OS X46* GUI environments.47*48* @see GraphicsDevice49* @see GraphicsConfiguration50*/51public final class CGraphicsEnvironment extends SunGraphicsEnvironment {5253/**54* Fetch an array of all valid CoreGraphics display identifiers.55*/56private static native int[] getDisplayIDs();5758/**59* Fetch the CoreGraphics display ID for the 'main' display.60*/61private static native int getMainDisplayID();6263/**64* Noop function that just acts as an entry point for someone to force a65* static initialization of this class.66*/67public static void init() { }6869static {70// Load libraries and initialize the Toolkit.71Toolkit.getDefaultToolkit();72// Install the correct surface manager factory.73SurfaceManagerFactory.setInstance(new MacosxSurfaceManagerFactory());74}7576/**77* Register the instance with CGDisplayRegisterReconfigurationCallback().78* The registration uses a weak global reference -- if our instance is79* garbage collected, the reference will be dropped.80*81* @return Return the registration context (a pointer).82*/83private native long registerDisplayReconfiguration();8485/**86* Remove the instance's registration with CGDisplayRemoveReconfigurationCallback()87*/88private native void deregisterDisplayReconfiguration(long context);8990/** Available CoreGraphics displays. */91private final Map<Integer, CGraphicsDevice> devices = new HashMap<>(5);92/**93* The key in the {@link #devices} for the main display.94*/95private int mainDisplayID;9697/** Reference to the display reconfiguration callback context. */98private final long displayReconfigContext;99100// list of invalidated graphics devices (those which were removed)101private List<WeakReference<CGraphicsDevice>> oldDevices = new ArrayList<>();102103/**104* Construct a new instance.105*/106public CGraphicsEnvironment() {107if (isHeadless()) {108displayReconfigContext = 0L;109return;110}111112/* Populate the device table */113rebuildDevices();114115/* Register our display reconfiguration listener */116displayReconfigContext = registerDisplayReconfiguration();117if (displayReconfigContext == 0L) {118throw new RuntimeException("Could not register CoreGraphics display reconfiguration callback");119}120}121122/**123* Updates the list of devices and notify listeners.124*/125private void rebuildDevices() {126initDevices();127displayChanged();128}129130/**131* Called by the CoreGraphics Display Reconfiguration Callback.132*133* @param displayId CoreGraphics displayId134* @param removed true if displayId was removed, false otherwise.135*/136void _displayReconfiguration(int displayId, boolean removed) {137// we ignore the passed parameters and check removed devices ourself138// Note that it is possible that this callback is called when the139// monitors are not added nor removed, but when the video card is140// switched to/from the discrete video card, so we should try to map the141// old to the new devices.142rebuildDevices();143}144145@Override146@SuppressWarnings("deprecation")147protected void finalize() throws Throwable {148try {149super.finalize();150} finally {151deregisterDisplayReconfiguration(displayReconfigContext);152}153}154155/**156* (Re)create all CGraphicsDevices, reuses a devices if it is possible.157*/158private synchronized void initDevices() {159Map<Integer, CGraphicsDevice> old = new HashMap<>(devices);160devices.clear();161mainDisplayID = getMainDisplayID();162163// initialization of the graphics device may change list of displays on164// hybrid systems via an activation of discrete video.165// So, we initialize the main display first, then retrieve actual list166// of displays, and then recheck the main display again.167if (!old.containsKey(mainDisplayID)) {168old.put(mainDisplayID, new CGraphicsDevice(mainDisplayID));169}170171int[] displayIDs = getDisplayIDs();172if (displayIDs.length == 0) {173// we could throw AWTError in this case.174displayIDs = new int[]{mainDisplayID};175}176for (int id : displayIDs) {177devices.put(id, old.containsKey(id) ? old.remove(id)178: new CGraphicsDevice(id));179}180// fetch the main display again, the old value might be outdated181mainDisplayID = getMainDisplayID();182183// unlikely but make sure the main screen is in the list of screens,184// most probably one more "displayReconfiguration" is on the road if not185if (!devices.containsKey(mainDisplayID)) {186mainDisplayID = displayIDs[0]; // best we can do187}188// if a device was not reused it should be invalidated189for (CGraphicsDevice gd : old.values()) {190oldDevices.add(new WeakReference<>(gd));191}192// Need to notify old devices, in case the user hold the reference to it193for (ListIterator<WeakReference<CGraphicsDevice>> it =194oldDevices.listIterator(); it.hasNext(); ) {195CGraphicsDevice gd = it.next().get();196if (gd != null) {197// If the old device has the same bounds as some new device198// then map that old device to the new, or to the main screen.199CGraphicsDevice similarDevice = getSimilarDevice(gd);200if (similarDevice == null) {201gd.invalidate(devices.get(mainDisplayID));202} else {203gd.invalidate(similarDevice);204}205gd.displayChanged();206} else {207// no more references to this device, remove it208it.remove();209}210}211}212213private CGraphicsDevice getSimilarDevice(CGraphicsDevice old) {214for (CGraphicsDevice device : devices.values()) {215if (device.getBounds().equals(old.getBounds())) {216// for now we will use the bounds only217return device;218}219}220return null;221}222223@Override224public synchronized GraphicsDevice getDefaultScreenDevice() throws HeadlessException {225return devices.get(mainDisplayID);226}227228@Override229public synchronized GraphicsDevice[] getScreenDevices() throws HeadlessException {230return devices.values().toArray(new CGraphicsDevice[devices.values().size()]);231}232233public synchronized GraphicsDevice getScreenDevice(int displayID) {234return devices.get(displayID);235}236237@Override238protected synchronized int getNumScreens() {239return devices.size();240}241242@Override243protected GraphicsDevice makeScreenDevice(int screennum) {244throw new UnsupportedOperationException("This method is unused and should not be called in this implementation");245}246247@Override248public boolean isDisplayLocal() {249return true;250}251252static String[] sLogicalFonts = { "Serif", "SansSerif", "Monospaced", "Dialog", "DialogInput" };253254@Override255public Font[] getAllFonts() {256257Font[] newFonts;258Font[] superFonts = super.getAllFonts();259260int numLogical = sLogicalFonts.length;261int numOtherFonts = superFonts.length;262263newFonts = new Font[numOtherFonts + numLogical];264System.arraycopy(superFonts,0,newFonts,numLogical,numOtherFonts);265266for (int i = 0; i < numLogical; i++)267{268newFonts[i] = new Font(sLogicalFonts[i], Font.PLAIN, 1);269}270return newFonts;271}272273}274275276