OLD | NEW |
| (Empty) |
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 "ui/base/gtk/g_object_destructor_filo.h" | |
6 | |
7 #include <glib-object.h> | |
8 | |
9 #include "base/logging.h" | |
10 #include "base/memory/singleton.h" | |
11 | |
12 namespace ui { | |
13 | |
14 GObjectDestructorFILO::GObjectDestructorFILO() { | |
15 } | |
16 | |
17 GObjectDestructorFILO::~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 | |
23 GObjectDestructorFILO* GObjectDestructorFILO::GetInstance() { | |
24 return Singleton<GObjectDestructorFILO>::get(); | |
25 } | |
26 | |
27 void 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 | |
39 void 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 | |
73 void 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 } // napespace ui | |
OLD | NEW |