diff -up firefox-66.0.1/widget/gtk/nsWindow.cpp.mozilla-1539471 firefox-66.0.1/widget/gtk/nsWindow.cpp --- firefox-66.0.1/widget/gtk/nsWindow.cpp.mozilla-1539471 2019-03-28 14:08:42.351128620 +0100 +++ firefox-66.0.1/widget/gtk/nsWindow.cpp 2019-03-28 14:20:23.282890178 +0100 @@ -312,6 +312,9 @@ static nsWindow *gFocusWindow = nullptr; static bool gBlockActivateEvent = false; static bool gGlobalsInitialized = false; static bool gRaiseWindows = true; +#ifdef MOZ_WAYLAND +static GList *gCurrentPopupWindows = nullptr; +#endif #if GTK_CHECK_VERSION(3, 4, 0) static uint32_t gLastTouchID = 0; @@ -1136,8 +1139,16 @@ void nsWindow::NativeMoveResizeWaylandPo return; } - GtkWidget* parentWidget = - GTK_WIDGET(gtk_window_get_transient_for(GTK_WINDOW(mShell))); + GtkWidget *parentWidget; + if (mPopupType == ePopupTypeTooltip && gCurrentPopupWindows) { + // Attach tooltip window to the latest popup window + // to have both visible. + parentWidget = GTK_WIDGET(gCurrentPopupWindows->data); + gtk_window_set_transient_for(GTK_WINDOW(mShell), + GTK_WINDOW(parentWidget)); + } else { + parentWidget = GTK_WIDGET(gtk_window_get_transient_for(GTK_WINDOW(mShell))); + } int x_parent, y_parent; gdk_window_get_origin(gtk_widget_get_window(parentWidget), &x_parent, &y_parent); @@ -3489,7 +3500,7 @@ nsresult nsWindow::Create(nsIWidget *aPa gtkTypeHint = GDK_WINDOW_TYPE_HINT_DND; mIsDragPopup = true; } else { - switch (aInitData->mPopupHint) { + switch (mPopupType) { case ePopupTypeMenu: gtkTypeHint = GDK_WINDOW_TYPE_HINT_POPUP_MENU; break; @@ -3610,6 +3621,8 @@ nsresult nsWindow::Create(nsIWidget *aPa return NS_ERROR_FAILURE; case eWindowType_child: { + MOZ_ASSERT(mIsX11Display, + "eWindowType_child is not supported on Wayland!"); if (parentMozContainer) { mGdkWindow = CreateGdkWindow(parentGdkWindow, parentMozContainer); mHasMappedToplevel = parentnsWindow->mHasMappedToplevel; @@ -3979,6 +3992,49 @@ void nsWindow::NativeMoveResize() { } } +#ifdef MOZ_WAYLAND +void nsWindow::OpenToplevelWaylandWindow() { + // Wayland keeps strong popup window hierarchy. We need to track active + // (visible) popup windows and make sure we hide popup on the same level + // before we open another one on that level. It means that every open + // popup needs to have an unique parent. + if (mWindowType == eWindowType_popup) { + GtkWidget *parentWidget = + GTK_WIDGET(gtk_window_get_transient_for(GTK_WINDOW(mShell))); + + if (gCurrentPopupWindows) { + do { + GtkWidget *widget = GTK_WIDGET(gCurrentPopupWindows->data); + if (widget == parentWidget) { + break; + } + nsWindow* window = get_window_for_gtk_widget(widget); + NS_ASSERTION(window, "Unknown window in popup widget list!"); + window->CloseToplevelWaylandWindow(); + + } while (gCurrentPopupWindows != nullptr); + } + gCurrentPopupWindows = g_list_prepend(gCurrentPopupWindows, mShell); + } + + gtk_widget_show(mShell); +} + +void nsWindow::CloseToplevelWaylandWindow() { + 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, + // destroy the compositor & recreate a new compositor on next + // expose event. + DestroyLayerManager(); + } + if (mWindowType == eWindowType_popup) { + gCurrentPopupWindows = g_list_remove(gCurrentPopupWindows, mShell); + } + gtk_widget_hide(mShell); +} +#endif + void nsWindow::NativeShow(bool aAction) { if (aAction) { // unset our flag now that our window has been shown @@ -3990,51 +4046,55 @@ void nsWindow::NativeShow(bool aAction) SetUserTimeAndStartupIDForActivatedWindow(mShell); } - gtk_widget_show(mShell); +#ifdef MOZ_WAYLAND + if (!mIsX11Display) { + OpenToplevelWaylandWindow(); + } else +#endif + { + gtk_widget_show(mShell); + } } else if (mContainer) { gtk_widget_show(GTK_WIDGET(mContainer)); } else if (mGdkWindow) { gdk_window_show_unraised(mGdkWindow); } } else { -#ifdef MOZ_WAYLAND - 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, - // destroy the compositor & recreate a new compositor on next - // expose event. - DestroyLayerManager(); - } -#endif - if (mIsTopLevel) { - // Workaround window freezes on GTK versions before 3.21.2 by - // ensuring that configure events get dispatched to windows before - // they are unmapped. See bug 1225044. - if (gtk_check_version(3, 21, 2) != nullptr && mPendingConfigures > 0) { - GtkAllocation allocation; - gtk_widget_get_allocation(GTK_WIDGET(mShell), &allocation); - - GdkEventConfigure event; - PodZero(&event); - event.type = GDK_CONFIGURE; - event.window = mGdkWindow; - event.send_event = TRUE; - event.x = allocation.x; - event.y = allocation.y; - event.width = allocation.width; - event.height = allocation.height; - - auto shellClass = GTK_WIDGET_GET_CLASS(mShell); - for (unsigned int i = 0; i < mPendingConfigures; i++) { - Unused << shellClass->configure_event(mShell, &event); +#ifdef MOZ_WAYLAND + if (!mIsX11Display) { + CloseToplevelWaylandWindow(); + } else +#endif + { + // Workaround window freezes on GTK versions before 3.21.2 by + // ensuring that configure events get dispatched to windows before + // they are unmapped. See bug 1225044. + if (gtk_check_version(3, 21, 2) != nullptr && mPendingConfigures > 0) { + GtkAllocation allocation; + gtk_widget_get_allocation(GTK_WIDGET(mShell), &allocation); + + GdkEventConfigure event; + PodZero(&event); + event.type = GDK_CONFIGURE; + event.window = mGdkWindow; + event.send_event = TRUE; + event.x = allocation.x; + event.y = allocation.y; + event.width = allocation.width; + event.height = allocation.height; + + auto shellClass = GTK_WIDGET_GET_CLASS(mShell); + for (unsigned int i = 0; i < mPendingConfigures; i++) { + Unused << shellClass->configure_event(mShell, &event); + } + mPendingConfigures = 0; } - mPendingConfigures = 0; - } - gtk_widget_hide(mShell); + gtk_widget_hide(mShell); - ClearTransparencyBitmap(); // Release some resources + ClearTransparencyBitmap(); // Release some resources + } } else if (mContainer) { gtk_widget_hide(GTK_WIDGET(mContainer)); } else if (mGdkWindow) { diff -up firefox-66.0.1/widget/gtk/nsWindow.h.mozilla-1539471 firefox-66.0.1/widget/gtk/nsWindow.h --- firefox-66.0.1/widget/gtk/nsWindow.h.mozilla-1539471 2019-03-28 14:08:42.345128639 +0100 +++ firefox-66.0.1/widget/gtk/nsWindow.h 2019-03-28 14:08:42.355128607 +0100 @@ -603,6 +603,11 @@ class nsWindow final : public nsBaseWidg void ForceTitlebarRedraw(); +#ifdef MOZ_WAYLAND + void OpenToplevelWaylandWindow(); + void CloseToplevelWaylandWindow(); +#endif + /** * |mIMContext| takes all IME related stuff. *