summaryrefslogtreecommitdiff
path: root/glib/glibmm/objectbase.h
blob: a3afd8340e032f67574e4a92cdeabab466311ff8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
#ifndef _GLIBMM_OBJECTBASE_H
#define _GLIBMM_OBJECTBASE_H

/* Copyright 2002 The gtkmm Development Team
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <glibmmconfig.h>
#include <glibmm/class.h>
#include <glibmm/signalproxy.h>
#include <glibmm/propertyproxy.h>
#include <glibmm/ustring.h>
#include <glibmm/value.h>
#include <glibmm/quark.h>
#include <glibmm/debug.h>
#include <sigc++/trackable.h>
#include <typeinfo>
#include <map> // Needed until the next ABI break.
#include <memory> // auto_ptr, needed until the next ABI break.

#ifndef DOXYGEN_SHOULD_SKIP_THIS
extern "C" { typedef struct _GObject GObject; }
#endif

namespace Glib
{

#ifndef DOXYGEN_SHOULD_SKIP_THIS
class GSigConnectionNode;
class Interface_Class;
namespace Threads
{
class Mutex;
}
#endif

//This inherits virtually from sigc::trackable so that people can multiply inherit glibmm classes from other sigc::trackable-derived classes.
//See bugzilla.gnome.org bug # 116280
/** Glib::ObjectBase is a common base class for Objects and Interfaces.
 *
 * This is used as virtual base class.  This means the ObjectBase
 * constructor runs before all others, either implicitly or explicitly.  Each of
 * the available constructors initializes custom_type_name_ in a different way.
 */
class GLIBMM_API ObjectBase : virtual public sigc::trackable
{
protected:
  /** This default constructor is called implicitly from the constructor of user-derived
   * classes, even if, for instance, Gtk::Button calls a different ObjectBase constructor.
   * This is normal behaviour for C++ virtual inheritance.
   *
   * The GType name will be gtkmm__anonymous_custom_type.
   */
  ObjectBase();

  /** A derived constructor always overrides this choice.
   * The C++ language itself ensures that the constructor
   * is only invoked once.
   *
   * All classes generated by gtkmmproc use this constructor, with custom_type_name = 0,
   * which essentially means it's not a custom type.  This is used to optimize
   * vfunc and signal handler callbacks -- since the C++ virtual methods are
   * not overridden, invocation can be skipped.
   *
   * The GType name will be @a custom_type_name.
   */
  explicit ObjectBase(const char* custom_type_name);

  /** This constructor is a special feature to allow creation of derived types on the
   * fly, without having to use g_object_new() manually.  This feature is
   * sometimes necessary, e.g. to implement a custom Gtk::CellRenderer.  The
   * neat trick with the virtual base class ctor makes it possible to reuse
   * the same direct base class' constructor as with non-custom types.
   *
   * The GType name will be @a custom_type_info.name().
   */
  explicit ObjectBase(const std::type_info& custom_type_info);

  virtual ~ObjectBase() = 0;

  // Called by Glib::Object and Glib::Interface constructors. See comments there.
  void initialize(GObject* castitem);

public:

  /// You probably want to use a specific property_*() accessor method instead.
  void set_property_value(const Glib::ustring& property_name, const Glib::ValueBase& value);

  /// You probably want to use a specific property_*() accessor method instead.
  void get_property_value(const Glib::ustring& property_name, Glib::ValueBase& value) const;

  /// You probably want to use a specific property_*() accessor method instead.
  template <class PropertyType>
  void set_property(const Glib::ustring& property_name, const PropertyType& value);

  /// You probably want to use a specific property_*() accessor method instead.
  template <class PropertyType>
  void get_property(const Glib::ustring& property_name, PropertyType& value) const;

  /** You can use the signal_changed() signal of the property proxy instead,
   * but this is necessary when using the reduced API.
   *
   * See also connect_property_changed_with_return().
   */
  void connect_property_changed(const Glib::ustring& property_name, const sigc::slot<void>& slot);

  /** You can use the signal_changed() signal of the property proxy instead,
   * but this is necessary when using the reduced API.
   *
   * This method was added because connect_property_changed() does not return a sigc::connection,
   * and we could not break the ABI by changing that function.
   */
  sigc::connection connect_property_changed_with_return(const Glib::ustring& property_name, const sigc::slot<void>& slot);

  /** Increases the freeze count on object. If the freeze count is non-zero, the
   * emission of "notify" signals on object is stopped. The signals are queued
   * until the freeze count is decreased to zero.
   *
   * This is necessary for accessors that modify multiple properties to prevent
   * premature notification while the object is still being modified.
   */
  void freeze_notify();

  /**
   * Reverts the effect of a previous call to freeze_notify(). The freeze count
   * is decreased on object and when it reaches zero, all queued "notify"
   * signals are emitted.
   *
   * It is an error to call this function when the freeze count is zero.
   */
  void thaw_notify();

