1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/ui/libgtk2ui/g_object_destructor_filo.h" 6 7#include <glib-object.h> 8 9#include "base/logging.h" 10#include "base/memory/singleton.h" 11 12namespace libgtk2ui { 13 14GObjectDestructorFILO::GObjectDestructorFILO() { 15} 16 17GObjectDestructorFILO::~GObjectDestructorFILO() { 18 // Probably CHECK(handler_map_.empty()) would look natural here. But 19 // some tests (some views_unittests) violate this assertion. 20} 21 22// static 23GObjectDestructorFILO* GObjectDestructorFILO::GetInstance() { 24 return Singleton<GObjectDestructorFILO>::get(); 25} 26 27void GObjectDestructorFILO::Connect( 28 GObject* object, DestructorHook callback, void* context) { 29 const Hook hook(object, callback, context); 30 HandlerMap::iterator iter = handler_map_.find(object); 31 if (iter == handler_map_.end()) { 32 g_object_weak_ref(object, WeakNotifyThunk, this); 33 handler_map_[object].push_front(hook); 34 } else { 35 iter->second.push_front(hook); 36 } 37} 38 39void GObjectDestructorFILO::Disconnect( 40 GObject* object, DestructorHook callback, void* context) { 41 HandlerMap::iterator iter = handler_map_.find(object); 42 if (iter == handler_map_.end()) { 43 LOG(DFATAL) << "Unable to disconnect destructor hook for object " << object 44 << ": hook not found (" << callback << ", " << context << ")."; 45 return; 46 } 47 HandlerList& dtors = iter->second; 48 if (dtors.empty()) { 49 LOG(DFATAL) << "Destructor list is empty for specified object " << object 50 << " Maybe it is being executed?"; 51 return; 52 } 53 if (!dtors.front().equal(object, callback, context)) { 54 // Reenable this warning once this bug is fixed: 55 // http://code.google.com/p/chromium/issues/detail?id=85603 56 DVLOG(1) << "Destructors should be unregistered the reverse order they " 57 << "were registered. But for object " << object << " " 58 << "deleted hook is "<< context << ", the last queued hook is " 59 << dtors.front().context; 60 } 61 for (HandlerList::iterator i = dtors.begin(); i != dtors.end(); ++i) { 62 if (i->equal(object, callback, context)) { 63 dtors.erase(i); 64 break; 65 } 66 } 67 if (dtors.empty()) { 68 g_object_weak_unref(object, WeakNotifyThunk, this); 69 handler_map_.erase(iter); 70 } 71} 72 73void GObjectDestructorFILO::WeakNotify(GObject* where_the_object_was) { 74 HandlerMap::iterator iter = handler_map_.find(where_the_object_was); 75 DCHECK(iter != handler_map_.end()); 76 DCHECK(!iter->second.empty()); 77 78 // Save destructor list for given object into local copy to avoid reentrancy 79 // problem: if callee wants to modify the caller list. 80 HandlerList dtors; 81 iter->second.swap(dtors); 82 handler_map_.erase(iter); 83 84 // Execute hooks in local list in FILO order. 85 for (HandlerList::iterator i = dtors.begin(); i != dtors.end(); ++i) 86 i->callback(i->context, where_the_object_was); 87} 88 89} // namespace libgtk2ui 90