Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

util.Desktop lacks cross-platform open file in default editor action #94

Closed
stanimirivanovde opened this issue Oct 8, 2018 · 12 comments
Milestone

Comments

@stanimirivanovde
Copy link

I need to open a file in the default editor for the user (a log file), but the dorkbox.util.Desktop abstraction doesn't support open, just browseURL() and browseDirectory(). browseURL() fails to open the file on Mac OS X but it works fine on Ubuntu. It fails on Mac OS X with the following message:

java.io.IOException: Failed to mail or browse /Users/zzz/a.log. Error code: -10814
	at sun.lwawt.macosx.CDesktopPeer.lsOpen(CDesktopPeer.java:72)
	at sun.lwawt.macosx.CDesktopPeer.browse(CDesktopPeer.java:65)
	at java.awt.Desktop.browse(Desktop.java:385)
	at dorkbox.util.Desktop$1.run(Desktop.java:91)
	at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
	at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
	at java.awt.EventQueue.access$500(EventQueue.java:97)
	at java.awt.EventQueue$3.run(EventQueue.java:709)
	at java.awt.EventQueue$3.run(EventQueue.java:703)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)

Prior to this I used Java's AWT Desktop instance and it has an open function: Desktop.getDesktop().open(logFile) which works well on Mac OS X and Windows 7 and 10. Actually the reason I use dorkbox's SystemTray is so I can have a system tray on Ubuntu.

But if I keep the AWT Desktop instance the whole application crashes on Ubuntu with the following message:

(java:29388): Gtk-ERROR **: 13:49:26.980: GTK+ 2.x symbols detected. Using GTK+ 2.x and GTK+ 3 in the same process is not supported

Apparently the AWT and the dorkbox SystemTray need different GTK versions.

I need a cross-platform way to open a file similar to what you have with Desktop.browseURL() and Desktop.browseDirectory().

@stanimirivanovde
Copy link
Author

I can confirm that I have a similar problem on Windows 10 when trying to open the log file. Also the Windows 10 menu looks worse from the one provided by AWT. May be switching to that would be better? Or at least having the option to prefer one or the other?

@stanimirivanovde
Copy link
Author

I tried playing around with FORCE_GTK2 and the TrayType options but nothing really did what I wanted. Here is my workaround which seems to do the job:

if( SystemUtils.IS_OS_LINUX ) {
	Desktop.browseURL( LOG_FILE_PATH );
} else {
	// Windows and Mac OS X
	java.awt.Desktop.getDesktop().open( new File( LOG_FILE_PATH ) );
}

@dorkbox
Copy link
Owner

dorkbox commented Oct 8, 2018

You're using an out of date version.

The project has moved (hence the note in the read me), can you try the latest?

The project development, source code, and issues have moved to https://git.dorkbox.com/dorkbox/SystemTray

@stanimirivanovde
Copy link
Author

@dorkbox, I am using 3.16. Sorry I opened this issue in the old project, but I am using the latest release. In build.gradle I have this line: compile 'com.dorkbox:SystemTray:+' which resolves to 3.16.

@dorkbox
Copy link
Owner

dorkbox commented Oct 8, 2018

:) Ah, ok!

I'll see what's going on, and add what you've got since these sorts of checks is 99% of what my stuff does.... :/

@stanimirivanovde
Copy link
Author

May be you'll need to add a third option Desktop.openFile() that would open the file in the default editor/viewer. Basically I would go with mimicking the functionality of the Java AWT Desktop class.

@tresf
Copy link

tresf commented Oct 8, 2018

