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.
25 #include <glib/gmessages.h>
26 #include <glib/gprintf.h>
27 #include <clutter/clutter-main.h>
29 #include "laugh-timing.h"
31 #define LAUGH_TIMING_CONTAINER_GET_PRIVATE(obj) \
32 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), LAUGH_TYPE_TIMING_CONTAINER, LaughTimingContainerPrivate))
35 static gpointer laugh_timing_container_parent_class
= ((void *)0);
37 static void laugh_timing_container_finalize (GObject
*object
)
39 G_OBJECT_CLASS (laugh_timing_container_parent_class
)->finalize (object
);
42 static void laugh_timing_container_dispose (GObject
*object
)
44 LaughTimingContainer
*self
= LAUGH_TIMING_CONTAINER(object
);
45 LaughRoleTiming
*segment
= self
->timing_role
;
47 G_OBJECT_CLASS (laugh_timing_container_parent_class
)->dispose (object
);
49 laugh_timing_role_delete (segment
);
53 _laugh_timing_container_init (LaughNode
*node
, LaughInitializer
*initializer
)
55 LaughTimingContainer
*self
= (LaughTimingContainer
*) node
;
57 LaughRoleTiming
*parent_segment
= initializer
->parent_segment
;
60 g_hash_table_foreach (node
->attributes
, laugh_attributes_set
, node
);
62 laugh_timing_role_child_add (initializer
->parent_segment
, self
->timing_role
);
64 initializer
->parent_segment
= self
->timing_role
;
66 for (child
= node
->first_child
; child
; child
= child
->next_sibling
)
67 laugh_node_init (child
, initializer
);
69 initializer
->parent_segment
= parent_segment
;
72 static void _laugh_timing_container_set_attribute (LaughNode
*node
,
73 LaughNodeAttributeId att
, const gchar
*value
, gpointer
*undo
)
75 const gchar
*val
= value
;
76 LaughTimingContainer
*self
= (LaughTimingContainer
*)node
;
78 laugh_node_base_set_attribute (node
, att
, val
, undo
);
79 /*g_printf ("_laugh_timing_container_set_attribute %s=%s\n", laugh_attribute_from_id (att), val);*/
82 val
= *(const gchar
**)undo
;
84 laugh_timing_setting_set_attribute (self
->timing_role
, att
, val
);
87 static LaughRole
*_laugh_timing_container_role (LaughNode
*node
, LaughRoleType type
)
89 LaughTimingContainer
*self
= (LaughTimingContainer
*) node
;
92 case LaughRoleTypeTiming
:
93 return (LaughRole
*) self
->timing_role
;
99 static void laugh_timing_container_class_init (LaughTimingContainerClass
*klass
)
101 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
102 LaughNodeClass
*node_class
= (LaughNodeClass
*) klass
;
104 laugh_timing_container_parent_class
= g_type_class_peek_parent (klass
);
106 gobject_class
->finalize
= laugh_timing_container_finalize
;
107 gobject_class
->dispose
= laugh_timing_container_dispose
;
108 node_class
->init
= _laugh_timing_container_init
;
109 node_class
->set_attribute
= _laugh_timing_container_set_attribute
;
110 node_class
->role
= _laugh_timing_container_role
;
112 /*g_type_class_add_private (gobject_class, sizeof (LaughTimingContainerPrivate));*/
116 void laugh_timing_container_instance_init (GTypeInstance
*instance
, gpointer g_class
)
118 LaughTimingContainer
*self
= (LaughTimingContainer
*)instance
;
120 /*self->priv = LAUGH_TIMING_CONTAINER_GET_PRIVATE (self);*/
122 self
->timing_role
= laugh_timing_role_new ((LaughNode
*) self
);
125 GType
laugh_timing_container_get_type (void)
127 static GType type
= 0;
129 static const GTypeInfo info
= {
130 sizeof (LaughTimingContainerClass
),
131 NULL
, /* base_init */
132 NULL
, /* base_finalize */
133 (GClassInitFunc
) laugh_timing_container_class_init
, /* class_init */
134 NULL
, /* class_finalize */
135 NULL
, /* class_data */
136 sizeof (LaughTimingContainer
),
138 laugh_timing_container_instance_init
/* instance_init */
140 type
= g_type_register_static (LAUGH_TYPE_NODE
,
141 "LaughTimingContainerType",
147 static int _timing_parse_time (const gchar
*tstr
, int *value
) {
150 const gchar
*nstart
= NULL
;
151 const gchar
*p
= tstr
;
163 } else if (*p
== '-') {
168 } else if (*p
>= '0' && *p
<= '9') {
171 } else if (*p
== '.') {
177 } else if (*p
== ' ') {
186 num
= g_strndup (nstart
, p
- tstr
);
187 *value
= sign
* (int) (1000 * g_strtod (nstart
, NULL
));
193 } else if (*p
== 'h') {
196 } else if (*p
!= ' ')
205 static int _get_timing (const gchar
*tstr
, LaughTiming
*timing
) {
206 const gchar
*orig
= tstr
;
208 const gchar
*p
= tstr
;
211 for ( ; *p
; ++p
, ++orig
) {
216 timing
->type
= LaughTimingUnknown
;
220 lower
= g_ascii_strdown (p
, -1);
223 if (_timing_parse_time (lower
, &timing
->offset
)) {
224 timing
->type
= LaughTimingTime
;
225 } else if (!strncmp (lower
, "id(", 3)) {
226 p
= (const gchar
*) strchr (lower
+ 3, ')');
228 idref
= g_strndup (orig
+ 3, p
- lower
- 3);
232 const char *q
= strchr (p
, '(');
236 } else if (!strncmp (lower
, "indefinite", 10)) {
237 timing
->type
= LaughTimingIndefinite
;
238 } else if (!strncmp (lower
, "media", 5)) {
239 timing
->type
= LaughTimingMedia
;
241 if (LaughTimingUnknown
== timing
->type
) {
242 const gchar
*idref_start
= p
;
247 last_esc
= last_esc
? 0 : 1;
248 } else if (*p
== '.' && !last_esc
) {
253 idref
= g_strdup (orig
+ (idref_start
- lower
));
255 idref
= g_strndup (orig
+ (idref_start
- lower
), p
- idref_start
);
259 timing
->element_id
= idref
;
260 if (_timing_parse_time (p
, &timing
->offset
)) {
261 timing
->type
= LaughTimingStartSync
;
262 } else if (*p
&& !strncmp (p
, "end", 3)) {
263 timing
->type
= LaughTimingEndSync
;
264 _timing_parse_time (p
+3, &timing
->offset
);
265 } else if (*p
&& !strncmp (p
, "begin", 5)) {
266 timing
->type
= LaughTimingStartSync
;
267 _timing_parse_time (p
+5, &timing
->offset
);
268 } else if (*p
&& !strncmp (p
, "activateevent", 13)) {
269 timing
->type
= LaughTimingActivated
;
270 _timing_parse_time (p
+13, &timing
->offset
);
271 } else if (*p
&& !strncmp (p
, "inboundsevent", 13)) {
272 timing
->type
= LaughTimingInbounds
;
273 _timing_parse_time (p
+13, &timing
->offset
);
274 } else if (*p
&& !strncmp (p
, "outofboundsevent", 16)) {
275 timing
->type
= LaughTimingOutbounds
;
276 _timing_parse_time (p
+16, &timing
->offset
);
278 g_printerr ("get_timings no match %s", lower
);
286 LaughTiming
*laugh_timing_new ()
288 return g_new0 (LaughTiming
, 1);
291 static void _laugh_timing_element_destroyed (LaughTiming
*timing
, GObject
*obj
)
293 if (timing
->handler_id
) {
294 timing
->handler_id
= 0;
297 g_printerr ("laugh_timing spurious destroy signal\n");
301 static gboolean
_laugh_timing_timeout (gpointer data
);
302 static void _laugh_timing_setting_started (LaughRoleTiming
*segment
);
303 static void _laugh_timing_setting_stopped (LaughRoleTiming
*segment
);
305 static void _laugh_timing_time_connect (LaughTiming
*timing
, int t
, gpointer data
)
307 timing
->handler_id
= g_timeout_add (t
> 0 ? t
: 0, _laugh_timing_timeout
, data
);
310 static void _laugh_timing_source_connect (LaughTiming
*timing
, LaughNode
*source
,
311 const gchar
*signal
, GCallback func
, gpointer data
)
313 timing
->element
= source
;
314 g_object_weak_ref ((GObject
*) source
, _laugh_timing_element_destroyed
, timing
);
315 timing
->handler_id
= g_signal_connect (G_OBJECT (source
), signal
, func
, data
);
318 static void _laugh_timing_source_disconnect (LaughTiming
*timing
)
320 if (timing
->handler_id
) {
321 switch (timing
->type
) {
322 case LaughTimingTime
:
323 g_source_remove (timing
->handler_id
);
326 if (timing
->element
) {
327 g_signal_handler_disconnect (timing
->element
, timing
->handler_id
);
328 g_object_weak_unref ((GObject
*) timing
->element
,
329 _laugh_timing_element_destroyed
, timing
);
333 timing
->element
= NULL
;
334 timing
->handler_id
= 0;
338 void laugh_timing_delete (LaughTiming
*timing
)
340 _laugh_timing_source_disconnect (timing
);
342 if (timing
->element_id
)
343 g_free (timing
->element_id
);
347 LaughRoleTiming
*laugh_timing_role_new (LaughNode
*node
)
349 LaughRoleTiming
*segment
= g_new0 (LaughRoleTiming
, 1);
351 segment
->role
.type
= LaughRoleTypeTiming
;
352 segment
->node
= node
;
357 void laugh_timing_role_source_disconnect (LaughRoleTiming
*role
)
360 _laugh_timing_source_disconnect (role
->begin
);
362 _laugh_timing_source_disconnect (role
->dur
);
364 _laugh_timing_source_disconnect (role
->end
);
367 void laugh_timing_role_delete (LaughRoleTiming
*segment
)
369 LaughRoleTiming
*parent
= segment
->parent
;
372 laugh_timing_delete (segment
->begin
);
374 laugh_timing_delete (segment
->dur
);
376 laugh_timing_delete (segment
->end
);
378 if (segment
->sub_segments
)
379 g_printerr ("TimingSegment %s leaking sub segments\n",
380 laugh_tag_from_id (segment
->node
->id
));
383 GSList
*s
= parent
->sub_segments
;
384 for ( ;s
; s
= s
->next
) {
385 GSList
*thread
= (GSList
*) s
->data
;
386 if (g_slist_find (thread
, segment
)) {
387 thread
= g_slist_remove (thread
, segment
);
389 parent
->sub_segments
= g_slist_remove (parent
->sub_segments
,
400 LaughTiming
*laugh_timing_new_from_string (const gchar
*value
)
402 LaughTiming
*t
= laugh_timing_new ();
403 if (laugh_timing_set_value (t
, value
))
405 laugh_timing_delete (t
);
409 void laugh_timing_role_child_add (LaughRoleTiming
*s
, LaughRoleTiming
*child
)
411 if (!s
->sub_segments
|| LaughTagIdPar
== s
->node
->id
) {
412 s
->sub_segments
= g_slist_append (s
->sub_segments
,
413 g_slist_append (NULL
, child
));
415 GSList
*last
= g_slist_last (s
->sub_segments
);
416 last
->data
= g_slist_append ((GSList
*) last
->data
, child
);
422 gboolean
laugh_timing_setting_set_attribute (LaughRoleTiming
*segment
,
423 LaughNodeAttributeId att
, const gchar
*val
)
425 LaughTiming
**timing
;
428 case LaughAttrIdBegin
:
429 timing
= &segment
->begin
;
432 timing
= &segment
->dur
;
435 timing
= &segment
->end
;
442 laugh_timing_set_value (*timing
, val
);
444 laugh_timing_delete (*timing
);
448 *timing
= laugh_timing_new_from_string (val
);
454 void _laugh_timing_stop (LaughTiming
*timing
)
457 _laugh_timing_source_disconnect (timing
);
460 static void _laugh_timing_role_dump (LaughRoleTiming
*segment
)
462 GSList
*s
= segment
->sub_segments
;
463 gboolean first
= TRUE
;
465 g_printf ("%s %d", laugh_tag_from_id (segment
->node
->id
), segment
->node
->state
);
469 for ( ; s
; s
= s
->next
) {
470 GSList
*s1
= (GSList
*) s
->data
;
471 gboolean sub_first
= TRUE
;
476 for ( ; s1
; s1
= s1
->next
) {
481 _laugh_timing_role_dump ((LaughRoleTiming
*) s1
->data
);
489 void _laugh_timing_setting_stop_freeze (LaughRoleTiming
*role
, LaughNodeState to_state
)
493 _laugh_timing_stop (role
->begin
);
494 _laugh_timing_stop (role
->dur
);
495 _laugh_timing_stop (role
->end
);
497 laugh_timing_role_source_disconnect (role
);
499 /*TODO determine freeze */
500 for (s
= role
->sub_segments
; s
; s
= s
->next
) {
502 for (sub
= (GSList
*) s
->data
; sub
; sub
= sub
->next
) {
503 LaughRoleTiming
*seg
= (LaughRoleTiming
*) sub
->data
;
505 laugh_timing_role_source_disconnect (seg
);
508 case LaughStateStopped
:
509 if (seg
->active
|| LaughStateFreezed
== seg
->node
->state
)
510 laugh_timing_setting_stop (seg
);
512 case LaughStateFreezed
:
514 /*FIXME: check fill*/
515 laugh_timing_setting_stop (seg
);
517 case LaughStateInitialized
:
518 if (seg
->node
->state
> LaughStateInitialized
&&
519 seg
->node
->state
!= LaughStateStopped
) {
520 _laugh_timing_setting_stop_freeze (seg
, to_state
);
521 LaughNodeClass
*klass
= LAUGH_NODE_GET_CLASS(seg
->node
);
523 klass
->stop (seg
->node
);
525 seg
->node
->state
= LaughStateInitialized
;
534 role
->stop_time_stamp
= clutter_get_timestamp ();
536 role
->active
= FALSE
;
539 static void _laugh_timing_setting_stopped (LaughRoleTiming
*segment
)
542 LaughRoleTiming
*parent
= segment
->parent
;
543 gboolean last_one
= TRUE
;
544 LaughRoleTiming
*start_next
= NULL
;
545 gboolean freeze
= FALSE
;
546 gboolean found
= FALSE
;
548 g_printf ("laugh_timing_setting_stopped %s\n",
549 laugh_tag_from_id (segment
->node
->id
));
552 for (s
= parent
->sub_segments
; s
; s
= s
->next
) {
553 GSList
*sub
= (GSList
*) s
->data
;
554 GSList
*l
= found
? NULL
: g_slist_find (sub
, segment
);
558 start_next
= (LaughRoleTiming
*) l
->next
->data
;
561 const gchar
*fill
= laugh_node_get_attribute (
562 segment
->node
, LaughAttrIdFill
);
563 if ((!fill
&& !segment
->dur
&& !segment
->end
) ||
564 (fill
&& !strcmp (fill
, "freeze")) ||
565 (fill
&& !strcmp (fill
, "hold")))
568 } else if (last_one
) {
569 LaughRoleTiming
*seg
=
570 (LaughRoleTiming
*) g_slist_last (sub
)->data
;
571 last_one
= seg
->node
->state
>= LaughStateStopped
;
573 if (found
&& !last_one
)
578 _laugh_timing_setting_stop_freeze (segment
, LaughStateFreezed
);
579 laugh_node_freeze (segment
->node
);
581 laugh_timing_setting_stop (segment
);
585 laugh_timing_setting_start (start_next
);
588 (parent
->dur
->type
== LaughTimingTime
&& !parent
->dur
->handler_id
)))
589 _laugh_timing_setting_stopped (parent
);
591 g_printf ("freeze %s\n", laugh_tag_from_id (segment
->node
->id
));
594 laugh_timing_setting_stop (segment
);
598 static void _laugh_timing_element_synced (LaughNode
*node
, LaughRoleTiming
*timing_role
)
600 LaughTiming
*timing
= NULL
;
602 if (timing_role
->begin
&& timing_role
->begin
->handler_id
)
603 timing
= timing_role
->begin
;
604 else if (timing_role
->end
&& timing_role
->end
->handler_id
)
605 timing
= timing_role
->end
;
608 g_printerr ("spurious element started event\n");
610 _laugh_timing_source_disconnect (timing
);
612 _laugh_timing_time_connect (timing
, timing
->offset
, timing_role
);
617 _laugh_timing_role_sync_on (LaughRoleTiming
*role
, LaughTiming
*timing
)
620 LaughRoleTiming
*target_role
;
621 LaughTimingType type
= timing
->type
;
622 LaughNodeState required_state
;
626 if (!timing
->element_id
) {
627 g_printerr ("Sync on element not specified\n");
631 target
= laugh_document_get_element_by_id (role
->node
->document
,
632 laugh_document_id_from_string (role
->node
->document
, timing
->element_id
));
634 g_printerr ("Sync on element %s: not found\n", timing
->element_id
);
638 target_role
= (LaughRoleTiming
*) laugh_node_role_get (target
, LaughRoleTypeTiming
);
640 g_printerr ("Sync on element %s: has no timing\n", timing
->element_id
);
645 case LaughTimingStartSync
:
647 required_state
= LaughStateBegun
;
648 offset
= (clutter_get_timestamp () - target_role
->start_time_stamp
) / 1000;
650 case LaughTimingEndSync
:
652 required_state
= LaughStateStopped
;
653 offset
= (clutter_get_timestamp () - target_role
->stop_time_stamp
) / 1000;
656 g_printerr ("TODO: connection to element event %d\n", type
);
660 if (target
->state
>= required_state
) {
661 _laugh_timing_time_connect (timing
, timing
->offset
- offset
, role
);
663 _laugh_timing_source_connect (timing
, target
, signal
,
664 (GCallback
)_laugh_timing_element_synced
, role
);
668 static void _laugh_timing_setting_started (LaughRoleTiming
*timing_role
)
670 LaughTiming
*dur
= timing_role
->dur
;
673 g_printf ("laugh_timing_setting_started %s\n",
674 laugh_tag_from_id (timing_role
->node
->id
));
675 laugh_node_start (timing_role
->node
);
676 if (dur
&& LaughTimingMedia
== dur
->type
)
677 g_printf ("laugh_timing_setting_started LaughTimingMedia\n");
679 if (dur
&& LaughTimingTime
== dur
->type
)
680 _laugh_timing_time_connect (dur
, dur
->offset
, timing_role
);
681 else if (timing_role
->end
)
682 _laugh_timing_role_sync_on (timing_role
, timing_role
->end
);
684 if (timing_role
->active
) {
685 if (timing_role
->sub_segments
) {
686 for (s
= timing_role
->sub_segments
; s
&& timing_role
->active
; s
= s
->next
)
687 laugh_timing_setting_start (
688 (LaughRoleTiming
*)((GSList
*) s
->data
)->data
);
689 } else if (!timing_role
->dur
&& !timing_role
->end
) {
690 _laugh_timing_setting_stopped (timing_role
);
695 static gboolean
_laugh_timing_timeout (gpointer data
)
697 LaughRoleTiming
*segment
= (LaughRoleTiming
*) data
;
699 if (segment
->begin
&& segment
->begin
->handler_id
) {
700 laugh_timing_notify (segment
, segment
->begin
->handler_id
);
701 segment
->begin
->handler_id
= 0;
702 } else if (segment
->dur
&& segment
->dur
->handler_id
) {
703 laugh_timing_notify (segment
, segment
->dur
->handler_id
);
704 segment
->dur
->handler_id
= 0;
707 return FALSE
; /*TODO handle repeat*/
710 gboolean
laugh_timing_setting_start (LaughRoleTiming
*timing_role
)
712 LaughTimingType timing_type
= LaughTimingTime
;
715 g_printf ("laugh_timing_setting_start %s\n",
716 laugh_tag_from_id (timing_role
->node
->id
));
717 timing_role
->active
= TRUE
;
718 timing_role
->start_time_stamp
= clutter_get_timestamp ();
720 if (!timing_role
->begin
)
721 timing_role
->begin
= laugh_timing_new ();
723 timing_type
= timing_role
->begin
->type
;
724 offset
= timing_role
->begin
->offset
;
726 if (LaughTimingTime
== timing_type
)
727 _laugh_timing_time_connect (timing_role
->begin
, offset
, timing_role
);
729 _laugh_timing_role_sync_on (timing_role
, timing_role
->begin
);
734 void laugh_timing_notify (LaughRoleTiming
*segment
, gulong handler_id
)
736 if (segment
->begin
&& segment
->begin
->handler_id
== handler_id
) {
737 _laugh_timing_setting_started (segment
);
738 } else if (segment
->dur
&& segment
->dur
->handler_id
== handler_id
) {
739 _laugh_timing_setting_stopped (segment
);
743 void laugh_timing_setting_stop (LaughRoleTiming
*segment
)
745 g_printf ("laugh_timing_setting_stop %s\n",
746 laugh_tag_from_id (segment
->node
->id
));
748 _laugh_timing_setting_stop_freeze (segment
, LaughStateStopped
);
750 laugh_node_stop (segment
->node
);
753 static LaughRoleTiming
*
754 _laugh_timing_settting_find (LaughRoleTiming
*segment
, const LaughNode
*node
)
756 if (segment
->node
== node
)
758 if (segment
->sub_segments
) {
760 for (s
= segment
->sub_segments
; s
; s
= s
->next
) {
762 for (sub
= (GSList
*) s
->data
; sub
; sub
= sub
->next
) {
763 LaughRoleTiming
*seg
= _laugh_timing_settting_find (
764 (LaughRoleTiming
*) sub
->data
, node
);
773 static void _laugh_timing_settting_sub_segments_force_stop (LaughRoleTiming
*segment
)
777 for (s
= segment
->sub_segments
; s
; s
= s
->next
) {
779 for (sub
= (GSList
*) s
->data
; sub
; sub
= sub
->next
) {
780 LaughRoleTiming
*seg
= (LaughRoleTiming
*) sub
->data
;
781 if (seg
->node
->state
> LaughStateInitialized
) {
782 _laugh_timing_setting_stop_freeze (seg
, LaughStateInitialized
);
783 if (seg
->node
->state
> LaughStateInitialized
&&
784 seg
->node
->state
!= LaughStateStopped
) {
785 LaughNodeClass
*klass
= LAUGH_NODE_GET_CLASS(seg
->node
);
787 klass
->stop (seg
->node
);
789 seg
->node
->state
= LaughStateInitialized
;
798 _laugh_timing_settting_recursive_start (LaughRoleTiming
*role
, LaughRoleTiming
*child
)
801 g_printerr ("jump target starting underflow error\n");
804 if (child
&& LaughTagIdPar
!= role
->node
->id
) {
807 for (s
= role
->sub_segments
; s
; s
= s
->next
) {
809 if (g_slist_find ((GSList
*)s
->data
, child
)) {
810 for (seg
= (GSList
*)s
->data
; seg
; seg
= seg
->next
) {
811 LaughRoleTiming
*r
= (LaughRoleTiming
*)seg
->data
;
814 r
->node
->state
= LaughStateStopped
;
822 _laugh_timing_settting_recursive_start (role
->parent
, role
);
823 if (LaughStateInitialized
>= role
->node
->state
)
824 laugh_timing_setting_start (role
);
828 void laugh_timing_setting_jump (LaughNode
*target
)
830 LaughRoleTiming
*segment
= target
->document
->timing
;
831 LaughRoleTiming
*seg
;
833 if (LaughStateBegun
== target
->state
) {
834 g_printerr ("jump target already active\n");
838 segment
= _laugh_timing_settting_find (segment
, target
);
840 g_printerr ("jump target not in tree\n");
844 for (seg
= segment
->parent
; seg
; seg
= seg
->parent
)
846 g_printf ("laugh_timing_setting_jump force stop %s\n",
847 laugh_tag_from_id (seg
->node
->id
));
849 if (LaughTagIdPar
!= seg
->node
->id
)
850 _laugh_timing_settting_sub_segments_force_stop (seg
);
851 _laugh_timing_settting_recursive_start (segment
, NULL
);
857 LaughNode
*laugh_timing_container_new (LaughDocument
*doc
, LaughNodeTagId id
,
858 GHashTable
*attributes
)
860 LaughNode
*n
= (LaughNode
*)g_object_new(LAUGH_TYPE_TIMING_CONTAINER
, NULL
);
862 laugh_node_base_construct (doc
, n
, id
, attributes
);
867 int laugh_timing_set_value (LaughTiming
*timing
, const gchar
*value
)
869 return _get_timing (value
, timing
);
872 /*#define TIMING_TEST*/
876 /* gcc laugh-timing.c -o timing-test `pkg-config --cflags --libs glib-2.0` -DTIMING_TEST*/
878 #define TEST_PARSE_TIME(s) \
881 int b = _timing_parse_time(s, &val); \
882 g_printf( "_timing_parse_time(%s) => %d: %d\n", (s), b, val); \
885 const char *timing_string (LaughTimingType tt
) {
887 case LaughTimingUnknown
:
889 case LaughTimingTime
:
891 case LaughTimingIndefinite
:
893 case LaughTimingMedia
:
895 case LaughTimingActivated
:
897 case LaughTimingInbounds
:
899 case LaughTimingOutbounds
:
901 case LaughTimingEndSync
:
903 case LaughTimingStartSync
:
911 #define TEST_GET_TIMING(s) \
913 LaughTiming *t = laugh_timing_new_from_string(s); \
914 g_printf( "_get_timing %s => target %s event %s offset%d\n", \
915 (s), t->element_id, timing_string(t->type), t->offset); \
916 laugh_timing_delete (t); \
920 TEST_PARSE_TIME("12");
921 TEST_PARSE_TIME("12s");
922 TEST_PARSE_TIME("12m");
923 TEST_PARSE_TIME("12h");
924 TEST_PARSE_TIME("12.4");
925 TEST_PARSE_TIME("12.4s");
926 TEST_PARSE_TIME("12.4m");
927 TEST_PARSE_TIME("12.4h");
928 TEST_PARSE_TIME(".4");
929 TEST_PARSE_TIME(".4s");
930 TEST_PARSE_TIME("+.4");
931 TEST_PARSE_TIME("+.4s");
932 TEST_PARSE_TIME("-.4");
933 TEST_PARSE_TIME("-.4s");
934 TEST_GET_TIMING("4");
935 TEST_GET_TIMING("myimage.activateEvent");
936 TEST_GET_TIMING("myimage.activateEvent+2");
937 TEST_GET_TIMING("myimage.endSync");
938 TEST_GET_TIMING("myimage.endSync-2m");
939 TEST_GET_TIMING("MyImage.endSync");
940 TEST_GET_TIMING("id(MyImage)(endSync)");
941 TEST_GET_TIMING("indefinite");