diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h --- a/widget/gtk/nsWindow.h +++ b/widget/gtk/nsWindow.h @@ -457,6 +457,10 @@ 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, diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -1109,13 +1109,89 @@ 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 (!sGdkWindowMoveToRect) { + gtk_window_move(GTK_WINDOW(mShell), aPosition->x, aPosition->y); + if (aSize) { + gtk_window_resize(GTK_WINDOW(mShell), aSize->width, aSize->height); + } + 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); + } } } @@ -3397,11 +3473,6 @@ 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()); @@ -3456,6 +3527,14 @@ 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", @@ -3895,23 +3974,27 @@ 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 @@ -6791,3 +6874,18 @@ 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; +}