Bug 726483 - avoid DispatchResized() during size-allocate. r=roc, a=lizzard
authorKarl Tomlinson <karlt+@karlt.net>
Wed, 11 Nov 2015 13:50:04 +1300
changeset 296745 c134a04010a0
parent 296744 6ceeb10435a8
child 296746 bc7eea62ab83
push id5316
push userkwierso@gmail.com
push date2015-11-16 20:42 +0000
treeherdermozilla-beta@c66289e84c50 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, lizzard
bugs726483
milestone43.0
Bug 726483 - avoid DispatchResized() during size-allocate. r=roc, a=lizzard
widget/gtk/nsWindow.cpp
widget/gtk/nsWindow.h
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -399,16 +399,17 @@ UpdateLastInputEventTime(void *aGdkEvent
 
 NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget)
 
 nsWindow::nsWindow()
 {
     mIsTopLevel          = false;
     mIsDestroyed         = false;
     mListenForResizes    = false;
+    mNeedsDispatchResized = false;
     mIsShown             = false;
     mNeedsShow           = false;
     mEnabled             = true;
     mCreated             = false;
 
     mContainer           = nullptr;
     mGdkWindow           = nullptr;
     mShell               = nullptr;
@@ -511,25 +512,34 @@ nsWindow::DispatchDeactivateEvent(void)
 #ifdef ACCESSIBILITY
     DispatchDeactivateEventAccessible();
 #endif //ACCESSIBILITY
 }
 
 void
 nsWindow::DispatchResized()
 {
+    mNeedsDispatchResized = false;
     if (mWidgetListener) {
         mWidgetListener->WindowResized(this, mBounds.width, mBounds.height);
     }
     if (mAttachedWidgetListener) {
         mAttachedWidgetListener->WindowResized(this,
                                                mBounds.width, mBounds.height);
     }
 }
 
+void
+nsWindow::MaybeDispatchResized()
+{
+    if (mNeedsDispatchResized && !mIsDestroyed) {
+        DispatchResized();
+    }
+}
+
 nsresult
 nsWindow::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus)
 {
 #ifdef DEBUG
     debug_DumpEvent(stdout, aEvent->widget, aEvent,
                     nsAutoCString("something"), 0);
 #endif
     aStatus = nsEventStatus_eIgnore;
@@ -2042,16 +2052,20 @@ ExtractExposeRegion(nsIntRegion& aRegion
 #if (MOZ_WIDGET_GTK == 2)
 gboolean
 nsWindow::OnExposeEvent(GdkEventExpose *aEvent)
 #else
 gboolean
 nsWindow::OnExposeEvent(cairo_t *cr)
 #endif
 {
+    // Send any pending resize events so that layout can update.
+    // May run event loop.
+    MaybeDispatchResized();
+
     if (mIsDestroyed) {
         return FALSE;
     }
 
     // Windows that are not visible will be painted after they become visible.
     if (!mGdkWindow || mIsFullyObscured || !mHasMappedToplevel)
         return FALSE;
 
@@ -2397,20 +2411,23 @@ nsWindow::OnSizeAllocate(GtkAllocation *
     if (mBounds.height < size.height) {
         GdkRectangle rect = DevicePixelsToGdkRectRoundOut(
             { 0, mBounds.height, size.width, size.height - mBounds.height });
         gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
     }
 
     mBounds.SizeTo(size);
 
-    if (!mGdkWindow)
-        return;
-
-    DispatchResized();
+    // Gecko permits running nested event loops during processing of events,
+    // GtkWindow callers of gtk_widget_size_allocate expect the signal
+    // handlers to return sometime in the near future.
+    mNeedsDispatchResized = true;
+    nsCOMPtr<nsIRunnable> r =
+        NS_NewRunnableMethod(this, &nsWindow::MaybeDispatchResized);
+    NS_DispatchToCurrentThread(r.forget());
 }
 
 void
 nsWindow::OnDeleteEvent()
 {
     if (mWidgetListener)
         mWidgetListener->RequestWindowClose(this);
 }
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -328,16 +328,17 @@ public:
 
 protected:
     virtual ~nsWindow();
 
     // event handling code
     void DispatchActivateEvent(void);
     void DispatchDeactivateEvent(void);
     void DispatchResized();
+    void MaybeDispatchResized();
 
     // Helper for SetParent and ReparentNativeWidget.
     void ReparentNativeWidgetInternal(nsIWidget* aNewParent,
                                       GtkWidget* aNewContainer,
                                       GdkWindow* aNewParentWindow,
                                       GtkWidget* aOldContainer);
 
     virtual nsresult NotifyIMEInternal(
@@ -346,16 +347,18 @@ protected:
     nsCOMPtr<nsIWidget> mParent;
     // Is this a toplevel window?
     bool                mIsTopLevel;
     // Has this widget been destroyed yet?
     bool                mIsDestroyed;
 
     // Should we send resize events on all resizes?
     bool                mListenForResizes;
+    // Does WindowResized need to be called on listeners?
+    bool                mNeedsDispatchResized;
     // This flag tracks if we're hidden or shown.
     bool                mIsShown;
     bool                mNeedsShow;
     // is this widget enabled?
     bool                mEnabled;
     // has the native window for this been created yet?
     bool                mCreated;