feffbd884d2f97cccd3218d34874e9c99d1af52b
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 <libnr/nr-macros.h>
20 #include "nr-object.h"
21 #include "debug/event-tracker.h"
22 #include "debug/simple-event.h"
23 #include "util/share.h"
24 #include "util/format.h"
26 unsigned int nr_emit_fail_warning(const gchar *file, unsigned int line, const gchar *method, const gchar *expr)
27 {
28 fprintf (stderr, "File %s line %d (%s): Assertion %s failed\n", file, line, method, expr);
29 return 1;
30 }
32 /* NRObject */
34 static NRObjectClass **classes = NULL;
35 static unsigned int classes_len = 0;
36 static unsigned int classes_size = 0;
38 NRType nr_type_is_a(NRType type, NRType test)
39 {
40 nr_return_val_if_fail(type < classes_len, FALSE);
41 nr_return_val_if_fail(test < classes_len, FALSE);
43 NRObjectClass *c = classes[type];
45 while (c) {
46 if (c->type == test) {
47 return TRUE;
48 }
49 c = c->parent;
50 }
52 return FALSE;
53 }
55 void const *nr_object_check_instance_cast(void const *ip, NRType tc)
56 {
57 nr_return_val_if_fail(ip != NULL, NULL);
58 nr_return_val_if_fail(nr_type_is_a(((NRObject const *) ip)->klass->type, tc), ip);
59 return ip;
60 }
62 unsigned int nr_object_check_instance_type(void const *ip, NRType tc)
63 {
64 if (ip == NULL) {
65 return FALSE;
66 }
68 return nr_type_is_a(((NRObject const *) ip)->klass->type, tc);
69 }
71 NRType nr_object_register_type(NRType parent,
72 gchar const *name,
73 unsigned int csize,
74 unsigned int isize,
75 void (* cinit) (NRObjectClass *),
76 void (* iinit) (NRObject *))
77 {
78 if (classes_len >= classes_size) {
79 classes_size += 32;
80 classes = nr_renew (classes, NRObjectClass *, classes_size);
81 if (classes_len == 0) {
82 classes[0] = NULL;
83 classes_len = 1;
84 }
85 }
87 NRType const type = classes_len;
88 classes_len += 1;
90 classes[type] = (NRObjectClass*) new char[csize];
91 NRObjectClass *c = classes[type];
93 /* FIXME: is this necessary? */
94 memset(c, 0, csize);
96 if (classes[parent]) {
97 memcpy(c, classes[parent], classes[parent]->csize);
98 }
100 c->type = type;
101 c->parent = classes[parent];
102 c->name = strdup(name);
103 c->csize = csize;
104 c->isize = isize;
105 c->cinit = cinit;
106 c->iinit = iinit;
108 c->cinit(c);
110 return type;
111 }
113 static void nr_object_class_init (NRObjectClass *klass);
114 static void nr_object_init (NRObject *object);
115 static void nr_object_finalize (NRObject *object);
117 NRType nr_object_get_type()
118 {
119 static NRType type = 0;
121 if (!type) {
122 type = nr_object_register_type (0,
123 "NRObject",
124 sizeof (NRObjectClass),
125 sizeof (NRObject),
126 (void (*) (NRObjectClass *)) nr_object_class_init,
127 (void (*) (NRObject *)) nr_object_init);
128 }
130 return type;
131 }
133 static void nr_object_class_init(NRObjectClass *c)
134 {
135 c->finalize = nr_object_finalize;
136 c->cpp_ctor = NRObject::invoke_ctor<NRObject>;
137 }
139 static void nr_object_init (NRObject *object)
140 {
141 }
143 static void nr_object_finalize (NRObject *object)
144 {
145 }
147 /* Dynamic lifecycle */
149 static void nr_class_tree_object_invoke_init(NRObjectClass *c, NRObject *object)
150 {
151 if (c->parent) {
152 nr_class_tree_object_invoke_init(c->parent, object);
153 }
154 c->iinit (object);
155 }
157 namespace {
159 namespace Debug = Inkscape::Debug;
160 namespace Util = Inkscape::Util;
162 typedef Debug::SimpleEvent<Debug::Event::FINALIZERS> BaseFinalizerEvent;
164 class FinalizerEvent : public BaseFinalizerEvent {
165 public:
166 FinalizerEvent(NRObject *object)
167 : BaseFinalizerEvent(Util::share_static_string("nr-object-finalizer"))
168 {
169 _addProperty("object", Util::format("%p", object));
170 _addProperty("class", Util::share_static_string(typeid(*object).name()));
171 }
172 };
174 void finalize_object(void *base, void *)
175 {
176 NRObject *object = reinterpret_cast<NRObject *>(base);
177 Debug::EventTracker<FinalizerEvent> tracker(object);
178 object->klass->finalize(object);
179 object->~NRObject();
180 }
182 }
184 NRObject *NRObject::alloc(NRType type)
185 {
186 nr_return_val_if_fail (type < classes_len, NULL);
188 NRObjectClass *c = classes[type];
190 if ( c->parent && c->cpp_ctor == c->parent->cpp_ctor ) {
191 g_error("Cannot instantiate NRObject class %s which has not registered a C++ constructor\n", c->name);
192 }
194 NRObject *object = reinterpret_cast<NRObject *>(
195 ::operator new(c->isize, Inkscape::GC::SCANNED, Inkscape::GC::AUTO,
196 &finalize_object, NULL)
197 );
198 memset(object, 0xf0, c->isize);
200 object->klass = c;
201 c->cpp_ctor(object);
202 nr_class_tree_object_invoke_init (c, object);
204 return object;
205 }
207 /* NRActiveObject */
209 static void nr_active_object_class_init(NRActiveObjectClass *c);
210 static void nr_active_object_init(NRActiveObject *object);
211 static void nr_active_object_finalize(NRObject *object);
213 static NRObjectClass *parent_class;
215 NRType nr_active_object_get_type()
216 {
217 static NRType type = 0;
218 if (!type) {
219 type = nr_object_register_type (NR_TYPE_OBJECT,
220 "NRActiveObject",
221 sizeof (NRActiveObjectClass),
222 sizeof (NRActiveObject),
223 (void (*) (NRObjectClass *)) nr_active_object_class_init,
224 (void (*) (NRObject *)) nr_active_object_init);
225 }
226 return type;
227 }
229 static void nr_active_object_class_init(NRActiveObjectClass *c)
230 {
231 NRObjectClass *object_class = (NRObjectClass *) c;
233 parent_class = object_class->parent;
235 object_class->finalize = nr_active_object_finalize;
236 object_class->cpp_ctor = NRObject::invoke_ctor<NRActiveObject>;
237 }
239 static void nr_active_object_init(NRActiveObject *object)
240 {
241 }
243 static void nr_active_object_finalize(NRObject *object)
244 {
245 NRActiveObject *aobject = (NRActiveObject *) object;
247 if (aobject->callbacks) {
248 for (unsigned int i = 0; i < aobject->callbacks->length; i++) {
249 NRObjectListener *listener = aobject->callbacks->listeners + i;
250 if ( listener->vector->dispose ) {
251 listener->vector->dispose(object, listener->data);
252 }
253 }
254 free (aobject->callbacks);
255 }
257 ((NRObjectClass *) (parent_class))->finalize(object);
258 }
260 void nr_active_object_add_listener(NRActiveObject *object,
261 const NRObjectEventVector *vector,
262 unsigned int size,
263 void *data)
264 {
265 if (!object->callbacks) {
266 object->callbacks = (NRObjectCallbackBlock*) malloc(sizeof(NRObjectCallbackBlock));
267 object->callbacks->size = 1;
268 object->callbacks->length = 0;
269 }
271 if (object->callbacks->length >= object->callbacks->size) {
272 int newsize = object->callbacks->size << 1;
273 object->callbacks = (NRObjectCallbackBlock *)
274 realloc(object->callbacks, sizeof(NRObjectCallbackBlock) + (newsize - 1) * sizeof (NRObjectListener));
275 object->callbacks->size = newsize;
276 }
278 NRObjectListener *listener = object->callbacks->listeners + object->callbacks->length;
279 listener->vector = vector;
280 listener->size = size;
281 listener->data = data;
282 object->callbacks->length += 1;
283 }
285 void nr_active_object_remove_listener_by_data(NRActiveObject *object, void *data)
286 {
287 if (object->callbacks == NULL) {
288 return;
289 }
291 for (unsigned i = 0; i < object->callbacks->length; i++) {
292 NRObjectListener *listener = object->callbacks->listeners + i;
293 if ( listener->data == data ) {
294 object->callbacks->length -= 1;
295 if ( object->callbacks->length < 1 ) {
296 free(object->callbacks);
297 object->callbacks = NULL;
298 } else if ( object->callbacks->length != i ) {
299 *listener = object->callbacks->listeners[object->callbacks->length];
300 }
301 return;
302 }
303 }
304 }
308 /*
309 Local Variables:
310 mode:c++
311 c-file-style:"stroustrup"
312 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
313 indent-tabs-mode:nil
314 fill-column:99
315 End:
316 */
317 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :