
com.sun.javafx.tk.Toolkit Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 2010, 2024, 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 com.sun.javafx.tk;
import javafx.application.ConditionalFeature;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.geometry.Dimension2D;
import javafx.scene.effect.BlurType;
import javafx.scene.image.Image;
import javafx.scene.image.PixelFormat;
import javafx.scene.image.WritableImage;
import javafx.scene.input.Dragboard;
import javafx.scene.input.InputMethodRequests;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.paint.Color;
import javafx.scene.paint.ImagePattern;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Paint;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;
import javafx.scene.shape.PathElement;
import javafx.scene.shape.SVGPath;
import javafx.scene.shape.StrokeLineCap;
import javafx.scene.shape.StrokeLineJoin;
import javafx.scene.shape.StrokeType;
import javafx.stage.FileChooser.ExtensionFilter;
import javafx.stage.Modality;
import javafx.stage.StageStyle;
import javafx.stage.Window;
import java.io.File;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import com.sun.glass.ui.CommonDialogs.FileChooserResult;
import com.sun.glass.ui.GlassRobot;
import com.sun.glass.utils.NativeLibLoader;
import com.sun.javafx.PlatformUtil;
import com.sun.javafx.beans.event.AbstractNotifyListener;
import com.sun.javafx.embed.HostInterface;
import com.sun.javafx.geom.Path2D;
import com.sun.javafx.geom.transform.BaseTransform;
import com.sun.javafx.perf.PerformanceTracker;
import com.sun.javafx.runtime.VersionInfo;
import com.sun.javafx.runtime.async.AsyncOperation;
import com.sun.javafx.runtime.async.AsyncOperationListener;
import com.sun.javafx.scene.text.TextLayoutFactory;
import com.sun.javafx.sg.prism.NGCamera;
import com.sun.javafx.sg.prism.NGLightBase;
import com.sun.javafx.sg.prism.NGNode;
import com.sun.javafx.util.Utils;
import com.sun.scenario.DelayedRunnable;
import com.sun.scenario.animation.AbstractPrimaryTimer;
import com.sun.scenario.effect.AbstractShadow.ShadowMode;
import com.sun.scenario.effect.Color4f;
import com.sun.scenario.effect.FilterContext;
import com.sun.scenario.effect.Filterable;
import java.util.Optional;
public abstract class Toolkit {
private static String tk;
private static Toolkit TOOLKIT;
private static Thread fxUserThread = null;
private static final String QUANTUM_TOOLKIT = "com.sun.javafx.tk.quantum.QuantumToolkit";
private static final String DEFAULT_TOOLKIT = QUANTUM_TOOLKIT;
private static final Map gradientMap = new WeakHashMap();
private static final boolean verbose = Boolean.getBoolean("javafx.verbose");
private static final String[] msLibNames = {
"api-ms-win-core-console-l1-1-0",
"api-ms-win-core-console-l1-2-0",
"api-ms-win-core-datetime-l1-1-0",
"api-ms-win-core-debug-l1-1-0",
"api-ms-win-core-errorhandling-l1-1-0",
"api-ms-win-core-file-l1-1-0",
"api-ms-win-core-file-l1-2-0",
"api-ms-win-core-file-l2-1-0",
"api-ms-win-core-handle-l1-1-0",
"api-ms-win-core-heap-l1-1-0",
"api-ms-win-core-interlocked-l1-1-0",
"api-ms-win-core-libraryloader-l1-1-0",
"api-ms-win-core-localization-l1-2-0",
"api-ms-win-core-memory-l1-1-0",
"api-ms-win-core-namedpipe-l1-1-0",
"api-ms-win-core-processenvironment-l1-1-0",
"api-ms-win-core-processthreads-l1-1-0",
"api-ms-win-core-processthreads-l1-1-1",
"api-ms-win-core-profile-l1-1-0",
"api-ms-win-core-rtlsupport-l1-1-0",
"api-ms-win-core-string-l1-1-0",
"api-ms-win-core-synch-l1-1-0",
"api-ms-win-core-synch-l1-2-0",
"api-ms-win-core-sysinfo-l1-1-0",
"api-ms-win-core-timezone-l1-1-0",
"api-ms-win-core-util-l1-1-0",
"api-ms-win-crt-conio-l1-1-0",
"api-ms-win-crt-convert-l1-1-0",
"api-ms-win-crt-environment-l1-1-0",
"api-ms-win-crt-filesystem-l1-1-0",
"api-ms-win-crt-heap-l1-1-0",
"api-ms-win-crt-locale-l1-1-0",
"api-ms-win-crt-math-l1-1-0",
"api-ms-win-crt-multibyte-l1-1-0",
"api-ms-win-crt-private-l1-1-0",
"api-ms-win-crt-process-l1-1-0",
"api-ms-win-crt-runtime-l1-1-0",
"api-ms-win-crt-stdio-l1-1-0",
"api-ms-win-crt-string-l1-1-0",
"api-ms-win-crt-time-l1-1-0",
"api-ms-win-crt-utility-l1-1-0",
"ucrtbase",
// Finally load VS 2017 DLLs in the following order
"vcruntime140",
"vcruntime140_1",
"msvcp140",
"msvcp140_1",
"msvcp140_2"
};
private static String lookupToolkitClass(String name) {
if ("prism".equalsIgnoreCase(name)) {
return QUANTUM_TOOLKIT;
} else if ("quantum".equalsIgnoreCase(name)) {
return QUANTUM_TOOLKIT;
}
return name;
}
public static synchronized void loadMSWindowsLibraries() {
for (String libName : msLibNames) {
try {
NativeLibLoader.loadLibrary(libName);
} catch (Throwable t) {
if (verbose) {
System.err.println("Error: failed to load "
+ libName + ".dll : " + t);
}
}
}
}
private static String getDefaultToolkit() {
if (PlatformUtil.isWindows()) {
return DEFAULT_TOOLKIT;
} else if (PlatformUtil.isMac()) {
return DEFAULT_TOOLKIT;
} else if (PlatformUtil.isLinux()) {
return DEFAULT_TOOLKIT;
} else if (PlatformUtil.isIOS()) {
return DEFAULT_TOOLKIT;
} else if (PlatformUtil.isAndroid()) {
return DEFAULT_TOOLKIT;
}
throw new UnsupportedOperationException(System.getProperty("os.name") + " is not supported");
}
public static synchronized Toolkit getToolkit() {
if (TOOLKIT != null) {
return TOOLKIT;
}
// Get the javafx.version and javafx.runtime.version from a preconstructed
// java class, VersionInfo, created at build time.
VersionInfo.setupSystemProperties();
// Load required Microsoft runtime DLLs on Windows platforms
if (PlatformUtil.isWindows()) {
loadMSWindowsLibraries();
}
boolean userSpecifiedToolkit = true;
// Check a system property to see if there is a specific toolkit to use.
String forcedToolkit = null;
forcedToolkit = System.getProperty("javafx.toolkit");
if (forcedToolkit == null) {
forcedToolkit = tk;
}
if (forcedToolkit == null) {
userSpecifiedToolkit = false;
forcedToolkit = getDefaultToolkit();
}
if (forcedToolkit.indexOf('.') == -1) {
// Turn a short name into a fully qualified classname
forcedToolkit = lookupToolkitClass(forcedToolkit);
}
boolean printToolkit = verbose
|| (userSpecifiedToolkit && !forcedToolkit.endsWith("StubToolkit"));
try {
Class clz = null;
try {
// try our priveledged loader first
final ClassLoader loader = Toolkit.class.getClassLoader();
clz = Class.forName(forcedToolkit, false, loader);
} catch (ClassNotFoundException e) {
// fall back and try the application class loader
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
clz = Class.forName(forcedToolkit, false, loader);
}
// Check that clz is a subclass of Toolkit
if (!Toolkit.class.isAssignableFrom(clz)) {
throw new IllegalArgumentException("Unrecognized FX Toolkit class: "
+ forcedToolkit);
}
TOOLKIT = (Toolkit)clz.getDeclaredConstructor().newInstance();
if (TOOLKIT.init()) {
if (printToolkit) {
System.err.println("JavaFX: using " + forcedToolkit);
}
return TOOLKIT;
}
TOOLKIT = null;
} catch (Exception any) {
TOOLKIT = null;
any.printStackTrace();
}
throw new RuntimeException("No toolkit found");
}
protected static Thread getFxUserThread() {
return fxUserThread;
}
protected static void setFxUserThread(Thread t) {
if (fxUserThread != null) {
throw new IllegalStateException("Error: FX User Thread already initialized");
}
fxUserThread = t;
}
public void checkFxUserThread() {
// Throw exception if not on FX user thread
if (!isFxUserThread()) {
throw new IllegalStateException("Not on FX application thread; currentThread = "
+ Thread.currentThread().getName());
}
}
// Toolkit can override this if needed
public boolean isFxUserThread() {
return Thread.currentThread() == fxUserThread;
}
protected Toolkit() {
}
public abstract boolean init();
/**
* Indicates whether a nested event loop can be started from the current thread in the current state.
* A nested event loop can be started from an event handler or from a {@code Runnable} passed to
* {@code Platform.runLater(Runnable)}.
* This method must be called on the JavaFX Application thread.
*
* @return {@code true} if a nested event loop can be started, and {@code false} otherwise.
*
* @throws IllegalStateException if this method is called on a thread other than the JavaFX Application Thread.
*/
public abstract boolean canStartNestedEventLoop();
/**
* Enter a nested event loop and block until the corresponding
* exitNestedEventLoop call is made.
* The key passed into this method is used to
* uniquely identify the matched enter/exit pair. This method creates a
* new nested event loop and blocks until the corresponding
* exitNestedEventLoop method is called with the same key.
* The return value of this method will be the {@code rval}
* object supplied to the exitNestedEventLoop method call that unblocks it.
*
* @param key the Object that identifies the nested event loop, which
* must not be null
*
* @throws IllegalArgumentException if the specified key is associated
* with a nested event loop that has not yet returned
*
* @throws NullPointerException if the key is null
*
* @throws IllegalStateException if this method is called on a thread
* other than the FX Application thread
*
* @return the value passed into the corresponding call to exitEventLoop
*/
public abstract Object enterNestedEventLoop(Object key);
/**
* Exit a nested event loop and unblock the caller of the
* corresponding enterNestedEventLoop.
* The key passed into this method is used to
* uniquely identify the matched enter/exit pair. This method causes the
* nested event loop that was previously created with the key to exit and
* return control to the caller. If the specified nested event loop is not
* the inner-most loop then it will not return until all other inner loops
* also exit.
*
* @param key the Object that identifies the nested event loop, which
* must not be null
*
* @param rval an Object that is returned to the caller of the
* corresponding enterNestedEventLoop. This may be null.
*
* @throws IllegalArgumentException if the specified key is not associated
* with an active nested event loop
*
* @throws NullPointerException if the key is null
*
* @throws IllegalStateException if this method is called on a thread
* other than the FX Application thread
*/
public abstract void exitNestedEventLoop(Object key, Object rval);
public abstract void exitAllNestedEventLoops();
public abstract boolean isNestedLoopRunning();
public abstract TKStage createTKStage(Window peerWindow, StageStyle stageStyle, boolean primary, Modality modality, TKStage owner, boolean rtl);
public abstract TKStage createTKPopupStage(Window peerWindow, StageStyle popupStyle, TKStage owner);
public abstract TKStage createTKEmbeddedStage(HostInterface host);
// The following collections of listeners is weakly referenced here in order
// to allow garbage collection when the listeners are otherwise no longer
// referenced.
private final Set stagePulseListeners = Collections.newSetFromMap(new WeakHashMap<>());
private final Set scenePulseListeners = Collections.newSetFromMap(new WeakHashMap<>());
private final Set postScenePulseListeners = Collections.newSetFromMap(new WeakHashMap<>());
private final Set toolkitListeners = Collections.newSetFromMap(new WeakHashMap<>());
// The set of shutdown hooks is strongly held to avoid premature GC.
private final Set shutdownHooks = new HashSet<>();
private void runPulse(final TKPulseListener listener) {
listener.pulse();
}
public void firePulse() {
// Stages need to be notified of pulses before scenes so the Stage can resized
// and those changes propogated to scene before it gets its pulse to update
// Copy of listener keySet
final Set stagePulseList = new HashSet<>();
final Set scenePulseList = new HashSet<>();
final Set postScenePulseList = new HashSet<>();
synchronized (this) {
stagePulseList.addAll(stagePulseListeners);
scenePulseList.addAll(scenePulseListeners);
postScenePulseList.addAll(postScenePulseListeners);
}
for (TKPulseListener listener : stagePulseList) {
runPulse(listener);
}
for (TKPulseListener listener : scenePulseList) {
runPulse(listener);
}
for (TKPulseListener listener : postScenePulseList) {
runPulse(listener);
}
if (lastTkPulseListener != null) {
runPulse(lastTkPulseListener);
}
}
public void addStageTkPulseListener(TKPulseListener listener) {
if (listener == null) {
return;
}
synchronized (this) {
stagePulseListeners.add(listener);
}
}
public void removeStageTkPulseListener(TKPulseListener listener) {
synchronized (this) {
stagePulseListeners.remove(listener);
}
}
public void addSceneTkPulseListener(TKPulseListener listener) {
if (listener == null) {
return;
}
synchronized (this) {
scenePulseListeners.add(listener);
}
}
public void removeSceneTkPulseListener(TKPulseListener listener) {
synchronized (this) {
scenePulseListeners.remove(listener);
}
}
public void addPostSceneTkPulseListener(TKPulseListener listener) {
if (listener == null) {
return;
}
synchronized (this) {
postScenePulseListeners.add(listener);
}
}
public void removePostSceneTkPulseListener(TKPulseListener listener) {
synchronized (this) {
postScenePulseListeners.remove(listener);
}
}
public void addTkListener(TKListener listener) {
if (listener == null) {
return;
}
toolkitListeners.add(listener);
}
public void removeTkListener(TKListener listener) {
toolkitListeners.remove(listener);
}
private TKPulseListener lastTkPulseListener = null;
public void setLastTkPulseListener(TKPulseListener listener) {
lastTkPulseListener = listener;
}
public void addShutdownHook(Runnable hook) {
if (hook == null) {
return;
}
synchronized (shutdownHooks) {
shutdownHooks.add(hook);
}
}
public void removeShutdownHook(Runnable hook) {
synchronized (shutdownHooks) {
shutdownHooks.remove(hook);
}
}
protected void notifyShutdownHooks() {
List hooks;
synchronized (shutdownHooks) {
hooks = new ArrayList<>(shutdownHooks);
shutdownHooks.clear();
}
for (Runnable hook : hooks) {
hook.run();
}
}
public void notifyWindowListeners(final List windows) {
for (TKListener listener : toolkitListeners) {
listener.changedTopLevelWindows(windows);
}
}
public void notifyLastNestedLoopExited() {
for (TKListener listener: toolkitListeners) {
listener.exitedLastNestedLoop();
}
}
// notify the pulse timer code that we need the next pulse to happen
// this flag is cleared each cycle so subsequent pulses must be requested
public abstract void requestNextPulse();
public abstract Future addRenderJob(RenderJob rj);
public abstract ImageLoader loadImage(String url,
double width, double height,
boolean preserveRatio,
boolean smooth);
public abstract ImageLoader loadImage(InputStream stream,
double width, double height,
boolean preserveRatio,
boolean smooth);
public abstract AsyncOperation loadImageAsync(
AsyncOperationListener extends ImageLoader> listener,
String url,
double width, double height,
boolean preserveRatio,
boolean smooth);
/*
* The loadPlatformImage method supports the following image types:
* - an object returned by the renderToImage method
* - an instance of com.sun.prism.Image (in case of prism)
* - an instance of an external image object, which can be a BufferedImage
* If JavaFX Image had one more constructor Image(ImageLoader),
* we could introduce a different method for external image loading support.
*/
public abstract ImageLoader loadPlatformImage(Object platformImage);
public abstract PlatformImage createPlatformImage(int w, int h);
// Indicates the default state of smooth for ImageView and MediaView
// Subclasses may override this to provide a platform-specific default
public boolean getDefaultImageSmooth() { return true; }
public abstract void startup(Runnable runnable);
public abstract void defer(Runnable runnable);
public void exit() {
fxUserThread = null;
}
public abstract Map
© 2015 - 2025 Weber Informatics LLC | Privacy Policy