Summary
When two or more asset editors of the same editor type are open (e.g. two Blueprint editors — one docked as a main-window tab, one in a floating window), their status bars end up sharing a single Slate widget instance for the “Unsaved assets + Revision Control” button cluster. A Slate widget can only correctly belong to one window, so:
Hovering the buttons shows the hover highlight in both windows simultaneously.
The buttons in one of the windows (typically the docked/main-window one) become unresponsive until the other window is closed or minimized, or a tab with a different status bar (e.g. the Level Editor tab) is brought to front.
Opening the Revision Control menu from the still-working window makes the menu flicker (it anchors against geometry belonging to the other window and gets dismissed repeatedly).
What Type of Bug are you experiencing?
UI / Tools
Steps to Reproduce
- In any project with revision control enabled, open two assets that use the same editor type (e.g. two Blueprints). Keep one docked in the main window as the foreground tab and float the other in its own OS window.
- Force a tool-menus refresh with the console command
ToolMenus.RefreshAllWidgets. (In normal use this happens organically — anyUToolMenus::RefreshAllWidgets()trigger such as editor-settings changes or scripted menu entries being added/removed poisons the state, which is why the bug appears “randomly” during long sessions.) - Hover and click the Unsaved-assets / Revision Control buttons in the bottom-right of each window.
Expected Result
Each status bar has its own independent, functional widget.
Observed Result
Hover state mirrors across both windows; buttons dead in one window; Revision Control menu flickers in the other.
Affects Versions
5.8
5.7
5.6
5.5
5.4
5.3
5.2
5.1
5.0
Platform(s)
Windows
Additional Notes
Root cause (traced in 5.8 source)
SStandaloneAssetEditorToolkitHostmakes each asset editor’s status bar name unique only via the FName number suffix:
StatusBarName = FName(AppName, ++StatusBarIdGenerator);(SStandaloneAssetEditorToolkitHost.cpp)SStatusBar::GetToolbarName()builds the toolbar’s ToolMenu name fromWidgetDrawer->GetSerializableName() + ".ToolBar", andSWidgetDrawer::GetSerializableName()returnsDrawerName.GetPlainNameString()— stripping the number. Every editor instance of the same app type therefore collides on the same registered menu name (e.g.BlueprintEditor.ToolBar).SStatusBar::RegisterSourceControlStatus()adds the source-control cluster to that shared menu as an already-constructed widget:FToolMenuEntry::InitWidget("SourceControl", FSourceControlMenuHelpers::MakeSourceControlStatusWidget(), ...).InitWidgetcaptures the concreteTSharedRef<SWidget>in a lambda that returns the same instance on every generation (ToolMenuEntry.cpp), andFToolMenuSection::AddEntryreplaces the previous entry of the same name (ToolMenuSection.cpp), so the shared menu always holds exactly one widget instance — the most recently opened editor’s.- On the next
UToolMenus::RefreshAllWidgets(),HandleNextTick()regenerates every live toolbar built from that menu name — handing the one stored widget instance to both windows’ status bars. From then on the two windows fight over a single widget: shared hover state, geometry/window association owned by whichever painted last (dead clicks in the other), and menu anchoring against the wrong window (flicker).
The Level Editor tab is unaffected because its status bar name (LevelEditor.StatusBar) has no number suffix and no collision.
Proposed fix
Make the status bar toolbar menu name unique per status bar instance by including the FName number, i.e. in SStatusBar::GetToolbarName() use the full drawer name instead of the plain string:
FName SStatusBar::GetToolbarName() const
{
// Use the full unique name (including the FName number that differentiates
// multiple editors of the same type) so each status bar registers its own
// toolbar menu and its own SourceControl widget instance.
return FName(*(WidgetDrawer->GetDrawerName().ToString() + TEXT(".ToolBar")));
}
Each status bar then registers its own ToolMenu and owns its own widget instance; a refresh regenerates each toolbar from its own entry. The number of registered menus stays bounded by the number of editor instances opened in the session.
SWidgetDrawer::GetSerializableName() should intentionally stay plain — it also keys per-editor-type persisted config (drawer sizes in GEditorSettingsIni), which should remain shared across instances of the same editor type.
An alternative (larger) fix is to make FToolMenuEntry::InitWidget unsuitable-by-construction for this case by registering a widget factory instead of an instance, but the one-line toolbar-name change is minimal and contained.