diff --git a/app/PdeBase.java b/app/PdeBase.java index 0ecd87e60..98d91c280 100644 --- a/app/PdeBase.java +++ b/app/PdeBase.java @@ -48,6 +48,8 @@ public class PdeBase { static String openedAtStartup; + static ClassLoader loader; + PdeEditor editor; static final int WINDOWS = 1; @@ -139,6 +141,10 @@ public class PdeBase { // show the window editor.show(); + + + // maybe? + loader = new PdeClassLoader(); } @@ -157,7 +163,11 @@ public class PdeBase { static public File getProcessingDataFolder() { File dataFolder = null; - if (platform == MACOSX) { + String pref = PdePreferences.get("settings.path"); + if (pref != null) { + dataFolder = new File(pref); + + } else if (platform == MACOSX) { // carbon folder constants // http://developer.apple.com/documentation/Carbon/Reference // /Folder_Manager/folder_manager_ref/constant_6.html#/ @@ -212,8 +222,8 @@ public class PdeBase { String appDataPath = localKey.getStringValue("AppData"); //System.out.println("app data path is " + appDataPath); //System.exit(0); - topKey.closeKey(); // necessary? - localKey.closeKey(); + //topKey.closeKey(); // necessary? + //localKey.closeKey(); dataFolder = new File(appDataPath, "Processing"); @@ -230,7 +240,25 @@ public class PdeBase { } // create the folder if it doesn't exist already - if (!dataFolder.exists()) dataFolder.mkdirs(); + boolean result = true; + if (!dataFolder.exists()) { + result = dataFolder.mkdirs(); + } + + if (!result) { + // try the fallback location + String fallback = PdePreferences.get("settings.path.fallback"); + dataFolder = new File(fallback); + if (!dataFolder.exists()) { + result = dataFolder.mkdirs(); + } + } + + if (!result) { + showError("Settings issues", + "Processing cannot run because it could not\n" + + "create a folder to store your settings.", null); + } return dataFolder; } @@ -241,6 +269,27 @@ public class PdeBase { } + static public File getBuildFolder() { + File folder = new File(getProcessingDataFolder(), "build"); + if (!folder.exists()) folder.mkdirs(); + return folder; + } + + + /* + static public void addBuildFolderToClassPath() { + String path = getBuildFolder().getAbsolutePath(); + String jcp = System.getProperty("java.class.path"); + if (jcp.indexOf(path) == -1) { + System.setProperty("java.class.path", path + File.pathSeparator + jcp); + //return new File(getProcessingDataFolder(), "build"); + System.out.println("jcp is now " + + System.getProperty("java.class.path")); + } + } + */ + + static public File getDefaultSketchbookFolder() { File sketchbookFolder = null; @@ -291,8 +340,8 @@ public class PdeBase { "\\Explorer\\Shell Folders"; RegistryKey localKey = topKey.openSubKey(localKeyPath); String personalPath = localKey.getStringValue("Personal"); - topKey.closeKey(); // necessary? - localKey.closeKey(); + //topKey.closeKey(); // necessary? + //localKey.closeKey(); sketchbookFolder = new File(personalPath, "Processing"); @@ -300,18 +349,44 @@ public class PdeBase { showError("Problem getting documents folder", "Error getting the Processing sketchbook folder.", e); } + + } else { + // on linux (or elsewhere?) prompt the user for the location + JFileChooser fc = new JFileChooser(); + //fc.setSelectedFile(new File(sketchbookLocationField.getText())); + fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + + int returned = fc.showOpenDialog(new JDialog()); + if (returned == JFileChooser.APPROVE_OPTION) { + //File file = fc.getSelectedFile(); + //sketchbookLocationField.setText(file.getAbsolutePath()); + sketchbookFolder = fc.getSelectedFile(); + + } else { + System.exit(0); + } } - // if it failed, or if on linux, prompt the user or quit - /* - File home = new File(System.getProperty("user.home")); - File phome = new File(home, ".processing"); - if (!phome.exists()) phome.mkdirs(); - return phome; - */ - // create the folder if it doesn't exist already - if (!sketchbookFolder.exists()) sketchbookFolder.mkdirs(); + boolean result = true; + if (!sketchbookFolder.exists()) { + result = sketchbookFolder.mkdirs(); + } + + if (!result) { + // try the fallback location + String fallback = PdePreferences.get("sketchbook.path.fallback"); + sketchbookFolder = new File(fallback); + if (!sketchbookFolder.exists()) { + result = sketchbookFolder.mkdirs(); + } + } + + if (!result) { + showError("error", + "Processing cannot run because it could not\n" + + "create a folder to store your sketchbook.", null); + } return sketchbookFolder; } diff --git a/app/PdeClassLoader.java b/app/PdeClassLoader.java new file mode 100755 index 000000000..dc6ab6f81 --- /dev/null +++ b/app/PdeClassLoader.java @@ -0,0 +1,225 @@ +/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/** + * Based on Simple1.2ClassLoader.java - simple Java 1.2 class loader + * Copyright (c) 1999 Ken McCrary, All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software + * and its documentation for NON-COMMERCIAL purposes and without + * fee is hereby granted provided that this copyright notice + * appears in all copies. + * + * KEN MCCRARY MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE + * SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. KEN MCCRARY + * SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT + * OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. + */ + +import java.io.*; +import java.net.*; +import java.util.*; +import java.util.jar.*; + +/** + * Simple class loader to illustrate custom Class + * loading with new delegation model in Java 1.2. + * + */ +public class PdeClassLoader extends ClassLoader { + String buildFolderPath; + + /* + PdeClassLoader(ClassLoader parent) { + super(parent); + init(); + } + */ + + PdeClassLoader() { + //super(); // uses system class loader + //init(); + //} + + //private void init() { + buildFolderPath = PdeBase.getBuildFolder().getAbsolutePath(); + + /* + FileInputStream fi = null; + + // Check for a manifest in the store directory + try + { + fi = new FileInputStream("store\\MANIFEST.MF"); + manifest = new Manifest(fi); + } + catch (Exception e) + { + // No manifest + } + finally + { + if ( null != fi ) + { + try + { + fi.close(); + } + catch (Exception e){} + } + } + */ + } + + + /** + * This is the method where the task of class loading + * is delegated to our custom loader. + * + * @param name the name of the class + * @return the resulting Class object + * @exception ClassNotFoundException if the class could not be found + */ + protected Class findClass(String name) throws ClassNotFoundException + { + FileInputStream fi = null; + + try { + //System.out.println("PCL finding class: " + name); + String path = + buildFolderPath + File.separator + name.replace('.', '/'); + //System.out.println("(from " + path + ")"); + fi = new FileInputStream(path + ".class"); + byte[] classBytes = new byte[fi.available()]; + fi.read(classBytes); + //definePackage(name); + return defineClass(name, classBytes, 0, classBytes.length); + + } catch (Exception e) { + // We could not find the class, so indicate the problem with an exception + throw new ClassNotFoundException(name); + + } finally { + if (fi != null) { + try { + fi.close(); + } catch (Exception e) { } + } + } + } + + + /** + * Identify where to load a resource from, resources for + * this simple ClassLoader are in a directory name "store" + * + * @param name the resource name + * @return URL for resource or null if not found + */ + protected URL findResource(String name) { + String path = + buildFolderPath + File.separator + name.replace('.', '/'); + File searchResource = new File(path, name); + //URL result = null; + + if (searchResource.exists()) { + try { + return searchResource.toURL(); + } catch (MalformedURLException mfe) { } + } + //return result; + return null; + } + + + /** + * Used for identifying resources from multiple URLS + * Since our simple Classloader only has one repository + * the returned Enumeration contains 0 to 1 items + * + * @param name the resource name + * @return Enumeration of one URL + */ + protected Enumeration findResources(final String name) throws IOException { + // Since we only have a single repository we will only have one + // resource of a particular name, the Enumeration will just return + // this single URL + + return new Enumeration() { + URL resource = findResource(name); + + public boolean hasMoreElements() { + return ( resource != null ? true : false); + } + + public Object nextElement() { + if (!hasMoreElements()) { + throw new NoSuchElementException(); + } else { + URL result = resource; + resource = null; + return result; + } + } + }; + } + + + /** + * Minimal package definition + * + */ + /* + private void definePackage(String className) + { + // Extract the package name from the class name, + String pkgName = className; + int index = className.lastIndexOf('.'); + if (-1 != index) + { + pkgName = className.substring(0, index); + } + + // Pre-conditions - need a manifest and the package + // is not previously defined + if ( null == manifest || + getPackage(pkgName) != null) + { + return; + } + + String specTitle, + specVersion, + specVendor, + implTitle, + implVersion, + implVendor; + + // Look up the versioning information + // This should really look for a named attribute + Attributes attr = manifest.getMainAttributes(); + + if ( null != attr) + { + specTitle = attr.getValue(Name.SPECIFICATION_TITLE); + specVersion = attr.getValue(Name.SPECIFICATION_VERSION); + specVendor = attr.getValue(Name.SPECIFICATION_VENDOR); + implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE); + implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION); + implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR); + + definePackage(pkgName, + specTitle, + specVersion, + specVendor, + implTitle, + implVersion, + implVendor, + null); // no sealing for simplicity + } + } + + private Manifest manifest; + */ +} diff --git a/app/PdeEditor.java b/app/PdeEditor.java index 5359aa2e0..f35a9ed74 100644 --- a/app/PdeEditor.java +++ b/app/PdeEditor.java @@ -1039,6 +1039,22 @@ public class PdeEditor extends JFrame presentationWindow.toFront(); } + try { + if (!sketch.handleRun()) return; + + runtime = new PdeRuntime(sketch, PdeEditor.this); + runtime.start(presenting ? presentLocation : appletLocation); + watcher = new RunButtonWatcher(); + + } catch (PdeException e) { + error(e); + + } catch (Exception e) { + e.printStackTrace(); + } + + // this doesn't seem to help much or at all + /* final SwingWorker worker = new SwingWorker() { public Object construct() { try { @@ -1058,6 +1074,7 @@ public class PdeEditor extends JFrame } }; worker.start(); + */ //sketch.cleanup(); // where does this go? } diff --git a/app/PdeRuntime.java b/app/PdeRuntime.java index 88e500a58..b4a0a4953 100644 --- a/app/PdeRuntime.java +++ b/app/PdeRuntime.java @@ -128,7 +128,8 @@ public class PdeRuntime implements PdeMessageConsumer { } else { // !externalRuntime //Class c = Class.forName(className); - Class c = Class.forName(sketch.mainClassName); + //Class c = Class.forName(sketch.mainClassName); + Class c = PdeBase.loader.loadClass(sketch.mainClassName); applet = (PApplet) c.newInstance(); // replaces setRuntime with PApplet having leechErr [fry] @@ -569,7 +570,9 @@ java.lang.NullPointerException // unless this is set to min, it seems to hork the app // since it's in charge of stuffing the editor console with strings // maybe it's time to get rid of/fix that friggin console - thread.setPriority(Thread.MIN_PRIORITY); + // ...disabled for 0075, with 0074's fix for code folder hanging + // this only seems to make the console unresponsive + //thread.setPriority(Thread.MIN_PRIORITY); thread.start(); } diff --git a/app/PdeSketch.java b/app/PdeSketch.java index 0a1064f34..be8f6564b 100644 --- a/app/PdeSketch.java +++ b/app/PdeSketch.java @@ -35,7 +35,7 @@ import com.oroinc.text.regex.*; public class PdeSketch { - static String TEMP_BUILD_PATH = "lib" + File.separator + "build"; + //static String TEMP_BUILD_PATH = "lib" + File.separator + "build"; static File tempBuildFolder; PdeEditor editor; @@ -100,6 +100,7 @@ public class PdeSketch { // exist when the application is started, then java will remove // the entry from the CLASSPATH, causing PdeRuntime to fail. // + /* tempBuildFolder = new File(TEMP_BUILD_PATH); if (!tempBuildFolder.exists()) { tempBuildFolder.mkdirs(); @@ -109,6 +110,9 @@ public class PdeSketch { "It has now been replaced, please restart \n" + "the application to complete the repair.", null); } + */ + tempBuildFolder = PdeBase.getBuildFolder(); + //PdeBase.addBuildFolderToClassPath(); folder = new File(new File(path).getParent()); //System.out.println("sketch dir is " + folder); @@ -912,7 +916,9 @@ public class PdeSketch { "_" + String.valueOf((int) (Math.random() * 10000))); // handle preprocessing the main file's code - mainClassName = build(TEMP_BUILD_PATH, suggestedClassName); + //mainClassName = build(TEMP_BUILD_PATH, suggestedClassName); + mainClassName = + build(tempBuildFolder.getAbsolutePath(), suggestedClassName); // externalPaths is magically set by build() if (!externalRuntime) { // only if not running externally already @@ -1048,12 +1054,16 @@ public class PdeSketch { //PApplet.printarr(codeFolderPackages); } else { + /* // check to see if multiple files that include a .java file externalRuntime = false; for (int i = 0; i < codeCount; i++) { if (code[i].flavor == JAVA) externalRuntime = true; } - //externalRuntime = (codeCount > 1); // may still be set true later + */ + // since using the special classloader, + // run externally whenever there are extra classes defined + externalRuntime = (codeCount > 1); //codeFolderPackages = null; libraryPath = ""; } @@ -1081,6 +1091,12 @@ public class PdeSketch { } } + // since using the special classloader, + // run externally whenever there are extra classes defined + if ((bigCode.indexOf(" class ") != -1) || + (bigCode.indexOf("\nclass ") != -1)) { + externalRuntime = true; + } // 2. run preproc on that code using the sugg class name // to create a single .java file and write to buildpath @@ -1092,8 +1108,6 @@ public class PdeSketch { // if (i != 0) preproc will fail if a pde file is not // java mode, since that's required String className = - // preprocessor.write(bigCode.toString(), buildPath, - // suggestedClassName); preprocessor.write(bigCode.toString(), buildPath, suggestedClassName, codeFolderPackages); if (className == null) { diff --git a/build/shared/lib/preferences.txt b/build/shared/lib/preferences.txt index 745bf1a6d..a8c5c8bd8 100755 --- a/build/shared/lib/preferences.txt +++ b/build/shared/lib/preferences.txt @@ -1,15 +1,46 @@ # !!!!!!!! UNLIKE PREVIOUS VERSIONS OF PROCESSING !!!!!!!!!! # DO NOT MODIFY THIS FILE, OR DELETE SETTINGS FROM THIS FILE -# These are the default preferences. They will be copied to: -# My Documents -> Processing -> preferences.txt (on windows) -# Documents -> Processing -> preferences.txt (on macosx) -# ~/.processing/preferences.txt (on linux) -# where you can make changes for your machine. +# These are the default preferences. If you want to modify +# them directly, use the per-user local version of the file: + +# Documents and Settings -> Application Data -> +# Processing -> preferences.txt (on windows) + +# ~/Library -> Processing -> preferences.txt (on macosx) + +# ~/.processing -> preferences.txt (on linux) # You'll have problems running Processing if you incorrectly # modify lines in this file. + +# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + +# DEFAULT PATHS FOR SKETCHBOOK AND SETTINGS + +# relative paths will be relative to processing.exe or procesing.app. +# absolute paths may also be used. + +# note that this path should use forward slashes (like unix) +# instead of \ on windows or : on macos or whatever else + +# the .fallback locations are used in case the default location +# cannot be written (and the line above it is not customized) + +# if you don't want users to have their sketchbook default to +# "my documents/processing" on windows and "documents/processing" on osx, +# set this to another path that will be used by default +#sketchbook.path=sketchbook +sketchbook.path.fallback=sketchbook + +# if you don't want settings to go into "application data" on windows +# and "library" on macosx, set this to the alternate location. +#settings.path=data +settings.path.fallback=data + + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -159,11 +190,8 @@ sketchbook.prompt = false # true if empty sketches should be removed automatically sketchbook.auto_clean = true -sketchbook.name.default = sketchbook +# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -# note that this path should use forward slashes (like unix) -# instead of \ on windows or : on windows or whatever else -#sketchbook.path = history.recording = true diff --git a/core/PApplet.java b/core/PApplet.java index 94b032c5d..818d70056 100644 --- a/core/PApplet.java +++ b/core/PApplet.java @@ -4029,6 +4029,7 @@ public class PApplet extends Applet } try { Thread.sleep(250); + //Thread.sleep(100); // kick up latency for 0075? } catch (InterruptedException e) { } } } diff --git a/core/todo.txt b/core/todo.txt index 45ece3a61..a13796cd5 100644 --- a/core/todo.txt +++ b/core/todo.txt @@ -32,6 +32,10 @@ _ or maybe need to get better at size() inside of draw() ? _ make this consistent with the regular PApplet _ otherwise things are going to be weird/difficult for debugging +_ still threading issues with running opengl +_ first run hangs until quit +_ though doesn't seem to replicate when p5 is restarted + _ fix non-bound textures from mangling everything else _ fix enable/disable textures for some objects _ fix endian ordering issues so that things work properly diff --git a/todo.txt b/todo.txt index 6fe8e557b..ab310d3d7 100644 --- a/todo.txt +++ b/todo.txt @@ -17,42 +17,60 @@ X is PdeEditorHeader one pixel too tall X move the tabs over just slightly X resize box intrudes on the scroller for the console area X need to set grow boxes intruding to false -X 1.3 version (deprecated): -Dcom.apple.mrj.application.growbox.intrudes=false -X 1.4 version: -Dapple.awt.showGrowBox=false +X 1.3 version (deprecated): +X -Dcom.apple.mrj.application.growbox.intrudes=false +X 1.4 version (much nicer): -Dapple.awt.showGrowBox=false X add mkdmg script to macosx build process X could significantly speed things up -X put 'play' on a SwingWorker thread -_ test this on a pc to see how it goes, especially with opengl - sketchbook/prefs location -_ read from registry key to get the proper name for these folders -_ also find some way to do this on the mac -_ on non-english windows (or at the broad) these will be named differently -_ http://support.microsoft.com/?kbid=221837&sd=RMVP -_ or is there a proper way to do this with java params? -_ move to ~/Application Data/Processing for windows -_ and ~/Library/Processing for macosx -_ and ~/.processing for linux -_ if it can't write prefs here, try creating a subfolder inside p5 -_ and if that fails, then tell the user that they suck -_ prompt for sketchbook location on linux -_ or on mac/pc if it can't write anywhere else -_ creating sketchbook / lab situations -_ test to see if it's possible to write to "My Documents" -_ if not, should bring up a prompt asking where to put sketchbook -_ also put something in lib/preferences.txt for default location -_ this way a course admin can change the default location -_ need to check if volume is read-only, notify and quit if it is -_ people are trying to run off the disk image -_ actually that should be fine.. -_ but make sure the prefs location can be written -_ need to pay attention to when running from read-only drive -_ reported by brandenberg -_ "p5 will launch from the disk image, but will -_ not draw the sketch name bar doesn't appear" -_ includes preferences.txt option to write to p5 folder first -_ this can be altered by instructors and re-packaged +X read from registry key to get the proper name for these folders +X also find some way to do this on the mac +X on non-english windows (or at the broad) these will be named differently +X http://support.microsoft.com/?kbid=221837&sd=RMVP +X or is there a proper way to do this with java params? +X move to ~/Application Data/Processing for windows +X and ~/Library/Processing for macosx +X and ~/.processing for linux +X if it can't write prefs here, try creating a subfolder inside p5 +X and if that fails, then tell the user that they suck +X prompt for sketchbook location on linux +X or on mac/pc if it can't write anywhere else +X creating sketchbook / lab situations +X test to see if it's possible to write to "My Documents" +X if not, should bring up a prompt asking where to put sketchbook +X also put something in lib/preferences.txt for default location +X this way a course admin can change the default location +o need to check if volume is read-only, notify and quit if it is +o people are trying to run off the disk image +o actually that should be fine.. +o but make sure the prefs location can be written +o need to pay attention to when running from read-only drive +o reported by brandenberg +o "p5 will launch from the disk image, but will +o not draw the sketch name bar doesn't appear" +X include preferences.txt option to write to p5 folder first +X this can be altered by instructors and re-packaged +X fixed a couple bugs causing the jnilib stuff to crash + +X put 'play' on a SwingWorker thread +X test this on a pc to see how it goes, especially with opengl +X doesn't seem to help anything +X PdeRuntime -> SystemOutSiphon, removed MIN_PRIORITY setting +o hack to not use console on the code folder +o no errors will propogate, but it should run fine + +X lib/build should not be a subfolder of p5 +X p5 environment installed to /Applications on lab machines +X instead use a temp folder +X maybe when running on lab machines in that case, always java mode? +X or is it possible to add to java.class.path while app is running? +X have to use a special class loader +X new class loader for single files +X if more than one class defined, forces it to run externally +X (basically any time it sees "class" in the code.. +X may be subject to errors, but errs on side of just running ext) +X runs out of processing data folder _ bring back "rename" ? @@ -60,7 +78,8 @@ _ may need a progress bar for "save as" _ or just the file copy function in general _ since it may take a long time (i.e. 1000s of screen grabs) -_ opening up sketch folder may be extremely slow +_ scanning sketchbook folder may be extremely slow +_ not sure why this would be the case _ preproc: making all functions public that have no specifier _ this will make draw() etc all much easier @@ -71,14 +90,6 @@ _ basic sample audio playback needed for p5 _ what's up with int() -> toInt() conversion? -_ hack to not use console on the code folder -_ no errors will propogate, but it should run fine - -_ lib/build should not be a subfolder of p5 -_ p5 environment installed to /Applications on lab machines -_ instead use a temp folder -_ maybe when running on lab machines in that case, always java mode? - //