9038f4eb6850293b6fd7ca30be86637c1040c4e7
galt
  Fri Jun 27 11:55:57 2025 -0700
Fixing issue with hideEmptySubtracks so it considers counts of all the windows in multi-region. This bug has existed since Kate added the feature. fixes #35472

diff --git src/hg/hgTracks/hgTracks.c src/hg/hgTracks/hgTracks.c
index cb50e894cbc..9d8dbbd4ced 100644
--- src/hg/hgTracks/hgTracks.c
+++ src/hg/hgTracks/hgTracks.c
@@ -4637,30 +4637,42 @@
 return TRUE;
 
 }
 
 boolean isLimitedVisHiddenForAllWindows(struct track *track)
 /* Check if track limitedVis == hidden for all windows.
  * Return true if all are hidden */
 {
 boolean result = TRUE;
 for(;track;track=track->nextWindow)
     if (track->limitedVis != tvHide)
 	result = FALSE;
 return result;
 }
 
+boolean anyWindowHaveItems(struct track *track)
+/* Check if track limitedVis == hidden for all windows.
+ * Return true if all are hidden */
+{
+for(;track;track=track->nextWindow)
+    {
+    if (slCount(track->items) > 0)
+	return TRUE;
+    }
+return FALSE;
+}
+
 boolean isTypeBedLike(struct track *track)
 /* Check if track type is BED-like packable thing (but not rmsk or joinedRmsk) */
 { // TODO GALT do we have all the types needed?
 // TODO could it be as simple as whether track->items exists?
 char *typeLine = track->tdb->type, *words[8], *type;
 int wordCount;
 if (typeLine == NULL)
     return FALSE;
 wordCount = chopLine(cloneString(typeLine), words);
 if (wordCount <= 0)
     return FALSE;
 type = words[0];
 // NOTE: if type is missing here, full mode fails to return an hgTracks object
 if (
 (  sameWord(type, "bed")
@@ -5134,32 +5146,33 @@
         {
         struct track *subtrack;
         if (isCompositeInAggregate(track))
             addPreFlatTrack(&preFlatTracks, track);
         else
             {
             boolean doHideEmpties = doHideEmptySubtracksNoMultiBed(cart, track);
                 // If multibed was found, it has been used to suppress loading,
                 // and subtracks lacking items in window are already set hidden
             for (subtrack = track->subtracks; subtrack != NULL; subtrack = subtrack->next)
                 {
                 if (!isSubtrackVisible(subtrack))
                     continue;
 
                 if (!isLimitedVisHiddenForAllWindows(subtrack) && 
-                        !(doHideEmpties && slCount(subtrack->items) == 0))
-                        // Ignore subtracks with no items in window
+                        !(doHideEmpties && !anyWindowHaveItems(subtrack)))
+                        // Ignore subtracks with no items in windows
+
                     {
                     addPreFlatTrack(&preFlatTracks, subtrack);
                     }
                 }
             }
         }
     else
 	{	
         addPreFlatTrack(&preFlatTracks, track);
 	}
     }
 slReverse(&preFlatTracks);
 
 // check total height
 #define MAXSAFEHEIGHT "maxTrackImageHeightPx"
@@ -8665,31 +8678,31 @@
 zoomedToCodonLevel = (ceil(virtWinBaseCount/3) * tl.mWidth) <= fullInsideWidth;
 zoomedToCodonNumberLevel = (ceil(virtWinBaseCount/3) * tl.mWidth * 5) <= fullInsideWidth;
 zoomedToCdsColorLevel = (virtWinBaseCount <= fullInsideWidth*3);
 
 if (psOutput != NULL)
    {
    hPrintDisable();
    hideControls = TRUE;
    withNextItemArrows = FALSE;
    withNextExonArrows = FALSE;
    hgFindMatches = NULL;
    }
 
 /* Tell browser where to go when they click on image. */
 hPrintf("<FORM ACTION=\"%s\" NAME=\"TrackHeaderForm\" id=\"TrackHeaderForm\" METHOD=\"GET\">\n\n", hgTracksName());
-jsonObjectAdd(jsonForClient, "insideX", newJsonNumber(insideX)); // TODO GALT  fullInsideX? or does not matter?
+jsonObjectAdd(jsonForClient, "insideX", newJsonNumber(insideX)); 
 jsonObjectAdd(jsonForClient, "revCmplDisp", newJsonBoolean(revCmplDisp));
 
 if (hPrintStatus()) cartSaveSession(cart);
 
 /* See if want to include sequence search results. */
 userSeqString = cartOptionalString(cart, "ss");
 if (userSeqString && !ssFilesExist(userSeqString))
     {
     userSeqString = NULL;
     cartRemove(cart, "ss");
     }
 if (!hideControls)
     hideControls = cartUsualBoolean(cart, "hideControls", FALSE);
 
 initTrackList();
@@ -8899,44 +8912,43 @@
 	    int pt;
 	    for (pt = 0; pt < ptMax; ++pt)
 		{
 		int rc = pthread_create(&threads[pt], NULL, remoteParallelLoad, NULL);
 		if (rc)
 		    {
 		    errAbort("Unexpected error %d from pthread_create(): %s",rc,strerror(rc));
 		    }
 		pthread_detach(threads[pt]);  // this thread will never join back with it's progenitor
 		    // Canceled threads that might leave locks behind,
 		    // so the theads are detached and will be neither joined nor canceled.
 		}
 	    }
 	}
 
-    // TODO GALT
     /* load regular tracks */
     for (track = trackList; track != NULL; track = track->next)
 	{
 	if (track->visibility != tvHide)
 	    {
             if (!track->parallelLoading)
 		{
 		if (measureTiming)
 		    lastTime = clock1000();
 
 		checkMaxWindowToDraw(track);
 
-		checkHideEmptySubtracks(track);     // TODO: Test with multi-window feature
+		checkHideEmptySubtracks(track);
 
 		checkIfWiggling(cart, track);
 
 		if (!loadHack)
 		    {
 		    track->loadItems(track);
                     if (tdbHasDecorators(track))
                         {
                         loadDecorators(track);
                         decoratorMethods(track);
                         }
 		    }
 		else
 		    {
 		    // TEMP HACK GALT REMOVE