1 #ifndef _GLIBMM_OBJECTBASE_H
2 #define _GLIBMM_OBJECTBASE_H
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 Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 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  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <glibmmconfig.h>
21 #include <glibmm/class.h>
22 #include <glibmm/signalproxy.h>
23 #include <glibmm/propertyproxy.h>
24 #include <glibmm/ustring.h>
25 #include <glibmm/value.h>
26 #include <glibmm/quark.h>
27 #include <glibmm/debug.h>
28 #include <sigc++/trackable.h>
29 #include <typeinfo>
30 #include <map> // Needed until the next ABI break.
31 #include <memory> // Not used by ObjectBase any more, but user code may rely on it being here.
32 #include <mutex>
33 
34 #ifndef DOXYGEN_SHOULD_SKIP_THIS
35 extern "C" {
36 using GObject = struct _GObject;
37 }
38 #endif
39 
40 namespace Glib
41 {
42 
43 #ifndef DOXYGEN_SHOULD_SKIP_THIS
44 class GLIBMM_API GSigConnectionNode;
45 class GLIBMM_API Interface_Class;
46 #endif
47 
48 // This inherits virtually from sigc::trackable so that people can multiply inherit glibmm classes
49 // from other sigc::trackable-derived classes.
50 // See bugzilla.gnome.org bug # 116280
51 /** Glib::ObjectBase is a common base class for Objects and Interfaces.
52  *
53  * This is used as virtual base class.  This means the ObjectBase
54  * constructor runs before all others, either implicitly or explicitly.  Each of
55  * the available constructors initializes custom_type_name_ in a different way.
56  */
57 class GLIBMM_API ObjectBase : virtual public sigc::trackable
58 {
59 public:
60   // noncopyable
61   ObjectBase(const ObjectBase&) = delete;
62   ObjectBase& operator=(const ObjectBase&) = delete;
63 
64 protected:
65   /** This default constructor is called implicitly from the constructor of user-derived
66    * classes, even if, for instance, Gtk::Button calls a different ObjectBase constructor.
67    * This is normal behaviour for C++ virtual inheritance.
68    *
69    * The GType name will be gtkmm__anonymous_custom_type.
70    */
71   ObjectBase();
72 
73   /** A derived constructor always overrides this choice.
74    * The C++ language itself ensures that the constructor
75    * is only invoked once.
76    *
77    * All classes generated by gtkmmproc use this constructor, with custom_type_name = nullptr,
78    * which essentially means it's not a custom type.  This is used to optimize
79    * vfunc and signal handler callbacks -- since the C++ virtual methods are
80    * not overridden, invocation can be skipped.
81    *
82    * The GType name will be @a custom_type_name.
83    */
84   explicit ObjectBase(const char* custom_type_name);
85 
86   /** This constructor is a special feature to allow creation of derived types on the
87    * fly, without having to use g_object_new() manually.  This feature is
88    * sometimes necessary, e.g. to implement a custom Gtk::CellRenderer.  The
89    * neat trick with the virtual base class ctor makes it possible to reuse
90    * the same direct base class' constructor as with non-custom types.
91    *
92    * The GType name will be @a custom_type_info.name().
93    */
94   explicit ObjectBase(const std::type_info& custom_type_info);
95 
96   ObjectBase(ObjectBase&& src) noexcept;
97   ObjectBase& operator=(ObjectBase&& src) noexcept;
98 
99   virtual ~ObjectBase() noexcept = 0;
100 
101   // Called by Glib::Object and Glib::Interface constructors. See comments there.
102   void initialize(GObject* castitem);
103 
104   // Called by Glib::Object and Glib::Interface C++ move operations.
105   void initialize_move(GObject* castitem, Glib::ObjectBase* previous_wrapper);
106 
107 public:
108   /// You probably want to use a specific property_*() accessor method instead.
109   void set_property_value(const Glib::ustring& property_name, const Glib::ValueBase& value);
110 
111   /// You probably want to use a specific property_*() accessor method instead.
112   void get_property_value(const Glib::ustring& property_name, Glib::ValueBase& value) const;
113 
114   /// You probably want to use a specific property_*() accessor method instead.
115   template <class PropertyType>
116   void set_property(const Glib::ustring& property_name, const PropertyType& value);
117 
118   /// You probably want to use a specific property_*() accessor method instead.
119   template <class PropertyType>
120   void get_property(const Glib::ustring& property_name, PropertyType& value) const;
121 
122   // TODO: At the next ABI break, delete connect_property_changed_with_return()
123   // and let connect_property_changed() return sigc::connection.
124   /** You can use the signal_changed() signal of the property proxy instead.
125    *
126    * See also connect_property_changed_with_return().
127    */
128   void connect_property_changed(const Glib::ustring& property_name, const sigc::slot<void>& slot);
129 
130   /** You can use the signal_changed() signal of the property proxy instead.
131    *
132    * @newin{2,48}
133    */
134   void connect_property_changed(const Glib::ustring& property_name, sigc::slot<void>&& slot);
135 
136   /** You can use the signal_changed() signal of the property proxy instead.
137    *
138    * This method was added because connect_property_changed() does not return a sigc::connection,
139    * and we could not break the ABI by changing that function.
140    */
141   sigc::connection connect_property_changed_with_return(
142     const Glib::ustring& property_name, const sigc::slot<void>& slot);
143 
144   /** You can use the signal_changed() signal of the property proxy instead.
145    *
146    * @newin{2,48}
147    */
148   sigc::connection connect_property_changed_with_return(
149     const Glib::ustring& property_name, sigc::slot<void>&& slot);
150 
151   /** Increases the freeze count on object. If the freeze count is non-zero, the
152    * emission of "notify" signals on object is stopped. The signals are queued
153    * until the freeze count is decreased to zero.
154    *
155    * This is necessary for accessors that modify multiple properties to prevent
156    * premature notification while the object is still being modified.
157    */
158   void freeze_notify();
159 
160   /**
161    * Reverts the effect of a previous call to freeze_notify(). The freeze count
162    * is decreased on object and when it reaches zero, all queued "notify"
163    * signals are emitted.
164    *
165    * It is an error to call this function when the freeze count is zero.
166    */
167   void thaw_notify();
168 
169   // Why are these virtual?
170   // Don't know why they were originally made virtual, but it came in handy when
171   // I wrapped GBinding in Glib::Binding. /Kjell
172   /** Increment the reference count for this object.
173    * You should never need to do this manually - use the object via a RefPtr instead.
174    */
175   virtual void reference() const;
176 
177   /** Decrement the reference count for this object.
178    * You should never need to do this manually - use the object via a RefPtr instead.
179    */
180   virtual void unreference() const;
181 
182   /// Provides access to the underlying C GObject.
gobj()183   inline GObject* gobj() { return gobject_; }
184 
185   /// Provides access to the underlying C GObject.
gobj()186   inline const GObject* gobj() const { return gobject_; }
187 
188   /// Give a ref-ed copy to someone. Use for direct struct access.
189   GObject* gobj_copy() const;
190 
191 #ifndef DOXYGEN_SHOULD_SKIP_THIS
192 
193   /// This is for use by gtkmm wrappers only, and not by applications.
194   static ObjectBase* _get_current_wrapper(
195     GObject* object); // We keep this non-inline version, to preserve ABI.
196 
197   // This is commented-out because it's not clear yet whether it's a worthwhile optimization.
198   /// This is for use by gtkmm wrappers only, and not by applications.
199   //
200   // inline static ObjectBase* _get_current_wrapper_inline(GObject* object)
201   //{
202   //  // This is what g_object_get_qdata does internally. However,
203   //  // g_object_get_qdata does an addition G_IS_OBJECT(object) check that
204   //  // needs three times as much time as the actual lookup.
205   //  if(object)
206   //    return static_cast<ObjectBase*>(g_datalist_id_get_data(&object->qdata, Glib::quark_));
207   //  else
208   //    return 0;
209   //}
210 
211   bool _cpp_destruction_is_in_progress() const;
212 #endif // DOXYGEN_SHOULD_SKIP_THIS
213 
214 protected:
215 #ifndef DOXYGEN_SHOULD_SKIP_THIS
216   GObject* gobject_; // the GLib/GDK/GTK+ object instance
217   const char* custom_type_name_;
218   bool cpp_destruction_in_progress_;
219 
220   bool is_anonymous_custom_() const;
221 
222   // The following 7 methods are used by Glib::ExtraClassInit, Glib::Interface
223   // and Glib::Object during construction of a named custom type.
224   void add_custom_interface_class(const Interface_Class* iface_class);
225   void add_custom_class_init_function(GClassInitFunc class_init_func, void* class_data = nullptr);
226   void set_custom_instance_init_function(GInstanceInitFunc instance_init_func);
227   const Class::interface_class_vector_type* get_custom_interface_classes() const;
228   const Class::class_init_funcs_type* get_custom_class_init_functions() const;
229   GInstanceInitFunc get_custom_instance_init_function() const;
230   void custom_class_init_finished();
231 
232 public:
233   //  is_derived_() must be public, so that overridden vfuncs and signal handlers can call it
234   //  via ObjectBase.
235   /// This is for use by gtkmm wrappers only, and not by applications.
236   bool is_derived_() const; // We keep this non-inline version, to preserve ABI.
237 
238   // This is commented-out because it's not clear yet whether it's a worthwhile optimization.
239   //
240   /// This is for use by gtkmm wrappers only, and not by applications.
241   // inline bool is_derived_inline_() const
242   //{
243   //  return (custom_type_name_ != nullptr);
244   //}
245 
246 protected:
247   static void destroy_notify_callback_(void* data);
248   virtual void destroy_notify_();
249 
250   void _set_current_wrapper(GObject* object);
251 
252   /// For (indirect) use by C++ move operations.
253   void _move_current_wrapper(GObject* object, Glib::ObjectBase* previous_wrapper) noexcept;
254 #endif // DOXYGEN_SHOULD_SKIP_THIS
255 
256 private:
257 #ifndef DOXYGEN_SHOULD_SKIP_THIS
258   virtual void set_manage(); // calls g_error()
259 
260   // TODO: At the next ABI break, replace extra_object_base_data by a non-static
261   // data member.
262   // Private part of implementation.
263   // Used only during construction of named custom types.
264   // This is a new data member that can't be added as instance data to
265   // ObjectBase now, because it would break ABI.
266   struct ExtraObjectBaseData
267   {
268     // Pointers to the interfaces of custom types.
269     Class::interface_class_vector_type custom_interface_classes;
270     // Pointers to extra class init functions.
271     Class::class_init_funcs_type custom_class_init_functions;
272     // Pointer to the instance init function.
273     GInstanceInitFunc custom_instance_init_function = nullptr;
274   };
275 
276   using extra_object_base_data_type = std::map<const ObjectBase*, ExtraObjectBaseData>;
277   static extra_object_base_data_type extra_object_base_data;
278   // ObjectBase instances may be used in different threads.
279   // Accesses to extra_object_base_data must be thread-safe.
280   static std::mutex extra_object_base_data_mutex;
281 #endif // DOXYGEN_SHOULD_SKIP_THIS
282 
283 #ifndef DOXYGEN_SHOULD_SKIP_THIS
284   friend class Glib::GSigConnectionNode; // for GSigConnectionNode::notify()
285 #endif
286 };
287 
288 #ifndef DOXYGEN_SHOULD_SKIP_THIS
289 
290 template <class PropertyType>
291 inline void
set_property(const Glib::ustring & property_name,const PropertyType & value)292 ObjectBase::set_property(const Glib::ustring& property_name, const PropertyType& value)
293 {
294   Glib::Value<PropertyType> property_value;
295   property_value.init(Glib::Value<PropertyType>::value_type());
296 
297   property_value.set(value);
298   this->set_property_value(property_name, property_value);
299 }
300 
301 template <class PropertyType>
302 inline void
get_property(const Glib::ustring & property_name,PropertyType & value)303 ObjectBase::get_property(const Glib::ustring& property_name, PropertyType& value) const
304 {
305   Glib::Value<PropertyType> property_value;
306   property_value.init(Glib::Value<PropertyType>::value_type());
307 
308   this->get_property_value(property_name, property_value);
309 
310   value = property_value.get();
311 }
312 
313 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
314 
315 GLIBMM_API
316 bool _gobject_cppinstance_already_deleted(GObject* gobject);
317 
318 } // namespace Glib
319 
320 #endif /* _GLIBMM_OBJECTBASE_H */
321