Merge branch 'fix/workspace-indicator-dot-animation' into 'main'

fix: workspace indicator dots

See merge request june/top-bar-organizer!4
This commit is contained in:
Ben Leppke 2026-10-28 15:58:15 +00:00
commit a59050e438

View file

@ -125,8 +125,8 @@ export default class TopBarOrganizerExtension extends Extension {
/// Go through the items of the validBoxOrder and order the GNOME Shell
/// top bar box accordingly.
for (let i = 0; i < validBoxOrder.length; i++) {
const item = validBoxOrder[i];
const indicatorContainers: St.Bin[] = [];
for (const item of validBoxOrder) {
// Get the indicator container associated with the current role.
const associatedIndicatorContainer = (Main.panel.statusArea as any)[item.role]?.container;
if (!(associatedIndicatorContainer instanceof St.Bin)) {
@ -134,29 +134,23 @@ export default class TopBarOrganizerExtension extends Extension {
continue;
}
indicatorContainers.push(associatedIndicatorContainer);
// Save whether or not the indicator container is visible.
const isVisible = associatedIndicatorContainer.visible;
// Only remove the indicator container from its current parent if
// it actually changes boxes. `remove_child()` stops all running
// transitions on the removed actor and its children (the default
// remove-child flags include `REMOVE_CHILD_STOP_TRANSITIONS`).
// Detaching e.g. the "activities" indicator container while GNOME
// Shell animates in a new workspace dot stops that animation,
// leaving the dot invisible or incorrectly sized until the next
// workspace change.
if (associatedIndicatorContainer.get_parent() !== panelBox) {
const parent = associatedIndicatorContainer.get_parent();
if (parent !== null) {
parent.remove_child(associatedIndicatorContainer);
}
if (box === "right") {
// If the target panel box is the right panel box, insert the
// indicator container at index `-1`, which just adds it to the
// end (correct order is ensured, since `validBoxOrder` is
// sorted correctly and we're looping over it in order).
// This way unaccounted-for indicator containers will be at the
// left, which is preferred, since the box is logically
// right-to-left.
// The same applies for indicator containers, which are just
// temporarily unaccounted for (like for indicator containers of
// not yet ready app indicators), since them being at the right
// for a probably temporary stay causes all the indicator
// containers to shift.
parent?.remove_child(associatedIndicatorContainer);
panelBox.insert_child_at_index(associatedIndicatorContainer, -1);
} else {
panelBox.insert_child_at_index(associatedIndicatorContainer, i);
}
// Hide the indicator container...
@ -172,6 +166,24 @@ export default class TopBarOrganizerExtension extends Extension {
associatedIndicatorContainer.hide();
}
}
// Order the indicator containers by changing their indexes in place.
// `set_child_at_index()` is logically equivalent to removing and
// re-inserting an actor, but unlike `remove_child()` it does not change
// the actor's state or stop its transitions.
//
// For the right box, the first indicator container has to be placed at
// the beginning of the block of accounted-for indicator containers at
// the end of the box. This way unaccounted-for indicator containers
// (e.g. not yet ready app indicators) will be at the left, which is
// preferred, since the box is logically right-to-left. For the left and
// center box, the block starts at index 0.
const firstIndex = box === "right"
? panelBox.get_n_children() - indicatorContainers.length
: 0;
for (let i = 0; i < indicatorContainers.length; i++) {
panelBox.set_child_at_index(indicatorContainers[i], firstIndex + i);
}
// To handle the case, where the box order got set to a permutation
// of an outdated box order, it would be wise, if the caller updated the
// box order now to include the items present in the top bar.