diff --git a/src/dorkbox/util/Desktop.java b/src/dorkbox/util/Desktop.java index 85bf629..46fbc09 100644 --- a/src/dorkbox/util/Desktop.java +++ b/src/dorkbox/util/Desktop.java @@ -24,10 +24,7 @@ import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; -import com.sun.jna.Pointer; - -import dorkbox.util.jna.linux.Gtk2; -import dorkbox.util.jna.linux.Gtk3; +import dorkbox.util.jna.linux.GnomeVFS; import dorkbox.util.jna.linux.GtkCheck; import dorkbox.util.jna.linux.GtkEventDispatch; import dorkbox.util.process.ShellExecutor; @@ -75,31 +72,8 @@ class Desktop { // Prevent GTK2/3 conflict caused by Desktop.getDesktop(), which is GTK2 only (via AWT) // Prefer JNA method over AWT, since there are fewer chances for JNA to fail (even though they call the same method) - // Additionally, xdg-open can cause problems in Linux with Chrome installed but not the default browser. It will crash Chrome - // if Chrome was open before this app opened a URL if ((OS.isUnix() || OS.isLinux()) && GtkCheck.isGtkLoaded) { - // there are problems with ubuntu and practically everything. Errors galore, and sometimes things don't even work. - // see: https://bugzilla.mozilla.org/show_bug.cgi?id=672671 - if (OSUtil.DesktopEnv.isUnity() && OSUtil.Linux.isUbuntu()) { - // use xdg-open, because it launches in a new shell and suppresses these errors/warnings. - // it can be really buggy though, so we only use it for ubuntu... - ShellExecutor.run("xdg-open", uri.toString()); - } - else { - GtkEventDispatch.dispatch(new Runnable() { - @Override - public - void run() { - if (GtkCheck.gtkIsGreaterOrEqual(3, 22, 0)) { - Pointer pointer = Gtk2.Gtk2.gdk_display_get_default(); - Gtk3.Gtk3.gtk_show_uri_on_window(pointer, uri.toString(), 0, null); - } - else { - Gtk2.Gtk2.gtk_show_uri(Gtk2.Gtk2.gdk_screen_get_default(), uri.toString(), 0, null); - } - } - }); - } + launch(uri.toString()); } else if (java.awt.Desktop.isDesktopSupported() && java.awt.Desktop.getDesktop() .isSupported(java.awt.Desktop.Action.BROWSE)) { @@ -151,20 +125,9 @@ class Desktop { } // Prevent GTK2/3 conflict caused by Desktop.getDesktop(), which is GTK2 only (via AWT) + // Prefer JNA method over AWT, since there are fewer chances for JNA to fail (even though they call the same method) if ((OS.isUnix() || OS.isLinux()) && GtkCheck.isGtkLoaded) { - GtkEventDispatch.dispatch(new Runnable() { - @Override - public - void run() { - if (GtkCheck.gtkIsGreaterOrEqual(3, 22, 0)) { - Pointer pointer = Gtk2.Gtk2.gdk_display_get_default(); - Gtk3.Gtk3.gtk_show_uri_on_window(pointer, uri.toString(), 0, null); - } - else { - Gtk2.Gtk2.gtk_show_uri(Gtk2.Gtk2.gdk_screen_get_default(), uri.toString(), 0, null); - } - } - }); + launch(uri.toString()); } else if (java.awt.Desktop.isDesktopSupported() && java.awt.Desktop.getDesktop() .isSupported(java.awt.Desktop.Action.MAIL)) { @@ -212,29 +175,7 @@ class Desktop { path = "file://" + path; } - final String finalPath = path; - // there are problems with ubuntu and practically everything. Errors galore, and sometimes things don't even work. - // see: https://askubuntu.com/questions/788182/nautilus-not-opening-up-showing-glib-error - if (OSUtil.DesktopEnv.isUnity() && OSUtil.Linux.isUbuntu()) { - // use xdg-open, because it launches in a new shell and suppresses these errors/warnings. - // it can be really buggy though, so we only use it for ubuntu... - ShellExecutor.runShell("xdg-open", finalPath); - } - else { - GtkEventDispatch.dispatch(new Runnable() { - @Override - public - void run() { - if (GtkCheck.gtkIsGreaterOrEqual(3, 22, 0)) { - Pointer pointer = Gtk2.Gtk2.gdk_display_get_default(); - Gtk3.Gtk3.gtk_show_uri_on_window(pointer, finalPath, 0, null); - } - else { - Gtk2.Gtk2.gtk_show_uri(Gtk2.Gtk2.gdk_screen_get_default(), finalPath, 0, null); - } - } - }); - } + launch(path); } else if (java.awt.Desktop.isDesktopSupported() && java.awt.Desktop.getDesktop() .isSupported(java.awt.Desktop.Action.OPEN)) { @@ -245,4 +186,40 @@ class Desktop { throw new IOException("Current OS and desktop configuration does not support opening a directory to browse"); } } + + /** + * Only called when (OS.isUnix() || OS.isLinux()) && GtkCheck.isGtkLoaded + * + * Of important note, xdg-open can cause problems in Linux with Chrome installed but not the default browser. It will crash Chrome + * if Chrome was open before this app opened a URL + * + * @param path the path to open + */ + private static + void launch(final String path) { + if ((OSUtil.Linux.isUbuntu() || OSUtil.DesktopEnv.isGnome()) && GnomeVFS.isInited) { + GtkEventDispatch.dispatch(new Runnable() { + @Override + public + void run() { + // try to open the URL via gnome. This is exactly how (ultimately) java natively does this, but we do it via our own + // loaded version of GTK via JNA + int errorCode = GnomeVFS.gnome_vfs_url_show_with_env(path, null); + if (errorCode != 0) { + // if there are problems, use xdg-open + // + // there are problems with ubuntu and practically everything. Errors galore, and sometimes things don't even work. + // see: https://bugzilla.mozilla.org/show_bug.cgi?id=672671 + // this can be really buggy ... you have been warned + ShellExecutor.run("xdg-open", path); + } + } + }); + } + else { + // just use xdg-open, since it's not gnome. + // this can be really buggy ... you have been warned + ShellExecutor.run("xdg-open", path); + } + } } diff --git a/src/dorkbox/util/jna/linux/GnomeVFS.java b/src/dorkbox/util/jna/linux/GnomeVFS.java new file mode 100644 index 0000000..7b18a2d --- /dev/null +++ b/src/dorkbox/util/jna/linux/GnomeVFS.java @@ -0,0 +1,82 @@ +/* + * Copyright 2017 dorkbox, llc + * + * 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.jna.linux; + +import org.slf4j.LoggerFactory; + +import com.sun.jna.NativeLibrary; +import com.sun.jna.Pointer; + +import dorkbox.util.jna.JnaHelper; + +/** + * bindings for gnome + *

+ * Direct-mapping, See: https://github.com/java-native-access/jna/blob/master/www/DirectMapping.md + *

+ * https://github.com/GNOME/libgnome/blob/master/libgnome/gnome-url.c + * + * NOTE: This is used to open URL/file/email/etc from java. In different places, they recommend using gtk_show_uri() -- we support that, + * NOTE: HOWEVER there are problems where GTK warnings/errors will STILL SHOW on the console for whatever target application is opened, + * NOTE: and because of these errors, it looks like crap. gnome_vfs_url_show_with_env() solves this problem. + */ +public +class GnomeVFS { + public final static boolean isInited; + + static { + boolean init = false; + try { + NativeLibrary library = JnaHelper.register("libgnomevfs-2", GnomeVFS.class); + if (library == null) { + // try with no version + library = JnaHelper.register("libgnomevfs", GnomeVFS.class); + } + if (library == null) { + // try v3 (maybe this happened? Not likely, but who knows) + library = JnaHelper.register("libgnomevfs-3", GnomeVFS.class); + } + + if (library == null) { + // not loading :/ + LoggerFactory.getLogger(GnomeVFS.class).error("Error loading GnomeVFS library, it failed to load."); + } else { + // must call call gnome_vfs_init() + GnomeVFS.gnome_vfs_init(); + init = true; + } + } catch (Throwable e) { + LoggerFactory.getLogger(GnomeVFS.class).error("Error loading GnomeVFS library, it failed to load {}", e.getMessage()); + } + + isInited = init; + } + + public static native + void gnome_vfs_init(); + + /** + * Open a URL or path to display using the default/registered handlers. + * + * @param url The url or path to display. The path can be relative to the current working + * directory or the user's home directory. This function will convert it into a fully + * qualified url using the gnome_url_get_from_input function. + * + * @return 0 if successful, non-0 if there were issues. + */ + public static native + int gnome_vfs_url_show_with_env(String url, Pointer shouldbeNull); +}