Re: Is it possible to disable JavaFX shutdown hook?
Hi Pavel Not sure if this will help in your situation but you can try using "primaryStage.setOnCloseRequest" where you can run any cleanup code needed. If you want to cancel the close request completely then just consume the WindowEvent and then later issue Platform.exit() when ready. Regards Jurgen On Thu, 25 Jul 2024 17:43:25 +0200, PavelTurk wrote: Hello all. JavaFX adds its own shutdown hook. That gives many problems when it is necessary to work with application, when system is shutting down, for example, if user presses CTRL+C. The first problem I described here - https://bugs.openjdk.org/browse/JDK-8320923 Another problem is that after pressing CTRL+C JavaFX seems not to respond anymore. For example I've observed that if after that we try to do Platform.runLater(() -> myCode is here), then myCode will never execute. So, it is necessary to check in system, how it is shutting down, if it is. And this problem creates other problems. Before opening a feature request, I decided to ask JavaFX developers, if it possible to disable JavaFX shutdown hook. I mean, if there is no system property (something like javafx.shutdownhook.disabled), it will be added, but if I want to call Platform.exit() manually I want to be able to disable JavaFX shutdown hook. Best regards, Pavel
Re: RFR: 8289115: Touch events is not dispatched after upgrade to JAVAFX17+
Thank you Michael, Jose, Florian, and Markus In my mind the "Too many touch points reported" exception fix (#394) appears to not be the correct fix for that issue and is what caused this regression. There seems to be two possible paths forward, either revert #394 or integrate this. In both cases the "Too many touch points reported" issue will need to be readdressed. It would be nice to see this move forward somehow. Thanks again, Jurgen On Tue, 04 Jun 2024 18:28:47 +0200, Markus Mack wrote: On Tue, 21 May 2024 14:25:51 GMT, Michael Strauß wrote: This PR fixes a bug ([JDK-8289115](https://bugs.openjdk.org/browse/JDK-8289115)) that was introduced with #394, which changed the following line in the `NotifyTouchInput` function (ViewContainer.cpp): - const bool isDirect = true; + const bool isDirect = IsTouchEvent(); `IsTouchEvent` is a small utility function that uses the Windows SDK function `GetMessageExtraInfo` to distinguish between mouse events and pen events as described in this article: https://learn.microsoft.com/en-us/windows/win32/tablet/system-events-and-mouse-messages I think that using this function to distinguish between touchscreen events and pen events is erroneous. The linked article states: _"When your application receives a **mouse message** (such as WM_LBUTTONDOWN) [...]"_ But we are not receiving a mouse message in `NotifyTouchInput`, we are receiving a `WM_TOUCH` message. I couldn't find any information on whether this API usage is also supported for `WM_TOUCH` messages, but my testing shows that that's probably not the case (I tested this with a XPS 15 touchscreen laptop, where `GetMessageExtraInfo` returns 0 for `WM_TOUCH` messages). My suggestion is to check the `TOUCHEVENTF_PEN` flag of the `TOUCHINPUT` structure instead: const bool isDirect = (ti->dwFlags & TOUCHEVENTF_PEN) == 0; I attempted to test this with the sample app in [JDK-8249737](https://bugs.openjdk.org/browse/JDK-8249737) and [Microsoft.Windows.Simulator](https://stackoverflow.com/questions/40274660/windows-10-how-do-i-test-touch-events-without-a-touchscreen) using the simulator's "Basic touch mode". The "Too many touch points reported" exception seems to be thrown consistently with `const bool isDirect = true;` (original before #394) and `const bool isDirect = (ti->dwFlags & TOUCHEVENTF_PEN) == 0;` (this PR) I didn't see the exception with `const bool isDirect = IsTouchEvent();` (#394) and `const bool isDirect = false` (which is probably what IsTouchEvent() returns here). Not sure what this simulator actually sends, but someone more knowledgeable might want to have a look at what's happening. - PR Comment: https://git.openjdk.org/jfx/pull/1459#issuecomment-2147933056
Touch events are not dispatched after upgrade to JavaFX 17
Hi All Can JDK-8289115 (Touch events are not dispatched after upgrade to JavaFX 17) please get some attention again for the next release. Thanks, regards Jurgen
Re: Integrated: 8324658: Allow animation play/start/stop/pause methods to be called on any thread
A big THANK YOU to everybody that was part of this process. It's very much appreciated ! Regards Jurgen On Tue, 30 Jan 2024 11:27:44 +0200, Nir Lisker wrote: On Fri, 26 Jan 2024 23:59:50 GMT, Nir Lisker wrote: Added a utility method to run code on the FX thread if it's not already, and changed the animation methods to use it. This pull request has now been integrated. Changeset: c5ab220b Author:Nir Lisker URL: https://git.openjdk.org/jfx/commit/c5ab220bbc885f2aa99d8c1d5ed8f1753e39251f Stats: 422 lines in 7 files changed: 225 ins; 148 del; 49 mod 8324658: Allow animation play/start/stop/pause methods to be called on any thread Reviewed-by: kcr, jpereda - PR: https://git.openjdk.org/jfx/pull/1352
Re: HEADS-UP: Threading restriction for Animation play, pause, stop now enforced USE CASE
Hi Kevin If I may make one more final appeal then to an alternative solution please. Could we then instead of throwing an Exception rather invoke runLater if needed inside play, stop, and resume. Putting the onus on the developer is fine if it is the developer that is invoking the call, but if it's in a library then it's a no go. In my application I have two libraries that I know of where this happens. The major problem is that with FX22 as it now stands my application just crashes because play() does an FX thread check and throws an Exception which it never did before. There are bound to be other applications out there that are going to find themselves in a similar position. PLEASE ! Regards Jurgen On Wed, 24 Jan 2024 15:15:31 +0200, Kevin Rushforth wrote: Thank you to Jurgen for raising the question and to Nir, John, and Michael for evaluating it. I conclude that there is insufficient motivation to revert the change in behavior implemented by JDK-8159048 to allow calling the play/>pause/stop methods of Animation on a background thread. Doing so without making it fully multi-thread-safe would be asking for problems, >and making it fully multi-thread-safe would be a fair bit of work to do it right without a clear benefit. We will proceed with the current approach and let JDK-8159048 stand. Further, we will proceed with https://bugs.openjdk.org/browse/>JDK-8324219 which is under review in https://github.com/openjdk/jfx/pull/1342 -- Kevin On 1/24/2024 12:30 AM, Nir Lisker wrote: After playing around with the code sample, I think that this is not the right way to use the animation. The reason is that there is >>no point in starting the animation before the control is attached to the scenegraph, or even made visible. A small refactoring >>where, e.g., the controller class exposes a method to start the animation in onSucceeded or just calls it on the FX thread is >>enough. I never start an animation as part of the construction because it's not the right time. John suggested tying the lifecycle >>of the animation to the showing of the node, which also solves the problem. There are animations like PauseTransition or other non-interfering Timelines that could reasonably be run on a background >>thread. Or maybe just on an unconnected control. This could be a reason to not limit animation methods to the FX thread at >>the expense of possible user errors, but document the pitfall. I don't see a good use case for modifying controls in a background thread while still interacting with the scenegraph, hence for >>adding multithread support. - Nir On Mon, Jan 22, 2024, 12:59 Jurgen Doll wrote: Here's an example as requested by Nir: public class FxTimeLineTest extends Application { private BorderPane bp = new BorderPane( new Label("Loading") ); public static void main( String[] args ) { launch( FxTimeLineTest.class, args ); } @Override public void start( Stage primaryStage ) throws Exception { new Thread( new LoadScene() ).start(); primaryStage.setScene(new Scene( bp, 300, 200 ) ); primaryStage.setTitle( "Memory Usage" ); primaryStage.show(); } private class LoadScene extends Task { @Override protected Parent call() throws Exception { Parent p = FXMLLoader.load( getClass( ).getResource("TestView.fxml") ); Thread.sleep( 1000 ); return p; } @Override protected void succeeded() { bp.setCenter( getValue() ); } @Override protected void failed() { getException().printStackTrace(); } } } -- public class TestView { @FXML private Label memory; private static final double MEGABYTE = 1024 * 1024; @FXML private void initialize() { var updater = new Timeline ( new K eyFrame( Duration.seconds(2.5), event -> { var runtime = Runtime.getRuntime(); double maxMemory = runtime.maxMemory() / MEGABYTE; double usedMemory = (runtime.totalMemory() - runtime.freeMemory()) / MEGABYTE; memory.setText( (int) usedMemory + " MB / " + (int) maxMemory +" MB" ); }) ); updater.setCycleCount(Animation.INDEFINITE); // This FXML is being loaded on a background thread updater.play(); } } -- TestView.fxml http://javafx.com/fxml/1"; fx:controller="TestView"> On Sat, 20 Jan 2024 17:08:41 +0200, Nir Li
Re: HEADS-UP: Threading restriction for Animation play, pause, stop now enforced USE CASE
Hi John Thank you for the hypothetical receivers array scenario, I think it explains the problem exactly and is why replacing the array with CopyOnWriteArrayList removes the NPE. Your perspective then is that AbstractPrimaryTimer is designed for single threaded use only. If that is indeed so, then could you please explain the purpose of the receiversLocked and animationTimersLocked flags, as well as the point of receivers.clone() and animationTimers.clone() all of which indicate to the contrary. Thanks, regards Jurgen On Tue, 23 Jan 2024 18:36:16 +0200, John Hendrikx wrote: On 23/01/2024 16:56, Jurgen Doll wrote: Hi John and others, I don't think we are entirely on the same page, so here's the objective. The Goal: To determine if the FX animation thread and a SINGLE other thread can access Animation in a >>safe manner wrt play, stop, and resume. The number of threads is irrelevant really, it's either thread safe or it isn't. Non Goal: Multi-threaded access of Animation play, stop, and resume is NOT a goal. Wrt play() and resume(), it is ALWAYS safe to call them on a background thread because at this point the >>Animation isn't being processed by the FX thread as the "Animation" isn't contained in the >>AbstractPrimaryTimer receivers array. I'm afraid that is incorrect. The fact that your animation is not running doesn't mean that AbstractPrimaryTimer isn't in use by other >animations that are running. These other animations are using the receivers array, and may be modifying it or reading from it from the FX >thread. When you start your animation on a different thread, you are accessing these fields with a different thread, and modifying them. Since the >JVM is free to cache values and do other fancy things (like reordering read/writes) in the absence of synchronized/locking, there is no >guarantee that the FX thread will see those modifications until these are flushed to main memory (or caches are synced). Even then, the FX >thread may have these values cached somewhere, and so it may not go all the way to main memory to see if its assumptions are now >incorrect. The only way to ensure this is with proper use of synchronization. So a hypothetical scenario: - AbstractPrimaryTimer has no receivers - A receiver is added via the FX thread, slot 0 is now filled and receiversLength is now 1. Due to cache lines being large, it also read slot 1 >(which is null) - You start your animation on another thread. Since you didn't see the receivers array yet, you may see one of these states: - The change from the FX thread was flushed to main memory, and you see [X, null] and receiversLength = 1 - The change from the FX thread was partially flushed, and you see [X, null] and receiversLength = 0 (!!) - Nothing was flushed yet, and you see [null, null] and receiversLength = 0 Now, you can see that it would be very dangerous to proceed to modify the array based on half flushed information. Something similar >happens when you are the first to start an animation, and then another is started later. If the changes of your thread are not flushed yet (or >partially) then the FX thread will act on partially flushed data, or even see no receivers yet at all... --John
Re: HEADS-UP: Threading restriction for Animation play, pause, stop now enforced USE CASE
Hi John and others, I don't think we are entirely on the same page, so here's the objective. The Goal: To determine if the FX animation thread and a SINGLE other thread can access Animation in a safe manner wrt play, stop, and resume. Non Goal: Multi-threaded access of Animation play, stop, and resume is NOT a goal. Wrt play() and resume(), it is ALWAYS safe to call them on a background thread because at this point the Animation isn't being processed by the FX thread as the "Animation" isn't contained in the AbstractPrimaryTimer receivers array. Wrt stop() from what I can tell there are no shared method calls that need synchronization (see audit below), however the following two boolean flags should be marked as volatile in order to ensure that animation is cut short if executing: TimelineClipCore.abort ClipEnvelope.abort This is simple enough to add to my original proposal of replacing the arrays in AbstractPrimaryTimer with CopyOnWriteArrayList which is thread safe and replicates the intended behavior in a clear and concise way. Here are the methods that are called when stop() is invoked: Timeline.stop() getStatus() clipCore.abort() isStopped() clipEnvelope.abortCurrentPulse() doStop() timer.removePulseReceiver(pulseReceiver); // After this point it doesn't matter setStatus(Status.STOPPED) doSetCurrentRate(0.0) jumpTo(Duration.ZERO) And for AbstractPrimaryTimer.timePulseImpl: AbstractPrimaryTimer.timePulseImpl Animation.PulseReceiver.timePulse Animation.doTimePulse clipEnvelope.timePulse animation.doPlayTo clipCore.playTo visitKeyFrame setTime animation.setCurrentTicks clipInterpolator.interpolate animation.doJumpTo sync(false) setCurrentTicks clipCore.jumpTo timeline.getStatus() clipInterpolator.interpolate Regards Jurgen On Tue, 23 Jan 2024 01:52:42 +0200, John Hendrikx wrote: This is not a good idea, the NPE is a symptom of the problem, but there can be many more subtler problems (and new ones may surface after >fixing the NPE) that can affect other animations making use of the shared structures involved. For one thing, absent a method of >synchronization, Java doesn't even guarantee that fields (or arrays) contain the same value for all threads. So your thread may modify some >state, but the FX thread wouldn't even know about it (or only partially), and may make assumptions about an incorrect state, and then make >further changes based on incorrect assumptions. A good example is that even a much simpler class like HashMap when accessed by multiple threads can get into a really bad state. It will >usually throw a "ConcurrentModificationException" (or perhaps a weird NPE or IllegalStateException) to alert you that you're using it wrong >-- but those are the **best** case scenarios... In the worst case scenario, modifying a HashMap on multiple threads can result in an infinite >loop -- this can happen when two modifications occur, both updating the same bucket, and the threads end up changing things in such a way >that the entries point to each other. Iterating it then (or accessing the wrong key) will cause an infinite loop (not hypothetical, I've had this >happen). I'm afraid that even the synchronization option I proposed is not very realistic due to the amount of work it will entail. We'd need to trace all >code paths that a call to play or stop could get to, and all those code paths would need to be made thread safe. --John
Re: HEADS-UP: Threading restriction for Animation play, pause, stop now enforced
Hi Michael starting an animation on a background thread would only be safe if the object graph affected by the animation is not accessed on the background thread after calling the play() method. Any access may potentially corrupt internal state. Agreed. Actually we should drive this further and say that "No changes should be made to properties that are being 'animated' while animation is in progress regardless of whether you're on the FX thread or not, or if the object is in the scene graph or not". updater.play(); memoryLabel.setStyle( "-fx-text-fill: green" ); // This is OK memoryLabel.setText( "This is NOT okay" ); // This is NOT, move to before play Interesting API idea, however I don't think it's really needed for sensible developers. Regards Jurgen On Mon, 22 Jan 2024 22:53:48 +0200, Michael Strauß wrote: Hi Jurgen, starting an animation on a background thread would only be safe if the object graph affected by the animation is not accessed on the background thread after calling the play() method. Any access may potentially corrupt internal state. From what I can see in your example, you're not doing anything with TestView after starting the animation, so you should be good here. From an API perspective, I wonder if that makes it too easy to introduce subtle bugs into an application. As a general principle, I think an API should make it easy to do the right thing, and hard to do the wrong thing. Allowing potentially unsafe method calls without some explicit procedure (like wrapping the call in Platform.runLater) might not be a good idea. Maybe we should provide an API that allows developers to safely modify an object graph on a background thread and call Platform.runLater without worrying about concurrent modifications. Something like this: try (var scope = Platform.deferredScope()) { var updater = new Timeline( new KeyFrame(Duration.seconds(2.5), event -> { int maxMemory = ; int usedMemory = ; memoryLabel.setText(usedMemory + " MB / "+ maxMemory +" MB"); }) ); // This call will only be dispatched after the deferred scope is closed: scope.runLater(updater::play); // Still safe to call in the deferred scope, wouldn't be safe if // Platform.runLater had been called before: memoryLabel.setText("N/A"); }
Re: HEADS-UP: Threading restriction for Animation play, pause, stop now enforced USE CASE
I've been delving into the usage of `aborted` and `inTimePulse` as mentioned by John and gleaned the following: 1. stop makes a best effort to abort the 'animation' if it is in the process of execution. 2. `aborted` and `inTimePulse` are reset with every pulse. As to the options that John mentioned there's also a fourth: Accept my original proposal of fixing the NPE which is a known problem and not worry about potential synchronization issues. I mean does it really matter if play, stop, or pause miss a beat due to synchronization, as the API does say this could happen. Furthermore it doesn't appear as though the animation code can be left in some strange inconsistent state as a result of this. Jurgen On Mon, 22 Jan 2024 17:58:20 +0200, John Hendrikx wrote: This seems like a reasonable use case, and perhaps this was the original intent of the "asynchronous call" documentation. The problem though is that the play/stop code does not seem to take into account being called from a different thread (there are several >synchronization issues when I delved into that code). So then there's a choice to make I think, either: - Disallow it completely, and have users wrap it into Platform.runLater() - Have play/stop do the wrapping itself - Make the methods thread safe by fixing the synchronization issues --John
HEADS-UP: Threading restriction for Animation play, pause, stop now enforced USE CASE
Here's an example as requested by Nir: public class FxTimeLineTest extends Application { private BorderPane bp = new BorderPane( new Label("Loading") ); public static void main( String[] args ) { launch( FxTimeLineTest.class, args ); } @Override public void start( Stage primaryStage ) throws Exception { new Thread( new LoadScene() ).start(); primaryStage.setScene( new Scene( bp, 300, 200 ) ); primaryStage.setTitle( "Memory Usage" ); primaryStage.show(); } private class LoadScene extends Task { @Override protected Parent call() throws Exception { Parent p = FXMLLoader.load( getClass().getResource("TestView.fxml") ); Thread.sleep( 1000 ); return p; } @Override protected void succeeded() { bp.setCenter( getValue() ); } @Override protected void failed() { getException().printStackTrace(); } } } -- public class TestView { @FXML private Label memory; private static final double MEGABYTE = 1024 * 1024; @FXML private void initialize() { var updater = new Timeline ( new KeyFrame( Duration.seconds(2.5), event -> { var runtime = Runtime.getRuntime(); double maxMemory = runtime.maxMemory() / MEGABYTE; double usedMemory = (runtime.totalMemory() - runtime.freeMemory()) / MEGABYTE; memory.setText( (int) usedMemory + " MB / " + (int) maxMemory +" MB" ); }) ); updater.setCycleCount(Animation.INDEFINITE); // This FXML is being loaded on a background thread updater.play(); } } -- TestView.fxml http://javafx.com/fxml/1"; fx:controller="TestView"> On Sat, 20 Jan 2024 17:08:41 +0200, Nir Lisker wrote: Hi Jurgen, What I'm confused about the most is what it is you are actually trying to do that necessitates the use of animations outside of the FX thread. >You said that you need to initialize controls on another thread, and that you are using Task (both of which are fine), but how does playing >animations relate? Playing an animation is something that is done explicitly, usually in order to manipulate data. Can you give a real use >case, like a minimized version of what you're doing? - Nir
Re: HEADS-UP: Threading restriction for Animation play, pause, stop now enforced
Hi Michael It seems we are misunderstanding one another. Firstly I agree that the animation code itself must and always has run only on the FX thread. So for example in the following code: new KeyFrame( Duration.seconds(2.5), event -> { int maxMemory = ; int usedMemory = ; memoryLabel.setText( usedMemory +" MB / "+ maxMemory +" MB" ); }) The lambda part ALWAYS executes on the FX thread by default, no matter on which thread this KeyFrame is created. And we all agree that the following is ILLEGAL: new KeyFrame( Duration.seconds(2.5), event -> { new Thread( () -> memoryLabel.setText( usedMemory +" MB / "+ maxMemory +" MB" ) ).start(); }) With the above clarified, what I'm contending is that the following can be excuted on any thread: var updater = new Timeline ( new KeyFrame( Duration.seconds(2.5), event -> { int maxMemory = ; int usedMemory = ; memoryLabel.setText( usedMemory +" MB / "+ maxMemory +" MB" ); }) ); updater.setCycleCount(Animation.INDEFINITE); updater.play(); The reason is because play, stop, and pause simply causes the Timeline to be added too or removed from an array in AbstractPrimaryTimer. If a pulse is busy executing so that the array is currently being accessed by the FX thread then a copy of the array is made and the addition/removal is made to the copy. (However there is a bug in this code that causes an NPE under certain conditions.) So when the API documentation says that it's asynchronous it means that the 'animation' execution may not yet have started/stopped when the call returns depending on when during the pulse the method was invoked. If play is invoked just before the next pulse then the 'animation' could be running, or if stop is invoked just as a pulse completes then it will not be executing. Otherwise the 'animation' will only actually be (not) executing in the next pulse. Hope this clarifies things. Regards Jurgen
Re: HEADS-UP: Threading restriction for Animation play, pause, stop now enforced
Hi Kevin I was hoping that others would way in on this fix (PR #1167), but now that we're in RDP1 with no other input coming in I decided to looked into this matter again and have found that this is not the correct solution for the following two reasons: 1. The current solution doesn't actually fix the bug, but merely avoids it: Specifically with regards to bug JDK-8159048 which reports a NPE occuring under some conditions in AbstractMasterTimer (subsequently renamed to AbstractPrimaryTimer). The reporter suggests that this is as a result of some concurrent modification occurring and suggests a workaround of wrapping the start/stop animation code in a Platform.runLater() call. Looking at the AbstractPrimaryTimer code it is apparent that the original author made an effort to isolate array modifications from array access. However this code has a bug in it which then manifests as a NPE under the right timing conditions. So the correct solution is to make the array modification code more robust, as apposed to forcing changes to occur on a single thread. The safest (and proper) solution is to convert the two arrays ("receivers" and "animationTimers") to be CopyOnWriteArrayList(s) which is an ideal JDK data structure for this use case as it replicates the intended behavior of the current implementation. (I've tried this out and it does solve the NPE problem.) 2. The current solution is based on the misconception that start, stop, and pause must occur on the FX thread: Specifically with regards to the CSR JDK-8313378 which makes this claim. Firstly the Animation API says explicitly that these methods are asynchronous, which means that the thread that invokes these methods and the actual execution of the animation occurs on different threads, and looking at AbstractPrimaryTimer code it can be seen that this is indeed the case. Secondly JavaFX had tests, as noted in JDK-8314266, that have run reliably for years without invoking these methods on the FX thread. FWIW I've also had code and used libraries for years now, where these methods have been invoked on a background thread (for example while loading FXML) without issue. In conclusion then I request permission to submit a new PR containing the following changes: 1. Revert PR #1167 (if this is the appropriate place, however the test case will require it) 2. Changing the arrays in AbstractPrimaryTimer to be CopyOnWriteArrayList(s) and removing previously supporting array code. 3. Adding a test based on the one supplied in JDK-8159048 to check that a NPE isn't thrown anymore. Hope this meets with your approval. Regards, Jurgen On 8/18/2023 4:17 PM, Kevin Rushforth wrote: As a heads-up for app developers who use JavaFX animation (including Animation, along with any subclasses, and AnimationTimer), a change went into the JavaFX 22+5 build to enforce that the play, pause, and stop methods must be called on the JavaFX Application thread. Applications should have been doing that all along (else they would have been subject to unpredictable errors), but for those who aren't sure, you might want to take 22+5 for a spin and see if you have any problems with your application. Please report them on the list if you do. See JDK-8159048 [1] and CSR JDK-8313378 [2] for more information on this change. Thanks. -- Kevin [1] https://bugs.openjdk.org/browse/JDK-8159048 [2] https://bugs.openjdk.org/browse/JDK-8313378
Re: HEADS-UP: Threading restriction for Animation play, pause, stop now enforced
Thanks for the heads-up Kevin, I gave it a spin and found that generally because I use Task to load my fxml views I had problems. Some of these I could resolve by wrapping the offending line with runlater in the fxml initialise method. This reminded me though of the days when Tooltips had to be wrapped as well and it felt wrong because generally a view may be constructed and modified on any thread as long as it's not yet attached to a Scene in a Window that is showing. This is highlighted further because I also have some third party controls and libraries that are being initialized as part of the view, which now just crash my application. This means that I cannot instantiate these controls or libraries on any thread I want but have to make sure its done on the FX thread, even though they're not attached to a Scene yet. As a possible solution I was wondering since the Animation API says that calls to play() and stop() are asynchronous if it wouldn't then be valid to instead of throwing an exception, if the call to it isn't being made on the FX thread, that it rather be delegated to the FX thread with for example something like: public abstract class Animation { public void play() { if ( Platform.isFxApplicationThread() ) playFX(); else Platform.runLater( () -> playFX() ); } private void playFX() { // previous play() code } } This would then prevent the NPE errors that sometimes occur but not put a burden on the existing code in the wild and allow views to be loaded with Task call() without worries. Thanks, regards Jurgen On 8/18/2023 4:17 PM, Kevin Rushforth wrote: As a heads-up for app developers who use JavaFX animation (including Animation, along with any subclasses, and AnimationTimer), a change went into the JavaFX 22+5 build to enforce that the play, pause, and stop methods must be called on the JavaFX Application thread. Applications should have been doing that all along (else they would have been subject to unpredictable errors), but for those who aren't sure, you might want to take 22+5 for a spin and see if you have any problems with your application. Please report them on the list if you do. See JDK-8159048 [1] and CSR JDK-8313378 [2] for more information on this change. Thanks. -- Kevin [1] https://bugs.openjdk.org/browse/JDK-8159048 [2] https://bugs.openjdk.org/browse/JDK-8313378
Re: HEADS-UP: Threading restriction for Animation play, pause, stop now enforced
Thanks for the heads-up Kevin, I gave it a spin and found that generally because I use Task to load my fxml views I had problems. Some of these I could resolve by wrapping the offending line with runlater in the fxml initialise method. This reminded me though of the days when Tooltips had to be wrapped as well and it felt wrong because generally a view may be constructed and modified on any thread as long as it's not yet attached to a Scene in a Window that is showing. This is highlighted further because I also have some third party controls and libraries that are being initialized as part of the view, which now just crash my application. This means that I cannot instantiate these controls or libraries on any thread I want but have to make sure its done on the FX thread, even though they're not attached to a Scene yet. As a possible solution I was wondering since the Animation API says that calls to play() and stop() are asynchronous if it wouldn't then be valid to instead of throwing an exception, if the call to it isn't being made on the FX thread, that it rather be delegated to the FX thread with for example something like: public abstract class Animation { public void play() { if ( Platform.isFxApplicationThread() ) playFX(); else Platform.runLater( () -> playFX() ); } private void playFX() { // previous play() code } } This would then prevent the NPE errors that sometimes occur but not put a burden on the existing code in the wild and allow views to be loaded with Task call() without worries. Thanks, regards Jurgen On 8/18/2023 4:17 PM, Kevin Rushforth wrote: As a heads-up for app developers who use JavaFX animation (including Animation, along with any subclasses, and AnimationTimer), a change went into the JavaFX 22+5 build to enforce that the play, pause, and stop methods must be called on the JavaFX Application thread. Applications should have been doing that all along (else they would have been subject to unpredictable errors), but for those who aren't sure, you might want to take 22+5 for a spin and see if you have any problems with your application. Please report them on the list if you do. See JDK-8159048 [1] and CSR JDK-8313378 [2] for more information on this change. Thanks. -- Kevin [1] https://bugs.openjdk.org/browse/JDK-8159048 [2] https://bugs.openjdk.org/browse/JDK-8313378
Comment for JDK-8289115 - Touch events are not dispatched after upgrade to FX17
Hi Could someone please add the following lines as comment to the issue JDK-8289115 (https://bugs.openjdk.org/browse/JDK-8289115) Thank you very much. @Praveen please have another look at Capture.pptx and you'll see that *ONLY* MouseEvents are being fired and NO TouchEvents. The test case illustrates exactly what the reporter describes as being the problem. So is reproducible. Note that this appears to be device INdependent, so any TouchScreen running Windows with either touch or pen/stylus, will show no TouchEvents are fired after jfx17-ea+2-win. This bug is a direct result of fixing JDK-8249737 RuntimeException: Too many touch points reported. (https://bugs.openjdk.java.net/browse/JDK-8249737) Please reopen both of these issues. Thanks, Jurgen
Comment for JDK-8289115 - Touch events are not dispatched after upgrade to FX17
Hi Could someone please add the following lines as comment to the issue JDK-8289115 (https://bugs.openjdk.org/browse/JDK-8289115) Thank you very much. @Praveen please have another look at Capture.pptx and you'll see that only MouseEvents are being fired and NO TouchEvents. The test case illustrates exactly what the reporter describes as being the problem. Note that this appears to be device INdependent, so any TouchScreen running Windows with either touch or pen/stylus and no TouchEvents are fired after jfx17-ea+2-win. This bug is a direct result of fixing JDK-8249737 RuntimeException: Too many touch points reported. (https://bugs.openjdk.java.net/browse/JDK-8249737) Please reopen both of these issues. Thanks, Jurgen