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