Merged revisions 6293,6296-6306,6308 via svnmerge from
[ardour.git] / libs / gtkmm2 / gtk / gtkmm / object.cc
1 // Generated by gtkmmproc -- DO NOT MODIFY!
2
3
4 #include <gtkmm/object.h>
5 #include <gtkmm/private/object_p.h>
6
7 /* $Id$ */
8
9 /* Copyright 1998-2002 The gtkmm Development Team
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Library General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Library General Public License for more details.
20  *
21  * You should have received a copy of the GNU Library General Public
22  * License along with this library; if not, write to the Free
23  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  */
25
26 #include <glibmm/quark.h>
27 #include <gtk/gtkobject.h>
28
29
30 namespace Gtk
31 {
32
33 Object::Object(const Glib::ConstructParams& construct_params)
34 :
35   Glib::Object(construct_params)
36 {
37    gobject_disposed_ = false;
38
39   _init_unmanage(); //We don't like the GTK+ default memory management - we want to be in control._)
40 }
41
42 Object::Object(GtkObject* castitem)
43 :
44   Glib::Object((GObject*) castitem)
45 {
46   gobject_disposed_ = false;
47
48    _init_unmanage(); //We don't like the GTK+ default memory management - we want to be in control.
49 }
50
51 void Object::_init_unmanage(bool /* is_toplevel = false */)
52 {
53   //GTKMM_LIFECYCLE
54
55   if(gobject_)
56   {
57     //Glib::Object::Object has already stored a pointer to this C++ instance in the underlying C instance,
58     //and connected a callback which will, in turn, call our destroy_notify_(),
59     //so will will know if GTK+ disposes of the underlying instance.
60
61     // Most GTK+ objects are floating, by default. This means that the container widget controls their lifetime.
62     // We'll change this:
63     if(g_object_is_floating (gobject_)) //Top-level Windows and Dialogs can not be manag()ed, so there is no need to do this.
64     {
65       GLIBMM_DEBUG_REFERENCE(this, gobject_);
66       g_object_ref_sink(gobject_); //Stops it from being floating - we will make this optional ( see Gtk::manage() ),
67
68       #ifdef GLIBMM_DEBUG_REFCOUNTING
69       g_warning("gtkmm after sink: C++ instance: %p, C instance: %p, refcount=%d\n", (void*)(Glib::ObjectBase*)this, (void*)gobject_, G_OBJECT(gobject_)->ref_count);
70       g_warning("    c instance gtype: %s\n", G_OBJECT_TYPE_NAME(gobject_));
71       #endif
72
73      referenced_ = true; //Not managed.
74     }
75     else
76     {
77        //This widget is already not floating. It's probably already been added to a GTK+ container, and has just had Glib::wrap() called on it.
78        //It's not floating because containers call g_object_sink() on child widgets to take control of them.
79        //We just ref() it so that we can unref it later.
80        //GLIBMM_DEBUG_REFERENCE(this, gobject_);
81        //g_object_ref(gobject_);
82     
83        //Alternatively, it might be a top-level window (e.g. a Dialog). We would then be doing one too-many refs(),
84        //We do an extra unref() in Window::_destroy_c_instance() to take care of that.
85
86        referenced_ = false; //Managed. We should not try to unfloat GtkObjects that we did not instantiate.
87     }
88   }
89 }
90
91 void Object::_destroy_c_instance()
92 {
93   #ifdef GLIBMM_DEBUG_REFCOUNTING
94   g_warning("Gtk::Object::_destroy_c_instance() this=%10X, gobject_=%10X\n", this, gobject_);
95     if(gobject_)
96       g_warning("  gtypename: %s\n", G_OBJECT_TYPE_NAME(gobject_));
97   #endif
98
99   cpp_destruction_in_progress_ = true;
100
101   // remove our hook.
102   GtkObject* object = gobj();
103
104   if (object)
105   { 
106     g_assert(GTK_IS_OBJECT(object));
107
108     disconnect_cpp_wrapper();
109     //Unfortunately this means that our dispose callback will not be called, because the qdata has been removed.
110     //So we'll connect the callback again, just so that gobject_disposed_ gets set for use later in this same method.
111     //See below:
112    
113
114     //This probably isn't a problem now:
115     //If we are killing the C++ instance before the C instance, then this might lead to strange behaviour.
116     //If this is a problem, then you'll have to use a managed() object, which will die only upon GTK+'s request.
117
118     //We can't do anything with the gobject_ if it's already been disposed.
119     //This prevents us from unref-ing it again, or destroying it again after GTK+ has told us that it has been disposed.
120     if (!gobject_disposed_)
121     {
122       if(referenced_)
123       {
124         //It's not manage()ed so we just unref to destroy it
125         #ifdef GLIBMM_DEBUG_REFCOUNTING
126         g_warning("final unref: gtypename: %s, refcount: %d\n", G_OBJECT_TYPE_NAME(object), ((GObject*)object)->ref_count);
127         #endif
128
129         //Because we called disconnect_cpp_wrapper() our dispose callback will not be called, because the qdata has been removed.
130         //So we'll connect a callback again, just so that gobject_disposed_ gets set for use later in this same method.
131         gulong connection_id_destroy = g_signal_connect (object, "destroy", G_CALLBACK (&callback_destroy_), this);
132
133         GLIBMM_DEBUG_UNREFERENCE(this, object);
134         g_object_unref(object);
135
136         if(!gobject_disposed_) //or if(g_signal_handler_is_connected(object, connection_id_destroy))
137           g_signal_handler_disconnect(object, connection_id_destroy);
138
139         //destroy_notify() should have been called after the final g_object_unref() or gtk_object_destroy(), so gobject_disposed_ should now be true.
140
141         //If the C instance still isn't dead then insist, by calling gtk_object_destroy().
142         //This is necessary because even a manage()d widget is refed when added to a container.
143         // <danielk> That's simply not true.  But references might be taken elsewhere,
144         // and gtk_object_destroy() just tells everyone "drop your refs, please!".
145         if (!gobject_disposed_)
146         {
147           #ifdef GLIBMM_DEBUG_REFCOUNTING
148           g_warning("Gtk::Object::_destroy_c_instance(): Calling gtk_object_destroy(): gobject_=%10X, gtypename=%s\n", object, G_OBJECT_TYPE_NAME(object));
149           #endif
150
151           g_assert(GTK_IS_OBJECT(object));
152           gtk_object_destroy(object); //Container widgets can respond to this.
153         }
154       }
155       else
156       {
157         //It's manag()ed, but the coder decided to delete it before deleting its parent.
158         //That should be OK because the Container can respond to that.
159         #ifdef GLIBMM_DEBUG_REFCOUNTING
160         g_warning("Gtk::Object::_destroy_c_instance(): Calling gtk_object_destroy(): gobject_=%10X\n", gobject_);
161         #endif
162
163         if (!gobject_disposed_)
164         {
165           g_assert(GTK_IS_OBJECT(object));
166           gtk_object_destroy(object);
167         }
168       }
169     }
170
171     //Glib::Object::~Object() will not g_object_unref() it too. because gobject_ is now 0.
172   }  
173 }
174
175 Object::~Object()
176 {
177   #ifdef GLIBMM_DEBUG_REFCOUNTING
178   g_warning("Gtk::Object::~Object() gobject_=%10X\n", gobject_);
179   #endif
180
181   //This has probably been called already from Gtk::Object::_destroy(), which is called from derived destructors.
182   _destroy_c_instance();
183 }
184
185 void Object::disconnect_cpp_wrapper()
186 {
187   //GTKMM_LIFECYCLE:
188
189   #ifdef GLIBMM_DEBUG_REFCOUNTING
190   g_warning("Gtk::Object::disconnect_cpp_wrapper() this=%10X, gobject_=%10X\n", this, gobject_);
191     if(gobject_)
192       g_warning("  gtypename: %s\n", G_OBJECT_TYPE_NAME(gobject_));
193   #endif
194
195   if(gobj())
196   {
197     //Prevent gtk vfuncs and default signal handlers from calling our instance methods:
198     g_object_steal_qdata((GObject*)gobj(), Glib::quark_); //It will no longer be possible to get the C++ instance from the C instance.
199
200     //Allow us to prevent generation of a new C++ wrapper during destruction:
201     g_object_set_qdata((GObject*)gobj(), Glib::quark_cpp_wrapper_deleted_, (gpointer)true);
202
203     //Prevent C++ instance from using GTK+ object:
204     gobject_ = 0;
205
206     //TODO: Disconnect any signals, using gtk methods.
207     //We'll have to keep a record of all the connections.
208   }
209 }
210
211 void Object::destroy_notify_()
212 {
213   //Overriden.
214   //GTKMM_LIFECYCLE
215
216   #ifdef GLIBMM_DEBUG_REFCOUNTING
217   g_warning("Gtk::Object::destroy_notify_: this=%10X, gobject_=%10X\n", this, gobject_);
218   if(gobject_)
219     g_warning("  gtypename=%s\n", G_OBJECT_TYPE_NAME(gobject_));
220   #endif
221
222   //Remember that it's been disposed (which only happens once):
223   //This also stops us from destroying it again in the destructor when it calls destroy_().
224   gobject_disposed_ = true;
225
226   if(!cpp_destruction_in_progress_) //This function might have been called as a side-effect of destroy() when it called gtk_object_destroy().
227   {
228     if (!referenced_) //If it's manage()ed.
229     {
230       #ifdef GLIBMM_DEBUG_REFCOUNTING
231       g_warning("Gtk::Object::destroy_notify_: before delete this.\n");
232       #endif
233       delete this; //Free the C++ instance.
234     }
235     else  //It's not managed, but the C gobject_ just died before the C++ instance..
236     {
237       #ifdef GLIBMM_DEBUG_REFCOUNTING
238       g_warning("Gtk::Object::destroy_notify_: setting gobject_ to 0\n");
239       #endif
240       gobject_ = 0;
241     }
242   }
243
244 }
245
246 void Object::destroy_()
247 {
248   //Called from destructors.
249   //GTKMM_LIFECYCLE
250
251   #ifdef GLIBMM_DEBUG_REFCOUNTING
252   g_warning("Gtk::Object::destroy_(): gobject_: %10X\n", gobject_);
253   if(gobject_)
254    g_warning("  gtypename: %s\n", G_OBJECT_TYPE_NAME(gobject_));
255   #endif
256
257   if ( !cpp_destruction_in_progress_ ) //see comment below.
258   {
259     //Prevent destroy_notify_() from running as a possible side-effect of gtk_object_destroy.
260     //We can't predict whether destroy_notify_() will really be run, so we'll disconnect the C++ instance here.
261     cpp_destruction_in_progress_ = true;
262
263     //destroy the C instance:
264     _destroy_c_instance();
265   }
266
267   //The C++ destructor will be reached later. This function was called by a destructor.
268 }
269
270 void Object::set_manage() 
271 {
272   //GTKMM_LIFECYCLE
273   //This object will not be unref()ed by gtkmm, though it could be destroyed if the coder deletes the C++ instance early.
274   //This method is overriden in Gtk::Window because they can not be manage()ed.
275
276   if (!referenced_) return; //It's already managed.
277
278   // remove our reference
279   if (gobject_->ref_count >= 1) //This should only happen just after creation. We don't use "==1" because GtkButton starts with a refcount of 2 when using a mnemonic.
280   {
281     //g_warning("Object::set_manage(), making object floating: %s\n", G_OBJECT_TYPE_NAME(gobject_));
282
283     // Cowardly refuse to remove last reference make floating instead. //TODO: What does that comment mean?
284     #ifdef GLIBMM_DEBUG_REFCOUNTING
285       g_warning("Object::set_manage(): setting GTK_FLOATING: gobject_ = %p", (void*) gobj());
286       g_warning("  gtypename=%s\n", G_OBJECT_TYPE_NAME(gobj()));
287     #endif
288     //deprecated: GTK_OBJECT_SET_FLAGS(gobj(), GTK_FLOATING);
289     g_object_force_floating(gobject_);
290   }
291   else
292   {
293     g_warning("Object::set_manage(). Refcount seems to be 0. %s\n", G_OBJECT_TYPE_NAME(gobject_));
294
295     //DEF_GLIBMM_DEBUG_UNREF(this, gobj())
296     //g_object_unref(gobj());
297   }
298
299   //g_warning("Object::set_manage(): end: %s", G_OBJECT_TYPE_NAME(gobject_));
300   //g_warning("  refcount=%d", G_OBJECT(gobj())->ref_count);
301
302   referenced_ = false;
303 }
304
305 void Object::callback_destroy_(GObject*, void* data) //static
306
307   //This is only used for a short time, then disconnected.
308
309   Object* cppObject = static_cast<Object*>(data);
310   if(cppObject) //This will be 0 if the C++ destructor has already run.
311   {
312     cppObject->gobject_disposed_ = true;
313   }
314 }
315
316 bool Object::is_managed_() const
317 {
318   return !referenced_;
319 }
320
321 } // namespace Gtk
322
323
324 namespace
325 {
326 } // anonymous namespace
327
328
329 namespace Glib
330 {
331
332 Gtk::Object* wrap(GtkObject* object, bool take_copy)
333 {
334   return dynamic_cast<Gtk::Object *> (Glib::wrap_auto ((GObject*)(object), take_copy));
335 }
336
337 } /* namespace Glib */
338
339 namespace Gtk
340 {
341
342
343 /* The *_Class implementation: */
344
345 const Glib::Class& Object_Class::init()
346 {
347   if(!gtype_) // create the GType if necessary
348   {
349     // Glib::Class has to know the class init function to clone custom types.
350     class_init_func_ = &Object_Class::class_init_function;
351
352     // This is actually just optimized away, apparently with no harm.
353     // Make sure that the parent type has been created.
354     //CppClassParent::CppObjectType::get_type();
355
356     // Create the wrapper type, with the same class/instance size as the base type.
357     register_derived_type(gtk_object_get_type());
358
359     // Add derived versions of interfaces, if the C type implements any interfaces:
360   }
361
362   return *this;
363 }
364
365 void Object_Class::class_init_function(void* g_class, void* class_data)
366 {
367   BaseClassType *const klass = static_cast<BaseClassType*>(g_class);
368   CppClassParent::class_init_function(klass, class_data);
369
370 #ifdef GLIBMM_VFUNCS_ENABLED
371 #endif //GLIBMM_VFUNCS_ENABLED
372
373 #ifdef GLIBMM_DEFAULT_SIGNAL_HANDLERS_ENABLED
374 #endif //GLIBMM_DEFAULT_SIGNAL_HANDLERS_ENABLED
375 }
376
377 #ifdef GLIBMM_VFUNCS_ENABLED
378 #endif //GLIBMM_VFUNCS_ENABLED
379
380 #ifdef GLIBMM_DEFAULT_SIGNAL_HANDLERS_ENABLED
381 #endif //GLIBMM_DEFAULT_SIGNAL_HANDLERS_ENABLED
382
383
384 Glib::ObjectBase* Object_Class::wrap_new(GObject* o)
385 {
386   return manage(new Object((GtkObject*)(o)));
387
388 }
389
390
391 /* The implementation: */
392
393 Object::CppClassType Object::object_class_; // initialize static member
394
395 GType Object::get_type()
396 {
397   return object_class_.init().get_type();
398 }
399
400 GType Object::get_base_type()
401 {
402   return gtk_object_get_type();
403 }
404
405
406 #ifdef GLIBMM_PROPERTIES_ENABLED
407 Glib::PropertyProxy<void*> Object::property_user_data() 
408 {
409   return Glib::PropertyProxy<void*>(this, "user-data");
410 }
411 #endif //GLIBMM_PROPERTIES_ENABLED
412
413 #ifdef GLIBMM_PROPERTIES_ENABLED
414 Glib::PropertyProxy_ReadOnly<void*> Object::property_user_data() const
415 {
416   return Glib::PropertyProxy_ReadOnly<void*>(this, "user-data");
417 }
418 #endif //GLIBMM_PROPERTIES_ENABLED
419
420
421 #ifdef GLIBMM_DEFAULT_SIGNAL_HANDLERS_ENABLED
422 #endif //GLIBMM_DEFAULT_SIGNAL_HANDLERS_ENABLED
423
424 #ifdef GLIBMM_VFUNCS_ENABLED
425 #endif //GLIBMM_VFUNCS_ENABLED
426
427
428 } // namespace Gtk
429
430