Skip to content

Fix menu misalignment on first open after login#13786

Open
H09-0 wants to merge 1 commit into
linuxmint:masterfrom
H09-0:fix/menu-first-position
Open

Fix menu misalignment on first open after login#13786
H09-0 wants to merge 1 commit into
linuxmint:masterfrom
H09-0:fix/menu-first-position

Conversation

@H09-0
Copy link
Copy Markdown

@H09-0 H09-0 commented May 28, 2026

Summary

Fix #13780 - the menu appears at the wrong horizontal position on the
first click after login, then snaps to the correct position ~1 second
later.

Root cause

Two interacting defects in js/ui/popupMenu.js open():

1. Animation path: _allocationChanged blocked during animation

The _allocationChanged handler is guarded by !this.animating (line 2128).
When animation is enabled and open() runs:

  1. this.animating = true is set (line 1851)
  2. _calculatePosition() runs but the menu layout is incomplete - the
    applet's _onOpenStateChanged only shows INITIAL_BUTTON_LOAD buttons
    synchronously and defers the rest via Mainloop.idle_add (applet.js:1554)
  3. When deferred buttons appear, the allocation changes, but
    _allocationChanged bails because animating is still true
  4. Only after animation completes and animating = false does the next
    allocation change trigger _allocationChanged - the ~1 second snap

2. Non-animation path: separate x/y assignment races

With this.actor.x = xPos; this.actor.y = yPos;, setting x fires
notify::allocation -> _allocationChanged -> set_position(x', y'),
then this.actor.y = yPos overwrites the corrected Y with the stale value.

Fix (3 insertions, 2 deletions in popupMenu.js)

Change 1 - Animation path onComplete (line 1859-1862)

onComplete: () => {
    this.animating = false;
    let [xPos, yPos] = this._calculatePosition();
    this.actor.set_position(xPos, yPos);
}

Recalculates and sets the correct position the instant the animation
finishes, no longer relying on a delayed _allocationChanged.

Change 2 - Non-animation path (line 1893-1896)

this.actor.set_position(xPos, yPos);

Atomic set eliminates the race between separate x/y assignments and the
synchronous _allocationChanged they trigger.

Testing

  1. Centre menu button on panel, reboot, click menu - correct on first click
  2. No visual diff on subsequent opens
  3. Test with animations enabled and disabled
  4. Test with side-panel layouts

Side effects

None. Adds a position recalibration at the natural completion point of the
animation (idempotent). Replaces racy two-step assignment with an atomic
call already used in this class (shiftToPosition, _allocationChanged).

- Add _calculatePosition() + set_position() in onComplete of the
  animation path to ensure the menu snaps to the correct position
  immediately after the visual transition finishes. Without this,
  _allocationChanged is blocked by this.animating during the
  animation, so any deferred layout changes (e.g. app buttons
  shown via Mainloop.idle_add) cannot correct the position until
  after the animation ends and the next allocation change fires.
- Replace separate this.actor.x / this.actor.y assignments with
  this.actor.set_position() in the non-animation path to avoid a
  race where setting x triggers _allocationChanged synchronously,
  which calls set_position(), and then the subsequent y assignment
  overwrites the corrected Y coordinate with the stale value.

Closes linuxmint#13780
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Menu shifts when opened the first time

1 participant