If there's an agreement, I can do it tomorrow. It will effectively revert JDK-8159048 and supersede JDK-8324219.
On Wed, Jan 24, 2024 at 8:42 PM Kevin Rushforth <kevin.rushfo...@oracle.com> wrote: > I also now favor option 2 and was in the process of writing something up > recommending that we do that. Phil and I (and a couple others) had an > offline discussion and think this is the way to go. > > Given the short amount of time to get this into 22, I will file the JBS > issue in the next hour or so. > > Nir: if you want to take it, that would be great. Otherwise, I will do it. > We need the PR and CSR filed before the end of this week. > > Regarding other methods that choose option 1, many of them are more > complicated (e.g., scene mutation can be done on a background thread as > long as the scene is not "showing") or must be synchronous. Animation > starts something that conceptually happens later on the FX animation thread > anyway, so wrapping it in a runLater (if not already on the right thread) > doesn't really change the semantics in an appreciable way. > > -- Kevin > > > On 1/24/2024 10:26 AM, Nir Lisker wrote: > > These are the options I see as reasonable: > > 1. Document that these methods *must* be run on the FX thread and throw an > exception otherwise. This leaves it to the responsibility of the user. > However, this will cause the backwards compatibility problems that Jugen > brought up. As a side note, we do this in other methods already, but I > always questioned why let the developer do something illegal - if there's > only one execution path, force it. > 2. Document that these methods *are* run on the FX thread (the user > doesn't need to do anything) and change the implementation to call > runLater(...) internally unless they are already on the FX thread. This > will be backwards compatible for the most part (see option 3). The downside > might be some surprise when these methods behave differently. > 3. Document that it's *recommended* that these methods be run on the FX > thread and let the user be responsible for the threading. We can explain > that manipulating nodes that are attached to an active scenegraph should be > avoided. > > I prefer option 2 over 1 regardless of the backwards compatibility issue > even, but would like to know if I'm missing something here because in > theory this change could be done to any "must run on the FX thread" method > and I question why the user had the option to get an exception. > Option 3 is risky and I wager a guess that it will be used wrongly more > often than not. It does allow some (what I would call) valid niche uses. I > never did it. > > On Wed, Jan 24, 2024 at 4:21 PM Kevin Rushforth < > kevin.rushfo...@oracle.com> wrote: > >> I'd like to hear from the others on this. I don't see any fundamental >> problem with having the play/pause/stop methods wrap their implementation >> in a runLater (if not on the FX Application thread already), and >> documenting that it does so, if we can get general agreement. >> >> -- Kevin >> >> >> On 1/24/2024 5:29 AM, Jurgen Doll wrote: >> >> 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 >> <kevin.rushfo...@oracle.com> <kevin.rushfo...@oracle.com> 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 >> <https://urldefense.com/v3/__https://github.com/openjdk/jfx/pull/1342__;!!ACWV5N9M2RV99hQ!PLtaZAvaobOk-fe_DRSy2AHiPOFUaK683TVXWIvmjnTiUGhmBp3x_GIy_wlMuEV3IHTUMx37HxJHiVuWiFRR$> >> >> -- 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 <jav...@ivoryemr.co.za> 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<Parent> { >>> >>> @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 >>> >>> <?xml version="1.0" encoding="UTF-8"?> >>> >>> <?import javafx.scene.control.Label?> >>> >>> <?import javafx.scene.layout.StackPane?> >>> >>> <StackPane xmlns:fx="http://javafx.com/fxml/1 >>> <https://urldefense.com/v3/__http://javafx.com/fxml/1__;!!ACWV5N9M2RV99hQ!PLtaZAvaobOk-fe_DRSy2AHiPOFUaK683TVXWIvmjnTiUGhmBp3x_GIy_wlMuEV3IHTUMx37HxJHia1cBAoi$>" >>> fx:controller="TestView"> >>> >>> <children> >>> >>> <Label fx:id="memory" text="Current / Max MB" > >>> >>> <properties hashCode="12345" /> >>> >>> </Label> >>> >>> </children> >>> >>> </StackPane> >>> >>> >>> >>> On Sat, 20 Jan 2024 17:08:41 +0200, Nir Lisker <nlis...@gmail.com> >>> 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 >>> >>> >> >> >> >> -- >> Using Opera's mail client: http://www.opera.com/mail/ >> <https://urldefense.com/v3/__http://www.opera.com/mail/__;!!ACWV5N9M2RV99hQ!PLtaZAvaobOk-fe_DRSy2AHiPOFUaK683TVXWIvmjnTiUGhmBp3x_GIy_wlMuEV3IHTUMx37HxJHifb0G69Z$> >> >> >> >