diff options
author | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-02 00:27:48 +0000 |
---|---|---|
committer | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-02 00:27:48 +0000 |
commit | a49437de9e757ffaf4e74f82686ee37b73950c6a (patch) | |
tree | 617e093be408d370fe19ad48c750dd2286bba5b5 /chrome | |
parent | b7d155f67aad56a2bab35339456fa10d1a2de13e (diff) | |
download | chromium_src-a49437de9e757ffaf4e74f82686ee37b73950c6a.zip chromium_src-a49437de9e757ffaf4e74f82686ee37b73950c6a.tar.gz chromium_src-a49437de9e757ffaf4e74f82686ee37b73950c6a.tar.bz2 |
[GTK] delay reference count check in OwnedWidgetGtk
It's a common problem that a GtkWidget will be referenced by an event that's currently on the callstack. These ref holders ignore the "destroy" signal, so when we go to destroy the owned widget, the refcount == 1 DCHECK fails. This change delays that DCHECK until the current stack has unwound, so we don't have to keep running into this.
BUG=none
TEST=in debug builds, Escape in a constrained window doesn't DCHECK, dragging a tab doesn't cause a DCHECK, pressing the custom frame [x] in lucid doesn't DCHECK; in general, no additional DCHECKs
Review URL: http://codereview.chromium.org/3416032
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@61269 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/gtk/constrained_window_gtk.cc | 7 | ||||
-rw-r--r-- | chrome/browser/gtk/gtk_theme_provider_unittest.cc | 4 | ||||
-rw-r--r-- | chrome/browser/gtk/owned_widget_gtk.cc | 39 | ||||
-rw-r--r-- | chrome/browser/gtk/reload_button_gtk_unittest.cc | 4 | ||||
-rw-r--r-- | chrome/browser/gtk/tabs/tab_gtk.cc | 7 | ||||
-rw-r--r-- | chrome/browser/renderer_host/gtk_key_bindings_handler_unittest.cc | 5 | ||||
-rw-r--r-- | chrome/browser/renderer_host/render_widget_host_view_gtk.cc | 8 | ||||
-rw-r--r-- | chrome/browser/sync/glue/theme_util_unittest.cc | 3 |
8 files changed, 54 insertions, 23 deletions
diff --git a/chrome/browser/gtk/constrained_window_gtk.cc b/chrome/browser/gtk/constrained_window_gtk.cc index b901083..bb53e68 100644 --- a/chrome/browser/gtk/constrained_window_gtk.cc +++ b/chrome/browser/gtk/constrained_window_gtk.cc @@ -70,11 +70,8 @@ TabContentsViewGtk* ConstrainedWindowGtk::ContainingView() { gboolean ConstrainedWindowGtk::OnKeyPress(GtkWidget* sender, GdkEventKey* key) { if (key->keyval == GDK_Escape) { - // Let the stack unwind so the event handler can release its ref - // on widget(). - MessageLoop::current()->PostTask(FROM_HERE, - factory_.NewRunnableMethod( - &ConstrainedWindowGtk::CloseConstrainedWindow)); + // This will delete us! + CloseConstrainedWindow(); return TRUE; } diff --git a/chrome/browser/gtk/gtk_theme_provider_unittest.cc b/chrome/browser/gtk/gtk_theme_provider_unittest.cc index 1836b80..4779063 100644 --- a/chrome/browser/gtk/gtk_theme_provider_unittest.cc +++ b/chrome/browser/gtk/gtk_theme_provider_unittest.cc @@ -4,6 +4,7 @@ #include <gtk/gtk.h> +#include "base/message_loop.h" #include "chrome/browser/gtk/gtk_theme_provider.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profile.h" @@ -36,6 +37,9 @@ class GtkThemeProviderTest : public testing::Test { provider_ = GtkThemeProvider::GetFrom(&profile_); } + private: + MessageLoop message_loop_; + protected: TestingProfile profile_; diff --git a/chrome/browser/gtk/owned_widget_gtk.cc b/chrome/browser/gtk/owned_widget_gtk.cc index 2315371..c646cd7 100644 --- a/chrome/browser/gtk/owned_widget_gtk.cc +++ b/chrome/browser/gtk/owned_widget_gtk.cc @@ -6,7 +6,32 @@ #include <gtk/gtk.h> +#include "base/debug_util.h" #include "base/logging.h" +#include "base/message_loop.h" + +namespace { + +class CheckWidgetRefCountTask : public Task { + public: + CheckWidgetRefCountTask(GtkWidget* widget, const std::string& stack) + : widget_(widget), stack_(stack) {} + + virtual ~CheckWidgetRefCountTask() {} + + virtual void Run() { + // NOTE: Assumes some implementation details about glib internals. + DCHECK_EQ(G_OBJECT(widget_)->ref_count, 1U) << + " with Destroy() stack: \n" << stack_; + g_object_unref(widget_); + } + + private: + GtkWidget* widget_; + std::string stack_; +}; + +} // namespace OwnedWidgetGtk::~OwnedWidgetGtk() { DCHECK(!widget_) << "You must explicitly call OwnerWidgetGtk::Destroy()."; @@ -34,8 +59,16 @@ void OwnedWidgetGtk::Destroy() { widget_ = NULL; gtk_widget_destroy(widget); +#ifndef NDEBUG DCHECK(!g_object_is_floating(widget)); - // NOTE: Assumes some implementation details about glib internals. - DCHECK_EQ(G_OBJECT(widget)->ref_count, 1U); - g_object_unref(widget); + + std::string stack(StackTrace().AsString()); +#else + std::string stack; +#endif + + // Make sure all other ref holders let go of their references (but delay + // the check because some ref holders won't let go immediately). + MessageLoop::current()->PostTask( + FROM_HERE, new CheckWidgetRefCountTask(widget, stack)); } diff --git a/chrome/browser/gtk/reload_button_gtk_unittest.cc b/chrome/browser/gtk/reload_button_gtk_unittest.cc index 12384b6..13c152d 100644 --- a/chrome/browser/gtk/reload_button_gtk_unittest.cc +++ b/chrome/browser/gtk/reload_button_gtk_unittest.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/message_loop.h" #include "chrome/browser/gtk/reload_button_gtk.h" #include "testing/gtest/include/gtest/gtest.h" @@ -51,6 +52,9 @@ class ReloadButtonGtkTest : public testing::Test { protected: ReloadButtonGtkTest() : reload_(NULL, NULL), peer_(&reload_) { } + private: + MessageLoop message_loop_; + protected: ReloadButtonGtk reload_; ReloadButtonGtkPeer peer_; diff --git a/chrome/browser/gtk/tabs/tab_gtk.cc b/chrome/browser/gtk/tabs/tab_gtk.cc index 148e7ea..13e6dbb 100644 --- a/chrome/browser/gtk/tabs/tab_gtk.cc +++ b/chrome/browser/gtk/tabs/tab_gtk.cc @@ -388,12 +388,7 @@ void TabGtk::EndDrag(bool canceled) { // Make sure we only run EndDrag once by canceling any tasks that want // to call EndDrag. drag_end_factory_.RevokeAll(); - - // We must let gtk clean up after we handle the drag operation, otherwise - // there will be outstanding references to the drag widget when we try to - // destroy it. - MessageLoop::current()->PostTask(FROM_HERE, - destroy_factory_.NewRunnableMethod(&TabGtk::DestroyDragWidget)); + DestroyDragWidget(); if (last_mouse_down_) { gdk_event_free(last_mouse_down_); diff --git a/chrome/browser/renderer_host/gtk_key_bindings_handler_unittest.cc b/chrome/browser/renderer_host/gtk_key_bindings_handler_unittest.cc index 19f0806..70850a4 100644 --- a/chrome/browser/renderer_host/gtk_key_bindings_handler_unittest.cc +++ b/chrome/browser/renderer_host/gtk_key_bindings_handler_unittest.cc @@ -1,6 +1,7 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. + #include "chrome/browser/renderer_host/gtk_key_bindings_handler.h" #include <gdk/gdkkeysyms.h> @@ -10,6 +11,7 @@ #include "base/basictypes.h" #include "base/file_util.h" +#include "base/message_loop.h" #include "base/path_service.h" #include "base/string_util.h" #include "chrome/common/chrome_paths.h" @@ -83,6 +85,7 @@ class GtkKeyBindingsHandlerTest : public testing::Test { protected: GtkWidget* window_; GtkKeyBindingsHandler* handler_; + MessageLoop message_loop_; }; TEST_F(GtkKeyBindingsHandlerTest, MoveCursor) { diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc index 6c49c81..a79129c 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc +++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc @@ -685,14 +685,6 @@ void RenderWidgetHostViewGtk::Destroy() { gtk_widget_destroy(gtk_widget_get_parent(view_.get())); } - // Remove |view_| from all containers now, so nothing else can hold a - // reference to |view_|'s widget except possibly a gtk signal handler if - // this code is currently executing within the context of a gtk signal - // handler. Note that |view_| is still alive after this call. It will be - // deallocated in the destructor. - // See http://www.crbug.com/11847 for details. - gtk_widget_destroy(view_.get()); - // The RenderWidgetHost's destruction led here, so don't call it. host_ = NULL; diff --git a/chrome/browser/sync/glue/theme_util_unittest.cc b/chrome/browser/sync/glue/theme_util_unittest.cc index fb6641f..4b12f8c6 100644 --- a/chrome/browser/sync/glue/theme_util_unittest.cc +++ b/chrome/browser/sync/glue/theme_util_unittest.cc @@ -5,6 +5,7 @@ #include "chrome/browser/sync/glue/theme_util.h" #include "base/file_path.h" +#include "base/message_loop.h" #include "base/values.h" #include "chrome/browser/profile.h" #include "chrome/browser/sync/protocol/theme_specifics.pb.h" @@ -21,6 +22,8 @@ namespace { using ::testing::Return; class ThemeUtilTest : public testing::Test { + private: + MessageLoop message_loop_; }; void MakeThemeExtension(Extension* extension, |