From 57463ac2b6fa83c256f62ef2c8d10707d521dfcb Mon Sep 17 00:00:00 2001 From: Jan Horak Date: Mon, 4 Nov 2019 09:56:33 +0100 Subject: git diff --- D49289-wayland-monitor-size.diff | 370 +++++++++++++++++++++++++++++++++++++++ firefox.spec | 2 + 2 files changed, 372 insertions(+) create mode 100644 D49289-wayland-monitor-size.diff diff --git a/D49289-wayland-monitor-size.diff b/D49289-wayland-monitor-size.diff new file mode 100644 index 0000000..ff2ce05 --- /dev/null +++ b/D49289-wayland-monitor-size.diff @@ -0,0 +1,370 @@ +diff --git a/layout/xul/nsMenuPopupFrame.cpp b/layout/xul/nsMenuPopupFrame.cpp +--- a/layout/xul/nsMenuPopupFrame.cpp ++++ b/layout/xul/nsMenuPopupFrame.cpp +@@ -1502,7 +1502,7 @@ + + nscoord oldAlignmentOffset = mAlignmentOffset; + +- bool inWayland = false; ++ static bool inWayland = false; + #ifdef MOZ_WAYLAND + inWayland = !GDK_IS_X11_DISPLAY(gdk_display_get_default()); + #endif +@@ -1512,9 +1512,9 @@ + // However, if a panel is already constrained or flipped (mIsOffset), then we + // want to continue to calculate this. Also, always do this for content + // shells, so that the popup doesn't extend outside the containing frame. +- if (!inWayland && (mInContentShell || (mFlip != FlipType_None && +- (!aIsMove || mIsOffset || +- mPopupType != ePopupTypePanel)))) { ++ if (mInContentShell || ++ (mFlip != FlipType_None && ++ (!aIsMove || mIsOffset || mPopupType != ePopupTypePanel))) { + int32_t appPerDev = presContext->AppUnitsPerDevPixel(); + LayoutDeviceIntRect anchorRectDevPix = + LayoutDeviceIntRect::FromAppUnitsToNearest(anchorRect, appPerDev); +@@ -1532,60 +1532,66 @@ + if (mRect.width > screenRect.width) mRect.width = screenRect.width; + if (mRect.height > screenRect.height) mRect.height = screenRect.height; + +- // at this point the anchor (anchorRect) is within the available screen +- // area (screenRect) and the popup is known to be no larger than the screen. ++ // We can't get the subsequent change of the popup position under ++ // waylande where gdk_window_move_to_rect is used to place them ++ // because we don't know the absolute position of the window on the screen. ++ if (!inWayland) { ++ // at this point the anchor (anchorRect) is within the available screen ++ // area (screenRect) and the popup is known to be no larger than the ++ // screen. + +- // We might want to "slide" an arrow if the panel is of the correct type - +- // but we can only slide on one axis - the other axis must be "flipped or +- // resized" as normal. +- bool slideHorizontal = false, slideVertical = false; +- if (mFlip == FlipType_Slide) { +- int8_t position = GetAlignmentPosition(); +- slideHorizontal = position >= POPUPPOSITION_BEFORESTART && +- position <= POPUPPOSITION_AFTEREND; +- slideVertical = position >= POPUPPOSITION_STARTBEFORE && +- position <= POPUPPOSITION_ENDAFTER; +- } ++ // We might want to "slide" an arrow if the panel is of the correct type - ++ // but we can only slide on one axis - the other axis must be "flipped or ++ // resized" as normal. ++ bool slideHorizontal = false, slideVertical = false; ++ if (mFlip == FlipType_Slide) { ++ int8_t position = GetAlignmentPosition(); ++ slideHorizontal = position >= POPUPPOSITION_BEFORESTART && ++ position <= POPUPPOSITION_AFTEREND; ++ slideVertical = position >= POPUPPOSITION_STARTBEFORE && ++ position <= POPUPPOSITION_ENDAFTER; ++ } + +- // Next, check if there is enough space to show the popup at full size when +- // positioned at screenPoint. If not, flip the popups to the opposite side +- // of their anchor point, or resize them as necessary. +- bool endAligned = IsDirectionRTL() +- ? mPopupAlignment == POPUPALIGNMENT_TOPLEFT || +- mPopupAlignment == POPUPALIGNMENT_BOTTOMLEFT +- : mPopupAlignment == POPUPALIGNMENT_TOPRIGHT || +- mPopupAlignment == POPUPALIGNMENT_BOTTOMRIGHT; +- nscoord preOffsetScreenPoint = screenPoint.x; +- if (slideHorizontal) { +- mRect.width = SlideOrResize(screenPoint.x, mRect.width, screenRect.x, +- screenRect.XMost(), &mAlignmentOffset); +- } else { +- mRect.width = FlipOrResize( +- screenPoint.x, mRect.width, screenRect.x, screenRect.XMost(), +- anchorRect.x, anchorRect.XMost(), margin.left, margin.right, +- offsetForContextMenu.x, hFlip, endAligned, &mHFlip); +- } +- mIsOffset = preOffsetScreenPoint != screenPoint.x; ++ // Next, check if there is enough space to show the popup at full size ++ // when positioned at screenPoint. If not, flip the popups to the opposite ++ // side of their anchor point, or resize them as necessary. ++ bool endAligned = IsDirectionRTL() ++ ? mPopupAlignment == POPUPALIGNMENT_TOPLEFT || ++ mPopupAlignment == POPUPALIGNMENT_BOTTOMLEFT ++ : mPopupAlignment == POPUPALIGNMENT_TOPRIGHT || ++ mPopupAlignment == POPUPALIGNMENT_BOTTOMRIGHT; ++ nscoord preOffsetScreenPoint = screenPoint.x; ++ if (slideHorizontal) { ++ mRect.width = SlideOrResize(screenPoint.x, mRect.width, screenRect.x, ++ screenRect.XMost(), &mAlignmentOffset); ++ } else { ++ mRect.width = FlipOrResize( ++ screenPoint.x, mRect.width, screenRect.x, screenRect.XMost(), ++ anchorRect.x, anchorRect.XMost(), margin.left, margin.right, ++ offsetForContextMenu.x, hFlip, endAligned, &mHFlip); ++ } ++ mIsOffset = preOffsetScreenPoint != screenPoint.x; + +- endAligned = mPopupAlignment == POPUPALIGNMENT_BOTTOMLEFT || +- mPopupAlignment == POPUPALIGNMENT_BOTTOMRIGHT; +- preOffsetScreenPoint = screenPoint.y; +- if (slideVertical) { +- mRect.height = SlideOrResize(screenPoint.y, mRect.height, screenRect.y, +- screenRect.YMost(), &mAlignmentOffset); +- } else { +- mRect.height = FlipOrResize( +- screenPoint.y, mRect.height, screenRect.y, screenRect.YMost(), +- anchorRect.y, anchorRect.YMost(), margin.top, margin.bottom, +- offsetForContextMenu.y, vFlip, endAligned, &mVFlip); ++ endAligned = mPopupAlignment == POPUPALIGNMENT_BOTTOMLEFT || ++ mPopupAlignment == POPUPALIGNMENT_BOTTOMRIGHT; ++ preOffsetScreenPoint = screenPoint.y; ++ if (slideVertical) { ++ mRect.height = SlideOrResize(screenPoint.y, mRect.height, screenRect.y, ++ screenRect.YMost(), &mAlignmentOffset); ++ } else { ++ mRect.height = FlipOrResize( ++ screenPoint.y, mRect.height, screenRect.y, screenRect.YMost(), ++ anchorRect.y, anchorRect.YMost(), margin.top, margin.bottom, ++ offsetForContextMenu.y, vFlip, endAligned, &mVFlip); ++ } ++ mIsOffset = mIsOffset || (preOffsetScreenPoint != screenPoint.y); ++ ++ NS_ASSERTION(screenPoint.x >= screenRect.x && ++ screenPoint.y >= screenRect.y && ++ screenPoint.x + mRect.width <= screenRect.XMost() && ++ screenPoint.y + mRect.height <= screenRect.YMost(), ++ "Popup is offscreen"); + } +- mIsOffset = mIsOffset || (preOffsetScreenPoint != screenPoint.y); +- +- NS_ASSERTION(screenPoint.x >= screenRect.x && +- screenPoint.y >= screenRect.y && +- screenPoint.x + mRect.width <= screenRect.XMost() && +- screenPoint.y + mRect.height <= screenRect.YMost(), +- "Popup is offscreen"); + } + + // snap the popup's position in screen coordinates to device pixels, +@@ -1687,6 +1693,14 @@ + screen->GetAvailRect(&screenRectPixels.x, &screenRectPixels.y, + &screenRectPixels.width, &screenRectPixels.height); + } ++#ifdef MOZ_WAYLAND ++ else { ++ if (GetWidget() && ++ GetWidget()->GetScreenRect(&screenRectPixels) != NS_OK) { ++ NS_WARNING("Cannot get screen rect from widget!"); ++ } ++ } ++#endif + } + + if (mInContentShell) { +diff --git a/widget/ScreenManager.cpp b/widget/ScreenManager.cpp +--- a/widget/ScreenManager.cpp ++++ b/widget/ScreenManager.cpp +@@ -11,6 +11,11 @@ + #include "mozilla/dom/DOMTypes.h" + #include "mozilla/Logging.h" + #include "mozilla/StaticPtr.h" ++#ifdef MOZ_WAYLAND ++# include ++# include ++# include ++#endif /* MOZ_WAYLAND */ + + static mozilla::LazyLogModule sScreenLog("WidgetScreen"); + +@@ -104,6 +109,15 @@ + NS_IMETHODIMP + ScreenManager::ScreenForRect(int32_t aX, int32_t aY, int32_t aWidth, + int32_t aHeight, nsIScreen** aOutScreen) { ++#ifdef MOZ_WAYLAND ++ static bool inWayland = !GDK_IS_X11_DISPLAY(gdk_display_get_default()); ++ ++ if (inWayland) { ++ *aOutScreen = nullptr; ++ return NS_OK; ++ } ++#endif ++ + if (mScreenList.IsEmpty()) { + MOZ_LOG(sScreenLog, LogLevel::Warning, + ("No screen available. This can happen in xpcshell.")); +diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h +--- a/widget/gtk/nsWindow.h ++++ b/widget/gtk/nsWindow.h +@@ -398,6 +398,9 @@ + static bool HideTitlebarByDefault(); + static bool GetTopLevelWindowActiveState(nsIFrame* aFrame); + static bool TitlebarCanUseShapeMask(); ++#ifdef MOZ_WAYLAND ++ virtual nsresult GetScreenRect(LayoutDeviceIntRect* aRect) override; ++#endif + + protected: + virtual ~nsWindow(); +@@ -630,6 +633,7 @@ + void HideWaylandTooltips(); + void HideWaylandPopupAndAllChildren(); + void CleanupWaylandPopups(); ++ GtkWindow* GetCurrentTopmostWindow(); + + /** + * |mIMContext| takes all IME related stuff. +diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp +--- a/widget/gtk/nsWindow.cpp ++++ b/widget/gtk/nsWindow.cpp +@@ -1294,10 +1294,14 @@ + GdkWindow* window, const GdkRectangle* flipped_rect, + const GdkRectangle* final_rect, gboolean flipped_x, gboolean flipped_y, + void* aWindow) { +- LOG(("%s [%p] flipped %d %d\n", __FUNCTION__, aWindow, flipped_rect->x, +- flipped_rect->y)); +- LOG(("%s [%p] final %d %d\n", __FUNCTION__, aWindow, final_rect->x, +- final_rect->y)); ++ LOG(("%s [%p] flipped_x %d flipped_y %d\n", __FUNCTION__, aWindow, flipped_x, ++ flipped_y)); ++ ++ LOG(("%s [%p] flipped %d %d w:%d h:%d\n", __FUNCTION__, aWindow, ++ flipped_rect->x, flipped_rect->y, flipped_rect->width, ++ flipped_rect->height)); ++ LOG(("%s [%p] final %d %d w:%d h:%d\n", __FUNCTION__, aWindow, final_rect->x, ++ final_rect->y, final_rect->width, final_rect->height)); + } + #endif + +@@ -1384,6 +1388,16 @@ + HideWaylandWindow(); + } + ++ LOG( ++ ("nsWindow::NativeMoveResizeWaylandPopup [%p]: requested rect: x%d y%d " ++ "w%d h%d\n", ++ this, rect.x, rect.y, rect.width, rect.height)); ++ if (aSize) { ++ LOG((" aSize: x%d y%d w%d h%d\n", aSize->x, aSize->y, aSize->width, ++ aSize->height)); ++ } else { ++ LOG((" No aSize given")); ++ } + sGdkWindowMoveToRect(gdkWindow, &rect, rectAnchor, menuAnchor, hints, 0, 0); + + if (isWidgetVisible) { +@@ -1399,7 +1413,8 @@ + LOG(("nsWindow::NativeMove [%p] %d %d\n", (void*)this, point.x, point.y)); + + if (IsWaylandPopup()) { +- NativeMoveResizeWaylandPopup(&point, nullptr); ++ GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mBounds.Size()); ++ NativeMoveResizeWaylandPopup(&point, &size); + } else if (mIsTopLevel) { + gtk_window_move(GTK_WINDOW(mShell), point.x, point.y); + } else if (mGdkWindow) { +@@ -6724,6 +6739,16 @@ + } + } + ++GtkWindow* nsWindow::GetCurrentTopmostWindow() { ++ GtkWindow* parentWindow = GTK_WINDOW(GetGtkWidget()); ++ GtkWindow* topmostParentWindow; ++ while (parentWindow) { ++ topmostParentWindow = parentWindow; ++ parentWindow = gtk_window_get_transient_for(parentWindow); ++ } ++ return topmostParentWindow; ++} ++ + gint nsWindow::GdkScaleFactor() { + GdkWindow* scaledGdkWindow = mGdkWindow; + if (!mIsX11Display) { +@@ -6732,12 +6757,7 @@ + // 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); +- } ++ GtkWindow* topmostParentWindow = GetCurrentTopmostWindow(); + if (topmostParentWindow) { + scaledGdkWindow = + gtk_widget_get_window(GTK_WIDGET(topmostParentWindow)); +@@ -7268,6 +7288,41 @@ + return window.forget(); + } + ++#ifdef MOZ_WAYLAND ++nsresult nsWindow::GetScreenRect(LayoutDeviceIntRect* aRect) { ++ typedef struct _GdkMonitor GdkMonitor; ++ static auto s_gdk_display_get_monitor_at_window = ++ (GdkMonitor * (*)(GdkDisplay*, GdkWindow*)) ++ dlsym(RTLD_DEFAULT, "gdk_display_get_monitor_at_window"); ++ ++ static auto s_gdk_monitor_get_workarea = ++ (void (*)(GdkMonitor*, GdkRectangle*))dlsym(RTLD_DEFAULT, ++ "gdk_monitor_get_workarea"); ++ ++ if (!s_gdk_display_get_monitor_at_window || !s_gdk_monitor_get_workarea) { ++ return NS_ERROR_NOT_IMPLEMENTED; ++ } ++ ++ GtkWindow* topmostParentWindow = GetCurrentTopmostWindow(); ++ GdkWindow* gdkWindow = gtk_widget_get_window(GTK_WIDGET(topmostParentWindow)); ++ ++ GdkMonitor* monitor = ++ s_gdk_display_get_monitor_at_window(gdk_display_get_default(), gdkWindow); ++ if (monitor) { ++ GdkRectangle workArea; ++ s_gdk_monitor_get_workarea(monitor, &workArea); ++ aRect->x = workArea.x; ++ aRect->y = workArea.y; ++ aRect->width = workArea.width; ++ aRect->height = workArea.height; ++ LOG((" workarea for [%p], monitor %p: x%d y%d w%d h%d\n", this, monitor, ++ workArea.x, workArea.y, workArea.width, workArea.height)); ++ return NS_OK; ++ } ++ return NS_ERROR_NOT_IMPLEMENTED; ++} ++#endif ++ + bool nsWindow::GetTopLevelWindowActiveState(nsIFrame* aFrame) { + // Used by window frame and button box rendering. We can end up in here in + // the content process when rendering one of these moz styles freely in a +diff --git a/widget/moz.build b/widget/moz.build +--- a/widget/moz.build ++++ b/widget/moz.build +@@ -210,7 +210,6 @@ + 'PuppetBidiKeyboard.cpp', + 'PuppetWidget.cpp', + 'Screen.cpp', +- 'ScreenManager.cpp', + 'SharedWidgetUtils.cpp', + 'TextEventDispatcher.cpp', + 'VsyncDispatcher.cpp', +@@ -242,6 +241,7 @@ + SOURCES += [ + 'nsBaseDragService.cpp', + 'nsBaseWidget.cpp', ++ 'ScreenManager.cpp', + ] + + if CONFIG['MOZ_INSTRUMENT_EVENT_LOOP']: +diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h +--- a/widget/nsIWidget.h ++++ b/widget/nsIWidget.h +@@ -1713,6 +1713,15 @@ + return NS_ERROR_NOT_IMPLEMENTED; + } + ++ // Get rectangle of the screen where the window is placed. ++ // It's used to detect popup overflow under Wayland because ++ // Screenmanager does not work under it. ++#ifdef MOZ_WAYLAND ++ virtual nsresult GetScreenRect(LayoutDeviceIntRect* aRect) { ++ return NS_ERROR_NOT_IMPLEMENTED; ++ } ++#endif ++ + private: + class LongTapInfo { + public: + diff --git a/firefox.spec b/firefox.spec index dfbb3c5..5e8c0f2 100644 --- a/firefox.spec +++ b/firefox.spec @@ -152,6 +152,7 @@ Patch417: bug1375074-save-restore-x28.patch Patch419: mozilla-1568569.patch Patch421: mozilla-1579023.patch Patch422: mozilla-1580174-webrtc-popup.patch +Patch423: D49289-wayland-monitor-size.diff # Wayland specific upstream patches Patch574: firefox-pipewire.patch @@ -361,6 +362,7 @@ This package contains results of tests executed during build. %endif %patch419 -p1 -b .1568569 %patch421 -p1 -b .1579023 +%patch423 -p1 -b .D49289 # Wayland specific upstream patches %patch574 -p1 -b .firefox-pipewire -- cgit