summaryrefslogtreecommitdiff
path: root/glib/glibmm/object.h
blob: 4cb6ad910dd5b377d4a07c1464cacbd95a6652e5 (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
284
285
#ifndef _GLIBMM_OBJECT_H
#define _GLIBMM_OBJECT_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, see <http://www.gnu.org/licenses/>.
 */

// X11 defines DestroyNotify and some other non-prefixed stuff, and it's too late to change that
// now,
// so let's give people a clue about the compilation errors that they will see:
#ifdef DestroyNotify
#error \
  "X11/Xlib.h seems to have been included before this header. Due to some commonly-named macros in X11/Xlib.h, it may only be included after any glibmm, gdkmm, or gtkmm headers."
#endif

#include <glibmmconfig.h>
#include <glibmm/objectbase.h>
#include <glibmm/wrap.h>
#include <glibmm/quark.h>
#include <glibmm/refptr.h>
#include <glibmm/utility.h> /* Could be private, but that would be tedious. */
#include <glibmm/containerhandle_shared.h> /* Because its specializations may be here. */
#include <glibmm/value.h>
#include <glib.h> // for G_GNUC_NULL_TERMINATED and GDestroyNotify

#ifndef DOXYGEN_SHOULD_SKIP_THIS
extern "C" {
using GObject = struct _GObject;
using GObjectClass = struct _GObjectClass;
}
#endif /* DOXYGEN_SHOULD_SKIP_THIS */

namespace Glib
{

#ifndef DOXYGEN_SHOULD_SKIP_THIS

class GLIBMM_API Class;
class GLIBMM_API Object_Class;
class GLIBMM_API GSigConnectionNode;

/* ConstructParams::ConstructParams() takes a varargs list of properties
 * and values, like g_object_new() does.  This list will then be converted
 * to an array of parameter names and an array of parameter values,
 * for use with g_object_new_with_properties().  No overhead is
 * involved, since g_object_new() is just a wrapper around g_object_new_with_properties()
 * as well.
 *
 * The advantage of an auxiliary ConstructParams object over g_object_new()
 * is that the actual construction is always done in the Glib::Object ctor.
 * This allows for neat tricks like easy creation of derived custom types,
 * without adding special support to each ctor of every class.
 *
 * The comments in object.cc and objectbase.cc should explain in detail
 * how this works.
 */
class GLIBMM_API ConstructParams
{
public:
  const Glib::Class& glibmm_class;
  unsigned int n_parameters;
  const char ** parameter_names;
  GValue* parameter_values;

  explicit ConstructParams(const Glib::Class& glibmm_class_);
  ConstructParams(const Glib::Class& glibmm_class_, const char* first_property_name,
    ...) G_GNUC_NULL_TERMINATED; // warn if called without a trailing NULL pointer
  ~ConstructParams() noexcept;

  ConstructParams(const ConstructParams& other) = delete;
  ConstructParams& operator=(const ConstructParams&) = delete;
};

#endif /* DOXYGEN_SHOULD_SKIP_THIS */

class GLIBMM_API Object : virtual public ObjectBase
{
public:
#ifndef DOXYGEN_SHOULD_SKIP_THIS
  using CppObjectType = Object;
  using CppClassType = Object_Class;
  using BaseObjectType = GObject;
  using BaseClassType = GObjectClass;
#endif /* DOXYGEN_SHOULD_SKIP_THIS */

  // noncopyable
  Object(const Object&) = delete;
  Object& operator=(const Object&) = delete;

  Object(Object&& src) noexcept;
  Object& operator=(Object&& src) noexcept;

protected:
  Object(); // For use by C++-only sub-types.
  explicit Object(const Glib::ConstructParams& construct_params);
  explicit Object(GObject* castitem);
  ~Object() noexcept override; // It should only be deleted by the callback.

public:
// static RefPtr<Object> create(); //You must reimplement this in each derived class.

#ifndef DOXYGEN_SHOULD_SKIP_THIS
  static GType get_type() G_GNUC_CONST;
  static GType get_base_type() G_GNUC_CONST;
#endif

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

  // TODO: When we can break ABI and API, remove DestroyNotify and the
  // set_data() that uses it. Rename set_data_with_c_callback() to set_data().
  void* get_data(const QueryQuark& key);
  void set_data(const Quark& key, void* data);
  using DestroyNotify = void (*)(gpointer data);
  /** @newin{2,78} */
  void set_data_with_c_callback(const Quark& key, void* data, GDestroyNotify notify);
  /** Prefer set_data_with_c_callback() with a callback with C linkage. */
  void set_data(const Quark& key, void* data, DestroyNotify notify);
  void remove_data(const QueryQuark& quark);
  // same as remove without notifying
  void* steal_data(const QueryQuark& quark);

// convenience functions
// template <class T>
// void set_data_typed(const Quark& quark, const T& data)
//  { set_data(quark, new T(data), delete_typed<T>); }

// template <class T>
// T& get_data_typed(const QueryQuark& quark)
//  { return *static_cast<T*>(get_data(quark)); }

#ifndef DOXYGEN_SHOULD_SKIP_THIS

private:
  friend class Glib::Object_Class;
  static CppClassType object_class_;

#endif /* DOXYGEN_SHOULD_SKIP_THIS */

  // Glib::Object can not be dynamic because it lacks a float state.
  // virtual void set_manage();
};

// For some (proably, more spec-compliant) compilers, these specializations must
// be next to the objects that they use.
#ifndef GLIBMM_CAN_USE_DYNAMIC_CAST_IN_UNUSED_TEMPLATE_WITHOUT_DEFINITION
#ifndef DOXYGEN_SHOULD_SKIP_THIS /* hide the specializations */

namespace Container_Helpers
{

/** Partial specialization for pointers to GObject instances.
 * @ingroup ContHelpers
 * The C++ type is always a Glib::RefPtr<>.
 */
template <class T>
struct TypeTraits<Glib::RefPtr<T>>
{
  using CppType = Glib::RefPtr<T>;
  using CType = typename T::BaseObjectType*;
  using CTypeNonConst = typename T::BaseObjectType*;

  static CType to_c_type(const CppType& ptr) { return Glib::unwrap(ptr); }
  static CType to_c_type(CType ptr) { return ptr; }
  static CppType to_cpp_type(CType ptr)
  {
    // return Glib::wrap(ptr, true);

    // We copy/paste the wrap() implementation here,
    // because we can not use a specific Glib::wrap(CType) overload here,
    // because that would be "dependent", and g++ 3.4 does not allow that.
    // The specific Glib::wrap() overloads don't do anything special anyway.
    GObject* cobj = (GObject*)const_cast<CTypeNonConst>(ptr);
    return Glib::make_refptr_for_instance<T>(dynamic_cast<T*>(Glib::wrap_auto(cobj, true /* take_copy */)));
    // We use dynamic_cast<> in case of multiple inheritance.
  }

  static void release_c_type(CType ptr)
  {
    GLIBMM_DEBUG_UNREFERENCE(nullptr, ptr);
    g_object_unref(ptr);
  }
};

// This confuses the SUN Forte compiler, so we ifdef it out:
#ifdef GLIBMM_HAVE_DISAMBIGUOUS_CONST_TEMPLATE_SPECIALIZATIONS

/** Partial specialization for pointers to const GObject instances.
 * @ingroup ContHelpers
 * The C++ type is always a Glib::RefPtr<>.
 */
template <class T>
struct TypeTraits<Glib::RefPtr<const T>>
{
  using CppType = Glib::RefPtr<const T>;
  using CType = const typename T::BaseObjectType*;
  using CTypeNonConst = typename T::BaseObjectType*;

  static CType to_c_type(const CppType& ptr) { return Glib::unwrap(ptr); }
  static CType to_c_type(CType ptr) { return ptr; }
  static CppType to_cpp_type(CType ptr)
  {
    // return Glib::wrap(ptr, true);

    // We copy/paste the wrap() implementation here,
    // because we can not use a specific Glib::wrap(CType) overload here,
    // because that would be "dependent", and g++ 3.4 does not allow that.
    // The specific Glib::wrap() overloads don't do anything special anyway.
    GObject* cobj = (GObject*)(ptr);
    return Glib::make_refptr_for_instance<const T>(
      dynamic_cast<const T*>(Glib::wrap_auto(cobj, true /* take_copy */)));
    // We use dynamic_cast<> in case of multiple inheritance.
  }

  static void release_c_type(CType ptr)
  {
    GLIBMM_DEBUG_UNREFERENCE(nullptr, ptr);
    g_object_unref(const_cast<CTypeNonConst>(ptr));
  }
};

#endif /* GLIBMM_HAVE_DISAMBIGUOUS_CONST_TEMPLATE_SPECIALIZATIONS */

} // namespace Container_Helpers

template <class PtrT>
inline PtrT
Value_Pointer<PtrT>::get_(Glib::Object*) const
{
  return dynamic_cast<T*>(get_object());
}

/** Partial specialization for RefPtr<> to Glib::Object.
 * @ingroup glibmmValue
 */
template <class T>
class Value<Glib::RefPtr<T>> : public ValueBase_Object
{
public:
  using CppType = Glib::RefPtr<T>;
  using CType = typename T::BaseObjectType*;

  static GType value_type() { return T::get_base_type(); }

  void set(const CppType& data) { set_object(data.get()); }
  CppType get() const { return std::dynamic_pointer_cast<T>(get_object_copy()); }
};

// The SUN Forte Compiler has a problem with this:
#ifdef GLIBMM_HAVE_DISAMBIGUOUS_CONST_TEMPLATE_SPECIALIZATIONS

/** Partial specialization for RefPtr<> to const Glib::Object.
 * @ingroup glibmmValue
 */
template <class T>
class Value<Glib::RefPtr<const T>> : public ValueBase_Object
{
public:
  using CppType = Glib::RefPtr<const T>;
  using CType = typename T::BaseObjectType*;

  static GType value_type() { return T::get_base_type(); }

  void set(const CppType& data) { set_object(const_cast<T*>(data.get())); }
  CppType get() const { return std::dynamic_pointer_cast<T>(get_object_copy()); }
};
#endif /* GLIBMM_HAVE_DISAMBIGUOUS_CONST_TEMPLATE_SPECIALIZATIONS */

#endif /* DOXYGEN_SHOULD_SKIP_THIS */
#endif /* GLIBMM_CAN_USE_DYNAMIC_CAST_IN_UNUSED_TEMPLATE_WITHOUT_DEFINITION */

} // namespace Glib

#endif /* _GLIBMM_OBJECT_H */