I can't speak on behalf of the Gtk conflicts, but for browsing a directory:

    private static final String OS_NAME = System.getProperty("os.name").toLowerCase();
    /**
     * 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>.  Adds <code>xdg-open</code> fallback.
     * @param path The directory to browse
     * @throws IOException
     */
    public static void browseDirectory(String path) throws IOException {
        File directory = new File(path);
        if (isMac() && path.endsWith(".app")) {
            // 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.length > 0) {
                // Get first child
                File child = directory.listFiles()[0];
                if (execute(new String[] {"open", "-R", child.getCanonicalPath()})) {
                    return;
                }
            }
        } else {
            try {
                // The default, java recommended usage
                Desktop d = Desktop.getDesktop();
                d.open(directory);
                return;
            } catch (IOException io) {
                if (isLinux()) {
                    // Fallback on xdg-open for Linux
                    if (execute(new String[] {"xdg-open", path})) {
                        return;
                    }
                }
                throw io;
            }
        }
        throw new IOException("Unable to open " + path);
    }

    /**
     * Executes a synchronous shell command and returns true if the {@code Process.exitValue()} is {@code 0}.
     *
     * @param commandArray array of command pieces to supply to the shell environment to e executed as a single command
     * @return {@code true} if {@code Process.exitValue()} is {@code 0}, otherwise {@code false}.
     */
    public static boolean execute(String[] commandArray) {
        log.debug("Executing: {}", Arrays.toString(commandArray));
        try {
            // Create and execute our new process
            Process p = Runtime.getRuntime().exec(commandArray, envp);
            p.waitFor();
            return p.exitValue() == 0;
        }
        catch(InterruptedException ex) {
            log.warn("InterruptedException waiting for a return value: {} envp: {}", Arrays.toString(commandArray), Arrays.toString(envp), ex);
        }
        catch(IOException ex) {
            log.error("IOException executing: {} envp: {}", Arrays.toString(commandArray), Arrays.toString(envp), ex);
        }

        return false;
    }

    /**
     * Determine if the current Operating System is Linux
     *
     * @return {@code true} if Linux, {@code false} otherwise
     */
    public static boolean isLinux() {
        return (OS_NAME.contains("linux"));
    }

    /**
     * Determine if the current Operating System is Mac OS
     *
     * @return {@code true} if Mac OS, {@code false} otherwise
     */
    public static boolean isMac() {
        return (OS_NAME.contains("mac"));
    }

Opening a file on Mac should be a very similar call to the one above. open is a good shell command to perform this operation and should do so without any native library conflicts.

@stanimirivanovde on a side note, we're considering abandoning Dorkbox because of Linux's completely abandonment of the system tray (#71). We too have Mac and Windows working fine without this library. We're going to try using Steam's technique instead (which has serious limitations, but if successful, we'll just adapt our interface instead).

@stanimirivanovde
Copy link
Author

@tresf, thanks for the note. I actually like how the dorkbox.SystemTray looks on Mac OS X. It has the shortcut keys next to the menu items like a native app. But the Windows 10 version is very Java looking so I switched that to the Java AWT SystemTray and now it looks native. I'll keep this for Ubuntu and Mac OS X for now and try to work around the limitations. I didn't know Ubuntu is pushing away from the SystemTray functionality. It is such a standard thing that I expect it to be there for most OS GUIs.

@stanimirivanovde
Copy link
Author

@dorkbox, thanks for looking into this issue. I hope this is helpful for improving the library.

@tresf
Copy link

tresf commented Oct 9, 2018

I actually like how the dorkbox.SystemTray looks on Mac OS X. It has the shortcut keys next to the menu items like a native app

That's AWT as well, no? That's how I've been doing it in my app at least. Looks great on Mac.

@stanimirivanovde
Copy link
Author

@tresf, you're right. I just tested it and shortcuts work well with AWT on Mac OS X. I didn't pay attention to java.awt.MenuShortcut. Thanks for the tip.

@dorkbox dorkbox added this to the Release 3.17 milestone Oct 23, 2018
@dorkbox
Copy link
Owner

dorkbox commented Nov 3, 2018

Version 3.17 is now released, and have fixed this. Additionally, there is support now for Ubuntu 17.10, 18.04, Fedora 27, 28, 29, and Debian 9.5 (+ all DE's possible from it's installer, so Gnome3, KDE, Xfce, LXDE, and MATE).

@dorkbox dorkbox closed this as completed Nov 3, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants