Bug Description
The main menu (mintMenu / start menu) fails to render its open/close animation in certain scenarios. Instead of playing the expected slide+fade transition, the menu simply appears or disappears instantly.
Reproduction Steps
- Ensure animations are enabled: System Settings → Effects → "Enable animations" ON, "Menus" effect ON
- Click the main menu applet icon to open → the menu appears instantly, no open animation
- Click the menu icon again to close → the menu disappears instantly, no close animation
- Press Super/Meta key to open → same as step 2, no animation
- Press Super/Meta key again to close → same as step 3, no animation
- Click the menu open, then click anywhere outside the menu to close → close animation renders correctly ✅
- Compare with other panel menus (volume, network, calendar) — their animations always render correctly in all scenarios ✅
Observations
| Trigger |
Open animation |
Close animation |
| Click menu icon |
❌ Skipped |
❌ Skipped |
| Press Super/Meta |
❌ Skipped |
❌ Skipped |
| Click outside menu |
N/A |
✅ Renders correctly |
| Other panel menus (any trigger) |
✅ Always |
✅ Always |
- The bug is consistent, not intermittent — it reproduces every time
- The menu still opens and functions correctly; only the transition animation is missing
- Disabling and re-enabling animations in settings does not change behavior
- The bug persists across Cinnamon restarts (Ctrl+Alt+Esc)
Technical Analysis (Speculative)
After examining the Cinnamon source code, here is my understanding of the likely root cause:
Code paths involved
All triggers ultimately call the same animation methods in js/ui/popupMenu.js:
- Click icon / Super key →
menu@cinnamon.org on_applet_clicked() or overlay-key binding → menu.toggle_with_options(true) → open(true) / close(true)
- Click outside →
PopupMenuManager._onEventCapture() → _closeMenu() → close(true)
What I think is happening
The open(true) method (popupMenu.js line 2329) does:
this.actor.show(); // triggers layout of the entire menu tree
this.actor.opacity = 0; // animation start state
// set initial position with offset ...
this.actor.ease(easeParams); // start Clutter implicit transition
The main menu is unique among panel menus because:
- Large actor tree — It builds 100+ St actors (sidebar, search box, apps list, categories, favorites, recents, system buttons) all as children of
this.actor
- Heavy
_onOpenStateChanged callback — Immediately after open() emits open-state-changed (line 2419), the applet's handler (applet.js line 1418) does synchronous work: set_key_focus(this.searchEntry), shows 30 app buttons, and queues an idle callback to show the rest
- First-time layout cost — When
show() is called, Clutter must map, allocate, and apply CSS to the entire complex tree. On a system with hundreds of installed apps, this can be expensive
My hypothesis: when show() triggers the initial layout of the heavy tree, the actor may not yet be fully "realized" (backing texture ready) by the time ease() is called. Clutter's implicit transition system may not properly capture the initial property delta if the actor isn't in a fully ready rendering state, causing the transition to complete instantly (snap to final state).
This would explain why:
- Close via outside click works — the actor is already fully mapped and visible when
close(true) is called, so the transition starts from a clean state
- Other menus are unaffected — their actor trees are much smaller, so
show() completes before ease() starts
- The bug is consistent — it's a timing issue, not a race condition
An alternative hypothesis
The _onOpenStateChanged callback calls global.stage.set_key_focus(this.searchEntry) synchronously right after the animation starts. Changing keyboard focus can trigger Clutter stage focus processing, which might flush or abort pending transitions on the actor.
Environment
- Cinnamon 6.6.7
- Linux Mint 22.3 Zena
- Kernel 6.17.0-35-generic
Bug Description
The main menu (mintMenu / start menu) fails to render its open/close animation in certain scenarios. Instead of playing the expected slide+fade transition, the menu simply appears or disappears instantly.
Reproduction Steps
Observations
Technical Analysis (Speculative)
After examining the Cinnamon source code, here is my understanding of the likely root cause:
Code paths involved
All triggers ultimately call the same animation methods in
js/ui/popupMenu.js:menu@cinnamon.orgon_applet_clicked()oroverlay-keybinding →menu.toggle_with_options(true)→open(true)/close(true)PopupMenuManager._onEventCapture()→_closeMenu()→close(true)What I think is happening
The
open(true)method (popupMenu.js line 2329) does:The main menu is unique among panel menus because:
this.actor_onOpenStateChangedcallback — Immediately afteropen()emitsopen-state-changed(line 2419), the applet's handler (applet.js line 1418) does synchronous work:set_key_focus(this.searchEntry), shows 30 app buttons, and queues an idle callback to show the restshow()is called, Clutter must map, allocate, and apply CSS to the entire complex tree. On a system with hundreds of installed apps, this can be expensiveMy hypothesis: when
show()triggers the initial layout of the heavy tree, the actor may not yet be fully "realized" (backing texture ready) by the timeease()is called. Clutter's implicit transition system may not properly capture the initial property delta if the actor isn't in a fully ready rendering state, causing the transition to complete instantly (snap to final state).This would explain why:
close(true)is called, so the transition starts from a clean stateshow()completes beforeease()startsAn alternative hypothesis
The
_onOpenStateChangedcallback callsglobal.stage.set_key_focus(this.searchEntry)synchronously right after the animation starts. Changing keyboard focus can trigger Clutter stage focus processing, which might flush or abort pending transitions on the actor.Environment