JDK-8097917 : add a pulse listener facility
  • Type: Enhancement
  • Component: javafx
  • Sub-Component: scenegraph
  • Affected Version: fx2.0
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2010-11-02
  • Updated: 2015-11-19
  • Resolved: 2015-11-19
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 9
9Fixed
Related Reports
Relates :  
Relates :  
Description
Add some kind of facility where programs can get a callback or notification
that a pulse has occurred. This might actually be a public API, not just
a developer API.

(This is from the UI controls offsite.)

Comments
Created JDK-8143358 as a follow-on for testing Platform.requestNextPulse().
19-11-2015

Changeset: http://hg.openjdk.java.net/openjfx/9-dev/rt/rev/13d1e46cf48f
19-11-2015

+1 on the API change Docs look good. Implementation looks good. Two comments on the tests (not blocking) : 1) You might as well remove the commented-out testAddPreLayoutPulseListenerOffThread test, since there is no way to run such a test in the graphics module given that all graphics tests are run with StubToolkit (it would require a system test). 2) You need a test for requestPulse -- at least a simple functional test in the graphics module to make sure it does anything at all. As a possible follow-on JIRA we should consider adding system tests for request pulse functionality and for checking the threading aspect of the pulse listeners and requestPulse. Approved for integration.
18-11-2015

Updated patch with unit tests, API, and javadocs improved.
14-11-2015

Two more comments on the docs / implementation: 1) We need to throw NPE in the add*PulseListener methods if the specified Runnable is null. Given this, you can remove "is null or" from "This method does nothing if the specified Runnable is null or is not already in the list". Also, I see that I added that sentence to the removePrePulseListener docs, but forgot to add it to the removePostPulseListener docs. 2) Would "addPreLayoutPulseListener", etc., be a better name? It's longer, but somewhat more descriptive, since someone could otherwise interpret them to mean before / after the pulse (when what it really is is before / after layout during the pulse). I'm OK with the current names, but thought I'd put the suggestion out there.
13-11-2015

A couple more comments on implementation and testing: 1) Please add the thread check call to the add/remove listener methods 2) The CopyOnWriteArrayList will do the job, but might be a bit heavy-weight since we don't have to protect against multiple threads from accessing it. However, it does need to be reentrant, and this might be the easiest way to do it. I would expect that mutating this list is rare, so if you want to stick with the current implementation that's fine 3) We will need unit tests for the new functionality.
11-11-2015

The latest version of the API from Nov 9 looks good. Here are my proposed changes to the javadocs: Platform.java: /** * Requests the Java Runtime to perform a pulse. This will run a pulse * even if there are no animation timers, scene graph modifications, * or window events that would otherwise cause the pulse to run. * If no pulse is in progress, then one will be scheduled to * run the next time the pulse timer fires. * If there is already a pulse running, then * at least one more pulse after the current pulse will be scheduled. * This method may be called on any thread. */ public static void requestNextPulse() { ========================== Scene.java: /** * Adds a new scene pre pulse listener to this scene. Every time a pulse occurs, * this listener will be called on the JavaFX Application Thread directly * <strong>before</strong> the CSS and layout passes, and also before * any rendering is done for * this frame. This scene pulse listener is suitable for knowing when a * scenegraph pulse is happening and also for modifying the scenegraph * (as it is called before CSS and layout, so any changes made will be properly * styled and positioned). * This method must be called on the JavaFX Application thread. * * @param r The Runnable to be called when the pulse occurs. * * @throws IllegalStateException if this method is called on a thread * other than the JavaFX Application Thread. * * @since 9 */ public final void addPrePulseListener(Runnable r) { ---------- /** * Removes a previously registered scene pre pulse listener from listening to * pulses in this scene. This method does nothing if the specified Runnable is * null or is not already in the list. * This method must be called on the JavaFX Application thread. * * @param r The Runnable that should no longer be called when the pulse * occurs for this scene. * * @throws IllegalStateException if this method is called on a thread * other than the JavaFX Application Thread. * * @since 9 */ public final void removePrePulseListener(Runnable r) { ---------- /** * Adds a new scene post pulse listener to this scene. Every time a pulse occurs, * this listener will be called on the JavaFX Application Thread directly * <strong>after</strong> the CSS and layout passes, but before any rendering is done for * this frame. This scene pulse listener is suitable for knowing when a * scenegraph pulse is happening, but it is not suited to use cases related * to modifying the scenegraph (as it is called after CSS and layout, so * any changes will possibly be incorrect until the next pulse is run). * An alternative (and better) solution for situations where a scenegraph * modification is required to happen is to use either the * {@link #addPrePulseListener(Runnable)} API or the the * {@link javafx.animation.AnimationTimer} API. * * This method must be called on the JavaFX Application thread. * * @param r The Runnable to be called when the pulse occurs. * * @throws IllegalStateException if this method is called on a thread * other than the JavaFX Application Thread. * * @since 9 */ public final void addPostPulseListener(Runnable r) { ---------- /** * Removes a previously registered scene post pulse listener from listening to * pulses in this scene. * * This method must be called on the JavaFX Application thread. * * @param r The Runnable that should no longer be called when the pulse * occurs for this scene. * * @throws IllegalStateException if this method is called on a thread * other than the JavaFX Application Thread. * * @since 9 */ public final void removePostPulseListener(Runnable r) {
11-11-2015

New patch attached that adds a pulse listener as requested to Scene.
02-10-2015

AnimationTimer (present since Presidio, but I can't select it from the list of fix versions) should be sufficient. Please reopen if it's not.
02-04-2013

Reassigning to scenegraph, although perhaps it should be graphics?
08-03-2011

Both for tooling (scenic view) and for some application uses it is handy to be able to add a pulse listener, such that we can listen to the pulses and insert application level work. For example, right now we do CSS and layout asynchronously. 3rd parties might have such things they want to do as well. The JavaOne demo from last year used such functionality, so it would be nice to get this into presidio
31-01-2011