1bb14e79fdfc57ba3554e307ebe012b8bedc23ad
[ardour.git] / libs / glibmm2 / glibmm / objectbase.cc
1 // -*- c++ -*-
2 /* $Id$ */
3
4 /* Copyright 2002 The gtkmm Development Team
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the Free
18  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 #include <glib-object.h>
22
23 #include <glibmm/quark.h>
24 #include <glibmm/objectbase.h>
25
26
27 namespace
28 {
29
30 // Used by the Glib::ObjectBase default ctor.  Using an explicitly defined
31 // char array rather than a string literal allows for fast pointer comparison,
32 // which is otherwise not guaranteed to work.
33
34 const char anonymous_custom_type_name[] = "gtkmm__anonymous_custom_type";
35
36 } // anonymous namespace
37
38
39 namespace Glib
40 {
41
42 /**** Glib::ObjectBase *****************************************************/
43
44 ObjectBase::ObjectBase()
45 :
46   gobject_                      (0),
47   custom_type_name_             (anonymous_custom_type_name),
48   cpp_destruction_in_progress_  (false)
49 {}
50
51 ObjectBase::ObjectBase(const char* custom_type_name)
52 :
53   gobject_                      (0),
54   custom_type_name_             (custom_type_name),
55   cpp_destruction_in_progress_  (false)
56 {}
57
58 ObjectBase::ObjectBase(const std::type_info& custom_type_info)
59 :
60   gobject_                      (0),
61   custom_type_name_             (custom_type_info.name()),
62   cpp_destruction_in_progress_  (false)
63 {}
64
65 // initialize() actually initializes the wrapper.  Glib::ObjectBase is used
66 // as virtual base class, which means the most-derived class' ctor invokes
67 // the Glib::ObjectBase ctor -- thus it's useless for Glib::Object.
68 //
69 void ObjectBase::initialize(GObject* castitem)
70 {
71   if(gobject_)
72   {
73     // initialize() might be called twice when used with MI, e.g. by the ctors
74     // of Glib::Object and Glib::Interface.  However, they must both refer to
75     // the same underlying GObject instance.
76     //
77     g_assert(gobject_ == castitem);
78
79     // TODO: Think about it.  Will this really be called twice?
80     g_printerr("ObjectBase::initialize() called twice for the same GObject\n");
81
82     return; // Don't initialize the wrapper twice.
83   }
84
85   //g_print("%s : %s\n", G_GNUC_PRETTY_FUNCTION, G_OBJECT_TYPE_NAME(castitem));
86
87   gobject_ = castitem;
88   _set_current_wrapper(castitem);
89 }
90
91 ObjectBase::~ObjectBase()
92 {
93   // Normally, gobject_ should always be 0 at this point, because:
94   //
95   // a) Gtk::Object handles memory management on its own and always resets
96   //    the gobject_ pointer in its destructor.
97   //
98   // b) Glib::Object instances that aren't Gtk::Objects will always be
99   //    deleted by the destroy_notify_() virtual method.  Calling delete
100   //    on a Glib::Object is a programming error.
101   //
102   // The *only* situation where gobject_ is validly not 0 at this point
103   // happens if a derived class's ctor throws an exception.  In that case
104   // we have to call g_object_unref() on our own.
105   //
106   if(GObject *const gobject = gobject_)
107   {
108 #ifdef GLIBMM_DEBUG_REFCOUNTING
109     g_warning("(Glib::ObjectBase::~ObjectBase): gobject_ = %p", (void*) gobject_);
110 #endif
111
112     gobject_ = 0;
113
114 #ifdef GLIBMM_DEBUG_REFCOUNTING
115     g_warning("(Glib::ObjectBase::~ObjectBase): before g_object_steal_qdata()");
116 #endif
117
118     // Remove the pointer to the wrapper from the underlying instance.
119     // This does _not_ cause invocation of the destroy_notify callback.
120     g_object_steal_qdata(gobject, quark_);
121
122 #ifdef GLIBMM_DEBUG_REFCOUNTING
123     g_warning("(Glib::ObjectBase::~ObjectBase): calling g_object_unref()");
124 #endif
125
126     g_object_unref(gobject);
127   }
128 }
129
130 void ObjectBase::reference() const
131 {
132   GLIBMM_DEBUG_REFERENCE(this, gobject_);
133   g_object_ref(gobject_);
134 }
135
136 void ObjectBase::unreference() const
137 {
138   GLIBMM_DEBUG_UNREFERENCE(this, gobject_);
139   g_object_unref(gobject_);
140 }
141
142 GObject* ObjectBase::gobj_copy() const
143 {
144   reference();
145   return gobject_;
146 }
147
148 void ObjectBase::_set_current_wrapper(GObject* object)
149 {
150   // Store a pointer to this wrapper in the underlying instance, so that we
151   // never create a second wrapper for the same underlying instance.  Also,
152   // specify a callback that will tell us when it's time to delete this C++
153   // wrapper instance:
154
155   if(object)
156   {
157     if(!g_object_get_qdata(object, Glib::quark_))
158     {
159       g_object_set_qdata_full(object, Glib::quark_, this, &destroy_notify_callback_);
160     }
161     else
162     {
163       g_warning("This object, of type %s, already has a wrapper.\n"
164                 "You should use wrap() instead of a constructor.",
165                 G_OBJECT_TYPE_NAME(object));
166     }
167   }
168 }
169
170 // static
171 ObjectBase* ObjectBase::_get_current_wrapper(GObject* object)
172 {
173   if(object)
174     return static_cast<ObjectBase*>(g_object_get_qdata(object, Glib::quark_));
175   else
176     return 0;
177 }
178
179 // static
180 void ObjectBase::destroy_notify_callback_(void* data)
181 {
182   //GLIBMM_LIFECYCLE
183
184   // This method is called (indirectly) from g_object_run_dispose().
185   // Get the C++ instance associated with the C instance:
186   ObjectBase* cppObject = static_cast<ObjectBase*>(data); //Previously set with g_object_set_qdata_full().
187
188 #ifdef GLIBMM_DEBUG_REFCOUNTING
189   g_warning("ObjectBase::destroy_notify_callback_: cppObject = %p, gobject_ = %p, gtypename = %s",
190             (void*) cppObject, (void*) cppObject->gobject_, cppObject->gobject_);
191 #endif
192
193   if(cppObject) //This will be 0 if the C++ destructor has already run.
194   {
195     cppObject->destroy_notify_(); //Virtual - it does different things for GObject and GtkObject.
196   }
197 }
198
199 void ObjectBase::destroy_notify_()
200 {
201   // The C instance is about to be disposed, making it unusable.  Now is a
202   // good time to delete the C++ wrapper of the C instance.  There is no way
203   // to force the disposal of the GObject (though GtkObject  has
204   // gtk_object_destroy()), So this is the *only* place where we delete the
205   // C++ wrapper.
206   //
207   // This will only happen after the last unreference(), which will be done by
208   // the RefPtr<> destructor.  There should be no way to access the wrapper or
209   // the undobjecterlying instance after that, so it's OK to delete this.
210
211 #ifdef GLIBMM_DEBUG_REFCOUNTING
212   g_warning("Glib::ObjectBase::destroy_notify_: gobject_ = %p", (void*) gobject_);
213 #endif
214
215   gobject_ = 0; // Make sure we don't unref it again in the dtor.
216
217   delete this;
218 }
219
220 bool ObjectBase::is_anonymous_custom_() const
221 {
222   // Doing high-speed pointer comparison is OK here.
223   return (custom_type_name_ == anonymous_custom_type_name);
224 }
225
226 bool ObjectBase::is_derived_() const
227 {
228   // gtkmmproc-generated classes initialize this to 0 by default.
229   return (custom_type_name_ != 0);
230 }
231
232 void ObjectBase::set_manage()
233 {
234   // This is a private method and Gtk::manage() is a template function.
235   // Thus this will probably never run, unless you do something like:
236   //
237   // manage(static_cast<Gtk::Object*>(refptr.operator->()));
238
239   g_error("Glib::ObjectBase::set_manage(): "
240           "only Gtk::Object instances can be managed");
241 }
242
243 bool ObjectBase::_cpp_destruction_is_in_progress() const
244 {
245   return cpp_destruction_in_progress_;
246 }
247
248 void ObjectBase::set_property_value(const Glib::ustring& property_name, const Glib::ValueBase& value)
249 {
250   g_object_set_property(gobj(), property_name.c_str(), value.gobj());
251 }
252
253 void ObjectBase::get_property_value(const Glib::ustring& property_name, Glib::ValueBase& value) const
254 {
255   g_object_get_property(const_cast<GObject*>(gobj()), property_name.c_str(), value.gobj());
256 }
257
258
259 bool _gobject_cppinstance_already_deleted(GObject* gobject)
260 {
261   //This function is used to prevent calling wrap() on a GTK+ instance whose gtkmm instance has been deleted.
262
263   if(gobject)
264     return (bool)g_object_get_qdata(gobject, Glib::quark_cpp_wrapper_deleted_); //true means that something is odd.
265   else
266     return false; //Nothing is particularly wrong.
267 }
268
269
270 } // namespace Glib
271