зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1423598 - [Wayland] Use gdk_window_move_to_rect() to place popup windows, r=ashie
Differential Revision: https://phabricator.services.mozilla.com/D22962 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
8d940c6e4d
Коммит
29fe37289b
|
@ -1114,10 +1114,93 @@ void nsWindow::Move(double aX, double aY) {
|
||||||
NotifyRollupGeometryChange();
|
NotifyRollupGeometryChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool nsWindow::IsWaylandPopup() {
|
||||||
|
return !mIsX11Display && mIsTopLevel && mWindowType == eWindowType_popup;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
static void NativeMoveResizeWaylandPopupCallback(
|
||||||
|
GdkWindow *window, const GdkRectangle *flipped_rect,
|
||||||
|
const GdkRectangle *final_rect, gboolean flipped_x, gboolean flipped_y,
|
||||||
|
void *unused) {
|
||||||
|
LOG(("%s flipped %d %d\n", __FUNCTION__, flipped_rect->x, flipped_rect->y));
|
||||||
|
LOG(("%s final %d %d\n", __FUNCTION__, 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
GdkWindow *gdkWindow = gtk_widget_get_window(GTK_WIDGET(mShell));
|
||||||
|
// gdk_window_move_to_rect() is not available, we don't have a valid GdkWindow
|
||||||
|
// (we're not realized yet) - try plain gtk_window_move() at least.
|
||||||
|
if (!sGdkWindowMoveToRect || !gdkWindow) {
|
||||||
|
gtk_window_move(GTK_WINDOW(mShell), aPosition->x, aPosition->y);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GtkWindow *parentWindow = GetPopupParentWindow();
|
||||||
|
if (parentWindow) {
|
||||||
|
gtk_window_set_transient_for(GTK_WINDOW(mShell), parentWindow);
|
||||||
|
} else {
|
||||||
|
parentWindow = gtk_window_get_transient_for(GTK_WINDOW(mShell));
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(("nsWindow::NativeMoveResizeWaylandPopup [%p] Set popup parent %p\n",
|
||||||
|
(void *)this, parentWindow));
|
||||||
|
|
||||||
|
int x_parent, y_parent;
|
||||||
|
gdk_window_get_origin(gtk_widget_get_window(GTK_WIDGET(parentWindow)),
|
||||||
|
&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;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(("%s [%p] request position %d,%d\n", __FUNCTION__, (void *)this,
|
||||||
|
aPosition->x, aPosition->y));
|
||||||
|
if (aSize) {
|
||||||
|
LOG((" request size %d,%d\n", aSize->width, aSize->height));
|
||||||
|
}
|
||||||
|
LOG((" request result %d %d\n", rect.x, rect.y));
|
||||||
|
#ifdef DEBUG
|
||||||
|
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() {
|
void nsWindow::NativeMove() {
|
||||||
GdkPoint point = DevicePixelsToGdkPointRoundDown(mBounds.TopLeft());
|
GdkPoint point = DevicePixelsToGdkPointRoundDown(mBounds.TopLeft());
|
||||||
|
|
||||||
if (mIsTopLevel) {
|
LOG(("nsWindow::NativeMove [%p] %d %d\n", (void *)this, point.x, point.y));
|
||||||
|
|
||||||
|
if (IsWaylandPopup()) {
|
||||||
|
NativeMoveResizeWaylandPopup(&point, nullptr);
|
||||||
|
} else if (mIsTopLevel) {
|
||||||
gtk_window_move(GTK_WINDOW(mShell), point.x, point.y);
|
gtk_window_move(GTK_WINDOW(mShell), point.x, point.y);
|
||||||
} else if (mGdkWindow) {
|
} else if (mGdkWindow) {
|
||||||
gdk_window_move(mGdkWindow, point.x, point.y);
|
gdk_window_move(mGdkWindow, point.x, point.y);
|
||||||
|
@ -3408,11 +3491,6 @@ nsresult nsWindow::Create(nsIWidget *aParent, nsNativeWidget aNativeParent,
|
||||||
GDK_WINDOW_TYPE_HINT_DIALOG);
|
GDK_WINDOW_TYPE_HINT_DIALOG);
|
||||||
gtk_window_set_transient_for(GTK_WINDOW(mShell), topLevelParent);
|
gtk_window_set_transient_for(GTK_WINDOW(mShell), topLevelParent);
|
||||||
} else if (mWindowType == eWindowType_popup) {
|
} 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",
|
gtk_window_set_wmclass(GTK_WINDOW(mShell), "Popup",
|
||||||
gdk_get_program_class());
|
gdk_get_program_class());
|
||||||
|
|
||||||
|
@ -3465,8 +3543,18 @@ nsresult nsWindow::Create(nsIWidget *aParent, nsNativeWidget aNativeParent,
|
||||||
gtk_window_set_type_hint(GTK_WINDOW(mShell), gtkTypeHint);
|
gtk_window_set_type_hint(GTK_WINDOW(mShell), gtkTypeHint);
|
||||||
|
|
||||||
if (topLevelParent) {
|
if (topLevelParent) {
|
||||||
|
LOG(("nsWindow::Create [%p] Set popup parent %p\n", (void *)this,
|
||||||
|
topLevelParent));
|
||||||
gtk_window_set_transient_for(GTK_WINDOW(mShell), 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
|
} else { // must be eWindowType_toplevel
|
||||||
SetDefaultIcon();
|
SetDefaultIcon();
|
||||||
gtk_window_set_wmclass(GTK_WINDOW(mShell), "Toplevel",
|
gtk_window_set_wmclass(GTK_WINDOW(mShell), "Toplevel",
|
||||||
|
@ -3910,23 +3998,27 @@ void nsWindow::NativeMoveResize() {
|
||||||
LOG(("nsWindow::NativeMoveResize [%p] %d %d %d %d\n", (void *)this, topLeft.x,
|
LOG(("nsWindow::NativeMoveResize [%p] %d %d %d %d\n", (void *)this, topLeft.x,
|
||||||
topLeft.y, size.width, size.height));
|
topLeft.y, size.width, size.height));
|
||||||
|
|
||||||
if (mIsTopLevel) {
|
if (IsWaylandPopup()) {
|
||||||
// x and y give the position of the window manager frame top-left.
|
NativeMoveResizeWaylandPopup(&topLeft, &size);
|
||||||
gtk_window_move(GTK_WINDOW(mShell), topLeft.x, topLeft.y);
|
} else {
|
||||||
// This sets the client window size.
|
if (mIsTopLevel) {
|
||||||
MOZ_ASSERT(size.width > 0 && size.height > 0,
|
// x and y give the position of the window manager frame top-left.
|
||||||
"Can't resize window smaller than 1x1.");
|
gtk_window_move(GTK_WINDOW(mShell), topLeft.x, topLeft.y);
|
||||||
gtk_window_resize(GTK_WINDOW(mShell), size.width, size.height);
|
// This sets the client window size.
|
||||||
} else if (mContainer) {
|
MOZ_ASSERT(size.width > 0 && size.height > 0,
|
||||||
GtkAllocation allocation;
|
"Can't resize window smaller than 1x1.");
|
||||||
allocation.x = topLeft.x;
|
gtk_window_resize(GTK_WINDOW(mShell), size.width, size.height);
|
||||||
allocation.y = topLeft.y;
|
} else if (mContainer) {
|
||||||
allocation.width = size.width;
|
GtkAllocation allocation;
|
||||||
allocation.height = size.height;
|
allocation.x = topLeft.x;
|
||||||
gtk_widget_size_allocate(GTK_WIDGET(mContainer), &allocation);
|
allocation.y = topLeft.y;
|
||||||
} else if (mGdkWindow) {
|
allocation.width = size.width;
|
||||||
gdk_window_move_resize(mGdkWindow, topLeft.x, topLeft.y, size.width,
|
allocation.height = size.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
|
#ifdef MOZ_X11
|
||||||
|
@ -3954,9 +4046,11 @@ void nsWindow::NativeShow(bool aAction) {
|
||||||
SetUserTimeAndStartupIDForActivatedWindow(mShell);
|
SetUserTimeAndStartupIDForActivatedWindow(mShell);
|
||||||
}
|
}
|
||||||
// Update popup window hierarchy run-time on Wayland.
|
// Update popup window hierarchy run-time on Wayland.
|
||||||
if (!mIsX11Display && mWindowType == eWindowType_popup) {
|
if (IsWaylandPopup()) {
|
||||||
GtkWindow *parentWindow = GetPopupParentWindow();
|
GtkWindow *parentWindow = GetPopupParentWindow();
|
||||||
if (parentWindow) {
|
if (parentWindow) {
|
||||||
|
LOG(("nsWindow::NativeShow [%p] Set popup parent %p\n", (void *)this,
|
||||||
|
parentWindow));
|
||||||
gtk_window_set_transient_for(GTK_WINDOW(mShell), parentWindow);
|
gtk_window_set_transient_for(GTK_WINDOW(mShell), parentWindow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5444,9 +5538,9 @@ static gboolean key_press_event_cb(GtkWidget *widget, GdkEventKey *event) {
|
||||||
// are generated only when the key is physically released.
|
// are generated only when the key is physically released.
|
||||||
# define NS_GDKEVENT_MATCH_MASK 0x1FFF // GDK_SHIFT_MASK .. GDK_BUTTON5_MASK
|
# define NS_GDKEVENT_MATCH_MASK 0x1FFF // GDK_SHIFT_MASK .. GDK_BUTTON5_MASK
|
||||||
// Our headers undefine X11 KeyPress - let's redefine it here.
|
// Our headers undefine X11 KeyPress - let's redefine it here.
|
||||||
#ifndef KeyPress
|
# ifndef KeyPress
|
||||||
#define KeyPress 2
|
# define KeyPress 2
|
||||||
#endif
|
# endif
|
||||||
GdkDisplay *gdkDisplay = gtk_widget_get_display(widget);
|
GdkDisplay *gdkDisplay = gtk_widget_get_display(widget);
|
||||||
if (GDK_IS_X11_DISPLAY(gdkDisplay)) {
|
if (GDK_IS_X11_DISPLAY(gdkDisplay)) {
|
||||||
Display *dpy = GDK_DISPLAY_XDISPLAY(gdkDisplay);
|
Display *dpy = GDK_DISPLAY_XDISPLAY(gdkDisplay);
|
||||||
|
@ -6819,18 +6913,32 @@ void nsWindow::ForceTitlebarRedraw(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GtkWindow* nsWindow::GetPopupParentWindow()
|
GtkWindow *nsWindow::GetPopupParentWindow() {
|
||||||
{
|
nsView *view = nsView::GetViewFor(this);
|
||||||
nsView* view = nsView::GetViewFor(this);
|
|
||||||
if (!view) {
|
if (!view) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
nsIFrame* frame = view->GetFrame();
|
nsIFrame *frame = view->GetFrame();
|
||||||
if (!frame) {
|
if (!frame) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
nsMenuPopupFrame* menuPopupFrame = do_QueryFrame(frame);
|
nsMenuPopupFrame *menuPopupFrame = do_QueryFrame(frame);
|
||||||
nsWindow* window =
|
nsWindow *window =
|
||||||
static_cast<nsWindow*>(menuPopupFrame->GetParentMenuWidget());
|
static_cast<nsWindow *>(menuPopupFrame->GetParentMenuWidget());
|
||||||
return window ? GTK_WINDOW(window->GetGtkWidget()) : nullptr;
|
return window ? GTK_WINDOW(window->GetGtkWidget()) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -460,6 +460,10 @@ class nsWindow final : public nsBaseWidget {
|
||||||
nsWindow* GetTransientForWindowIfPopup();
|
nsWindow* GetTransientForWindowIfPopup();
|
||||||
bool IsHandlingTouchSequence(GdkEventSequence* aSequence);
|
bool IsHandlingTouchSequence(GdkEventSequence* aSequence);
|
||||||
|
|
||||||
|
void NativeMoveResizeWaylandPopup(GdkPoint* aPosition, GdkRectangle* aSize);
|
||||||
|
|
||||||
|
GtkTextDirection GetTextDirection();
|
||||||
|
|
||||||
#ifdef MOZ_X11
|
#ifdef MOZ_X11
|
||||||
typedef enum {GTK_WIDGET_COMPOSIDED_DEFAULT = 0,
|
typedef enum {GTK_WIDGET_COMPOSIDED_DEFAULT = 0,
|
||||||
GTK_WIDGET_COMPOSIDED_DISABLED = 1,
|
GTK_WIDGET_COMPOSIDED_DISABLED = 1,
|
||||||
|
@ -608,6 +612,8 @@ class nsWindow final : public nsBaseWidget {
|
||||||
// This is used by Wayland backend to keep strict popup window hierarchy.
|
// This is used by Wayland backend to keep strict popup window hierarchy.
|
||||||
GtkWindow* GetPopupParentWindow();
|
GtkWindow* GetPopupParentWindow();
|
||||||
|
|
||||||
|
bool IsWaylandPopup();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* |mIMContext| takes all IME related stuff.
|
* |mIMContext| takes all IME related stuff.
|
||||||
*
|
*
|
||||||
|
|
Загрузка…
Ссылка в новой задаче