1 #define __NR_OBJECT_C__
3 /*
4 * RGBA display list system for inkscape
5 *
6 * Authors:
7 * Lauris Kaplinski <lauris@kaplinski.com>
8 * MenTaLguY <mental@rydia.net>
9 *
10 * This code is in public domain
11 */
13 #include <string.h>
14 #include <stdio.h>
16 #include <typeinfo>
18 #include <glib/gmem.h>
19 #include <libnr/nr-macros.h>
21 #include "nr-object.h"
22 #include "debug/event-tracker.h"
23 #include "debug/simple-event.h"
24 #include "util/share.h"
25 #include "util/format.h"
27 unsigned int nr_emit_fail_warning(const gchar *file, unsigned int line, const gchar *method, const gchar *expr)
28 {
29 fprintf (stderr, "File %s line %d (%s): Assertion %s failed\n", file, line, method, expr);
30 return 1;
31 }
33 /* NRObject */
35 static NRObjectClass **classes = NULL;
36 static unsigned int classes_len = 0;
37 static unsigned int classes_size = 0;
39 NRType nr_type_is_a(NRType type, NRType test)
40 {
41 nr_return_val_if_fail(type < classes_len, FALSE);
42 nr_return_val_if_fail(test < classes_len, FALSE);
44 NRObjectClass *c = classes[type];
46 while (c) {
47 if (c->type == test) {
48 return TRUE;
49 }
50 c = c->parent;
51 }
53 return FALSE;
54 }
56 void const *nr_object_check_instance_cast(void const *ip, NRType tc)
57 {
58 nr_return_val_if_fail(ip != NULL, NULL);
59 nr_return_val_if_fail(nr_type_is_a(((NRObject const *) ip)->klass->type, tc), ip);
60 return ip;
61 }
63 unsigned int nr_object_check_instance_type(void const *ip, NRType tc)
64 {
65 if (ip == NULL) {
66 return FALSE;
67 }
69 return nr_type_is_a(((NRObject const *) ip)->klass->type, tc);
70 }
72 NRType nr_object_register_type(NRType parent,
73 gchar const *name,
74 unsigned int csize,
75 unsigned int isize,
76 void (* cinit) (NRObjectClass *),
77 void (* iinit) (NRObject *))
78 {
79 if (classes_len >= classes_size) {
80 classes_size += 32;
81 classes = g_renew (NRObjectClass *, classes, classes_size);
82 if (classes_len == 0) {
83 classes[0] = NULL;
84 classes_len = 1;
85 }
86 }
88 NRType const type = classes_len;
89 classes_len += 1;
91 classes[type] = (NRObjectClass*) new char[csize];
92 NRObjectClass *c = classes[type];
94 /* FIXME: is this necessary? */
95 memset(c, 0, csize);
97 if (classes[parent]) {
98 memcpy(c, classes[parent], classes[parent]->csize);
99 }
101 c->type = type;
102 c->parent = classes[parent];
103 c->name = strdup(name);
104 c->csize = csize;
105 c->isize = isize;
106 c->cinit = cinit;
107 c->iinit = iinit;
109 c->cinit(c);
111 return type;
112 }
114 static void nr_object_class_init (NRObjectClass *klass);
115 static void nr_object_init (NRObject *object);
116 static void nr_object_finalize (NRObject *object);
118 NRType nr_object_get_type()
119 {
120 static NRType type = 0;
122 if (!type) {
123 type = nr_object_register_type (0,
124 "NRObject",
125 sizeof (NRObjectClass),
126 sizeof (NRObject),
127 (void (*) (NRObjectClass *)) nr_object_class_init,
128 (void (*) (NRObject *)) nr_object_init);
129 }
131 return type;
132 }
134 static void nr_object_class_init(NRObjectClass *c)
135 {
136 c->finalize = nr_object_finalize;
137 c->cpp_ctor = NRObject::invoke_ctor<NRObject>;
138 }
140 static void nr_object_init (NRObject *object)
141 {
142 }
144 static void nr_object_finalize (NRObject *object)
145 {
146 }
148 /* Dynamic lifecycle */
150 static void nr_class_tree_object_invoke_init(NRObjectClass *c, NRObject *object)
151 {
152 if (c->parent) {
153 nr_class_tree_object_invoke_init(c->parent, object);
154 }
155 c->iinit (object);
156 }
158 namespace {
160 namespace Debug = Inkscape::Debug;
161 namespace Util = Inkscape::Util;
163 typedef Debug::SimpleEvent<Debug::Event::FINALIZERS> BaseFinalizerEvent;
165 class FinalizerEvent : public BaseFinalizerEvent {
166 public:
167 FinalizerEvent(NRObject *object)
168 : BaseFinalizerEvent(Util::share_static_string("nr-object-finalizer"))
169 {
170 _addProperty("object", Util::format("%p", object));
171 _addProperty("class", Util::share_static_string(typeid(*object).name()));
172 }
173 };
175 void finalize_object(void *base, void *)
176 {
177 NRObject *object = reinterpret_cast<NRObject *>(base);
178 Debug::EventTracker<FinalizerEvent> tracker(object);
179 object->klass->finalize(object);
180 object->~NRObject();
181 }
183 }
185 NRObject *NRObject::alloc(NRType type)
186 {
187 nr_return_val_if_fail (type < classes_len, NULL);
189 NRObjectClass *c = classes[type];
191 if ( c->parent && c->cpp_ctor == c->parent->cpp_ctor ) {
192 g_error("Cannot instantiate NRObject class %s which has not registered a C++ constructor\n", c->name);
193 }
195 NRObject *object = reinterpret_cast<NRObject *>(
196 ::operator new(c->isize, Inkscape::GC::SCANNED, Inkscape::GC::AUTO,
197 &finalize_object, NULL)
198 );
199 memset(object, 0xf0, c->isize);
201 object->klass = c;
202 c->cpp_ctor(object);
203 nr_class_tree_object_invoke_init (c, object);
205 return object;
206 }
208 /* NRActiveObject */
210 static void nr_active_object_class_init(NRActiveObjectClass *c);
211 static void nr_active_object_init(NRActiveObject *object);
212 static void nr_active_object_finalize(NRObject *object);
214 static NRObjectClass *parent_class;
216 NRType nr_active_object_get_type()
217 {
218 static NRType type = 0;
219 if (!type) {
220 type = nr_object_register_type (NR_TYPE_OBJECT,
221 "NRActiveObject",
222 sizeof (NRActiveObjectClass),
223 sizeof (NRActiveObject),
224 (void (*) (NRObjectClass *)) nr_active_object_class_init,
225 (void (*) (NRObject *)) nr_active_object_init);
226 }
227 return type;
228 }
230 static void nr_active_object_class_init(NRActiveObjectClass *c)
231 {
232 NRObjectClass *object_class = (NRObjectClass *) c;
234 parent_class = object_class->parent;
236 object_class->finalize = nr_active_object_finalize;
237 object_class->cpp_ctor = NRObject::invoke_ctor<NRActiveObject>;
238 }
240 static void nr_active_object_init(NRActiveObject *object)
241 {
242 }
244 static void nr_active_object_finalize(NRObject *object)
245 {
246 NRActiveObject *aobject = (NRActiveObject *) object;
248 if (aobject->callbacks) {
249 for (unsigned int i = 0; i < aobject->callbacks->length; i++) {
250 NRObjectListener *listener = aobject->callbacks->listeners + i;
251 if ( listener->vector->dispose ) {
252 listener->vector->dispose(object, listener->data);
253 }
254 }
255 g_free (aobject->callbacks);
256 }
258 ((NRObjectClass *) (parent_class))->finalize(object);
259 }
261 void nr_active_object_add_listener(NRActiveObject *object,
262 const NRObjectEventVector *vector,
263 unsigned int size,
264 void *data)
265 {
266 if (!object->callbacks) {
267 object->callbacks = (NRObjectCallbackBlock*)g_malloc(sizeof(NRObjectCallbackBlock));
268 object->callbacks->size = 1;
269 object->callbacks->length = 0;
270 }
272 if (object->callbacks->length >= object->callbacks->size) {
273 int newsize = object->callbacks->size << 1;
274 object->callbacks = (NRObjectCallbackBlock *)
275 g_realloc(object->callbacks, sizeof(NRObjectCallbackBlock) + (newsize - 1) * sizeof (NRObjectListener));
276 object->callbacks->size = newsize;
277 }
279 NRObjectListener *listener = object->callbacks->listeners + object->callbacks->length;
280 listener->vector = vector;
281 listener->size = size;
282 listener->data = data;
283 object->callbacks->length += 1;
284 }
286 void nr_active_object_remove_listener_by_data(NRActiveObject *object, void *data)
287 {
288 if (object->callbacks == NULL) {
289 return;
290 }
292 for (unsigned i = 0; i < object->callbacks->length; i++) {
293 NRObjectListener *listener = object->callbacks->listeners + i;
294 if ( listener->data == data ) {
295 object->callbacks->length -= 1;
296 if ( object->callbacks->length < 1 ) {
297 g_free(object->callbacks);
298 object->callbacks = NULL;
299 } else if ( object->callbacks->length != i ) {
300 *listener = object->callbacks->listeners[object->callbacks->length];
301 }
302 return;
303 }
304 }
305 }
309 /*
310 Local Variables:
311 mode:c++
312 c-file-style:"stroustrup"
313 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
314 indent-tabs-mode:nil
315 fill-column:99
316 End:
317 */
318 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :