summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--D49289-wayland-monitor-size.diff370
-rw-r--r--firefox.spec2
2 files changed, 372 insertions, 0 deletions
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 <gdk/gdk.h>
++# include <gdk/gdkx.h>
++# include <gdk/gdkwayland.h>
++#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
bgstack15