@@ -238,15 +238,17 @@ widget::PopupLevel nsMenuPopupFrame::GetPopupLevel(bool aIsNoAutoHide) const {
238
238
return sDefaultLevelIsTop ? PopupLevel::Top : PopupLevel::Parent;
239
239
}
240
240
241
- void nsMenuPopupFrame::PrepareWidget (bool aRecreate ) {
241
+ void nsMenuPopupFrame::PrepareWidget (bool aForceRecreate ) {
242
242
nsView* ourView = GetView ();
243
- if (aRecreate) {
244
- if (auto * widget = GetWidget ()) {
243
+ if (auto * widget = GetWidget ()) {
244
+ nsCOMPtr<nsIWidget> parent = ComputeParentWidget ();
245
+ if (aForceRecreate || widget->GetParent () != parent ||
246
+ widget->NeedsRecreateToReshow ()) {
245
247
// Widget's WebRender resources needs to be cleared before creating new
246
248
// widget.
247
249
widget->ClearCachedWebrenderResources ();
250
+ ourView->DestroyWidget ();
248
251
}
249
- ourView->DestroyWidget ();
250
252
}
251
253
if (!ourView->HasWidget ()) {
252
254
CreateWidgetForView (ourView);
@@ -255,6 +257,35 @@ void nsMenuPopupFrame::PrepareWidget(bool aRecreate) {
255
257
}
256
258
}
257
259
260
+ already_AddRefed<nsIWidget> nsMenuPopupFrame::ComputeParentWidget () const {
261
+ auto popupLevel = GetPopupLevel (IsNoAutoHide ());
262
+ // Panels which have a parent level need a parent widget. This allows them to
263
+ // always appear in front of the parent window but behind other windows that
264
+ // should be in front of it.
265
+ nsCOMPtr<nsIWidget> parentWidget;
266
+ if (popupLevel != PopupLevel::Top) {
267
+ nsCOMPtr<nsIDocShellTreeItem> dsti = PresContext ()->GetDocShell ();
268
+ if (!dsti) {
269
+ return nullptr ;
270
+ }
271
+
272
+ nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
273
+ dsti->GetTreeOwner (getter_AddRefs (treeOwner));
274
+ if (!treeOwner) {
275
+ return nullptr ;
276
+ }
277
+
278
+ nsCOMPtr<nsIBaseWindow> baseWindow (do_QueryInterface (treeOwner));
279
+ if (baseWindow) {
280
+ baseWindow->GetMainWidget (getter_AddRefs (parentWidget));
281
+ }
282
+ }
283
+ if (!parentWidget && mView && mView ->GetParent ()) {
284
+ parentWidget = mView ->GetParent ()->GetNearestWidget (nullptr );
285
+ }
286
+ return parentWidget.forget ();
287
+ }
288
+
258
289
nsresult nsMenuPopupFrame::CreateWidgetForView (nsView* aView) {
259
290
// Create a widget for ourselves.
260
291
widget::InitData widgetData;
@@ -273,33 +304,16 @@ nsresult nsMenuPopupFrame::CreateWidgetForView(nsView* aView) {
273
304
}
274
305
}
275
306
276
- bool remote = HasRemoteContent ();
307
+ const bool remote = HasRemoteContent ();
277
308
278
309
const auto mode = nsLayoutUtils::GetFrameTransparency (this , this );
279
310
widgetData.mHasRemoteContent = remote;
280
311
widgetData.mTransparencyMode = mode;
281
312
widgetData.mPopupLevel = GetPopupLevel (widgetData.mNoAutoHide );
282
313
283
- // Panels which have a parent level need a parent widget. This allows them to
284
- // always appear in front of the parent window but behind other windows that
285
- // should be in front of it.
286
- nsCOMPtr<nsIWidget> parentWidget;
287
- if (widgetData.mPopupLevel != PopupLevel::Top) {
288
- nsCOMPtr<nsIDocShellTreeItem> dsti = PresContext ()->GetDocShell ();
289
- if (!dsti) {
290
- return NS_ERROR_FAILURE;
291
- }
292
-
293
- nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
294
- dsti->GetTreeOwner (getter_AddRefs (treeOwner));
295
- if (!treeOwner) {
296
- return NS_ERROR_FAILURE;
297
- }
298
-
299
- nsCOMPtr<nsIBaseWindow> baseWindow (do_QueryInterface (treeOwner));
300
- if (baseWindow) {
301
- baseWindow->GetMainWidget (getter_AddRefs (parentWidget));
302
- }
314
+ nsCOMPtr<nsIWidget> parentWidget = ComputeParentWidget ();
315
+ if (NS_WARN_IF(!parentWidget)) {
316
+ return NS_ERROR_FAILURE;
303
317
}
304
318
305
319
nsresult rv = aView->CreateWidgetForPopup (&widgetData, parentWidget);
@@ -308,8 +322,9 @@ nsresult nsMenuPopupFrame::CreateWidgetForView(nsView* aView) {
308
322
}
309
323
310
324
nsIWidget* widget = aView->GetWidget ();
311
- widget->SetTransparencyMode (mode );
325
+ MOZ_ASSERT ( widget->GetParent () == parentWidget );
312
326
327
+ widget->SetTransparencyMode (mode);
313
328
PropagateStyleToWidget ();
314
329
315
330
return NS_OK;
@@ -757,9 +772,7 @@ void nsMenuPopupFrame::InitializePopup(nsIContent* aAnchorContent,
757
772
int32_t aXPos, int32_t aYPos,
758
773
MenuPopupAnchorType aAnchorType,
759
774
bool aAttributesOverride) {
760
- auto * widget = GetWidget ();
761
- bool recreateWidget = widget && widget->NeedsRecreateToReshow ();
762
- PrepareWidget (recreateWidget);
775
+ PrepareWidget ();
763
776
764
777
mPopupState = ePopupShowing;
765
778
mAnchorContent = aAnchorContent;
@@ -887,9 +900,7 @@ void nsMenuPopupFrame::InitializePopup(nsIContent* aAnchorContent,
887
900
void nsMenuPopupFrame::InitializePopupAtScreen (nsIContent* aTriggerContent,
888
901
int32_t aXPos, int32_t aYPos,
889
902
bool aIsContextMenu) {
890
- auto * widget = GetWidget ();
891
- bool recreateWidget = widget && widget->NeedsRecreateToReshow ();
892
- PrepareWidget (recreateWidget);
903
+ PrepareWidget ();
893
904
894
905
mPopupState = ePopupShowing;
895
906
mAnchorContent = nullptr ;
@@ -2080,10 +2091,12 @@ nsresult nsMenuPopupFrame::AttributeChanged(int32_t aNameSpaceID,
2080
2091
MoveToAttributePosition ();
2081
2092
}
2082
2093
2083
- if (aAttribute == nsGkAtoms::remote) {
2094
+ if (aAttribute == nsGkAtoms::remote && GetWidget () ) {
2084
2095
// When the remote attribute changes, we need to create a new widget to
2085
2096
// ensure that it has the correct compositor and transparency settings to
2086
- // match the new value.
2097
+ // match the new value. Do that only if we already have a widget.
2098
+ // TODO(emilio): We should consider doing it only when we get re-shown or
2099
+ // so.
2087
2100
PrepareWidget (true );
2088
2101
}
2089
2102
0 commit comments