Blob Blame History Raw
diff -up firefox-67.0/widget/gtk/nsWindow.cpp.mozilla-1423598-popup firefox-67.0/widget/gtk/nsWindow.cpp
--- firefox-67.0/widget/gtk/nsWindow.cpp.mozilla-1423598-popup	2019-05-15 15:21:25.590222702 +0200
+++ firefox-67.0/widget/gtk/nsWindow.cpp	2019-05-15 15:24:26.925439991 +0200
@@ -1115,13 +1115,89 @@ void nsWindow::Move(double aX, double aY
   NotifyRollupGeometryChange();
 }
 
+#ifdef DEBUG
+static void NativeMoveResizeWaylandPopupCallback(GdkWindow *window,
+  const GdkRectangle *flipped_rect, const GdkRectangle *final_rect,
+  gboolean flipped_x, gboolean flipped_y, void *unused)
+{
+  LOG(("NativeMoveResizeWaylandPopupCallback flipped %d %d\n",
+    flipped_rect->x, flipped_rect->y));
+  LOG(("NativeMoveResizeWaylandPopupCallback final %d %d\n",
+    final_rect->x, final_rect->y));
+}
+#endif
+
+void nsWindow::NativeMoveResizeWaylandPopup(GdkPoint* aPosition, GdkRectangle* aSize) {
+  // Available as of GTK 3.24+
+  static auto sGdkWindowMoveToRect =
+      (void (*)(GdkWindow *, const GdkRectangle *, GdkGravity, GdkGravity,
+                GdkAnchorHints, gint, gint))
+                dlsym(RTLD_DEFAULT, "gdk_window_move_to_rect");
+
+  if (aSize) {
+    gtk_window_resize(GTK_WINDOW(mShell), aSize->width, aSize->height);
+  }
+  if (!sGdkWindowMoveToRect) {
+    gtk_window_move(GTK_WINDOW(mShell), aPosition->x, aPosition->y);
+    return;
+  }
+
+  GdkWindow *gdkWindow = gtk_widget_get_window(GTK_WIDGET(mShell));
+  if (!gdkWindow) {
+    return;
+  }
+
+  GtkWidget* 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);
+
+  GdkRectangle rect = { aPosition->x - x_parent,
+                        aPosition->y - y_parent,
+                        1, 1};
+  if (aSize) {
+    rect.width = aSize->width;
+    rect.height = aSize->height;
+  }
+
+#ifdef DEBUG
+  LOG(("NativeMoveResizeWaylandPopup request position %d,%d\n",
+    aPosition->x, aPosition->y));
+  if (aSize) {
+    LOG(("NativeMoveResizeWaylandPopup request size %d,%d\n",
+      aSize->width, aSize->height));
+  }
+  LOG(("NativeMoveResizeWaylandPopup result %d %d\n", rect.x, rect.y));
+  g_signal_connect(gdkWindow, "moved-to-rect",
+    G_CALLBACK(NativeMoveResizeWaylandPopupCallback), this);
+#endif
+
+  GdkGravity rectAnchor = GDK_GRAVITY_NORTH_WEST;
+  GdkGravity menuAnchor = GDK_GRAVITY_NORTH_WEST;
+  if (GetTextDirection() == GTK_TEXT_DIR_RTL) {
+    rectAnchor = GDK_GRAVITY_NORTH_EAST;
+    menuAnchor = GDK_GRAVITY_NORTH_EAST;
+  }
+
+  GdkAnchorHints hints = GdkAnchorHints(GDK_ANCHOR_SLIDE | GDK_ANCHOR_FLIP);
+  if (aSize) {
+    hints = GdkAnchorHints(hints|GDK_ANCHOR_RESIZE);
+  }
+
+  sGdkWindowMoveToRect(gdkWindow, &rect, rectAnchor, menuAnchor, hints, 0, 0);
+}
+
 void nsWindow::NativeMove() {
   GdkPoint point = DevicePixelsToGdkPointRoundDown(mBounds.TopLeft());
-
-  if (mIsTopLevel) {
-    gtk_window_move(GTK_WINDOW(mShell), point.x, point.y);
-  } else if (mGdkWindow) {
-    gdk_window_move(mGdkWindow, point.x, point.y);
+  if (!mIsX11Display && mIsTopLevel && mWindowType == eWindowType_popup) {
+    NativeMoveResizeWaylandPopup(&point, nullptr);
+  } else {
+    if (mIsTopLevel) {
+      gtk_window_move(GTK_WINDOW(mShell), point.x, point.y);
+    } else if (mGdkWindow) {
+      gdk_window_move(mGdkWindow, point.x, point.y);
+    }
   }
 }
 
@@ -3412,11 +3488,6 @@ nsresult nsWindow::Create(nsIWidget *aPa
                                  GDK_WINDOW_TYPE_HINT_DIALOG);
         gtk_window_set_transient_for(GTK_WINDOW(mShell), topLevelParent);
       } else if (mWindowType == eWindowType_popup) {
-        // With popup windows, we want to control their position, so don't
-        // wait for the window manager to place them (which wouldn't
-        // happen with override-redirect windows anyway).
-        NativeMove();
-
         gtk_window_set_wmclass(GTK_WINDOW(mShell), "Popup",
                                gdk_get_program_class());
 
@@ -3475,6 +3546,14 @@ nsresult nsWindow::Create(nsIWidget *aPa
         if (topLevelParent) {
           gtk_window_set_transient_for(GTK_WINDOW(mShell), topLevelParent);
         }
+
+        // We need realized mShell at NativeMove().
+        gtk_widget_realize(mShell);
+
+        // With popup windows, we want to control their position, so don't
+        // wait for the window manager to place them (which wouldn't
+        // happen with override-redirect windows anyway).
+        NativeMove();
       } else {  // must be eWindowType_toplevel
         SetDefaultIcon();
         gtk_window_set_wmclass(GTK_WINDOW(mShell), "Toplevel",
@@ -3918,23 +3997,27 @@ void nsWindow::NativeMoveResize() {
   LOG(("nsWindow::NativeMoveResize [%p] %d %d %d %d\n", (void *)this, topLeft.x,
        topLeft.y, size.width, size.height));
 
-  if (mIsTopLevel) {
-    // x and y give the position of the window manager frame top-left.
-    gtk_window_move(GTK_WINDOW(mShell), topLeft.x, topLeft.y);
-    // This sets the client window size.
-    MOZ_ASSERT(size.width > 0 && size.height > 0,
-               "Can't resize window smaller than 1x1.");
-    gtk_window_resize(GTK_WINDOW(mShell), size.width, size.height);
-  } else if (mContainer) {
-    GtkAllocation allocation;
-    allocation.x = topLeft.x;
-    allocation.y = topLeft.y;
-    allocation.width = size.width;
-    allocation.height = size.height;
-    gtk_widget_size_allocate(GTK_WIDGET(mContainer), &allocation);
-  } else if (mGdkWindow) {
-    gdk_window_move_resize(mGdkWindow, topLeft.x, topLeft.y, size.width,
-                           size.height);
+  if (!mIsX11Display && mIsTopLevel && mWindowType == eWindowType_popup) {
+    NativeMoveResizeWaylandPopup(&topLeft, &size);
+  } else {
+    if (mIsTopLevel) {
+      // x and y give the position of the window manager frame top-left.
+      gtk_window_move(GTK_WINDOW(mShell), topLeft.x, topLeft.y);
+      // This sets the client window size.
+      MOZ_ASSERT(size.width > 0 && size.height > 0,
+                 "Can't resize window smaller than 1x1.");
+      gtk_window_resize(GTK_WINDOW(mShell), size.width, size.height);
+    } else if (mContainer) {
+      GtkAllocation allocation;
+      allocation.x = topLeft.x;
+      allocation.y = topLeft.y;
+      allocation.width = size.width;
+      allocation.height = size.height;
+      gtk_widget_size_allocate(GTK_WIDGET(mContainer), &allocation);
+    } else if (mGdkWindow) {
+      gdk_window_move_resize(mGdkWindow, topLeft.x, topLeft.y, size.width,
+                             size.height);
+    }
   }
 
 #ifdef MOZ_X11
@@ -6818,3 +6901,18 @@ void nsWindow::ForceTitlebarRedraw(void)
                                     RestyleHint{0}, nsChangeHint_RepaintFrame);
   }
 }
+
+GtkTextDirection nsWindow::GetTextDirection() {
+  nsView *view = nsView::GetViewFor(this);
+  if (!view) {
+    return GTK_TEXT_DIR_LTR;
+  }
+  nsIFrame *frame = view->GetFrame();
+  if (!frame) {
+    return GTK_TEXT_DIR_LTR;
+  }
+
+  WritingMode wm = frame->GetWritingMode();
+  bool isFrameRTL = !(wm.IsVertical() ? wm.IsVerticalLR() : wm.IsBidiLTR());
+  return isFrameRTL ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR;
+}
diff -up firefox-67.0/widget/gtk/nsWindow.h.mozilla-1423598-popup firefox-67.0/widget/gtk/nsWindow.h
--- firefox-67.0/widget/gtk/nsWindow.h.mozilla-1423598-popup	2019-05-14 01:08:37.000000000 +0200
+++ firefox-67.0/widget/gtk/nsWindow.h	2019-05-15 15:21:25.890221541 +0200
@@ -460,6 +460,10 @@ class nsWindow final : public nsBaseWidg
   nsWindow* GetTransientForWindowIfPopup();
   bool IsHandlingTouchSequence(GdkEventSequence* aSequence);
 
+  void NativeMoveResizeWaylandPopup(GdkPoint* aPosition, GdkRectangle* aSize);
+
+  GtkTextDirection GetTextDirection();
+
 #ifdef MOZ_X11
   typedef enum {GTK_WIDGET_COMPOSIDED_DEFAULT = 0,
                 GTK_WIDGET_COMPOSIDED_DISABLED = 1,