diff --git a/build/shared/libraries/howto.txt b/build/shared/libraries/howto.txt index 74172ba58..9865ab19a 100644 --- a/build/shared/libraries/howto.txt +++ b/build/shared/libraries/howto.txt @@ -1,480 +1,5 @@ -LIBRARIES IN PROCESSING +This file has been replaced by an entire section of dev.processing.org +dedicated to libraries, people who make libraries, and people who +love library development trivia. The new page can be found here: -Some basic instructions on how libraries work with Processing. -(I'm also adding to this as people have trouble with it.. -Pretty soon it's gonna be an outrageous mess!) - -Libraries are a new feature that are present only in revisions 70 -and higher. Before revision 70, users could place any sort of code -inside the 'code' folder of their sketch, but this meant too many -copies of each library. The code folder is still an option, but the -use of the new "library" system is encouraged as a simple packaging -mechanism for your projects. - -A Processing library can be any sort of Java code that's been -given a package name and packed into a jar file. It can also register -itself with the parent applet to get notification of when events -happen in the sketch, for instance whenever draw() is called or a -key is pressed. - -Most libraries may not need that much functionality, but they -may want to implement the dispose() call, which is called as the -applet is closed. Many libraries, especially those with native code, -need this to properly shut down. - -It is not possible to build libraries from within Processing itself. -In fact, creating a library with Processing will cause problems -because when exported as an applet, the jar file will contain the -current version of the processing.core classes, which will cause -major conflicts when trying to use any other code. - -The PDE is built with the sole purpose of creating short sketches that -are part of PApplet that have a few files at most. We don't plan to -extend the PDE to also support developing libraries (or "tools," once -those are enabled) because then it simply becomes like any other IDE -that is quickly too general for our target audience. Users who are -advanced enough in their programming skills to build libraries will -almost always be skilled enough to use another IDE like Eclipse -(if they aren't already) to build their library. - - -////////////////////////////////////////////////////////////// - - -Where to put Libraries - -Core libraries live inside the "libraries" folder of the Processing -distribution. Starting with release 0149, user-installed libraries -must live in a folder named "libraries" inside the sketchbook folder. - -If a library works only with a particular release of Processing, -then it may make sense for the user to put things into the -Processing libraries folder, however we'd like to keep users -out of there as much as possible. In fact, it may not be visible -in future releases of Processing (for instance, on Mac OS X it -already lives inside the .app bundle). - - -////////////////////////////////////////////////////////////// - - -Notes on Library distribution - -There are two categories of libraries. The "core" libraries -(Video, OpenGL, Serial, Net) are part of the Processing distribution, -and "contributed libraries" are developed, owned, and maintained -by members of the Processing community. - -It's very possible that contributed libraries might make their way -into the regular distribution if it makes sense for all involved. -After the 1.0 release, we'll re-evaluate if some libraries should be -made a part of the standard distribution. For now, we don't have the -people resources to support this, because it would require us to -debug the libraries with each release. - -We try to place a strong focus on the importance of clear -documentation for the Processing project, so please attempt similar -effort into communicating your library's features to potential users -by hosting a descriptive web site. - -If you'd like to have your library posted on the Processing website -(http://processing.org/reference/libraries) please email -reas at processing.org and we'll make a decision about its inclusion. -We strongly encourage (and may someday require as a stipulation for -placement on the site) that the source to your library be included. -We're giving away all our stuff, and we want others to do so as well -because it's good for the community. - -The contributed libraries are one of the most important aspects of -the Processing project and have an enormous impact on how people -understand Processing. Libraries have been designed into the larger -Processing plan to enable simple extensions of the core API in new, -innovative, and unexpected directions. The libraries are the future -of the project as we plan for processing.core.* to remain as minimal -as possible. - - -////////////////////////////////////////////////////////////// - - -A Very Basic Example - - -package libraryexample; -import processing.core.*; - -public class BoringLibrary { - PApplet parent; - - public BoringLibrary(PApplet parent) { - this.parent = parent; - parent.registerDispose(this); - } - - public void dispose() { - // anything in here will be called automatically when - // the parent applet shuts down. for instance, this might - // shut down a thread used by this library. - // note that this currently has issues, see bug #183 - // http://dev.processing.org/bugs/show_bug.cgi?id=183 - } -} - - -Usually you'll need to pass "this" to a library's constructor so that -the library can access functions from PApplet, i.e graphics methods -like line() and stroke() or loadImage(). See later in the document for -information about reading and writing files. - -If you'd like to use constants such as "RGB", use the following: -public class BoringLibrary implements PConstants { -which will allow all the constants to be used by that class. - - -////////////////////////////////////////////////////////////// - - -Library Methods - -public void pre() -method that's called just after beginFrame(), meaning that it -can affect drawing. - -public void draw() -method that's called at the end of draw(), but before endFrame(). - -public void mouseEvent(MouseEvent e) -called when a mouse event occurs in the parent applet - -public void keyEvent(KeyEvent e) -called when a key event occurs in the parent applet - -public void post() -method called after draw has completed and the frame is done. -no drawing allowed. - -public void size(int width, int height) -this will be called the first time an applet sets its size, -but also any time that it's called while the PApplet is running. -no drawing should occur inside of this method, because it may -not be the case that the new renderer is yet valid and ready. -use this only to flag the new size and prepare for the next frame. - -public void stop() -can be called by users, for instance movie.stop() will shut down -a movie that's being played, or camera.stop() stops capturing -video. server.stop() will shut down the server and shut it down -completely, which is identical to its "dispose" function. - -public void dispose() -this should only be called by PApplet. dispose() is what gets -called when the host applet is stopped, so this should shut down -any threads, disconnect from the net, unload memory, etc. -currently, this method is not being called consistently: -http://dev.processing.org/bugs/show_bug.cgi?id=77 - -To register any of these methods with the parent, call -parent.registerPre(this) or whatever the name of the function -is that you'd like to use. - -Note that making things "public" is extremely important. When running -inside Processing, anything left blank has public added by the -preprocessor, meaning "void draw()" becomes "public void draw()". - -You can only draw inside of pre(), draw(), mouseEvent(), or keyEvent() -otherwise you may run into trouble. pre() and draw() happen while -legitimate drawing is taking place, and the mouse/key events happen -just before draw() events are called, they're queued up by the host -applet until it's safe to draw. - -For this reason, you should use registerMouseEvent() and mouseEvent() -(and same for the keys) to handle your events, rather than your class -implementing MouseListener. For instance, to figure out what the mouse -event is throwing back at you, this would be an example handler: - -public void mouseEvent(MouseEvent event) { - int x = event.getX(); - int y = event.getY(); - - switch (event.getID()) { - case MouseEvent.MOUSE_PRESSED: - // do something for the mouse being pressed - break; - case MouseEvent.MOUSE_RELEASED: - // do something for mouse released - break; - case MouseEvent.MOUSE_CLICKED: - // do something for mouse clicked - break; - case MouseEvent.MOUSE_DRAGGED: - // do something for mouse dragged - break; - case MouseEvent.MOUSE_MOVED: - // umm... - break; - } -} - -More on mouse handling can be found in Sun's Java documentation: -http://java.sun.com/j2se/1.4.2/docs/api/java/awt/event/MouseEvent.html -which also covers things like modifiers (shift-click) and whatnot. -Also check out the code for PApplet to see how ctrl-click is handled -on Mac OS X so that it properly registers as a right-click. - - -////////////////////////////////////////////////////////////// - - -Structure of a Library Folder - -The Sonia library by Amit Pitaru is a good example here. To make a -library called sonia, you create a folder called "sonia" and within -that, a subfolder named "library". The sonia folder should be placed -inside the Processing "libraries" folder, or a user can place it -inside their sketchbook folder. - -Inside "library", you'll find "sonia.jar". Anything that is found -inside library will be exported with your sketch. - -If different sets of files should be exported with applets versus -applications, a file called "export.txt" should be included. For -sonia, this looks like: - -# only export the jar file for applets.. -# everything else is installed as a separate browser plugin -applet=sonia.jar -# application needs everything -application=sonia.jar,JSynClasses.jar,JSynV142.dll,libJSynV142.jnilib - -This will include sonia.jar for applets, because in a web browser, the -DLL files must be installed separately along with JSynClasses.jar. -The # sign in front of a line means that the line is a comment, -and it'll be ignored by the PDE. - -As of revision 0097, you can also specify what to export for other -platforms as well (at least Mac OS X, Windows, Linux). For the example -above, the application line could instead be changed to: - -application.macosx=sonia.jar,JSynClasses.jar,libJSynV142.jnilib -application.windows=sonia.jar,JSynClasses.jar,JSynV142.dll - -Platform-specific exports will be checked first, and if they don't -exist, the "application" will be used. If neither exist (or export.txt -doesn't exist), the entire contents of the library folder will be -copied. - - -////////////////////////////////////////////////////////////// - - -Using Other Java Code As A Library - -So long as the code is inside a package, it can be set up for use as -a library. For instance, if you want to make a library called 'poopy' -set up a folder as follows: - -poopy -> - library -> - poopy.jar - -Then, the folder should be placed in the Processing 'libraries' folder -or inside the user's sketch folder to be recognized by Processing and -its "Import Library" menu. As of now, you may need to restart -Processing in order to get the library to show up. - -While this process may sound a little complicated, the intent is to -make it easier for users than a typical Java IDE. A little added -complexity for the developers of library code (who will generally be -more advanced users) is traded for great simplicity by the users, -since Processing is intended to target beginning programmers. - - -////////////////////////////////////////////////////////////// - - -Import Statements and How They Work - -If your library is sonia.jar, found at sonia/library/sonia.jar, all -the packages found in sonia.jar will be added as imports into the -user's sketch when they selected "Import Library". - -In the case of Sonia, an additional .jar file can be found in the -sonia/library/ folder, jsyn.jar. The contents of jsyn.jar will not be -added to the import statements. This is to avoid every library having -a ridiculously large number of import statements. For instance, if you -want to use the "video" library, you don't want all 15-20 packages for -the QuickTime libraries listed there to confuse your users. - -Bottom line, if you want packages from the other .jar to be loaded by -Processing, then you need to put those .class files into the main .jar -file for the library (sonia/library/sonia.jar in this case). - - -////////////////////////////////////////////////////////////// - - -Import Statements and the Code Folder - -The code folder works differently, and every package inside every .jar -found in the code folder is simply added to the import statements by -the preprocessor. The user never sees this, it just happens magically. - - -////////////////////////////////////////////////////////////// - - -Creating .jar Files For Your Library - -Since your code is inside a package, you need to make sure that it's -inside subfolders in the .jar file. It should be noted that jar files -are simply .zip files (they can be opened with WinZip or Stuffit) with -a "manifest" file. - -In the past, you may have used: -javac *.java -to compile your files. Once they're inside a packages, you must use: -javac -d . *.java -which will create folders and subfolders for the packages. For -instance, for all the stuff in processing.core.* it would create: - -processing/ -> - core/ -> - PApplet.class - PGraphics.class - ..etc - -then you can jar that stuff up using: -jar -cf core.jar processing -or with the command line info-zip utility: -zip -r core.jar processing - - -////////////////////////////////////////////////////////////// - - -The "Import Library" Menu Item - -All this does is add the "import yourlibrary.*;" statement to the top -of your sketch. If you've handwritten the import statements, then -there's no need to use "Import Library". - - -////////////////////////////////////////////////////////////// - - -Getting a UnsupportedClassVersionError? (Java 1.5 and later) - -When I compiled blah.jar (using the successful method mentioned -earlier) under Java 1.5, I get the following error from Processing: - -java.lang.UnsupportedClassVersionError: blah/SomeClass - (Unsupported major.minor version 49.0) - -This is because more recent versions of Java like to use their own -class file format that's not backwards compatible. - -When compiling a library, use somtehing like: - javac -source 1.4 -target 1.4 -d . \ - -classpath /path/to/core.jar path/to/java/source/*.java - - -////////////////////////////////////////////////////////////// - - -Adding Your Own Library Events - -So that your library can notify the host applet that something -interesting has happened, this is how you implement an event -method in the style of serialEvent, serverEvent, etc. - - -public class FancyLibrary { - Method fancyEventMethod; - - public YourLibrary(PApplet parent) { - // your library init code here... - - // check to see if the host applet implements - // public void fancyEvent(FancyLibrary f) - try { - fancyEventMethod = - parent.getClass().getMethod("fancyEvent", - new Class[] { FancyLibrary.class }); - } catch (Exception e) { - // no such method, or an error.. which is fine, just ignore - } - } - - // then later, to fire that event - public void makeEvent() { - if (fancyEventMethod != null) { - try { - fancyEventMethod.invoke(parent, new Object[] { this }); - } catch (Exception e) { - System.err.println("Disabling fancyEvent() for " + name + - " because of an error."); - e.printStackTrace(); - fancyEventMethod = null; - } - } -} - - -////////////////////////////////////////////////////////////// - - -Using built-in functions from processing.core - -Many methods in PApplet are made static for use by other libraries -and code that interfaces with Processing. For instance, openStream() -requires an applet object, but loadStrings() is a static method -that can be run on any InputStream. See the developer's reference -for more information about which methods are available. - - -////////////////////////////////////////////////////////////// - - -Accessing files from inside a library - -To open files for use with a library, use the openStream() method. -This is the most compatible means for loading data, and makes use -of many hours of headaches that were the result of attempts to -create functions that loaded data across platforms (Mac, Windows, -and Linux) and circumstances (applet, application, and other). - -The functions sketchPath(), savePath(), dataPath(), and createPath() -all facilitate reading and writing files relative to the sketch -folder. They should be used to ensure that file I/O works consistently -between your library and functions like loadImage() or loadStrings(). -Their documentation can be seen in the online javadoc reference found -on dev.processing.org. The variable sketchPath is available for -convenience, but in nearly all cases, the sketchPath() method is -a better (and more compatible) route. - -The xxxxPath() functions were finalized in revision 0096. - - -////////////////////////////////////////////////////////////// - - -Library Naming Rules - -Libraries, or classes inside them, should not be prefixed with "P" -the way that the core Processing classes are (PImage, PGraphics, etc). -It's tempting to prefix everything that way to identify it with -Processing, but we'd like to reserve that naming for "official" -things that are inside processing.core and other associated classes. - -Same goes for using "Processing", "Pro", or "P5" just like "P", -or whether it's a prefix or a suffix. - -Similarly, please don't using processing.* as the prefix for your -library packages. We'd like to keep that name space clear for -official things as well. - - -////////////////////////////////////////////////////////////// - - -Ben Fry, last updated 19 August 2008 +http://dev.processing.org/libraries/