зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1661516 [Wayland] Don't use context menu shift in nsMenuPopupFrame::SetPopupPosition(), r=jhorak
- Clear mAdjustOffsetForContextMenu at nsMenuPopupFrame when running on Wayland and use move-to-rect to produce the offset. - Implement nsWindow::WaylandPopupIsContextMenu() - Use mBonuds directly in NativeMoveResizeWaylandPopupCallback() instead of Gtk query. - Add some more loggin and code polishing. Differential Revision: https://phabricator.services.mozilla.com/D117283
This commit is contained in:
Родитель
e436a16c30
Коммит
4da0695dac
|
@ -550,12 +550,7 @@ void nsMenuPopupFrame::LayoutPopup(nsBoxLayoutState& aState,
|
|||
}
|
||||
prefSize = XULBoundsCheck(minSize, prefSize, maxSize);
|
||||
|
||||
#ifdef MOZ_WAYLAND
|
||||
static bool inWayland = mozilla::widget::GdkIsWaylandDisplay();
|
||||
#else
|
||||
static bool inWayland = false;
|
||||
#endif
|
||||
if (inWayland) {
|
||||
if (mozilla::widget::GdkIsWaylandDisplay()) {
|
||||
// If prefSize it is not a whole number in css pixels we need round it up
|
||||
// to avoid reflow of the tooltips/popups and putting the text on two lines
|
||||
// (usually happens with 200% scale factor and font scale factor <> 1)
|
||||
|
@ -905,7 +900,9 @@ void nsMenuPopupFrame::InitializePopupAtScreen(nsIContent* aTriggerContent,
|
|||
mPopupAlignment = POPUPALIGNMENT_NONE;
|
||||
mPosition = POPUPPOSITION_UNKNOWN;
|
||||
mIsContextMenu = aIsContextMenu;
|
||||
mAdjustOffsetForContextMenu = aIsContextMenu;
|
||||
// Wayland does menu adjustments at widget code
|
||||
mAdjustOffsetForContextMenu =
|
||||
mozilla::widget::GdkIsWaylandDisplay() ? false : aIsContextMenu;
|
||||
mIsNativeMenu = false;
|
||||
mAnchorType = MenuPopupAnchorType_Point;
|
||||
mPositionedOffset = 0;
|
||||
|
@ -924,7 +921,8 @@ void nsMenuPopupFrame::InitializePopupAsNativeContextMenu(
|
|||
mPopupAlignment = POPUPALIGNMENT_NONE;
|
||||
mPosition = POPUPPOSITION_UNKNOWN;
|
||||
mIsContextMenu = true;
|
||||
mAdjustOffsetForContextMenu = true;
|
||||
// Wayland does menu adjustments at widget code
|
||||
mAdjustOffsetForContextMenu = !mozilla::widget::GdkIsWaylandDisplay();
|
||||
mIsNativeMenu = true;
|
||||
mAnchorType = MenuPopupAnchorType_Point;
|
||||
mPositionedOffset = 0;
|
||||
|
@ -1629,16 +1627,11 @@ nsresult nsMenuPopupFrame::SetPopupPosition(nsIFrame* aAnchorFrame,
|
|||
if (mRect.width > screenRect.width) mRect.width = screenRect.width;
|
||||
if (mRect.height > screenRect.height) mRect.height = screenRect.height;
|
||||
|
||||
// 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.
|
||||
#ifdef MOZ_WAYLAND
|
||||
static bool inWayland = mozilla::widget::GdkIsWaylandDisplay();
|
||||
#else
|
||||
static bool inWayland = false;
|
||||
#endif
|
||||
if (!inWayland) {
|
||||
// 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 (!mozilla::widget::GdkIsWaylandDisplay()) {
|
||||
// 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.
|
||||
|
@ -1781,12 +1774,7 @@ LayoutDeviceIntRect nsMenuPopupFrame::GetConstraintRect(
|
|||
nsCOMPtr<nsIScreen> screen;
|
||||
nsCOMPtr<nsIScreenManager> sm(
|
||||
do_GetService("@mozilla.org/gfx/screenmanager;1"));
|
||||
#ifdef MOZ_WAYLAND
|
||||
static bool inWayland = mozilla::widget::GdkIsWaylandDisplay();
|
||||
#else
|
||||
static bool inWayland = false;
|
||||
#endif
|
||||
if (sm && !inWayland) {
|
||||
if (sm && !mozilla::widget::GdkIsWaylandDisplay()) {
|
||||
// for content shells, get the screen where the root frame is located.
|
||||
// This is because we need to constrain the content to this content area,
|
||||
// so we should use the same screen. Otherwise, use the screen where the
|
||||
|
|
|
@ -384,8 +384,10 @@ void GetWindowOrigin(GdkWindow* aWindow, int* aX, int* aY) {
|
|||
if (aWindow) {
|
||||
gdk_window_get_origin(aWindow, aX, aY);
|
||||
}
|
||||
// GetWindowOrigin / gdk_window_get_origin is very fast on Wayland as the
|
||||
// window position is cached by Gtk.
|
||||
|
||||
// TODO(bug 1655924): gdk_window_get_origin is can block waiting for the x
|
||||
// TODO(bug 1655924): gdk_window_get_origin is can block waiting for the X
|
||||
// server for a long time, we would like to use the implementation below
|
||||
// instead. However, removing the synchronous x server queries causes a race
|
||||
// condition to surface, causing issues such as bug 1652743 and bug 1653711.
|
||||
|
@ -461,15 +463,18 @@ nsWindow::nsWindow()
|
|||
mPopupTrackInHierarchy(false),
|
||||
mPopupTrackInHierarchyConfigured(false),
|
||||
mPopupPosition(),
|
||||
mTranslatedPopupPosition(),
|
||||
mPopupAnchored(false),
|
||||
mPopupContextMenu(false),
|
||||
mRelativePopupPosition(),
|
||||
mRelativePopupOffset(),
|
||||
mPopupMatchesLayout(false),
|
||||
mPopupChanged(false),
|
||||
mPopupTemporaryHidden(false),
|
||||
mPopupClosed(false),
|
||||
mPreferredPopupRect(),
|
||||
mPreferredPopupRectFlushed(false),
|
||||
mWaitingForMoveToRectCB(false),
|
||||
mPendingSizeRect(LayoutDeviceIntRect(0, 0, 0, 0))
|
||||
mWaitingForMoveToRectCallback(false),
|
||||
mNewSizeAfterMoveToRect(LayoutDeviceIntRect(0, 0, 0, 0))
|
||||
#ifdef ACCESSIBILITY
|
||||
,
|
||||
mRootAccessible(nullptr)
|
||||
|
@ -1218,13 +1223,13 @@ void nsWindow::Enable(bool aState) { mEnabled = aState; }
|
|||
bool nsWindow::IsEnabled() const { return mEnabled; }
|
||||
|
||||
void nsWindow::Move(double aX, double aY) {
|
||||
LOG(("nsWindow::Move [%p] %f %f\n", (void*)this, aX, aY));
|
||||
|
||||
double scale =
|
||||
BoundsUseDesktopPixels() ? GetDesktopToDeviceScale().scale : 1.0;
|
||||
int32_t x = NSToIntRound(aX * scale);
|
||||
int32_t y = NSToIntRound(aY * scale);
|
||||
|
||||
LOG(("nsWindow::Move [%p] to %d %d\n", (void*)this, x, y));
|
||||
|
||||
if (mWindowType == eWindowType_toplevel ||
|
||||
mWindowType == eWindowType_dialog) {
|
||||
SetSizeMode(nsSizeMode_Normal);
|
||||
|
@ -1233,6 +1238,7 @@ void nsWindow::Move(double aX, double aY) {
|
|||
// Since a popup window's x/y coordinates are in relation to to
|
||||
// the parent, the parent might have moved so we always move a
|
||||
// popup window.
|
||||
LOG((" bounds %d %d\n", mBounds.y, mBounds.y));
|
||||
if (x == mBounds.x && y == mBounds.y && mWindowType != eWindowType_popup) {
|
||||
return;
|
||||
}
|
||||
|
@ -1568,26 +1574,40 @@ void nsWindow::WaylandPopupHierarchyCalculatePositions() {
|
|||
size.height / p2a));
|
||||
}
|
||||
#endif
|
||||
if (popup->mPopupAnchored) {
|
||||
if (popup->mPopupContextMenu && !popup->mPopupAnchored) {
|
||||
LOG_POPUP((" popup [%p] is first context menu", popup));
|
||||
static int menuOffsetX =
|
||||
LookAndFeel::GetInt(LookAndFeel::IntID::ContextMenuOffsetHorizontal);
|
||||
static int menuOffsetY =
|
||||
LookAndFeel::GetInt(LookAndFeel::IntID::ContextMenuOffsetVertical);
|
||||
popup->mRelativePopupPosition = popup->mPopupPosition;
|
||||
mRelativePopupOffset.x = menuOffsetX;
|
||||
mRelativePopupOffset.y = menuOffsetY;
|
||||
} else if (popup->mPopupAnchored) {
|
||||
LOG_POPUP((" popup [%p] is anchored", popup));
|
||||
if (!popup->mPopupMatchesLayout) {
|
||||
NS_WARNING("Anchored popup does not match layout!");
|
||||
}
|
||||
popup->mTranslatedPopupPosition = popup->mPopupPosition;
|
||||
popup->mRelativePopupPosition = popup->mPopupPosition;
|
||||
} else if (popup->mWaylandPopupPrev->mWaylandToplevel == nullptr) {
|
||||
LOG_POPUP((" popup [%p] has toplevel as parent", popup));
|
||||
popup->mTranslatedPopupPosition = popup->mPopupPosition;
|
||||
popup->mRelativePopupPosition = popup->mPopupPosition;
|
||||
} else {
|
||||
int parentX, parentY;
|
||||
GetParentPosition(&parentX, &parentY);
|
||||
|
||||
LOG_POPUP((" popup [%p] uses transformed coordinates\n", popup));
|
||||
popup->mTranslatedPopupPosition.x =
|
||||
popup->mPopupPosition.x - popup->mWaylandPopupPrev->mPopupPosition.x;
|
||||
popup->mTranslatedPopupPosition.y =
|
||||
popup->mPopupPosition.y - popup->mWaylandPopupPrev->mPopupPosition.y;
|
||||
LOG_POPUP((" parent position [%d, %d]\n", parentX, parentY));
|
||||
LOG_POPUP((" popup position [%d, %d]\n", popup->mPopupPosition.x,
|
||||
popup->mPopupPosition.y));
|
||||
|
||||
popup->mRelativePopupPosition.x = popup->mPopupPosition.x - parentX;
|
||||
popup->mRelativePopupPosition.y = popup->mPopupPosition.y - parentY;
|
||||
}
|
||||
LOG_POPUP(
|
||||
(" popup [%p] transformed popup coordinates [%d, %d] -> [%d, %d]",
|
||||
(" popup [%p] transformed popup coordinates from [%d, %d] to [%d, %d]",
|
||||
popup, popup->mPopupPosition.x, popup->mPopupPosition.y,
|
||||
popup->mTranslatedPopupPosition.x, popup->mTranslatedPopupPosition.y));
|
||||
popup->mRelativePopupPosition.x, popup->mRelativePopupPosition.y));
|
||||
popup = popup->mWaylandPopupNext;
|
||||
}
|
||||
}
|
||||
|
@ -1602,6 +1622,14 @@ bool nsWindow::WaylandPopupIsMenu() {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool nsWindow::WaylandPopupIsContextMenu() {
|
||||
nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(GetFrame());
|
||||
if (!popupFrame) {
|
||||
return false;
|
||||
}
|
||||
return popupFrame->IsContextMenu();
|
||||
}
|
||||
|
||||
bool nsWindow::WaylandPopupIsPermanent() {
|
||||
nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(GetFrame());
|
||||
if (!popupFrame) {
|
||||
|
@ -1629,6 +1657,16 @@ bool nsWindow::IsWidgetOverflowWindow() {
|
|||
return false;
|
||||
}
|
||||
|
||||
void nsWindow::GetParentPosition(int* aX, int* aY) {
|
||||
*aX = *aY = 0;
|
||||
GtkWindow* parentGtkWindow = gtk_window_get_transient_for(GTK_WINDOW(mShell));
|
||||
if (!parentGtkWindow || !GTK_IS_WIDGET(parentGtkWindow)) {
|
||||
NS_WARNING("Popup has no parent!");
|
||||
return;
|
||||
}
|
||||
GetWindowOrigin(gtk_widget_get_window(GTK_WIDGET(parentGtkWindow)), aX, aY);
|
||||
}
|
||||
|
||||
#ifdef MOZ_LOGGING
|
||||
void nsWindow::LogPopupHierarchy() {
|
||||
LOG_POPUP(("Widget Popup Hierarchy:\n"));
|
||||
|
@ -1639,15 +1677,13 @@ void nsWindow::LogPopupHierarchy() {
|
|||
nsWindow* popup = mWaylandToplevel->mWaylandPopupNext;
|
||||
while (popup) {
|
||||
nsPrintfCString indentString("%*s", indent, " ");
|
||||
nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(popup->GetFrame());
|
||||
LOG_POPUP(
|
||||
("%s %s %s nsWindow [%p] Menu %d Permanent %d ContextMenu %d "
|
||||
"Anchored %d Visible %d\n",
|
||||
indentString.get(), popup->GetWindowNodeName().get(),
|
||||
popup->GetPopupTypeName().get(), popup, popup->WaylandPopupIsMenu(),
|
||||
popup->WaylandPopupIsPermanent(),
|
||||
popupFrame && popupFrame->IsContextMenu(), popup->mPopupAnchored,
|
||||
gtk_widget_is_visible(popup->mShell)));
|
||||
popup->WaylandPopupIsPermanent(), popup->mPopupContextMenu,
|
||||
popup->mPopupAnchored, gtk_widget_is_visible(popup->mShell)));
|
||||
indent += 4;
|
||||
popup = popup->mWaylandPopupNext;
|
||||
}
|
||||
|
@ -1663,14 +1699,13 @@ void nsWindow::LogPopupHierarchy() {
|
|||
nsWindow* window = static_cast<nsWindow*>(widgetChain[i]);
|
||||
nsPrintfCString indentString("%*s", (int)(i + 1) * 4, " ");
|
||||
if (window) {
|
||||
nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(window->GetFrame());
|
||||
LOG_POPUP(
|
||||
("%s %s %s nsWindow [%p] Menu %d Permanent %d ContextMenu %d "
|
||||
"Anchored %d Visible %d\n",
|
||||
indentString.get(), window->GetWindowNodeName().get(),
|
||||
window->GetPopupTypeName().get(), window,
|
||||
window->WaylandPopupIsMenu(), window->WaylandPopupIsPermanent(),
|
||||
popupFrame && popupFrame->IsContextMenu(), window->mPopupAnchored,
|
||||
window->mPopupContextMenu, window->mPopupAnchored,
|
||||
gtk_widget_is_visible(window->mShell)));
|
||||
} else {
|
||||
LOG_POPUP(("%s null window\n", indentString.get()));
|
||||
|
@ -1712,6 +1747,7 @@ bool nsWindow::WaylandPopupNeedsTrackInHierarchy() {
|
|||
// We have nsMenuPopupFrame so we can configure the popup now.
|
||||
mPopupTrackInHierarchy = !WaylandPopupIsPermanent();
|
||||
mPopupAnchored = WaylandPopupIsAnchored();
|
||||
mPopupContextMenu = WaylandPopupIsContextMenu();
|
||||
|
||||
// See gdkwindow-wayland.c and
|
||||
// should_map_as_popup()/should_map_as_subsurface()
|
||||
|
@ -1863,9 +1899,10 @@ void nsWindow::UpdateWaylandPopupHierarchy() {
|
|||
bool useMoveToRect = popup->mPopupMatchesLayout;
|
||||
if (useMoveToRect) {
|
||||
// We use move_to_rect when:
|
||||
// Popup is anchored, i.e. it has an anchor defined by layout
|
||||
// (mPopupAnchored). Popup isn't anchored but has toplevel as parent, i.e.
|
||||
// it's first popup.
|
||||
// - Popup is anchored, i.e. it has an anchor defined by layout
|
||||
// (mPopupAnchored).
|
||||
// - Popup isn't anchored but it has toplevel as parent, i.e.
|
||||
// it's first popup.
|
||||
useMoveToRect = (popup->mPopupAnchored ||
|
||||
(!popup->mPopupAnchored &&
|
||||
popup->mWaylandPopupPrev->mWaylandToplevel == nullptr));
|
||||
|
@ -1883,88 +1920,69 @@ void nsWindow::UpdateWaylandPopupHierarchy() {
|
|||
changedPopup->WaylandPopupHierarchyShowTemporaryHidden();
|
||||
}
|
||||
|
||||
static void NativeMoveResizeWaylandPopupCallback(
|
||||
GdkWindow* window, const GdkRectangle* flipped_rect,
|
||||
const GdkRectangle* final_rect, gboolean flipped_x, gboolean flipped_y,
|
||||
void* aWindow) {
|
||||
LOG_POPUP(
|
||||
("NativeMoveResizeWaylandPopupCallback [%p] flipped_x %d flipped_y %d\n",
|
||||
aWindow, flipped_x, flipped_y));
|
||||
|
||||
LOG_POPUP((" flipped_rect x=%d y=%d width=%d height=%d\n", flipped_rect->x,
|
||||
flipped_rect->y, flipped_rect->width, flipped_rect->height));
|
||||
LOG_POPUP((" final_rect x=%d y=%d width=%d height=%d\n", final_rect->x,
|
||||
static void NativeMoveResizeCallback(GdkWindow* window,
|
||||
const GdkRectangle* flipped_rect,
|
||||
const GdkRectangle* final_rect,
|
||||
gboolean flipped_x, gboolean flipped_y,
|
||||
void* aWindow) {
|
||||
LOG_POPUP(("NativeMoveResizeCallback [%p] flipped_x %d flipped_y %d\n",
|
||||
aWindow, flipped_x, flipped_y));
|
||||
LOG_POPUP((" new position [%d, %d] -> [%d x %d]", final_rect->x,
|
||||
final_rect->y, final_rect->width, final_rect->height));
|
||||
nsWindow* wnd = get_window_for_gdk_window(window);
|
||||
|
||||
wnd->NativeMoveResizeWaylandPopupCB(final_rect, flipped_x, flipped_y);
|
||||
wnd->NativeMoveResizeWaylandPopupCallback(final_rect, flipped_x, flipped_y);
|
||||
}
|
||||
|
||||
void nsWindow::NativeMoveResizeWaylandPopupCB(const GdkRectangle* aFinalSize,
|
||||
bool aFlippedX, bool aFlippedY) {
|
||||
LOG_POPUP((" orig mBounds x=%d y=%d width=%d height=%d\n", mBounds.x,
|
||||
mBounds.y, mBounds.width, mBounds.height));
|
||||
|
||||
mWaitingForMoveToRectCB = false;
|
||||
void nsWindow::NativeMoveResizeWaylandPopupCallback(
|
||||
const GdkRectangle* aFinalSize, bool aFlippedX, bool aFlippedY) {
|
||||
mWaitingForMoveToRectCallback = false;
|
||||
|
||||
// We ignore the callback position data because the another resize has been
|
||||
// called before the callback have been triggered.
|
||||
if (mPendingSizeRect.height > 0 || mPendingSizeRect.width > 0) {
|
||||
if (mNewSizeAfterMoveToRect.height > 0 || mNewSizeAfterMoveToRect.width > 0) {
|
||||
LOG_POPUP(
|
||||
(" Another resize called during waiting for callback, calling "
|
||||
"Resize(%d, %d)\n",
|
||||
mPendingSizeRect.width, mPendingSizeRect.height));
|
||||
mNewSizeAfterMoveToRect.width, mNewSizeAfterMoveToRect.height));
|
||||
// Set the preferred size to zero to avoid wrong size of popup because the
|
||||
// mPreferredPopupRect is used in nsMenuPopupFrame to set dimensions
|
||||
mPreferredPopupRect = nsRect(0, 0, 0, 0);
|
||||
|
||||
// We need to schedule another resize because the window has been resized
|
||||
// again before callback was called.
|
||||
Resize(mPendingSizeRect.width, mPendingSizeRect.height, true);
|
||||
Resize(mNewSizeAfterMoveToRect.width, mNewSizeAfterMoveToRect.height, true);
|
||||
DispatchResized();
|
||||
mPendingSizeRect.width = mPendingSizeRect.height = 0;
|
||||
mNewSizeAfterMoveToRect.width = mNewSizeAfterMoveToRect.height = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: use out widget hierarchy to calculate widget position/hierarchy.
|
||||
GtkWindow* parentGtkWindow = gtk_window_get_transient_for(GTK_WINDOW(mShell));
|
||||
if (!parentGtkWindow || !GTK_IS_WIDGET(parentGtkWindow)) {
|
||||
NS_WARNING("Popup has no parent!");
|
||||
return;
|
||||
}
|
||||
int parentX, parentY;
|
||||
GetParentPosition(&parentX, &parentY);
|
||||
|
||||
// The position of the menu in GTK is relative to it's parent window while
|
||||
// in mBounds we have position relative to toplevel window. We need to check
|
||||
// and update mBounds in the toplevel coordinates.
|
||||
int x_parent, y_parent;
|
||||
GetWindowOrigin(gtk_widget_get_window(GTK_WIDGET(parentGtkWindow)), &x_parent,
|
||||
&y_parent);
|
||||
parentX = GdkCoordToDevicePixels(parentX);
|
||||
parentY = GdkCoordToDevicePixels(parentY);
|
||||
|
||||
LayoutDeviceIntRect newBounds(aFinalSize->x, aFinalSize->y, aFinalSize->width,
|
||||
aFinalSize->height);
|
||||
LOG_POPUP((" orig mBounds [%d, %d] -> [%d x %d]\n", mBounds.x, mBounds.y,
|
||||
mBounds.width, mBounds.height));
|
||||
|
||||
newBounds.x = GdkCoordToDevicePixels(newBounds.x);
|
||||
newBounds.y = GdkCoordToDevicePixels(newBounds.y);
|
||||
LayoutDeviceIntRect newBounds(0, 0, aFinalSize->width, aFinalSize->height);
|
||||
newBounds.x = GdkCoordToDevicePixels(aFinalSize->x) + parentX;
|
||||
newBounds.y = GdkCoordToDevicePixels(aFinalSize->y) + parentY;
|
||||
|
||||
double scale =
|
||||
BoundsUseDesktopPixels() ? GetDesktopToDeviceScale().scale : 1.0;
|
||||
int32_t newWidth = NSToIntRound(scale * newBounds.width);
|
||||
int32_t newHeight = NSToIntRound(scale * newBounds.height);
|
||||
|
||||
// Convert newBounds to "absolute" coordinates (relative to toplevel)
|
||||
newBounds.x += x_parent * GdkCeiledScaleFactor();
|
||||
newBounds.y += y_parent * GdkCeiledScaleFactor();
|
||||
|
||||
LOG_POPUP(
|
||||
(" new mBounds x=%d y=%d width=%d height=%d x_parent=%d y_parent=%d\n",
|
||||
newBounds.x, newBounds.y, newWidth, newHeight, x_parent, y_parent));
|
||||
LOG_POPUP((" new mBounds [%d, %d] -> [%d x %d]", newBounds.x, newBounds.y,
|
||||
newWidth, newHeight));
|
||||
|
||||
bool needsPositionUpdate =
|
||||
(newBounds.x != mBounds.x || newBounds.y != mBounds.y);
|
||||
bool needsSizeUpdate =
|
||||
(newWidth != mBounds.width || newHeight != mBounds.height);
|
||||
// Update view
|
||||
|
||||
if (needsSizeUpdate) {
|
||||
LOG_POPUP((" needSizeUpdate\n"));
|
||||
// TODO: use correct monitor here?
|
||||
|
@ -1988,14 +2006,11 @@ void nsWindow::NativeMoveResizeWaylandPopupCB(const GdkRectangle* aFinalSize,
|
|||
}
|
||||
|
||||
if (needsPositionUpdate) {
|
||||
LOG_POPUP((" needPositionUpdate\n"));
|
||||
// The newBounds are in coordinates relative to the parent window/popup.
|
||||
// The NotifyWindowMoved requires the coordinates relative to the toplevel.
|
||||
// We use the gdk_window_get_origin to get correct coordinates.
|
||||
// TODO: anchored/unanchored
|
||||
gint x, y;
|
||||
GetWindowOrigin(gtk_widget_get_window(GTK_WIDGET(mShell)), &x, &y);
|
||||
NotifyWindowMoved(GdkCoordToDevicePixels(x), GdkCoordToDevicePixels(y));
|
||||
LOG_POPUP((" needPositionUpdate, new bounds [%d, %d]", newBounds.x,
|
||||
newBounds.y));
|
||||
mBounds.x = newBounds.x;
|
||||
mBounds.y = newBounds.y;
|
||||
NotifyWindowMoved(mBounds.x, mBounds.y);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2084,23 +2099,34 @@ void nsWindow::WaylandPopupMove(bool aUseMoveToRect) {
|
|||
gint, gint))dlsym(RTLD_DEFAULT, "gdk_window_move_to_rect");
|
||||
|
||||
GdkWindow* gdkWindow = gtk_widget_get_window(GTK_WIDGET(mShell));
|
||||
|
||||
if (!sGdkWindowMoveToRect || !gdkWindow || !aUseMoveToRect) {
|
||||
LOG_POPUP((" use gtk_window_move(%d, %d)\n", mTranslatedPopupPosition.x,
|
||||
mTranslatedPopupPosition.y));
|
||||
gtk_window_move(GTK_WINDOW(mShell), mTranslatedPopupPosition.x,
|
||||
mTranslatedPopupPosition.y);
|
||||
return;
|
||||
}
|
||||
nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(GetFrame());
|
||||
|
||||
LOG_POPUP((" original widget popup position [%d, %d]\n", mPopupPosition.x,
|
||||
mPopupPosition.y));
|
||||
LOG_POPUP((" translated widget popup position [%d, %d]\n",
|
||||
mTranslatedPopupPosition.x, mTranslatedPopupPosition.y));
|
||||
LOG_POPUP((" relative widget popup position [%d, %d]\n",
|
||||
mRelativePopupPosition.x, mRelativePopupPosition.y));
|
||||
LOG_POPUP((" relative widget popup offset [%d, %d]\n",
|
||||
mRelativePopupOffset.x, mRelativePopupOffset.y));
|
||||
|
||||
if (!sGdkWindowMoveToRect || !gdkWindow || !aUseMoveToRect || !popupFrame) {
|
||||
LOG_POPUP((" use gtk_window_move(%d, %d)\n", mRelativePopupPosition.x,
|
||||
mRelativePopupPosition.y));
|
||||
gtk_window_move(GTK_WINDOW(mShell),
|
||||
mRelativePopupPosition.x + mRelativePopupOffset.x,
|
||||
mRelativePopupPosition.y + mRelativePopupOffset.y);
|
||||
if (mRelativePopupOffset.x || mRelativePopupOffset.y) {
|
||||
mBounds.x = (mRelativePopupPosition.x + mRelativePopupOffset.x) *
|
||||
FractionalScaleFactor();
|
||||
mBounds.y = (mRelativePopupPosition.y + mRelativePopupOffset.y) *
|
||||
FractionalScaleFactor();
|
||||
LOG_POPUP((" setting new bounds [%d, %d]\n", mBounds.x, mBounds.y));
|
||||
NotifyWindowMoved(mBounds.x, mBounds.y);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Get anchor rectangle
|
||||
LayoutDeviceIntRect anchorRect(0, 0, 0, 0);
|
||||
nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(GetFrame());
|
||||
|
||||
int32_t p2a;
|
||||
double devPixelsPerCSSPixel = StaticPrefs::layout_css_devPixelsPerPx();
|
||||
|
@ -2109,60 +2135,65 @@ void nsWindow::WaylandPopupMove(bool aUseMoveToRect) {
|
|||
} else {
|
||||
p2a = AppUnitsPerCSSPixel() / gfxPlatformGtk::GetFontScaleFactor();
|
||||
}
|
||||
if (popupFrame) {
|
||||
#ifdef MOZ_WAYLAND
|
||||
nsRect anchorRectAppUnits = popupFrame->GetAnchorRect();
|
||||
anchorRect = LayoutDeviceIntRect::FromUnknownRect(
|
||||
anchorRectAppUnits.ToNearestPixels(p2a));
|
||||
#endif
|
||||
}
|
||||
LOG_POPUP((" layout popup position [%d, %d]\n", anchorRect.x, anchorRect.y));
|
||||
|
||||
#ifdef MOZ_WAYLAND
|
||||
bool hasAnchorRect = true;
|
||||
#endif
|
||||
if (anchorRect.width == 0) {
|
||||
LOG_POPUP((" No anchor rect given, use position for anchor"));
|
||||
anchorRect.SetRect(mPopupPosition.x, mPopupPosition.y, 1, 1);
|
||||
#ifdef MOZ_WAYLAND
|
||||
hasAnchorRect = false;
|
||||
#endif
|
||||
}
|
||||
LOG_POPUP((" anchor x %d y %d width %d height %d (absolute coords)\n",
|
||||
anchorRect.x, anchorRect.y, anchorRect.width, anchorRect.height));
|
||||
nsRect anchorRectAppUnits = popupFrame->GetAnchorRect();
|
||||
anchorRect = LayoutDeviceIntRect::FromUnknownRect(
|
||||
anchorRectAppUnits.ToNearestPixels(p2a));
|
||||
|
||||
// Anchor rect is in the toplevel coordinates but we need to transfer it to
|
||||
// the coordinates relative to the popup parent for the
|
||||
// gdk_window_move_to_rect
|
||||
if (mWaylandPopupPrev->mWaylandToplevel != nullptr) {
|
||||
anchorRect.x -= mWaylandPopupPrev->mPopupPosition.x;
|
||||
anchorRect.y -= mWaylandPopupPrev->mPopupPosition.y;
|
||||
LOG_POPUP((" layout popup anchor [%d, %d] -> [%d, %d]\n", anchorRect.x,
|
||||
anchorRect.y, anchorRect.width, anchorRect.height));
|
||||
|
||||
bool hasAnchorRect = true;
|
||||
if (mRelativePopupOffset.x || mRelativePopupOffset.y) {
|
||||
hasAnchorRect = false;
|
||||
anchorRect.SetRect(mRelativePopupPosition.x - mRelativePopupOffset.x,
|
||||
mRelativePopupPosition.y - mRelativePopupOffset.y,
|
||||
mRelativePopupOffset.x * 2, mRelativePopupOffset.y * 2);
|
||||
LOG_POPUP((" Set anchor rect with offset [%d, %d] -> [%d x %d]",
|
||||
anchorRect.x, anchorRect.y, anchorRect.width,
|
||||
anchorRect.height));
|
||||
} else if (anchorRect.width == 0) {
|
||||
LOG_POPUP((" No anchor rect given, use position for anchor [%d, %d]",
|
||||
mRelativePopupPosition.x, mRelativePopupPosition.y));
|
||||
hasAnchorRect = false;
|
||||
anchorRect.SetRect(mRelativePopupPosition.x, mRelativePopupPosition.y, 1,
|
||||
1);
|
||||
} else {
|
||||
if (mWaylandPopupPrev->mWaylandToplevel != nullptr) {
|
||||
int parentX, parentY;
|
||||
GetParentPosition(&parentX, &parentY);
|
||||
LOG_POPUP((" subtract parent position [%d, %d]\n", parentX, parentY));
|
||||
anchorRect.x -= parentX;
|
||||
anchorRect.y -= parentY;
|
||||
}
|
||||
}
|
||||
|
||||
GdkRectangle rect = {anchorRect.x, anchorRect.y, anchorRect.width,
|
||||
anchorRect.height};
|
||||
|
||||
LOG_POPUP((" final popup position [%d, %d]\n", anchorRect.x, anchorRect.y));
|
||||
LOG_POPUP((" final popup rect position [%d, %d] -> [%d x %d]\n",
|
||||
anchorRect.x, anchorRect.y, anchorRect.width, anchorRect.height));
|
||||
|
||||
// Get gravity and flip type
|
||||
GdkGravity rectAnchor = GDK_GRAVITY_NORTH_WEST;
|
||||
GdkGravity menuAnchor = GDK_GRAVITY_NORTH_WEST;
|
||||
FlipType flipType = FlipType_Default;
|
||||
int8_t position = -1;
|
||||
if (popupFrame) {
|
||||
#ifdef MOZ_WAYLAND
|
||||
if (mPopupContextMenu && !mPopupAnchored) {
|
||||
if (GetTextDirection() == GTK_TEXT_DIR_RTL) {
|
||||
rectAnchor = GDK_GRAVITY_SOUTH_WEST;
|
||||
menuAnchor = GDK_GRAVITY_NORTH_EAST;
|
||||
|
||||
} else {
|
||||
rectAnchor = GDK_GRAVITY_SOUTH_EAST;
|
||||
menuAnchor = GDK_GRAVITY_NORTH_WEST;
|
||||
}
|
||||
} else {
|
||||
rectAnchor = PopupAlignmentToGdkGravity(popupFrame->GetPopupAnchor());
|
||||
menuAnchor = PopupAlignmentToGdkGravity(popupFrame->GetPopupAlignment());
|
||||
flipType = popupFrame->GetFlipType();
|
||||
position = popupFrame->GetAlignmentPosition();
|
||||
#endif
|
||||
} else {
|
||||
LOG_POPUP((" NO ANCHOR INFO"));
|
||||
if (GetTextDirection() == GTK_TEXT_DIR_RTL) {
|
||||
rectAnchor = GDK_GRAVITY_NORTH_EAST;
|
||||
menuAnchor = GDK_GRAVITY_NORTH_EAST;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_POPUP((" parentRect gravity: %d anchor gravity: %d\n", rectAnchor,
|
||||
menuAnchor));
|
||||
|
||||
|
@ -2183,8 +2214,7 @@ void nsWindow::WaylandPopupMove(bool aUseMoveToRect) {
|
|||
hints = GdkAnchorHints(hints | GDK_ANCHOR_SLIDE_Y);
|
||||
}
|
||||
|
||||
if (popupFrame && rectAnchor == GDK_GRAVITY_CENTER &&
|
||||
menuAnchor == GDK_GRAVITY_CENTER) {
|
||||
if (rectAnchor == GDK_GRAVITY_CENTER && menuAnchor == GDK_GRAVITY_CENTER) {
|
||||
// only slide
|
||||
hints = GdkAnchorHints(hints | GDK_ANCHOR_SLIDE);
|
||||
} else {
|
||||
|
@ -2231,14 +2261,10 @@ void nsWindow::WaylandPopupMove(bool aUseMoveToRect) {
|
|||
gtk_widget_hide(mShell);
|
||||
}
|
||||
|
||||
LOG_POPUP((" requested rect: x: %d y: %d width: %d height: %d\n", rect.x,
|
||||
rect.y, rect.width, rect.height));
|
||||
|
||||
// Inspired by nsMenuPopupFrame::AdjustPositionForAnchorAlign
|
||||
nsPoint cursorOffset(0, 0);
|
||||
#ifdef MOZ_WAYLAND
|
||||
// Offset is already computed to the tooltips
|
||||
if (hasAnchorRect && popupFrame && mPopupType != ePopupTypeTooltip) {
|
||||
if (hasAnchorRect && mPopupType != ePopupTypeTooltip) {
|
||||
nsMargin margin(0, 0, 0, 0);
|
||||
popupFrame->StyleMargin()->GetMargin(margin);
|
||||
switch (popupFrame->GetPopupAlignment()) {
|
||||
|
@ -2257,18 +2283,18 @@ void nsWindow::WaylandPopupMove(bool aUseMoveToRect) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!g_signal_handler_find(
|
||||
gdkWindow, G_SIGNAL_MATCH_FUNC, 0, 0, nullptr,
|
||||
FuncToGpointer(NativeMoveResizeWaylandPopupCallback), this)) {
|
||||
if (!g_signal_handler_find(gdkWindow, G_SIGNAL_MATCH_FUNC, 0, 0, nullptr,
|
||||
FuncToGpointer(NativeMoveResizeCallback), this)) {
|
||||
g_signal_connect(gdkWindow, "moved-to-rect",
|
||||
G_CALLBACK(NativeMoveResizeWaylandPopupCallback), this);
|
||||
G_CALLBACK(NativeMoveResizeCallback), this);
|
||||
}
|
||||
|
||||
LOG_POPUP((" popup window cursor offset x: %d y: %d\n", cursorOffset.x / p2a,
|
||||
cursorOffset.y / p2a));
|
||||
mWaitingForMoveToRectCB = true;
|
||||
GdkRectangle rect = {anchorRect.x, anchorRect.y, anchorRect.width,
|
||||
anchorRect.height};
|
||||
mWaitingForMoveToRectCallback = true;
|
||||
sGdkWindowMoveToRect(gdkWindow, &rect, rectAnchor, menuAnchor, hints,
|
||||
cursorOffset.x / p2a, cursorOffset.y / p2a);
|
||||
|
||||
|
@ -5568,7 +5594,8 @@ nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
|
|||
|
||||
// resize so that everything is set to the right dimensions
|
||||
if (!mIsTopLevel) {
|
||||
Resize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, false);
|
||||
ResizeInt(mBounds.x, mBounds.y, mBounds.width, mBounds.height,
|
||||
/* aMove */ false, /* aRepaint */ false);
|
||||
}
|
||||
|
||||
#ifdef MOZ_X11
|
||||
|
@ -5696,9 +5723,9 @@ void nsWindow::NativeResize() {
|
|||
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);
|
||||
if (mWaitingForMoveToRectCB) {
|
||||
if (mWaitingForMoveToRectCallback) {
|
||||
LOG_POPUP((" waiting for move to rect, schedulling "));
|
||||
mPendingSizeRect = mBounds;
|
||||
mNewSizeAfterMoveToRect = mBounds;
|
||||
}
|
||||
} else if (mContainer) {
|
||||
GtkWidget* widget = GTK_WIDGET(mContainer);
|
||||
|
|
|
@ -375,8 +375,8 @@ class nsWindow final : public nsBaseWidget {
|
|||
static bool GetTopLevelWindowActiveState(nsIFrame* aFrame);
|
||||
static bool TitlebarUseShapeMask();
|
||||
bool IsRemoteContent() { return HasRemoteContent(); }
|
||||
void NativeMoveResizeWaylandPopupCB(const GdkRectangle* aFinalSize,
|
||||
bool aFlippedX, bool aFlippedY);
|
||||
void NativeMoveResizeWaylandPopupCallback(const GdkRectangle* aFinalSize,
|
||||
bool aFlippedX, bool aFlippedY);
|
||||
static bool IsToplevelWindowTransparent();
|
||||
|
||||
#ifdef MOZ_WAYLAND
|
||||
|
@ -615,10 +615,13 @@ class nsWindow final : public nsBaseWidget {
|
|||
|
||||
void ApplySizeConstraints(void);
|
||||
|
||||
void GetParentPosition(int* aX, int* aY);
|
||||
|
||||
// Wayland Popup section
|
||||
bool WaylandPopupNeedsTrackInHierarchy();
|
||||
bool WaylandPopupIsAnchored();
|
||||
bool WaylandPopupIsMenu();
|
||||
bool WaylandPopupIsContextMenu();
|
||||
bool WaylandPopupIsPermanent();
|
||||
bool IsWidgetOverflowWindow();
|
||||
void RemovePopupFromHierarchyList();
|
||||
|
@ -697,9 +700,17 @@ class nsWindow final : public nsBaseWidget {
|
|||
*/
|
||||
bool mPopupAnchored;
|
||||
|
||||
/* Translated mPopupPosition against parent window when it's anchored.
|
||||
/* When popup is context menu.
|
||||
*/
|
||||
GdkPoint mTranslatedPopupPosition;
|
||||
bool mPopupContextMenu;
|
||||
|
||||
/* mRelativePopupPosition is popup position calculated against parent window.
|
||||
*/
|
||||
GdkPoint mRelativePopupPosition;
|
||||
|
||||
/* mRelativePopupOffset is used by context menus.
|
||||
*/
|
||||
GdkPoint mRelativePopupOffset;
|
||||
|
||||
/* Indicates that this popup matches layout setup so we can use
|
||||
* parent popup coordinates reliably.
|
||||
|
@ -735,13 +746,14 @@ class nsWindow final : public nsBaseWidget {
|
|||
nsRect mPreferredPopupRect;
|
||||
bool mPreferredPopupRectFlushed;
|
||||
|
||||
/* Set true when we call move-to-rect and before move-to-rect callback
|
||||
* comes back another resize is issued. In such case we need to ignore
|
||||
* size from move-to-rect callback callback and use size from the latest
|
||||
* resize (mPendingSizeRect).
|
||||
/* mWaitingForMoveToRectCallback is set when move-to-rect is called
|
||||
* and we're waiting for move-to-rect callback.
|
||||
*
|
||||
* If another resize request comes between move-to-rect call and
|
||||
* move-to-rect callback we store it to mNewSizeAfterMoveToRect.
|
||||
*/
|
||||
bool mWaitingForMoveToRectCB;
|
||||
LayoutDeviceIntRect mPendingSizeRect;
|
||||
bool mWaitingForMoveToRectCallback;
|
||||
LayoutDeviceIntRect mNewSizeAfterMoveToRect;
|
||||
|
||||
/**
|
||||
* |mIMContext| takes all IME related stuff.
|
||||
|
|
Загрузка…
Ссылка в новой задаче