Menuitems added via async onPopupShowing handler create duplicates on macos
Categories
(Core :: Widget: Cocoa, defect, P1)
Tracking
()
| Tracking | Status | |
|---|---|---|
| firefox134 | --- | fixed |
People
(Reporter: jhirsch, Assigned: mstange)
References
Details
Attachments
(3 files)
If a menubar menupopup is populated by an async onPopupShowing handler, which awaits some async data, and then renders it into menuitems, then on macos only (not windows) each of the inserted menuitems creates a second menuitem, rendered in the menu in reverse order, see screenshot.
Attempting to delete these extra menuitems via DOM JS APIs fails--these extra menuitems are not counted as children from the DOM perspective.
This behavior is observed whether the items are inserted one-by-one or whether they are added to a document fragment which is then inserted into the XUL DOM.
Based on initial debugging it seems that dynamically added items are double-inserted by a mutation observer: nsINode::InsertBefore is called, triggering MutationObserverWrapper::ContentInserted, which calls nsMenuGroupOwnerX::ContentInserted, then nsMenuX::ObserveContentInserted, then nsMenuX::InsertMenuChild.
On the other hand, elements left over from the previous rendering of the menu are initially displayed via nsMenuX::menuOpened calling nsMenuX::rebuildMenu calling nsMenuX::addMenuChild.
See screenshot and https://phabricator.services.mozilla.com/D226415 for a demo of this bug (you should have some extra profiles to test this out, they can be created via about:profiles).
| Assignee | ||
Comment 1•1 year ago
|
||
I can reproduce this. I haven't started debugging yet.
| Assignee | ||
Comment 2•1 year ago
•
|
||
This is a legitimate bug. I think this might be the first use of this type:
- A menupopup is being mutated while it's open
- The menu is not the root menupopup of a context menu
From what I can tell, the way the native menu system sets up its mutation observers is bound to cause duplicate notifications: We register the observer on the <menubar>, on the context menu's root <menupopup>, and on every nested <menu>. But mutation observers observe the entire DOM subtree. So we get lots of duplicate mutation callbacks for anything that's nested at least one level deep.
And it seems we've always been getting these duplicate callbacks. It's just that, if our observer is called while the menu is closed, we just set a "need to rebuild" flag and return.
But when the menu is open, these duplicate notifications cause trouble.
| Assignee | ||
Comment 3•1 year ago
|
||
I have a super simple fix, writing a test now.
| Assignee | ||
Comment 4•1 year ago
|
||
Updated•1 year ago
|
| Assignee | ||
Comment 5•1 year ago
|
||
In the case of this bug, we were creating different NSMenuItem
objects which ended up referring to the same nsIContent object.
Updated•1 year ago
|
Comment 7•1 year ago
|
||
Backed out for causing macOS assertion failures
Backout link: https://hg.mozilla.org/integration/autoland/rev/8b099f2b18f3af46c2624ade20b2b0bbd2417ebb
Backed out for causing mochitest failures at test_native_menus.xhtml.
| Assignee | ||
Comment 10•1 year ago
|
||
| Assignee | ||
Comment 11•1 year ago
|
||
In the try push, two out of the three bc4 tests fail with "WARNING: YOU ARE LEAKING THE WORLD", so I think having an unconditional mutation listener on the root element of the menu hierarchy keeps things alive for too long. I'll try to make it so that we only have the root mutation listener if there are registered menu change observers.
| Assignee | ||
Comment 12•1 year ago
|
||
Comment 13•1 year ago
|
||
Comment 14•1 year ago
|
||
| bugherder | ||
https://hg.mozilla.org/mozilla-central/rev/c57ae217dc8c
https://hg.mozilla.org/mozilla-central/rev/f001943cbf9b
Description
•