JTablet does not seem to close correctly. If the **last** JTablet-
enabled applet is closed, and then some time later a new JTablet-
enabled applet started **in the same JVM**, drawing does not work in
the newly-started applet. While this bug sounds hard to trigger, its
really quite easy. Since most browsers keep Java running for at least
a few seconds the last applet has closed, the reproduction steps are
simply:
1. Go to
http://jtablet.cellosoft.com/jtablet2-demo.html
2. Draw something
3. Refresh the page
4. Try to draw something again
If you wait for Java to exit before reloading the applet (for example,
replace step 3 with "leave the page, wait a minute or so, go back to
the page") then there should be no problem. The easiest way to see
when Java has exited is to do the steps listed under method 1 at
http://www.java.com/en/download/help/javaconsole.xml -- as soon as
Java starts a console will open, and the console will naturally
disappear as soon as Java exits.
I'm not 100% sure what is causing this bug, though I have a theory
after some debugging. I think that the problem occurs because of an
interaction of two things. First is that the static instance of
TabletManagerImpl held by TabletManager is **not** garbage collected
(it is a static variable, afterall). Second is that when the applet is
closed, NativeTabletManager threads are stopped by **Java** not the
**applet**. I believe the two interact in the following way:
1. JVM starts up
2. DemoApplet calls TabletManager.getDefaultManager()
3. A static instance of TabletManagerImpl is created (which creates a
NativeTabletManager to do the dirty work)
4. DemoApplet calls addTabletListener() and addScreenTabletListener()
5. Each of these methods in turn call startIfNeeded() in
ScreenTabletManager to start the NativeTabletManager threads
6. NativeTabletManager threads begin relaying events
7. Time passes... User draws something... User exits applet
8. Applet gets a "close" singal
9. Java stops running threads
10. Objects are garbage collected
11. Time passes... User opens a new applet
12. Applet calls TabletManager.getDefaultManager()
13. The static instance of TabletManagerImpl is created (referencing
the same NativeTabletManager it always has)
14. DemoApplet calls addTabletListener() and addScreenTabletListener()
15. Each of these methods in turn call startIfNeeded(), but since
'started' is still 'true' (stopIfNeeded() was never called!) no thread
is started
16. No events are ever relayed.
Provided I have this timeline correct (and that it is indeed the
source of this bug) we either need to ensure that 'started' is reset
to 'false' when the last applet using JTablet is closed, or to ensure
our NativeTabletManager is garbage collected. Implementing either seem
problematic: the former requires we know when the last JTablet applet
has ended, while the latter seems to be incompatible with the
singleton approach used in TabletManagerImpl.