Added Desktop Utility functions, similar to java.awt.Desktop with cases
built-in for Linux/Unix when GTK3 is loaded (and thus, java.awt.Desktop is not supported). Code derivative from QZTray, which was released exclusively as Apache 2.0 for this purpose.
This commit is contained in:
parent
e588ed19c1
commit
2ca0b14164
146
src/dorkbox/util/Desktop.java
Normal file
146
src/dorkbox/util/Desktop.java
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 dorkbox, llc
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 Tres Finocchiaro, QZ Industries, LLC
|
||||||
|
* Derivative code has been released as Apache 2.0, used with permission.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package dorkbox.util;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
|
||||||
|
import dorkbox.util.process.ShellExecutor;
|
||||||
|
|
||||||
|
@SuppressWarnings("WeakerAccess")
|
||||||
|
public
|
||||||
|
class Desktop {
|
||||||
|
/**
|
||||||
|
* Launches the default browser to display a {@code URI}.
|
||||||
|
*
|
||||||
|
* If the default browser is not able to handle the specified {@code URI}, the application registered for handling
|
||||||
|
* {@code URIs} of the specified type is invoked. The application is determined from the protocol and path of the {@code URI}, as
|
||||||
|
* defined by the {@code URI} class.
|
||||||
|
*
|
||||||
|
* @param uri the URL to browse/open
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static void browseURL(URI uri) throws IOException {
|
||||||
|
// Prevent GTK2/3 conflict caused by Desktop.getDesktop(), which is GTK2 only (via AWT)
|
||||||
|
if ((OS.isUnix() || OS.isLinux()) && OSUtil.DesktopEnv.isGtkLoaded && OSUtil.DesktopEnv.isGtk3) {
|
||||||
|
if (!ShellExecutor.run("xdg-open", uri.toString())) {
|
||||||
|
throw new IOException("Error running xdg-open for " + uri.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (java.awt.Desktop.isDesktopSupported() && java.awt.Desktop.getDesktop().isSupported(java.awt.Desktop.Action.BROWSE)) {
|
||||||
|
java.awt.Desktop.getDesktop().browse(uri);
|
||||||
|
} else {
|
||||||
|
throw new IOException("Current OS and desktop configuration does not support browsing for a URL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Launches the mail composing window of the user default mail client for the specified address.
|
||||||
|
*
|
||||||
|
* @param address who the email goes to
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static void launchEmail(String address) throws IOException {
|
||||||
|
URI uri = null;
|
||||||
|
try {
|
||||||
|
uri = new URI(address);
|
||||||
|
launchEmail(uri);
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
throw new IOException("Invalid URI " + address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Launches the mail composing window of the user default mail client, filling the message fields specified by a {@code mailto:} URI.
|
||||||
|
* <p>
|
||||||
|
* A <code>mailto:</code> URI can specify message fields including <i>"to"</i>, <i>"cc"</i>, <i>"subject"</i>, <i>"body"</i>, etc.
|
||||||
|
* See <a href="http://www.ietf.org/rfc/rfc2368.txt">The mailto URL scheme (RFC 2368)</a> for the {@code mailto:} URI specification
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* @param uri the specified {@code mailto:} URI
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static void launchEmail(final URI uri) throws IOException {
|
||||||
|
// Prevent GTK2/3 conflict caused by Desktop.getDesktop(), which is GTK2 only (via AWT)
|
||||||
|
if ((OS.isUnix() || OS.isLinux()) && OSUtil.DesktopEnv.isGtkLoaded && OSUtil.DesktopEnv.isGtk3) {
|
||||||
|
if (!ShellExecutor.run("xdg-email", uri.toString())) {
|
||||||
|
throw new IOException("Error running xdg-email for " + uri.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (java.awt.Desktop.isDesktopSupported() && java.awt.Desktop.getDesktop().isSupported(java.awt.Desktop.Action.MAIL)) {
|
||||||
|
java.awt.Desktop.getDesktop().mail(uri);
|
||||||
|
} else {
|
||||||
|
throw new IOException("Current OS and desktop configuration does not support launching an email client");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the specified path in the system-default file browser.
|
||||||
|
*
|
||||||
|
* Works around several OS limitations:
|
||||||
|
* - Apple tries to launch <code>.app</code> bundle directories as applications rather than browsing contents
|
||||||
|
* - Linux has mixed support for <code>Desktop.getDesktop()</code>. Uses the <code>xdg-open</code> fallback.
|
||||||
|
*
|
||||||
|
* @param path The directory to browse
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static void browseDirectory(String path) throws IOException {
|
||||||
|
if (OS.isMacOsX()) {
|
||||||
|
File directory = new File(path);
|
||||||
|
|
||||||
|
// Mac tries to open the .app rather than browsing it. Instead, pass a child with -R to select it in finder
|
||||||
|
File[] files = directory.listFiles();
|
||||||
|
if (files != null && files.length > 0) {
|
||||||
|
// Get first child
|
||||||
|
File child = files[0];
|
||||||
|
if (!ShellExecutor.run("open", "-R", child.getCanonicalPath())) {
|
||||||
|
throw new IOException("Error opening the directory for " + path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Prevent GTK2/3 conflict caused by Desktop.getDesktop(), which is GTK2 only (via AWT)
|
||||||
|
if ((OS.isUnix() || OS.isLinux()) && OSUtil.DesktopEnv.isGtkLoaded && OSUtil.DesktopEnv.isGtk3) {
|
||||||
|
if (!ShellExecutor.run("xdg-open", path)) {
|
||||||
|
throw new IOException("Error running xdg-open for " + path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (java.awt.Desktop.isDesktopSupported() && java.awt.Desktop.getDesktop().isSupported(java.awt.Desktop.Action.OPEN)) {
|
||||||
|
java.awt.Desktop.getDesktop().open(new File(path));
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
throw new IOException("Current OS and desktop configuration does not support opening a directory to browse");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IOException("Unable to open " + path);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,123 +0,0 @@
|
||||||
package dorkbox.util;
|
|
||||||
|
|
||||||
import java.awt.Component;
|
|
||||||
import java.awt.Desktop;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class defines a mix of useful methods for different frameworks such as JavaFX or SWT. Swing, being that it is builtin, and always
|
|
||||||
* available to the JRE (JavaFX can be excluded...) is in it's own class ({@link Swing}).
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
class Framework {
|
|
||||||
|
|
||||||
public final static boolean isJavaFxLoaded;
|
|
||||||
public final static boolean isJavaFxGtk3;
|
|
||||||
|
|
||||||
public final static boolean isSwtLoaded;
|
|
||||||
public final static boolean isSwtGtk3;
|
|
||||||
|
|
||||||
|
|
||||||
static {
|
|
||||||
boolean isJavaFxLoaded_ = false;
|
|
||||||
boolean isJavaFxGtk3_ = false;
|
|
||||||
|
|
||||||
boolean isSwtLoaded_ = false;
|
|
||||||
boolean isSwtGtk3_ = false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// this is important to use reflection, because if JavaFX is not being used, calling getToolkit() will initialize it...
|
|
||||||
java.lang.reflect.Method m = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
|
|
||||||
m.setAccessible(true);
|
|
||||||
ClassLoader cl = ClassLoader.getSystemClassLoader();
|
|
||||||
|
|
||||||
// JavaFX Java7,8 is GTK2 only. Java9 can have it be GTK3 if -Djdk.gtk.version=3 is specified
|
|
||||||
// see http://mail.openjdk.java.net/pipermail/openjfx-dev/2016-May/019100.html
|
|
||||||
isJavaFxLoaded_ = (null != m.invoke(cl, "com.sun.javafx.tk.Toolkit")) || (null != m.invoke(cl, "javafx.application.Application"));
|
|
||||||
|
|
||||||
if (isJavaFxLoaded_) {
|
|
||||||
// JavaFX Java7,8 is GTK2 only. Java9 can MAYBE have it be GTK3 if `-Djdk.gtk.version=3` is specified
|
|
||||||
// see
|
|
||||||
// http://mail.openjdk.java.net/pipermail/openjfx-dev/2016-May/019100.html
|
|
||||||
// https://docs.oracle.com/javafx/2/system_requirements_2-2-3/jfxpub-system_requirements_2-2-3.htm
|
|
||||||
// from the page: JavaFX 2.2.3 for Linux requires gtk2 2.18+.
|
|
||||||
|
|
||||||
isJavaFxGtk3_ = OS.javaVersion >= 9 && System.getProperty("jdk.gtk.version", "2").equals("3");
|
|
||||||
}
|
|
||||||
|
|
||||||
// maybe we should load the SWT version? (In order for us to work with SWT, BOTH must be the same!!
|
|
||||||
// SWT is GTK2, but if -DSWT_GTK3=1 is specified, it can be GTK3
|
|
||||||
isSwtLoaded_ = null != m.invoke(cl, "org.eclipse.swt.widgets.Display");
|
|
||||||
|
|
||||||
if (isSwtLoaded_) {
|
|
||||||
// Necessary for us to work with SWT based on version info. We can try to set us to be compatible with whatever it is set to
|
|
||||||
// System.setProperty("SWT_GTK3", "0"); (or -DSWT_GTK3=1)
|
|
||||||
|
|
||||||
// was SWT forced?
|
|
||||||
String swt_gtk3 = System.getProperty("SWT_GTK3");
|
|
||||||
isSwtGtk3_ = swt_gtk3 != null && !swt_gtk3.equals("0");
|
|
||||||
if (!isSwtGtk3_) {
|
|
||||||
// check a different property
|
|
||||||
String property = System.getProperty("org.eclipse.swt.internal.gtk.version");
|
|
||||||
isSwtGtk3_ = property != null && !property.startsWith("2.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
LoggerFactory.getLogger(Framework.class).debug("Error detecting if JavaFX/SWT is loaded", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
isJavaFxLoaded = isJavaFxLoaded_;
|
|
||||||
isJavaFxGtk3 = isJavaFxGtk3_;
|
|
||||||
|
|
||||||
isSwtLoaded = isSwtLoaded_;
|
|
||||||
isSwtGtk3 = isSwtGtk3_;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static
|
|
||||||
void initDispatch() {
|
|
||||||
if (Framework.isJavaFxLoaded) {
|
|
||||||
// This will initialize javaFX dispatch methods
|
|
||||||
JavaFX.init();
|
|
||||||
}
|
|
||||||
else if (Framework.isSwtLoaded) {
|
|
||||||
// This will initialize swt dispatch methods
|
|
||||||
SwtBytecodeOverride.init(); // necessary to properly fix methods in {@link Swt}
|
|
||||||
dorkbox.util.Swt.init();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens the given website in the default browser, or show a message saying that no default browser could be accessed.
|
|
||||||
*
|
|
||||||
* @param parent The parent of the error message, if raised
|
|
||||||
* @param uri The website uri
|
|
||||||
*/
|
|
||||||
public static
|
|
||||||
void browse(final Component parent, final String uri) {
|
|
||||||
boolean cannotBrowse = false;
|
|
||||||
if (Desktop.isDesktopSupported() && Desktop.getDesktop()
|
|
||||||
.isSupported(Desktop.Action.BROWSE)) {
|
|
||||||
try {
|
|
||||||
Desktop.getDesktop()
|
|
||||||
.browse(new URI(uri));
|
|
||||||
} catch (URISyntaxException ignored) {
|
|
||||||
} catch (IOException ex) {
|
|
||||||
cannotBrowse = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
cannotBrowse = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cannotBrowse) {
|
|
||||||
JOptionPane.showMessageDialog(parent, "It seems that I can't open a website using your default browser, sorry.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user