Backed out changeset 30310d7d693a (bug 1582679) for mochitest assertions at nsWindow.cpp:3766. CLOSED TREE

This commit is contained in:
Brindusan Cristian 2019-10-02 00:14:31 +03:00
parent ea7d31a7d8
commit bc0bc5f832
2 changed files with 157 additions and 169 deletions

View File

@ -407,6 +407,7 @@ nsWindow::nsWindow() {
mContainer = nullptr;
mGdkWindow = nullptr;
mShell = nullptr;
mToplevelParentWindow = nullptr;
mCompositorWidgetDelegate = nullptr;
mHasMappedToplevel = false;
mIsFullyObscured = false;
@ -873,6 +874,7 @@ void nsWindow::SetParent(nsIWidget* aNewParent) {
gdk_window_reparent(mGdkWindow, newParentWindow,
DevicePixelsToGdkCoordRoundDown(mBounds.x),
DevicePixelsToGdkCoordRoundDown(mBounds.y));
mToplevelParentWindow = GTK_WINDOW(gtk_widget_get_toplevel(newContainer));
}
bool parentHasMappedToplevel = newParent && newParent->mHasMappedToplevel;
@ -900,6 +902,7 @@ void nsWindow::ReparentNativeWidget(nsIWidget* aNewParent) {
if (shell && gtk_window_get_transient_for(shell)) {
gtk_window_set_transient_for(shell, newParentWidget);
mToplevelParentWindow = newParentWidget;
}
}
@ -1146,52 +1149,55 @@ void nsWindow::HideWaylandTooltips() {
LOG(("nsWindow::HideWaylandTooltips [%p] hidding tooltip [%p].\n",
(void*)this, window));
window->HideWaylandWindow();
gVisibleWaylandPopupWindows = g_list_delete_link(
gVisibleWaylandPopupWindows, gVisibleWaylandPopupWindows);
}
}
// Hide popup nsWindows which are no longer in the nsXULPopupManager widget
// chain list.
void nsWindow::CleanupWaylandPopups() {
LOG(("nsWindow::CleanupWaylandPopups...\n"));
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
AutoTArray<nsIWidget*, 5> widgetChain;
pm->GetSubmenuWidgetChain(&widgetChain);
GList* popupList = gVisibleWaylandPopupWindows;
while (popupList) {
LOG((" Looking for %p [nsWindow]\n", popupList->data));
nsWindow* waylandWnd = static_cast<nsWindow*>(popupList->data);
bool popupFound = false;
for (unsigned long i = 0; i < widgetChain.Length(); i++) {
if (waylandWnd == widgetChain[i]) {
popupFound = true;
break;
}
}
if (!popupFound) {
LOG((" nsWindow [%p] not found in PopupManager, hiding it.\n",
waylandWnd));
waylandWnd->HideWaylandWindow();
popupList = gVisibleWaylandPopupWindows;
} else {
LOG((" nsWindow [%p] is still open.\n", waylandWnd));
popupList = popupList->next;
}
void nsWindow::HideWaylandPopupAndAllChildren() {
if (g_list_find(gVisibleWaylandPopupWindows, this) == nullptr) {
NS_WARNING("Popup window isn't in wayland popup list!");
return;
}
while (gVisibleWaylandPopupWindows) {
nsWindow* window =
static_cast<nsWindow*>(gVisibleWaylandPopupWindows->data);
bool quit = gVisibleWaylandPopupWindows->data == this;
window->HideWaylandWindow();
gVisibleWaylandPopupWindows = g_list_delete_link(
gVisibleWaylandPopupWindows, gVisibleWaylandPopupWindows);
if (quit) break;
}
}
// The MenuList popups are used as dropdown menus for example in WebRTC
// microphone/camera chooser or autocomplete widgets.
bool nsWindow::IsMainMenuWindow() {
nsIFrame* frame = GetFrame();
if (frame) {
nsMenuPopupFrame* menuPopupFrame = nullptr;
menuPopupFrame = do_QueryFrame(frame);
if (menuPopupFrame) {
LOG((" nsMenuPopupFrame [%p] type: %d IsMenu: %d, IsMenuList: %d\n",
menuPopupFrame, menuPopupFrame->PopupType(),
menuPopupFrame->IsMenu(), menuPopupFrame->IsMenuList()));
return mPopupType == ePopupTypeMenu && !menuPopupFrame->IsMenuList();
}
bool IsPopupWithoutToplevelParent(nsMenuPopupFrame* aMenuPopupFrame) {
// Check if the popup is autocomplete (like tags autocomplete
// in the bookmark edit popup).
nsAtom* popupId = aMenuPopupFrame->GetContent()->GetID();
if (popupId &&
popupId->Equals(NS_LITERAL_STRING("editBMPanel_tagsAutocomplete"))) {
return true;
}
nsIFrame* parentFrame = aMenuPopupFrame->GetParent();
if (!parentFrame) {
return false;
}
// Check if the popup is in the folder menu list
nsAtom* parentId = parentFrame->GetContent()->GetID();
if (parentId &&
parentId->Equals(NS_LITERAL_STRING("editBMPanel_folderMenuList"))) {
return true;
}
// Check if the popup is in popupnotificationcontent (like choosing capture
// device when starting webrtc session).
parentFrame = parentFrame->GetParent();
if (parentFrame && parentFrame->GetContent()->NodeName().EqualsLiteral(
"popupnotificationcontent")) {
return true;
}
return false;
}
@ -1201,20 +1207,12 @@ bool nsWindow::IsMainMenuWindow() {
// before we open another one on that level. It means that every open
// popup needs to have an unique parent.
GtkWidget* nsWindow::ConfigureWaylandPopupWindows() {
MOZ_ASSERT(this->mWindowType == eWindowType_popup);
LOG(("nsWindow::ConfigureWaylandPopupWindows [%p]\n", (void*)this));
#if DEBUG
if (this->GetFrame() && this->GetFrame()->GetContent()->GetID()) {
nsCString nodeId;
this->GetFrame()->GetContent()->GetID()->ToUTF8String(nodeId);
LOG((" [%p] popup node id=%s\n", this, nodeId.get()));
}
#endif
// Check if we're already configured.
if (gVisibleWaylandPopupWindows &&
g_list_find(gVisibleWaylandPopupWindows, this)) {
LOG((" [%p] is already configured.\n", (void*)this));
LOG(("...[%p] is already configured.\n", (void*)this));
return GTK_WIDGET(gtk_window_get_transient_for(GTK_WINDOW(mShell)));
}
@ -1222,56 +1220,96 @@ GtkWidget* nsWindow::ConfigureWaylandPopupWindows() {
// as it's short lived temporary window.
HideWaylandTooltips();
GtkWindow* parentGtkWindow = nullptr;
GtkWindow* parentWidget = mToplevelParentWindow;
if (gVisibleWaylandPopupWindows) {
LOG(("... there's visible active popup [%p]\n",
gVisibleWaylandPopupWindows->data));
if (IsMainMenuWindow()) {
// Remove and hide already closed popups from the
// gVisibleWaylandPopupWindows which were not yet been hidden.
CleanupWaylandPopups();
// Since the popups are shown by unknown order it can happen that child
// popup is shown before parent popup. The
// We look for the current window parent in nsXULPopupManager since it
// always has correct popup hierarchy while gVisibleWaylandPopupWindows may
// not.
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
AutoTArray<nsIWidget*, 5> widgetChain;
pm->GetSubmenuWidgetChain(&widgetChain);
for (unsigned long i = 0; i < widgetChain.Length(); i++) {
unsigned long parentIndex = i + 1;
if (widgetChain.Length() > parentIndex && widgetChain[i] == this) {
nsWindow* parentWindow =
static_cast<nsWindow*>(widgetChain[parentIndex]);
parentGtkWindow = GTK_WINDOW(parentWindow->GetGtkWidget());
LOG((" [%p] Found %p as parent in nsXULPopupManager.", this,
parentWindow));
break;
if (mPopupType == ePopupTypeTooltip) {
LOG(("...[%p] is tooltip, parent [%p]\n", (void*)this,
gVisibleWaylandPopupWindows->data));
// Attach tooltip window to the latest popup window
// to have both visible.
nsWindow* window =
static_cast<nsWindow*>(gVisibleWaylandPopupWindows->data);
parentWidget = GTK_WINDOW(window->GetGtkWidget());
} else {
nsMenuPopupFrame* menuPopupFrame = nullptr;
nsIFrame* frame = GetFrame();
if (frame) {
menuPopupFrame = do_QueryFrame(frame);
}
// The popup is not fully created yet (we're called from
// nsWindow::Create()) or we're toplevel popup without parent.
// In both cases just use parent which was passed to nsWindow::Create().
if (!menuPopupFrame) {
LOG(("...[%p] menuPopupFrame = null, using given parent widget [%p]\n",
(void*)this, parentWidget));
return GTK_WIDGET(parentWidget);
}
LOG(("...[%p] is %s\n", (void*)this,
menuPopupFrame->IsContextMenu() ? "context menu" : "popup"));
nsWindow* parentWindow =
static_cast<nsWindow*>(menuPopupFrame->GetParentMenuWidget());
LOG(("...[%p] GetParentMenuWidget() = %p\n", (void*)this, parentWindow));
// If the popup is a regular menu but GetParentMenuWidget() returns
// nullptr which means is not a submenu of any other menu.
// In this case use a parent given at nsWindow::Create().
// But we have to avoid using mToplevelParentWindow in case the popup
// is in 'popupnotificationcontent' element or autocomplete popup,
// otherwise the popupnotification would disappear when for
// example opening a popup with microphone selection.
if (!parentWindow && !menuPopupFrame->IsContextMenu() &&
!IsPopupWithoutToplevelParent(menuPopupFrame)) {
parentWindow =
get_window_for_gtk_widget(GTK_WIDGET(mToplevelParentWindow));
}
if (!parentWindow) {
LOG(("...[%p] using active/visible popups as a parent [%p]\n",
(void*)this, gVisibleWaylandPopupWindows->data));
// We're toplevel popup menu attached to another menu. Just use our
// latest popup as a parent.
parentWindow =
static_cast<nsWindow*>(gVisibleWaylandPopupWindows->data);
parentWidget = GTK_WINDOW(parentWindow->GetGtkWidget());
} else {
// We're a regular menu in the same frame hierarchy.
// Close child popups on the same level as we can't have two popups
// with one parent on Wayland.
parentWidget = GTK_WINDOW(parentWindow->GetGtkWidget());
nsWindow* lastChildOnTheSameLevel = nullptr;
for (GList* popup = gVisibleWaylandPopupWindows; popup;
popup = popup->next) {
nsWindow* window =
static_cast<nsWindow*>(gVisibleWaylandPopupWindows->data);
if (GTK_WINDOW(window->GetGtkWidget()) == parentWidget) {
break;
} else {
lastChildOnTheSameLevel = window;
}
}
if (lastChildOnTheSameLevel) {
lastChildOnTheSameLevel->HideWaylandPopupAndAllChildren();
}
}
}
} else {
// For popups in panels use the last opened popup window as parent,
// panels are not stored in nsXULPopupManager.
if (gVisibleWaylandPopupWindows) {
nsWindow* parentWindow =
static_cast<nsWindow*>(gVisibleWaylandPopupWindows->data);
parentGtkWindow = GTK_WINDOW(parentWindow->GetGtkWidget());
}
}
if (parentGtkWindow) {
MOZ_ASSERT(parentGtkWindow != GTK_WINDOW(this->GetGtkWidget()),
"Cannot set self as parent");
gtk_window_set_transient_for(GTK_WINDOW(mShell),
GTK_WINDOW(parentGtkWindow));
} else {
// Fallback to the parent given in nsWindow::Create (most likely the
// toplevel window).
parentGtkWindow = gtk_window_get_transient_for(GTK_WINDOW(mShell));
MOZ_ASSERT(parentWidget, "Missing parent widget for wayland popup!");
if (parentWidget) {
LOG(("...[%p] set parent widget [%p]\n", (void*)this, parentWidget));
gtk_window_set_transient_for(GTK_WINDOW(mShell), parentWidget);
}
// Add current window to the visible popup list
gVisibleWaylandPopupWindows =
g_list_prepend(gVisibleWaylandPopupWindows, this);
LOG((" Parent window for %p: %p [GtkWindow]", this, parentGtkWindow));
return GTK_WIDGET(parentGtkWindow);
return GTK_WIDGET(parentWidget);
}
#ifdef DEBUG
@ -3547,14 +3585,6 @@ static GdkWindow* CreateGdkWindow(GdkWindow* parent, GtkWidget* widget) {
nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
const LayoutDeviceIntRect& aRect,
nsWidgetInitData* aInitData) {
#ifdef MOZ_LOGGING
if (this->GetFrame() && this->GetFrame()->GetContent()) {
nsCString nodeName =
NS_ConvertUTF16toUTF8(this->GetFrame()->GetContent()->NodeName());
LOG(("nsWindow::Create: creating [%p]: nodename %s\n", this,
nodeName.get()));
}
#endif
// only set the base parent if we're going to be a dialog or a
// toplevel
nsIWidget* baseParent =
@ -3588,16 +3618,15 @@ nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
mBounds = aRect;
ConstrainSize(&mBounds.width, &mBounds.height);
GtkWidget* eventWidget = nullptr;
bool drawToContainer = false;
bool needsAlphaVisual = (mWindowType == eWindowType_popup &&
(aInitData && aInitData->mSupportTranslucency));
// Figure out our parent window - only used for eWindowType_child
// figure out our parent window
GtkWidget* parentMozContainer = nullptr;
GtkContainer* parentGtkContainer = nullptr;
GdkWindow* parentGdkWindow = nullptr;
nsWindow* parentnsWindow = nullptr;
GtkWidget* eventWidget = nullptr;
bool drawToContainer = false;
bool needsAlphaVisual =
(mWindowType == eWindowType_popup && aInitData->mSupportTranslucency);
if (aParent) {
parentnsWindow = static_cast<nsWindow*>(aParent);
@ -3615,15 +3644,19 @@ nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
// get the widget for the window - it should be a moz container
parentMozContainer = parentnsWindow->GetMozContainerWidget();
if (!parentMozContainer) return NS_ERROR_FAILURE;
// get the toplevel window just in case someone needs to use it
// for setting transients or whatever.
mToplevelParentWindow =
GTK_WINDOW(gtk_widget_get_toplevel(parentMozContainer));
}
// ^^ only used for eWindowType_child
if (!mIsX11Display) {
if (mWindowType == eWindowType_child) {
// eWindowType_child is not supported on Wayland. Just switch to toplevel
// as a workaround.
mWindowType = eWindowType_toplevel;
} else if (mWindowType == eWindowType_popup && !aNativeParent && !aParent) {
} else if (mWindowType == eWindowType_popup && !mToplevelParentWindow) {
// Workaround for Wayland where the popup windows always need to have
// parent window. For example webrtc ui is a popup window without parent.
mWindowType = eWindowType_toplevel;
@ -3761,17 +3794,7 @@ nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
SetDefaultIcon();
gtk_window_set_type_hint(GTK_WINDOW(mShell),
GDK_WINDOW_TYPE_HINT_DIALOG);
MOZ_ASSERT(parentnsWindow != nullptr,
"Dialog should always be created with parent!");
if (parentnsWindow) {
gtk_window_set_transient_for(
GTK_WINDOW(mShell), GTK_WINDOW(parentnsWindow->GetGtkWidget()));
LOG((
"nsWindow::Create(): dialog [%p], parent window %p [GdkWindow]\n",
this, aNativeParent));
}
gtk_window_set_transient_for(GTK_WINDOW(mShell), mToplevelParentWindow);
} else if (mWindowType == eWindowType_popup) {
mGtkWindowRoleName = "Popup";
@ -3822,11 +3845,12 @@ nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
}
}
gtk_window_set_type_hint(GTK_WINDOW(mShell), gtkTypeHint);
if (parentnsWindow) {
LOG(("nsWindow::Create() [%p]: parent window for popup: %p\n", this,
parentnsWindow));
gtk_window_set_transient_for(
GTK_WINDOW(mShell), GTK_WINDOW(parentnsWindow->GetGtkWidget()));
if (mToplevelParentWindow) {
LOG(("nsWindow::Create [%p] Set popup parent %p\n", (void*)this,
mToplevelParentWindow));
gtk_window_set_transient_for(GTK_WINDOW(mShell),
mToplevelParentWindow);
}
// We need realized mShell at NativeMove().
@ -4330,13 +4354,6 @@ void nsWindow::NativeMoveResize() {
void nsWindow::HideWaylandWindow() {
#ifdef MOZ_WAYLAND
if (mWindowType == eWindowType_popup) {
GList* foundWindow = g_list_find(gVisibleWaylandPopupWindows, this);
if (foundWindow) {
gVisibleWaylandPopupWindows =
g_list_delete_link(gVisibleWaylandPopupWindows, foundWindow);
}
}
if (mContainer && moz_container_has_wl_egl_window(mContainer)) {
// Because wl_egl_window is destroyed on moz_container_unmap(),
// the current compositor cannot use it anymore. To avoid crash,
@ -4360,10 +4377,7 @@ void nsWindow::NativeShow(bool aAction) {
}
// Update popup window hierarchy run-time on Wayland.
if (IsWaylandPopup()) {
if (!ConfigureWaylandPopupWindows()) {
mNeedsShow = true;
return;
}
ConfigureWaylandPopupWindows();
}
gtk_widget_show(mShell);
} else if (mContainer) {
@ -4373,10 +4387,11 @@ void nsWindow::NativeShow(bool aAction) {
}
} else {
if (!mIsX11Display) {
if (IsWaylandPopup() && IsMainMenuWindow()) {
CleanupWaylandPopups();
if (IsWaylandPopup()) {
HideWaylandPopupAndAllChildren();
} else {
HideWaylandWindow();
}
HideWaylandWindow();
} else if (mIsTopLevel) {
// Workaround window freezes on GTK versions before 3.21.2 by
// ensuring that configure events get dispatched to windows before
@ -5284,7 +5299,7 @@ bool nsWindow::CheckForRollup(gdouble aMouseX, gdouble aMouseY, bool aIsWheel,
AutoTArray<nsIWidget*, 5> widgetChain;
uint32_t sameTypeCount =
rollupListener->GetSubmenuWidgetChain(&widgetChain);
for (unsigned long i = 0; i < widgetChain.Length(); ++i) {
for (uint32_t i = 0; i < widgetChain.Length(); ++i) {
nsIWidget* widget = widgetChain[i];
auto* currWindow = (GdkWindow*)widget->GetNativeData(NS_NATIVE_WINDOW);
if (is_mouse_in_window(currWindow, aMouseX, aMouseY)) {
@ -6647,37 +6662,11 @@ void nsWindow::SetDrawsInTitlebar(bool aState) {
}
gint nsWindow::GdkScaleFactor() {
GdkWindow* scaledGdkWindow = mGdkWindow;
if (!mIsX11Display) {
// For popup windows/dialogs with parent window we need to get scale factor
// of the topmost window. Otherwise the scale factor of the popup is
// not updated during it's hidden.
if (mWindowType == eWindowType_popup || mWindowType == eWindowType_dialog) {
// Get toplevel window for scale factor:
GtkWindow* parentWindow = GTK_WINDOW(GetGtkWidget());
GtkWindow* topmostParentWindow;
while (parentWindow) {
topmostParentWindow = parentWindow;
parentWindow = gtk_window_get_transient_for(parentWindow);
}
if (topmostParentWindow) {
scaledGdkWindow =
gtk_widget_get_window(GTK_WIDGET(topmostParentWindow));
} else {
NS_WARNING("Popup/Dialog has no parent.");
}
// Fallback for windows which parent has been unrealized.
if (!scaledGdkWindow) {
scaledGdkWindow = mGdkWindow;
}
}
}
// Available as of GTK 3.10+
static auto sGdkWindowGetScaleFactorPtr =
(gint(*)(GdkWindow*))dlsym(RTLD_DEFAULT, "gdk_window_get_scale_factor");
if (sGdkWindowGetScaleFactorPtr && scaledGdkWindow) {
return (*sGdkWindowGetScaleFactorPtr)(scaledGdkWindow);
}
if (sGdkWindowGetScaleFactorPtr && mGdkWindow)
return (*sGdkWindowGetScaleFactorPtr)(mGdkWindow);
return ScreenHelperGTK::GetGTKMonitorScaleFactor();
}

View File

@ -483,6 +483,7 @@ class nsWindow final : public nsBaseWidget {
GtkWidget* mShell;
MozContainer* mContainer;
GdkWindow* mGdkWindow;
GtkWindow* mToplevelParentWindow;
bool mWindowShouldStartDragging = false;
PlatformCompositorWidgetDelegate* mCompositorWidgetDelegate;
@ -620,12 +621,10 @@ class nsWindow final : public nsBaseWidget {
void SetPopupWindowDecoration(bool aShowOnTaskbar);
bool IsMainMenuWindow();
GtkWidget* ConfigureWaylandPopupWindows();
void HideWaylandWindow();
void HideWaylandTooltips();
void HideWaylandPopupAndAllChildren();
void CleanupWaylandPopups();
/**
* |mIMContext| takes all IME related stuff.