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 <libnr/nr-macros.h>
18 #include "nr-object.h"
20 unsigned int nr_emit_fail_warning(const gchar *file, unsigned int line, const gchar *method, const gchar *expr)
21 {
22 fprintf (stderr, "File %s line %d (%s): Assertion %s failed\n", file, line, method, expr);
23 return 1;
24 }
26 /* NRObject */
28 static NRObjectClass **classes = NULL;
29 static unsigned int classes_len = 0;
30 static unsigned int classes_size = 0;
32 NRType nr_type_is_a(NRType type, NRType test)
33 {
34 nr_return_val_if_fail(type < classes_len, FALSE);
35 nr_return_val_if_fail(test < classes_len, FALSE);
37 NRObjectClass *c = classes[type];
39 while (c) {
40 if (c->type == test) {
41 return TRUE;
42 }
43 c = c->parent;
44 }
46 return FALSE;
47 }
49 void const *nr_object_check_instance_cast(void const *ip, NRType tc)
50 {
51 nr_return_val_if_fail(ip != NULL, NULL);
52 nr_return_val_if_fail(nr_type_is_a(((NRObject const *) ip)->klass->type, tc), ip);
53 return ip;
54 }
56 unsigned int nr_object_check_instance_type(void const *ip, NRType tc)
57 {
58 if (ip == NULL) {
59 return FALSE;
60 }
62 return nr_type_is_a(((NRObject const *) ip)->klass->type, tc);
63 }
65 NRType nr_object_register_type(NRType parent,
66 gchar const *name,
67 unsigned int csize,
68 unsigned int isize,
69 void (* cinit) (NRObjectClass *),
70 void (* iinit) (NRObject *))
71 {
72 if (classes_len >= classes_size) {
73 classes_size += 32;
74 classes = nr_renew (classes, NRObjectClass *, classes_size);
75 if (classes_len == 0) {
76 classes[0] = NULL;
77 classes_len = 1;
78 }
79 }
81 NRType const type = classes_len;
82 classes_len += 1;
84 classes[type] = (NRObjectClass*) new char[csize];
85 NRObjectClass *c = classes[type];
87 /* FIXME: is this necessary? */
88 memset(c, 0, csize);
90 if (classes[parent]) {
91 memcpy(c, classes[parent], classes[parent]->csize);
92 }
94 c->type = type;
95 c->parent = classes[parent];
96 c->name = strdup(name);
97 c->csize = csize;
98 c->isize = isize;
99 c->cinit = cinit;
100 c->iinit = iinit;
102 c->cinit(c);
104 return type;
105 }
107 static void nr_object_class_init (NRObjectClass *klass);
108 static void nr_object_init (NRObject *object);
109 static void nr_object_finalize (NRObject *object);
111 NRType nr_object_get_type()
112 {
113 static NRType type = 0;
115 if (!type) {
116 type = nr_object_register_type (0,
117 "NRObject",
118 sizeof (NRObjectClass),
119 sizeof (NRObject),
120 (void (*) (NRObjectClass *)) nr_object_class_init,
121 (void (*) (NRObject *)) nr_object_init);
122 }
124 return type;
125 }
127 static void nr_object_class_init(NRObjectClass *c)
128 {
129 c->finalize = nr_object_finalize;
130 c->cpp_ctor = NRObject::invoke_ctor<NRObject>;
131 }
133 static void nr_object_init (NRObject *object)
134 {
135 }
137 static void nr_object_finalize (NRObject *object)
138 {
139 }
141 /* Dynamic lifecycle */
143 static void nr_class_tree_object_invoke_init(NRObjectClass *c, NRObject *object)
144 {
145 if (c->parent) {
146 nr_class_tree_object_invoke_init(c->parent, object);
147 }
148 c->iinit (object);
149 }
151 namespace {
153 void finalize_object(void *base, void *)
154 {
155 NRObject *object = reinterpret_cast<NRObject *>(base);
156 object->klass->finalize(object);
157 object->~NRObject();
158 }
160 }
162 NRObject *NRObject::alloc(NRType type)
163 {
164 nr_return_val_if_fail (type < classes_len, NULL);
166 NRObjectClass *c = classes[type];
168 if ( c->parent && c->cpp_ctor == c->parent->cpp_ctor ) {
169 g_error("Cannot instantiate NRObject class %s which has not registered a C++ constructor\n", c->name);
170 }
172 NRObject *object = reinterpret_cast<NRObject *>(
173 ::operator new(c->isize, Inkscape::GC::SCANNED, Inkscape::GC::AUTO,
174 &finalize_object, NULL)
175 );
176 memset(object, 0xf0, c->isize);
178 object->klass = c;
179 c->cpp_ctor(object);
180 nr_class_tree_object_invoke_init (c, object);
182 return object;
183 }
185 /* NRActiveObject */
187 static void nr_active_object_class_init(NRActiveObjectClass *c);
188 static void nr_active_object_init(NRActiveObject *object);
189 static void nr_active_object_finalize(NRObject *object);
191 static NRObjectClass *parent_class;
193 NRType nr_active_object_get_type()
194 {
195 static NRType type = 0;
196 if (!type) {
197 type = nr_object_register_type (NR_TYPE_OBJECT,
198 "NRActiveObject",
199 sizeof (NRActiveObjectClass),
200 sizeof (NRActiveObject),
201 (void (*) (NRObjectClass *)) nr_active_object_class_init,
202 (void (*) (NRObject *)) nr_active_object_init);
203 }
204 return type;
205 }
207 static void nr_active_object_class_init(NRActiveObjectClass *c)
208 {
209 NRObjectClass *object_class = (NRObjectClass *) c;
211 parent_class = object_class->parent;
213 object_class->finalize = nr_active_object_finalize;
214 object_class->cpp_ctor = NRObject::invoke_ctor<NRActiveObject>;
215 }
217 static void nr_active_object_init(NRActiveObject *object)
218 {
219 }
221 static void nr_active_object_finalize(NRObject *object)
222 {
223 NRActiveObject *aobject = (NRActiveObject *) object;
225 if (aobject->callbacks) {
226 for (unsigned int i = 0; i < aobject->callbacks->length; i++) {
227 NRObjectListener *listener = aobject->callbacks->listeners + i;
228 if ( listener->vector->dispose ) {
229 listener->vector->dispose(object, listener->data);
230 }
231 }
232 free (aobject->callbacks);
233 }
235 ((NRObjectClass *) (parent_class))->finalize(object);
236 }
238 void nr_active_object_add_listener(NRActiveObject *object,
239 const NRObjectEventVector *vector,
240 unsigned int size,
241 void *data)
242 {
243 if (!object->callbacks) {
244 object->callbacks = (NRObjectCallbackBlock*) malloc(sizeof(NRObjectCallbackBlock));
245 object->callbacks->size = 1;
246 object->callbacks->length = 0;
247 }
249 if (object->callbacks->length >= object->callbacks->size) {
250 int newsize = object->callbacks->size << 1;
251 object->callbacks = (NRObjectCallbackBlock *)
252 realloc(object->callbacks, sizeof(NRObjectCallbackBlock) + (newsize - 1) * sizeof (NRObjectListener));
253 object->callbacks->size = newsize;
254 }
256 NRObjectListener *listener = object->callbacks->listeners + object->callbacks->length;
257 listener->vector = vector;
258 listener->size = size;
259 listener->data = data;
260 object->callbacks->length += 1;
261 }
263 void nr_active_object_remove_listener_by_data(NRActiveObject *object, void *data)
264 {
265 if (object->callbacks == NULL) {
266 return;
267 }
269 for (unsigned i = 0; i < object->callbacks->length; i++) {
270 NRObjectListener *listener = object->callbacks->listeners + i;
271 if ( listener->data == data ) {
272 object->callbacks->length -= 1;
273 if ( object->callbacks->length < 1 ) {
274 free(object->callbacks);
275 object->callbacks = NULL;
276 } else if ( object->callbacks->length != i ) {
277 *listener = object->callbacks->listeners[object->callbacks->length];
278 }
279 return;
280 }
281 }
282 }
286 /*
287 Local Variables:
288 mode:c++
289 c-file-style:"stroustrup"
290 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
291 indent-tabs-mode:nil
292 fill-column:99
293 End:
294 */
295 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :