LIBRARIES IN PROCESSING

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.

Libraries live inside the "libraries" folder of the Processing
distribution, however users are encouraged to install "contributed"
libraries in their sketchbook folder, which will prevent them 
from having to move their libraries with new Processing releases.

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.


//////////////////////////////////////////////////////////////


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 very 
minimal.


//////////////////////////////////////////////////////////////


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 23 October 2007
