Bug 1965143 - Remove X11 special-case for noautohide popups that end up using toplevel windows. r=stransky
As noted in the comment for Wayland, most noautohide popups already work this way, as the noautohide attribute is dynamic. I did a quick smoke test of these popups and they still remain not autohiding as expected, and follow their anchor and so on. Differential Revision: https://phabricator.services.mozilla.com/D248413
This commit is contained in:
committed by
ealvarez@mozilla.com
parent
f8995ac2ee
commit
7d331ed1ee
@@ -284,7 +284,6 @@ nsresult nsMenuPopupFrame::CreateWidgetForView(nsView* aView) {
|
|||||||
widgetData.mBorderStyle = widget::BorderStyle::Default;
|
widgetData.mBorderStyle = widget::BorderStyle::Default;
|
||||||
widgetData.mClipSiblings = true;
|
widgetData.mClipSiblings = true;
|
||||||
widgetData.mPopupHint = mPopupType;
|
widgetData.mPopupHint = mPopupType;
|
||||||
widgetData.mNoAutoHide = IsNoAutoHide();
|
|
||||||
|
|
||||||
if (!mInContentShell) {
|
if (!mInContentShell) {
|
||||||
// A drag popup may be used for non-static translucent drag feedback
|
// A drag popup may be used for non-static translucent drag feedback
|
||||||
@@ -300,7 +299,7 @@ nsresult nsMenuPopupFrame::CreateWidgetForView(nsView* aView) {
|
|||||||
const auto mode = nsLayoutUtils::GetFrameTransparency(this, this);
|
const auto mode = nsLayoutUtils::GetFrameTransparency(this, this);
|
||||||
widgetData.mHasRemoteContent = remote;
|
widgetData.mHasRemoteContent = remote;
|
||||||
widgetData.mTransparencyMode = mode;
|
widgetData.mTransparencyMode = mode;
|
||||||
widgetData.mPopupLevel = GetPopupLevel(widgetData.mNoAutoHide);
|
widgetData.mPopupLevel = GetPopupLevel(IsNoAutoHide());
|
||||||
|
|
||||||
nsCOMPtr<nsIWidget> parentWidget = ComputeParentWidget();
|
nsCOMPtr<nsIWidget> parentWidget = ComputeParentWidget();
|
||||||
if (NS_WARN_IF(!parentWidget)) {
|
if (NS_WARN_IF(!parentWidget)) {
|
||||||
|
|||||||
@@ -83,7 +83,6 @@ struct InitData {
|
|||||||
bool mClipChildren = false;
|
bool mClipChildren = false;
|
||||||
bool mClipSiblings = false;
|
bool mClipSiblings = false;
|
||||||
bool mRTL = false;
|
bool mRTL = false;
|
||||||
bool mNoAutoHide = false; // true for noautohide panels
|
|
||||||
bool mIsDragPopup = false; // true for drag feedback panels
|
bool mIsDragPopup = false; // true for drag feedback panels
|
||||||
// true if window creation animation is suppressed, e.g. for session restore
|
// true if window creation animation is suppressed, e.g. for session restore
|
||||||
bool mIsAnimationSuppressed = false;
|
bool mIsAnimationSuppressed = false;
|
||||||
|
|||||||
@@ -249,17 +249,6 @@ static gboolean touch_event_cb(GtkWidget* aWidget, GdkEventTouch* aEvent);
|
|||||||
static gboolean generic_event_cb(GtkWidget* widget, GdkEvent* aEvent);
|
static gboolean generic_event_cb(GtkWidget* widget, GdkEvent* aEvent);
|
||||||
static void widget_destroy_cb(GtkWidget* widget, gpointer user_data);
|
static void widget_destroy_cb(GtkWidget* widget, gpointer user_data);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
#ifdef MOZ_X11
|
|
||||||
static GdkFilterReturn popup_take_focus_filter(GdkXEvent* gdk_xevent,
|
|
||||||
GdkEvent* event, gpointer data);
|
|
||||||
#endif /* MOZ_X11 */
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
static gboolean drag_motion_event_cb(GtkWidget* aWidget,
|
static gboolean drag_motion_event_cb(GtkWidget* aWidget,
|
||||||
GdkDragContext* aDragContext, gint aX,
|
GdkDragContext* aDragContext, gint aX,
|
||||||
gint aY, guint aTime, gpointer aData);
|
gint aY, guint aTime, gpointer aData);
|
||||||
@@ -445,7 +434,6 @@ nsWindow::nsWindow()
|
|||||||
mPendingBoundsChangeMayChangeCsdMargin(false),
|
mPendingBoundsChangeMayChangeCsdMargin(false),
|
||||||
mTitlebarBackdropState(false),
|
mTitlebarBackdropState(false),
|
||||||
mAlwaysOnTop(false),
|
mAlwaysOnTop(false),
|
||||||
mNoAutoHide(false),
|
|
||||||
mIsTransparent(false),
|
mIsTransparent(false),
|
||||||
mHasReceivedSizeAllocate(false),
|
mHasReceivedSizeAllocate(false),
|
||||||
mWidgetCursorLocked(false),
|
mWidgetCursorLocked(false),
|
||||||
@@ -1049,8 +1037,9 @@ void nsWindow::ResizeInt(const Maybe<LayoutDeviceIntPoint>& aMove,
|
|||||||
|
|
||||||
NativeMoveResize(moved, resized);
|
NativeMoveResize(moved, resized);
|
||||||
|
|
||||||
// We optimistically assume size changes immediately in two cases:
|
// We optimistically assume size/position changes immediately in two cases:
|
||||||
// 1. Override-redirect window: Size is controlled by only us.
|
//
|
||||||
|
// 1. Popup: Size is controlled by only us.
|
||||||
// 2. Managed window that has not not yet received a size-allocate event:
|
// 2. Managed window that has not not yet received a size-allocate event:
|
||||||
// Resize() Callers expect initial sizes to be applied synchronously.
|
// Resize() Callers expect initial sizes to be applied synchronously.
|
||||||
// If the size request is not honored, then we'll correct in
|
// If the size request is not honored, then we'll correct in
|
||||||
@@ -1064,8 +1053,7 @@ void nsWindow::ResizeInt(const Maybe<LayoutDeviceIntPoint>& aMove,
|
|||||||
// So we don't update mBounds until OnContainerSizeAllocate() when we know the
|
// So we don't update mBounds until OnContainerSizeAllocate() when we know the
|
||||||
// request is granted.
|
// request is granted.
|
||||||
bool isOrWillBeVisible = mHasReceivedSizeAllocate || mNeedsShow || mIsShown;
|
bool isOrWillBeVisible = mHasReceivedSizeAllocate || mNeedsShow || mIsShown;
|
||||||
if (!isOrWillBeVisible ||
|
if (!isOrWillBeVisible || IsPopup()) {
|
||||||
gtk_window_get_window_type(GTK_WINDOW(mShell)) == GTK_WINDOW_POPUP) {
|
|
||||||
mBounds.SizeTo(aSize);
|
mBounds.SizeTo(aSize);
|
||||||
if (moved) {
|
if (moved) {
|
||||||
mBounds.MoveTo(*aMove);
|
mBounds.MoveTo(*aMove);
|
||||||
@@ -6012,30 +6000,18 @@ nsresult nsWindow::Create(nsIWidget* aParent, const LayoutDeviceIntRect& aRect,
|
|||||||
}
|
}
|
||||||
|
|
||||||
mAlwaysOnTop = aInitData && aInitData->mAlwaysOnTop;
|
mAlwaysOnTop = aInitData && aInitData->mAlwaysOnTop;
|
||||||
// mNoAutoHide seems to be always false here.
|
|
||||||
// The mNoAutoHide state is set later on nsMenuPopupFrame level
|
|
||||||
// and can be changed so we use WaylandPopupIsPermanent() to get
|
|
||||||
// recent popup config (Bug 1728952).
|
|
||||||
mNoAutoHide = aInitData && aInitData->mNoAutoHide;
|
|
||||||
mIsAlert = aInitData && aInitData->mIsAlert;
|
mIsAlert = aInitData && aInitData->mIsAlert;
|
||||||
mIsDragPopup = aInitData && aInitData->mIsDragPopup;
|
mIsDragPopup = aInitData && aInitData->mIsDragPopup;
|
||||||
|
|
||||||
// Popups that are not noautohide are only temporary. The are used
|
// For popups, use the standard GtkWindowType GTK_WINDOW_POPUP,
|
||||||
// for menus and the like and disappear when another window is used.
|
|
||||||
// For most popups, use the standard GtkWindowType GTK_WINDOW_POPUP,
|
|
||||||
// which will use a Window with the override-redirect attribute
|
// which will use a Window with the override-redirect attribute
|
||||||
// (for temporary windows).
|
// (for temporary windows).
|
||||||
// For long-lived windows, their stacking order is managed by the
|
|
||||||
// window manager, as indicated by GTK_WINDOW_TOPLEVEL.
|
|
||||||
// For Wayland we have to always use GTK_WINDOW_POPUP to control
|
// For Wayland we have to always use GTK_WINDOW_POPUP to control
|
||||||
// popup window position.
|
// popup window position.
|
||||||
GtkWindowType type = GTK_WINDOW_TOPLEVEL;
|
GtkWindowType type = GTK_WINDOW_TOPLEVEL;
|
||||||
if (mWindowType == WindowType::Popup) {
|
if (mWindowType == WindowType::Popup) {
|
||||||
MOZ_ASSERT(aInitData);
|
MOZ_ASSERT(aInitData);
|
||||||
type = GTK_WINDOW_POPUP;
|
type = GTK_WINDOW_POPUP;
|
||||||
if (GdkIsX11Display() && mNoAutoHide) {
|
|
||||||
type = GTK_WINDOW_TOPLEVEL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
mShell = gtk_window_new(type);
|
mShell = gtk_window_new(type);
|
||||||
|
|
||||||
@@ -6127,35 +6103,6 @@ nsresult nsWindow::Create(nsIWidget* aParent, const LayoutDeviceIntRect& aRect,
|
|||||||
|
|
||||||
LOG(" nsWindow::Create() Popup");
|
LOG(" nsWindow::Create() Popup");
|
||||||
|
|
||||||
if (mNoAutoHide) {
|
|
||||||
// ... but the window manager does not decorate this window,
|
|
||||||
// nor provide a separate taskbar icon.
|
|
||||||
if (mBorderStyle == BorderStyle::Default) {
|
|
||||||
gtk_window_set_decorated(GTK_WINDOW(mShell), FALSE);
|
|
||||||
} else {
|
|
||||||
bool decorate = bool(mBorderStyle & BorderStyle::Title);
|
|
||||||
gtk_window_set_decorated(GTK_WINDOW(mShell), decorate);
|
|
||||||
if (decorate) {
|
|
||||||
gtk_window_set_deletable(GTK_WINDOW(mShell),
|
|
||||||
bool(mBorderStyle & BorderStyle::Close));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gtk_window_set_skip_taskbar_hint(GTK_WINDOW(mShell), TRUE);
|
|
||||||
// Element focus is managed by the parent window so the
|
|
||||||
// WM_HINTS input field is set to False to tell the window
|
|
||||||
// manager not to set input focus to this window ...
|
|
||||||
gtk_window_set_accept_focus(GTK_WINDOW(mShell), FALSE);
|
|
||||||
#ifdef MOZ_X11
|
|
||||||
// ... but when the window manager offers focus through
|
|
||||||
// WM_TAKE_FOCUS, focus is requested on the parent window.
|
|
||||||
if (GdkIsX11Display()) {
|
|
||||||
gtk_widget_realize(mShell);
|
|
||||||
gdk_window_add_filter(GetToplevelGdkWindow(), popup_take_focus_filter,
|
|
||||||
nullptr);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mIsDragPopup) {
|
if (mIsDragPopup) {
|
||||||
gtk_window_set_type_hint(GTK_WINDOW(mShell), GDK_WINDOW_TYPE_HINT_DND);
|
gtk_window_set_type_hint(GTK_WINDOW(mShell), GDK_WINDOW_TYPE_HINT_DND);
|
||||||
LOG(" nsWindow::Create() Drag popup\n");
|
LOG(" nsWindow::Create() Drag popup\n");
|
||||||
@@ -8085,74 +8032,6 @@ static gboolean focus_out_event_cb(GtkWidget* widget, GdkEventFocus* event) {
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MOZ_X11
|
|
||||||
// For long-lived popup windows that don't really take focus themselves but
|
|
||||||
// may have elements that accept keyboard input when the parent window is
|
|
||||||
// active, focus is handled specially. These windows include noautohide
|
|
||||||
// panels. (This special handling is not necessary for temporary popups where
|
|
||||||
// the keyboard is grabbed.)
|
|
||||||
//
|
|
||||||
// Mousing over or clicking on these windows should not cause them to steal
|
|
||||||
// focus from their parent windows, so, the input field of WM_HINTS is set to
|
|
||||||
// False to request that the window manager not set the input focus to this
|
|
||||||
// window. http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.7
|
|
||||||
//
|
|
||||||
// However, these windows can still receive WM_TAKE_FOCUS messages from the
|
|
||||||
// window manager, so they can still detect when the user has indicated that
|
|
||||||
// they wish to direct keyboard input at these windows. When the window
|
|
||||||
// manager offers focus to these windows (after a mouse over or click, for
|
|
||||||
// example), a request to make the parent window active is issued. When the
|
|
||||||
// parent window becomes active, keyboard events will be received.
|
|
||||||
|
|
||||||
static GdkFilterReturn popup_take_focus_filter(GdkXEvent* gdk_xevent,
|
|
||||||
GdkEvent* event, gpointer data) {
|
|
||||||
auto* xevent = static_cast<XEvent*>(gdk_xevent);
|
|
||||||
if (xevent->type != ClientMessage) {
|
|
||||||
return GDK_FILTER_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
XClientMessageEvent& xclient = xevent->xclient;
|
|
||||||
if (xclient.message_type != gdk_x11_get_xatom_by_name("WM_PROTOCOLS")) {
|
|
||||||
return GDK_FILTER_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
Atom atom = xclient.data.l[0];
|
|
||||||
if (atom != gdk_x11_get_xatom_by_name("WM_TAKE_FOCUS")) {
|
|
||||||
return GDK_FILTER_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
guint32 timestamp = xclient.data.l[1];
|
|
||||||
|
|
||||||
GtkWidget* widget = get_gtk_widget_for_gdk_window(event->any.window);
|
|
||||||
if (!widget) {
|
|
||||||
return GDK_FILTER_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
GtkWindow* parent = gtk_window_get_transient_for(GTK_WINDOW(widget));
|
|
||||||
if (!parent) {
|
|
||||||
return GDK_FILTER_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gtk_window_is_active(parent)) {
|
|
||||||
return GDK_FILTER_REMOVE; // leave input focus on the parent
|
|
||||||
}
|
|
||||||
|
|
||||||
GdkWindow* parent_window = gtk_widget_get_window(GTK_WIDGET(parent));
|
|
||||||
if (!parent_window) {
|
|
||||||
return GDK_FILTER_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// In case the parent has not been deiconified.
|
|
||||||
gdk_window_show_unraised(parent_window);
|
|
||||||
|
|
||||||
// Request focus on the parent window.
|
|
||||||
// Use gdk_window_focus rather than gtk_window_present to avoid
|
|
||||||
// raising the parent window.
|
|
||||||
gdk_window_focus(parent_window, timestamp);
|
|
||||||
return GDK_FILTER_REMOVE;
|
|
||||||
}
|
|
||||||
#endif /* MOZ_X11 */
|
|
||||||
|
|
||||||
static gboolean key_press_event_cb(GtkWidget* widget, GdkEventKey* event) {
|
static gboolean key_press_event_cb(GtkWidget* widget, GdkEventKey* event) {
|
||||||
LOGW("key_press_event_cb\n");
|
LOGW("key_press_event_cb\n");
|
||||||
|
|
||||||
@@ -9788,12 +9667,6 @@ void nsWindow::OnMap() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mWindowType == WindowType::Popup) {
|
if (mWindowType == WindowType::Popup) {
|
||||||
if (mNoAutoHide) {
|
|
||||||
gint wmd = ConvertBorderStyles(mBorderStyle);
|
|
||||||
if (wmd != -1) {
|
|
||||||
gdk_window_set_decorations(mGdkWindow, (GdkWMDecoration)wmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If the popup ignores mouse events, set an empty input shape.
|
// If the popup ignores mouse events, set an empty input shape.
|
||||||
SetInputRegion(mInputRegion);
|
SetInputRegion(mInputRegion);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -704,7 +704,6 @@ class nsWindow final : public nsBaseWidget {
|
|||||||
// Draw titlebar with :backdrop css state (inactive/unfocused).
|
// Draw titlebar with :backdrop css state (inactive/unfocused).
|
||||||
bool mTitlebarBackdropState : 1;
|
bool mTitlebarBackdropState : 1;
|
||||||
bool mAlwaysOnTop : 1;
|
bool mAlwaysOnTop : 1;
|
||||||
bool mNoAutoHide : 1;
|
|
||||||
bool mIsTransparent : 1;
|
bool mIsTransparent : 1;
|
||||||
// We can expect at least one size-allocate event after early resizes.
|
// We can expect at least one size-allocate event after early resizes.
|
||||||
bool mHasReceivedSizeAllocate : 1;
|
bool mHasReceivedSizeAllocate : 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user