4 * An glib SMIL library.
6 * Authored By Koos Vriezen <koos.vriezen@gmail.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
26 * @short_description: DOM bases classes.
33 #include "laugh-dom.h"
35 #include "laugh-layout.h"
36 #include "laugh-timing.h"
40 #include <glib/gprintf.h>
42 #define LAUGH_NODE_GET_PRIVATE(obj) \
43 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), LAUGH_TYPE_NODE, LaughNodePrivate))
44 #define LAUGH_DOCUMENT_GET_PRIVATE(obj) \
45 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), LAUGH_TYPE_DOCUMENT, LaughDocumentPrivate))
56 typedef struct _DocumentBuilder
62 typedef struct _LaughIdMapping
64 GHashTable
*string_id
;
65 GHashTable
*id_string
;
69 static guint laugh_node_signals
[LAST_SIGNAL
] = { 0 };
71 static LaughIdMapping _laugh_tag_map
;
72 static LaughIdMapping _laugh_attr_map
;
75 /*struct _LaughNodePrivate
79 static gpointer laugh_node_parent_class
= ((void *)0);
81 static void laugh_node_finalize (GObject
*object
)
83 G_OBJECT_CLASS (laugh_node_parent_class
)->finalize (object
);
86 static void laugh_node_dispose (GObject
*object
)
88 LaughNode
*node
= LAUGH_NODE(object
);
92 g_hash_table_destroy (node
->attributes
);
94 for (child
= node
->first_child
; child
; ) {
95 LaughNode
*tmp
= child
->next_sibling
;
96 g_object_unref (child
);
100 G_OBJECT_CLASS (laugh_node_parent_class
)->dispose (object
);
103 void laugh_node_base_set_attribute (LaughNode
*node
,
104 LaughNodeAttributeId attr
, const gchar
*val
, gpointer
*undo
)
106 /*TODO: if val is NULL and undo is not NULL, free *undo and
107 * set *undo to old value*/
109 /* TODO: create a dynamic attribute list, create or handle undo */
111 /*This is ugly, during initialize g_hash_table_foreach call us */
112 if (node
->state
> LaughStateInit
&& node
->attributes
)
113 g_hash_table_insert (node
->attributes
,
114 (gpointer
) (long) attr
, (gpointer
) val
);
118 void _laugh_node_set_attribute (LaughNode
*node
,
119 LaughNodeAttributeId attr
, const gchar
*val
, gpointer
*undo
)
121 laugh_node_base_set_attribute (node
, attr
, val
, undo
);
124 static const gchar
*_laugh_node_get_attribute (LaughNode
*node
,
125 LaughNodeAttributeId att
)
127 if (node
->attributes
)
128 return (gchar
*) g_hash_table_lookup (
129 node
->attributes
, (gpointer
) (long) att
);
133 static void _laugh_node_init (LaughNode
*node
, LaughInitializer
*initializer
)
137 if (node
->attributes
)
138 g_hash_table_foreach (node
->attributes
, laugh_attributes_set
, node
);
140 for (child
= node
->first_child
; child
; child
= child
->next_sibling
)
141 laugh_node_init (child
, initializer
);
144 static void _laugh_add_mapping (LaughIdMapping
*m
, long id
, const gchar
*s
)
146 g_hash_table_insert (m
->string_id
, (gpointer
) s
, (gpointer
) id
);
147 g_hash_table_insert (m
->id_string
, (gpointer
) id
, (gpointer
) s
);
150 static void laugh_node_class_init (LaughNodeClass
*klass
)
152 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
154 laugh_node_parent_class
= g_type_class_peek_parent (klass
);
156 gobject_class
->finalize
= laugh_node_finalize
;
157 gobject_class
->dispose
= laugh_node_dispose
;
158 klass
->set_attribute
= _laugh_node_set_attribute
;
159 klass
->get_attribute
= _laugh_node_get_attribute
;
160 klass
->init
= _laugh_node_init
;
162 /*g_type_class_add_private (gobject_class, sizeof (LaughNodePrivate));*/
164 laugh_node_signals
[INITIALIZED
] =
165 g_signal_new ("initialized",
166 G_TYPE_FROM_CLASS (gobject_class
),
168 G_STRUCT_OFFSET (LaughNodeClass
, initialized
),
170 g_cclosure_marshal_VOID__VOID
,
173 laugh_node_signals
[STARTED
] =
174 g_signal_new ("started",
175 G_TYPE_FROM_CLASS (gobject_class
),
177 G_STRUCT_OFFSET (LaughNodeClass
, started
),
179 g_cclosure_marshal_VOID__VOID
,
182 laugh_node_signals
[STOPPED
] =
183 g_signal_new ("stopped",
184 G_TYPE_FROM_CLASS (gobject_class
),
186 G_STRUCT_OFFSET (LaughNodeClass
, stopped
),
188 g_cclosure_marshal_VOID__VOID
,
191 _laugh_tag_map
.string_id
= g_hash_table_new (g_str_hash
, g_str_equal
);
192 _laugh_tag_map
.id_string
= g_hash_table_new (NULL
, NULL
);
193 _laugh_tag_map
.string_unknown
= LaughTagIdLast
;
195 _laugh_attr_map
.string_id
= g_hash_table_new (g_str_hash
, g_str_equal
);
196 _laugh_attr_map
.id_string
= g_hash_table_new (NULL
, NULL
);
197 _laugh_attr_map
.string_unknown
= LaughAttrIdLast
;
199 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdDocument
, "document");
200 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdSmil
, "smil");
201 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdHead
, "head");
202 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdLayout
, "layout");
203 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdRootLayout
, "root-layout");
204 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdRegion
, "region");
205 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdBody
, "body");
206 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdSeq
, "seq");
207 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdPar
, "par");
208 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdExcl
, "excl");
209 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdSwitch
, "switch");
210 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdAudio
, "audio");
211 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdImg
, "img");
212 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdRef
, "ref");
213 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdText
, "text");
214 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdVideo
, "video");
216 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdId
, "id");
217 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdName
, "name");
218 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdLeft
, "left");
219 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdTop
, "top");
220 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdWidth
, "width");
221 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdHeight
, "height");
222 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdRight
, "right");
223 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdBottom
, "bottom");
224 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdBgColor
, "background-color");
225 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdBgColor1
, "backgroundColor");
226 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdBgImage
, "backgroundImage");
227 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdShowBg
, "showBackground");
228 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdZIndex
, "z-index");
229 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdBegin
, "begin");
230 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdDur
, "dur");
231 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdEnd
, "end");
232 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdEndSync
, "endSync");
233 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdRepeat
, "repeat");
234 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdSrc
, "src");
235 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdType
, "type");
236 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdSubType
, "subType");
237 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdFill
, "fil");
238 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdFit
, "fit");
239 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdPeers
, "peers");
240 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdHigher
, "higher");
241 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdLower
, "lower");
242 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdPauseDisplay
, "pauseDisplay");
243 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdHRef
, "href");
244 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdCoord
, "coord");
245 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdTransIn
, "trans-in");
246 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdTransOut
, "trans-out");
247 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdSystemBitrate
, "system-bitrate");
248 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdSensitivity
, "sensitivity");
249 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdFontColor
, "fontColor");
250 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdFontSize
, "fontSize");
251 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdHAlign
, "hAlign");
252 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdVAlign
, "vAlign");
253 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdCharset
, "charset");
254 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdBgOpacity
, "backgroundOpacity");
255 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdTargetAttr
, "targetAttribute");
256 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdTarget
, "target");
257 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdAttr
, "attribute");
258 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdAttrName
, "attributeName");
259 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdTo
, "to");
260 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdChangeBy
, "changed-by");
261 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdFrom
, "from");
262 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdValues
, "values");
263 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdCalcMode
, "calcMode");
264 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdKeyTimes
, "keyTimes");
265 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdKeySplines
, "keySplines");
268 static void laugh_node_instance_init (GTypeInstance
*instance
, gpointer g_class
)
270 LaughNode
*self
= (LaughNode
*)instance
;
272 /*self->priv = LAUGH_NODE_GET_PRIVATE (self);*/
274 self
->state
= LaughStateInit
;
275 self
->parent_node
= NULL
;
276 self
->first_child
= NULL
;
277 self
->previous_sibling
= NULL
;
278 self
->next_sibling
= NULL
;
279 self
->attributes
= NULL
;
282 GType
laugh_node_get_type (void)
284 static GType type
= 0;
286 static const GTypeInfo info
= {
287 sizeof (LaughNodeClass
),
288 NULL
, /* base_init */
289 NULL
, /* base_finalize */
290 (GClassInitFunc
) laugh_node_class_init
, /* class_init */
291 NULL
, /* class_finalize */
292 NULL
, /* class_data */
295 laugh_node_instance_init
/* instance_init */
297 type
= g_type_register_static (G_TYPE_OBJECT
,
304 struct _LaughDocumentPrivate
310 static gpointer laugh_document_parent_class
= ((void *)0);
312 static void laugh_document_finalize (GObject
*object
)
314 G_OBJECT_CLASS (laugh_document_parent_class
)->finalize (object
);
317 static void laugh_document_dispose (GObject
*object
)
319 LaughDocument
*document
= LAUGH_DOCUMENT(object
);
320 LaughTimingSegment
*segment
= document
->timing
;
322 g_free (document
->priv
->uri
);
324 G_OBJECT_CLASS (laugh_document_parent_class
)->dispose (object
);
326 laugh_timing_segment_delete (segment
);
330 void _lauch_document_mime_type (LaughIO
*io
, const gchar
*mime
, gpointer d
)
332 g_printf ("lauch_document_mime_type: %s\n", mime
);
333 if (strcmp (mime
, "application/smil")) {
334 LaughNode
*node
= LAUGH_NODE (d
);
336 g_printerr ("not a smil document\n");
337 laugh_io_cancel (io
);
339 g_object_unref (G_OBJECT (io
));
341 laugh_node_base_emit_initialized (node
);
346 _lauch_document_completed (LaughIO
*io
, gsize sz
, gpointer data
, gpointer d
)
348 LaughInitializer
*initializer
= (LaughInitializer
*)d
;
349 LaughNode
*node
= initializer
->node
;
351 g_printf ("_lauch_document_completed: %u\n", sz
);
353 laugh_node_set_inner_xml (node
, (const gchar
*) data
);
357 if (node
->first_child
)
358 laugh_node_init (node
->first_child
, initializer
);
360 g_object_unref (G_OBJECT (io
));
362 /*TODO wait for initialized signals*/
363 laugh_node_base_emit_initialized (node
);
366 static void _laugh_document_init (LaughNode
*doc
, LaughInitializer
*initializer
)
368 LaughDocument
*document
= (LaughDocument
*) doc
;
369 LaughDocumentPrivate
*priv
= document
->priv
;
371 initializer
->node
= doc
;
372 initializer
->parent_segment
= document
->timing
;
373 priv
->io
= laugh_io_new (priv
->uri
);
375 g_signal_connect (G_OBJECT (priv
->io
), "mime-type",
376 (GCallback
) _lauch_document_mime_type
, (gpointer
) doc
);
377 g_signal_connect (G_OBJECT (priv
->io
), "completed",
378 (GCallback
) _lauch_document_completed
, (gpointer
) initializer
);
380 laugh_io_open (priv
->io
);
383 static void laugh_document_class_init (LaughDocumentClass
*klass
)
385 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
386 LaughNodeClass
*node_class
= (LaughNodeClass
*) klass
;
388 laugh_document_parent_class
= g_type_class_peek_parent (klass
);
390 gobject_class
->finalize
= laugh_document_finalize
;
391 gobject_class
->dispose
= laugh_document_dispose
;
392 node_class
->init
= _laugh_document_init
;
394 g_type_class_add_private (gobject_class
, sizeof (LaughDocumentPrivate
));
398 void laugh_document_instance_init (GTypeInstance
*instance
, gpointer g_class
)
400 LaughDocument
*self
= (LaughDocument
*)instance
;
402 self
->priv
= LAUGH_DOCUMENT_GET_PRIVATE (self
);
403 self
->timing
= g_new0 (LaughTimingSegment
, 1);
404 self
->timing
->node
= (LaughNode
*) self
;
407 GType
laugh_document_get_type (void)
409 static GType type
= 0;
411 static const GTypeInfo info
= {
412 sizeof (LaughDocumentClass
),
413 NULL
, /* base_init */
414 NULL
, /* base_finalize */
415 (GClassInitFunc
) laugh_document_class_init
, /* class_init */
416 NULL
, /* class_finalize */
417 NULL
, /* class_data */
418 sizeof (LaughDocument
),
420 laugh_document_instance_init
/* instance_init */
422 type
= g_type_register_static (LAUGH_TYPE_NODE
,
429 static long _laugh_mapping_from_string (LaughIdMapping
*map
, const gchar
*tag
)
431 gpointer id
= g_hash_table_lookup (map
->string_id
, (gpointer
) tag
);
433 id
= (gpointer
) map
->string_unknown
++;
434 _laugh_add_mapping (map
, (long) id
, g_strdup (tag
));
439 LaughNodeTagId
laugh_tag_from_string (const gchar
*tag
)
441 return (LaughNodeTagId
) _laugh_mapping_from_string (&_laugh_tag_map
, tag
);
444 const gchar
*laugh_tag_from_id (LaughNodeTagId id
)
446 return (const gchar
*) g_hash_table_lookup (_laugh_tag_map
.id_string
,
450 LaughNodeAttributeId
laugh_attribute_from_string (const gchar
*attr
)
452 return (LaughNodeAttributeId
)_laugh_mapping_from_string (
453 &_laugh_attr_map
, attr
);
456 const gchar
*laugh_attribute_from_id (LaughNodeAttributeId id
)
458 return (const gchar
*) g_hash_table_lookup (_laugh_attr_map
.id_string
,
462 LaughInitializer
*laugh_dom_initializer_new (ClutterContainer
*parent
,
463 guint width
, guint height
)
465 LaughInitializer
*initializer
= g_new0 (LaughInitializer
, 1);
467 initializer
->parent_region
= parent
;
468 initializer
->parent_width
= width
;
469 initializer
->parent_height
= height
;
474 LaughNode
*laugh_node_new (LaughDocument
*document
, LaughNodeTagId id
,
477 LaughNode
*node
= LAUGH_NODE (g_object_new (LAUGH_TYPE_NODE
, NULL
));
479 laugh_node_base_construct (document
, node
, id
, attrs
);
484 LaughDocument
*laugh_document_new (const gchar
*uri
)
486 LaughDocument
*d
= LAUGH_DOCUMENT(g_object_new (LAUGH_TYPE_DOCUMENT
, NULL
));
487 LaughNode
*node
= (LaughNode
*)d
;
489 laugh_node_base_construct (d
, node
, LaughTagIdDocument
, NULL
);
490 d
->priv
->uri
= g_strdup (uri
);
495 void laugh_node_base_construct (LaughDocument
*document
, LaughNode
*node
,
496 LaughNodeTagId id
, GHashTable
*attributes
)
499 node
->document
= document
;
500 node
->attributes
= attributes
;
503 void laugh_attributes_set (gpointer key
, gpointer val
, gpointer data
)
505 laugh_node_set_attribute ((LaughNode
*)data
,
506 (LaughNodeAttributeId
) (long) key
, (const gchar
*) val
, NULL
);
509 void laugh_node_base_emit_initialized (LaughNode
*node
)
511 g_signal_emit (node
, laugh_node_signals
[INITIALIZED
], 0);
514 const gchar
*laugh_node_get_attribute (LaughNode
*node
,
515 LaughNodeAttributeId attribute
)
517 LaughNodeClass
*klass
= LAUGH_NODE_GET_CLASS(node
);
519 return klass
->get_attribute (node
, attribute
);
522 void laugh_node_set_attribute (LaughNode
*node
,
523 LaughNodeAttributeId attr
, const gchar
*value
, gpointer
*undo
)
525 LaughNodeClass
*klass
= LAUGH_NODE_GET_CLASS(node
);
527 klass
->set_attribute (node
, attr
, value
, undo
);
531 void _laugh_xml_start_tag (void *data
, const char *tag
, const char **attr
)
533 DocumentBuilder
*builder
= (DocumentBuilder
*) data
;
535 GHashTable
*attrs
= NULL
;
536 LaughNodeTagId id
= laugh_tag_from_string (tag
);
538 if (attr
&& attr
[0]) {
540 attrs
= g_hash_table_new_full (
541 NULL
, NULL
, NULL
, (GDestroyNotify
) g_free
);
542 for (i
= 0; attr
[i
]; i
+= 2)
543 g_hash_table_insert (attrs
,
544 (gpointer
) (long) laugh_attribute_from_string (attr
[i
]),
545 g_strdup (attr
[i
+1]));
548 case LaughTagIdLayout
:
549 case LaughTagIdRootLayout
:
550 case LaughTagIdRegion
:
551 node
= laugh_layout_new (builder
->top_node
->document
, id
, attrs
);
557 node
= laugh_timing_container_new (builder
->top_node
->document
,
561 node
= laugh_node_new (builder
->top_node
->document
, id
, attrs
);
563 laugh_node_append_child (builder
->current
, node
);
565 builder
->current
= node
;
568 static void _laugh_xml_end_tag (void *data
, const char *tag
)
570 DocumentBuilder
*builder
= (DocumentBuilder
*) data
;
572 if (laugh_tag_from_string (tag
) != builder
->current
->id
)
573 g_printerr ("unmatched tag %s, expects %s\n",
574 tag
, laugh_tag_from_id (builder
->current
->id
));
575 else if (builder
->current
!= builder
->top_node
)
576 builder
->current
= builder
->current
->parent_node
;
578 g_printerr ("spurious end tag %s", tag
);
581 void laugh_node_set_inner_xml (LaughNode
*node
, const gchar
*xml
)
583 DocumentBuilder builder
;
584 XML_Parser parser
= XML_ParserCreate (0L);
586 /*TODO: clear all node's child nodes*/
587 builder
.top_node
= node
;
588 builder
.current
= node
;
590 XML_SetUserData (parser
, &builder
);
591 XML_SetElementHandler (parser
, _laugh_xml_start_tag
, _laugh_xml_end_tag
);
593 if (XML_Parse (parser
, xml
, strlen (xml
), TRUE
) == XML_STATUS_ERROR
) {
597 XML_ParserFree(parser
);
600 static void _laugh_node_get_outer_xml (LaughNode
*node
, GString
*buffer
, int sp
)
605 indent
= (gchar
*) g_malloc (sp
+ 1);
606 memset (indent
, ' ', sp
);
608 g_string_append (buffer
, indent
);
611 g_string_append_c (buffer
, '<');
612 g_string_append (buffer
, laugh_tag_from_id (node
->id
));
613 if (node
->attributes
) {
616 g_hash_table_iter_init (&iter
, node
->attributes
);
617 while (g_hash_table_iter_next (&iter
, &key
, &value
)) {
618 g_string_append_c (buffer
, ' ');
619 g_string_append (buffer
, laugh_attribute_from_id ((long) key
));
620 g_string_append (buffer
, "=\"");
621 g_string_append (buffer
, (const gchar
*)value
);/*TODO escape*/
622 g_string_append_c (buffer
, '"');
625 if (node
->first_child
) {
627 g_string_append (buffer
, ">\n");
628 for (child
= node
->first_child
; child
; child
= child
->next_sibling
)
629 _laugh_node_get_outer_xml (child
, buffer
, sp
+2);
630 g_string_append (buffer
, indent
);
631 g_string_append (buffer
, "</");
632 g_string_append (buffer
, laugh_tag_from_id (node
->id
));
633 g_string_append (buffer
, ">\n");
635 g_string_append (buffer
, "/>\n");
642 gchar
*laugh_node_get_inner_xml (LaughNode
*node
)
644 GString
*buffer
= g_string_new ("");
648 for (child
= node
->first_child
; child
; child
= child
->next_sibling
)
649 _laugh_node_get_outer_xml (child
, buffer
, 0);
651 xml
= g_string_free (buffer
, FALSE
);
656 void laugh_node_append_child (LaughNode
*node
, LaughNode
*child
)
658 LaughNode
*n
= node
->last_child
;
661 n
->next_sibling
= child
;
662 child
->previous_sibling
= n
;
663 child
->next_sibling
= NULL
;
665 node
->first_child
= child
;
666 child
->previous_sibling
= NULL
;
667 child
->next_sibling
= NULL
;
669 node
->last_child
= child
;
670 child
->parent_node
= node
;
673 void laugh_node_init (LaughNode
*node
, LaughInitializer
*initializer
)
675 LaughNodeClass
*klass
= LAUGH_NODE_GET_CLASS(node
);
677 klass
->init (node
, initializer
);
680 #ifdef LAUGH_DOM_TEST
681 /* gcc laugh-dom.c laugh-io.c laugh-layout.c -o domtest `pkg-config --libs --cflags gio-2.0 glib-2.0 gthread-2.0 clutter-gtk-0.6` -lexpat -DLAUGH_DOM_TEST */
683 #include <sys/types.h>
684 #include <sys/stat.h>
687 static GMainLoop
*mainloop
;
689 void initialized_callback (LaughNode
*node
, gpointer d
)
691 gchar
*xml
= laugh_node_get_inner_xml (node
);
692 g_printf ("cb initialized\n%s\n", xml
);
696 g_main_loop_quit (mainloop
);
699 int main (int argc
, char **argv
)
702 LaughInitializer
*initializer
;
705 g_printerr ("usage %s uri\n", argv
[0]);
709 g_thread_init (NULL
);
712 doc
= laugh_document_new (argv
[1]);
713 initializer
= laugh_dom_initializer_new (NULL
, 640, 480);
715 g_signal_connect (G_OBJECT (doc
), "initialized",
716 (GCallback
) initialized_callback
, (gpointer
) 0);
718 laugh_node_init (LAUGH_NODE (doc
), initializer
);
720 mainloop
= g_main_loop_new (NULL
, TRUE
);
721 g_main_loop_run (mainloop
);
723 g_object_unref (G_OBJECT (doc
));
724 g_free (initializer
);