Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.sun.javafx.tk.quantum.QuantumToolkit Maven / Gradle / Ivy
/*
* Copyright (c) 2010, 2013, 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.quantum;
import java.io.File;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import javafx.application.ConditionalFeature;
import javafx.geometry.Dimension2D;
import javafx.scene.image.Image;
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.CycleMethod;
import javafx.scene.paint.ImagePattern;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;
import javafx.scene.shape.ClosePath;
import javafx.scene.shape.CubicCurveTo;
import javafx.scene.shape.FillRule;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.PathElement;
import javafx.scene.shape.QuadCurveTo;
import javafx.scene.shape.SVGPath;
import javafx.stage.FileChooser;
import javafx.stage.Modality;
import javafx.stage.StageStyle;
import com.sun.glass.ui.Application;
import com.sun.glass.ui.Clipboard;
import com.sun.glass.ui.ClipboardAssistance;
import com.sun.glass.ui.CommonDialogs;
import com.sun.glass.ui.CommonDialogs.FileChooserResult;
import com.sun.glass.ui.EventLoop;
import com.sun.glass.ui.Screen;
import com.sun.glass.ui.Timer;
import com.sun.glass.ui.View;
import com.sun.javafx.PlatformUtil;
import com.sun.javafx.embed.HostInterface;
import com.sun.javafx.geom.Path2D;
import com.sun.javafx.geom.PathIterator;
import com.sun.javafx.geom.Shape;
import com.sun.javafx.geom.transform.BaseTransform;
import com.sun.javafx.perf.PerformanceTracker;
import com.sun.javafx.runtime.async.AbstractRemoteResource;
import com.sun.javafx.runtime.async.AsyncOperationListener;
import com.sun.javafx.scene.text.HitInfo;
import com.sun.javafx.scene.text.TextLayoutFactory;
import com.sun.javafx.sg.PGArc;
import com.sun.javafx.sg.PGCanvas;
import com.sun.javafx.sg.PGCircle;
import com.sun.javafx.sg.PGCubicCurve;
import com.sun.javafx.sg.PGEllipse;
import com.sun.javafx.sg.PGExternalNode;
import com.sun.javafx.sg.PGGroup;
import com.sun.javafx.sg.PGImageView;
import com.sun.javafx.sg.PGLine;
import com.sun.javafx.sg.PGPath;
import com.sun.javafx.sg.PGPolygon;
import com.sun.javafx.sg.PGPolyline;
import com.sun.javafx.sg.PGQuadCurve;
import com.sun.javafx.sg.PGRectangle;
import com.sun.javafx.sg.PGRegion;
import com.sun.javafx.sg.PGSVGPath;
import com.sun.javafx.sg.PGShape.StrokeLineCap;
import com.sun.javafx.sg.PGShape.StrokeLineJoin;
import com.sun.javafx.sg.PGShape.StrokeType;
import com.sun.javafx.sg.PGText;
import com.sun.javafx.sg.prism.NGArc;
import com.sun.javafx.sg.prism.NGCanvas;
import com.sun.javafx.sg.prism.NGCircle;
import com.sun.javafx.sg.prism.NGCubicCurve;
import com.sun.javafx.sg.prism.NGEllipse;
import com.sun.javafx.sg.prism.NGGroup;
import com.sun.javafx.sg.prism.NGImageView;
import com.sun.javafx.sg.prism.NGLine;
import com.sun.javafx.sg.prism.NGNode;
import com.sun.javafx.sg.prism.NGPath;
import com.sun.javafx.sg.prism.NGPolygon;
import com.sun.javafx.sg.prism.NGPolyline;
import com.sun.javafx.sg.prism.NGQuadCurve;
import com.sun.javafx.sg.prism.NGRectangle;
import com.sun.javafx.sg.prism.NGRegion;
import com.sun.javafx.sg.prism.NGSVGPath;
import com.sun.javafx.sg.prism.NGText;
import com.sun.javafx.tk.AppletWindow;
import com.sun.javafx.tk.CompletionListener;
import com.sun.javafx.tk.FileChooserType;
import com.sun.javafx.tk.FontLoader;
import com.sun.javafx.tk.ImageLoader;
import com.sun.javafx.tk.PlatformImage;
import com.sun.javafx.tk.RenderJob;
import com.sun.javafx.tk.ScreenConfigurationAccessor;
import com.sun.javafx.tk.TKClipboard;
import com.sun.javafx.tk.TKDragGestureListener;
import com.sun.javafx.tk.TKDragSourceListener;
import com.sun.javafx.tk.TKDropTargetListener;
import com.sun.javafx.tk.TKScene;
import com.sun.javafx.tk.TKScreenConfigurationListener;
import com.sun.javafx.tk.TKStage;
import com.sun.javafx.tk.TKSystemMenu;
import com.sun.javafx.tk.Toolkit;
import com.sun.prism.BasicStroke;
import com.sun.prism.Graphics;
import com.sun.prism.GraphicsPipeline;
import com.sun.prism.PixelFormat;
import com.sun.prism.RTTexture;
import com.sun.prism.ResourceFactory;
import com.sun.prism.ResourceFactoryListener;
import com.sun.prism.Texture.WrapMode;
import com.sun.prism.camera.PrismCameraImpl;
import com.sun.prism.impl.Disposer;
import com.sun.prism.impl.PrismSettings;
import com.sun.scenario.DelayedRunnable;
import com.sun.scenario.animation.AbstractMasterTimer;
import com.sun.scenario.effect.FilterContext;
import com.sun.scenario.effect.Filterable;
import com.sun.scenario.effect.impl.prism.PrFilterContext;
import com.sun.scenario.effect.impl.prism.PrImage;
import static com.sun.javafx.logging.PulseLogger.*;
import com.sun.javafx.sg.PGAmbientLight;
import com.sun.javafx.sg.PGBox;
import com.sun.javafx.sg.PGCylinder;
import com.sun.javafx.sg.PGMeshView;
import com.sun.javafx.sg.PGParallelCamera;
import com.sun.javafx.sg.PGPerspectiveCamera;
import com.sun.javafx.sg.PGPhongMaterial;
import com.sun.javafx.sg.PGPointLight;
import com.sun.javafx.sg.PGSphere;
import com.sun.javafx.sg.PGSubScene;
import com.sun.javafx.sg.PGTriangleMesh;
import com.sun.javafx.sg.prism.NGAmbientLight;
import com.sun.javafx.sg.prism.NGBox;
import com.sun.javafx.sg.prism.NGCylinder;
import com.sun.javafx.sg.prism.NGMeshView;
import com.sun.javafx.sg.prism.NGParallelCamera;
import com.sun.javafx.sg.prism.NGPerspectiveCamera;
import com.sun.javafx.sg.prism.NGPhongMaterial;
import com.sun.javafx.sg.prism.NGPointLight;
import com.sun.javafx.sg.prism.NGSphere;
import com.sun.javafx.sg.prism.NGSubScene;
import com.sun.javafx.sg.prism.NGTriangleMesh;
import com.sun.javafx.sg.prism.NGExternalNode;
public final class QuantumToolkit extends Toolkit {
public static final boolean verbose =
AccessController.doPrivileged(new PrivilegedAction() {
@Override public Boolean run() {
return Boolean.getBoolean("quantum.verbose");
}
});
public static final boolean pulseDebug =
AccessController.doPrivileged(new PrivilegedAction() {
@Override public Boolean run() {
return Boolean.getBoolean("quantum.pulse");
}
});
public static final boolean multithreaded =
AccessController.doPrivileged(new PrivilegedAction() {
@Override public Boolean run() {
// If it is not specified, or it is true, then it should
// be true. Otherwise it should be false.
String value = System.getProperty("quantum.multithreaded");
value = value == null ? "" : value.trim();
final boolean result = "".equals(value) || Boolean.parseBoolean(value);
if (verbose) {
System.out.println(result ? "Multi-Threading Enabled" : "Multi-Threading Disabled");
}
return result;
}
});
private static boolean debug =
AccessController.doPrivileged(new PrivilegedAction() {
@Override public Boolean run() {
return Boolean.getBoolean("quantum.debug");
}
});
private static Integer pulseHZ =
AccessController.doPrivileged(new PrivilegedAction() {
@Override public Integer run() {
return Integer.getInteger("javafx.animation.pulse");
}
});
static final boolean liveResize =
AccessController.doPrivileged(new PrivilegedAction() {
@Override public Boolean run() {
boolean isSWT = "swt".equals(System.getProperty("glass.platform"));
String result = PlatformUtil.isMac() && !isSWT ? "true" : "false";
return result.equals(System.getProperty("javafx.live.resize", "true"));
}
});
static final boolean drawInPaint =
AccessController.doPrivileged(new PrivilegedAction() {
@Override public Boolean run() {
boolean isSWT = "swt".equals(System.getProperty("glass.platform"));
String result = PlatformUtil.isMac() && isSWT ? "true" : "false";
return result.equals(System.getProperty("javafx.draw.in.paint", "true"));}
});
private static boolean singleThreaded =
AccessController.doPrivileged(new PrivilegedAction() {
@Override public Boolean run() {
Boolean result = Boolean.getBoolean("quantum.singlethreaded");
if (/*verbose &&*/ result) {
System.out.println("Warning: Single GUI Threadiong is enabled, FPS should be slower");
}
return result;
}
});
private static boolean noRenderJobs =
AccessController.doPrivileged(new PrivilegedAction() {
@Override public Boolean run() {
Boolean result = Boolean.getBoolean("quantum.norenderjobs");
if (/*verbose &&*/ result) {
System.out.println("Warning: Quantum will not submit render jobs, nothing should draw");
}
return result;
}
});
private AtomicBoolean toolkitRunning = new AtomicBoolean(false);
private AtomicBoolean animationRunning = new AtomicBoolean(false);
private AtomicBoolean nextPulseRequested = new AtomicBoolean(false);
private AtomicBoolean pulseRunning = new AtomicBoolean(false);
private CountDownLatch launchLatch = new CountDownLatch(1);
final int PULSE_INTERVAL = (int)(TimeUnit.SECONDS.toMillis(1L) / getRefreshRate());
final int FULLSPEED_INTERVAL = 1; // ms
boolean nativeSystemVsync = false;
private float _maxPixelScale;
private Runnable pulseRunnable, userRunnable, timerRunnable;
private Timer pulseTimer = null;
private Thread shutdownHook = null;
private PaintCollector collector;
private QuantumRenderer renderer;
private GraphicsPipeline pipeline;
private ClassLoader ccl;
private HashMap eventLoopMap = null;
private final PerformanceTracker perfTracker = new PerformanceTrackerImpl();
@Override public boolean init() {
/*
* The below no longer applies with for jfx 8.0 on jdk 8.0. But leaving
* the check and comments to avoid breaking jfx running with older
* versions of jdk.
*
* AWT headful trips up glass, and is used in various places throughout
* prism, such as J2DFontFactory and BufferedImageTools, but only
* required AWT in a headless capacity.
*
* AWT headful interferes with glass and is used in various places throughout
* prism, such as J2DFontFactory and BufferedImageTools, but the only
* required AWT is in a headless capacity.
*
* It is assumed that we don't need AWT headful, and if it is needed
* then AWT is already initialized before this property is set. In that
* case the code below is harmless.
*
* Further Consideration and Dependencies:
* - This fix introduces a order dependency in Swing/AWT and FX interop
* mode on Mac. Now Swing/AWT must be initialization before FX.
*
* - On Mac this causes the warning message "Process manager already
* initialized -- can't fully enable headless mode."
*
* - On Windows AWT headful does not cause problems.
*
* - This Mac specific fix should be removed as soon as possible.
* Once RT-12452 has been implemented, then we should be able to do
* just that. Introducing a long term restriction on Mac only, is worse
* then adding universal platform restriction.
*/
if (PlatformUtil.isMac()) {
String version = AccessController.doPrivileged(new PrivilegedAction() {
@Override public String run() {
return System.getProperty("os.version");
}
});
if (version.startsWith("10.4") || version.startsWith("10.5")) {
throw new RuntimeException("JavaFX requires Mac OSX 10.6 or higher to run");
}
String javaVersion = AccessController.doPrivileged(new PrivilegedAction() {
@Override public String run() {
return System.getProperty("java.version");
}
});
// We only support 1.6 and higher no need to check older versions
if (javaVersion.startsWith("1.6") || javaVersion.startsWith("1.7")) {
AccessController.doPrivileged(new PrivilegedAction() {
@Override public Void run() {
System.setProperty("java.awt.headless", "true");
return null;
}
});
}
}
/*
* Glass Mac, X11 need Application.setDeviceDetails to happen prior to Glass Application.Run
*/
renderer = QuantumRenderer.getInstance();
collector = PaintCollector.createInstance(this);
pipeline = GraphicsPipeline.getPipeline();
if (PrismSettings.shutdownHook) {
shutdownHook = new Thread("Glass/Prism Shutdown Hook") {
@Override public void run() {
dispose();
}
};
AccessController.doPrivileged(new PrivilegedAction() {
@Override public Void run() {
Runtime.getRuntime().addShutdownHook(shutdownHook);
return null;
}
});
}
return true;
}
/**
* This method is invoked by PlatformImpl. It is typically called on the main
* thread, NOT the JavaFX Application Thread. The userStartupRunnable will
* be invoked on the JavaFX Application Thread.
*
* @param userStartupRunnable A runnable invoked on the JavaFX Application Thread
* that allows the system to perform some startup
* functionality after the toolkit has been initialized.
*/
@Override public void startup(final Runnable userStartupRunnable) {
// Save the context class loader of the launcher thread
ccl = Thread.currentThread().getContextClassLoader();
try {
this.userRunnable = userStartupRunnable;
Application.run(new Runnable () {
public void run () {
// Ensure that the toolkit can only be started here
runToolkit();
}
});
} catch (RuntimeException ex) {
if (verbose) {
ex.printStackTrace();
}
throw ex;
} catch (Throwable t) {
if (verbose) {
t.printStackTrace();
}
throw new RuntimeException(t);
}
try {
launchLatch.await();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
// restart the toolkit if previously terminated
private void assertToolkitRunning() {
// not implemented
}
// Called by Glass from Application.run()
void runToolkit() {
Thread user = Thread.currentThread();
if (!toolkitRunning.getAndSet(true)) {
user.setName("JavaFX Application Thread");
// Set context class loader to the same as the thread that called startup
user.setContextClassLoader(ccl);
setFxUserThread(user);
/*
* Glass Application instance is now valid - create the ResourceFactory
* on the render thread
*/
renderer.createResourceFactory();
pulseRunnable = new Runnable() {
@Override public void run() {
QuantumToolkit.this.pulse();
}
};
timerRunnable = new Runnable() {
@Override public void run() {
try {
QuantumToolkit.this.postPulse();
} catch (Throwable th) {
th.printStackTrace(System.err);
// } catch (RuntimeException re) {
// ignore spurious Glass timer events while exiting...
}
}
};
pulseTimer = Application.GetApplication().createTimer(timerRunnable);
Application.GetApplication().setEventHandler(new Application.EventHandler() {
@Override public void handleQuitAction(Application app, long time) {
GlassStage.requestClosingAllWindows();
}
});
}
launchLatch.countDown();
try {
Application.invokeAndWait(this.userRunnable);
if (getMasterTimer().isFullspeed()) {
/*
* FULLSPEED_INTVERVAL workaround
*
* Application.invokeLater(pulseRunnable);
*/
pulseTimer.start(FULLSPEED_INTERVAL);
} else {
nativeSystemVsync = Screen.getVideoRefreshPeriod() != 0.0;
if (nativeSystemVsync) {
// system supports vsync
pulseTimer.start();
} else {
// rely on millisecond resolution timer to provide
// nominal pulse sync and use pulse hinting on
// synchronous pipelines to fine tune the interval
pulseTimer.start(PULSE_INTERVAL);
}
}
} catch (Throwable th) {
th.printStackTrace(System.err);
} finally {
if (PrismSettings.verbose) {
System.err.println(" vsync: " + PrismSettings.isVsyncEnabled +
" vpipe: " + pipeline.isVsyncSupported());
}
PerformanceTracker.logEvent("Toolkit.startup - finished");
}
}
boolean hasNativeSystemVsync() {
return nativeSystemVsync;
}
boolean isVsyncEnabled() {
return (PrismSettings.isVsyncEnabled &&
pipeline.isVsyncSupported());
}
@Override public void checkFxUserThread() {
super.checkFxUserThread();
renderer.checkRendererIdle();
}
protected static Thread getFxUserThread() {
return Toolkit.getFxUserThread();
}
@Override public Future addRenderJob(RenderJob r) {
// Do not run any render jobs (this is for benchmarking only)
if (noRenderJobs) {
CompletionListener listener = r.getCompletionListener();
if (r instanceof PaintRenderJob) {
((ViewScene)(((PaintRenderJob)r).getScene())).setPainting(false);
}
if (listener != null) {
try {
listener.done(r);
} catch (Throwable th) {
th.printStackTrace();
}
}
return null;
}
// Run the render job in the UI thread (this is for benchmarking only)
if (singleThreaded) {
r.run();
return null;
}
return (renderer.submitRenderJob(r));
}
void postPulse() {
if (toolkitRunning.get() &&
(animationRunning.get() || nextPulseRequested.get() || collector.hasDirty()) &&
!setPulseRunning()) {
Application.invokeLater(pulseRunnable);
if (debug) {
System.err.println("QT.postPulse@(" + System.nanoTime() + "): " + pulseString());
}
} else if (debug) {
System.err.println("QT.postPulse#(" + System.nanoTime() + ") DROP: " + pulseString());
}
}
private String pulseString() {
return ((toolkitRunning.get() ? "T" : "t") +
(animationRunning.get() ? "A" : "a") +
(pulseRunning.get() ? "P" : "p") +
(nextPulseRequested.get() ? "N" : "n") +
(collector.hasDirty() ? "D" : "d"));
}
private boolean setPulseRunning() {
return (pulseRunning.getAndSet(true));
}
private void endPulseRunning() {
pulseRunning.set(false);
if (debug) {
System.err.println("QT.endPulse: " + System.nanoTime());
}
}
protected void pulse() {
pulse(true);
}
void pulse(boolean collect) {
try {
if (PULSE_LOGGING_ENABLED) {
PULSE_LOGGER.pulseStart();
}
if (!toolkitRunning.get()) {
return;
}
try {
nextPulseRequested.set(false);
if (animationRunnable != null) {
animationRunning.set(true);
animationRunnable.run();
} else {
animationRunning.set(false);
}
firePulse();
if (collect) collector.renderAll();
endPulseRunning();
} catch (Throwable th) {
th.printStackTrace(System.err);
}
} finally {
if (PULSE_LOGGING_ENABLED) {
PULSE_LOGGER.pulseEnd();
}
}
}
void vsyncHint() {
if (isVsyncEnabled()) {
if (debug) {
System.err.println("QT.vsyncHint: postPulse: " + System.nanoTime());
}
postPulse();
}
}
@Override public AppletWindow createAppletWindow(long parent, String serverName) {
GlassAppletWindow parentWindow = new GlassAppletWindow(parent, serverName);
// Make this the parent window for all future Stages
WindowStage.setAppletWindow(parentWindow);
return parentWindow;
}
@Override public void closeAppletWindow() {
GlassAppletWindow gaw = WindowStage.getAppletWindow();
if (null != gaw) {
gaw.dispose();
WindowStage.setAppletWindow(null);
// any further strong refs will be in the applet itself
}
}
@Override public TKStage createTKStage(StageStyle stageStyle,
boolean primary, Modality modality, TKStage owner, boolean rtl) {
assertToolkitRunning();
WindowStage stage = new WindowStage(stageStyle, primary, modality, owner);
stage.setRTL(rtl);
stage.init(systemMenu);
return stage;
}
@Override public Object enterNestedEventLoop(Object key) {
checkFxUserThread();
if (key == null) {
throw new NullPointerException();
}
if (eventLoopMap == null) {
eventLoopMap = new HashMap<>();
}
if (eventLoopMap.containsKey(key)) {
throw new IllegalArgumentException(
"Key already associated with a running event loop: " + key);
}
EventLoop eventLoop = Application.GetApplication().createEventLoop();
eventLoopMap.put(key, eventLoop);
return eventLoop.enter();
}
@Override public void exitNestedEventLoop(Object key, Object rval) {
checkFxUserThread();
if (key == null) {
throw new NullPointerException();
}
if (eventLoopMap == null || !eventLoopMap.containsKey(key)) {
throw new IllegalArgumentException(
"Key not associated with a running event loop: " + key);
}
EventLoop eventLoop = eventLoopMap.get(key);
eventLoopMap.remove(key);
eventLoop.leave(rval);
}
@Override public TKStage createTKPopupStage(StageStyle stageStyle, TKStage owner) {
assertToolkitRunning();
return new PopupStage(owner).init(systemMenu);
}
@Override public TKStage createTKEmbeddedStage(HostInterface host) {
assertToolkitRunning();
return new EmbeddedStage(host);
}
private static ScreenConfigurationAccessor screenAccessor =
new ScreenConfigurationAccessor() {
@Override public int getMinX(Object obj) {
return ((Screen)obj).getX();
}
@Override public int getMinY(Object obj) {
return ((Screen)obj).getY();
}
@Override public int getWidth(Object obj) {
return ((Screen)obj).getWidth();
}
@Override public int getHeight(Object obj) {
return ((Screen)obj).getHeight();
}
@Override public int getVisualMinX(Object obj) {
return ((Screen)obj).getVisibleX();
}
@Override public int getVisualMinY(Object obj) {
return ((Screen)obj).getVisibleY();
}
@Override public int getVisualWidth(Object obj) {
return ((Screen)obj).getVisibleWidth();
}
@Override public int getVisualHeight(Object obj) {
return ((Screen)obj).getVisibleHeight();
}
@Override public float getDPI(Object obj) {
return ((Screen)obj).getResolutionX();
}
};
@Override public ScreenConfigurationAccessor
setScreenConfigurationListener(final TKScreenConfigurationListener listener) {
Screen.setEventHandler(new Screen.EventHandler() {
@Override public void handleSettingsChanged() {
notifyScreenListener(listener);
}
});
return screenAccessor;
}
private static void notifyScreenListener(TKScreenConfigurationListener listener) {
listener.screenConfigurationChanged();
}
@Override public Object getPrimaryScreen() {
return Screen.getMainScreen();
}
@Override public List> getScreens() {
return Screen.getScreens();
}
@Override
public PerformanceTracker getPerformanceTracker() {
return perfTracker;
}
@Override
public PerformanceTracker createPerformanceTracker() {
return new PerformanceTrackerImpl();
}
public float getMaxPixelScale() {
if (_maxPixelScale == 0) {
for (Object o : getScreens()) {
_maxPixelScale = Math.max(_maxPixelScale, ((Screen) o).getScale());
}
}
return _maxPixelScale;
}
@Override public ImageLoader loadImage(String url, int width, int height, boolean preserveRatio, boolean smooth) {
return new PrismImageLoader2(url, width, height, preserveRatio, getMaxPixelScale(), smooth);
}
@Override public ImageLoader loadImage(InputStream stream, int width, int height,
boolean preserveRatio, boolean smooth) {
return new PrismImageLoader2(stream, width, height, preserveRatio, smooth);
}
@Override public AbstractRemoteResource extends ImageLoader> loadImageAsync(
AsyncOperationListener listener, String url,
int width, int height, boolean preserveRatio, boolean smooth) {
return new PrismImageLoader2.AsyncImageLoader(listener, url, width, height, preserveRatio, smooth);
}
@Override public void defer(Runnable runnable) {
if (!toolkitRunning.get()) {
throw new IllegalStateException("Attempt to call defer when toolkit not running");
}
Application.invokeLater(runnable);
}
@Override public void exit() {
notifyShutdownHooks();
pulseTimer.stop();
AbstractPainter.renderLock.lock();
try {
//TODO - should update glass scene view state
//TODO - doesn't matter because we are exiting
Application app = Application.GetApplication();
app.terminate();
} finally {
AbstractPainter.renderLock.unlock();
}
dispose();
super.exit();
}
public void dispose() {
if (toolkitRunning.compareAndSet(true, false)) {
renderer.stopRenderer();
if (PrismSettings.shutdownHook) {
try {
Runtime.getRuntime().removeShutdownHook(shutdownHook);
} catch (IllegalStateException ignore) {
// throw when shutdown hook already removed
}
}
}
}
@Override public boolean isForwardTraversalKey(KeyEvent e) {
return (e.getCode() == KeyCode.TAB)
&& (e.getEventType() == KeyEvent.KEY_PRESSED)
&& !e.isShiftDown();
}
@Override public boolean isBackwardTraversalKey(KeyEvent e) {
return (e.getCode() == KeyCode.TAB)
&& (e.getEventType() == KeyEvent.KEY_PRESSED)
&& e.isShiftDown();
}
private Map contextMap = Collections.synchronizedMap(new HashMap<>());
@Override public Map getContextMap() {
return contextMap;
}
@Override public int getRefreshRate() {
if (pulseHZ == null) {
return 60;
} else {
return pulseHZ;
}
}
private DelayedRunnable animationRunnable;
@Override public void setAnimationRunnable(DelayedRunnable animationRunnable) {
if (animationRunnable != null) {
animationRunning.set(true);
}
this.animationRunnable = animationRunnable;
}
@Override public void requestNextPulse() {
nextPulseRequested.set(true);
}
@Override public void waitFor(Task t) {
if (t.isFinished()) {
return;
}
}
@Override protected Object createColorPaint(Color color) {
return new com.sun.prism.paint.Color(
(float)color.getRed(), (float)color.getGreen(),
(float)color.getBlue(), (float)color.getOpacity());
}
private com.sun.prism.paint.Color toPrismColor(Color color) {
return (com.sun.prism.paint.Color) Toolkit.getPaintAccessor().getPlatformPaint(color);
}
private List convertStops(List paintStops) {
List stops =
new ArrayList<>(paintStops.size());
for (Stop s : paintStops) {
stops.add(new com.sun.prism.paint.Stop(toPrismColor(s.getColor()),
(float) s.getOffset()));
}
return stops;
}
@Override protected Object createLinearGradientPaint(LinearGradient paint) {
int cmi = com.sun.prism.paint.Gradient.REPEAT;
CycleMethod cycleMethod = paint.getCycleMethod();
if (cycleMethod == CycleMethod.NO_CYCLE) {
cmi = com.sun.prism.paint.Gradient.PAD;
} else if (cycleMethod == CycleMethod.REFLECT) {
cmi = com.sun.prism.paint.Gradient.REFLECT;
}
// TODO: extract colors/offsets and pass them in directly...
List stops = convertStops(paint.getStops());
return new com.sun.prism.paint.LinearGradient(
(float)paint.getStartX(), (float)paint.getStartY(), (float)paint.getEndX(), (float)paint.getEndY(),
null, paint.isProportional(), cmi, stops);
}
@Override
protected Object createRadialGradientPaint(RadialGradient paint) {
float cx = (float)paint.getCenterX();
float cy = (float)paint.getCenterY();
float fa = (float)paint.getFocusAngle();
float fd = (float)paint.getFocusDistance();
int cmi = 0;
if (paint.getCycleMethod() == CycleMethod.NO_CYCLE) {
cmi = com.sun.prism.paint.Gradient.PAD;
} else if (paint.getCycleMethod() == CycleMethod.REFLECT) {
cmi = com.sun.prism.paint.Gradient.REFLECT;
} else {
cmi = com.sun.prism.paint.Gradient.REPEAT;
}
// TODO: extract colors/offsets and pass them in directly...
List stops = convertStops(paint.getStops());
return new com.sun.prism.paint.RadialGradient(cx, cy, fa, fd,
(float)paint.getRadius(), null, paint.isProportional(), cmi, stops);
}
@Override
protected Object createImagePatternPaint(ImagePattern paint) {
if (paint.getImage() == null) {
return com.sun.prism.paint.Color.TRANSPARENT;
} else {
return new com.sun.prism.paint.ImagePattern((com.sun.prism.Image) paint.getImage().impl_getPlatformImage(),
(float)paint.getX(),
(float)paint.getY(),
(float)paint.getWidth(),
(float)paint.getHeight(),
paint.isProportional(),
Toolkit.getPaintAccessor().isMutable(paint));
}
}
static BasicStroke tmpStroke = new BasicStroke();
private void initStroke(StrokeType pgtype, double strokewidth,
StrokeLineCap pgcap,
StrokeLineJoin pgjoin, float miterLimit,
float[] dashArray, float dashOffset)
{
int type;
if (pgtype == StrokeType.CENTERED) {
type = BasicStroke.TYPE_CENTERED;
} else if (pgtype == StrokeType.INSIDE) {
type = BasicStroke.TYPE_INNER;
} else {
type = BasicStroke.TYPE_OUTER;
}
int cap;
if (pgcap == StrokeLineCap.BUTT) {
cap = BasicStroke.CAP_BUTT;
} else if (pgcap == StrokeLineCap.SQUARE) {
cap = BasicStroke.CAP_SQUARE;
} else {
cap = BasicStroke.CAP_ROUND;
}
int join;
if (pgjoin == StrokeLineJoin.BEVEL) {
join = BasicStroke.JOIN_BEVEL;
} else if (pgjoin == StrokeLineJoin.MITER) {
join = BasicStroke.JOIN_MITER;
} else {
join = BasicStroke.JOIN_ROUND;
}
tmpStroke.set(type, (float) strokewidth, cap, join, miterLimit);
if ((dashArray != null) && (dashArray.length > 0)) {
tmpStroke.set(dashArray, dashOffset);
} else {
tmpStroke.set((float[])null, 0);
}
}
@Override
public void accumulateStrokeBounds(Shape shape, float bbox[],
StrokeType pgtype,
double strokewidth,
StrokeLineCap pgcap,
StrokeLineJoin pgjoin,
float miterLimit,
BaseTransform tx)
{
initStroke(pgtype, strokewidth, pgcap, pgjoin, miterLimit, null, 0);
if (tx.isTranslateOrIdentity()) {
tmpStroke.accumulateShapeBounds(bbox, shape, tx);
} else {
Shape.accumulate(bbox, tmpStroke.createStrokedShape(shape), tx);
}
}
@Override
public boolean strokeContains(Shape shape, double x, double y,
StrokeType pgtype,
double strokewidth,
StrokeLineCap pgcap,
StrokeLineJoin pgjoin,
float miterLimit)
{
initStroke(pgtype, strokewidth, pgcap, pgjoin, miterLimit, null, 0);
// TODO: The contains testing could be done directly without creating a Shape
return tmpStroke.createStrokedShape(shape).contains((float) x, (float) y);
}
@Override
public Shape createStrokedShape(Shape shape,
StrokeType pgtype,
double strokewidth,
StrokeLineCap pgcap,
StrokeLineJoin pgjoin,
float miterLimit,
float[] dashArray,
float dashOffset) {
initStroke(pgtype, strokewidth, pgcap, pgjoin, miterLimit,
dashArray, dashOffset);
return tmpStroke.createStrokedShape(shape);
}
@Override public Dimension2D getBestCursorSize(int preferredWidth, int preferredHeight) {
return CursorUtils.getBestCursorSize(preferredWidth, preferredHeight);
}
@Override public int getMaximumCursorColors() {
return 2;
}
@Override public int getKeyCodeForChar(String character) {
return (character.length() == 1)
? com.sun.glass.events.KeyEvent.getKeyCodeForChar(
character.charAt(0))
: com.sun.glass.events.KeyEvent.VK_UNDEFINED;
}
@Override public PathElement[] convertShapeToFXPath(Object shape) {
if (shape == null) {
return new PathElement[0];
}
List elements = new ArrayList<>();
// iterate over the shape and turn it into a series of path
// elements
com.sun.javafx.geom.Shape geomShape = (com.sun.javafx.geom.Shape) shape;
PathIterator itr = geomShape.getPathIterator(null);
PathIteratorHelper helper = new PathIteratorHelper(itr);
PathIteratorHelper.Struct struct = new PathIteratorHelper.Struct();
while (!helper.isDone()) {
// true if WIND_EVEN_ODD, false if WIND_NON_ZERO
boolean windEvenOdd = helper.getWindingRule() == PathIterator.WIND_EVEN_ODD;
int type = helper.currentSegment(struct);
PathElement el;
if (type == PathIterator.SEG_MOVETO) {
el = new MoveTo(struct.f0, struct.f1);
} else if (type == PathIterator.SEG_LINETO) {
el = new LineTo(struct.f0, struct.f1);
} else if (type == PathIterator.SEG_QUADTO) {
el = new QuadCurveTo(
struct.f0,
struct.f1,
struct.f2,
struct.f3);
} else if (type == PathIterator.SEG_CUBICTO) {
el = new CubicCurveTo (
struct.f0,
struct.f1,
struct.f2,
struct.f3,
struct.f4,
struct.f5);
} else if (type == PathIterator.SEG_CLOSE) {
el = new ClosePath();
} else {
throw new IllegalStateException("Invalid element type: " + type);
}
helper.next();
elements.add(el);
}
return elements.toArray(new PathElement[elements.size()]);
}
@Override public HitInfo convertHitInfoToFX(Object hit) {
Integer textHitPos = (Integer) hit;
HitInfo hitInfo = new HitInfo();
hitInfo.setCharIndex(textHitPos);
hitInfo.setLeading(true);
return hitInfo;
}
@Override public Filterable toFilterable(Image img) {
return PrImage.create((com.sun.prism.Image) img.impl_getPlatformImage());
}
@Override public FilterContext getFilterContext(Object config) {
if (config == null || (!(config instanceof com.sun.glass.ui.Screen))) {
return PrFilterContext.getDefaultInstance();
}
Screen screen = (Screen)config;
return PrFilterContext.getInstance(screen);
}
@Override public AbstractMasterTimer getMasterTimer() {
return MasterTimer.getInstance();
}
@Override public FontLoader getFontLoader() {
return com.sun.javafx.font.PrismFontLoader.getInstance();
}
@Override public TextLayoutFactory getTextLayoutFactory() {
return com.sun.javafx.text.PrismTextLayoutFactory.getFactory();
}
@Override public PGArc createPGArc() {
return new NGArc();
}
@Override public PGCircle createPGCircle() {
return new NGCircle();
}
@Override public PGCubicCurve createPGCubicCurve() {
return new NGCubicCurve();
}
@Override public PGEllipse createPGEllipse() {
return new NGEllipse();
}
@Override public PGLine createPGLine() {
return new NGLine();
}
@Override public PGPath createPGPath() {
return new NGPath();
}
@Override public PGSVGPath createPGSVGPath() {
return new NGSVGPath();
}
@Override public PGSubScene createPGSubScene() {
return new NGSubScene();
}
@Override public PGPolygon createPGPolygon() {
return new NGPolygon();
}
@Override public PGPolyline createPGPolyline() {
return new NGPolyline();
}
@Override public PGQuadCurve createPGQuadCurve() {
return new NGQuadCurve();
}
@Override public PGRectangle createPGRectangle() {
return new NGRectangle();
}
@Override public PGImageView createPGImageView() {
return new NGImageView();
}
@Override public PGGroup createPGGroup() {
return new NGGroup();
}
@Override public PGRegion createPGRegion() {
return new NGRegion();
}
@Override public PGCanvas createPGCanvas() {
return new NGCanvas();
}
@Override public PGText createPGText() {
return new NGText();
}
@Override public PGExternalNode createPGExternalNode() {
return new NGExternalNode();
}
@Override public Object createSVGPathObject(SVGPath svgpath) {
int windingRule = svgpath.getFillRule() == FillRule.NON_ZERO ? PathIterator.WIND_NON_ZERO : PathIterator.WIND_EVEN_ODD;
Path2D path = new Path2D(windingRule);
path.appendSVGPath(svgpath.getContent());
return path;
}
@Override public Path2D createSVGPath2D(SVGPath svgpath) {
int windingRule = svgpath.getFillRule() == FillRule.NON_ZERO ? PathIterator.WIND_NON_ZERO : PathIterator.WIND_EVEN_ODD;
Path2D path = new Path2D(windingRule);
path.appendSVGPath(svgpath.getContent());
return path;
}
@Override public boolean imageContains(Object image, float x, float y) {
if (image == null) {
return false;
}
com.sun.prism.Image pImage = (com.sun.prism.Image)image;
int intX = (int)x + pImage.getMinX();
int intY = (int)y + pImage.getMinY();
if (pImage.getPixelFormat().isOpaque()) {
return true;
}
if (pImage.getPixelFormat() == PixelFormat.INT_ARGB_PRE) {
IntBuffer ib = (IntBuffer) pImage.getPixelBuffer();
int index = intX + intY * pImage.getRowLength();
if (index >= ib.limit()) {
return false;
} else {
return (ib.get(index) & 0xff000000) != 0;
}
} else if (pImage.getPixelFormat() == PixelFormat.BYTE_BGRA_PRE) {
ByteBuffer bb = (ByteBuffer) pImage.getPixelBuffer();
int index = intX * pImage.getBytesPerPixelUnit() + intY * pImage.getScanlineStride() + 3;
if (index >= bb.limit()) {
return false;
} else {
return (bb.get(index) & 0xff) != 0;
}
} else if (pImage.getPixelFormat() == PixelFormat.BYTE_ALPHA) {
ByteBuffer bb = (ByteBuffer) pImage.getPixelBuffer();
int index = intX * pImage.getBytesPerPixelUnit() + intY * pImage.getScanlineStride();
if (index >= bb.limit()) {
return false;
} else {
return (bb.get(index) & 0xff) != 0;
}
}
return true;
}
@Override
public boolean isSupported(ConditionalFeature feature) {
switch (feature) {
case SCENE3D:
return GraphicsPipeline.getPipeline().is3DSupported();
case EFFECT:
return GraphicsPipeline.getPipeline().isEffectSupported();
case SHAPE_CLIP:
return true;
case INPUT_METHOD:
return false; // TODO: RT-28495, implement input method query
case TRANSPARENT_WINDOW:
return Application.GetApplication().supportsTransparentWindows();
case UNIFIED_WINDOW:
return Application.GetApplication().supportsUnifiedWindows();
case TWO_LEVEL_FOCUS:
return Application.GetApplication().hasTwoLevelFocus();
case VIRTUAL_KEYBOARD:
return Application.GetApplication().hasVirtualKeyboard();
case INPUT_TOUCH:
return Application.GetApplication().hasTouch();
case INPUT_MULTITOUCH:
return Application.GetApplication().hasMultiTouch();
case INPUT_POINTER:
return Application.GetApplication().hasPointer();
default:
return false;
}
}
static TransferMode clipboardActionToTransferMode(final int action) {
switch (action) {
case Clipboard.ACTION_NONE:
return null;
case Clipboard.ACTION_COPY:
//IE drop action for URL copy
case Clipboard.ACTION_COPY | Clipboard.ACTION_REFERENCE:
return TransferMode.COPY;
case Clipboard.ACTION_MOVE:
//IE drop action for URL move
case Clipboard.ACTION_MOVE | Clipboard.ACTION_REFERENCE:
return TransferMode.MOVE;
case Clipboard.ACTION_REFERENCE:
return TransferMode.LINK;
case Clipboard.ACTION_ANY:
return TransferMode.COPY; // select a reasonable trasnfer mode as workaround until RT-22840
}
return null;
}
private QuantumClipboard clipboard;
@Override public TKClipboard getSystemClipboard() {
if (clipboard == null) {
clipboard = QuantumClipboard.getClipboardInstance(new ClipboardAssistance(com.sun.glass.ui.Clipboard.SYSTEM));
}
return clipboard;
}
private GlassSystemMenu systemMenu = new GlassSystemMenu();
@Override public TKSystemMenu getSystemMenu() {
return systemMenu;
}
@Override public TKClipboard getNamedClipboard(String name) {
return null;
}
@Override public void startDrag(TKScene scene, Set tm, TKDragSourceListener l, Dragboard dragboard) {
if (dragboard == null) {
throw new IllegalArgumentException("dragboard should not be null");
}
GlassScene view = (GlassScene)scene;
view.setTKDragSourceListener(l);
QuantumClipboard gc = (QuantumClipboard)dragboard.impl_getPeer();
gc.setSupportedTransferMode(tm);
gc.flush();
// flush causes a modal DnD event loop, when we return, close the clipboard
gc.close();
}
@Override public void enableDrop(TKScene s, TKDropTargetListener l) {
assert s instanceof GlassScene;
GlassScene view = (GlassScene)s;
view.setTKDropTargetListener(l);
}
@Override public void registerDragGestureListener(TKScene s, Set tm, TKDragGestureListener l) {
assert s instanceof GlassScene;
GlassScene view = (GlassScene)s;
view.setTKDragGestureListener(l);
}
@Override
public void installInputMethodRequests(TKScene scene, InputMethodRequests requests) {
assert scene instanceof GlassScene;
GlassScene view = (GlassScene)scene;
view.setInputMethodRequests(requests);
}
// 3D API support for FX 8
@Override
public PGBox createPGBox() {
return new NGBox();
}
@Override
public PGCylinder createPGCylinder() {
return new NGCylinder();
}
@Override
public PGSphere createPGSphere() {
return new NGSphere();
}
@Override
public PGTriangleMesh createPGTriangleMesh() {
return new NGTriangleMesh();
}
@Override
public PGMeshView createPGMeshView() {
return new NGMeshView();
}
@Override
public PGPhongMaterial createPGPhongMaterial() {
return new NGPhongMaterial();
}
@Override
public PGAmbientLight createPGAmbientLight() {
return new NGAmbientLight();
}
@Override
public PGPointLight createPGPointLight() {
return new NGPointLight();
}
@Override
public PGParallelCamera createPGParallelCamera() {
return new NGParallelCamera();
}
@Override
public PGPerspectiveCamera createPGPerspectiveCamera(boolean fixedEyeAtCameraZero) {
return new NGPerspectiveCamera(fixedEyeAtCameraZero);
}
static class QuantumImage implements com.sun.javafx.tk.ImageLoader, ResourceFactoryListener {
// cache rt here
private com.sun.prism.RTTexture rt;
private com.sun.prism.Image image;
private ResourceFactory rf;
QuantumImage(com.sun.prism.Image image) {
this.image = image;
}
RTTexture getRT(int w, int h, ResourceFactory rfNew) {
boolean rttOk = rt != null && rf == rfNew &&
rt.getContentWidth() == w && rt.getContentHeight() == h;
if (rttOk) {
rt.lock();
if (rt.isSurfaceLost()) {
rttOk = false;
}
}
if (!rttOk) {
if (rt != null) {
rt.dispose();
}
if (rf != null) {
rf.removeFactoryListener(this);
rf = null;
}
rt = rfNew.createRTTexture(w, h, WrapMode.CLAMP_TO_ZERO);
if (rt != null) {
rf = rfNew;
rf.addFactoryListener(this);
}
}
return rt;
}
void dispose() {
if (rt != null) {
rt.dispose();
rt = null;
}
}
void setImage(com.sun.prism.Image img) {
image = img;
}
@Override
public Exception getException() {
return (image == null)
? new IllegalStateException("Unitialized image")
: null;
}
@Override
public int getFrameCount() { return 1; }
@Override
public PlatformImage getFrame(int index) { return image; }
@Override
public int getFrameDelay(int index) { return 0; }
@Override
public int getWidth() { return image.getWidth(); }
@Override
public int getHeight() { return image.getHeight(); }
@Override
public void factoryReset() { dispose(); }
@Override
public void factoryReleased() { dispose(); }
}
@Override public ImageLoader loadPlatformImage(Object platformImage) {
if (platformImage instanceof QuantumImage) {
return (QuantumImage)platformImage;
}
if (platformImage instanceof com.sun.prism.Image) {
return new QuantumImage((com.sun.prism.Image) platformImage);
}
throw new UnsupportedOperationException("unsupported class for loadPlatformImage");
}
@Override
public PlatformImage createPlatformImage(int w, int h) {
ByteBuffer bytebuf = ByteBuffer.allocate(w * h * 4);
return com.sun.prism.Image.fromByteBgraPreData(bytebuf, w, h);
}
@Override
public Object renderToImage(ImageRenderingContext p) {
Object saveImage = p.platformImage;
final ImageRenderingContext params = p;
final com.sun.prism.paint.Paint currentPaint = p.platformPaint instanceof com.sun.prism.paint.Paint ?
(com.sun.prism.paint.Paint)p.platformPaint : null;
RenderJob re = new RenderJob(new Runnable() {
private com.sun.prism.paint.Color getClearColor() {
if (currentPaint == null) {
return com.sun.prism.paint.Color.WHITE;
} else if (currentPaint.getType() == com.sun.prism.paint.Paint.Type.COLOR) {
return (com.sun.prism.paint.Color) currentPaint;
} else if (currentPaint.isOpaque()) {
return com.sun.prism.paint.Color.TRANSPARENT;
} else {
return com.sun.prism.paint.Color.WHITE;
}
}
private void draw(Graphics g, int x, int y, int w, int h) {
g.setDepthBuffer(params.depthBuffer);
g.clear(getClearColor());
if (currentPaint != null &&
currentPaint.getType() != com.sun.prism.paint.Paint.Type.COLOR) {
g.getRenderTarget().setOpaque(currentPaint.isOpaque());
g.setPaint(currentPaint);
g.fillQuad(0, 0, w, h);
}
// Set up transform
if (x != 0 || y != 0) {
g.translate(-x, -y);
}
if (params.transform != null) {
g.transform(params.transform);
}
if (params.root != null) {
if (params.camera instanceof PrismCameraImpl) {
g.setCamera((PrismCameraImpl)params.camera);
}
NGNode ngNode = (NGNode)params.root;
ngNode.render(g);
}
}
@Override
public void run() {
ResourceFactory rf = GraphicsPipeline.getDefaultResourceFactory();
if (!rf.isDeviceReady()) {
return;
}
int x = params.x;
int y = params.y;
int w = params.width;
int h = params.height;
if (w <= 0 || h <= 0) {
return;
}
try {
QuantumImage pImage = (params.platformImage instanceof QuantumImage) ?
(QuantumImage)params.platformImage : new QuantumImage(null);
com.sun.prism.RTTexture rt = pImage.getRT(w, h, rf);
if (rt == null) {
return;
}
Graphics g = rt.createGraphics();
draw(g, x, y, w, h);
int[] pixels = pImage.rt.getPixels();
if (pixels != null) {
pImage.setImage(com.sun.prism.Image.fromIntArgbPreData(pixels, w, h));
} else {
IntBuffer ib = IntBuffer.allocate(w*h);
if (pImage.rt.readPixels(ib, pImage.rt.getContentX(),
pImage.rt.getContentY(), w, h))
{
pImage.setImage(com.sun.prism.Image.fromIntArgbPreData(ib, w, h));
} else {
pImage.dispose();
pImage = null;
}
}
rt.unlock();
params.platformImage = pImage;
} catch (Throwable t) {
t.printStackTrace(System.err);
} finally {
Disposer.cleanUp();
}
}
});
final CountDownLatch latch = new CountDownLatch(1);
re.setCompletionListener(new CompletionListener() {
@Override public void done(final RenderJob job) {
latch.countDown();
}
});
addRenderJob(re);
do {
try {
latch.await();
break;
} catch (InterruptedException ex) {
ex.printStackTrace();
}
} while (true);
Object image = params.platformImage;
params.platformImage = saveImage;
return image;
}
@Override
public List showFileChooser(final TKStage ownerWindow,
final String title,
final File initialDirectory,
final String initialFileName,
final FileChooserType fileChooserType,
final List
extensionFilters) {
WindowStage blockedStage = null;
try {
// NOTE: we block the owner of the owner deliberately.
// The native system blocks the nearest owner itself.
// Otherwise sheets on Mac are unusable.
blockedStage = blockOwnerStage(ownerWindow);
FileChooserResult result = CommonDialogs.showFileChooser(
(ownerWindow instanceof WindowStage)
? ((WindowStage) ownerWindow).getPlatformWindow()
: null,
initialDirectory,
initialFileName,
title,
(fileChooserType == FileChooserType.SAVE)
? CommonDialogs.Type.SAVE
: CommonDialogs.Type.OPEN,
(fileChooserType == FileChooserType.OPEN_MULTIPLE),
convertExtensionFilters(extensionFilters),
0);
return result.getFiles();
} finally {
if (blockedStage != null) {
blockedStage.setEnabled(true);
}
}
}
@Override
public File showDirectoryChooser(final TKStage ownerWindow,
final String title,
final File initialDirectory) {
WindowStage blockedStage = null;
try {
// NOTE: we block the owner of the owner deliberately.
// The native system blocks the nearest owner itself.
// Otherwise sheets on Mac are unusable.
blockedStage = blockOwnerStage(ownerWindow);
return CommonDialogs.showFolderChooser(
(ownerWindow instanceof WindowStage)
? ((WindowStage) ownerWindow).getPlatformWindow()
: null,
initialDirectory, title);
} finally {
if (blockedStage != null) {
blockedStage.setEnabled(true);
}
}
}
private WindowStage blockOwnerStage(final TKStage stage) {
if (stage instanceof WindowStage) {
final TKStage ownerStage = ((WindowStage) stage).getOwner();
if (ownerStage instanceof WindowStage) {
final WindowStage ownerWindowStage = (WindowStage) ownerStage;
ownerWindowStage.setEnabled(false);
return ownerWindowStage;
}
}
return null;
}
private static List
convertExtensionFilters(final List
extensionFilters) {
final CommonDialogs.ExtensionFilter[] glassExtensionFilters =
new CommonDialogs.ExtensionFilter[extensionFilters.size()];
int i = 0;
for (final FileChooser.ExtensionFilter extensionFilter:
extensionFilters) {
glassExtensionFilters[i++] =
new CommonDialogs.ExtensionFilter(
extensionFilter.getDescription(),
extensionFilter.getExtensions());
}
return Arrays.asList(glassExtensionFilters);
}
@Override
public long getMultiClickTime() {
return View.getMultiClickTime();
}
@Override
public int getMultiClickMaxX() {
return View.getMultiClickMaxX();
}
@Override
public int getMultiClickMaxY() {
return View.getMultiClickMaxY();
}
}