/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* Part of the Processing project - http://processing.org Copyright (c) 2012-15 The Processing Foundation Copyright (c) 2008-12 Ben Fry and Casey Reas This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package processing.app; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; import java.util.HashMap; import java.util.Map; import com.sun.jna.platform.FileUtils; import processing.app.platform.DefaultPlatform; import processing.core.PApplet; import processing.core.PConstants; public class Platform { static DefaultPlatform inst; static Map<Integer, String> platformNames = new HashMap<Integer, String>(); static { platformNames.put(PConstants.WINDOWS, "windows"); //$NON-NLS-1$ platformNames.put(PConstants.MACOSX, "macosx"); //$NON-NLS-1$ platformNames.put(PConstants.LINUX, "linux"); //$NON-NLS-1$ } static Map<String, Integer> platformIndices = new HashMap<String, Integer>(); static { platformIndices.put("windows", PConstants.WINDOWS); //$NON-NLS-1$ platformIndices.put("macosx", PConstants.MACOSX); //$NON-NLS-1$ platformIndices.put("linux", PConstants.LINUX); //$NON-NLS-1$ } /** How many bits this machine is */ static int nativeBits; static { nativeBits = 32; // perhaps start with 32 String bits = System.getProperty("sun.arch.data.model"); //$NON-NLS-1$ if (bits != null) { if (bits.equals("64")) { //$NON-NLS-1$ nativeBits = 64; } } else { // if some other strange vm, maybe try this instead if (System.getProperty("java.vm.name").contains("64")) { //$NON-NLS-1$ //$NON-NLS-2$ nativeBits = 64; } } } // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . static public void init() { try { Class<?> platformClass = Class.forName("processing.app.Platform"); //$NON-NLS-1$ if (Platform.isMacOS()) { platformClass = Class.forName("processing.app.platform.MacPlatform"); //$NON-NLS-1$ } else if (Platform.isWindows()) { platformClass = Class.forName("processing.app.platform.WindowsPlatform"); //$NON-NLS-1$ } else if (Platform.isLinux()) { platformClass = Class.forName("processing.app.platform.LinuxPlatform"); //$NON-NLS-1$ } inst = (DefaultPlatform) platformClass.newInstance(); } catch (Exception e) { Messages.showError("Problem Setting the Platform", "An unknown error occurred while trying to load\n" + "platform-specific code for your machine.", e); } } static public void initBase(Base base) throws Exception { inst.initBase(base); } static public void setLookAndFeel() throws Exception { inst.setLookAndFeel(); } static public File getSettingsFolder() throws Exception { return inst.getSettingsFolder(); } static public File getDefaultSketchbookFolder() throws Exception { return inst.getDefaultSketchbookFolder(); } static public void saveLanguage(String languageCode) { inst.saveLanguage(languageCode); } // static public void openURL(String url) throws Exception { // inst.openURL(url); // } // // // public boolean openFolderAvailable() { // return inst.openFolderAvailable(); // } // // // public void openFolder(File file) throws Exception { // inst.openFolder(file); // } /** * Implements the cross-platform headache of opening URLs. * * For 2.0a8 and later, this requires the parameter to be an actual URL, * meaning that you can't send it a file:// path without a prefix. It also * just calls into Platform, which now uses java.awt.Desktop (where * possible, meaning not on Linux) now that we're requiring Java 6. * As it happens the URL must also be properly URL-encoded. */ static public void openURL(String url) { try { inst.openURL(url); } catch (Exception e) { Messages.showWarning("Problem Opening URL", "Could not open the URL\n" + url, e); } } /** * Used to determine whether to disable the "Show Sketch Folder" option. * @return true If a means of opening a folder is known to be available. */ static public boolean openFolderAvailable() { return inst.openFolderAvailable(); } /** * Implements the other cross-platform headache of opening * a folder in the machine's native file browser. */ static public void openFolder(File file) { try { inst.openFolder(file); } catch (Exception e) { Messages.showWarning("Problem Opening Folder", "Could not open the folder\n" + file.getAbsolutePath(), e); } } // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . /** * Return whether sketches will run as 32- or 64-bits based * on the JVM that's in use. */ static public int getNativeBits() { return nativeBits; } /** * Return the value of the os.arch property */ static public String getNativeArch() { // This will return "arm" for 32-bit ARM, "aarch64" for 64-bit ARM (both on Linux) return System.getProperty("os.arch"); } /* * Return a string that identifies the variant of a platform * e.g. "32" or "64" on Intel */ static public String getVariant() { return getVariant(PApplet.platform, getNativeArch(), getNativeBits()); } static public String getVariant(int platform, String arch, int bits) { if (platform == PConstants.LINUX && bits == 32 && "arm".equals(Platform.getNativeArch())) { return "armv6hf"; // assume armv6hf } else if (platform == PConstants.LINUX && bits == 64 && "aarch64".equals(Platform.getNativeArch())) { return "arm64"; } return Integer.toString(bits); // 32 or 64 } static public String getName() { return PConstants.platformNames[PApplet.platform]; } /** * Map a platform constant to its name. * @param which PConstants.WINDOWS, PConstants.MACOSX, PConstants.LINUX * @return one of "windows", "macosx", or "linux" */ static public String getName(int which) { return platformNames.get(which); } static public int getIndex(String what) { Integer entry = platformIndices.get(what); return (entry == null) ? -1 : entry.intValue(); } // These were changed to no longer rely on PApplet and PConstants because // of conflicts that could happen with older versions of core.jar, where // the MACOSX constant would instead read as the LINUX constant. /** * returns true if Processing is running on a Mac OS X machine. */ static public boolean isMacOS() { //return PApplet.platform == PConstants.MACOSX; return System.getProperty("os.name").indexOf("Mac") != -1; //$NON-NLS-1$ //$NON-NLS-2$ } /** * returns true if running on windows. */ static public boolean isWindows() { //return PApplet.platform == PConstants.WINDOWS; return System.getProperty("os.name").indexOf("Windows") != -1; //$NON-NLS-1$ //$NON-NLS-2$ } /** * true if running on linux. */ static public boolean isLinux() { //return PApplet.platform == PConstants.LINUX; return System.getProperty("os.name").indexOf("Linux") != -1; //$NON-NLS-1$ //$NON-NLS-2$ } // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . static protected File processingRoot; /** * Get reference to a file adjacent to the executable on Windows and Linux, * or inside Contents/Resources/Java on Mac OS X. This will return the local * JRE location, *whether or not it is the active JRE*. */ static public File getContentFile(String name) { if (processingRoot == null) { // Get the path to the .jar file that contains Base.class URL pathURL = Base.class.getProtectionDomain().getCodeSource().getLocation(); // Decode URL String decodedPath; try { decodedPath = pathURL.toURI().getSchemeSpecificPart(); } catch (URISyntaxException e) { e.printStackTrace(); return null; } if (decodedPath.contains("/app/bin")) { // This means we're in Eclipse final File build = new File(decodedPath, "../../build").getAbsoluteFile(); if (Platform.isMacOS()) { processingRoot = new File(build, "macosx/work/Processing.app/Contents/Java"); } else if (Platform.isWindows()) { processingRoot = new File(build, "windows/work"); } else if (Platform.isLinux()) { processingRoot = new File(build, "linux/work"); } } else { // The .jar file will be in the lib folder File jarFolder = new File(decodedPath).getParentFile(); if (jarFolder.getName().equals("lib")) { // The main Processing installation directory. // This works for Windows, Linux, and Apple's Java 6 on OS X. processingRoot = jarFolder.getParentFile(); } else if (Platform.isMacOS()) { // This works for Java 8 on OS X. We don't have things inside a 'lib' // folder on OS X. Adding it caused more problems than it was worth. processingRoot = jarFolder; } if (processingRoot == null || !processingRoot.exists()) { // Try working directory instead (user.dir, different from user.home) System.err.println("Could not find lib folder via " + jarFolder.getAbsolutePath() + ", switching to user.dir"); processingRoot = new File(""); // resolves to "user.dir" } } } return new File(processingRoot, name); } static public File getJavaHome() { if (Platform.isMacOS()) { //return "Contents/PlugIns/jdk1.7.0_40.jdk/Contents/Home/jre/bin/java"; File[] plugins = getContentFile("../PlugIns").listFiles(new FilenameFilter() { public boolean accept(File dir, String name) { return dir.isDirectory() && name.endsWith(".jdk") && !name.startsWith("."); } }); return new File(plugins[0], "Contents/Home/jre"); } // On all other platforms, it's the 'java' folder adjacent to Processing return getContentFile("java"); } /** Get the path to the embedded Java executable. */ static public String getJavaPath() { String javaPath = "bin/java" + (Platform.isWindows() ? ".exe" : ""); File javaFile = new File(getJavaHome(), javaPath); try { return javaFile.getCanonicalPath(); } catch (IOException e) { return javaFile.getAbsolutePath(); } } // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . /** * Attempts to move to the Trash on OS X, or the Recycle Bin on Windows. * Also tries to find a suitable Trash location on Linux. * If not possible, just deletes the file or folder instead. * @param file the folder or file to be removed/deleted * @return true if the folder was successfully removed * @throws IOException */ static public boolean deleteFile(File file) throws IOException { FileUtils fu = FileUtils.getInstance(); if (fu.hasTrash()) { fu.moveToTrash(new File[] { file }); return true; } else if (file.isDirectory()) { Util.removeDir(file); return true; } else { return file.delete(); } } // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . static public void setenv(String variable, String value) { inst.setenv(variable, value); } static public String getenv(String variable) { return inst.getenv(variable); } static public int unsetenv(String variable) { return inst.unsetenv(variable); } // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . static public int getSystemDPI() { return inst.getSystemDPI(); } }