bug 726483 avoid DispatchResized() during size-allocate r=roc
authorKarl Tomlinson <karlt+@karlt.net>
Wed, 11 Nov 2015 13:50:04 +1300
changeset 308470 ac6f3f8116d7c3ba9f49e05f3fd33c052b1336f2
parent 308469 552dfded623eafa06ef5cae91f5dd4e87cd4fabc
child 308471 30f18e492189af365a61cd98e575adaabca7322f
push id7470
push users.kaspari@gmail.com
push dateThu, 12 Nov 2015 12:51:02 +0000
reviewersroc
bugs726483
milestone45.0a1
bug 726483 avoid DispatchResized() during size-allocate r=roc
widget/gtk/nsWindow.cpp
widget/gtk/nsWindow.h
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -410,16 +410,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;
 #if GTK_CHECK_VERSION(3,4,0)
     mHandleTouchEvent    = false;
 #endif
 
@@ -525,25 +526,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;
@@ -2088,16 +2098,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;
 
@@ -2448,20 +2462,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
@@ -352,16 +352,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(
@@ -372,16 +373,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;
 #if GTK_CHECK_VERSION(3,4,0)