  // Why are these virtual?
  // Don't know why they were originally made virtual, but it came in handy when
  // I wrapped GBinding in Glib::Binding. /Kjell
  /** Increment the reference count for this object.
   * You should never need to do this manually - use the object via a RefPtr instead.
   */
  virtual void reference() const;

  /** Decrement the reference count for this object.
   * You should never need to do this manually - use the object via a RefPtr instead.
   */
  virtual void unreference() const;

  ///Provides access to the underlying C GObject.
  inline GObject*       gobj()       { return gobject_; }

  ///Provides access to the underlying C GObject.
  inline const GObject* gobj() const { return gobject_; }

  /// Give a ref-ed copy to someone. Use for direct struct access.
  GObject* gobj_copy() const;

#ifndef DOXYGEN_SHOULD_SKIP_THIS

  /// This is for use by gtkmm wrappers only, and not by applications.
  static ObjectBase* _get_current_wrapper(GObject* object); //We keep this non-inline version, to preserve ABI.

  // This is commented-out because it's not clear yet whether it's a worthwhile optimization.
  /// This is for use by gtkmm wrappers only, and not by applications.
  //
  //inline static ObjectBase* _get_current_wrapper_inline(GObject* object)
  //{
  //  // This is what g_object_get_qdata does internally. However,
  //  // g_object_get_qdata does an addition G_IS_OBJECT(object) check that
  //  // needs three times as much time as the actual lookup.
  //  if(object)
  //    return static_cast<ObjectBase*>(g_datalist_id_get_data(&object->qdata, Glib::quark_));
  //  else
  //    return 0;
  //}

  bool _cpp_destruction_is_in_progress() const;
#endif //DOXYGEN_SHOULD_SKIP_THIS

protected:

#ifndef DOXYGEN_SHOULD_SKIP_THIS
  GObject*            gobject_; // the GLib/GDK/GTK+ object instance
  const char*         custom_type_name_;
  bool                cpp_destruction_in_progress_;

  bool is_anonymous_custom_() const;

//TODO: At the next ABI break, replace extra_object_base_data by a non-static
// data member.
// This is a new data member that can't be added as instance data to
// ObjectBase now, because it would break ABI.
struct ExtraObjectBaseData
{
  Class::interface_class_vector_type custom_interface_classes;
};

typedef std::map<const ObjectBase*, ExtraObjectBaseData> extra_object_base_data_type;
static extra_object_base_data_type extra_object_base_data;
// ObjectBase instances may be used in different threads.
// Accesses to extra_object_base_data must be thread-safe.
// auto_ptr, because we don't want to include glibmm/threads.h in objectbase.h.
// threads.h must be the first included file that includes glib.h. That could cause
// problems in files that directly or indirectly include objectbase.h.
static std::auto_ptr<Threads::Mutex> extra_object_base_data_mutex;

public: //  is_derived_() must be public, so that overridden vfuncs and signal handlers can call it via ObjectBase.

  /// This is for use by gtkmm wrappers only, and not by applications.
  bool is_derived_() const; //We keep this non-inline version, to preserve ABI.

  //This is commented-out because it's not clear yet whether it's a worthwhile optimization.
  //
  /// This is for use by gtkmm wrappers only, and not by applications.
  //inline bool is_derived_inline_() const
  //{
  //  return (custom_type_name_ != 0);
  //}

protected:
  static  void destroy_notify_callback_(void* data);
  virtual void destroy_notify_();

  void _set_current_wrapper(GObject* object);
#endif //DOXYGEN_SHOULD_SKIP_THIS

private:
  // noncopyable
  ObjectBase(const ObjectBase&);
  ObjectBase& operator=(const ObjectBase&);

#ifndef DOXYGEN_SHOULD_SKIP_THIS
  virtual void set_manage(); // calls g_error()
#endif //DOXYGEN_SHOULD_SKIP_THIS

#ifndef DOXYGEN_SHOULD_SKIP_THIS
  friend class Glib::GSigConnectionNode; // for GSigConnectionNode::notify()
#endif
};

#ifndef DOXYGEN_SHOULD_SKIP_THIS

template <class PropertyType> inline
void ObjectBase::set_property(const Glib::ustring& property_name, const PropertyType& value)
{
  Glib::Value<PropertyType> property_value;
  property_value.init(Glib::Value<PropertyType>::value_type());

  property_value.set(value);
  this->set_property_value(property_name, property_value);
}

template <class PropertyType> inline
void ObjectBase::get_property(const Glib::ustring& property_name, PropertyType& value) const
{
  Glib::Value<PropertyType> property_value;
  property_value.init(Glib::Value<PropertyType>::value_type());

  this->get_property_value(property_name, property_value);

  value = property_value.get();
}

#endif /* DOXYGEN_SHOULD_SKIP_THIS */


bool _gobject_cppinstance_already_deleted(GObject* gobject);

} // namespace Glib


#endif /* _GLIBMM_OBJECTBASE_H */