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"
39 #include <glib/gprintf.h>
41 #define LAUGH_NODE_GET_PRIVATE(obj) \
42 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), LAUGH_TYPE_NODE, LaughNodePrivate))
43 #define LAUGH_DOCUMENT_GET_PRIVATE(obj) \
44 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), LAUGH_TYPE_DOCUMENT, LaughDocumentPrivate))
55 typedef struct _DocumentBuilder
61 typedef struct _LaughIdMapping
63 GHashTable
*string_id
;
64 GHashTable
*id_string
;
68 static guint laugh_node_signals
[LAST_SIGNAL
] = { 0 };
70 static LaughIdMapping _laugh_tag_map
;
71 static LaughIdMapping _laugh_attr_map
;
74 struct _LaughNodePrivate
76 GHashTable
*attributes
;
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
);
91 if (node
->priv
->attributes
)
92 g_hash_table_destroy (node
->priv
->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
);
104 void _laugh_node_set_attribute (LaughNode
*node
,
105 LaughNodeAttributeId att
, const gchar
*val
, gpointer
*undo
)
107 LaughNodePrivate
*priv
= node
->priv
;
109 /* TODO: create a dynamic attribute list, create or handle undo */
110 if (priv
->attributes
)
111 g_hash_table_insert (priv
->attributes
,
112 (gpointer
) (long) att
, (gpointer
) val
);
115 static const gchar
*_laugh_node_get_attribute (LaughNode
*node
,
116 LaughNodeAttributeId att
)
118 LaughNodePrivate
*priv
= node
->priv
;
120 if (priv
->attributes
)
121 return (gchar
*) g_hash_table_lookup (
122 priv
->attributes
, (gpointer
) (long) att
);
126 static void _laugh_node_init (LaughNode
*node
, LaughInitializer
*initializer
)
130 for (child
= node
->first_child
; child
; child
= child
->next_sibling
)
131 laugh_node_init (child
, initializer
);
134 static void _laugh_add_mapping (LaughIdMapping
*m
, long id
, const gchar
*s
)
136 g_hash_table_insert (m
->string_id
, (gpointer
) s
, (gpointer
) id
);
137 g_hash_table_insert (m
->id_string
, (gpointer
) id
, (gpointer
) s
);
140 static void laugh_node_class_init (LaughNodeClass
*klass
)
142 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
144 laugh_node_parent_class
= g_type_class_peek_parent (klass
);
146 gobject_class
->finalize
= laugh_node_finalize
;
147 gobject_class
->dispose
= laugh_node_dispose
;
148 klass
->set_attribute
= _laugh_node_set_attribute
;
149 klass
->get_attribute
= _laugh_node_get_attribute
;
150 klass
->init
= _laugh_node_init
;
152 g_type_class_add_private (gobject_class
, sizeof (LaughNodePrivate
));
154 laugh_node_signals
[INITIALIZED
] =
155 g_signal_new ("initialized",
156 G_TYPE_FROM_CLASS (gobject_class
),
158 G_STRUCT_OFFSET (LaughNodeClass
, initialized
),
160 g_cclosure_marshal_VOID__VOID
,
163 laugh_node_signals
[STARTED
] =
164 g_signal_new ("started",
165 G_TYPE_FROM_CLASS (gobject_class
),
167 G_STRUCT_OFFSET (LaughNodeClass
, started
),
169 g_cclosure_marshal_VOID__VOID
,
172 laugh_node_signals
[STOPPED
] =
173 g_signal_new ("stopped",
174 G_TYPE_FROM_CLASS (gobject_class
),
176 G_STRUCT_OFFSET (LaughNodeClass
, stopped
),
178 g_cclosure_marshal_VOID__VOID
,
181 _laugh_tag_map
.string_id
= g_hash_table_new (g_str_hash
, g_str_equal
);
182 _laugh_tag_map
.id_string
= g_hash_table_new (NULL
, NULL
);
183 _laugh_tag_map
.string_unknown
= LaughTagIdLast
;
185 _laugh_attr_map
.string_id
= g_hash_table_new (g_str_hash
, g_str_equal
);
186 _laugh_attr_map
.id_string
= g_hash_table_new (NULL
, NULL
);
187 _laugh_attr_map
.string_unknown
= LaughTagIdLast
;
189 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdSmil
, "smil");
190 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdHead
, "head");
191 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdLayout
, "layout");
192 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdRootLayout
, "root-layout");
193 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdRegion
, "region");
194 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdBody
, "body");
195 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdSeq
, "seq");
196 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdPar
, "par");
197 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdExcl
, "excl");
198 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdSwitch
, "switch");
199 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdAudio
, "audio");
200 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdImg
, "img");
201 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdRef
, "ref");
202 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdText
, "text");
203 _laugh_add_mapping (&_laugh_tag_map
, LaughTagIdVideo
, "video");
205 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdId
, "id");
206 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdName
, "name");
207 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdLeft
, "left");
208 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdTop
, "top");
209 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdWidth
, "width");
210 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdHeight
, "height");
211 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdBgColor
, "background-color");
212 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdBgColor1
, "backgroundColor");
213 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdBgImage
, "backgroundImage");
214 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdShowBg
, "showBackground");
215 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdZIndex
, "z-index");
216 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdBegin
, "begin");
217 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdDur
, "dur");
218 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdEnd
, "end");
219 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdEndSync
, "endSync");
220 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdRepeat
, "repeat");
221 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdSrc
, "src");
222 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdType
, "type");
223 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdSubType
, "subType");
224 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdFill
, "fil");
225 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdFit
, "fit");
226 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdPeers
, "peers");
227 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdHigher
, "higher");
228 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdLower
, "lower");
229 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdPauseDisplay
, "pauseDisplay");
230 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdHRef
, "href");
231 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdCoord
, "coord");
232 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdTransIn
, "trans-in");
233 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdTransOut
, "trans-out");
234 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdSystemBitrate
, "system-bitrate");
235 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdSensitivity
, "sensitivity");
236 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdFontColor
, "fontColor");
237 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdFontSize
, "fontSize");
238 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdHAlign
, "hAlign");
239 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdVAlign
, "vAlign");
240 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdCharset
, "charset");
241 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdBgOpacity
, "backgroundOpacity");
242 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdTargetAttr
, "targetAttribute");
243 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdTarget
, "target");
244 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdAttr
, "attribute");
245 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdAttrName
, "attributeName");
246 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdTo
, "to");
247 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdChangeBy
, "changed-by");
248 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdFrom
, "from");
249 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdValues
, "values");
250 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdCalcMode
, "calcMode");
251 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdKeyTimes
, "keyTimes");
252 _laugh_add_mapping (&_laugh_attr_map
, LaughAttrIdKeySplines
, "keySplines");
255 static void laugh_node_instance_init (GTypeInstance
*instance
, gpointer g_class
)
257 LaughNode
*self
= (LaughNode
*)instance
;
259 self
->priv
= LAUGH_NODE_GET_PRIVATE (self
);
261 self
->parent_node
= NULL
;
262 self
->first_child
= NULL
;
263 self
->previous_sibling
= NULL
;
264 self
->next_sibling
= NULL
;
265 self
->priv
->attributes
= NULL
;
268 GType
laugh_node_get_type (void)
270 static GType type
= 0;
272 static const GTypeInfo info
= {
273 sizeof (LaughNodeClass
),
274 NULL
, /* base_init */
275 NULL
, /* base_finalize */
276 (GClassInitFunc
) laugh_node_class_init
, /* class_init */
277 NULL
, /* class_finalize */
278 NULL
, /* class_data */
281 laugh_node_instance_init
/* instance_init */
283 type
= g_type_register_static (G_TYPE_OBJECT
,
290 struct _LaughDocumentPrivate
296 static gpointer laugh_document_parent_class
= ((void *)0);
298 static void laugh_document_finalize (GObject
*object
)
300 G_OBJECT_CLASS (laugh_document_parent_class
)->finalize (object
);
303 static void laugh_document_dispose (GObject
*object
)
305 LaughDocument
*document
= LAUGH_DOCUMENT(object
);
307 g_free (document
->priv
->uri
);
309 G_OBJECT_CLASS (laugh_document_parent_class
)->dispose (object
);
313 void _lauch_document_mime_type (LaughIO
*io
, const gchar
*mime
, gpointer d
)
315 g_printf ("lauch_document_mime_type: %s\n", mime
);
316 if (strcmp (mime
, "application/smil")) {
317 LaughNode
*node
= LAUGH_NODE (d
);
319 g_printerr ("not a smil document\n");
320 laugh_io_cancel (io
);
322 g_object_unref (G_OBJECT (io
));
324 laugh_node_base_emit_initialized (node
);
329 _lauch_document_completed (LaughIO
*io
, gsize sz
, gpointer data
, gpointer d
)
331 LaughNode
*node
= LAUGH_NODE (d
);
333 g_printf ("_lauch_document_completed: %u\n", sz
);
335 laugh_node_set_inner_xml (node
, (const gchar
*) data
);
339 g_object_unref (G_OBJECT (io
));
341 /*TODO init children and wait for initialized signals*/
342 laugh_node_base_emit_initialized (node
);
345 static void _laugh_document_init (LaughNode
*doc
, LaughInitializer
*initializer
)
347 LaughDocumentPrivate
*priv
= LAUGH_DOCUMENT (doc
)->priv
;
349 priv
->io
= laugh_io_new (priv
->uri
);
351 g_signal_connect (G_OBJECT (priv
->io
), "mime-type",
352 (GCallback
) _lauch_document_mime_type
, (gpointer
) doc
);
353 g_signal_connect (G_OBJECT (priv
->io
), "completed",
354 (GCallback
) _lauch_document_completed
, (gpointer
) doc
);
356 laugh_io_open (priv
->io
);
359 static void laugh_document_class_init (LaughDocumentClass
*klass
)
361 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
362 LaughNodeClass
*node_class
= (LaughNodeClass
*) klass
;
364 laugh_document_parent_class
= g_type_class_peek_parent (klass
);
366 gobject_class
->finalize
= laugh_document_finalize
;
367 gobject_class
->dispose
= laugh_document_dispose
;
368 node_class
->init
= _laugh_document_init
;
370 g_type_class_add_private (gobject_class
, sizeof (LaughDocumentPrivate
));
374 void laugh_document_instance_init (GTypeInstance
*instance
, gpointer g_class
)
376 LaughDocument
*self
= (LaughDocument
*)instance
;
378 self
->priv
= LAUGH_DOCUMENT_GET_PRIVATE (self
);
381 GType
laugh_document_get_type (void)
383 static GType type
= 0;
385 static const GTypeInfo info
= {
386 sizeof (LaughDocumentClass
),
387 NULL
, /* base_init */
388 NULL
, /* base_finalize */
389 (GClassInitFunc
) laugh_document_class_init
, /* class_init */
390 NULL
, /* class_finalize */
391 NULL
, /* class_data */
392 sizeof (LaughDocument
),
394 laugh_document_instance_init
/* instance_init */
396 type
= g_type_register_static (LAUGH_TYPE_NODE
,
403 static long _laugh_mapping_from_string (LaughIdMapping
*map
, const gchar
*tag
)
405 gpointer id
= g_hash_table_lookup (map
->string_id
, (gpointer
) tag
);
407 id
= (gpointer
) map
->string_unknown
++;
408 _laugh_add_mapping (map
, (long) id
, g_strdup (tag
));
410 return (LaughNodeTagId
) (long) id
;
413 LaughNodeTagId
laugh_tag_from_string (const gchar
*tag
)
415 return (LaughNodeTagId
) _laugh_mapping_from_string (&_laugh_tag_map
, tag
);
418 const gchar
*laugh_tag_from_id (LaughNodeTagId id
)
420 return (const gchar
*) g_hash_table_lookup (_laugh_tag_map
.id_string
,
424 LaughNodeAttributeId
laugh_attribute_from_string (const gchar
*attr
)
426 return (LaughNodeAttributeId
)_laugh_mapping_from_string (
427 &_laugh_attr_map
, attr
);
430 const gchar
*laugh_attribute_from_id (LaughNodeAttributeId id
)
432 return (const gchar
*) g_hash_table_lookup (_laugh_attr_map
.id_string
,
436 LaughNode
*laugh_node_new (LaughDocument
*document
, LaughNodeTagId id
,
439 LaughNode
*node
= LAUGH_NODE (g_object_new (LAUGH_TYPE_NODE
, NULL
));
441 laugh_node_base_init (document
, node
, id
, attrs
);
446 LaughDocument
*laugh_document_new (const gchar
*uri
)
448 LaughDocument
*d
= LAUGH_DOCUMENT(g_object_new (LAUGH_TYPE_DOCUMENT
, NULL
));
449 LaughNode
*node
= (LaughNode
*)d
;
451 laugh_node_base_init (d
, node
, LaughTagIdDocument
, NULL
);
452 d
->priv
->uri
= g_strdup (uri
);
457 void laugh_node_base_init (LaughDocument
*document
, LaughNode
*node
,
458 LaughNodeTagId id
, GHashTable
*attributes
)
461 node
->document
= document
;
462 node
->priv
->attributes
= attributes
;
465 void laugh_node_base_emit_initialized (LaughNode
*node
)
467 g_signal_emit (node
, laugh_node_signals
[INITIALIZED
], 0);
470 const gchar
*laugh_node_get_attribute (LaughNode
*node
,
471 LaughNodeAttributeId attribute
)
473 LaughNodeClass
*klass
= LAUGH_NODE_GET_CLASS(node
);
475 return klass
->get_attribute (node
, attribute
);
478 void laugh_node_set_attribute (LaughNode
*node
,
479 LaughNodeAttributeId attr
, const gchar
*value
, gpointer
*undo
)
481 LaughNodeClass
*klass
= LAUGH_NODE_GET_CLASS(node
);
483 klass
->set_attribute (node
, attr
, value
, undo
);
487 void _laugh_xml_start_tag (void *data
, const char *tag
, const char **attr
)
489 DocumentBuilder
*builder
= (DocumentBuilder
*) data
;
491 GHashTable
*attrs
= NULL
;
492 LaughNodeTagId id
= laugh_tag_from_string (tag
);
494 if (attr
&& attr
[0]) {
496 attrs
= g_hash_table_new_full (
497 NULL
, NULL
, NULL
, (GDestroyNotify
) g_free
);
498 for (i
= 0; attr
[i
]; i
+= 2)
499 g_hash_table_insert (attrs
,
500 (gpointer
) (long) laugh_attribute_from_string (attr
[i
]),
501 g_strdup (attr
[i
+1]));
504 case LaughTagIdLayout
:
505 case LaughTagIdRootLayout
:
506 case LaughTagIdRegion
:
507 node
= laugh_layout_new (builder
->top_node
->document
, id
, attrs
);
510 node
= laugh_node_new (builder
->top_node
->document
, id
, attrs
);
512 laugh_node_append_child (builder
->current
, node
);
514 builder
->current
= node
;
517 static void _laugh_xml_end_tag (void *data
, const char *tag
)
519 DocumentBuilder
*builder
= (DocumentBuilder
*) data
;
521 if (laugh_tag_from_string (tag
) != builder
->current
->id
)
522 g_printerr ("unmatched tag %s, expects %s\n",
523 tag
, laugh_tag_from_id (builder
->current
->id
));
524 else if (builder
->current
!= builder
->top_node
)
525 builder
->current
= builder
->current
->parent_node
;
527 g_printerr ("spurious end tag %s", tag
);
530 void laugh_node_set_inner_xml (LaughNode
*node
, const gchar
*xml
)
532 DocumentBuilder builder
;
533 XML_Parser parser
= XML_ParserCreate (0L);
535 /*TODO: clear all node's child nodes*/
536 builder
.top_node
= node
;
537 builder
.current
= node
;
539 XML_SetUserData (parser
, &builder
);
540 XML_SetElementHandler (parser
, _laugh_xml_start_tag
, _laugh_xml_end_tag
);
542 if (XML_Parse (parser
, xml
, strlen (xml
), TRUE
) == XML_STATUS_ERROR
) {
546 XML_ParserFree(parser
);
549 static void _laugh_node_get_outer_xml (LaughNode
*node
, GString
*buffer
, int sp
)
551 LaughNodePrivate
*priv
= node
->priv
;
555 indent
= (gchar
*) g_malloc (sp
+ 1);
556 memset (indent
, ' ', sp
);
558 g_string_append (buffer
, indent
);
561 g_string_append_c (buffer
, '<');
562 g_string_append (buffer
, laugh_tag_from_id (node
->id
));
563 if (priv
->attributes
) {
566 g_hash_table_iter_init (&iter
, priv
->attributes
);
567 while (g_hash_table_iter_next (&iter
, &key
, &value
)) {
568 g_string_append_c (buffer
, ' ');
569 g_string_append (buffer
, laugh_attribute_from_id ((long) key
));
570 g_string_append (buffer
, "=\"");
571 g_string_append (buffer
, (const gchar
*)value
);/*TODO escape*/
572 g_string_append_c (buffer
, '"');
575 if (node
->first_child
) {
577 g_string_append (buffer
, ">\n");
578 for (child
= node
->first_child
; child
; child
= child
->next_sibling
)
579 _laugh_node_get_outer_xml (child
, buffer
, sp
+2);
580 g_string_append (buffer
, indent
);
581 g_string_append (buffer
, "</");
582 g_string_append (buffer
, laugh_tag_from_id (node
->id
));
583 g_string_append (buffer
, ">\n");
585 g_string_append (buffer
, "/>\n");
592 gchar
*laugh_node_get_inner_xml (LaughNode
*node
)
594 GString
*buffer
= g_string_new ("");
598 for (child
= node
->first_child
; child
; child
= child
->next_sibling
)
599 _laugh_node_get_outer_xml (child
, buffer
, 0);
601 xml
= g_string_free (buffer
, FALSE
);
606 void laugh_node_append_child (LaughNode
*node
, LaughNode
*child
)
608 LaughNode
*n
= node
->last_child
;
611 n
->next_sibling
= child
;
612 child
->previous_sibling
= n
;
613 child
->next_sibling
= NULL
;
615 node
->first_child
= child
;
616 child
->previous_sibling
= NULL
;
617 child
->next_sibling
= NULL
;
619 node
->last_child
= child
;
620 child
->parent_node
= node
;
623 void laugh_node_init (LaughNode
*node
, LaughInitializer
*initializer
)
625 LaughNodeClass
*klass
= LAUGH_NODE_GET_CLASS(node
);
627 klass
->init (node
, initializer
);
630 #ifdef LAUGH_DOM_TEST
631 /* gcc laugh-dom.c laugh-io.c -o domtest `pkg-config --libs --cflags gio-2.0 glib-2.0 gthread-2.0` -lexpat */
633 #include <sys/types.h>
634 #include <sys/stat.h>
637 static GMainLoop
*mainloop
;
639 void initialized_callback (LaughNode
*node
, gpointer d
)
641 gchar
*xml
= laugh_node_get_inner_xml (node
);
642 g_printf ("cb initialized\n%s\n", xml
);
646 g_main_loop_quit (mainloop
);
649 int main (int argc
, char **argv
)
652 LaughInitializer initializer
;
655 g_printerr ("usage %s uri\n", argv
[0]);
659 g_thread_init (NULL
);
662 doc
= laugh_document_new (argv
[1]);
664 g_signal_connect (G_OBJECT (doc
), "initialized",
665 (GCallback
) initialized_callback
, (gpointer
) 0);
667 laugh_node_init (LAUGH_NODE (doc
), &initializer
);
669 mainloop
= g_main_loop_new (NULL
, TRUE
);
670 g_main_loop_run (mainloop
);
672 g_object_unref (G_OBJECT (doc
));