1515import java .util .concurrent .atomic .AtomicReference ;
1616import java .util .logging .Level ;
1717
18+ import javafx .application .Platform ;
1819import org .csstudio .display .builder .model .DirtyFlag ;
1920import org .csstudio .display .builder .model .DisplayModel ;
2021import org .csstudio .display .builder .model .UntypedWidgetPropertyListener ;
@@ -256,7 +257,7 @@ private void fileChanged(final WidgetProperty<?> property, final Object old_valu
256257
257258 /** Update to the next pending display
258259 *
259- * <p>Synchronized to serialize the background threads.
260+ * <p>Executed on the JavaFX Application Thread to serialize the background threads.
260261 *
261262 * <p>Example: Displays A, B, C are requested in quick succession.
262263 *
@@ -270,65 +271,56 @@ private void fileChanged(final WidgetProperty<?> property, final Object old_valu
270271 * As thread C finally continues, it finds pending_display_and_group empty.
271272 * --> Showing A, then C, skipping B.
272273 */
273- private synchronized void updatePendingDisplay (final JobMonitor monitor )
274- {
275- try
276- {
277- final DisplayAndGroup handle = pending_display_and_group .getAndSet (null );
278- if (handle == null )
279- {
280- // System.out.println("Nothing to handle");
281- return ;
282- }
283- if (inner == null )
284- {
285- // System.out.println("Aborted: " + handle);
286- return ;
287- }
274+ private void updatePendingDisplay (final JobMonitor monitor ) {
275+ Platform .runLater (() -> {
276+ try {
277+ final DisplayAndGroup handle = pending_display_and_group .getAndSet (null );
278+ if (handle == null ) {
279+ // System.out.println("Nothing to handle");
280+ return ;
281+ }
282+ if (inner == null ) {
283+ // System.out.println("Aborted: " + handle);
284+ return ;
285+ }
288286
289- monitor .beginTask ("Load " + handle );
290- try
291- { // Load new model (potentially slow)
292- final DisplayModel new_model = loadDisplayModel (model_widget , handle );
287+ monitor .beginTask ("Load " + handle );
288+ try { // Load new model (potentially slow)
289+ final DisplayModel new_model = loadDisplayModel (model_widget , handle );
293290
294- // Stop (old) runtime
295- // EmbeddedWidgetRuntime tracks this property to start/stop the embedded model's runtime
296- model_widget .runtimePropEmbeddedModel ().setValue (null );
291+ // Stop (old) runtime
292+ // EmbeddedWidgetRuntime tracks this property to start/stop the embedded model's runtime
293+ model_widget .runtimePropEmbeddedModel ().setValue (null );
297294
298- // Atomically update the 'active' model
299- final DisplayModel old_model = active_content_model .getAndSet (new_model );
300- new_model .propBackgroundColor ().addUntypedPropertyListener (backgroundChangedListener );
295+ // Atomically update the 'active' model
296+ final DisplayModel old_model = active_content_model .getAndSet (new_model );
297+ new_model .propBackgroundColor ().addUntypedPropertyListener (backgroundChangedListener );
301298
302- if (old_model != null )
303- { // Dispose old model
299+ if (old_model != null ) { // Dispose old model
300+ final Future <Object > completion = toolkit .submit (() ->
301+ {
302+ toolkit .disposeRepresentation (old_model );
303+ return null ;
304+ });
305+ checkCompletion (model_widget , completion , "timeout disposing old representation" );
306+ }
307+ // Represent new model on UI thread
308+ toolkit .onRepresentationStarted ();
304309 final Future <Object > completion = toolkit .submit (() ->
305310 {
306- toolkit . disposeRepresentation ( old_model );
311+ representContent ( new_model );
307312 return null ;
308313 });
309- checkCompletion (model_widget , completion , "timeout disposing old representation" );
314+ checkCompletion (model_widget , completion , "timeout representing new content" );
315+ // Allow EmbeddedWidgetRuntime to start the new runtime
316+ model_widget .runtimePropEmbeddedModel ().setValue (new_model );
317+ } catch (Exception ex ) {
318+ logger .log (Level .WARNING , "Failed to handle embedded display " + handle , ex );
310319 }
311- // Represent new model on UI thread
312- toolkit .onRepresentationStarted ();
313- final Future <Object > completion = toolkit .submit (() ->
314- {
315- representContent (new_model );
316- return null ;
317- });
318- checkCompletion (model_widget , completion , "timeout representing new content" );
319-
320- // Allow EmbeddedWidgetRuntime to start the new runtime
321- model_widget .runtimePropEmbeddedModel ().setValue (new_model );
320+ } finally {
321+ toolkit .onRepresentationFinished ();
322322 }
323- catch (Exception ex )
324- {
325- logger .log (Level .WARNING , "Failed to handle embedded display " + handle , ex );
326- }
327- }
328- finally
329- {
330- toolkit .onRepresentationFinished ();
331- }
323+ });
332324 }
333325
334326 /** @param content_model Model to represent */
@@ -471,26 +463,28 @@ else if (inner.getHeight() != 0.0 && inner.getWidth() != 0.0)
471463 }
472464
473465 @ Override
474- public void dispose ()
475- {
476- // When the file name is changed, updatePendingDisplay()
477- // will atomically update the active_content_model,
478- // represent the new model, and then set runtimePropEmbeddedModel.
479- //
480- // Fetching the embedded model from active_content_model
481- // could dispose a representation that hasn't been represented, yet.
482- // Fetching the embedded model from runtimePropEmbeddedModel
483- // could fail to dispose what's just now being represented.
484- //
485- // --> Very unlikely to happen because runtime has been stopped,
486- // so nothing is changing the file name right now.
487- final DisplayModel em = active_content_model .getAndSet (null );
488- model_widget .runtimePropEmbeddedModel ().setValue (null );
489-
490- if (inner != null && em != null )
491- toolkit .disposeRepresentation (em );
492- inner = null ;
493-
494- super .dispose ();
466+ public void dispose () {
467+ Platform .runLater (() -> {
468+ // When the file name is changed, updatePendingDisplay()
469+ // will atomically update the active_content_model,
470+ // represent the new model, and then set runtimePropEmbeddedModel.
471+ //
472+ // Fetching the embedded model from active_content_model
473+ // could dispose a representation that hasn't been represented, yet.
474+ // Fetching the embedded model from runtimePropEmbeddedModel
475+ // could fail to dispose what's just now being represented.
476+ //
477+ // --> Very unlikely to happen because runtime has been stopped,
478+ // so nothing is changing the file name right now.
479+
480+ final DisplayModel em = active_content_model .getAndSet (null );
481+ model_widget .runtimePropEmbeddedModel ().setValue (null );
482+
483+ if (inner != null && em != null )
484+ toolkit .disposeRepresentation (em );
485+ inner = null ;
486+
487+ super .dispose ();
488+ });
495489 }
496490}
0 commit comments