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:
Martin Stransky 2019-04-25 09:00:16 +00:00
Родитель 8d940c6e4d
Коммит 29fe37289b
2 изменённых файлов: 148 добавлений и 34 удалений

Просмотреть файл

@ -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.
* *