--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -211,16 +211,19 @@ static gboolean visibility_notify_event_
GdkEventVisibility *event);
static void hierarchy_changed_cb (GtkWidget *widget,
GtkWidget *previous_toplevel);
static gboolean window_state_event_cb (GtkWidget *widget,
GdkEventWindowState *event);
static void theme_changed_cb (GtkSettings *settings,
GParamSpec *pspec,
nsWindow *data);
+static void check_resize_cb (GtkContainer* container,
+ gpointer user_data);
+
#if (MOZ_WIDGET_GTK == 3)
static void scale_changed_cb (GtkWidget* widget,
GParamSpec* aPSpec,
gpointer aPointer);
#endif
#if GTK_CHECK_VERSION(3,4,0)
static gboolean touch_event_cb (GtkWidget* aWidget,
GdkEventTouch* aEvent);
@@ -470,16 +473,17 @@ nsWindow::nsWindow()
mTransparencyBitmapWidth = 0;
mTransparencyBitmapHeight = 0;
#if GTK_CHECK_VERSION(3,4,0)
mLastScrollEventTime = GDK_CURRENT_TIME;
#endif
mFallbackSurface = nullptr;
+ mPendingConfigures = 0;
}
nsWindow::~nsWindow()
{
LOG(("nsWindow::~nsWindow() [%p]\n", (void *)this));
delete[] mTransparencyBitmap;
mTransparencyBitmap = nullptr;
@@ -2412,16 +2416,18 @@ nsWindow::OnConfigureEvent(GtkWidget *aW
// the client window.
//
// Override-redirect windows are children of the root window so parent
// coordinates are root coordinates.
LOG(("configure event [%p] %d %d %d %d\n", (void *)this,
aEvent->x, aEvent->y, aEvent->width, aEvent->height));
+ mPendingConfigures--;
+
LayoutDeviceIntRect screenBounds;
GetScreenBounds(screenBounds);
if (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog) {
// This check avoids unwanted rollup on spurious configure events from
// Cygwin/X (bug 672103).
if (mBounds.x != screenBounds.x ||
mBounds.y != screenBounds.y) {
@@ -3399,16 +3405,22 @@ nsWindow::OnDPIChanged()
presShell->BackingScaleFactorChanged();
// Update menu's font size etc
presShell->ThemeChanged();
}
}
}
void
+nsWindow::OnCheckResize()
+{
+ mPendingConfigures++;
+}
+
+void
nsWindow::DispatchDragEvent(EventMessage aMsg, const LayoutDeviceIntPoint& aRefPoint,
guint aTime)
{
WidgetDragEvent event(true, aMsg, this);
if (aMsg == eDragOver) {
InitDragEvent(event);
}
@@ -3854,16 +3866,18 @@ nsWindow::Create(nsIWidget* aParent,
// attach listeners for events
if (mShell) {
g_signal_connect(mShell, "configure_event",
G_CALLBACK(configure_event_cb), nullptr);
g_signal_connect(mShell, "delete_event",
G_CALLBACK(delete_event_cb), nullptr);
g_signal_connect(mShell, "window_state_event",
G_CALLBACK(window_state_event_cb), nullptr);
+ g_signal_connect(mShell, "check-resize",
+ G_CALLBACK(check_resize_cb), nullptr);
GtkSettings* default_settings = gtk_settings_get_default();
g_signal_connect_after(default_settings,
"notify::gtk-theme-name",
G_CALLBACK(theme_changed_cb), this);
g_signal_connect_after(default_settings,
"notify::gtk-font-name",
G_CALLBACK(theme_changed_cb), this);
@@ -4173,17 +4187,41 @@ nsWindow::NativeShow(bool aAction)
gtk_widget_show(GTK_WIDGET(mContainer));
}
else if (mGdkWindow) {
gdk_window_show_unraised(mGdkWindow);
}
}
else {
if (mIsTopLevel) {
- gtk_widget_hide(GTK_WIDGET(mShell));
+ // Workaround window freezes on GTK versions before 3.21.2 by
+ // ensuring that configure events get dispatched to windows before
+ // they are unmapped. See bug 1225044.
+ if (gtk_check_version(3, 21, 2) != nullptr && mPendingConfigures > 0) {
+ GtkAllocation allocation;
+ gtk_widget_get_allocation(GTK_WIDGET(mShell), &allocation);
+
+ GdkEventConfigure event;
+ PodZero(&event);
+ event.type = GDK_CONFIGURE;
+ event.window = mGdkWindow;
+ event.send_event = TRUE;
+ event.x = allocation.x;
+ event.y = allocation.y;
+ event.width = allocation.width;
+ event.height = allocation.height;
+
+ auto shellClass = GTK_WIDGET_GET_CLASS(mShell);
+ for (int i = 0; i < mPendingConfigures; i++) {
+ Unused << shellClass->configure_event(mShell, &event);
+ }
+ mPendingConfigures = 0;
+ }
+
+ gtk_widget_hide(mShell);
ClearTransparencyBitmap(); // Release some resources
}
else if (mContainer) {
gtk_widget_hide(GTK_WIDGET(mContainer));
}
else if (mGdkWindow) {
gdk_window_hide(mGdkWindow);
@@ -6028,16 +6066,26 @@ window_state_event_cb (GtkWidget *widget
static void
theme_changed_cb (GtkSettings *settings, GParamSpec *pspec, nsWindow *data)
{
RefPtr<nsWindow> window = data;
window->ThemeChanged();
}
+static void
+check_resize_cb (GtkContainer* container, gpointer user_data)
+{
+ RefPtr<nsWindow> window = get_window_for_gtk_widget(GTK_WIDGET(container));
+ if (!window) {
+ return;
+ }
+ window->OnCheckResize();
+}
+
#if (MOZ_WIDGET_GTK == 3)
static void
scale_changed_cb (GtkWidget* widget, GParamSpec* aPSpec, gpointer aPointer)
{
RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
if (!window) {
return;
}
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -249,16 +249,17 @@ public:
void SetPluginType(PluginType aPluginType);
#ifdef MOZ_X11
void SetNonXEmbedPluginFocus(void);
void LoseNonXEmbedPluginFocus(void);
#endif /* MOZ_X11 */
void ThemeChanged(void);
void OnDPIChanged(void);
+ void OnCheckResize(void);
#ifdef MOZ_X11
Window mOldFocusWindow;
#endif /* MOZ_X11 */
static guint32 sLastButtonPressTime;
NS_IMETHOD BeginResizeDrag(mozilla::WidgetGUIEvent* aEvent,
@@ -468,16 +469,20 @@ private:
// If we're using xshm rendering
RefPtr<nsShmImage> mFrontShmImage;
RefPtr<nsShmImage> mBackShmImage;
#endif
// A fallback image surface when a SHM surface is unavailable.
cairo_surface_t* mFallbackSurface;
+ // Upper bound on pending ConfigureNotify events to be dispatched to the
+ // window. See bug 1225044.
+ int mPendingConfigures;
+
#ifdef ACCESSIBILITY
RefPtr<mozilla::a11y::Accessible> mRootAccessible;
/**
* Request to create the accessible for this window if it is top level.
*/
void CreateRootAccessible();