diff --git a/src/main/java/org/igv/ui/IGV.java b/src/main/java/org/igv/ui/IGV.java index 4b54a54ea..4c5794cab 100644 --- a/src/main/java/org/igv/ui/IGV.java +++ b/src/main/java/org/igv/ui/IGV.java @@ -2164,10 +2164,8 @@ public void repaintHeaderPanels() { } - - private volatile boolean isLoading = false; - private Set pendingTracks = null; + private volatile boolean repaintPending = false; private final Object repaintLock = new Object(); private void repaint(final JComponent component, Collection trackList) { @@ -2195,28 +2193,32 @@ private void repaint(final JComponent component, Collection tra } else { + // Hold lock for the entire check-and-set operation to prevent race conditions + List> futures; synchronized (repaintLock) { if (isLoading) { - // Track data is being loaded. Paint the component with available data and queue these tracks for - // the next repaint cycle - UIUtilities.invokeOnEventThread(contentPane::repaint); - if (pendingTracks == null) { - pendingTracks = new HashSet<>(); - } - pendingTracks.addAll(trackList); + // Track data is being loaded. Just flag that a repaint is needed when loading completes. + // Since repaint() has no state, we only need to know that *a* repaint was requested. + repaintPending = true; return; } - } - // Not currently loading - // Find tracks that need loading (not ready to paint) - List> futures = new ArrayList<>(); - for (ReferenceFrame frame : FrameManager.getFrames()) { - for (Track track : trackList) { - if (!track.isReadyToPaint(frame)) { - futures.add(CompletableFuture.runAsync(() -> track.load(frame), threadExecutor)); + // Not currently loading - find tracks that need loading (not ready to paint) + futures = new ArrayList<>(); + for (ReferenceFrame frame : FrameManager.getFrames()) { + for (Track track : trackList) { + if (!track.isReadyToPaint(frame)) { + futures.add(CompletableFuture.runAsync(() -> track.load(frame), threadExecutor)); + } } } + + if (futures.isEmpty()) { + // All tracks are ready to paint - no need to set isLoading + } else { + // One or more tracks require loading before repaint - set loading flag while holding lock + isLoading = true; + } } if (futures.isEmpty()) { @@ -2225,16 +2227,11 @@ private void repaint(final JComponent component, Collection tra UIUtilities.invokeOnEventThread(() -> { checkPanelLayouts(); component.repaint(); - }); return; } - - // One or more tracks require loading before repaint. - synchronized (repaintLock) { - isLoading = true; - } + // Loading is now in progress final WaitCursorManager.CursorToken token = WaitCursorManager.showWaitCursor(); CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).whenComplete((ignored, ex) -> { @@ -2244,12 +2241,12 @@ private void repaint(final JComponent component, Collection tra log.error("Error loading track data", ex); } - // Collect pending tracks and reset state under lock - Set tracksToRepaint; + // Check if a repaint was requested while loading, and reset state under lock + boolean needsRepaint; synchronized (repaintLock) { isLoading = false; - tracksToRepaint = pendingTracks; - pendingTracks = null; + needsRepaint = repaintPending; + repaintPending = false; } // Autoscale (modifies track internal state, not UI) @@ -2258,11 +2255,11 @@ private void repaint(final JComponent component, Collection tra // Check layouts and repaint on EDT UIUtilities.invokeOnEventThread(() -> { checkPanelLayouts(); - if (tracksToRepaint != null && !tracksToRepaint.isEmpty()) { - // Pending tracks exist - repaint will be called by the recursive invocation - repaint(component, tracksToRepaint); - } else { - component.repaint(); + component.repaint(); + // If a repaint was requested while loading, trigger another repaint cycle + // to load any new data that may be needed + if (needsRepaint) { + repaint(component, getAllTracks()); } }); }); @@ -2270,10 +2267,14 @@ private void repaint(final JComponent component, Collection tra } } + /** + * Check if any track panels need layout revalidation due to height changes. + * Note: This method should be called from the EDT. + */ private void checkPanelLayouts() { for (TrackPanel tp : getTrackPanels()) { if (tp.isHeightChanged()) { - UIUtilities.invokeOnEventThread(() -> tp.revalidate()); + tp.revalidate(); } } } diff --git a/src/main/java/org/igv/ui/panel/RulerPanel.java b/src/main/java/org/igv/ui/panel/RulerPanel.java index f0f9a1100..eb3557fc5 100644 --- a/src/main/java/org/igv/ui/panel/RulerPanel.java +++ b/src/main/java/org/igv/ui/panel/RulerPanel.java @@ -55,8 +55,6 @@ public class RulerPanel extends JPanel { public static final String CHROM_TOOLTIP = "Click and drag to zoom in."; - private final boolean darkMode; - boolean drawSpan = true; private Font tickFont = FontManager.getFont(10); private Font spanFont = FontManager.getFont(Font.BOLD, 12); @@ -68,10 +66,8 @@ public class RulerPanel extends JPanel { private Color collapsedInsertionColor = Color.BLACK; private Color zoomedoutInsertionColor = ColorUtilities.modifyAlpha(Color.LIGHT_GRAY, 50); - private boolean showInsertions = false; private List clickLinks = new ArrayList(); - boolean dragging = false; int dragStart; int dragEnd; @@ -81,7 +77,6 @@ public class RulerPanel extends JPanel { public RulerPanel(ReferenceFrame frame) { this.frame = frame; - this.darkMode = Globals.isDarkMode(); init(); } @@ -262,10 +257,7 @@ private void render(Graphics g) { Collection tracks = IGV.getInstance().getAlignmentTracks(); int maxVizWindow = tracks.size() == 0 ? 0 : tracks.stream().mapToInt(t -> t.getVisibilityWindow()).max().getAsInt(); if (!frame.getChrName().equals(Globals.CHR_ALL) && (frame.getEnd() - frame.getOrigin()) <= maxVizWindow) { - showInsertions = true; drawInsertionMarkers(g); - } else { - showInsertions = false; } } } @@ -420,9 +412,7 @@ private void drawChromosomeTicks(Graphics g) { frame.changeChromosome((String) ch, true); })); } - even = !even; - } } } diff --git a/test/sessions/100_bigwigs.xml b/test/sessions/100_bigwigs.xml index b640f1fb7..532326a11 100644 --- a/test/sessions/100_bigwigs.xml +++ b/test/sessions/100_bigwigs.xml @@ -1,108 +1,108 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + + - - - - + + + + + + - - - - - + + + + - - + + + - - - - - - - - + + - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + - - - - + + + + - + + - - - - - - - - - - - + + + + + + - - - - - - - - + + - - + + + + + + + + + + + + + - + @@ -404,11 +404,11 @@ - + - +