7eeac1243491a5660563c82f7daa570dc6496237
[lttv.git] / lttv / lttv / attribute.c
1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16 * MA 02111-1307, USA.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <string.h>
24 #include <lttv/attribute.h>
25 #include <ltt/ltt.h>
26 #include <ltt/compiler.h>
27
28 typedef union _AttributeValue {
29 int dv_int;
30 unsigned dv_uint;
31 long dv_long;
32 unsigned long dv_ulong;
33 float dv_float;
34 double dv_double;
35 LttTime dv_time;
36 gpointer dv_pointer;
37 char *dv_string;
38 GObject *dv_gobject;
39 } AttributeValue;
40
41
42 typedef struct _Attribute {
43 LttvAttributeName name;
44 LttvAttributeType type;
45 AttributeValue value;
46 gboolean is_named;
47 } Attribute;
48
49
50 static __inline__ LttvAttributeValue
51 address_of_value(LttvAttributeType t, AttributeValue *v)
52 {
53 LttvAttributeValue va = { NULL }; /* init to NULL for gcc */
54
55 switch(t) {
56 case LTTV_INT: va.v_int = &v->dv_int; break;
57 case LTTV_UINT: va.v_uint = &v->dv_uint; break;
58 case LTTV_LONG: va.v_long = &v->dv_long; break;
59 case LTTV_ULONG: va.v_ulong = &v->dv_ulong; break;
60 case LTTV_FLOAT: va.v_float = &v->dv_float; break;
61 case LTTV_DOUBLE: va.v_double = &v->dv_double; break;
62 case LTTV_TIME: va.v_time = &v->dv_time; break;
63 case LTTV_POINTER: va.v_pointer = &v->dv_pointer; break;
64 case LTTV_STRING: va.v_string = &v->dv_string; break;
65 case LTTV_GOBJECT: va.v_gobject = &v->dv_gobject; break;
66 case LTTV_NONE: break;
67 }
68 return va;
69 }
70
71
72 AttributeValue
73 init_value(LttvAttributeType t)
74 {
75 AttributeValue v;
76
77 switch(t) {
78 case LTTV_INT: v.dv_int = 0; break;
79 case LTTV_UINT: v.dv_uint = 0; break;
80 case LTTV_LONG: v.dv_long = 0; break;
81 case LTTV_ULONG: v.dv_ulong = 0; break;
82 case LTTV_FLOAT: v.dv_float = 0; break;
83 case LTTV_DOUBLE: v.dv_double = 0; break;
84 case LTTV_TIME: v.dv_time.tv_sec = 0; v.dv_time.tv_nsec = 0; break;
85 case LTTV_POINTER: v.dv_pointer = NULL; break;
86 case LTTV_STRING: v.dv_string = NULL; break;
87 case LTTV_GOBJECT: v.dv_gobject = NULL; break;
88 case LTTV_NONE: break;
89 }
90 return v;
91 }
92
93
94 unsigned int
95 lttv_attribute_get_number(LttvAttribute *self)
96 {
97 return self->attributes->len;
98 }
99
100 gboolean
101 lttv_attribute_named(LttvAttribute *self, gboolean *homogeneous)
102 {
103 *homogeneous = FALSE;
104 return TRUE;
105 }
106
107 LttvAttributeType
108 lttv_attribute_get(LttvAttribute *self, unsigned i, LttvAttributeName *name,
109 LttvAttributeValue *v, gboolean *is_named)
110 {
111 Attribute *a;
112
113 a = &g_array_index(self->attributes, Attribute, i);
114 *name = a->name;
115 *v = address_of_value(a->type, &(a->value));
116 *is_named = a->is_named;
117 return a->type;
118 }
119
120
121 LttvAttributeType
122 lttv_attribute_get_by_name(LttvAttribute *self, LttvAttributeName name,
123 LttvAttributeValue *v)
124 {
125 Attribute *a;
126
127 unsigned i;
128
129 gpointer p;
130
131 p = g_hash_table_lookup(self->names, GUINT_TO_POINTER(name));
132 if(p == NULL) return LTTV_NONE;
133
134 i = GPOINTER_TO_UINT(p);
135 i--;
136 a = &g_array_index(self->attributes, Attribute, i);
137 *v = address_of_value(a->type, &(a->value));
138 return a->type;
139 }
140
141
142 LttvAttributeValue
143 lttv_attribute_add(LttvAttribute *self, LttvAttributeName name,
144 LttvAttributeType t)
145 {
146 unsigned int i;
147
148 Attribute a, *pa;
149
150 i = GPOINTER_TO_UINT(g_hash_table_lookup(self->names, GUINT_TO_POINTER(name)));
151 if(i != 0) g_error("duplicate entry in attribute table");
152
153 a.name = name;
154 a.is_named = 1;
155 a.type = t;
156 a.value = init_value(t);
157 g_array_append_val(self->attributes, a);
158 i = self->attributes->len - 1;
159 pa = &g_array_index(self->attributes, Attribute, i);
160 g_hash_table_insert(self->names, GUINT_TO_POINTER(name),
161 GUINT_TO_POINTER(i + 1));
162 return address_of_value(t, &(pa->value));
163 }
164
165 LttvAttributeValue
166 lttv_attribute_add_unnamed(LttvAttribute *self, LttvAttributeName name,
167 LttvAttributeType t)
168 {
169 unsigned int i;
170
171 Attribute a, *pa;
172
173 i = GPOINTER_TO_UINT(g_hash_table_lookup(self->names, GUINT_TO_POINTER(name)));
174 if(i != 0) g_error("duplicate entry in attribute table");
175
176 a.name = name;
177 a.is_named = 0;
178 a.type = t;
179 a.value = init_value(t);
180 g_array_append_val(self->attributes, a);
181 i = self->attributes->len - 1;
182 pa = &g_array_index(self->attributes, Attribute, i);
183 g_hash_table_insert(self->names, GUINT_TO_POINTER(name),
184 GUINT_TO_POINTER(i + 1));
185 return address_of_value(t, &(pa->value));
186 }
187
188
189 /* Remove an attribute */
190
191 void
192 lttv_attribute_remove(LttvAttribute *self, unsigned i)
193 {
194 Attribute *a;
195
196 a = &g_array_index(self->attributes, Attribute, i);
197
198 /* If the element is a gobject, unreference it. */
199 if(a->type == LTTV_GOBJECT && a->value.dv_gobject != NULL)
200 g_object_unref(a->value.dv_gobject);
201
202 /* Remove the array element and its entry in the name index */
203
204 g_hash_table_remove(self->names, GUINT_TO_POINTER(a->name));
205 g_array_remove_index_fast(self->attributes, i);
206
207 /* The element used to replace the removed element has its index entry
208 all wrong now. Reinsert it with its new position. */
209
210 if(likely(self->attributes->len != i)){
211 g_hash_table_remove(self->names, GUINT_TO_POINTER(a->name));
212 g_hash_table_insert(self->names, GUINT_TO_POINTER(a->name), GUINT_TO_POINTER(i + 1));
213 }
214 }
215
216 void
217 lttv_attribute_remove_by_name(LttvAttribute *self, LttvAttributeName name)
218 {
219 unsigned int i;
220
221 i = GPOINTER_TO_UINT(g_hash_table_lookup(self->names, GUINT_TO_POINTER(name)));
222 if(unlikely(i == 0)) g_error("remove by name non existent attribute");
223
224 lttv_attribute_remove(self, i - 1);
225 }
226
227 /* Create an empty iattribute object and add it as an attribute under the
228 specified name, or return an existing iattribute attribute. If an
229 attribute of that name already exists but is not a GObject supporting the
230 iattribute interface, return NULL. */
231
232 /*CHECK*/LttvAttribute*
233 lttv_attribute_find_subdir(LttvAttribute *self, LttvAttributeName name)
234 {
235 unsigned int i;
236
237 Attribute a;
238
239 LttvAttribute *new;
240
241 i = GPOINTER_TO_UINT(g_hash_table_lookup(self->names, GUINT_TO_POINTER(name)));
242 if(likely(i != 0)) {
243 a = g_array_index(self->attributes, Attribute, i - 1);
244 if(likely(a.type == LTTV_GOBJECT && LTTV_IS_IATTRIBUTE(a.value.dv_gobject))) {
245 return LTTV_ATTRIBUTE(a.value.dv_gobject);
246 }
247 else return NULL;
248 }
249 new = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
250 *(lttv_attribute_add(self, name, LTTV_GOBJECT).v_gobject) = G_OBJECT(new);
251 return (LttvAttribute *)new;
252 }
253
254 /*CHECK*/LttvAttribute*
255 lttv_attribute_find_subdir_unnamed(LttvAttribute *self, LttvAttributeName name)
256 {
257 unsigned int i;
258
259 Attribute a;
260
261 LttvAttribute *new;
262
263 i = GPOINTER_TO_UINT(g_hash_table_lookup(self->names, GUINT_TO_POINTER(name)));
264 if(likely(i != 0)) {
265 a = g_array_index(self->attributes, Attribute, i - 1);
266 if(likely(a.type == LTTV_GOBJECT && LTTV_IS_IATTRIBUTE(a.value.dv_gobject))) {
267 return LTTV_ATTRIBUTE(a.value.dv_gobject);
268 }
269 else return NULL;
270 }
271 new = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
272 *(lttv_attribute_add_unnamed(self, name, LTTV_GOBJECT).v_gobject)
273 = G_OBJECT(new);
274 return (LttvAttribute *)new;
275 }
276
277 gboolean
278 lttv_attribute_find(LttvAttribute *self, LttvAttributeName name,
279 LttvAttributeType t, LttvAttributeValue *v)
280 {
281 unsigned int i;
282
283 Attribute *a;
284
285 i = GPOINTER_TO_UINT(g_hash_table_lookup(self->names, GUINT_TO_POINTER(name)));
286 if(likely(i != 0)) {
287 a = &g_array_index(self->attributes, Attribute, i - 1);
288 if(unlikely(a->type != t)) return FALSE;
289 *v = address_of_value(t, &(a->value));
290 return TRUE;
291 }
292
293 *v = lttv_attribute_add(self, name, t);
294 return TRUE;
295 }
296
297 gboolean
298 lttv_attribute_find_unnamed(LttvAttribute *self, LttvAttributeName name,
299 LttvAttributeType t, LttvAttributeValue *v)
300 {
301 unsigned i;
302
303 Attribute *a;
304
305 i = GPOINTER_TO_UINT(g_hash_table_lookup(self->names, GUINT_TO_POINTER(name)));
306 if(likely(i != 0)) {
307 a = &g_array_index(self->attributes, Attribute, i - 1);
308 if(unlikely(a->type != t)) return FALSE;
309 *v = address_of_value(t, &(a->value));
310 return TRUE;
311 }
312
313 *v = lttv_attribute_add_unnamed(self, name, t);
314 return TRUE;
315 }
316
317
318 /*void lttv_attribute_recursive_free(LttvAttribute *self)
319 {
320 int i, nb;
321
322 Attribute *a;
323
324 nb = self->attributes->len;
325
326 for(i = 0 ; i < nb ; i++) {
327 a = &g_array_index(self->attributes, Attribute, i);
328 if(a->type == LTTV_GOBJECT && LTTV_IS_ATTRIBUTE(a->value.dv_gobject)) {
329 lttv_attribute_recursive_free((LttvAttribute *)(a->value.dv_gobject));
330 }
331 }
332 g_object_unref(self);
333 }*/
334
335
336 void
337 lttv_attribute_recursive_add(LttvAttribute *dest, LttvAttribute *src)
338 {
339 int i, nb;
340
341 Attribute *a;
342
343 LttvAttributeValue value;
344 gboolean retval;
345
346 nb = src->attributes->len;
347
348 for(i = 0 ; i < nb ; i++) {
349 a = &g_array_index(src->attributes, Attribute, i);
350 if(a->type == LTTV_GOBJECT && LTTV_IS_ATTRIBUTE(a->value.dv_gobject)) {
351 if(a->is_named)
352 lttv_attribute_recursive_add(
353 /*CHECK*/(LttvAttribute *)lttv_attribute_find_subdir(dest, a->name),
354 (LttvAttribute *)(a->value.dv_gobject));
355 else
356 lttv_attribute_recursive_add(
357 /*CHECK*/(LttvAttribute *)lttv_attribute_find_subdir_unnamed(
358 dest, a->name), (LttvAttribute *)(a->value.dv_gobject));
359 }
360 else {
361 if(a->is_named) {
362 retval= lttv_attribute_find(dest, a->name, a->type, &value);
363 g_assert(retval);
364 }
365 else {
366 retval= lttv_attribute_find_unnamed(dest, a->name, a->type, &value);
367 g_assert(retval);
368 }
369 switch(a->type) {
370 case LTTV_INT:
371 *value.v_int += a->value.dv_int;
372 break;
373 case LTTV_UINT:
374 *value.v_uint += a->value.dv_uint;
375 break;
376 case LTTV_LONG:
377 *value.v_long += a->value.dv_long;
378 break;
379 case LTTV_ULONG:
380 *value.v_ulong += a->value.dv_ulong;
381 break;
382 case LTTV_FLOAT:
383 *value.v_float += a->value.dv_float;
384 break;
385 case LTTV_DOUBLE:
386 *value.v_double += a->value.dv_double;
387 break;
388 case LTTV_TIME:
389 *value.v_time = ltt_time_add(*value.v_time, a->value.dv_time);
390 break;
391 case LTTV_POINTER:
392 break;
393 case LTTV_STRING:
394 break;
395 case LTTV_GOBJECT:
396 break;
397 case LTTV_NONE:
398 break;
399 }
400 }
401 }
402 }
403
404
405 static void
406 print_indent(FILE *fp, int pos)
407 {
408 int i;
409
410 for(i = 0 ; i < pos ; i++) putc(' ', fp);
411 }
412
413
414 void
415 lttv_attribute_write_xml(LttvAttribute *self, FILE *fp, int pos, int indent)
416 {
417 int i, nb;
418
419 Attribute *a;
420
421 nb = self->attributes->len;
422
423 fprintf(fp,"<ATTRS>\n");
424 for(i = 0 ; i < nb ; i++) {
425 a = &g_array_index(self->attributes, Attribute, i);
426 print_indent(fp, pos);
427 fprintf(fp, "<ATTR NAME=\"%s\" ", g_quark_to_string(a->name));
428 if(a->type == LTTV_GOBJECT && LTTV_IS_ATTRIBUTE(a->value.dv_gobject)) {
429 fprintf(fp, "TYPE=ATTRS>");
430 lttv_attribute_write_xml((LttvAttribute *)(a->value.dv_gobject), fp,
431 pos + indent, indent);
432 }
433 else {
434 switch(a->type) {
435 case LTTV_INT:
436 fprintf(fp, "TYPE=INT VALUE=%d/>\n", a->value.dv_int);
437 break;
438 case LTTV_UINT:
439 fprintf(fp, "TYPE=UINT VALUE=%u/>\n", a->value.dv_uint);
440 break;
441 case LTTV_LONG:
442 fprintf(fp, "TYPE=LONG VALUE=%ld/>\n", a->value.dv_long);
443 break;
444 case LTTV_ULONG:
445 fprintf(fp, "TYPE=ULONG VALUE=%lu/>\n", a->value.dv_ulong);
446 break;
447 case LTTV_FLOAT:
448 fprintf(fp, "TYPE=FLOAT VALUE=%f/>\n", a->value.dv_float);
449 break;
450 case LTTV_DOUBLE:
451 fprintf(fp, "TYPE=DOUBLE VALUE=%f/>\n", a->value.dv_double);
452 break;
453 case LTTV_TIME:
454 fprintf(fp, "TYPE=TIME SEC=%lu NSEC=%lu/>\n",
455 a->value.dv_time.tv_sec, a->value.dv_time.tv_nsec);
456 break;
457 case LTTV_POINTER:
458 fprintf(fp, "TYPE=POINTER VALUE=%p/>\n", a->value.dv_pointer);
459 break;
460 case LTTV_STRING:
461 fprintf(fp, "TYPE=STRING VALUE=\"%s\"/>\n", a->value.dv_string);
462 break;
463 case LTTV_GOBJECT:
464 fprintf(fp, "TYPE=GOBJECT VALUE=%p/>\n", a->value.dv_gobject);
465 break;
466 case LTTV_NONE:
467 fprintf(fp, "TYPE=NONE/>\n");
468 break;
469 }
470 }
471 }
472 print_indent(fp, pos);
473 fprintf(fp,"</ATTRS>\n");
474 }
475
476
477 void
478 lttv_attribute_read_xml(LttvAttribute *self, FILE *fp)
479 {
480 int res;
481
482 char buffer[256], type[10];
483
484 LttvAttributeName name;
485
486 LttvAttributeValue value;
487
488 LttvAttribute *subtree;
489
490 res = fscanf(fp, "<ATTRS>");
491 g_assert(res > 0);
492 while(1) {
493 res = fscanf(fp, "<ATTR NAME=\"%256[^\"]\" TYPE=%10[^ >]", buffer, type);
494 g_assert(res == 2);
495 name = g_quark_from_string(buffer);
496 if(strcmp(type, "ATTRS") == 0) {
497 res = fscanf(fp, ">");
498 g_assert(res > 0);
499 subtree = lttv_attribute_find_subdir(self, name);
500 lttv_attribute_read_xml(subtree, fp);
501 }
502 else if(strcmp(type, "INT") == 0) {
503 value = lttv_attribute_add(self, name, LTTV_INT);
504 res = fscanf(fp, " VALUE=%d/>", value.v_int);
505 g_assert(res == 1);
506 }
507 else if(strcmp(type, "UINT") == 0) {
508 value = lttv_attribute_add(self, name, LTTV_UINT);
509 res = fscanf(fp, " VALUE=%u/>", value.v_uint);
510 g_assert(res == 1);
511 }
512 else if(strcmp(type, "LONG") == 0) {
513 value = lttv_attribute_add(self, name, LTTV_LONG);
514 res = fscanf(fp, " VALUE=%ld/>", value.v_long);
515 g_assert(res == 1);
516 }
517 else if(strcmp(type, "ULONG") == 0) {
518 value = lttv_attribute_add(self, name, LTTV_ULONG);
519 res = fscanf(fp, " VALUE=%lu/>", value.v_ulong);
520 g_assert(res == 1);
521 }
522 else if(strcmp(type, "FLOAT") == 0) {
523 float d;
524 value = lttv_attribute_add(self, name, LTTV_FLOAT);
525 res = fscanf(fp, " VALUE=%f/>", &d);
526 *(value.v_float) = d;
527 g_assert(res == 1);
528 }
529 else if(strcmp(type, "DOUBLE") == 0) {
530 value = lttv_attribute_add(self, name, LTTV_DOUBLE);
531 res = fscanf(fp, " VALUE=%lf/>", value.v_double);
532 g_assert(res == 1);
533 }
534 else if(strcmp(type, "TIME") == 0) {
535 value = lttv_attribute_add(self, name, LTTV_TIME);
536 res = fscanf(fp, " SEC=%lu NSEC=%lu/>", &(value.v_time->tv_sec),
537 &(value.v_time->tv_nsec));
538 g_assert(res == 2);
539 }
540 else if(strcmp(type, "POINTER") == 0) {
541 value = lttv_attribute_add(self, name, LTTV_POINTER);
542 res = fscanf(fp, " VALUE=%p/>", value.v_pointer);
543 g_error("Cannot read a pointer");
544 }
545 else if(strcmp(type, "STRING") == 0) {
546 value = lttv_attribute_add(self, name, LTTV_STRING);
547 res = fscanf(fp, " VALUE=\"%256[^\"]\"/>", buffer);
548 *(value.v_string) = g_strdup(buffer);
549 g_assert(res == 1);
550 }
551 else if(strcmp(type, "GOBJECT") == 0) {
552 value = lttv_attribute_add(self, name, LTTV_GOBJECT);
553 res = fscanf(fp, " VALUE=%p/>", value.v_gobject);
554 g_error("Cannot read a pointer");
555 }
556 else if(strcmp(type, "NONE") == 0) {
557 value = lttv_attribute_add(self, name, LTTV_NONE);
558 res = fscanf(fp, "/>");
559 g_assert(res > 0);
560 }
561 else g_error("Unknown type to read");
562 }
563 res = fscanf(fp, "</ATTRS>");
564 g_assert(res > 0);
565 }
566
567 static LttvAttribute *
568 new_attribute (LttvAttribute *self)
569 {
570 return g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
571 }
572
573
574 static void
575 attribute_interface_init (gpointer g_iface, gpointer iface_data)
576 {
577 LttvIAttributeClass *klass = (LttvIAttributeClass *)g_iface;
578
579 klass->new_attribute = (LttvIAttribute* (*) (LttvIAttribute *self))
580 new_attribute;
581
582 klass->get_number = (unsigned int (*) (LttvIAttribute *self))
583 lttv_attribute_get_number;
584
585 klass->named = (gboolean (*) (LttvIAttribute *self, gboolean *homogeneous))
586 lttv_attribute_named;
587
588 klass->get = (LttvAttributeType (*) (LttvIAttribute *self, unsigned i,
589 LttvAttributeName *name, LttvAttributeValue *v, gboolean *is_named))
590 lttv_attribute_get;
591
592 klass->get_by_name = (LttvAttributeType (*) (LttvIAttribute *self,
593 LttvAttributeName name, LttvAttributeValue *v))
594 lttv_attribute_get_by_name;
595
596 klass->add = (LttvAttributeValue (*) (LttvIAttribute *self,
597 LttvAttributeName name, LttvAttributeType t)) lttv_attribute_add;
598
599 klass->add_unnamed = (LttvAttributeValue (*) (LttvIAttribute *self,
600 LttvAttributeName name, LttvAttributeType t)) lttv_attribute_add_unnamed;
601
602 klass->remove = (void (*) (LttvIAttribute *self, unsigned i))
603 lttv_attribute_remove;
604
605 klass->remove_by_name = (void (*) (LttvIAttribute *self,
606 LttvAttributeName name)) lttv_attribute_remove_by_name;
607
608 klass->find_subdir = (LttvIAttribute* (*) (LttvIAttribute *self,
609 LttvAttributeName name)) lttv_attribute_find_subdir;
610
611 klass->find_subdir = (LttvIAttribute* (*) (LttvIAttribute *self,
612 LttvAttributeName name)) lttv_attribute_find_subdir_unnamed;
613 }
614
615 static void
616 attribute_instance_init (GTypeInstance *instance, gpointer g_class)
617 {
618 LttvAttribute *self = (LttvAttribute *)instance;
619 self->names = g_hash_table_new(g_direct_hash,
620 g_direct_equal);
621 self->attributes = g_array_new(FALSE, FALSE, sizeof(Attribute));
622 }
623
624
625 static void
626 attribute_finalize (LttvAttribute *self)
627 {
628 guint i;
629 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "attribute_finalize()");
630
631 for(i=0;i<self->attributes->len;i++) {
632 lttv_attribute_remove(self, i);
633 }
634
635 g_hash_table_destroy(self->names);
636 g_array_free(self->attributes, TRUE);
637 }
638
639
640 static void
641 attribute_class_init (LttvAttributeClass *klass)
642 {
643 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
644
645 gobject_class->finalize = (void (*)(GObject *self))attribute_finalize;
646 }
647
648 GType
649 lttv_attribute_get_type (void)
650 {
651 static GType type = 0;
652 if (type == 0) {
653 static const GTypeInfo info = {
654 sizeof (LttvAttributeClass),
655 NULL, /* base_init */
656 NULL, /* base_finalize */
657 (GClassInitFunc) attribute_class_init, /* class_init */
658 NULL, /* class_finalize */
659 NULL, /* class_data */
660 sizeof (LttvAttribute),
661 0, /* n_preallocs */
662 (GInstanceInitFunc) attribute_instance_init, /* instance_init */
663 NULL /* value handling */
664 };
665
666 static const GInterfaceInfo iattribute_info = {
667 (GInterfaceInitFunc) attribute_interface_init, /* interface_init */
668 NULL, /* interface_finalize */
669 NULL /* interface_data */
670 };
671
672 type = g_type_register_static (G_TYPE_OBJECT, "LttvAttributeType", &info,
673 0);
674 g_type_add_interface_static (type, LTTV_IATTRIBUTE_TYPE, &iattribute_info);
675 }
676 return type;
677 }
678
679
This page took 0.041304 seconds and 3 git commands to generate.